# 澳美香港销售流向平台

## 页面级、字段级、逻辑级 PRD V3.2.0

**文档状态：** 开发对接基线  
**产品名称：** 澳美香港销售流向平台  
**产品别名：** 生意参谋  
**默认语言：** 繁体中文，支持中英文切换  
**适用范围：** 当前 HTML 演示版页面及正式生产版改造说明  
**数据范围：** 2025、2026 流向数据及责任区域、终端、小组/人员主数据  
**关联文档：** `docs/03-prd-v3.0.md`、`docs/data/02-flow-data-dictionary.md`、`docs/data/04-metric-definition.md`  

> 本文以当前 `index.html` 的实际页面结构、字段和交互为准。文中同时标识当前演示实现与正式生产要求，避免将前端演示权限、本地 JSON 或 localStorage 误认为生产能力。

## 1. 产品范围

平台包含两个一级业务域：

1. **生意参谋**：面向销售管理、GM、FIN 和销售人员查看 Private、Tender、客户管理数据。
2. **管理**：维护流向查询、区域档案、终端档案、销售小组/员工和修改日志。

### 1.1 当前页面入口

| 一级入口 | HTML 标识 | 默认状态 | 说明 |
|---|---|---|---|
| 生意参谋 | `data-tab="dashboard"` | 默认选中 | 经营分析与客户管理 |
| 管理 | `data-tab="management"` | 未选中 | 主数据、流向和日志维护 |

### 1.2 正式生产边界

| 能力 | 当前 HTML 演示版 | 正式生产版要求 |
|---|---|---|
| 数据源 | `data/*.json` | EIP API 与服务端同步任务 |
| 用户身份 | 固定 `admin` | 公司 SSO / AD |
| 角色切换 | 前端 `select` 演示 | 服务端 RBAC，不允许前端绕过 |
| 管理数据 | 浏览器 `localStorage` | 数据库持久化 |
| 修改日志 | 浏览器本地日志 | 服务端不可篡改审计日志 |
| 导出 | 前端生成 XLSX | 服务端校验权限后生成或签名下载 |
| 发布数据 | `demo` 可脱敏发布 | 生产数据只能通过授权 API 返回 |

## 2. 角色与权限

### 2.1 角色

| 角色代码 | 页面显示 | 主要职责 |
|---|---|---|
| `SALES` | 销售管理 | 查看授权 Private 和客户管理数据，维护职责范围内数据 |
| `GM` | GM | 查看全部 Private、Tender 和客户管理数据，执行经营分析 |
| `FIN` | FIN | 查看财务授权范围和 Tender 数据，执行核对和导出 |
| `DATA_ADMIN` | 数据管理员 | 维护主数据、导入、日志和数据质量 |

### 2.2 页面权限矩阵

| 功能 | SALES | GM | FIN | DATA_ADMIN |
|---|---:|---:|---:|---:|
| Private 生意参谋 | 授权范围 | 全部 | 授权范围 | 只读 |
| Tender 生意参谋 | 不可见 | 可见 | 可见 | 只读 |
| 客户管理 | 授权范围 | 全部 | 授权范围 | 只读 |
| 流向查询 | 授权范围 | 全部 | 审核范围 | 全部 |
| 区域/终端档案 | 职责范围 | 全部 | 只读或审核 | 全部 |
| 小组/员工管理 | 职责范围 | 全部 | 只读或审核 | 全部 |
| 导出 | 授权范围 | 允许 | 允许 | 审计授权 |
| 修改日志 | 只读 | 可查 | 可查 | 全部 |

正式生产必须同时在页面、API 和数据库查询层执行权限控制。前端隐藏不等于权限隔离。

## 3. 全局页面壳

### 3.1 顶部平台栏

