HEL-342: 管理总览 KPI 绑定真实 dashboard 接口
去掉写死的演示金额与账期进度,改由 /api/admin/dashboard 的 totals 与 period_progress 填充;无数据走空态。 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
b905cba52c
commit
b2bcd47e62
@@ -50,7 +50,7 @@ class ConfirmStatusSourceContractTests(unittest.TestCase):
|
||||
self.assertIn('id="workspacePendingStatus"', html)
|
||||
self.assertIn('id="workspaceFlowSub"', html)
|
||||
self.assertIn('data-view-link="reconcile"', html)
|
||||
self.assertIn("app.js?v=16", html)
|
||||
self.assertIn("app.js?v=17", html)
|
||||
# 静态初值仍为进行中(黄),由 JS 在 pending=0 时切 done
|
||||
self.assertRegex(html, r'class="flow-step doing"[^>]*data-view-link="reconcile"')
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ class TransfersPageSourceContractTests(unittest.TestCase):
|
||||
self.assertIn('id="transferEvidenceDrawer"', html)
|
||||
self.assertIn("期间净变动", html)
|
||||
self.assertNotIn("本公司往来合计", html)
|
||||
self.assertIn("design-system.css?v=11", html)
|
||||
self.assertIn("app.js?v=16", html)
|
||||
self.assertIn("design-system.css?v=12", html)
|
||||
self.assertIn("app.js?v=17", html)
|
||||
# 侧栏顺序:流水管理 → 转账往来 → 往来确认
|
||||
flows = html.index('data-view="flows"')
|
||||
transfers = html.index('data-view="transfers"')
|
||||
|
||||
@@ -33,6 +33,42 @@ class DashboardUnitTests(unittest.TestCase):
|
||||
self.assertEqual(0, payload["audit"]["total"])
|
||||
self.assertEqual([], payload["companies"])
|
||||
self.assertEqual(7, len(payload["weekly_flow"]["labels"]))
|
||||
self.assertEqual(0, payload["totals"]["company_count"])
|
||||
self.assertEqual(0, payload["totals"]["detail_count"])
|
||||
self.assertEqual("0.00", payload["totals"]["debit_wan"])
|
||||
self.assertEqual("0.00", payload["totals"]["credit_wan"])
|
||||
progress = payload["period_progress"]
|
||||
self.assertEqual("2026-08", progress["year_month"])
|
||||
self.assertEqual(0, progress["enabled_count"])
|
||||
self.assertEqual(0, progress["done"])
|
||||
self.assertEqual(0, progress["in_progress"])
|
||||
self.assertEqual(0, progress["unsubmitted"])
|
||||
self.assertEqual(0, progress["percent"])
|
||||
|
||||
def test_period_progress_unsubmitted_when_account_active_no_flows(self) -> None:
|
||||
now = master_data.utc_now()
|
||||
cursor = self.connection.execute(
|
||||
"INSERT INTO companies (name, credit_code, cashier_name, status, created_at, updated_at) "
|
||||
"VALUES ('甲公司', NULL, NULL, 'active', ?, ?)",
|
||||
(now, now),
|
||||
)
|
||||
company_id = int(cursor.lastrowid)
|
||||
self.connection.execute(
|
||||
"""
|
||||
INSERT INTO bank_accounts (
|
||||
company_id, account_number, bank_name, account_type, status,
|
||||
created_at, updated_at
|
||||
) VALUES (?, '6222020000000099', '工行', '一般户', 'active', ?, ?)
|
||||
""",
|
||||
(company_id, now, now),
|
||||
)
|
||||
self.connection.commit()
|
||||
progress = dashboard.period_progress(self.connection, year_month="2026-08")
|
||||
self.assertEqual(1, progress["enabled_count"])
|
||||
self.assertEqual(0, progress["done"])
|
||||
self.assertEqual(0, progress["in_progress"])
|
||||
self.assertEqual(1, progress["unsubmitted"])
|
||||
self.assertEqual(0, progress["percent"])
|
||||
|
||||
def test_pending_account_counts_as_medium(self) -> None:
|
||||
now = master_data.utc_now()
|
||||
@@ -267,6 +303,9 @@ class DashboardApiTests(unittest.TestCase):
|
||||
self.assertEqual(200, status)
|
||||
self.assertEqual("ok", data["status"])
|
||||
self.assertIn("audit", data)
|
||||
self.assertIn("totals", data)
|
||||
self.assertIn("period_progress", data)
|
||||
self.assertIn("debit_wan", data["totals"])
|
||||
self.assertEqual(1, len(data["companies"]))
|
||||
self.assertEqual("甲公司", data["companies"][0]["name"])
|
||||
|
||||
@@ -494,5 +533,39 @@ class DashboardApiTests(unittest.TestCase):
|
||||
self.assertEqual([], detail["groups"])
|
||||
|
||||
|
||||
class DashboardPageContractTests(unittest.TestCase):
|
||||
"""HEL-343 阻断项:管理总览 KPI 不得写死演示金额。"""
|
||||
|
||||
def test_admin_html_kpi_placeholders_not_demo_amounts(self) -> None:
|
||||
html = (Path(__file__).resolve().parents[1] / "web" / "admin.html").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
self.assertIn('id="dashPageSub"', html)
|
||||
self.assertIn('id="dashDebitValue"', html)
|
||||
self.assertIn('id="dashCreditValue"', html)
|
||||
self.assertIn('id="dashPeriodPercent"', html)
|
||||
self.assertIn('id="dashPeriodBar"', html)
|
||||
self.assertIn('id="dashPeriodFoot"', html)
|
||||
self.assertNotIn("42,040.30", html)
|
||||
self.assertNotIn("39,040.30", html)
|
||||
self.assertNotIn("8.11 亿", html)
|
||||
self.assertNotIn("392 笔", html)
|
||||
self.assertNotIn("3 家已完成 · 2 家在途 · 1 家未提交", html)
|
||||
self.assertNotRegex(html, r'id="flowStart"[^>]*value="2026-07-01"')
|
||||
self.assertIn('id="pending-check-all"', html)
|
||||
self.assertIn("pending-check-all", html)
|
||||
|
||||
def test_app_js_binds_dashboard_totals(self) -> None:
|
||||
js = (Path(__file__).resolve().parents[1] / "web" / "app.js").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
self.assertIn("function applyDashKpis(", js)
|
||||
self.assertIn("applyDashKpis(data)", js)
|
||||
self.assertIn("dashDebitValue", js)
|
||||
self.assertIn("dashCreditValue", js)
|
||||
self.assertIn("period_progress", js)
|
||||
self.assertIn("master.disabled = boxes.length === 0", js)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -37,8 +37,8 @@ class RemindersPageSourceContractTests(unittest.TestCase):
|
||||
self.assertIn('id="reminder-tbody"', html)
|
||||
self.assertIn('id="reminder-tabs"', html)
|
||||
self.assertIn('id="reminder-detail-drawer"', html)
|
||||
self.assertIn("design-system.css?v=11", html)
|
||||
self.assertIn("app.js?v=16", html)
|
||||
self.assertIn("design-system.css?v=12", html)
|
||||
self.assertIn("app.js?v=17", html)
|
||||
pending = html.index('id="pending-reminders-card"')
|
||||
history = html.index('id="reminder-history-card"')
|
||||
send = html.index('id="send-reminder-card"')
|
||||
@@ -135,7 +135,7 @@ class RemindersPageLayoutSmokeTests(unittest.TestCase):
|
||||
|
||||
def test_send_flow_columns_and_no_page_overflow(self) -> None:
|
||||
html = (WEB / "admin.html").read_text(encoding="utf-8")
|
||||
self.assertIn("app.js?v=16", html)
|
||||
self.assertIn("app.js?v=17", html)
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch()
|
||||
page = browser.new_page()
|
||||
|
||||
Reference in New Issue
Block a user