---
name: baoyu-war-room
description: 宝锐生物诊断原料作战室 — 角色分权HTML作战室（总经理/销售总监/业务员/销售支持），白底蓝调主题（宝锐蓝#1a73e8），整合ERP+月度报告多源数据、客户分级（大客户部/重点/非重点）、月度趋势、KPI对标、部门同比、过程指标。触发：作战室更新、数据刷新、新增模块。
category: productivity
---


# 宝锐生物诊断原料作战室

## 触发条件
- 用户要求构建/更新诊断原料作战室
- 要求角色分权视图（总经理/总监/业务员/支持）
- 要求客户分级/月度趋势/KPI对标/过程指标/部门同比
- 默认白底蓝调主题（宝锐蓝 #1a73e8，适合PPT截图）。深色主题为历史版本

## 与现有仪表盘的关系

| 项目 | baoyu-dashboard-update | baoyu-war-room（本技能） |
|------|----------------------|------------------------|
| 主题 | 白底蓝调科技风 | 白底蓝调（#f0f2f5底色，卡片白+阴影） |
| 业务线 | 全产品线混合 | 单业务线（诊断原料，`产品大类#=核酸诊断`） |
| 数据 | 主要来自工作汇报Excel | ERP+月度报告多源管线 |
| 角色 | 无角色区分 | 4角色独立视图 |
| 更新方式 | patch现有HTML | JSON+HTML增量更新 |
| 客户分级 | KA/A/B/C金额分级 | 大客户部/重点/非重点（静态清单） |

## 白底蓝调配色规范（v5.0）

