HEL-155: 按第三轮效果图改造管理端首页

替换借贷轧差为待审核统计卡;公司往来合计/明细合成主从模块(折叠明细);
新增柱状图与折线图位;接入 /api/admin/dashboard 真实归集与审核队列数据。

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
施工员
2026-08-26 03:32:47 +00:00
co-authored by Cursor multica-agent
parent ece3e53472
commit 77fc625ded
6 changed files with 992 additions and 173 deletions
+51 -1
View File
@@ -11,7 +11,7 @@ from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import parse_qs, urlparse
from bank_importer import (
auth, importing, ledger_events, manual_records, master_data, matching,
auth, dashboard, importing, ledger_events, manual_records, master_data, matching,
multipart, personal_transit, positions, settings, subjects,
)
from bank_importer.db import connect, migrate, utc_now
@@ -95,6 +95,13 @@ class AppHandler(SimpleHTTPRequestHandler):
if path == "/api/admin/match-exceptions":
self._handle_admin_match_exceptions(query)
return
if path == "/api/admin/dashboard":
self._handle_admin_dashboard(query)
return
company_dash = re.fullmatch(r"/api/admin/dashboard/companies/(\d+)", path)
if company_dash:
self._handle_admin_dashboard_company(int(company_dash.group(1)), query)
return
if path == "/api/admin/personal-transit-mappings":
self._handle_admin_personal_mappings(query)
return
@@ -1866,6 +1873,49 @@ class AppHandler(SimpleHTTPRequestHandler):
finally:
connection.close()
def _handle_admin_dashboard(self, query: dict[str, list[str]]) -> None:
connection = connect(DB_PATH)
try:
user = self._require_admin(connection)
if user is None:
return
from_date = (query.get("from") or ["2026-01-01"])[0] or "2026-01-01"
cutoff = (query.get("cutoff") or [None])[0] or None
try:
payload = dashboard.build_dashboard(
connection, from_date=from_date, cutoff=cutoff
)
except ValueError as exc:
self._send_json(400, {"status": "error", "message": str(exc)})
return
self._send_json(200, {"status": "ok", **payload})
finally:
connection.close()
def _handle_admin_dashboard_company(
self, company_id: int, query: dict[str, list[str]]
) -> None:
connection = connect(DB_PATH)
try:
user = self._require_admin(connection)
if user is None:
return
from_date = (query.get("from") or ["2026-01-01"])[0] or "2026-01-01"
cutoff = (query.get("cutoff") or [dashboard.today_shanghai()])[0]
try:
payload = dashboard.company_peer_groups(
connection, company_id, from_date=from_date, cutoff=cutoff
)
except KeyError:
self._send_json(404, {"status": "error", "message": "公司不存在。"})
return
except ValueError as exc:
self._send_json(400, {"status": "error", "message": str(exc)})
return
self._send_json(200, {"status": "ok", **payload})
finally:
connection.close()
def _handle_admin_reconcile(self) -> None:
connection = connect(DB_PATH)
try: