初始提交: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 个单测通过。
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
# 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` 中。
|
||||
Reference in New Issue
Block a user