diff --git a/backend/api/project_assistant.py b/backend/api/project_assistant.py index 2c45df0..f1ea1e0 100644 --- a/backend/api/project_assistant.py +++ b/backend/api/project_assistant.py @@ -334,11 +334,88 @@ def business_command(payload: CommandInput, request: Request): return {"intent": "submit_review", "message": "AI预审报告已提交评审,历史版本保持可查看。", "object_id": submitted["id"], "url": f"/review-pool?submitted={payload.project_id}"} unresolved = [f for f in project_body["findings"] if f["status"] not in ("已解决", "不适用")] latest = project_body["runs"][0] if project_body["runs"] else None - message_text = f"{project_body['customer']}当前有{len(unresolved)}项待处理风险、{len(project_body['pending_candidates'])}项材料候选待确认。" - if latest: - message_text += f"最近一次{('独立评审' if latest.get('run_kind') == 'independent_review' else 'AI预审')}状态为{latest['status']}。" - message_text += "下一步:" + (f"处理“{unresolved[0]['title']}”" if unresolved else "生成报告或提交下一环节") - return {"intent": "project_status", "message": message_text, "items": [{"id": f["id"], "title": f["title"], "status": f["status"]} for f in unresolved[:5]], "url": f"/xingbang-workbench?project={payload.project_id}"} + pending = project_body["pending_candidates"] + project_url = f"/xingbang-workbench?project={quote(payload.project_id)}" + run_labels = {"queued": "等待执行", "running": "执行中", "completed": "已完成", "partial": "部分完成", "failed": "执行失败", "cancelled": "已取消"} + workflow_labels = {"report_ready": "报告准备", "supplementing": "补充材料", "submitted": "待评审领取", "under_review": "评审办理", "returned": "退回补件", "review_approved": "评审通过", "withdrawn": "已撤回"} + field_labels = {"facility.amount": "融资金额", "lease.total_value": "租赁物价值", "lease.duplicate_count": "设备清单重复情况", "financial.operating_cashflow": "经营现金流资料", "financial.total_liabilities": "财报负债", "due_diligence.liabilities": "尽调负债", "collection.evidence": "回款依据", "credit.overdue_count": "征信逾期记录", "credit.report_date": "征信报告日期"} + + def finding_title(item): + title = item.get("title", "待核查问题") + if "." in title and title.endswith("完整性"): + field = next(iter(item.get("fields", [])), title[:-3]) + return field_labels.get(field, title) + "是否完整" + return title + + if any(word in message for word in ("下一步", "接下来", "要做什么", "该做什么", "怎么推进", "如何推进", "怎么办")): + workflow = project_body.get("workflow_state", "") + independent = next((r for r in project_body["runs"] if r.get("run_kind") == "independent_review"), None) + if current_role == "reviewer" and workflow == "submitted" and not project_body.get("reviewer_id"): + next_text = "下一步请先到项目评审池领取该项目;领取后再发起独立评审。" + next_url = "/review-pool" + elif current_role == "reviewer" and not independent: + next_text = "下一步请发起独立评审,系统会基于评审员专用 Skills 与规则重新核查全链路。" + next_url = project_url + "&tab=review" + elif workflow == "returned": + returned = next((d for d in project_body["review_decisions"] if d.get("decision") == "退回" and not d.get("finding_id") and not d.get("node_id")), None) + reason = (returned or {}).get("opinion") or "请查看评审员的退回要求" + next_text = f"下一步请先补充退回材料:{reason}。确认材料来源后,重新发起AI预审。" + next_url = project_url + "&tab=findings" + elif pending: + next_text = f"下一步请先确认{len(pending)}项材料候选,确认期间、口径和来源后再更新项目事实。" + next_url = project_url + "&tab=findings" + elif latest and latest["status"] in ("queued", "running"): + next_text = f"本次{('独立评审' if latest.get('run_kind') == 'independent_review' else 'AI预审')}正在{run_labels[latest['status']]}。下一步先查看运行进度,完成后再处理问题。" + next_url = project_url + elif unresolved: + first = unresolved[0] + action = first.get("suggested_action") or "补充对应材料并说明核实口径" + next_text = f"下一步先处理“{finding_title(first)}”:{action}。处理后重新AI预审,确认问题是否闭环。" + next_url = project_url + "&tab=findings#project-findings" + elif not latest: + next_text = "下一步请发起AI预审,系统会检查当前材料并列出需要补充或人工确认的事项。" + next_url = project_url + elif not project_body["reports"]: + next_text = "当前问题已闭环。下一步请生成AI预审报告,并核对报告内容和来源版本。" + next_url = project_url + "&tab=report" + elif workflow != "submitted": + next_text = "当前报告已经具备送审条件。下一步请核对报告后提交正式评审。" + next_url = project_url + "&tab=report" + else: + next_text = "项目已经提交。下一步请到项目评审池查看领取状态和等待时间。" + next_url = "/review-pool" + return {"intent": "next_step", "message": next_text, "url": next_url} + + if any(word in message for word in ("什么问题", "哪些问题", "问题是什么", "风险", "异常")): + if unresolved: + details = ";".join(f"{index + 1}.{finding_title(item)}({item['status']})" for index, item in enumerate(unresolved[:5])) + message_text = f"当前共有{len(unresolved)}项未闭环问题:{details}。打开问题页可以逐项查看数据来源、AI判断和解决建议。" + else: + message_text = "当前没有未闭环问题。你可以继续生成报告,或查看历史检查记录和来源依据。" + return {"intent": "project_issues", "message": message_text, "items": [{"id": f["id"], "title": f["title"], "status": f["status"]} for f in unresolved[:5]], "url": project_url + "&tab=findings#project-findings"} + + if any(word in message for word in ("还缺", "缺什么", "缺少", "材料", "补件")): + if pending: + fields = "、".join(str(item.get("field") or "待确认字段") for item in pending[:5]) + message_text = f"当前有{len(pending)}项材料解析候选尚未确认:{fields}。请打开材料档案,核对期间、单位和来源后确认。" + elif unresolved: + message_text = f"当前没有待确认的材料解析候选,但仍有{len(unresolved)}项业务问题。请先查看“{finding_title(unresolved[0])}”的数据依据和补件建议。" + else: + message_text = f"当前没有待确认的材料候选,已归档{len(project_body['documents'])}份材料,现有问题已闭环。" + return {"intent": "materials", "message": message_text, "url": project_url + "&tab=findings"} + + if any(word in message for word in ("到哪", "进度", "状态", "阶段", "办到")): + stage = workflow_labels.get(project_body.get("workflow_state", ""), project_body.get("stage") or "处理中") + message_text = f"{project_body['customer']}当前处于“{stage}”阶段:有{len(unresolved)}项风险待处理,{len(pending)}项材料候选待确认。" + if latest: + run_name = "独立评审" if latest.get("run_kind") == "independent_review" else "AI预审" + message_text += f"最近一次{run_name}{run_labels.get(latest['status'], latest['status'])}。" + return {"intent": "project_status", "message": message_text, "items": [{"id": f["id"], "title": f["title"], "status": f["status"]} for f in unresolved[:5]], "url": project_url} + + if any(word in message for word in ("能做什么", "可以做什么", "怎么用", "如何使用", "帮助")) or message in ("你好", "您好", "嗨"): + return {"intent": "help", "message": "我可以帮你查项目进度、说明下一步、列出问题与缺失材料,也可以发起AI预审、生成报告和提交正式评审。你可以直接问:这个项目到哪一步了?或:我接下来要做什么?", "url": project_url} + + return {"intent": "clarify", "message": "我还不能确定你要查哪一项。你可以直接说“查看项目进度”“下一步做什么”“有哪些问题”“还缺什么材料”,也可以使用左侧快捷操作。复杂的自由分析请切换到 mini-openclaw。", "url": project_url} @router.get("/projects/{project_id}/reports/{report_id}/export") diff --git a/backend/test_project_assistant.py b/backend/test_project_assistant.py index db0c177..01e6044 100644 --- a/backend/test_project_assistant.py +++ b/backend/test_project_assistant.py @@ -351,6 +351,28 @@ class ProjectAssistantTests(unittest.TestCase): self.assertEqual(returned["next_action"], "查看退回要求并补充材料") self.assertTrue(returned["returned_at"]) + def test_conversation_read_questions_receive_distinct_answers(self): + env = {"XINGBANG_DEMO_ROLE_LOGIN": "1", "XINGBANG_DEMO_PROJECTS": "DEMO-A,DEMO-B,DEMO-C"} + headers = {"X-Xingbang-Demo-Role": "manager"} + with patch.dict(os.environ, env): + status = self.post("/commands", {"project_id": "DEMO-B", "message": "这个项目到哪一步了?"}, headers=headers) + next_step = self.post("/commands", {"project_id": "DEMO-B", "message": "我接下来要做什么?"}, headers=headers) + issues = self.post("/commands", {"project_id": "DEMO-B", "message": "现在有哪些风险?"}, headers=headers) + materials = self.post("/commands", {"project_id": "DEMO-B", "message": "还缺什么材料?"}, headers=headers) + unknown = self.post("/commands", {"project_id": "DEMO-B", "message": "请详细分析这个客户"}, headers=headers) + for response in (status, next_step, issues, materials, unknown): + self.assertEqual(response.status_code, 200, response.text) + self.assertEqual(status.json()["intent"], "project_status") + self.assertIn("当前处于", status.json()["message"]) + self.assertEqual(next_step.json()["intent"], "next_step") + self.assertIn("下一步", next_step.json()["message"]) + self.assertNotIn("lease.duplicate_count完整性", next_step.json()["message"]) + self.assertNotEqual(status.json()["message"], next_step.json()["message"]) + self.assertEqual(issues.json()["intent"], "project_issues") + self.assertIn("未闭环问题", issues.json()["message"]) + self.assertEqual(materials.json()["intent"], "materials") + self.assertEqual(unknown.json()["intent"], "clarify") + def test_full_review_topics_gate_approval_and_freeze_trace(self): pre_run = self.run_project("DEMO-A") report = self.post("/projects/DEMO-A/reports", {"run_id": pre_run["id"]}).json() diff --git a/docs/兴邦金租对公智能评审平台业务手册-v1.0.docx b/docs/兴邦金租对公智能评审平台业务手册-v1.0.docx new file mode 100644 index 0000000..b191bfb Binary files /dev/null and b/docs/兴邦金租对公智能评审平台业务手册-v1.0.docx differ diff --git a/scripts/test_ui_readability.cjs b/scripts/test_ui_readability.cjs new file mode 100644 index 0000000..55f1e5a --- /dev/null +++ b/scripts/test_ui_readability.cjs @@ -0,0 +1,26 @@ +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); + +const root = path.resolve(__dirname, ".."); +const read = (file) => fs.readFileSync(path.join(root, file), "utf8"); + +const globals = read("src/app/globals.css"); +const navigation = read("src/components/xingbang/navigation.css"); +const workspace = read("src/app/data-access/workspace.css"); +const assistant = read("src/components/xingbang/business-assistant.css"); +const operations = read("src/app/operations-center/operations.css"); + +assert.match(globals, /font-size:\s*16px/, "全局正文应提供清晰的基础字号"); +assert.match(globals, /:focus-visible/, "键盘操作应有明显焦点提示"); +assert.match(navigation, /\.xb-agent-nav a\{min-height:42px[^}]*font-size:14px/, "主导航应扩大文字和点击区域"); +assert.match(navigation, /\.xb-role-switch\{min-height:42px/, "身份选择器应保留足够大的点击区域"); +assert.match(workspace, /\.ra-button\{min-height:42px[^}]*font-size:14px[^}]*font-weight:700/, "工作台按钮应清晰且易点击"); +assert.match(workspace, /\.ra-button\.primary\{background:#17634c/, "主操作按钮应采用稳定的主色强调"); +assert.match(workspace, /\.xb-review-final>\.ra-button:not\(\.primary\)\{border-color:#d7837b/, "退回操作应与批准操作清楚区分"); +assert.match(workspace, /\.xb-panel>p,.xb-panel p,.xb-panel details\{font-size:14px/, "业务面板正文不应继续使用过小字号"); +assert.match(assistant, /\.ba-messages article p\{font-size:15px/, "助手对话正文应易于阅读"); +assert.match(assistant, /\.ba-workspace aside button\{min-height:46px/, "助手快捷操作应有明显点击区域"); +assert.match(operations, /\.td-hero-actions button,.td-hero-actions select\{height:46px/, "时效看板操作控件应易于辨认和点击"); + +console.log("Business UI readability checks passed"); diff --git a/scripts/verify.py b/scripts/verify.py index 570ecae..ea7e292 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -210,6 +210,7 @@ def main() -> int: ("backend-unit", [project_python(), "-m", "unittest", "discover", "-s", ".", "-p", "test_*.py", "-v"], BACKEND), ("reviewer-workspace-ui", [executable("node"), "scripts/test_reviewer_workspace.cjs"], ROOT), ("identity-recovery-ui", [executable("node"), "scripts/test_identity_recovery.cjs"], ROOT), + ("ui-readability", [executable("node"), "scripts/test_ui_readability.cjs"], ROOT), ("frontend-build", [npm, "run", "build"], ROOT), ("compose-local-config", [docker, "compose", "-f", "docker-compose.yml", "config", "--quiet"], ROOT), ("compose-aliyun-config", [docker, "compose", "--env-file", "deploy/aliyun.env.example", "-f", "deploy/docker-compose.aliyun.yml", "config", "--quiet"], ROOT), diff --git a/src/app/data-access/workspace.css b/src/app/data-access/workspace.css index d728836..c823a4e 100644 --- a/src/app/data-access/workspace.css +++ b/src/app/data-access/workspace.css @@ -12,3 +12,41 @@ .xb-decision-editor{display:block;margin-top:10px}.xb-decision-editor>span{display:block;margin-bottom:6px;color:#51675a;font-size:10px;font-weight:700}.xb-decision-editor textarea{box-sizing:border-box;width:100%;min-height:82px;padding:10px 11px;resize:vertical;border:1px solid #d9e2dc;border-radius:7px;background:#fff;color:#273c30;font:inherit;line-height:1.6;outline:none}.xb-decision-editor textarea:focus{border-color:#3b8d64;box-shadow:0 0 0 3px #3b8d6418}.xb-decision-editor>small{display:block;margin-top:4px;text-align:right;color:#8a958e;font-size:9px} .xb-return-reason{display:block;width:min(360px,100%)}.xb-return-reason>span{display:block;margin-bottom:5px;color:#587063;font-size:9px;font-weight:700}.xb-return-reason textarea{box-sizing:border-box;width:100%;min-height:58px;padding:8px 10px;resize:vertical;border:1px solid #ccdcd2;border-radius:7px;background:#fff;color:#273c30;font:inherit;line-height:1.5;outline:none}.xb-return-reason textarea:focus{border-color:#3b8d64;box-shadow:0 0 0 3px #3b8d6418}@media(max-width:900px){.xb-return-reason{width:100%}} .xb-project-card.is-returned{border-color:#e7847b;background:#fff1ef;box-shadow:0 7px 24px #b8403020}.xb-project-card.is-returned:hover{border-color:#c74d42;box-shadow:0 9px 28px #b8403030}.xb-project-card.is-returned>span{background:#c9463b;color:#fff}.xb-returned-summary{display:grid;gap:6px;margin:15px 0;padding:12px 14px;border-left:3px solid #d04d43;border-radius:7px;background:#fff8f7}.xb-returned-summary small{color:#9a5c56}.xb-returned-summary strong{font-size:12px;line-height:1.6;color:#8d3029} + +/* Readability and action hierarchy for all consolidated business workspaces. */ +.ra-app{font-family:"Microsoft YaHei","PingFang SC",sans-serif;font-size:15px;line-height:1.65} +.ra-main,.xb-overview{color:#24352c} +.ra-heading h1{font-size:31px}.ra-heading p,.xb-overview-heading p{font-size:14px;color:#65766d} +.ra-eyebrow,.ra-side-label{font-size:12px}.ra-top{font-size:14px}.ra-badge,.ra-status{font-size:12px} +.ra-button{min-height:42px;padding:10px 16px;border:1px solid #b8c8bf;border-radius:8px;background:#fff;color:#234d39;font-size:14px;font-weight:700;box-shadow:0 2px 7px #173d2b0c;transition:background-color .16s,border-color .16s,box-shadow .16s,transform .16s} +.ra-button:hover{background:#edf6f1;border-color:#4e8b6c;box-shadow:0 5px 15px #173d2b16;transform:translateY(-1px)} +.ra-button.primary{background:#17634c;border-color:#17634c;color:#fff;box-shadow:0 5px 14px #17634c30}.ra-button.primary:hover{background:#104d3a;border-color:#104d3a} +.ra-button:disabled{box-shadow:none;transform:none} +.ra-field,.ra-run-form label{font-size:14px;color:#53675c}.ra-field>span{font-weight:600} +.ra-field input,.ra-field textarea,.ra-field select,.ra-run-form input,.ra-run-form select,.xb-actions input,.xb-actions select,.xb-panel>select,.xb-report>select{min-height:42px;padding:10px 12px;border-color:#c6d2cb;border-radius:7px;font-size:14px;color:#283b31} +.ra-field input:focus,.ra-field textarea:focus,.ra-field select:focus,.xb-actions input:focus,.xb-actions select:focus{border-color:#3b8d64;box-shadow:0 0 0 3px #3b8d6418} +.ra-alert{padding:15px 16px;border-radius:8px;font-size:14px;font-weight:600} +.ra-pipeline-step b{font-size:14px}.ra-pipeline-step small{font-size:12px} +.ra-card h2{font-size:18px}.ra-card>p{font-size:14px;color:#66756d}.ra-chips span,.ra-card-detail,.ra-card footer{font-size:12px} +.xb-role-banner{padding:7px 11px;font-size:12px}.xb-project-card{padding:24px;border-color:#cedbd3;border-radius:12px;box-shadow:0 3px 12px #244a3708} +.xb-project-card>span{font-size:12px;font-weight:700}.xb-project-card h2{font-size:20px}.xb-project-card p{font-size:14px;color:#64766c}.xb-project-card footer b,.xb-project-card footer small{font-size:13px} +.xb-next{padding:14px}.xb-next small{font-size:12px}.xb-next b{font-size:14px} +.xb-tabs button,.xb-tabs a{min-height:46px;padding:14px 18px;font-size:15px;font-weight:600}.xb-tabs button:hover,.xb-tabs a:hover{background:#edf5f0;color:#17633f} +.xb-panel{border-color:#cedbd3;border-radius:10px}.xb-panel h2{font-size:21px}.xb-panel h3{font-size:17px}.xb-panel>p,.xb-panel p,.xb-panel details{font-size:14px;color:#586d61} +.xb-finding b{font-size:15px}.xb-finding p{font-size:14px}.xb-finding small{font-size:12px} +.xb-status,.xb-result{font-size:12px}.xb-review-clock small,.xb-review-clock span{font-size:12px}.xb-review-clock b{font-size:13px}.xb-review-clock strong{font-size:17px} +.xb-step-business>summary{padding:18px 20px;cursor:pointer}.xb-step-business>summary small{font-size:13px}.xb-step-business>summary strong{font-size:13px} +.xb-solution b{font-size:14px}.xb-solution small{font-size:13px} +.xb-review-heading>div>span{font-size:12px}.xb-review-heading h2{font-size:25px}.xb-review-heading p{font-size:14px}.xb-review-progress small{font-size:12px} +.xb-review-kpis span,.xb-review-lanes span{font-size:13px}.xb-review-topic>summary span>small,.xb-review-topic>summary>strong{font-size:12px}.xb-topic-lanes h3{font-size:15px} +.xb-source>summary{padding:12px}.xb-source>summary span>small,.xb-source>summary em{font-size:11px}.xb-source>p{font-size:12px!important;line-height:1.6}.xb-empty-source{font-size:12px} +.xb-ai-state p{font-size:13px!important}.xb-ai-check>span{height:auto;font-size:11px}.xb-ai-check b{font-size:13px}.xb-ai-check p,.xb-ai-check small{font-size:12px!important} +.xb-decision-editor>span,.xb-return-reason>span{font-size:13px}.xb-decision-editor>small,.xb-current-decision small,.xb-trace-note{font-size:11px} +.xb-decision-actions{gap:9px}.xb-decision-actions .ra-button{min-height:40px;padding:9px 12px;font-size:13px} +.xb-review-final{padding:20px;border:1px solid #cce2d5}.xb-review-final b{font-size:16px}.xb-review-final small{font-size:13px} +.xb-review-final>.ra-button:not(.primary){border-color:#d7837b;background:#fff7f5;color:#9b382f}.xb-review-final>.ra-button:not(.primary):hover{border-color:#bb4d43;background:#ffebe8} +.xb-return-reason textarea,.xb-decision-editor textarea{font-size:14px;border-color:#bfcfc6} +.xb-timeline article b,.xb-timeline article strong{font-size:14px}.xb-timeline article p{font-size:13px}.xb-timeline article small{font-size:12px} +.xb-history-counts button,.xb-event-list a{font-size:14px}.xb-history-counts small,.xb-event-list small{font-size:12px} +.xb-returned-summary small{font-size:12px}.xb-returned-summary strong{font-size:14px} +@media(max-width:760px){.ra-button{min-height:42px;font-size:13px}.xb-project-card h2{font-size:18px}.xb-tabs button,.xb-tabs a{font-size:13px}.xb-review-heading h2{font-size:22px}} diff --git a/src/app/globals.css b/src/app/globals.css index 4503fbd..59b22a2 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -16,10 +16,24 @@ body { min-height: 100%; } body { color: var(--text-primary); - font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", "Segoe UI", Roboto, sans-serif; + font-family: "Microsoft YaHei", "PingFang SC", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-size: 16px; + line-height: 1.6; -webkit-font-smoothing: antialiased; } +button, +input, +select, +textarea { + font: inherit; +} + +:focus-visible { + outline: 3px solid rgba(23, 99, 76, 0.28); + outline-offset: 3px; +} + /* ── Layered background ─────────────────────────────── */ .app-bg { background: diff --git a/src/app/operations-center/operations.css b/src/app/operations-center/operations.css index 080984f..1499b69 100644 --- a/src/app/operations-center/operations.css +++ b/src/app/operations-center/operations.css @@ -1 +1,11 @@ .td-shell{min-height:100vh;background:#071711;color:#eff8f3;font-family:Arial,"Microsoft YaHei",sans-serif}.td-main{max-width:1500px;margin:auto;padding:42px 38px 80px}.td-hero{display:flex;align-items:flex-end;justify-content:space-between;gap:28px;padding:34px 38px;border:1px solid #ffffff16;border-radius:22px;background:radial-gradient(circle at 75% 5%,#1b725850,transparent 35%),linear-gradient(135deg,#102b20,#0a1d16);box-shadow:0 28px 80px #0006;position:relative;overflow:hidden}.td-hero:after{content:"";position:absolute;width:260px;height:260px;border:1px solid #6ce1ae20;border-radius:50%;right:-80px;top:-150px}.td-hero p,.td-panel header p,.td-projects>header p{font-size:10px;letter-spacing:.18em;color:#72c99f;margin-bottom:12px}.td-hero h1{font-family:Georgia,"Microsoft YaHei",serif;font-size:38px;font-weight:500;letter-spacing:-.03em}.td-hero span{display:block;color:#91ab9e;font-size:13px;margin-top:13px}.td-hero-actions{display:flex;gap:10px;z-index:1}.td-hero-actions button,.td-hero-actions select{height:42px;padding:0 15px;border-radius:10px;border:1px solid #ffffff1f;background:#ffffff0d;color:#d9eee3;font-size:12px}.td-hero-actions option{color:#17251e}.td-hero-actions button{display:flex;align-items:center;gap:8px;background:#46c98c;color:#062116;border:0;font-weight:700}.spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.td-error,.td-loading{padding:24px;border:1px solid #ffffff18;border-radius:15px;margin-top:20px}.td-loading{display:flex;align-items:center;justify-content:center;gap:12px;color:#80a391;min-height:180px}.td-kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:18px 0}.td-kpis article{padding:22px 23px;border:1px solid #ffffff12;border-radius:16px;background:#0d2119}.td-kpis article.accent{background:linear-gradient(145deg,#163a2b,#10271d);border-color:#5ad39838}.td-kpis article>div{display:flex;justify-content:space-between;color:#86a495;font-size:11px}.td-kpis article>div svg{color:#4cc68c}.td-kpis strong{font-size:27px;font-weight:500;display:block;margin:17px 0 9px}.td-kpis strong small{font-size:11px;margin-left:4px;color:#718e80}.td-kpis p{font-size:10px;color:#627b6f;line-height:1.6}.td-insight{display:flex;align-items:center;justify-content:space-between;padding:26px 31px;margin-bottom:18px;border-radius:18px;background:linear-gradient(100deg,#eaf8f1,#dff2e8);color:#11261c}.td-insight p{font-size:10px;color:#4d8068;letter-spacing:.1em;margin-bottom:9px}.td-insight h2{font-family:Georgia,"Microsoft YaHei",serif;font-size:20px;font-weight:500}.td-donut{width:72px;height:72px;border-radius:50%;background:conic-gradient(#e2a354 0 58%,#38c487 58% 100%);display:grid;place-items:center;position:relative}.td-donut:after{content:"";position:absolute;inset:8px;border-radius:50%;background:#e6f5ed}.td-donut strong,.td-donut span{position:absolute;z-index:1}.td-donut strong{font-size:17px}.td-donut span{font-size:8px;margin-top:25px;color:#5d7f6e}.td-grid{display:grid;grid-template-columns:minmax(0,2.2fr) minmax(260px,.8fr);gap:16px}.td-panel,.td-projects{border:1px solid #ffffff12;background:#0d2119;border-radius:18px;padding:26px}.td-panel header,.td-projects>header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}.td-panel h2,.td-projects h2{font-size:18px;font-weight:500}.td-panel header small,.td-projects>header>span{font-size:10px;color:#658073}.td-phase{display:grid;grid-template-columns:180px 1fr 75px;gap:14px;align-items:center;margin:18px 0}.td-phase>div:first-child{display:flex;justify-content:space-between;align-items:center}.td-phase b{font-size:11px}.td-phase span{font-size:9px;color:#688174}.td-track{height:8px!important;border-radius:10px;background:#ffffff09;overflow:hidden}.td-track i{display:block;height:100%;border-radius:10px;background:linear-gradient(90deg,#309e70,#59d4a0);box-shadow:0 0 15px #3bd29144}.td-phase>strong{font-size:11px;text-align:right;color:#a9c0b5}.td-legend>div{display:grid;grid-template-columns:12px 1fr auto;align-items:center;gap:9px;padding:14px 0;border-bottom:1px solid #ffffff0b;font-size:11px}.td-legend>div i{width:8px;height:8px;border-radius:50%}.td-legend>div strong{font-weight:500}.td-legend>p{font-size:10px;color:#668174;line-height:1.8;margin-top:20px}.td-projects{margin-top:16px}.td-project{display:grid;grid-template-columns:240px 1fr 120px;gap:25px;align-items:center;padding:22px 0;border-top:1px solid #ffffff0d;color:inherit}.td-project:hover h3{color:#66daa5}.td-project-title>span{font-size:9px;letter-spacing:.12em;color:#5ab98b}.td-project-title h3{font-size:14px;margin:7px 0}.td-project-title small,.td-project-total small{font-size:9px;color:#61796d}.td-bars{height:24px;display:flex;gap:3px;align-items:center}.td-segment{height:100%;min-width:4px;border-radius:4px;display:grid;place-items:center;overflow:hidden}.td-segment span{font-size:8px;color:#062218;white-space:nowrap}.td-project-total{display:grid;grid-template-columns:1fr auto;align-items:center}.td-project-total small{grid-column:1/-1}.td-project-total strong{font-size:15px;margin-top:5px}.td-project-total svg{color:#58c892}.td-project-events{grid-column:2/-1;display:flex;gap:14px;flex-wrap:wrap}.td-project-events>span{display:grid;grid-template-columns:8px auto auto;gap:6px;align-items:center;font-size:9px;color:#799486}.td-project-events i{width:6px;height:6px;border-radius:50%}.td-project-events b{color:#bdd0c7}.td-project-events small{grid-column:2/-1;color:#536a5e}@media(max-width:950px){.td-kpis{grid-template-columns:1fr 1fr}.td-grid{grid-template-columns:1fr}.td-project{grid-template-columns:1fr}.td-project-events{grid-column:auto}.td-hero{align-items:flex-start;flex-direction:column}}@media(max-width:600px){.td-main{padding:20px 14px 60px}.td-hero{padding:27px 22px}.td-hero h1{font-size:29px}.td-kpis{grid-template-columns:1fr}.td-phase{grid-template-columns:1fr}.td-phase>strong{text-align:left}.td-projects,.td-panel{padding:20px}.td-hero-actions{width:100%}.td-hero-actions select,.td-hero-actions button{flex:1}} + +/* Larger dashboard labels and a stronger refresh action. */ +.td-shell{font-family:"Microsoft YaHei","PingFang SC",sans-serif;font-size:15px} +.td-hero p,.td-panel header p,.td-projects>header p{font-size:12px}.td-hero span{font-size:15px;line-height:1.7} +.td-hero-actions button,.td-hero-actions select{height:46px;padding:0 17px;font-size:14px;border-color:#ffffff38}.td-hero-actions button{box-shadow:0 7px 18px #0003}.td-hero-actions button:hover{background:#5bd79d;transform:translateY(-1px)} +.td-kpis article>div{font-size:13px}.td-kpis p{font-size:12px;color:#819b8e}.td-kpis strong small{font-size:13px} +.td-insight p{font-size:12px}.td-insight h2{font-size:23px}.td-donut span{font-size:10px} +.td-panel h2,.td-projects h2{font-size:20px}.td-panel header small,.td-projects>header>span{font-size:12px;color:#82998e} +.td-phase b,.td-phase>strong{font-size:13px}.td-phase span{font-size:11px}.td-legend>div{font-size:13px}.td-legend>p{font-size:12px;color:#81998d} +.td-project-title>span{font-size:11px}.td-project-title h3{font-size:17px}.td-project-title small,.td-project-total small{font-size:11px}.td-project-total strong{font-size:17px}.td-project-events>span{font-size:11px}.td-segment span{font-size:10px;font-weight:700} diff --git a/src/components/xingbang/business-assistant.css b/src/components/xingbang/business-assistant.css index 990b269..a844e30 100644 --- a/src/components/xingbang/business-assistant.css +++ b/src/components/xingbang/business-assistant.css @@ -1 +1,13 @@ .ba-shell{min-height:100vh;background:#f1f5f2;color:#173127;font-family:Arial,"Microsoft YaHei",sans-serif}.ba-shell *{box-sizing:border-box}.ba-main{max-width:1420px;margin:auto;padding:44px 38px 70px}.ba-heading{display:flex;justify-content:space-between;align-items:flex-end;gap:24px}.ba-heading>div>p{font-size:10px;letter-spacing:.16em;color:#378265;margin-bottom:10px}.ba-heading h1{font:500 36px/1.2 Georgia,"Microsoft YaHei",serif}.ba-heading>div>span{display:block;color:#74857d;font-size:12px;margin-top:12px}.ba-mode-tabs{display:flex;gap:5px;margin-top:28px}.ba-mode-tabs button{display:flex;align-items:center;gap:7px;border:0;background:transparent;color:#6f8178;padding:10px 13px;border-radius:9px;font-size:11px}.ba-mode-tabs button.active{background:#dcece3;color:#17633f;font-weight:700}.ba-context{display:grid;grid-template-columns:minmax(280px,1.4fr) .7fr 1fr auto;align-items:center;gap:18px;background:#0e2a1e;color:white;margin:10px 0 16px;padding:18px 22px;border-radius:15px;box-shadow:0 15px 42px #0d2d201c}.ba-context>div{min-width:0;border-right:1px solid #ffffff17}.ba-context span{display:block;font-size:9px;color:#7ba18e;margin-bottom:7px}.ba-context select{width:90%;border:0;background:transparent;color:#eaf7f0;font-size:13px;font-weight:700}.ba-context select option{color:#1a2a22}.ba-context b{display:block;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ba-context>a{display:flex;align-items:center;gap:6px;color:#73dfa9;font-size:11px}.ba-workspace{display:grid;grid-template-columns:290px minmax(0,1fr);min-height:610px;border:1px solid #dfe8e2;border-radius:18px;overflow:hidden;background:#fff;box-shadow:0 30px 80px #274d3a0e}.ba-workspace>aside{padding:30px 24px;background:linear-gradient(160deg,#f7fbf8,#edf5f0);border-right:1px solid #e1eae4}.ba-workspace>aside>svg{color:#2c9c6a}.ba-workspace aside h2{font-size:17px;margin:18px 0 10px}.ba-workspace aside p{color:#718179;font-size:11px;line-height:1.8;margin-bottom:24px}.ba-workspace aside button{width:100%;display:flex;justify-content:space-between;align-items:center;border:1px solid #dbe7df;background:#fff;color:#345a48;padding:12px 13px;border-radius:9px;margin-bottom:9px;font-size:11px;cursor:pointer}.ba-workspace aside button:hover{border-color:#62ad89;color:#17633f}.ba-workspace aside small{display:flex;align-items:flex-start;gap:7px;color:#8a9991;font-size:9px;line-height:1.7;margin-top:28px}.ba-chat{display:flex;flex-direction:column;min-width:0}.ba-messages{flex:1;padding:28px 34px;overflow:auto;max-height:560px}.ba-messages article{max-width:75%;margin-bottom:18px}.ba-messages article>div{display:flex;align-items:flex-start;gap:9px}.ba-messages article p{padding:13px 15px;border-radius:12px;background:#edf4f0;color:#385347;font-size:12px;line-height:1.8}.ba-messages article.user{margin-left:auto}.ba-messages article.user p{background:#17633f;color:#fff}.ba-messages article svg{color:#369367;margin-top:13px;flex-shrink:0}.ba-messages article small{display:block;color:#9aa6a0;font-size:9px;margin:7px 0 0 25px}.ba-messages article a{display:inline-flex;align-items:center;gap:4px;color:#24724f;font-size:10px;margin:6px 0 0 25px}.ba-messages .pending{opacity:.65}.ba-error{margin:0 28px 10px;color:#9c463b;background:#fff0ed;padding:10px 13px;border-radius:8px;font-size:11px}.ba-chat form{display:flex;align-items:center;gap:9px;margin:0 28px;padding:8px 9px;border:1px solid #d8e3dc;border-radius:13px;background:#fff;box-shadow:0 8px 25px #244a370d}.ba-chat form>input{flex:1;border:0;outline:0;padding:10px;font-size:12px}.ba-chat form>button,.ba-attach{width:38px;height:38px;display:grid;place-items:center;border:0;border-radius:9px;cursor:pointer}.ba-chat form>button{background:#17633f;color:#fff}.ba-chat form>button:disabled{opacity:.4}.ba-attach{color:#668078;background:#eff4f1}.ba-attach input{display:none}.ba-chat footer{display:flex;align-items:center;gap:6px;color:#93a199;font-size:9px;padding:10px 38px 20px}.ba-native{height:610px;display:grid;grid-template-rows:auto 1fr;overflow:hidden;border:1px solid #dfe8e2;border-radius:18px;background:#fff;box-shadow:0 30px 80px #274d3a0e}.ba-native>header{display:flex;justify-content:space-between;align-items:center;padding:14px 20px;border-bottom:1px solid #e1e9e4;background:#f6faf7}.ba-native>header>div,.ba-native>header>a{display:flex;align-items:center;gap:9px}.ba-native>header b{font-size:12px}.ba-native>header span{display:block;color:#819087;font-size:9px;margin-top:4px}.ba-native>header>a{color:#21704d;font-size:10px}@media(max-width:820px){.ba-main{padding:26px 14px 50px}.ba-heading{align-items:flex-start;flex-direction:column}.ba-heading h1{font-size:29px}.ba-context{grid-template-columns:1fr 1fr}.ba-workspace{grid-template-columns:1fr}.ba-workspace>aside{border-right:0;border-bottom:1px solid #e1eae4}.ba-messages{padding:22px 18px}.ba-messages article{max-width:90%}.ba-chat form{margin:0 14px}.ba-chat footer{padding-left:22px}} + +/* Larger business copy and clearer assistant actions. */ +.ba-shell{font-family:"Microsoft YaHei","PingFang SC",sans-serif;font-size:15px} +.ba-heading>div>p{font-size:12px}.ba-heading>div>span{font-size:14px;line-height:1.7} +.ba-mode-tabs button{min-height:44px;padding:11px 16px;font-size:14px;border:1px solid transparent;cursor:pointer} +.ba-mode-tabs button:hover{background:#e8f1ec;color:#17633f}.ba-mode-tabs button.active{border-color:#bdd9c8;box-shadow:0 3px 12px #1c5a3b12} +.ba-context span{font-size:12px}.ba-context select{font-size:15px}.ba-context b{font-size:14px}.ba-context>a{font-size:13px;font-weight:700} +.ba-workspace aside h2{font-size:20px}.ba-workspace aside p{font-size:14px;color:#5d7167}.ba-workspace aside button{min-height:46px;padding:12px 15px;border-color:#c9d9d0;font-size:14px;font-weight:600;box-shadow:0 2px 8px #244a3708} +.ba-workspace aside button:hover{background:#edf7f1;border-color:#3e8f68;box-shadow:0 4px 14px #244a3712} +.ba-workspace aside small{font-size:12px}.ba-messages article p{font-size:15px}.ba-messages article small{font-size:12px}.ba-messages article a{font-size:13px;font-weight:700} +.ba-error{font-size:14px}.ba-chat form{border-color:#bdd2c6;box-shadow:0 8px 28px #244a3715}.ba-chat form>input{font-size:15px}.ba-chat form>button,.ba-attach{width:44px;height:44px}.ba-chat footer{font-size:12px} +.ba-native>header b{font-size:14px}.ba-native>header span{font-size:12px}.ba-native>header>a{font-size:13px;font-weight:700} diff --git a/src/components/xingbang/navigation.css b/src/components/xingbang/navigation.css index d3c5f37..2987644 100644 --- a/src/components/xingbang/navigation.css +++ b/src/components/xingbang/navigation.css @@ -1 +1,13 @@ .xb-agent-nav{position:sticky;top:0;z-index:100;display:flex;align-items:center;gap:8px;padding:10px 22px;background:#fffffff5;backdrop-filter:blur(18px);border-bottom:1px solid #dfe7e3;color:#667b6d;box-shadow:0 2px 14px #1e3d2e0f;font-family:Arial,"Microsoft YaHei",sans-serif}.xb-agent-nav a{display:flex;align-items:center;gap:7px;padding:8px 10px;min-height:36px;border-radius:7px;font-size:12px;font-weight:500}.xb-agent-nav a:hover{background:#f2f6f3;color:#216b48}.xb-agent-nav a.selected{background:#e4f1e9;color:#17633f;box-shadow:inset 0 0 0 1px #cce2d4}.xb-agent-nav .xb-brand{gap:8px;padding:2px 14px 2px 0;margin-right:2px;border-right:1px solid #e4eae5;border-radius:0}.xb-brand-mark{width:30px;height:30px;display:grid;place-items:center;border-radius:7px;background:#17634c;color:#fff;font-size:15px;font-weight:700;box-shadow:inset 0 -2px 0 #0002}.xb-brand b{display:block;color:#17634c;font-size:13px;line-height:1.1}.xb-brand small{display:block;margin-top:4px;color:#91a197;font-size:9px;line-height:1.1}.xb-nav-spacer{flex:1}.xb-project-context{font-size:10px;color:#58705f;background:#f2f7f3;border:1px solid #deebe1;border-radius:999px;padding:7px 11px;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.xb-identity{display:flex;align-items:center;gap:7px;padding:7px 11px;border-radius:999px;background:#f2f6f3;border:1px solid #dce8e0;font-size:10px;color:#7d8c82;white-space:nowrap}.xb-identity i{width:7px;height:7px;border-radius:50%;background:#55a778;box-shadow:0 0 0 4px #55a77818}.xb-identity b{font-size:11px;color:#244a36}.xb-identity.role-reviewer{background:#eef2fb;border-color:#dce3f3}.xb-identity.role-reviewer i{background:#607bb8}.xb-identity.role-reviewer b{color:#344c82}.xb-identity.role-admin{background:#f8f2e8;border-color:#eadfc9}.xb-identity.role-admin i{background:#bc8541}.xb-identity.role-admin b{color:#76511f}.xb-overview{max-width:1480px;margin:auto;padding:32px}.xb-overview-heading{display:flex;justify-content:space-between;gap:16px;align-items:center;margin-bottom:28px}.xb-overview-heading h1{font-size:26px;font-weight:600}.xb-overview-heading p{font-size:12px;color:#84948b;margin-top:9px}.xb-role-switch{display:flex;align-items:center;gap:8px;border:1px solid #cee0d5;background:#fff;padding:9px 12px;border-radius:12px;box-shadow:0 7px 24px #183b2b0b}.xb-role-switch>span{font-size:10px;color:#87978f}.xb-role-switch svg{color:#27805a}.xb-role-switch select{font-weight:700;color:#245c43;border:0;background:transparent;outline:none}.xb-role-switch.dark{border-color:#ffffff1f;background:#ffffff0d;box-shadow:none}.xb-role-switch.dark>span{color:#8daf9e}.xb-role-switch.dark svg{color:#55d49b}.xb-role-switch.dark select{color:#e1f5eb}.xb-role-switch.dark select option{color:#17251e}@media(max-width:760px){.xb-agent-nav{padding:8px 10px;gap:3px;flex-wrap:wrap}.xb-agent-nav a{font-size:10px;padding:6px}.xb-agent-nav .xb-brand{border:0;padding-right:5px}.xb-brand small,.xb-nav-spacer,.xb-identity>span{display:none}.xb-identity{margin-left:auto}.xb-project-context{order:10;width:100%;max-width:none}.xb-overview{padding:22px 15px}.xb-overview-heading{align-items:flex-start;flex-wrap:wrap}} + +/* Business UI readability: keep navigation and identity obvious at a glance. */ +.xb-agent-nav{min-height:64px;padding:11px 24px;gap:10px;font-family:"Microsoft YaHei","PingFang SC",sans-serif} +.xb-agent-nav a{min-height:42px;padding:10px 13px;border-radius:9px;font-size:14px;font-weight:600;transition:background-color .16s,color .16s,box-shadow .16s} +.xb-agent-nav a.selected{box-shadow:inset 0 0 0 1px #bdd8c8,0 3px 10px #1d563a12} +.xb-brand-mark{width:36px;height:36px;font-size:17px} +.xb-brand b{font-size:15px}.xb-brand small{font-size:11px} +.xb-project-context{font-size:12px;padding:8px 13px} +.xb-role-switch{min-height:42px;padding:8px 13px;border-color:#bcd5c6;box-shadow:0 4px 16px #183b2b12} +.xb-role-switch>span{font-size:12px}.xb-role-switch select{font-size:14px;cursor:pointer} +.xb-overview-heading h1{font-size:30px;line-height:1.35}.xb-overview-heading p{font-size:14px;line-height:1.75;color:#667970} +@media(max-width:760px){.xb-agent-nav a{font-size:12px;min-height:38px;padding:8px}.xb-brand b{font-size:14px}.xb-overview-heading h1{font-size:26px}}