diff --git a/document/development/工作台费用统计详情弹窗/CONCEPT.md b/document/development/工作台费用统计详情弹窗/CONCEPT.md index fb40115..0d90f1f 100644 --- a/document/development/工作台费用统计详情弹窗/CONCEPT.md +++ b/document/development/工作台费用统计详情弹窗/CONCEPT.md @@ -105,3 +105,7 @@ $$ - 当前数据来自工作台前端汇总,历史维度受首页已加载单据范围影响;若后续需要跨年或分页全量统计,应补后端专用接口。 - 单据类型归类依赖标题、场景和备注,属于前端轻量归类;后续可与 ontology 费用类别字段打通。 + +## 2026-06-03 饼图呈现修正 + +费用分布仍复用项目已有 `DonutChart`,但在费用统计详情弹窗内关闭组件自带图例,只保留一个环形饼图入口。费用类型、金额、笔数和占比改为右侧文字明细列表,避免环图主体和双列图例在同一卡片内被误认为出现两个饼图。 diff --git a/document/development/工作台费用统计详情弹窗/TODO.md b/document/development/工作台费用统计详情弹窗/TODO.md index 21aefe5..42ac62a 100644 --- a/document/development/工作台费用统计详情弹窗/TODO.md +++ b/document/development/工作台费用统计详情弹窗/TODO.md @@ -13,6 +13,8 @@ - [x] 新增费用统计详情弹窗组件,展示三个详情区块和空状态。[CONCEPT: 功能能力] 证据:新增 `ExpenseStatsDetailModal.vue`。 - [x] 在 `PersonalWorkbench.vue` 接入弹窗状态与费用统计“查看详情”按钮。[CONCEPT: 方案设计] 证据:新增 `expenseStatsModalOpen` 与 `openExpenseStatsModal`。 - [x] 将费用分布区从条形列表改为 `DonutChart` 饼图展示。[CONCEPT: 功能能力] 证据:`ExpenseStatsDetailModal.vue` 已接入 `DonutChart` 和 `distributionChartItems`。 +- [x] 关闭费用详情内 `DonutChart` 自带图例,改为单饼图加右侧文字明细。[CONCEPT: 2026-06-03 饼图呈现修正] 证据:`ExpenseStatsDetailModal.vue` 传入 `:show-legend="false"` 并新增 `expense-distribution-summary-list`。 +- [x] 为通用 `DonutChart` 增加可隐藏内置图例的开关,默认保持其它页面不变。[CONCEPT: 2026-06-03 饼图呈现修正] 证据:`DonutChart.vue` 新增 `showLegend` 默认值和 `donut-chart--legendless` 状态。 ## 测试与验证 @@ -21,8 +23,9 @@ - [x] 补充弹窗源码测试,覆盖费用分布、处理时间、系统操作详情区块。[CONCEPT: 测试方案] 证据:`node web/tests/expense-stats-detail-modal.test.mjs` 通过。 - [x] 运行前端定向测试和构建验证。[CONCEPT: 指标与验收] 证据:以上定向测试和 `npm.cmd --prefix web run build` 均通过。 - [x] 更新弹窗源码测试,确认费用分布使用饼图组件。[CONCEPT: 测试方案] 证据:`node web/tests/expense-stats-detail-modal.test.mjs` 通过,`npm.cmd --prefix web run build` 通过。 +- [x] 更新弹窗与环图源码测试,确认详情弹窗只使用一个饼图入口且关闭内置图例。[CONCEPT: 2026-06-03 饼图呈现修正] 证据:`node web/tests/expense-stats-detail-modal.test.mjs` 与 `node web/tests/donut-chart.test.mjs` 通过。 ## 交付 - [x] 复查本次暂存范围,避免纳入无关工作区改动。[CONCEPT: 风险与开放问题] 证据:`git diff --cached --name-only` 仅包含本次工作台弹窗、样式、汇总测试和开发文档。 -- [ ] 提交并 push 本次功能分支。[CONCEPT: 指标与验收] +- [x] 提交并 push 本次功能分支。[CONCEPT: 指标与验收] 证据:本次单饼图修复完成后提交并推送当前分支。 diff --git a/web/src/components/business/ExpenseStatsDetailModal.vue b/web/src/components/business/ExpenseStatsDetailModal.vue index 1c9385b..5c98c62 100644 --- a/web/src/components/business/ExpenseStatsDetailModal.vue +++ b/web/src/components/business/ExpenseStatsDetailModal.vue @@ -51,12 +51,29 @@
暂无历史报销费用分布。
@@ -188,6 +205,10 @@ const distributionChartItems = computed(() => distributionRows.value.map((row, i color: distributionChartColors[index % distributionChartColors.length] }))) +function resolveDistributionColor(index) { + return distributionChartColors[index % distributionChartColors.length] +} + function emitClose() { emit('close') } @@ -454,26 +475,84 @@ function resolveTagType(tone) { align-items: stretch; } -.expense-distribution-donut { +.expense-distribution-chart-layout { + display: grid; + grid-template-columns: minmax(170px, 0.86fr) minmax(0, 1.14fr); + align-items: center; + gap: 12px; min-height: 286px; } +.expense-distribution-donut { + min-height: 0; +} + .expense-distribution-donut :deep(.donut-body) { - height: 194px; + height: 220px; margin-top: 0; } -.expense-distribution-donut :deep(.donut-legend) { - gap: 7px 14px; +.expense-distribution-summary-list { + min-width: 0; + display: grid; + align-content: center; + gap: 8px; } -.expense-distribution-donut :deep(.legend-name) { +.expense-distribution-summary-row { min-width: 0; + display: grid; + grid-template-columns: 10px minmax(0, 1fr) auto; + align-items: center; + gap: 8px; + padding: 8px 0; + border-top: 1px solid #e8eef5; +} + +.expense-distribution-summary-row:first-child { + border-top: 0; +} + +.expense-distribution-summary-row i { + width: 10px; + height: 10px; + border-radius: 2px; +} + +.expense-distribution-summary-row div { + min-width: 0; + display: grid; + gap: 2px; +} + +.expense-distribution-summary-row strong, +.expense-distribution-summary-row span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.expense-distribution-summary-row strong { + color: #334155; + font-size: 12.5px; + font-weight: 850; +} + +.expense-distribution-summary-row span { + color: #94a3b8; + font-size: 11px; + font-weight: 650; +} + +.expense-distribution-summary-row em { + color: #0f172a; + font-size: 12px; + font-style: normal; + font-weight: 850; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + .expense-processing-row { display: grid; grid-template-columns: minmax(124px, 0.8fr) minmax(164px, 1fr) auto 58px; @@ -580,6 +659,14 @@ function resolveTagType(tone) { } @media (max-width: 620px) { + .expense-distribution-chart-layout { + grid-template-columns: 1fr; + } + + .expense-distribution-donut :deep(.donut-body) { + height: 190px; + } + .expense-processing-row, .expense-operation-row { grid-template-columns: 1fr; diff --git a/web/src/components/charts/DonutChart.vue b/web/src/components/charts/DonutChart.vue index 8f26bc7..fd764fc 100644 --- a/web/src/components/charts/DonutChart.vue +++ b/web/src/components/charts/DonutChart.vue @@ -1,5 +1,5 @@ -