# 客户档案全维度数据架构 (2026-07-11 最终版)

## 七维度数据聚合

| 维度 | 数据源 | API/方法 | 实测 |
|------|--------|---------|------|
| 💰 ERP价格 | 本地 `数据/pricing/{客户}.json` | JSON fetch | 全量1,197客户 |
| 🔗 决策链 | MCP MQL WHERE精确匹配 | `SELECT 客户名称, 决策链URL链接 WHERE 客户名称 = "x"` | ✅ 可读; ❌ update_field不持久化 |
| 👤 联系人 | `list_related_workitem` + relation_id | `客户-联系人关联` (relation_1715033831836) | 圣湘:50人 |
| 💼 商机 | `get_view_detail`(视图)+ `list_related_workitem` | 视图 sm7MYQiNg, 528条 → 商机-客户关联(relation_1706630317962) | 101家有商机 |
| 🔴 客诉 | `get_view_detail`(视图) + 二级跳转 | 视图 TDWUJhYHg, 64条 → 客诉→销售订单→客户 | 43家有客诉 |
| 🏗️ 客户项目 | `get_view_detail`(视图) + relation | 视图 uAhLe5eIR, 64条 → 客户项目流程-客户(relation_1712924598201) | 43家有项目 |
| ✅ 待办 | localStorage | `cust_todos_{客户名}` key | 增删勾选 |

## 各维度飞书链接格式

所有面板行右侧均有 `查看→` 链接，点击跳转飞书详情页：
| 维度 | URL格式 |
|------|---------|
| 👤 联系人 | `https://project.feishu.cn/xsguanli/lxr/detail/{id}` |
| 💼 商机 | `https://project.feishu.cn/xsguanli/story/detail/{id}` |
| 🏗️ 项目 | `https://project.feishu.cn/csrw/test/detail/{id}` |
| 🔴 客诉 | `https://project.feishu.cn/br-shgl/khts/detail/{id}` |
| 🔗 决策链 | Wiki直链（如 `https://i16l6v9noru.feishu.cn/wiki/...`） |

## 集团决策链面板

客户档案显示整个集团的决策链，非仅当前客户：
- 从 `数据/customer_groups.json` 加载集团映射（17个集团，53条）
- 当前客户加粗显示，同集团成员列出各自的Wiki链接
- 缺失决策链的标橙色⚠标记

## 核心突破

### 视图API批量提取模式

当MCP `search_view_by_title` 查不到视图时，用Chrome AppleScript找到视图URL：
```python
# 从URL提取view_id:
# https://project.feishu.cn/xsguanli/storyView/sm7MYQiNg → sm7MYQiNg
# https://project.feishu.cn/br-shgl/workObjectView/khts/TDWUJhYHg → TDWUJhYHg
# https://project.feishu.cn/csrw/workObjectView/test/uAhLe5eIR → uAhLe5eIR

# 批量获取
view = mcp('get_view_detail', {
    'project_key': '6593cd71471290e3cc6be6e6',
    'view_id': 'sm7MYQiNg', 'page_size': 50, 'page_num': 1
})
```

### 二级跳转（客诉→订单→客户）

客诉不直接关联客户，需要：
```
客诉(wid) → list_related_workitem(relation_1727283754885) → 销售订单(id)
 → 切换到销售管理空间
 → list_related_workitem(dynamic relation from list_workitem_relations) → 客户(name)
```
每笔销售订单的客户关联relation_id不同，需用 `list_workitem_relations` 动态获取。

### relation_id 必须精确  
- 商机→客户: `1706630317962`（正确） vs `1706635236372`（其他关联，返回0）
- 必须实际 `list_workitem_relations` 后从中选取正确的relation_id

### update_field 陷阱
决策链URL链接是表单模板字段。`update_field` 返回 `mcp_result: ""`（看起来成功）但不实际持久化。

## profile JSON 结构
```json
{"customer":"圣湘生物科技股份有限公司","work_item_id":"4196204802",
 "group_name":"圣湘集团",
 "pricing":{"total_amount":11738288,"total_orders":2366,"top_products":[...]},
 "contacts":[{"name":"段正兴","id":"...","url":"https://project.feishu.cn/..."},...],
 "opportunities":[{"name":"DNA单管","status":"沟通需求确认","creator":"张文蝶","id":"...","url":"..."},...],
 "complaints":[{"name":"20260710-青岛嘉智-...","status":"销售部经理审核中","id":"...","url":"..."},...],
 "projects":[{"name":"20260710-细菌八重...","status":"项目立项申请中","id":"...","url":"..."},...],
 "decision_url":"...","group_chains":[{"name":"圣湘（上海）","url":"..."},...]}
```

## HTML渲染
`工具/客户档案.html` — 首页客户筛选列表 → 点击进入档案详情。
每面板行右侧有 `查看→` 蓝色链接，点击跳转飞书对应详情页。

### 首页必须是筛选列表（用户铁律）

**严禁默认展示某个客户**。首页设计为：
- 搜索框 + 客户清单表格（客户名/累计采购/决策链/联系人/商机/项目/客诉列）
- 点击行进入档案详情页（顶栏出现 `← 返回列表` 按钮）
- 仅显示 **KA客户清单**（大客户销售部89家），非全部1,197家
- 数据源：`数据/pricing/_key_customers.json`（从KA清单Excel + ERP价格匹配生成）

### 批量生成档案的安全模式

MCP调用极易返回None导致脚本崩溃。**每条MCP调用必须加None保护**：

```python
# ❌ 危险写法（会在第N个客户崩溃，前功尽弃）
rr = mcp('list_related_workitem', {...})
contacts = [{'name': i.get('name', '')} for i in rr.get('list', [])]  # rr可能为None

# ✅ 安全写法
rr = mcp('list_related_workitem', {...})
contacts = [{'name': i.get('name',''), 'id': str(i.get('id',''))} 
            for i in (rr.get('list') or [])] if rr else []
```

**关键安全模式**：
- 所有 `for items in xxx.values()` 前确保 xxx 非 None：`for items in (r.get('data',{}))).values()`
- 所有 `for item in items` 前确保 items 非 None：`for item in (items or [])`
- MCP函数本身包在 `try/except` 中，超时/网络错误全部返回 None
- 批量生成时用一个 `existing` set 跟踪已完成，崩溃后从断点续跑
- 每个客户先生成空profile兜底，token/field逐个填充

### 进度监控

长时间批量任务必须提供监控页（`工具/档案生成进度.html`）：
- 每3秒轮询索引JSON的 `contacts` 字段计数进度
- 进度条 + 已完成客户列表 + 用时显示
- 完成后显示 "🎉 全部完成!"