| 字段/控件 | HTML 标识 | 类型 | 当前值/选项 | 规则 |
|---|---|---|---|---|
| 品牌名称 | `platformTitle` | 文本 | 澳美香港销售流向平台 | 支持中英文 |
| 品牌副标题 | `platformSubtitle` | 文本 | 香港销售流向管理 | 支持中英文 |
| 生意参谋 Tab | `data-tab="dashboard"` | 按钮 | 生意参谋 | 切换 `#dashboardPage` |
| 管理 Tab | `data-tab="management"` | 按钮 | 管理 | 切换 `#managementPage` |
| 登录状态 | `signedIn` | 文本 | 已登录 | 生产由会话决定 |
| 当前用户 | `salesManager`、`CURRENT_USER` | 文本 | 销售管理 / admin | 生产使用 SSO 用户 |
| 角色 | `#roleSelect` | 单选 | SALES、GM、FIN | 当前为演示角色切换 |
| 语言 | `#languageToggle` | 按钮 | 中/EN | 切换简体/繁体转换和英文文案 |
| 退出 | `#logoutButton` | 按钮 | 退出 | 清除会话并回到登录页 |

### 3.2 公共状态

所有页面和模块都必须定义以下状态：

- 初始加载
- 加载中
- 成功有数据
- 成功无数据
- 无权限
- 接口错误
- 数据过期
- 导出中
- 导出成功
- 导出失败
- 编辑未保存
- 保存成功
- 保存失败

当前静态 HTML 对加载和接口状态的支持有限，正式版需由 API 状态驱动。

<!-- PRD_MODULE: advisorPage START -->
## 4. 生意参谋页面

页面容器：`#dashboardPage`

### 4.1 全局年月筛选

| 字段 | HTML 标识 | 类型 | 默认值 | 校验/影响范围 |
|---|---|---|---|---|
| 年份 | `#advisorYearFilter` | 下拉单选 | 最新有数据年度 | 只允许可用年度 |
| 开始年月 | `#advisorStartMonth` | `month` | 该年度首个有数据月 | 不得晚于结束年月 |
| 结束年月 | `#advisorEndMonth` | `month` | 该年度最后有数据月 | 不得早于开始年月 |
| 截止日期 | `#advisorCutoff` | 只读文本 | 筛选范围内最大销售日期 | 不可编辑 |
| 重置 | `#advisorResetFilters` | 按钮 | 无 | 恢复年度默认范围 |

规则：

1. 年份切换后，开始年月和结束年月重置为该年度可用月份。
2. 开始年月和结束年月必须属于所选年份。
3. 开始年月大于结束年月时阻止刷新并显示错误提示。
4. 当前范围为空时，所有模块显示空状态，不使用上一轮数据。
5. 所有看板、图表、明细弹窗和导出继承当前年月范围。
6. 生命周期计算保留开始年月以前的历史数据作为回溯依据，但页面只展示范围内月份。
7. 2026 对比 2025 同期真实数据；2025 对比 2024 模拟同比数据。
8. 模拟同比必须在副标题、图例、tooltip 和导出表头中明确标记。

### 4.2 业务页签

| 页签 | HTML 标识 | 页面容器 | 可见规则 |
|---|---|---|---|
| Private | `data-advisor-tab="private"` | `data-advisor-view="private"` | 默认页签 |
| Tender | `data-advisor-tab="tender"` | `data-advisor-view="tender"` | GM、FIN 可查看 |
| 客户管理 | `data-advisor-tab="customers"` | `data-advisor-view="customers"` | 授权用户查看 |

### 4.3 快捷导航

容器：`#advisorQuickNav`

Private 模块：月度趋势、渠道结构、合作客户、销售组织、区域年累计、产品年累计。  
Tender 模块：Tender 销售、Tender 产品。  
客户管理模块：客户生命周期、潜在流失。

规则：

- 只渲染当前页签模块。
- 页面向下滚动时固定在顶部平台栏下方。
- 点击后平滑定位到目标模块。
- 移动端支持横向滚动。
- 已删除或隐藏模块不得出现在快捷导航。

<!-- PRD_MODULE: advisorPage END -->
<!-- PRD_MODULE: privatePage START -->
## 5. Private 页面规格

<!-- PRD_MODULE: privateKpis START -->
### 5.1 核心 KPI

容器：`#kpiGrid`

显示顺序：

1. 零售销售额
2. 合作客户
3. 新增客户
4. 流失客户
5. 潜在流失客户

