## 新增功能 ### 商机中心 (/opportunity) - Stats统计卡片(商机总数、金额、赢单、转化率) - Pipeline商机管道(阶段Tab:全部/线索/谈判中/方案/赢单) - 商机列表真实数据渲染(来自crm_opportunity表) - 商机卡片详情(经销商、负责人、金额、概率) - Pipeline计数实时更新 ### 线索中心 (/lead) - 线索列表完整功能(CRUD) - 线索详情Drawer(基础信息 + 跟进记录Timeline) - 新建线索(含ERP客户关联、手机号验证) - 添加跟进记录(跟进方式、内容、下次时间) - 分配负责人(用户选择器,显示真实姓名) - 线索转经销商(自动创建商机) - 删除线索(逻辑删除) ## 后端开发 ### 数据库表 - crm_lead(线索表) - crm_lead_follow(线索跟进记录表) - crm_dealer(经销商表) - crm_opportunity(商机表) - crm_opportunity_follow(商机跟进记录表) - 数据字典初始化 ### API接口 - 线索管理:CRUD、详情、跟进、分配、转化 - 商机管理:列表查询 - 用户选择器:员工门户专用API ### 核心功能 - 线索转化自动创建经销商和商机 - 负责人翻译显示真实姓名(修复) - 手机号前后端双重格式验证(修复) ## 前端开发 ### 页面架构改进 - 商机中心:保留原CRM设计风格(Stats + Pipeline) - 线索中心:独立页面(完整线索管理) - 左侧菜单:独立菜单项(商机中心、线索中心) ### API模块 - src/api/crm/:线索和商机API类型定义和调用方法 - src/api/user/:用户选择器API ### 样式设计 - 商机中心:100%保持原CRM Pipeline设计风格 - 使用CSS变量系统(var(--radius-lg), var(--shadow-sm)等) - Pipeline Tab白色圆角设计 - 商机卡片阴影和hover效果 - 头像堆叠显示 ## 配置修改 - Gateway路由:添加CRM模块路由配置 - Gateway路由:添加system模块路由配置 - Aside菜单:拆分商机中心和线索中心 ## Bug修复 - 修复负责人显示手机号问题(UserNameTranslationImpl返回昵称) - 修复手机号格式验证缺失(前后端双重验证) - 修复商机管道设计风格不一致(完整复制原CRM样式) ## 文档 - CRM销售模块详细设计说明书V3.md - CRM线索转化API契约 - CRM线索转化开发计划 - CRM线索转化测试指引 - CRM线索管理测试指引 - CRM商机管理测试指引 - CRM架构改进报告 - CRM Bug修复报告 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
512 lines
11 KiB
Markdown
512 lines
11 KiB
Markdown
# CRM 线索中心模块 API 契约(V3 - 员工门户)
|
||
|
||
## 基础信息
|
||
|
||
- **服务归属**: hzhub-system (端口 8083)
|
||
- **API前缀**: `/crm/lead` (通过 Gateway 路由 `/crm/**` → hzhub-system)
|
||
- **前端项目**: hzhub-portal-employee (员工门户)
|
||
- **响应格式**: `R<T>` (org.hzhub.common.core.domain.R)
|
||
- **分页格式**: `TableDataInfo<T>` (org.hzhub.common.mybatis.core.page.TableDataInfo)
|
||
|
||
---
|
||
|
||
## 接口列表
|
||
|
||
### 1. 线索列表查询
|
||
|
||
**接口**: `GET /crm/lead/list`
|
||
|
||
**请求参数** (Query):
|
||
|
||
```json
|
||
{
|
||
"companyName": "XX贸易", // 公司名称(模糊查询)
|
||
"mobile": "13800000000", // 手机号
|
||
"intentLevel": "high", // AI意向等级(字典:crm_intent_level)
|
||
"riskLevel": "low", // 风险等级(字典:crm_risk_level)
|
||
"ownerUserId": 12345, // 负责人ID
|
||
"leadStatus": "following", // 线索状态(字典:crm_lead_status)
|
||
"sourceType": "activity", // 来源类型(字典:crm_lead_source)
|
||
"customerCode": "C001", // ERP客户编码
|
||
"pageNum": 1, // 页码
|
||
"pageSize": 10 // 每页大小
|
||
}
|
||
```
|
||
|
||
**响应**: `TableDataInfo<CrmLeadVo>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"rows": [
|
||
{
|
||
"leadId": 1001,
|
||
"tenantId": "000000",
|
||
"customerCode": "C001", // ERP客户编码
|
||
"companyName": "XX贸易有限公司",
|
||
"contactName": "张三",
|
||
"mobile": "138****0000", // 脱敏
|
||
"wechat": "zhangsan",
|
||
"province": "广东省",
|
||
"city": "深圳市",
|
||
"regionId": 100,
|
||
"regionName": "华南区", // 翻译
|
||
"sourceType": "activity",
|
||
"sourceTypeName": "活动", // 翻译
|
||
"industry": "食品",
|
||
"industryName": "食品行业", // 翻译
|
||
"storeCount": 20,
|
||
"intentLevel": "high",
|
||
"intentLevelName": "高意向", // 翻译
|
||
"aiScore": 85.5,
|
||
"riskLevel": "low",
|
||
"riskLevelName": "低风险", // 翻译
|
||
"ownerUserId": 12345,
|
||
"ownerUserName": "李四", // 翻译
|
||
"leadStatus": "following",
|
||
"leadStatusName": "跟进中", // 翻译
|
||
"nextFollowTime": "2026-05-20 14:00:00",
|
||
"createBy": 1,
|
||
"createByName": "系统管理员", // 翻译
|
||
"createTime": "2026-05-15 10:00:00"
|
||
}
|
||
],
|
||
"total": 100
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 线索详情查询
|
||
|
||
**接口**: `GET /crm/lead/{leadId}`
|
||
|
||
**路径参数**: `leadId` (Long)
|
||
|
||
**响应**: `R<CrmLeadVo>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": {
|
||
"leadId": 1001,
|
||
"customerCode": "C001",
|
||
"companyName": "XX贸易有限公司",
|
||
"contactName": "张三",
|
||
"mobile": "13800000000", // 未脱敏
|
||
// ... 其他字段同列表
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. 新增线索
|
||
|
||
**接口**: `POST /crm/lead`
|
||
|
||
**请求体**: `CrmLeadBo`
|
||
|
||
```json
|
||
{
|
||
"customerCode": "C001", // ERP客户编码(可选)
|
||
"companyName": "XX贸易有限公司",
|
||
"contactName": "张三",
|
||
"mobile": "13800000000",
|
||
"wechat": "zhangsan",
|
||
"province": "广东省",
|
||
"city": "深圳市",
|
||
"regionId": 100, // 关联 sys_dept
|
||
"sourceType": "activity",
|
||
"activityName": "春季招商会",
|
||
"referrerName": "王五",
|
||
"industry": "食品",
|
||
"companyScale": "50-100人",
|
||
"storeCount": 20,
|
||
"remark": "意向强烈,希望尽快对接"
|
||
}
|
||
```
|
||
|
||
**业务逻辑**:
|
||
|
||
1. 如果提供 `customerCode`,调用 `hzhub-erp:8082/erp/dynamic/v1/customer/detail` 拉取ERP客户信息
|
||
2. 自动填充客户基础信息(companyName, contactName, mobile等)
|
||
3. 校验手机号是否重复(同租户内)
|
||
4. 调用 LangChain4j AI服务分析意向等级(`hzhub-ai:6039/ai/analyze/intent` - **第二阶段实现**)
|
||
5. 根据区域规则(sys_dept)分配销售(owner_user_id - **可选**)
|
||
6. 返回成功消息
|
||
|
||
**响应**: `R<Void>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "新增成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4. 编辑线索
|
||
|
||
**接口**: `PUT /crm/lead`
|
||
|
||
**请求体**: `CrmLeadBo`
|
||
|
||
```json
|
||
{
|
||
"leadId": 1001,
|
||
"companyName": "XX贸易(已改名)",
|
||
"contactName": "张三",
|
||
"mobile": "13800000000",
|
||
// ... 其他可编辑字段
|
||
}
|
||
```
|
||
|
||
**响应**: `R<Void>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "修改成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 5. 删除线索
|
||
|
||
**接口**: `DELETE /crm/lead/{leadIds}`
|
||
|
||
**路径参数**: `leadIds` (String,逗号分隔,如 "1001,1002,1003")
|
||
|
||
**响应**: `R<Void>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "删除成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 6. 分配线索
|
||
|
||
**接口**: `PUT /crm/lead/assign`
|
||
|
||
**请求体**:
|
||
|
||
```json
|
||
{
|
||
"leadId": 1001,
|
||
"ownerUserId": 12345 // 新负责人ID(关联 sys_user)
|
||
}
|
||
```
|
||
|
||
**响应**: `R<Void>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "分配成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 7. 获取跟进记录列表
|
||
|
||
**接口**: `GET /crm/lead/follow/{leadId}`
|
||
|
||
**路径参数**: `leadId` (Long)
|
||
|
||
**响应**: `R<List<CrmLeadFollowVo>>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": [
|
||
{
|
||
"followId": 2001,
|
||
"leadId": 1001,
|
||
"followType": "phone",
|
||
"followTypeName": "电话", // 翻译
|
||
"content": "客户表达了合作意向,希望了解招商政策",
|
||
"aiSummary": "客户意向高,关注返点政策",
|
||
"nextFollowTime": "2026-05-20 14:00:00",
|
||
"followUserId": 12345,
|
||
"followUserName": "李四", // 翻译
|
||
"createTime": "2026-05-15 15:00:00"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 8. 添加跟进记录
|
||
|
||
**接口**: `POST /crm/lead/follow`
|
||
|
||
**请求体**: `CrmLeadFollowBo`
|
||
|
||
```json
|
||
{
|
||
"leadId": 1001,
|
||
"followType": "phone",
|
||
"content": "与客户沟通了具体合作细节,客户对返点政策满意",
|
||
"nextFollowTime": "2026-05-20 14:00:00"
|
||
}
|
||
```
|
||
|
||
**业务逻辑**:
|
||
|
||
1. 保存跟进记录
|
||
2. 调用 LangChain4j AI生成摘要(`hzhub-ai:6039/ai/summarize` - **第二阶段实现**)
|
||
3. 更新线索的 `nextFollowTime`
|
||
|
||
**响应**: `R<Void>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "跟进成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 9. 线索转经销商(第二阶段实现)
|
||
|
||
**接口**: `POST /crm/lead/convert`
|
||
|
||
**请求体**:
|
||
|
||
```json
|
||
{
|
||
"leadId": 1001,
|
||
"dealerName": "XX贸易",
|
||
"dealerCode": "DL20260001",
|
||
"customerCode": "C001" // ERP客户编码(可选)
|
||
}
|
||
```
|
||
|
||
**响应**: `R<Void>`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "转化成功"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 数据字典定义
|
||
|
||
### crm_lead_source(线索来源)
|
||
|
||
| 字典值 | 字典标签 | 备注 |
|
||
|---|---|---|
|
||
| activity | 活动 | 线下招商活动 |
|
||
| referral | 推荐 | 客户推荐 |
|
||
| website | 网站 | 官网咨询 |
|
||
| exhibition | 展会 | 行业展会 |
|
||
| wecom | 企业微信 | 企业微信咨询 |
|
||
| erp | ERP客户 | 从ERP客户转化 |
|
||
| other | 其他 | 其他来源 |
|
||
|
||
### crm_lead_status(线索状态)
|
||
|
||
| 字典值 | 字典标签 | 备注 |
|
||
|---|---|---|
|
||
| new | 新线索 | 刚录入,未分配 |
|
||
| following | 跟进中 | 已分配,正在跟进 |
|
||
| converted | 已转化 | 已转为经销商 |
|
||
| invalid | 已作废 | 线索无效 |
|
||
|
||
### crm_intent_level(AI意向等级)
|
||
|
||
| 字典值 | 字典标签 | AI评分范围 |
|
||
|---|---|---|
|
||
| high | 高意向 | >= 80 |
|
||
| medium | 中意向 | 60-80 |
|
||
| low | 低意向 | < 60 |
|
||
|
||
### crm_risk_level(风险等级)
|
||
|
||
| 字典值 | 字典标签 | 备注 |
|
||
|---|---|---|
|
||
| high | 高风险 | 需重点关注 |
|
||
| medium | 中风险 | 需持续跟踪 |
|
||
| low | 低风险 | 正常跟进 |
|
||
|
||
### crm_follow_type(跟进方式)
|
||
|
||
| 字典值 | 字典标签 |
|
||
|---|---|
|
||
| phone | 电话 |
|
||
| wecom | 企业微信 |
|
||
| visit | 拜访 |
|
||
| email | 邮件 |
|
||
| other | 其他 |
|
||
|
||
---
|
||
|
||
## 前端类型定义(TypeScript - 员工门户)
|
||
|
||
```typescript
|
||
// CrmLeadVo
|
||
export interface CrmLeadVo {
|
||
leadId: number;
|
||
tenantId: string;
|
||
customerCode?: string; // ERP客户编码
|
||
companyName: string;
|
||
contactName: string;
|
||
mobile: string;
|
||
wechat?: string;
|
||
province?: string;
|
||
city?: string;
|
||
regionId?: number;
|
||
regionName?: string;
|
||
sourceType?: string;
|
||
sourceTypeName?: string;
|
||
activityName?: string;
|
||
referrerName?: string;
|
||
industry?: string;
|
||
industryName?: string;
|
||
companyScale?: string;
|
||
storeCount?: number;
|
||
intentLevel?: string;
|
||
intentLevelName?: string;
|
||
aiScore?: number;
|
||
riskLevel?: string;
|
||
riskLevelName?: string;
|
||
ownerUserId?: number;
|
||
ownerUserName?: string;
|
||
leadStatus: string;
|
||
leadStatusName?: string;
|
||
convertedDealerId?: number;
|
||
nextFollowTime?: string;
|
||
remark?: string;
|
||
createBy: number;
|
||
createByName?: string;
|
||
createTime: string;
|
||
updateBy?: number;
|
||
updateByName?: string;
|
||
updateTime?: string;
|
||
}
|
||
|
||
// CrmLeadBo
|
||
export interface CrmLeadBo {
|
||
leadId?: number;
|
||
customerCode?: string; // ERP客户编码(可选)
|
||
companyName: string;
|
||
contactName: string;
|
||
mobile: string;
|
||
wechat?: string;
|
||
province?: string;
|
||
city?: string;
|
||
regionId?: number;
|
||
sourceType?: string;
|
||
activityName?: string;
|
||
referrerName?: string;
|
||
industry?: string;
|
||
companyScale?: string;
|
||
storeCount?: number;
|
||
ownerUserId?: number;
|
||
remark?: string;
|
||
}
|
||
|
||
// CrmLeadFollowVo
|
||
export interface CrmLeadFollowVo {
|
||
followId: number;
|
||
leadId: number;
|
||
followType: string;
|
||
followTypeName?: string;
|
||
content: string;
|
||
aiSummary?: string;
|
||
nextFollowTime?: string;
|
||
followUserId: number;
|
||
followUserName?: string;
|
||
createTime: string;
|
||
}
|
||
|
||
// CrmLeadFollowBo
|
||
export interface CrmLeadFollowBo {
|
||
followId?: number;
|
||
leadId: number;
|
||
followType: string;
|
||
content: string;
|
||
nextFollowTime?: string;
|
||
}
|
||
|
||
// TableDataInfo(员工门户已定义)
|
||
export interface TableDataInfo<T> {
|
||
code: number;
|
||
msg: string;
|
||
rows: T[];
|
||
total: number;
|
||
}
|
||
|
||
// R(员工门户已定义)
|
||
export interface R<T> {
|
||
code: number;
|
||
msg: string;
|
||
data?: T;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 注意事项(员工门户适配)
|
||
|
||
1. **多租户支持**: 所有查询自动过滤租户ID(TenantEntity)
|
||
2. **数据权限**: 根据 sys_dept 层级进行数据隔离
|
||
3. **敏感字段脱敏**: mobile 字段在列表查询时脱敏
|
||
4. **字段翻译**: 字典字段、用户ID、部门ID 自动翻译为名称
|
||
5. **操作日志**: 新增、编辑、删除操作记录日志
|
||
6. **防重复提交**: 新增操作防重复
|
||
7. **逻辑删除**: 使用 @TableLogic,删除时不物理删除
|
||
8. **ERP关联**: 如果提供 customerCode,自动拉取ERP客户信息
|
||
9. **无需Sa-Token注解**: 员工门户权限由Gateway统一控制
|
||
|
||
---
|
||
|
||
## ERP集成接口(hzhub-erp)
|
||
|
||
### 获取ERP客户详情
|
||
|
||
**接口**: `GET /erp/dynamic/v1/customer/detail`
|
||
|
||
**请求参数**: `customerCode`
|
||
|
||
**响应**: `R<CustomerVO>`
|
||
|
||
**CustomerVO**(员工门户已定义):
|
||
|
||
```typescript
|
||
interface CustomerVO {
|
||
customerCode: string;
|
||
customerName: string;
|
||
contactName: string;
|
||
salesAreaName: string;
|
||
brandName: string;
|
||
phone: string;
|
||
province: string;
|
||
city: string;
|
||
// ... 其他字段见 hzhub-portal-employee/src/api/erp/index.ts
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 开发优先级
|
||
|
||
- **P0(必须实现)**: 接口1-8(基础CRUD + 跟进)
|
||
- **P1(第二阶段)**: 接口9(线索转经销商)+ AI意向识别 + AI摘要生成
|
||
- **P2(第三阶段)**: AI风险分析 + AI预测模型 |