# 财务看板排行口径与部门人员占比

## 功能一句话

在分析看板的财务看板中补齐部门人员报销占比，并让部门、个人、高额单据使用统一的排行时间筛选口径。

## 背景与问题

当前财务看板已有部门报销排行、个人报销排行和本月高额单据，但存在三个问题：

- 部门排行的时间筛选只有本周、本月、本季度，缺少本年和全部。
- 个人报销排行标题固定为“本月”，实际无法由用户切换本月、本季度、本年和全部。
- 高额单据旁缺少部门内人员报销构成，财务人员难以判断高额单据是否集中在少数人员或单一部门。

## 目标与非目标

目标：

- 新增“部门人员报销占比”饼图，放在“本月高额单据”左侧，并与排行时间筛选口径联动。
- 部门报销排行增加参与人员数量，卡片空间完整展示排行内容。
- 个人报销排行增加报销笔数和所属部门信息，卡片空间完整展示排行内容。
- 部门排行、个人排行、高额单据、部门人员占比统一支持：本月、本季度、本年、全部。

非目标：

- 不新增独立页面。
- 不重做顶部 KPI、趋势图、预算指标和系统/风险/数字员工看板。
- 不引入新的图表库，继续复用现有 ECharts 封装组件。

## 用户与场景

用户：

- 高级财务人员、预算监控员、管理员。

场景：

- 财务人员进入分析看板后，查看不同时间口径下的部门费用集中度。
- 财务人员切换本季度、本年或全部后，对比部门排行、个人排行、高额单据和人员占比。
- 财务人员判断某部门报销金额高，是因为多人正常报销，还是少数人集中报销。

## 功能能力

输入：

- `department_range` 查询参数，取值：`本月`、`本季度`、`本年`、`全部`。

输出：

- `department_ranking`：部门报销排行，新增 `employeeCount`。
- `employee_ranking`：个人报销排行，保留金额、笔数、部门，并随筛选口径变化。
- `top_claims`：高额单据，随筛选口径变化，标题不再固定为本月。
- `department_employee_mix`：部门人员报销占比饼图数据。

状态与边界：

- 没有真实数据时返回空数组或“暂无数据”占位。
- 草稿、删除等非支出口径状态不参与金额排行。
- 缺失部门或人员名称的数据不进入排行和占比图。
- `全部` 表示所有可用报销单据，不按日期裁剪。

## 方案设计

后端：

- 在 `FinanceDashboardService` 中扩展排行时间范围解析。
- 将 `department_range` 作为排行分析窗口，统一供部门排行、个人排行、高额单据和部门人员占比使用。
- 部门排行按部门聚合金额、单据数、待付款金额和人员数量。
- 部门人员占比按“部门 + 人员”聚合金额，展示排名靠前的人员构成，名称格式为 `部门 · 人员`。

接口：

- `GET /api/v1/analytics/finance-dashboard` 保持原路径。
- `department_range` 支持 `本月`、`本季度`、`本年`、`全部`。
- 响应体新增 `department_employee_mix`。

前端：

- `analytics.js` 增加 `departmentEmployeeMix` 归一化。
- `metrics.js` 将 `departmentRangeOptions` 改为 `本月 / 本季度 / 本年 / 全部`。
- `useOverviewView.js` 新增部门人员占比 legend，并让部门/个人排行读取新增字段。
- `OverviewView.vue` 调整财务看板底部布局：
  - 部门排行占更宽区域，并保留筛选器。
  - 个人排行占更宽区域，并增加相同筛选器。
  - 高额单据卡片左侧放部门人员报销占比饼图，右侧放高额单据列表。
- 样式继续沿用企业 SaaS 直角、低饱和、Element Plus 控件和已有 `DonutChart` / `BarChart`。

## 算法与公式

支出金额：

$$
amount_i = claim_i.amount
$$

部门金额：

$$
departmentAmount_d = \sum_{i \in claims(d)} amount_i
$$

部门人员数：

$$
employeeCount_d = \left| distinct(employeeName_i), i \in claims(d) \right|
$$

个人金额：

$$
employeeAmount_e = \sum_{i \in claims(e)} amount_i
$$

部门人员报销占比：

$$
share_{d,e} = \frac{\sum_{i \in claims(d,e)} amount_i}{\sum_{i \in rankingClaims} amount_i}
$$

其中 `rankingClaims` 为当前 `department_range` 时间口径下过滤后的有效报销单据。

## 测试方案

- 后端单元测试：
  - 覆盖 `department_range=本年` 和 `department_range=全部`。
  - 验证部门排行返回 `employeeCount`。
  - 验证个人排行随口径变化。
  - 验证 `department_employee_mix` 返回正确人员占比数据。
- 前端源码测试：
  - 验证筛选选项包含本月、本季度、本年、全部。
  - 验证个人排行和部门排行都有筛选器。
  - 验证高额单据卡片包含部门人员报销占比图。
  - 验证服务层归一化新增字段。
- 构建验证：
  - `npm.cmd --prefix web run build`。
- 容器验证：
  - 后端测试在 `x-financial-main:/app` 中运行，超时不超过 60s。
  - 可用时通过接口检查 `department_employee_mix`、`employeeCount` 和 `department_range=全部`。

## 指标与验收

- 财务看板接口返回 `department_employee_mix`。
- 部门排行每项返回 `employeeCount`。
- 部门排行和个人排行都可选择本月、本季度、本年、全部。
- 个人排行标题不再固定“本月”。
- 高额单据卡片左侧显示部门人员报销占比饼图。
- 定向后端测试和前端构建通过。

## 风险与开放问题

- 当前工作区存在大量未提交变更，提交时必须只纳入本次相关文件。
- 如果浏览器自动化不可用，前端以源码测试、构建和接口验证为主要证据。
- `全部` 口径数据量可能更大，当前实现继续沿用内存聚合；后续数据量过大时再考虑 SQL 聚合优化。
