409 lines
13 KiB
Markdown
409 lines
13 KiB
Markdown
# 团队 CRM 查询与项目追踪设计
|
||
|
||
## 目标
|
||
|
||
在保持现有只读 CRM MCP 和受控项目写入兼容的前提下,增加:
|
||
|
||
- 基于 CRM 正式团队关系的查询;
|
||
- 团队与成员双层客户、跟进和项目统计;
|
||
- 长期未跟进客户查询,并明确标注当前 NocoBase 不支持的闭环能力;
|
||
- 客户归属、实际记录人、参与人员等角色的明确区分;
|
||
- CRM 项目完整跟进时间线;
|
||
- 北京时间、完整分页、稳定 JSON 解析和数据质量提示。
|
||
|
||
本设计以 2026-07-24 从目标 NocoBase 读取的集合和字段元数据为依据。元数据盘点未读取或修改业务记录。
|
||
|
||
## 已确认的数据模型
|
||
|
||
### 团队与用户
|
||
|
||
团队集合为 `t_team_management`(团队管理)。
|
||
|
||
| 业务含义 | 字段 | 类型 | 目标 |
|
||
| --- | --- | --- | --- |
|
||
| 团队名 | `f_team_name` | string | - |
|
||
| 团队负责人 | `tdgl_manager` | belongsToMany | `users` |
|
||
| 团队成员 | `tdgl_team_members` | belongsToMany | `users` |
|
||
|
||
`users` 中存在反向关系:
|
||
|
||
- `yh_belong_teams`:所属团队;
|
||
- `yh_managed_team`:管理的团队;
|
||
- `yh_status`:员工状态。
|
||
|
||
员工状态中已确认:
|
||
|
||
| 标签 | 内部值 |
|
||
| --- | --- |
|
||
| 正式员工 | `nkluuumb1r1` |
|
||
| 实习生 | `n7cnn29kzo1` |
|
||
| 已离职 | `bpsfm63uc8i` |
|
||
| 交接中 | `yv6pkhjxtfz` |
|
||
| 临时员工 | `4g6m1y5uy1s` |
|
||
|
||
“正式团队成员”定义为:
|
||
|
||
1. 用户出现在团队的 `tdgl_team_members` 关系中;
|
||
2. 用户的 `yh_status` 等于 `nkluuumb1r1`。
|
||
|
||
负责人可以有多人,不应在 MCP 中强制压缩为单个负责人。
|
||
|
||
系统另有 `departments` 树形部门集合。部门和 CRM 团队是两套不同关系,首版团队查询以 `t_team_management` 为准,不用部门关系替代团队关系。
|
||
|
||
### 客户角色
|
||
|
||
客户集合为 `t_nt3pjadelqi`。
|
||
|
||
| 字段 | 标题 | 建议语义 |
|
||
| --- | --- | --- |
|
||
| `kehu_manage_person` | 管理人 | 管理或权限相关人员,不代表客户归属 |
|
||
| `kehu_followup_person` | 跟进人 | 客户归属人员 |
|
||
| `kehu_lookup_people` | 可查看人 | ACL 可见人员,不代表业务协同 |
|
||
| `createdBy` | 创建人 | 数据创建者,不代表客户负责人 |
|
||
|
||
上述前三个字段均可能包含多人。客户归属以 `kehu_followup_person` 为准。MCP 不应将
|
||
`kehu_manage_person` 或 `kehu_lookup_people` 计为客户归属或协同贡献,也不应把
|
||
`createdBy` 当作客户负责人。
|
||
|
||
由于 `kehu_followup_person` 是多值关系,接口使用复数 `customer_owners`,不能从列表
|
||
顺序推断唯一主负责人。
|
||
|
||
### 跟进角色与分类
|
||
|
||
跟进集合为 `t_07667a5evtr`。
|
||
|
||
| 字段 | 标题 | 建议语义 |
|
||
| --- | --- | --- |
|
||
| `createdBy` | 创建人 | 跟进记录提交人 |
|
||
| `gjjl_followup_person` | 参与跟进人员 | 明确的参与人员 |
|
||
| `gjjl_client` | 客户 | 关联客户 |
|
||
| `gjjl_client_contacts` | 客户联系人 | 关联联系人 |
|
||
| `f_gjjl_projects` | 相关项目 | 关联 CRM 项目 |
|
||
| `f_srysmjkwfq1` | 跟进时间 | 业务发生时间 |
|
||
| `gjjl_followup_type` | 跟进类型 | 沟通方式 |
|
||
| `f_19iplxz0nds` | 跟进内容 | 跟进正文 |
|
||
| `f_hskl7gjvos9` | 状态 | 记录状态 |
|
||
|
||
已确认的跟进方式:
|
||
|
||
- 邮件
|
||
- 电话
|
||
- 视频会议
|
||
- 拜访/请客
|
||
- 审厂/来访
|
||
- 论坛/大会
|
||
- 代理跟进情况代填
|
||
|
||
已确认的跟进状态为“审批中、OK、迟交、无效”。它更接近记录审批或提交质量状态,不能直接解释为下一步事项的完成状态。
|
||
|
||
首版角色输出必须同时保留:
|
||
|
||
- `record_creator`:`createdBy`,只表示记录提交人;
|
||
- `participants`:`gjjl_followup_person`;
|
||
- `customer_owners`:关联客户的 `kehu_followup_person`;
|
||
- `customer_management_users`:关联客户的 `kehu_manage_person`,仅作为补充信息;
|
||
- `team_managers`:命中团队的 `tdgl_manager`。
|
||
|
||
`createdBy` 不一定是实际跟进人,因此不得用于实际跟进贡献统计。实际跟进贡献只按
|
||
`gjjl_followup_person` 统计;多人参与时每位参与人各获得一次参与贡献,同时团队总跟进
|
||
记录按记录 ID 去重。`record_creator` 仅用于审计和数据质量检查。
|
||
|
||
### CRM 项目
|
||
|
||
CRM 项目集合为 `t_projects`,与现有 MCP 项目写入使用同一集合。
|
||
|
||
已确认关系:
|
||
|
||
- 客户:`f_projects_client` / 外键 `client_ID`;
|
||
- 联系人:`f_projects_contacts`;
|
||
- 跟进记录:`f_projects_followup_records`;
|
||
- 项目进展:`f_projects_progress`;
|
||
- 项目情况更新:`f_u28gm9h2uzl`;
|
||
- 附件:`f_projects_attachments`。
|
||
|
||
项目进展为:
|
||
|
||
- 询价阶段
|
||
- 已报价
|
||
- 送样
|
||
- 已定点
|
||
- SOP
|
||
- 终止
|
||
|
||
项目情况更新集合为 `t_qxeepjvi39s`,包含:
|
||
|
||
- 项目:`f_k37rbpi4vye`;
|
||
- 更新日期:`f_6g9fw5oqef9`;
|
||
- 更新内容:`f_ei16g0ihwwd`;
|
||
- 附件:`f_6pk5pv17i27`;
|
||
- 创建人:`createdBy`。
|
||
|
||
当前没有独立的报价、样品、测试或定点事件集合映射。首版只能使用项目阶段和项目情况更新正文展示这些信息,不能可靠统计每类业务事件的数量或状态。
|
||
|
||
### 另一套项目管理模型
|
||
|
||
系统还存在:
|
||
|
||
- `market_pm`(项目管理);
|
||
- `project_updates`(项目节点)。
|
||
|
||
这套模型有项目负责人、预计完成时间、项目状态,以及节点负责人、节点状态和节点预计完成时间,但没有已确认的客户关系,也没有与 `t_projects` 的关联字段。
|
||
|
||
因此:
|
||
|
||
- `t_projects` 是 CRM 项目查询的权威来源;
|
||
- `market_pm` / `project_updates` 作为独立的任务型项目模型;
|
||
- 在没有稳定关联键之前,两套项目不得按名称自动合并;
|
||
- 如后续需要统一展示,返回值必须带 `project_source`,例如 `crm` 或 `management`。
|
||
|
||
## 当前数据模型缺口
|
||
|
||
跟进记录中没有已确认的以下结构化字段:
|
||
|
||
- 下一步事项;
|
||
- 事项责任人;
|
||
- 截止日期;
|
||
- 完成状态;
|
||
- 完成时间;
|
||
- 优先级;
|
||
- 风险类型。
|
||
|
||
因此“逾期未完成事项”和“无下一步的重点项目”不能仅凭现有跟进记录准确计算。
|
||
|
||
本项目不得修改 NocoBase 数据模型,因此不新增行动项集合,也不增加跟进字段。以下能力
|
||
明确跳过:
|
||
|
||
- 精确查询逾期未完成事项;
|
||
- 按行动项完成状态统计;
|
||
- 权威判断跟进是否存在下一步;
|
||
- 权威判断下一步责任人和截止日期。
|
||
|
||
不从跟进正文推断权威的下一步、风险或逾期状态。
|
||
|
||
报价、样品、测试等完整链路同样需要结构化事件模型。项目阶段只能表示当前状态,不能还原每次状态变化的时间和责任人。
|
||
|
||
## 配置扩展
|
||
|
||
建议在 `config.json` 增加以下可配置映射,默认值采用本次确认字段:
|
||
|
||
```json
|
||
{
|
||
"timezone": "Asia/Shanghai",
|
||
"teams": {
|
||
"resource": "t_team_management",
|
||
"idField": "id",
|
||
"nameField": "f_team_name",
|
||
"managerField": "tdgl_manager",
|
||
"memberField": "tdgl_team_members",
|
||
"userStatusField": "yh_status",
|
||
"formalUserStatusValue": "nkluuumb1r1"
|
||
},
|
||
"roles": {
|
||
"customerOwnerField": "kehu_followup_person",
|
||
"customerManagementField": "kehu_manage_person",
|
||
"customerViewerField": "kehu_lookup_people",
|
||
"followupCreatorField": "createdBy",
|
||
"followupParticipantField": "gjjl_followup_person"
|
||
},
|
||
"crmProjects": {
|
||
"contactField": "f_projects_contacts",
|
||
"followupField": "f_projects_followup_records",
|
||
"updateField": "f_u28gm9h2uzl",
|
||
"updateResource": "t_qxeepjvi39s",
|
||
"updateProjectField": "f_k37rbpi4vye",
|
||
"updateDateField": "f_6g9fw5oqef9",
|
||
"updateContentField": "f_ei16g0ihwwd"
|
||
}
|
||
}
|
||
```
|
||
|
||
不设计或预留会写入 NocoBase 的闭环字段。相关能力在 MCP capability 中明确标为不可用。
|
||
|
||
## MCP 工具设计
|
||
|
||
### 团队发现
|
||
|
||
```text
|
||
list_teams(query?, include_members=false, formal_members_only=true)
|
||
resolve_team(query)
|
||
get_team(team_id, include_members=true, formal_members_only=true)
|
||
```
|
||
|
||
团队解析规则与负责人解析一致:无匹配或多匹配返回结构化候选结果,不静默选择。
|
||
|
||
### 查询工具兼容扩展
|
||
|
||
现有工具保留原参数,并增加:
|
||
|
||
```text
|
||
list_customers(..., team?, team_id?)
|
||
list_followups(..., team?, team_id?, project_id?, followup_type?, record_status?)
|
||
crm_overview(..., team?, team_id?)
|
||
```
|
||
|
||
`team` 和 `team_id` 不得同时提供。团队过滤使用正式成员 ID 集合,客户和跟进分别应用对应角色关系,不能把“团队客户”和“团队实际跟进”混成同一口径。
|
||
|
||
### 团队统计
|
||
|
||
```text
|
||
team_crm_overview(
|
||
team,
|
||
date_from?,
|
||
date_to?,
|
||
formal_members_only=true,
|
||
include_member_breakdown=true
|
||
)
|
||
```
|
||
|
||
建议返回:
|
||
|
||
```json
|
||
{
|
||
"team": {},
|
||
"period": {},
|
||
"totals": {
|
||
"assigned_customers": 0,
|
||
"owned_customers": 0,
|
||
"followup_records": 0,
|
||
"active_customers": 0,
|
||
"active_projects": 0
|
||
},
|
||
"by_member": [],
|
||
"by_customer": [],
|
||
"by_followup_type": [],
|
||
"by_project_stage": [],
|
||
"contribution_basis": {
|
||
"participant": "gjjl_followup_person"
|
||
}
|
||
}
|
||
```
|
||
|
||
同一条多人参与的跟进:
|
||
|
||
- 团队总量只计一次;
|
||
- 成员贡献中每位参与人各计一次;
|
||
- 返回 `unique_followups` 和 `participation_count`,防止将两种口径混淆。
|
||
|
||
### 项目追溯
|
||
|
||
```text
|
||
get_project(project_id, include_contacts=true, include_followups=true)
|
||
get_project_timeline(project_id, date_from?, date_to?)
|
||
list_projects(customer_id?, team?, stage?, updated_since?)
|
||
```
|
||
|
||
时间线事件来源:
|
||
|
||
- 项目创建与阶段;
|
||
- 项目情况更新;
|
||
- 关联跟进记录;
|
||
- 联系人;
|
||
- 附件元数据。
|
||
|
||
每个事件返回 `event_type`、`occurred_at`、`actors`、`source_resource` 和 `source_id`。
|
||
|
||
### 长期未跟进客户
|
||
|
||
现有模型可以支持:
|
||
|
||
```text
|
||
list_stale_customers(team?, owner?, inactive_days=30, as_of?)
|
||
```
|
||
|
||
该工具仅依据客户最后一次有效跟进时间计算。以下工具不实现:
|
||
|
||
- `list_action_items`
|
||
- `list_overdue_action_items`
|
||
|
||
不得以跟进记录的“迟交”状态代替行动项逾期状态。
|
||
|
||
## 时间、分页与统计规则
|
||
|
||
### 北京时间
|
||
|
||
- 服务内部使用带时区的 `datetime`;
|
||
- NocoBase UTC 时间转换到 `Asia/Shanghai`;
|
||
- `dateOnly` 保持日期不做时区偏移;
|
||
- 输出统一为 ISO 8601,例如 `2026-07-24T15:30:00+08:00`;
|
||
- 响应增加 `"timezone": "Asia/Shanghai"`。
|
||
|
||
### 分页
|
||
|
||
保持现有 `limit`、`offset` 参数兼容,但修复任意 offset:
|
||
|
||
- 不再直接用 `offset // limit + 1` 近似;
|
||
- 读取覆盖目标窗口的底层页并在服务层精确切片;
|
||
- 返回 `limit`、`offset`、`total`、`has_more`、`next_offset`;
|
||
- 内部全量统计循环读取所有页;
|
||
- 设置独立的最大扫描记录数和超时保护,超过时返回明确的截断警告。
|
||
|
||
### 聚合
|
||
|
||
- 团队总量按记录 ID 去重;
|
||
- 成员贡献保留参与次数;
|
||
- 所有聚合返回统计口径;
|
||
- “无效”跟进不计入有效贡献;“审批中、OK、迟交”保留并分别展示;
|
||
- 不再使用固定 50 个分组作为完整统计结果。
|
||
|
||
## JSON 与元数据稳定性
|
||
|
||
`nb` 输出解析需要支持 stdout 混入非 JSON 日志的情况:
|
||
|
||
1. 继续设置 `NB_CLI_LOG_DISABLED=1` 和 `NB_SKIP_STARTUP_UPDATE=1`;
|
||
2. 首先尝试对完整 stdout 执行 `json.loads`;
|
||
3. 失败时使用 `json.JSONDecoder.raw_decode` 定位完整顶层 JSON 对象;
|
||
4. 仅接受唯一、完整的 JSON 对象;
|
||
5. 其余文本作为已脱敏诊断信息,不进入正常 MCP 数据;
|
||
6. 无法可靠定位时返回 `nb_invalid_json`,不返回部分业务数据;
|
||
7. API Token 必须同时从命令、stdout 和 stderr 中脱敏。
|
||
|
||
## 数据质量提示
|
||
|
||
查询响应增加统一的 `data_quality_warnings`,包括:
|
||
|
||
- 客户有多个归属跟进人;
|
||
- 跟进没有参与人员,无法归属实际贡献;
|
||
- 跟进没有客户或项目;
|
||
- 项目更新没有业务日期;
|
||
- 项目阶段有变化但没有结构化事件记录;
|
||
- 团队成员不是正式员工;
|
||
- 统计因扫描上限被截断。
|
||
|
||
## 兼容与实施顺序
|
||
|
||
### 第一阶段:基础稳定性
|
||
|
||
- 北京时间转换;
|
||
- 精确分页和全量聚合;
|
||
- JSON 日志混入容错;
|
||
- 统一响应元数据和测试。
|
||
|
||
### 第二阶段:团队查询
|
||
|
||
- 团队配置、解析和成员发现;
|
||
- 客户与跟进增加团队过滤;
|
||
- 分离客户归属跟进人、管理人、记录创建人和参与人员;
|
||
- 团队整体与成员贡献统计。
|
||
|
||
### 第三阶段:CRM 项目时间线
|
||
|
||
- CRM 项目只读查询;
|
||
- 关联客户、联系人、跟进和项目情况更新;
|
||
- 长期未跟进客户查询。
|
||
|
||
现有工具名、参数和默认紧凑输出保持兼容。新字段只做增量添加;团队和项目查询工具为新工具。现有 stdio 模式继续只读,HTTP 写入范围仍只限当前项目字段和附件操作。
|
||
|
||
## 已确认业务决策
|
||
|
||
1. 客户归属以 `kehu_followup_person`(跟进人)为准。
|
||
2. `createdBy` 不一定是实际跟进人,只作为记录提交人展示。
|
||
3. 不修改 NocoBase 数据模型;现有模型不支持的闭环能力直接跳过。
|
||
|
||
## 实施时采用的默认口径
|
||
|
||
1. 实际跟进贡献按 `gjjl_followup_person`(参与跟进人员)统计。
|
||
2. 正式成员只包含 `yh_status = nkluuumb1r1`,排除实习、离职、交接中和临时员工。
|
||
3. `t_projects` 作为 CRM 项目权威表;不与 `market_pm` 按名称自动合并。
|
||
4. 团队统计默认排除“无效”跟进;“审批中、OK、迟交”保留并分别展示。
|
||
5. 长期未跟进默认阈值为 30 天,允许调用方覆盖。
|