""" 补测脚本:覆盖 e2e_test.py 没打到、但后端有路由的接口。 仅做路由存在性 + 基本结构校验,不做深度业务链(e2e 已覆盖状态机链)。 """ import sys, io, json, requests sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') TOKEN = sys.argv[1] BASE = "http://localhost:8080" H = {"Authorization": f"Bearer {TOKEN}"} OPP_ID = "999999999001" results = [] def call(method, path, params=None, data=None, expect_code=0): url = BASE + path try: if method == "GET": r = requests.get(url, headers=H, params=params, timeout=10) else: r = requests.post(url, headers=H, params=params, data=data, timeout=10) try: d = r.json() code = d.get("code") ok = (code == expect_code) if expect_code is not None else True results.append((method, path, r.status_code, code, "OK" if ok else "FAIL", str(d.get("message", ""))[:60])) except Exception: results.append((method, path, r.status_code, "non-json", "FAIL", r.text[:60])) except Exception as e: results.append((method, path, "ERR", "ERR", "FAIL", str(e)[:60])) # ===== 状态机批量接口(e2e 未测) ===== call("POST", "/api/opportunity/claim-batch", data={"ids": OPP_ID}) call("POST", "/api/opportunity/assign-batch", data={"ids": OPP_ID, "userId": "739564171091247104"}) call("POST", "/api/opportunity/close-batch", data={"ids": OPP_ID, "closeReason": "supplement"}) # ===== 现场勘察 add/delete(e2e 仅测 page) ===== r = requests.post(f"{BASE}/api/opportunity/site-survey/add", headers=H, data={ "oppId": OPP_ID, "surveyDate": "2026-08-27", "surveyTimes": "FIRST", "applyType": "SELF", "remark": "sup"}, timeout=10) try: d = r.json(); sid = d.get("data") results.append(("POST", "/api/opportunity/site-survey/add", r.status_code, d.get("code"), "OK" if d.get("code") == 0 else "FAIL", str(d.get("message", ""))[:60])) if sid: r2 = requests.post(f"{BASE}/api/opportunity/site-survey/delete", headers=H, params={"id": sid}, timeout=10) d2 = r2.json() results.append(("POST", "/api/opportunity/site-survey/delete", r2.status_code, d2.get("code"), "OK" if d2.get("code") == 0 else "FAIL", str(d2.get("message", ""))[:60])) except Exception: results.append(("POST", "/api/opportunity/site-survey/add", r.status_code, "non-json", "FAIL", r.text[:60])) # ===== 附件 add/delete(e2e 测了 list + 上限) ===== r = requests.post(f"{BASE}/api/opportunity/attachment/add", headers=H, data={ "oppId": OPP_ID, "fileId": 59998, "bizType": "FOLLOW_UP", "bizId": 555}, timeout=10) d = r.json() results.append(("POST", "/api/opportunity/attachment/add", r.status_code, d.get("code"), "OK" if d.get("code") == 0 else "FAIL", str(d.get("message", ""))[:60])) # 找一个附件 id 删除 r = requests.get(f"{BASE}/api/opportunity/attachment/list", headers=H, params={"oppId": OPP_ID}, timeout=10) att_id = None try: atts = r.json().get("data", []) or [] if isinstance(atts, list) and atts: att_id = atts[0].get("id") except Exception: pass if att_id: r2 = requests.post(f"{BASE}/api/opportunity/attachment/delete", headers=H, params={"id": att_id}, timeout=10) d2 = r2.json() results.append(("POST", "/api/opportunity/attachment/delete", r2.status_code, d2.get("code"), "OK" if d2.get("code") == 0 else "FAIL", str(d2.get("message", ""))[:60])) # ===== 方案卡 save/submit/detail/selectable-templates(e2e 仅测 list) ===== call("GET", "/api/opportunity/scheme-card/selectable-templates", params={"oppId": OPP_ID}) call("GET", "/api/opportunity/scheme-card/detail", params={"id": "1"}) r = requests.post(f"{BASE}/api/opportunity/scheme-card/save", headers=H, data={ "oppId": OPP_ID, "customerId": "1", "projectStage": "PRE_BID", "bidForm": "ZC", "projectAmount": 100, "customerDemand": "sup"}, timeout=10) d = r.json() results.append(("POST", "/api/opportunity/scheme-card/save", r.status_code, d.get("code"), "OK" if d.get("code") == 0 else "FAIL", str(d.get("message", ""))[:60])) sc_id = d.get("data") if sc_id: r2 = requests.post(f"{BASE}/api/opportunity/scheme-card/submit", headers=H, params={"id": sc_id}, timeout=10) d2 = r2.json() results.append(("POST", "/api/opportunity/scheme-card/submit", r2.status_code, d2.get("code"), "OK" if d2.get("code") == 0 else "FAIL", str(d2.get("message", ""))[:60])) # ===== convertible-leads(新建商机的关联线索) ===== call("GET", "/api/opportunity/convertible-leads") # ===== 协作批量/协作 follow page ===== call("POST", "/api/opportunity/focus-batch", data={"oppIds": OPP_ID}) # ===== 规则族:detail/copy/publish/disable/delete/save-draft/field-defs/versions ===== for prefix, pid in [("/api/rule/opp-stage-template", "747831302652166144"), ("/api/rule/opp-scheme-template", "747831301075107840"), ("/api/rule/opp-pool-rule", None)]: call("GET", f"{prefix}/detail", params={"id": pid} if pid else None) call("GET", f"{prefix}/versions", params={"id": pid} if pid else None) call("POST", f"{prefix}/copy", params={"id": pid} if pid else None) call("POST", f"{prefix}/publish", params={"id": pid} if pid else None) call("POST", f"{prefix}/disable", params={"id": pid} if pid else None) call("POST", f"{prefix}/delete", params={"id": pid} if pid else None) call("POST", f"{prefix}/save-draft", data={"templateName": "sup-draft"}) if "scheme-template" in prefix: call("GET", f"{prefix}/field-defs", params={"templateId": pid} if pid else None) # ===== 字典 group/item 全套 ===== call("POST", "/api/dict/group/page", data={"pageNum": 1, "pageSize": 5}) call("GET", "/api/dict/group/enabled-list") call("POST", "/api/dict/item/page", data={"pageNum": 1, "pageSize": 5}) call("GET", "/api/dict/item/enabled-list", params={"groupCode": "opp_stage"}) call("GET", "/api/dict/item/enabled-list", params={"groupCode": "opp_pause_reason"}) call("GET", "/api/dict/item/enabled-list", params={"groupCode": "opp_close_reason"}) call("GET", "/api/dict/item/enabled-list", params={"groupCode": "opp_pause_reason"}) call("GET", "/api/dict/item/enabled-list", params={"groupCode": "opp_status"}) # ===== preference(视图/自定义字段) ===== call("GET", "/api/preference/get", params={"scopeKey": "opportunity.list"}) call("POST", "/api/preference/save", data={"scopeKey": "opportunity.list", "config": "{}"}) call("GET", "/api/preference/view/list", params={"scopeKey": "opportunity.list"}) call("POST", "/api/preference/view/save", data={"scopeKey": "opportunity.list", "viewName": "sup"}) call("POST", "/api/preference/view/delete", params={"id": "1"}) call("POST", "/api/preference/view/set-default", params={"id": "1"}) # ===== region(地区树) ===== call("GET", "/api/rule/region/list") call("GET", "/api/rule/region/level") # ===== 输出 ===== ok = sum(1 for r in results if r[4] == "OK") fail = sum(1 for r in results if r[4] == "FAIL") print(f"\n{'='*80}") print(f"补测:OK={ok} FAIL={fail} 共{len(results)}条") print(f"{'='*80}") for m, p, http, code, st, msg in results: icon = "[OK] " if st == "OK" else "[FAIL]" print(f"{icon} {m:4} {p:55} HTTP:{http} code:{code} | {msg}")