diff --git a/document/development/风险与数字员工看板视觉优化/CONCEPT.md b/document/development/风险与数字员工看板视觉优化/CONCEPT.md new file mode 100644 index 0000000..dd76d9d --- /dev/null +++ b/document/development/风险与数字员工看板视觉优化/CONCEPT.md @@ -0,0 +1,95 @@ +# 风险与数字员工看板视觉优化 + +## 功能一句话 + +修正分析看板中风险看板的英文指标展示,将异常排行改成图表化表达,并优化数字员工看板的卡片布局和图表填充。 + +## 背景与问题 + +当前分析看板已经接入风险观察和数字员工数据,但存在三个影响个人操作体验的问题: + +- 风险看板仍会把 `duplicate_invoice`、`rule_center`、`unknown` 等后端 key 直接展示给用户。 +- 异常排行以多列文字列表呈现,分类多、层级碎,难以快速判断哪个异常维度最突出。 +- 数字员工看板部分卡片高度没有被内容充分利用,图表固定高度偏小,视觉上留下较多空白。 + +## 目标与非目标 + +目标: + +- 风险看板可见指标全部中文化,常见风险信号、来源、状态、规则名和未知占位都不再直接显示英文 key。 +- 异常排行聚合成一张图表化总览,保留部门、员工、供应商、规则和费用类型五个维度,并展示数量与金额。 +- 数字员工看板减少无效空白,让趋势图、技能分布、模块排行和业务产出更充分占满卡片。 +- 保持企业 SaaS 风格,继续复用现有 ECharts 封装组件和直角低饱和视觉体系。 + +非目标: + +- 不新增接口,不改变后端数据契约。 +- 不引入新的图表库。 +- 不重做分析看板顶部导航、财务看板、系统看板和页面路由。 + +## 用户与场景 + +用户: + +- 财务人员、风险复核人员、管理员。 + +场景: + +- 用户进入风险看板,快速识别最近周期的风险来源、风险等级和主要异常维度。 +- 用户查看异常排行时,优先通过图形长度和金额标签判断高发异常。 +- 用户进入数字员工看板,查看后台任务趋势、技能类型、工作模块和产出,不需要在大面积空白里寻找信息。 + +## 功能能力 + +风险看板: + +- 对风险信号 key、风险来源 key、状态 key、英文规则名和未知值做前端中文化。 +- 异常排行从五列小列表改为组合图表: + - 每个维度取排名第一项作为主条形图。 + - 展示维度名称、异常项名称、数量和金额。 + - 保留各维度的次级排行,作为图表下方的紧凑明细。 + +数字员工看板: + +- 主趋势卡片与每日摘要组成同一行,趋势图高度随卡片拉伸。 +- 技能分布、工作模块排行和业务产出统一为等高卡片。 +- 最近工作记录独占整行,减少右侧空白和表格压缩。 + +## 前端方案 + +- `RiskObservationDashboard.vue` + - 扩展 `formatSignal`、`formatDimensionName`、`formatRiskLevel` 等映射。 + - 新增异常排行图表数据 `rankingChartItems`,复用 `BarChart` 展示五个维度的头部异常。 + - 将原 `risk-ranking-grid` 改成图表 + 紧凑明细布局。 + +- `DigitalEmployeeDashboard.vue` + - 给卡片设置 flex 纵向结构,让图表区和列表区可拉伸。 + - 调整栅格跨度:趋势 7、每日摘要 5;技能分布、模块排行、业务产出各 4;最近记录 12。 + - 为图表容器增加可填充高度,减少固定高度导致的空白。 + +- `DigitalEmployeeDailyWorkChart.vue` + - 将固定高度改为跟随父容器的 `100%`,用最小高度保证可读性。 + +## 测试方案 + +- 前端源码测试: + - 风险看板不再暴露常见英文风险 key。 + - 异常排行包含 `rankingChartItems` 并复用 `BarChart`。 + - 数字员工看板包含布局填充类名和可拉伸图表区域。 +- 构建验证: + - `node web/tests/risk-observation-dashboard.test.mjs` + - `node web/tests/digital-employee-dashboard.test.mjs` + - `npm.cmd --prefix web run build` + +## 验收标准 + +- 风险看板常见英文 key 在用户可见位置被中文文案替代。 +- 异常排行以图表作为主视觉,不再只是五列文字列表。 +- 数字员工看板主要图表能够跟随卡片高度填充,卡片间高度更均衡。 +- 定向测试和前端构建通过。 + +## 风险与开放问题 + +- 当前工作区有大量既有未提交和未跟踪文件,本次提交需要严格隔离目标文件。 +- 若现有测试文件中保留了旧版乱码断言,需要同步更新为 UTF-8 中文断言。 +- 本次不改后端,如果后端后续新增新的风险 key,需要前端映射表继续补充。 diff --git a/document/development/风险与数字员工看板视觉优化/TODO.md b/document/development/风险与数字员工看板视觉优化/TODO.md new file mode 100644 index 0000000..e410415 --- /dev/null +++ b/document/development/风险与数字员工看板视觉优化/TODO.md @@ -0,0 +1,31 @@ +# 风险与数字员工看板视觉优化 TODO + +## 调研 + +- [x] 盘点风险看板英文指标、异常排行和数字员工布局现状。[CONCEPT: 背景与问题] 证据:已检查 `RiskObservationDashboard.vue`、`DigitalEmployeeDashboard.vue`、`DigitalEmployeeDailyWorkChart.vue`、`BarChart.vue` 和相关测试。 + +## 契约 + +- [x] 确认本次不改后端接口,只做前端展示归一化和布局优化。[CONCEPT: 目标与非目标] 证据:风险看板和数字员工看板已有所需数据字段。 + +## 前端 + +- [x] 扩展风险看板中文化映射,覆盖风险信号、来源、状态、未知值和规则名。[CONCEPT: 功能能力] 证据:新增 `riskLabels.js`,`RiskObservationDashboard.vue` 和 `useOverviewView.js` 已接入统一中文化函数。 +- [x] 将异常排行改为图表化主视觉,并保留紧凑明细。[CONCEPT: 前端方案] 证据:`RiskObservationDashboard.vue` 新增 `rankingChartItems`、`rankingDetailGroups` 和 `risk-ranking-visual`。 +- [x] 优化数字员工看板卡片跨度、等高布局和图表填充。[CONCEPT: 前端方案] 证据:`DigitalEmployeeDashboard.vue` 调整趋势/摘要/最近记录栅格,并新增 `digital-chart-fill`、`digital-card-fill`。 +- [x] 调整数字员工趋势图高度,使其跟随父容器填充。[CONCEPT: 前端方案] 证据:`DigitalEmployeeDailyWorkChart.vue` 高度改为 `100%` 并保留 `min-height`。 + +## 测试 + +- [x] 更新风险看板源码测试,覆盖中文化和图表化异常排行。[CONCEPT: 测试方案] 证据:`risk-observation-dashboard.test.mjs` 新增中文化 helper 和排行图表断言。 +- [x] 更新数字员工看板源码测试,覆盖布局填充类名和图表高度策略。[CONCEPT: 测试方案] 证据:`digital-employee-dashboard.test.mjs` 新增填充布局断言。 +- [x] 运行风险看板定向测试。[CONCEPT: 测试方案] 证据:`node web/tests/risk-observation-dashboard.test.mjs`,7 passed。 +- [x] 运行数字员工看板定向测试。[CONCEPT: 测试方案] 证据:`node web/tests/digital-employee-dashboard.test.mjs`,4 passed。 +- [x] 运行前端构建验证。[CONCEPT: 测试方案] 证据:`npm.cmd --prefix web run build` 通过,仍有既有 Rollup 注释和大 chunk 警告。 + +## 验收 + +- [x] 确认风险看板可见文案不再暴露常见英文 key。[CONCEPT: 验收标准] 证据:测试覆盖 `duplicate_invoice`、`policy.duplicate_invoice`、`travel`、`rule_center`、`financial_risk_graph` 中文化。 +- [x] 确认异常排行主视觉为图表形式。[CONCEPT: 验收标准] 证据:组件中异常排行由 `BarChart` 的 `rankingChartItems` 驱动。 +- [x] 确认数字员工看板主要图表和卡片减少无效空白。[CONCEPT: 验收标准] 证据:趋势图、饼图、条形图和业务产出卡片均接入可填充容器。 +- [x] 评估提交和推送范围,避免纳入无关脏工作区变更。[CONCEPT: 风险与开放问题] 证据:暂存区限定为分析看板前端、风险标签工具、定向测试和本开发文档,未纳入 `server/storage`、日志、临时截图等无关文件。 diff --git a/web/src/assets/styles/views/overview-view.css b/web/src/assets/styles/views/overview-view.css index ba0e7c8..0e23338 100644 --- a/web/src/assets/styles/views/overview-view.css +++ b/web/src/assets/styles/views/overview-view.css @@ -1,4 +1,5 @@ .dashboard { + position: relative; min-width: 0; display: grid; gap: 16px; @@ -6,6 +7,33 @@ animation: fadeUp 260ms var(--ease) both; } +.dashboard-loading-overlay { + position: absolute; + inset: 0; + z-index: 20; + display: grid; + place-content: center; + justify-items: center; + gap: 10px; + min-height: 320px; + border: 1px solid #e2e8f0; + border-radius: 4px; + background: rgba(248, 250, 252, .88); + color: #334155; + font-size: 13px; + font-weight: 800; + backdrop-filter: blur(2px); +} + +.dashboard-loading-overlay i { + color: var(--theme-primary); + font-size: 28px; +} + +.dashboard.is-loading > :not(.dashboard-loading-overlay) { + pointer-events: none; +} + .kpi-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); diff --git a/web/src/components/charts/DigitalEmployeeDailyWorkChart.vue b/web/src/components/charts/DigitalEmployeeDailyWorkChart.vue index 9547a3c..67a5bb8 100644 --- a/web/src/components/charts/DigitalEmployeeDailyWorkChart.vue +++ b/web/src/components/charts/DigitalEmployeeDailyWorkChart.vue @@ -149,6 +149,7 @@ useEcharts(chartElement, chartOptions) diff --git a/web/src/components/dashboard/DigitalEmployeeDashboard.vue b/web/src/components/dashboard/DigitalEmployeeDashboard.vue index 87633cb..878de1c 100644 --- a/web/src/components/dashboard/DigitalEmployeeDashboard.vue +++ b/web/src/components/dashboard/DigitalEmployeeDashboard.vue @@ -16,14 +16,16 @@ {{ errorMessage }} - +
+ +

