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>
This commit is contained in:
512
docs/crm-api-contract-v3.md
Normal file
512
docs/crm-api-contract-v3.md
Normal file
@@ -0,0 +1,512 @@
|
||||
# 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预测模型
|
||||
Reference in New Issue
Block a user