HEL-174: 公司端往来确认完成态改为 success 绿
确认全部完成后,账期流程第 3 步从 doing(warn 黄)切到 done(success 绿), 本月待办 pill 与阻断提示同步用 success;待确认仍保留 warn。补前端契约与 DOM 色值测试。 Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
co-authored by
Cursor
multica-agent
parent
642604f688
commit
7e7354a809
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
"""HEL-174: 360 / 820 / 1440 截图——待确认黄 vs 已完成绿。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import threading
|
||||
from functools import partial
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
WEB = ROOT / "web"
|
||||
OUT = Path(__file__).resolve().parent.parent / "hel174-shots"
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
VIEWPORTS = [
|
||||
(1440, 900, "1440"),
|
||||
(820, 900, "820"),
|
||||
(360, 800, "360"),
|
||||
]
|
||||
|
||||
|
||||
def extract_fn(source: str, name: str) -> str:
|
||||
marker = f"function {name}("
|
||||
start = source.index(marker)
|
||||
depth = 0
|
||||
for i, ch in enumerate(source[start:], start):
|
||||
if ch == "{":
|
||||
depth += 1
|
||||
elif ch == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return source[start : i + 1]
|
||||
raise RuntimeError(name)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
app_js = (WEB / "app.js").read_text(encoding="utf-8")
|
||||
inject = "\n".join(
|
||||
[
|
||||
"const state = {};",
|
||||
"function $(sel, root) { return (root || document).querySelector(sel); }",
|
||||
"function $$(sel, root) { return Array.from((root || document).querySelectorAll(sel)); }",
|
||||
extract_fn(app_js, "formatWorkspaceAmount"),
|
||||
extract_fn(app_js, "applyCompanyWorkspace"),
|
||||
]
|
||||
)
|
||||
|
||||
handler = partial(SimpleHTTPRequestHandler, directory=str(WEB))
|
||||
httpd = ThreadingHTTPServer(("127.0.0.1", 0), handler)
|
||||
port = httpd.server_address[1]
|
||||
thread = threading.Thread(target=httpd.serve_forever, daemon=True)
|
||||
thread.start()
|
||||
base = f"http://127.0.0.1:{port}"
|
||||
|
||||
html = f"""<!doctype html>
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="stylesheet" href="{base}/design-system.css"/>
|
||||
<title>HEL-174 往来确认状态色</title>
|
||||
<style>
|
||||
body {{ margin: 0; background: var(--bg); font-family: var(--font-body); color: var(--fg); }}
|
||||
.shot-wrap {{ padding: 16px; max-width: 1100px; margin: 0 auto; }}
|
||||
.shot-label {{ font-size: 13px; color: var(--muted); margin: 0 0 10px; }}
|
||||
</style>
|
||||
</head>
|
||||
<body data-portal="company">
|
||||
<div class="shot-wrap">
|
||||
<p class="shot-label" id="shotLabel">状态预览</p>
|
||||
<button id="workspaceUnilateralCta" class="btn btn-primary">去确认单边流水 (0)</button>
|
||||
<div class="card" id="workspaceTodos" style="margin-top:12px;">
|
||||
<div class="card-head">
|
||||
<span class="card-title">本月待办<span class="sub" id="workspaceTodoSub">…</span></span>
|
||||
<span class="pill pill-warn" id="workspacePendingStatus">加载中</span>
|
||||
</div>
|
||||
<div id="workspaceTodoList"></div>
|
||||
<div class="table-foot" id="workspaceTodoFoot"><span>…</span></div>
|
||||
</div>
|
||||
<div class="card" style="margin-top:12px;">
|
||||
<div class="card-head">
|
||||
<span class="card-title">账期流程 · 2026-07<span class="sub" id="workspaceFlowSub">…</span></span>
|
||||
</div>
|
||||
<div class="flow">
|
||||
<a class="flow-step part" href="#upload">
|
||||
<div class="fs-top"><span class="fs-idx">01</span><span class="fs-dot"></span><span class="fs-name">流水导入</span></div>
|
||||
<div class="fs-state">部分完成</div>
|
||||
</a>
|
||||
<a class="flow-step done" href="#manual">
|
||||
<div class="fs-top"><span class="fs-idx">02</span><span class="fs-dot"></span><span class="fs-name">手工补录</span></div>
|
||||
<div class="fs-state">已完成</div>
|
||||
</a>
|
||||
<a class="flow-step doing" data-view-link="reconcile" href="#reconcile">
|
||||
<div class="fs-top"><span class="fs-idx">03</span><span class="fs-dot"></span><span class="fs-name">往来确认</span></div>
|
||||
<div class="fs-state" id="workspaceConfirmState">加载中…</div>
|
||||
<div class="fs-meta" id="workspaceConfirmMeta">…</div>
|
||||
</a>
|
||||
<div class="flow-step wait">
|
||||
<div class="fs-top"><span class="fs-idx">04</span><span class="fs-dot"></span><span class="fs-name">管理复核</span></div>
|
||||
<div class="fs-state">等待集团</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="notice warn" id="blocking-notice" style="margin-top:12px;">
|
||||
<div>
|
||||
<div class="n-title" id="notice-title">…</div>
|
||||
<div class="n-body" id="notice-body">…</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top:12px;">
|
||||
<span class="pill pill-warn">待确认</span>
|
||||
<span class="pill pill-success" style="margin-left:8px;">已确认</span>
|
||||
</div>
|
||||
<span class="tab-count" id="count-match" hidden>0</span>
|
||||
<nav class="side-nav" hidden><a data-view="reconcile"><span class="nav-badge">0</span></a></nav>
|
||||
</div>
|
||||
</body></html>"""
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True, args=["--no-sandbox"])
|
||||
page = browser.new_page()
|
||||
for width, height, tag in VIEWPORTS:
|
||||
page.set_viewport_size({"width": width, "height": height})
|
||||
page.set_content(html, wait_until="domcontentloaded")
|
||||
page.add_script_tag(content=inject)
|
||||
|
||||
page.evaluate(
|
||||
"""() => {
|
||||
document.getElementById('shotLabel').textContent = '待确认(应黄)';
|
||||
applyCompanyWorkspace({
|
||||
pending_unilateral: 3, pending_total: 3,
|
||||
unilateral_events: [
|
||||
{event_id:1, amount:'100000.00', currency:'CNY',
|
||||
counterparty_company_name:'金牛贸易', effective_at:'2026-07-03'},
|
||||
{event_id:2, amount:'200000.00', currency:'CNY',
|
||||
counterparty_company_name:'金牛物流', effective_at:'2026-07-11'},
|
||||
{event_id:3, amount:'300000.00', currency:'CNY',
|
||||
counterparty_company_name:'金牛置业', effective_at:'2026-07-24'}
|
||||
]
|
||||
});
|
||||
}"""
|
||||
)
|
||||
page.wait_for_timeout(200)
|
||||
page.screenshot(path=str(OUT / f"hel174-pending-{tag}.png"), full_page=True)
|
||||
|
||||
page.evaluate(
|
||||
"""() => {
|
||||
document.getElementById('shotLabel').textContent = '已完成(应绿)';
|
||||
applyCompanyWorkspace({
|
||||
pending_unilateral: 0, pending_total: 0, unilateral_events: []
|
||||
});
|
||||
}"""
|
||||
)
|
||||
page.wait_for_timeout(200)
|
||||
page.screenshot(path=str(OUT / f"hel174-done-{tag}.png"), full_page=True)
|
||||
|
||||
colors = page.evaluate(
|
||||
"""() => {
|
||||
const step = document.querySelector('.flow-step[data-view-link="reconcile"]');
|
||||
const state = document.getElementById('workspaceConfirmState');
|
||||
const pill = document.getElementById('workspacePendingStatus');
|
||||
return {
|
||||
stepClass: step.className,
|
||||
stateText: state.textContent,
|
||||
stateColor: getComputedStyle(state).color,
|
||||
pillClass: pill.className,
|
||||
overflowX: document.documentElement.scrollWidth > document.documentElement.clientWidth + 1,
|
||||
};
|
||||
}"""
|
||||
)
|
||||
assert "done" in colors["stepClass"], colors
|
||||
assert "pill-success" in colors["pillClass"], colors
|
||||
assert colors["stateText"] == "已完成", colors
|
||||
assert not colors["overflowX"], colors
|
||||
print(tag, colors)
|
||||
|
||||
browser.close()
|
||||
httpd.shutdown()
|
||||
print("shots:", sorted(p.name for p in OUT.glob("*.png")))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user