| KPI 键 | 页面名称 | 主值 | 辅助说明 |
|---|---|---|---|
| `retailSales` | 零售销售额 | Private 净销售额 | 正向销售额 |
| `cooperationCustomers` | 合作客户 | 合作客户数 | 平均客单价 |
| `newCustomers` | 新增客户 | 年累计新增事件 | 本月有单且前 12 月无单 |
| `lostCustomers` | 流失客户 | 年累计流失事件 | 首次连续 12 月无单 |
| `atRiskCustomers` | 潜在流失客户 | 最新时点潜在流失数 | 连续 9–11 月无单 |
| `activeCustomers` | 近 12 个月下单客户 | 当前隐藏 KPI | 按 Ship to code 去重 |

所有 KPI 卡必须使用稳定的 `data-kpi-key`，禁止使用 `nth-child` 判断业务含义。

#### 零售销售额规则

- Private = 销售小组不等于 `Tender`。
- 净销售额 = 范围内所有 Private 流向销售金额求和。
- 贷项/退货按原始金额符号参与计算。
- 正向销售额为非 CR 交易金额合计。

#### 合作客户规则

- 仅统计交易类型为 `IV` 的 Private 流向。
- 按 `Ship to code` 去重。
- 合作客户数为当前年月范围内出现过 Private IV 流向的终端数。
- 平均客单价 = Private 净销售额 / 合作客户数。
- 合作客户数为 0 时平均客单价显示 `-`。

<!-- PRD_MODULE: privateKpis END -->
<!-- PRD_MODULE: privateTrend START -->
### 5.2 零售月度销售趋势

容器：`#privateTrendPanel`、图表 `#trendChart`

视图切换：

- `data-trend-view="monthly"`：当月
- `data-trend-view="ytd"`：YTD 累计

月度字段：

| 字段 | 说明 |
|---|---|
| `month` | 当前月份 |
| `sales` | 当前年度实际销售额 |
| `priorSales` | 去年同期销售额 |
| `yoy` | 销售额同比 |
| `qty` | 销售数量 |
| `qtyMom` | 销售数量环比 |
| `ytdSales` | 当前年度累计销售额 |
| `priorYtdSales` | 去年同期累计销售额 |

规则：

- 当月模式按月展示当前实际与去年同期。
- YTD 模式从筛选起始月开始累计。
- 去年同期按月份偏移 12 个月匹配。
- 去年同期为 0 或无数据时同比显示 `-`。
- 支持导出当前年月范围的月度数据。

导出按钮：`data-export="private-trend"`

<!-- PRD_MODULE: privateTrend END -->
<!-- PRD_MODULE: privateChannel START -->
### 5.3 渠道销售占比

容器：`#channelPanel`、图表 `#channelChart`

固定渠道：

- 私家医院
- 诊所
- 药店
- 贸易

每个渠道展示：

- 渠道名称
- 销售额
- 客户数
- 销售额占比

规则：

- 只统计 Private 数据。
- 客户数按 `Ship to code` 去重。
- 占比 = 渠道销售额 / Private 总销售额。
- 不展示 Tender 金额。
- 支持导出当前年份、年月范围、渠道名称、销售额、客户数和占比。

导出按钮：`data-export="private-channels"`

<!-- PRD_MODULE: privateChannel END -->
<!-- PRD_MODULE: cooperation START -->
### 5.4 合作客户分析

容器：`#cooperationPanel`

模块字段：

| 字段 | 说明 |
|---|---|
| `totalSales` | 当前范围 Private 净销售额 |
| `customers` | 当前范围 Private IV 合作客户数 |
| `averageOrderValue` | 净销售额 / 合作客户数 |
| `monthly.sales` | 月度销售额 |
| `monthly.customers` | 月度合作客户数 |
| `monthly.averageOrderValue` | 月度平均客单价 |
| `monthly.priorSales` | 去年同期销售额 |
| `monthly.priorCustomers` | 去年同期合作客户数 |
| `monthly.priorAverageOrderValue` | 去年同期平均客单价 |
| `monthly.yoy` | 月度同比 |

指标切换：

- 销售额
- 合作客户
- 平均客单价

显示条件弹窗：`#cooperationSettingsModal`

- 销售额
- 合作客户数
- 平均客单价
- 去年同比

交互规则：

1. 默认四项均显示。
2. 至少保留一项指标可见。
3. 取消、关闭或按 Esc 不改变当前页面。
4. 套用后才刷新图表和明细表。
5. 当前演示版保存到 `localStorage`；生产版保存到用户偏好服务。
6. 支持导出当前筛选范围、当前显示指标和同比数据。