每日工作摘要

-
+

技能类型分布

- +
+ +

工作模块排行

- +
+ +
当前周期暂无工作记录 @@ -70,7 +75,7 @@

业务产出

-
+
@@ -216,12 +221,17 @@ function formatRunMetrics(metrics = {}) { .digital-employee-dashboard { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); + grid-auto-rows: minmax(300px, auto); + align-items: stretch; gap: 18px; min-width: 0; } .dashboard-card { min-width: 0; + min-height: 300px; + display: flex; + flex-direction: column; padding: 18px; border: 1px solid #edf2f7; background: #fff; @@ -270,23 +280,72 @@ function formatRunMetrics(metrics = {}) { font-weight: 800; } -.digital-work-trend-panel, -.digital-recent-panel { - grid-column: span 8; +.digital-work-trend-panel { + grid-column: span 7; + min-height: 380px; } .digital-work-day-panel { - grid-column: span 4; + grid-column: span 5; + min-height: 380px; } .digital-category-panel, .digital-task-panel, .digital-output-panel { grid-column: span 4; + min-height: 320px; +} + +.digital-recent-panel { + grid-column: span 12; + min-height: 330px; +} + +.digital-card-fill { + flex: 1; + min-height: 0; +} + +.digital-chart-fill { + flex: 1; + min-height: 250px; + display: flex; + min-width: 0; +} + +.digital-chart-fill > :deep(*) { + flex: 1; + min-width: 0; +} + +.digital-trend-fill { + min-height: 290px; +} + +.digital-donut-fill :deep(.donut-chart) { + min-height: 100%; +} + +.digital-donut-fill :deep(.donut-body) { + flex: 1; + height: auto; + min-height: 168px; +} + +.digital-bar-fill :deep(.bar-chart) { + min-height: 100%; + align-items: stretch; +} + +.digital-bar-fill :deep(.chart-area) { + height: auto; + min-height: 240px; } .digital-dashboard-state, .digital-dashboard-empty { + flex: 1; min-height: 220px; display: grid; place-content: center; @@ -314,7 +373,9 @@ function formatRunMetrics(metrics = {}) { .digital-day-list { display: grid; + align-content: start; gap: 9px; + overflow: auto; } .digital-day-row { @@ -372,12 +433,13 @@ function formatRunMetrics(metrics = {}) { .digital-output-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-template-rows: repeat(2, minmax(0, 1fr)); gap: 10px; } .digital-output-item { min-width: 0; - min-height: 92px; + min-height: 0; display: flex; align-items: center; gap: 12px; @@ -420,7 +482,10 @@ function formatRunMetrics(metrics = {}) { } .digital-recent-table { + flex: 1; + min-height: 0; display: grid; + align-content: start; border: 1px solid #edf2f7; border-radius: 4px; overflow: hidden; diff --git a/web/src/components/dashboard/RiskObservationDashboard.vue b/web/src/components/dashboard/RiskObservationDashboard.vue index 00a5740..b4f582e 100644 --- a/web/src/components/dashboard/RiskObservationDashboard.vue +++ b/web/src/components/dashboard/RiskObservationDashboard.vue @@ -1,6 +1,6 @@