Files
hzhub/docs/crm-api-contract-v3.md
大壮 3f643ef31f feat: 完成CRM商机和线索管理模块开发
## 新增功能

### 商机中心 (/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>
2026-05-20 09:46:59 +00:00

512 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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_levelAI意向等级
| 字典值 | 字典标签 | 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. **多租户支持**: 所有查询自动过滤租户IDTenantEntity
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预测模型