<!-- PRD_MODULE: cooperation END -->
<!-- PRD_MODULE: salesOrganization START -->
### 5.5 销售组织表现

容器：`#salesOrganizationPanel`

模式：

- 按小组：`#salesGroupMode`
- 按个人：`#salesPersonMode`

筛选按钮：

- `#salesGroupFilterTrigger`
- `#salesPersonFilterTrigger`

筛选弹窗：`#selectionModal`

支持：搜索、全选、清空、取消、套用、多选。

数据字段：

- 小组/人员名称
- 当前年度销售额
- 去年同期销售额
- 同比
- 客户数
- 月度销售额
- 月度客户数
- 归属类型

规则：

- 默认全部选中。
- 主图展示选中对象合计的当前实际与去年同期。
- 明细区域展示每个对象的销售额、同比和客户数。
- 终端主数据中的销售人员归属优先于流向记录。
- 缺失人员时按小组稳定分配演示人员，并标记“模拟归属”。
- 导出继承当前模式、对象选择、年月范围和同比口径。

导出按钮：`data-export="sales-organization"`

<!-- PRD_MODULE: salesOrganization END -->
<!-- PRD_MODULE: regionAnnual START -->
### 5.6 区域年累计销售

容器：`#regionAnnualPanel`、列表 `#regionAnnualChart`

默认显示前 20 条，容器约显示 10 行并支持垂直滚动。

固定字段：

| 字段 | 说明 |
|---|---|
| `rank` | 当前年度销售额排名 |
| `name` | 区域名称 |
| `sales` | 当前年度销售额 |
| `customers` | 按 Ship to code 去重的客户数 |
| `share` | 区域销售额占比 |
| `priorSales` | 去年同期销售额 |
| `yoy` | 同比 |

规则：

- 按当前年度销售额降序。
- 左侧保留当前年度与去年同期条形对比。
- 客户数、占比、去年同期销售额和同比分栏显示。
- 长名称通过 tooltip 查看完整值。
- 去年无数据时同比显示 `
- 支持导出全部区域数据，不只导出屏幕前 20 条。

导出按钮：`data-export="private-regions"`

<!-- PRD_MODULE: regionAnnual END -->
<!-- PRD_MODULE: productAnnual START -->
### 5.7 产品年累计销售

容器：`#productAnnualPanel`、列表 `#productAnnualChart`

默认显示前 10 条，支持滚动查看完整结果。

字段与区域年度排名相同：排名、产品名称、当年销售额、客户数、占比、去年同期销售额、同比。

规则：

- 按当年销售额降序。
- 同额时按产品名称排序。
- 客户数按 Ship to code 去重。
- 占比以当前 Private 总销售额为分母。
- 支持导出全部产品排名。

导出按钮：`data-export="private-products"`

<!-- PRD_MODULE: productAnnual END -->
<!-- PRD_MODULE: privatePage END -->
<!-- PRD_MODULE: tenderPage START -->
## 6. Tender 页面规格

页面容器：`#tenderContent`

Tender 判定规则：

```text
normalize(销售小组) === "tender"
```

其余销售小组均归入 Private。

### 6.1 权限状态

| 角色 | Tender 页状态 |
|---|---|
| SALES | 显示无权限提示，不渲染 Tender 金额 |
| GM | 显示完整 Tender 页面 |
| FIN | 显示完整 Tender 页面 |

容器：`#tenderAccessPanel`

<!-- PRD_MODULE: tenderKpis START -->
### 6.2 Tender KPI

容器：`#tenderKpiGrid`

字段：

- Tender 净销售额
- Tender 客户数
- Tender 正向销售额

客户数按 `Ship to code` 去重。

<!-- PRD_MODULE: tenderKpis END -->
<!-- PRD_MODULE: tenderTrend START -->
### 6.3 Tender 销售业绩

容器：`#tenderPanel`、图表 `#tenderTrendChart`

视图：

- 当月
- YTD

字段：月份、Tender 实际销售额、去年同期销售额、同比、YTD 累计值。

导出按钮：`data-export="tender-trend"`

<!-- PRD_MODULE: tenderTrend END -->
<!-- PRD_MODULE: tenderProducts START -->
### 6.4 Tender 产品业绩

容器：`#tenderProductPanel`、列表 `#tenderProductChart`

