Files
QTImport/README.md
T
chenshoulin 58850314cf 初始提交:QuickTeam 工单接口导入工具
用「WCF + 通用存储过程网关」接口替代 Selenium(D://Learning//Python//工单自动化)导入工单:
单 Sprint 12 个项目 175s 跑完(旧方案 25~35 分钟),失败可断点续跑且不重复建单。

- 分层:transport(HTTP/协议)/ api(存储过程语义)/ domain(纯规则)/
  workflow(阶段编排)/ store(SQLite 台账)/ report / CLI
- 幂等:台账驱动断点续跑;dry-run 与跳过行不污染进度;--rollback-on-fail 清理半成品
- 命令:plan / apply / report / status,真实写入需 --yes
- tools:只读探针、存储过程源码导出(sp_helptext)、导入诊断
- docs:调研与设计文档(含联调踩到的 5 个坑)+ 6 个关键存储过程源码

实测:Sprint 2026 Sprint 10 的 12 个项目全部完成建单→导入→确认→推送 TFS,
工单 225134–225145,35 个功能模块,重跑 plan 全部 skip-pushed。69 个单测通过。
2026-11-05 19:14:25 +08:00

139 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QTImport
通过接口(而非浏览器自动化)把工单数据批量导入 QuickTeam 的项目。
替代 `D:\Learning\Python\工单自动化\auto_quickteam.py`(Selenium 版):单项目 2~3 分钟、依赖 DOM、易随前端改版失效,失败重跑还可能重复建单。
## 状态
| 阶段 | 内容 | 状态 |
| --- | --- | --- |
| M0 | 接口调研 + 只读探针 | ✅ 完成 |
| M1 | 读链路(登录/项目/工单/上传/TFS 上下文) | ✅ 完成,已在生产实测 |
| M2 | 写入链路(建单/填单/导入/确认/推送) | ✅ 完成,单项目已真实写入并核对落库 |
| M3 | 幂等台账、断点续跑、回滚、报告 | ✅ 完成,69 个单测通过 |
| M4 | 真实项目联调 + 灰度 | ✅ 12 个项目已真实执行(工单 225134–225145) |
全量实测:Sprint `2026 Sprint 10` 的 12 个项目全部建单 → 导入明细(33 个功能模块,逐文件与 Excel 核对一致)
→ 确认 → 推送 TFS,整轮 175 s(旧方案同流程约 25~35 分钟),重跑 `plan` 全部 `skip-pushed`。设计文档与联调踩坑记录:
[docs/QuickTeam-API导入-调研与设计.md](docs/QuickTeam-API导入-调研与设计.md) §8。
## 为什么可行
QuickTeam 前端是 Vue SPA,业务数据全部经一层「WCF + 通用存储过程网关」读写:
```
POST /Services/CommonService.svc/ExecTable
{ "connectionName": "QuickTeam", "param": "<encodeURIComponent(SPName+SQLParams)>" }
```
前端本身就是这套接口的客户端,复刻调用序列即可绕开浏览器与 DOM。实测:登录 0.5s、215 个项目 1.7s、
单项目工单查询 1.05s、文件上传 0.19s;12 个项目的完整演练 19s(旧方案约 25~35 分钟)。
## 快速开始
```bash
cp config/config.example.json config/config.json # 填账号、Sprint、目录、起止日期
```
凭据可用环境变量覆盖,避免落盘:`export QT_PASSWORD=***`。
```bash
# 1. 只读预演:能做什么、为什么跳过
python -m qtimport plan --config config/config.json
# 2. 演练完整链路(不发任何写请求,打印每一步的真实参数)
python -m qtimport apply --config config/config.json --dry-run
# 3. 真实执行(必须显式 --yes)
python -m qtimport apply --config config/config.json --yes
# 4. 看状态与报告
python -m qtimport status --config config/config.json
python -m qtimport report --config config/config.json
```
`plan` 输出:
```
项目 动作 说明
信托 - 上海信托 create 本项目该 Sprint 无工单
资管 - 华泰保险资管 create 本项目该 Sprint 无工单
资管 - 华泰资管 create 本项目该 Sprint 无工单
```
## 幂等与续跑
- 业务唯一键 `(ProjectId, SystemName)`:同一项目同一 Sprint 只建一张工单。
- 台账在 `state/qtimport.db`(SQLite),每推进一个阶段落一次,中断后重跑自动从断点继续。
- 已存在但无台账记录的工单默认跳过(不接管别人的单);确认要接管加 `--adopt`。
- 已推送 TFS 的不再推;失败时可用 `--rollback-on-fail` 删掉本次新建的半成品(已推送的绝不删)。
常用参数:
| 参数 | 用途 |
| --- | --- |
| `--project "资管 - 粤海资本"` | 只处理指定项目(可多次) |
| `--limit 1` | 只跑前 1 个,联调用 |
| `--skip-tfs` | 只建单+导入+确认,不推送 |
| `--adopt` | 接管无台账记录的既有工单 |
| `--rollback-on-fail` | 失败时回滚本次新建的半成品 |
| `--workers 3` | 并发数(默认取配置,写路径建议 ≤4) |
| `--force` | 跳过 Excel 模板预检 |
## 联调(唯一剩余的验证)
第一次真实写入建议这样跑,只影响一个项目:
```bash
python -m qtimport apply --config config/config.json \
--project "资管 - 粤海资本" --limit 1 --skip-tfs --rollback-on-fail --yes
```
预期:建单 → 填 17 个字段 → 上传 xlsx → 服务器解析明细 → 确认工单(技术责任人确认版 → 客户责任人确认版)。
然后到 QuickTeam 页面上核对:工单数、明细行数、三个责任人、起止日期、状态。
核对无误后再去掉 `--skip-tfs` 验证推送,最后 `--limit 1` 换成全量。
**注意**:`config.start_time` / `end_time` 会原样写进工单,执行前务必确认为该 Sprint 的真实区间。
## 目录
```
QTImport/
├── config/
│ ├── config.example.json # 模板
│ └── config.json # 含凭据,已 gitignore
├── docs/
│ └── QuickTeam-API导入-调研与设计.md
├── qtimport/
│ ├── transport.py # WCF 网关:双层 JSON、错误解析、裸字节上传
│ ├── api.py # 存储过程语义封装
│ ├── domain.py # 项目匹配、动作判定、版本推进、Excel 预检
│ ├── workflow.py # 阶段编排、并发、回滚
│ ├── store.py # SQLite 台账
│ ├── report.py # summary.md / detail.csv / JSONL
│ └── __main__.py # CLI
├── tools/
│ └── api_probe.py # 只读探针(零依赖,可独立交付)
└── tests/ # 69 个用例,无需网络
```
## 测试
```bash
python -m unittest discover -s tests -t .
```
覆盖:双层 JSON 解码、WCF 错误分类、项目名精确匹配(避免 `contains` 误命中)、
动作判定全分支、版本推进、Excel 预检、17 个参数构造、Column1 判定、TFS 路径解析、
dry-run 隔离、断点续跑、失败归属与回滚。
## 环境
Python 3.12+,零第三方依赖,不需要浏览器。需能访问 `http://192.168.1.213`。
## 注意
- `ExecTable` 网关无身份校验,本工具只在内网执行;请使用个人账号(`Operator` 会写入真实姓名,便于审计)。
- 凭据不要提交:`config/config.json`、`state/`、`reports/`、`logs/` 均在 `.gitignore` 中。