因用户需要截图到PPT，作战室已从深色改为白底。配色以宝锐Logo蓝(#1a73e8)为主色：

```css
:root{--pri:#1a73e8;--pri2:#0059b3;--ok:#0d904f;--warn:#f4a236;
  --bad:#d93025;--bg0:#f0f2f5;--bg1:#ffffff;--bg2:#e8eaed;
  --text:#202124;--sub:#5f6368;--border:#e0e0e0;
  --radius:12px;--shadow:0 1px 3px rgba(0,0,0,.08)}
body{background:#f0f2f5}
.panel-card{background:#fff;border:1px solid #e8eaed;box-shadow:0 1px 3px rgba(0,0,0,.06)}
.topbar{background:#fff;height:48px;box-shadow:0 1px 4px rgba(0,0,0,.06)}
.topbar .logo span{color:var(--pri)}
```

**图表配色**：2024=灰#9e9e9e, 2025=金橙#f4a236, 2026=宝锐蓝#1a73e8。
**表格**：白底+浅灰表头(#f1f3f4)+宝锐蓝底部边框。

完整转换用Python一次性替换（不要逐个patch——容易产生转义错误）：
```python
# 在Python中读取HTML → 全面替换CSS变量 → 替换图表颜色 → 写回
# 然后用 node --check 验证JS语法
```

**页面全中文化**：所有图表图例、表格列头、月份标签都必须用中文（24年/25年/26年，1-12月）。

## 完整构建流程

### Phase 1: 数据管线（Python → JSON）

按优先级生成以下JSON文件（全部保存到 `/数据/` 目录）：

```python
# 1. 从ERP筛选诊断原料数据（产品大类# = 核酸诊断，排除测试/赠品/预测）
wb = openpyxl.load_workbook("erp销售订单_*.xlsx", read_only=True, data_only=True)
# 列映射：Col0=客户, Col1=合同日期, Col2=销售员, Col3=价税合计
# Col5=单据类型, Col13=是否赠品, Col22=区域#, Col24=产品大类#

# 2. diag_customers.json — 客户维度聚合
#    含：name, amount, orders, first_date, last_date, days_inactive, status, salespeople, top_products
#    status = active(≤90天) / at_risk(91-180天) / dormant(>180天)

# 3. diag_salespeople.json — 销售员维度聚合
#    含：name, amount, orders, customers, avg_order, monthly

# 4. diag_monthly.json — 月度营收趋势
#    含：month, amount, yoy_growth

# 5. diag_summary.json — 全局KPI
#    含：total_revenue, total_customers, active/at_risk/dormant, regions

# 6. diag_ltc_funnel.json — LTC管道（CRM+ERP混合）
#    阶段：strategic(战略>50万) / supply(批量>10万+5单) / trial(复购≥2单) / testing(测试中) / sample(送样) / lead(线索)
#    来源：CRM飞书活动导出(客户拜访纪要_*.xlsx) + ERP订单分级
#    CRM列映射：Col1=客户, Col4=创建时间, Col6=活动描述, Col8=活动类型

# 7. diag_kpis.json — KPI对标（从权威年度指标文件读取）
#    **使用 2026年度指标-诊断原料.xlsx，不要用 my_kpis.json**
#    含：name, dept, annual_target, diag_revenue, orders, customers, diag_target_ratio, status
#    Sheet1=大客户部（赵云浩1350w等），销售拓展部-年度指标--销售额目标（陈溪子670w等13人）
#    年度目标在列15，删除"（离职）"后缀，处理"-6月交接给XXX"复合名

# 合并增量数据（如5月新订单）：
# - 以客户名为key匹配，更新amount/last_date/days_inactive/status
# - 以销售员名为key匹配，更新amount/monthly
```

### Phase 2: HTML构建

**主题规范**：白底蓝调v5.0（见上方「白底蓝调配色规范」），非暗色。

**结构**：单HTML文件，包含4个 `role-view` div + JS全部内联

**顶部栏**：Logo + "诊断原料作战室"标题 + 4按钮角色切换器
```html
<button class="role-btn active" onclick="switchRole('gm')">👑 总经理</button>
<button class="role-btn" onclick="switchRole('director')">📊 销售总监</button>
<button class="role-btn" onclick="switchRole('sales')">🎯 业务员</button>
<button class="role-btn" onclick="switchRole('support')">🔧 销售支持</button>
```

**数据加载**：`Promise.all`加载6个JSON，失败时显示错误信息

**组件依赖**：
- Chart.js CDN（图表）
- hermes-table.js（表格排序/筛选/分页）
- 所有数据从JSON fetch，不硬编码

### Phase 3: 四维视图内容

#### 👑 总经理
- KPI行：总营收/客户数/活跃/人均产值
- LTC漏斗：6阶段可视化条（宽度=价值占比，高度=客户数）
- 月度趋势图：Chart.js **三线叠加折线图**（2024/2025/2026分年对比，12月横轴）
- **年度汇总表**：年份/营收/月均/月数/同比增长，含合计行
- KPI行改为年度分列：总营收 | 2024年 | 2025年 | 2026年(H1) | 客户数
- 区域分布：Chart.js doughnut
- Top20客户表：HermesTable（含状态标签）
- 销售员排行表：HermesTable

#### 📊 销售总监
- KPI行：团队人数/活跃/预警/沉睡
- 客户健康度饼图：活跃/预警/沉睡
- 预警清单：>90天未采购客户（标注金额+天数+销售员）
- KPI达成表：HermesTable（目标/实际/达成率+进度条）

#### 🎯 业务员
- Select下拉选人（显示名字+业绩概要）
- 个人KPI：业绩/订单数/客户数/客单价 + 年度目标+达成率（来自KPI数据）
- 月度趋势：个人6月Chart.js bar chart
- 我的客户表：HermesTable（过滤 salespeople 包含该销售员）

#### 🔧 销售支持
- KPI行：总客户/活跃/预警/沉睡/团队
- 客户状态饼图
- 沉睡客户清单（>180天）
## 数据源路径清单

| 数据 | 路径 | 说明 |
|------|------|------|
| 主ERP | `erp销售订单_2026032814241310_102319.xlsx` | 2024.05-2026.03, 25列 |
| **2024全年** | `2026订单分析/2024全年订单.xlsx` | 26K行, Jan-Dec完整, 有产品大类 |
| **2025全年** | `2026订单分析/2025全年订单.xlsx` | Jan-May ~4K行, 有产品大类 |
| **2026H1** | `2026订单分析/2026年1-6月订单.xlsx` | **16K行**, 完整6个月, 有产品大类 |
| CRM | `~/work/secure/客户拜访纪要_2024-2026_飞书导出.xlsx` | 23K行 |
| KPI指标 | `指标数据/2026年度指标-诊断原料.xlsx` | 15人6,050万 |
| **月度报告(权威)** | `hermas工作台数据库/月度销售额数据/1、2026上半年月度数据-诊断原料大客户销售部.xlsx` | 官方月报，数据比ERP导出更完整 |
| **月度报告(销售拓展)** | `hermas工作台数据库/月度销售额数据/2、2026上半年月度数据-诊断原料销售拓展部.xlsx` | 同上 |
| **指标明细(人均)** | `hermas工作台数据库/指标数据/指标明细/` | 人均分月销售数据(拜访/测试/订单) |
| 组织架构 | `hermas工作台数据库/销售组织架构/统一工作台运行及授权.xlsx` | 人员清单sheet |
| 客户清单 | `hermas工作台数据库/客户清单/诊断原料&生命科学客户清单20260630.xls` | 43行，.xls格式需xlrd |

## 月度报告优先原则

官方月度报告（`月度销售额数据/`下的Excel）比ERP导出更权威。当两者数据冲突时，月度报告优先。典型场景：ERP导出可能是月中截图（如6月27日），月度报告覆盖完整月。直接用月度报告的"实际完成"行替换JSON中的月度数据。

## 月度报告 → JSON 增量更新流程（Phase 1.5）

当用户更新了 `月度销售额数据/` 下的月度报告Excel文件，需要提取新维度数据并生成增量JSON，再更新作战室HTML。

### 数据文件结构

三个文件分别对应三个部门：
- `1、2026上半年月度数据-诊断原料大客户销售部.xlsx`（5个Sheet）
- `2、2026上半年月度数据-诊断原料销售拓展部.xlsx`（5个Sheet）
- `3、2026上半年月度数据-生命科学销售部.xlsx`（仅诊断原料需要前两个）

### Sheet 1：年度指标达成情况 → diag_monthly_targets.json

**结构**：Row4=部门/月份表头，Row5=月度目标行，Row6=实际完成行，Row7=达成率行
**列布局**：Col0=部门, Col1=空, Col2="月份", Col3=1月, Col4=2月, ..., Col8=6月

```python
def parse_target_sheet(ws, data_start_row=4):
    result = {}
    for row in ws.iter_rows(min_row=data_start_row, max_row=data_start_row+3, values_only=True):
        label = str(row[2]).strip() if row[2] else ''
        if '目标' in label:
            for i in range(1, 7):
                result[f"{i}月"] = result.get(f"{i}月", {})
                result[f"{i}月"]['target'] = round(float(row[2+i]))
        elif '完成' in label or '实际' in label:
            for i in range(1, 7):
                result[f"{i}月"] = result.get(f"{i}月", {})
                result[f"{i}月"]['actual'] = round(float(row[2+i]))
    for m in range(1, 7):
        key = f"{m}月"
        t = result[key].get('target', 0)
        a = result[key].get('actual', 0)
        result[key]['rate'] = round(a/t*100, 1) if t > 0 else 0
    return result
```

### Sheet 2：过程指标（月度绩效）→ diag_process_kpis.json

**⚠️ 两个部门列结构不同！**

大客户部（9列）：`[0]部门 [1]姓名 [2]拜访 [3]测试发放 [4]NGS发放 [5]反馈 [6]反馈率 [7]订单数 [8]订单金额`

销售拓展部（11列）：`[0]部门 [1]姓名 [2]拜访总数 [3]NGS拜访 [4]测试发放 [5]NGS测试 [6]反馈 [7]反馈率 [9]订单数 [10]订单金额`

数据从Row4开始，跳过"合计"行。反馈率在Excel中为小数（如0.81），需×100转百分比。

### Sheet "大客户部近三年销售数据" / "5）销售拓展部近三年销售数据" → diag_dept_monthly.json

**结构**：Row4=表头，Row5=2024年数据，Row6=2025年数据，Row7=2026年数据

**⚠️ 关键：列偏移 `row[2+m]`，不是 `row[3+m]`！**
- Row[0]=''（空）, Row[1]=部门名, Row[2]='2024年'
- Row[3]=1月, Row[4]=2月, ..., Row[14]=12月
- 所以获取第m月用 `row[2+m]`（m从1开始）

```python
def parse_3year_sheet(ws, data_start_row=4):
    result = {}
    for row in ws.iter_rows(min_row=data_start_row, max_row=data_start_row+3, values_only=True):
        year = str(row[2]).strip() if row[2] else ''
        if '2024' in year or '2025' in year or '2026' in year:
            yr = year[:4]
            result[yr] = {}
            for m in range(1, 13):
                try:
                    result[yr][f"{m}月"] = round(float(row[2+m]))  # NOT row[3+m]!
                except:
                    result[yr][f"{m}月"] = 0
    return result
```

### 生成的JSON文件

| JSON | 内容 |
|------|------|
| `diag_monthly_targets.json` | 两个部门+合计的月度目标/实际/达成率 |
| `diag_process_kpis.json` | 6月每人过程指标（拜访/测试/反馈/订单） |
| `diag_dept_monthly.json` | 两个部门2024-2026逐月营收 |
| `diag_summary.json`（更新） | 新增 `h1_2026` 和 `process_jun` 字段 |

### HTML新增模块

**总经理视图**：在月度营收趋势下方添加部门分拆柱状图（`canvas#gmDept`），大客户部+拓展部堆叠bar，2026 H1每月分拆。

**销售总监视图**：在预警清单下方添加：
1. 月度目标达成率图（`canvas#dirTarget`）— 目标折线 + 实际柱状图，红黄绿三色
2. 6月过程指标表（`#dirProcessTbl`）— HermesTable，全员拜访/测试/反馈率/订单/金额

**HTML修改方式**：三步走
1. Promise.all 增加3个新JSON fetch，声明全局变量
2. body中添加canvas容器div
3. renderGM()/renderDirector()中添加图表渲染代码

### ⚠️ patch工具JS代码注入陷阱

用 `patch` 工具插入多行JS代码时，`\n` 会被转义为字面字符串 `\\n`，导致JS语法错误。**必须用Python修复**：

```python
import re
with open('诊断原料作战室.html') as f: html = f.read()
# 修复script标签内的转义换行符
html = re.sub(
    r'<script>(.*?)</script>',
    lambda m: '<script>' + m.group(1).replace('\\n', '\n') + '</script>',
    html, flags=re.DOTALL
)
with open('诊断原料作战室.html', 'w') as f: f.write(html)
```

然后用 `node --check` 验证JS语法正确性。

## 详细资料（按需查阅）

> 以下文件不在本 SKILL.md 内，需要时再读；正文只保留每次都会用到的部分。

- **`references/data-pipeline.md`** — 含 3 节：客户分级（v4.0）— 大客户部 / 重点 / 非重点、集团归集与组织映射（v2.0）、完整数据管线（修正版）
- **`references/deploy-cdn.md`** — 含 1 节：外网访问
- **`references/details.md`** — 含 6 节：客户深耕 · 潜力股（v5.0）、重点客户清单匹配策略、常见陷阱、会议记录模板、销售支持视图升级、常见陷阱
- **`references/frontend-ui.md`** — 含 1 节：分年对比折线图

### 既有参考文件（原正文未引用，此处补齐索引）

- **`references/column-index-mapping.md`** — ERP Excel 列索引映射速查表