展示全部 Tender 产品，固定高度滚动。

字段：排名、产品名称、当年销售额、客户数、占比、去年同期销售额、同比。

导出按钮：`data-export="tender-products"`

<!-- PRD_MODULE: tenderProducts END -->
<!-- PRD_MODULE: tenderPage END -->
<!-- PRD_MODULE: customerPage START -->
## 7. 客户管理页面规格

页面容器：`data-advisor-view="customers"`

<!-- PRD_MODULE: customerLifecycle START -->
### 7.1 客户生命周期

容器：`#privateLifecyclePanel`、图表 `#privateLifecycleChart`

按月展示：

- 新增客户
- 潜在流失客户
- 流失客户
- 新增占比
- 潜在流失占比
- 流失占比
- YTD 新增
- YTD 流失
- 最新潜在流失

销售人员筛选：`#salesPersonLifecycleFilter`

支持搜索、多选、全选、清空、取消和套用。

<!-- PRD_MODULE: customerLifecycle END -->
### 7.2 客户生命周期逻辑

1. 只使用 `TRANSACTION TYPE = IV` 判断下单。
2. 按 `Ship to code` 作为客户/终端唯一主键。
3. 当月有 IV 且前 12 个完整月无 IV，记为新增事件。
4. 连续 9–11 个月无 IV，计入潜在流失。
5. 连续满 12 个月无 IV，潜在流失减少 1，流失事件增加 1。
6. 当月重新下 IV，立即退出潜在流失。
7. 重新下单后再次连续 9 个月无单，可以再次进入潜在流失。
8. 同一统计月内，新增、潜在流失和流失状态互斥。
9. 筛选开始月以前的数据仅用于历史回溯，不直接显示。

<!-- PRD_MODULE: atRisk START -->
### 7.3 潜在流失客户

容器：`#atRiskPanel`、图表 `#atRiskChart`

图表：

- 按 1–12 月展示潜在流失客户数量。
- 尚未到达的月份不显示。
- 不再按 9/10/11 月分段展示。
- 点击月份柱可查看该月客户明细。

月份筛选按钮：`#atRiskMonthFilterTrigger`

支持：全部月份、单选、多选、搜索、全选、清空、取消、套用。

客户名单弹窗：`#listModal`

字段：

- 状态月份
- 客户名称
- Ship to code
- 区域
- 销售人员
- 最后下单月
- 未下单月数
- 状态

规则：

- 弹窗约占 80vw × 80vh。
- 表格支持滚动。
- 选择全部月份时保留每个客户每月的状态记录。
- 支持导出当前月份选择对应的全部明细。

<!-- PRD_MODULE: atRisk END -->
<!-- PRD_MODULE: customerPage END -->
<!-- PRD_MODULE: managementPage START -->
## 8. 管理页面规格

页面容器：`#managementPage`

Tab 顺序：

1. 流向查询
2. 区域档案
3. 终端档案
4. 销售小组/员工

<!-- PRD_MODULE: regionManagement START -->
### 8.1 区域档案

容器：`#regionPanel`、列表 `#regionManager`

字段：区域 ID、区域名称、是否启用、分配销售人员、操作。

操作：

- 新增区域
- 编辑区域 ID和名称
- 启用/停用
- 分配销售人员
- 删除

规则：

- 区域名称在责任区域中唯一。
- 修改自动记录修改时间和修改人。
- 删除前需校验是否有终端或流向引用。
- 正式版删除建议改为停用，避免破坏历史数据。

<!-- PRD_MODULE: regionManagement END -->
<!-- PRD_MODULE: terminalManagement START -->
### 8.2 终端档案

容器：`#terminalPanel`、列表 `#terminalManager`

字段：

- 客户 ID
- 客户名称
- 所在区域
- 客户类型
- 合作状态
- 销售小组
- 销售人员
- 操作

客户类型：私家医院、诊所、药店、贸易。  
合作状态：合作、不合作、待确认。

筛选字段：所在区域、客户类型、客户名称/ID、销售小组、销售人员。

规则：

- `Ship to code` 为终端唯一键。
- 区域、销售小组和销售人员必须来自主数据。
- 新导入终端默认合作状态为待确认。
- 终端修改记录字段、修改前值、修改后值、修改人和时间。

