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

11 KiB
Raw Blame History

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):

{
  "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>

{
  "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>

{
  "code": 200,
  "msg": "查询成功",
  "data": {
    "leadId": 1001,
    "customerCode": "C001",
    "companyName": "XX贸易有限公司",
    "contactName": "张三",
    "mobile": "13800000000",           // 未脱敏
    // ... 其他字段同列表
  }
}

3. 新增线索

接口: POST /crm/lead

请求体: CrmLeadBo

{
  "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>

{
  "code": 200,
  "msg": "新增成功"
}

4. 编辑线索

接口: PUT /crm/lead

请求体: CrmLeadBo

{
  "leadId": 1001,
  "companyName": "XX贸易已改名",
  "contactName": "张三",
  "mobile": "13800000000",
  // ... 其他可编辑字段
}

响应: R<Void>

{
  "code": 200,
  "msg": "修改成功"
}

5. 删除线索

接口: DELETE /crm/lead/{leadIds}

路径参数: leadIds (String逗号分隔如 "1001,1002,1003")

响应: R<Void>

{
  "code": 200,
  "msg": "删除成功"
}

6. 分配线索

接口: PUT /crm/lead/assign

请求体:

{
  "leadId": 1001,
  "ownerUserId": 12345               // 新负责人ID关联 sys_user
}

响应: R<Void>

{
  "code": 200,
  "msg": "分配成功"
}

7. 获取跟进记录列表

接口: GET /crm/lead/follow/{leadId}

路径参数: leadId (Long)

响应: R<List<CrmLeadFollowVo>>

{
  "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

{
  "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>

{
  "code": 200,
  "msg": "跟进成功"
}

9. 线索转经销商(第二阶段实现)

接口: POST /crm/lead/convert

请求体:

{
  "leadId": 1001,
  "dealerName": "XX贸易",
  "dealerCode": "DL20260001",
  "customerCode": "C001"             // ERP客户编码可选
}

响应: R<Void>

{
  "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 - 员工门户)

// 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(员工门户已定义):

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预测模型