# -*- coding: utf-8 -*- """票16 UI 补充4:U40 销售回退提交被拒 / U41 销售在他人进行中 stage0 项目的冲突解除""" import io, json, pathlib, sys sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') from playwright.sync_api import sync_playwright AUD = pathlib.Path(r"E:\code\crm-backend-matt\.scratch\crm-project\audit") SHOTS = AUD / "screenshots" DEMO = pathlib.Path(r"E:\code\crm-backend-matt\.scratch\crm-project\demo\index.html") SALES = "99021003"; BASE = "http://localhost:8080" PID_RB = (AUD / "rbpid.txt").read_text().strip() results = [] def step(name, ok, note=""): results.append({"step": name, "ok": bool(ok), "note": str(note)[:400]}) print(("PASS " if ok else "!! ") + name + ((" | " + str(note)) if note else "")) with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_context(viewport={"width": 1680, "height": 1000}).new_page() page.set_default_timeout(15000) page.goto(DEMO.as_uri() + "?api=" + BASE) page.evaluate(f"() => fetch('{BASE}/api/auth/debug/token?userId={SALES}').then(r=>r.json()).then(j=>{{const d=j.data; localStorage.setItem('a5_token', typeof d==='string'?d:d.token);}})") page.evaluate("() => localStorage.setItem('a5_me', JSON.stringify({userId:'99021003',userName:'A5销售'}))") page.goto(DEMO.as_uri() + "?api=" + BASE); page.wait_for_timeout(1500) # U40: 打开他人进行中 stage2 项目 → 点回退 → 确认 → 68005 page.evaluate(f"() => openProject('{PID_RB}')"); page.wait_for_timeout(1200) page.click("#detailActions button:has-text('回退…')"); page.wait_for_selector("#dlgRollback[open]") page.click("#dlgRollback .dfoot .ok") # 确认回退 page.wait_for_timeout(1200) t = page.inner_text("#toast") step("U40 销售提交回退被服务端拒 68005", "68005" in t, t) page.screenshot(path=str(SHOTS / "20-sales-rollback-denied.png"), full_page=True) # demo 行为观察: 失败后弹窗是否仍开 still_open = page.evaluate("() => document.getElementById('dlgRollback').open") page.click("#dlgRollback .dfoot button:not(.ok)"); page.wait_for_timeout(300) step("U40b 回退失败后弹窗保持打开(仅 toast 反馈)", still_open, "open=" + str(still_open)) # U41: 他人 stage0 且进行中的项目 page.click("nav.tabs button[data-tab='list']"); page.wait_for_timeout(600) page.select_option("#fStage", "0"); page.wait_for_timeout(1500) rows = page.query_selector_all("#listBox tr.row") picked = None for r in rows: txt = r.inner_text() if "进行中" in txt and "审核中" in txt: picked = r; break if picked: picked.click(); page.wait_for_timeout(1200) acts = page.inner_text("#detailActions") step("U41 普通销售在他人进行中 stage0 项目可见「冲突解除」", "冲突解除" in acts, acts[:120]) page.screenshot(path=str(SHOTS / "21-sales-filing-visible.png"), full_page=True) page.click("#detailActions button:has-text('冲突解除')"); page.wait_for_selector("#dlgFiling[open]") page.select_option("#filingApproved", "true"); page.click("#dlgFiling .dfoot .ok"); page.wait_for_timeout(1200) t2 = page.inner_text("#toast") step("U41b 销售提交冲突解除成功(服务端无权限校验)", "报备审核回填成功" in t2, t2) else: step("U41 无进行中 stage0 行可验", False, "rows=" + str(len(rows))) browser.close() passed = sum(1 for r in results if r["ok"]) print(f"\n==== UI补4 {passed}/{len(results)} PASS ====") (AUD / "ui-result4.json").write_text(json.dumps(results, ensure_ascii=False, indent=1), encoding="utf-8")