<!-- PRD_MODULE: terminalManagement END -->
<!-- PRD_MODULE: flowManagement START -->
### 8.3 流向查询

容器：`#flowPanel`、表格 `#flowManager`

模式：当月流向、历史流向。

筛选字段：产品、终端、单号、开始日期、结束日期。

#### 固定查询字段

| 编号 | 字段 | HTML/数据键 | 类型 | 当前月可编辑 |
|---|---|---|---|---:|
| 1 | 年份 | `year` | integer | 否 |
| 2 | 月份 | `month` | `YYYY-MM` | 否 |
| 3 | 发票日期 | `invoiceDate` | date | 否 |
| 4-1 | 发票编码 | `invoiceNo` | string | 否 |
| 4-2 | 发票行号 | `invoiceLineNo` | string | 否 |
| 5 | 买方名称 | `buyerName` | string | 否 |
| 6 | SDS 物料代码 | `sdsItemCode` | string | 否 |
| 7 | 物料描述 | `materialDesc` | string | 否 |
| 8 | 销售数量 | `sellingQty` | decimal | 否 |
| 9 | 单价 | `unitPrice` | decimal | 否 |
| 10 | 销售金额 | `salesValue` | decimal HKD | 否 |
| 11 | 区域 | `territory` | string | 否 |
| 12 | 销售组 | `salesGroup` | string | 是 |
| 13 | 销售人员 | `salesPerson` | string | 是 |
| 14 | 渠道 | `channel` | string | 否 |
| 15 | 收货方代码 | `shipToCode` | string | 否 |
| 16 | 收货方名称 | `shipToName` | string | 否 |
| 17 | 收货地址 1 | `shipToAddress1` | string | 否 |
| 18 | 收货地址 2 | `shipToAddress2` | string | 否 |

编号 4 展开为两列，因此实际表格共 19 个物理列。

#### 流向编辑规则

1. 当月流向默认展示当前数据月。
2. 当月仅允许暂存修改销售组和销售人员。
3. 历史流向全部只读。
4. 修改后显示待确认数量、取消更改和确认更改。
5. 取消清空所有暂存值并恢复原值。
6. 确认后批量写入，成功后清除待确认栏。
7. 确认失败时保留暂存内容并提示失败原因。
8. 每个确认字段必须写入审计日志。

<!-- PRD_MODULE: flowManagement END -->
<!-- PRD_MODULE: salesGroupManagement START -->
### 8.4 销售小组/员工

容器：`#salesGroupPanel`、列表 `#salesGroupManager`

字段：

- 销售小组
- 小组人员
- 负责区域数量
- 负责终端数量
- 操作

操作：新增小组、新增员工、修改小组人员、查看负责区域、查看负责终端、删除。

规则：

- 一个小组可以包含多个销售人员。
- 区域和终端通过责任归属关联到小组。
- 区域和终端数量点击后打开明细弹窗。
- 修改小组或人员必须写入修改日志。
- 正式版需要支持员工启用/停用，不直接删除有历史业绩的员工。

<!-- PRD_MODULE: salesGroupManagement END -->
<!-- PRD_MODULE: auditLog START -->
### 8.5 修改日志

容器：`#auditLogPanel`、列表 `#auditLogManager`

字段：模块、对象 ID、修改内容、修改前、修改后、修改人、修改时间。

正式版额外记录：用户 ID、请求 ID、IP、操作结果、失败原因和数据版本。

<!-- PRD_MODULE: auditLog END -->
<!-- PRD_MODULE: managementPage END -->
## 9. 字段与数据规则

### 9.1 流向底层保留字段

即使不在 19 列查询表展示，底层仍需保留：

- 交易类型
- 产品组
- 客户分组
- 原始客户代码
- `soldToCode`
- `soldToName`
- `vendorBatchNo`
- 效期
- 数据来源
- 导入批次号
- 导入时间
- 数据质量状态
- 记录版本

### 9.2 主键与去重

- 终端和合作客户主键：`Ship to code`。
- 流向业务幂等键：来源系统 + 发票编码 + 发票行号 + 物料代码 + Ship to code。
- 若 EIP 提供稳定行 ID，优先使用 EIP 行 ID，同时保留组合键用于对账。
- 空 Ship to code 不纳入客户去重，但必须进入数据质量异常清单。

### 9.3 显示格式

- 金额单位：港币 HKD。
- 金额采用千位分隔。
- 百分比默认保留一位小数。
- 数量和客户数默认显示整数。
- 无去年同期基数显示 `-`。
- 空数据使用明确空状态，不显示 `NaN`、`undefined` 或空白表格。
- 客户名称、地址、代码和产品名称输出前必须进行 HTML 转义。

## 10. 同比、YTD 与导出逻辑

### 10.1 同比

```text
yoy = (current - prior) / abs(prior)
```

- 当前范围 2026-01 至 2026-06，对比 2025-01 至 2025-06。
- 当前范围为 2025 时，对比 2024 模拟同比数据。
- prior 为 0 或不存在时显示 `-`。
- 2024 模拟值只能用于演示和明确标识的同比展示。

### 10.2 YTD

- 按当前筛选起始月开始累计。
- 每个月显示截至该月的累计值。
- 导出必须保留当月值和累计值，避免只导出累计结果无法核对。

### 10.3 导出

导出模块：

- `private-trend`
- `private-channels`
- `cooperation`
- `sales-organization`
- `private-regions`
- `private-products`
- `tender-trend`
- `tender-products`
- `at-risk-details`
- `lifecycle-details`

通用规则：

1. 继承当前年度、开始年月、结束年月、页签和模块筛选。
2. 文件名包含模块、年度和截止年月。
3. 导出列名使用当前页面繁体字段。
4. 2024 模拟数据必须在表头或文件说明中标记。
5. 权限不足时不生成文件。
6. 生成失败时显示明确错误，不静默失败。
7. 正式版由服务端重新校验筛选和权限。

## 11. 交互验收标准

### 页面结构

- 一级 Tab 只有生意参谋和管理。
- 生意参谋包含 Private、Tender、客户管理三个业务页签。
- Private 页面不出现 Tender 金额。
- SALES 角色不能查看 Tender 数据。
- 快捷导航只显示当前页签模块并支持置顶定位。

### 筛选与图表

- 年份、开始年月、结束年月默认值正确。
- 非法年月范围不能刷新。
- 月度趋势和 YTD 数据正确切换。
- 区域排名最多显示 20 条，产品排名最多显示 10 条，均支持滚动。
- 区域和产品固定列显示销售额、客户数、占比、去年同期和同比。

### 客户生命周期

- 合作客户按 Private IV 和 Ship to code 去重。
- 重新下单后潜在流失即时减少。
- 第 12 个月潜在流失减 1，流失增加 1。
- 新增、潜在流失和流失不重复。
- 客户明细弹窗支持月份筛选和导出。

### 管理功能

- 流向表字段顺序严格为 19 个物理列。
- 当月流向可暂存销售组和人员修改。
- 无修改时不显示确认栏。
- 取消恢复原值，确认写入并生成日志。
- 历史流向只读。
- 区域、终端、小组/员工字段可编辑并写入日志。

## 12. 需求追踪编号

| 编号范围 | 内容 |
|---|---|
| `PAGE-001` 至 `PAGE-010` | 页面和页签 |
| `FIELD-001` 至 `FIELD-050` | 页面字段和流向字段 |
| `METRIC-001` 至 `METRIC-020` | KPI、同比、YTD、生命周期 |
| `RULE-001` 至 `RULE-030` | 筛选、权限、编辑、导出和状态转换 |
| `DIALOG-001` 至 `DIALOG-010` | 弹窗和下钻 |
| `EXPORT-001` 至 `EXPORT-010` | 导出模块 |
| `QA-001` 至 `QA-050` | 测试和验收用例 |

每条需求必须关联：页面容器、字段键、指标定义、接口、测试用例和发布版本。

## 13. 开发交接说明

前端开发优先依据本文的页面容器、HTML 标识、字段键和交互规则实现。  
后端开发优先依据数据字典、指标口径、权限矩阵和导出规则实现。  
数据开发优先依据 Ship to code 主键、Tender/Private 分类、生命周期回溯和对账规则实现。  
测试人员优先依据第 11 节验收标准和 `docs/04-requirements-traceability.md` 编写用例。

任何新需求如果改变字段、指标或状态转换，必须同步更新本 PRD、数据字典、指标口径、需求追踪矩阵和测试用例。
