## 新增功能 ### 商机中心 (/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>
33 KiB
CRM销售自动化(渠道版)执行级详细设计说明书 V3
1. 文档说明
1.1 文档目标
本文档用于指导HZHub项目中CRM销售自动化(渠道版)系统的:
- 数据库设计(适配 MySQL 8 + MyBatis-Plus)
- 后端接口开发(适配 hzhub-system 服务)
- 前端页面开发(适配 hzhub-portal-employee 员工门户)
- AI能力集成(适配 LangChain4j + Weaviate)
- 企业微信集成
- 自动化流程配置(适配 warm-flow)
- 权限与组织体系建设(适配 Sa-Token)
本文档属于"开发执行版设计文档 V3",针对**员工门户(hzhub-portal-employee)**进行定制化适配。
1.2 与 V1/V2 版本的主要差异
| 方面 | V1 版本 | V2 版本 | V3 版本(员工门户适配) |
|---|---|---|---|
| 前端项目 | Vue3 + Element Plus(通用) | Vben Admin(管理后台) | Element Plus(员工门户) |
| 前端路径 | /api/** |
/crm/**(管理后台) |
/crm/**(员工门户) |
| 现有基础 | 无 | 无 | 已有CRM和经销商页面 |
| 数据来源 | 独立CRM表 | 独立CRM表 | ERP客户数据 + CRM表 |
| 技术栈 | Python FastAPI | LangChain4j | LangChain4j + Vue3 Composition API |
| UI风格 | 未指定 | Vben Admin 企业级 | Element Plus 卡片式 |
| 用户角色 | 通用销售人员 | 管理员 + 销售 | 企业员工 + 销售人员 |
1.3 员工门户现有功能
已实现页面
| 页面 | 路径 | 功能 | 数据来源 |
|---|---|---|---|
| 销售CRM | /crm |
商机管道视图 + 客户列表 | ERP Customer(动态API) |
| 经销商管理 | /dealer |
经销商卡片视图 + 筛选 | ERP Customer(动态API) |
现有API
// ERP 客户数据(动态API)
GET /erp/dynamic/v1/customer/list // 客户列表
GET /erp/dynamic/v1/customer/detail // 客户详情
GET /erp/dynamic/v1/customer/sales-areas // 销区列表
GET /erp/dynamic/v1/customer/brands // 品牌列表
现有数据模型(CustomerVO)
interface CustomerVO {
customerCode: string; // 客户编码
customerName: string; // 客户名称
companyCode: string; // 公司编码
companyName: string; // 公司名称
brand: string; // 品牌
brandName: string; // 品牌名称
contactName: string; // 联系人
salesAreaCode: string; // 销区编码
salesAreaName: string; // 销区名称
salesPersonCode: string; // 销售人员编码
salesPersonName: string; // 销售人员姓名
province: string; // 省
city: string; // 市
isStop: number; // 状态(0合作中,1停用)
// ... 其他字段
}
2. 系统总体架构
2.1 HZHub 集成架构(员工门户)
服务归属
CRM模块归属于 hzhub-system 服务(端口 8083),前端在 hzhub-portal-employee 实现。
┌─────────────────────────────────────────┐
│ hzhub-portal-employee (员工门户) │
│ Vue3 + Element Plus + TypeScript │
│ Port: 5137 │
│ 已有: /crm (销售CRM) + /dealer (经销商) │
└────────────┬────────────────────────────┘
│
┌────────┴────────┐
│ hzhub-gateway │ (API Gateway, port 8080)
│ Spring Cloud │ JWT auth, routing
└───┬──────┬──────┘
│ │
┌───▼──────────┐
│ hzhub-system │ CRM 模块归属服务
│ 8083 │ (Users, Roles, CRM)
└─────────────┘
Gateway 路由配置
在 hzhub-gateway/src/main/resources/application.yml 中添加 CRM 路由:
spring:
cloud:
gateway:
routes:
# CRM 路由(新增)
- id: hzhub-crm
uri: lb://hzhub-system
predicates:
- Path=/crm/**
filters:
- StripPrefix=1 # 去除 /crm 前缀
2.2 技术栈适配(员工门户)
| 层级 | HZHub 技术栈 | 说明 |
|---|---|---|
| 前端Web | Vue3 + Element Plus + TypeScript | hzhub-portal-employee 已部署 |
| 前端路由 | Vue Router | 静态路由配置(staticRouter.ts) |
| 状态管理 | Pinia + persistedstate | 已集成 |
| HTTP请求 | hook-fetch + SSE | 已集成 |
| 后端 | Spring Boot 3.5.8 + MyBatis-Plus | hzhub-system 服务 |
| 数据库 | MySQL 8.0 | 已部署 |
| ERP数据 | SQL Server 2008 R2 | hzhub-erp 服务 |
| 缓存 | Redis 7 | 已部署 |
| 向量数据库 | Weaviate 1.25.0 | 已部署 |
| AI服务 | LangChain4j + LangGraph4j | hzhub-ai 服务集成 |
| 文件存储 | MinIO | 已部署 |
| 工作流 | warm-flow 1.8.2 | 已集成在 hzhub-system |
| 权限 | Sa-Token | 已集成,JWT-based |
3. 数据库设计规范(HZHub 适配)
3.1 通用字段规范
所有CRM业务表继承 TenantEntity,包含以下字段:
| 字段 | 类型 | 注解 | 说明 |
|---|---|---|---|
| tenant_id | varchar(20) | 无注解(继承) | 租户ID(多租户) |
| create_dept | bigint | @TableField(fill = INSERT) | 创建部门 |
| create_by | bigint | @TableField(fill = INSERT) | 创建人 |
| create_time | datetime | @TableField(fill = INSERT) | 创建时间 |
| update_by | bigint | @TableField(fill = INSERT_UPDATE) | 更新人 |
| update_time | datetime | @TableField(fill = INSERT_UPDATE) | 更新时间 |
注意: 不需要手动添加 id 字段,使用 MyBatis-Plus 的 @TableId 注解。
3.2 Entity 实体类规范
基类继承
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("crm_lead")
public class CrmLead extends TenantEntity {
@TableId(value = "lead_id", type = IdType.ASSIGN_ID)
private Long leadId;
// 业务字段...
/**
* 删除标志(0代表存在 1代表删除)
*/
@TableLogic
private Integer delFlag;
}
4. 线索中心模块设计(适配员工门户)
4.1 模块目标
用于管理潜在经销商,支持:
- 多渠道线索接入
- 关联ERP客户数据(customer_code)
- AI意向识别(LangChain4j)
- AI风险分析
- 自动分配销售
- 商机转化
4.2 数据表设计
4.2.1 crm_lead(线索表)
| 字段 | 类型 | 注解 | 说明 |
|---|---|---|---|
| lead_id | bigint | @TableId(ASSIGN_ID) | 主键 |
| customer_code | varchar(100) | - | ERP客户编码(关联) |
| company_name | varchar(200) | - | 公司名称 |
| contact_name | varchar(100) | - | 联系人 |
| mobile | varchar(50) | - | 手机号 |
| varchar(100) | - | 微信号 | |
| province | varchar(50) | - | 省 |
| city | varchar(50) | - | 市 |
| region_id | bigint | - | 区域ID(关联 sys_dept) |
| source_type | varchar(50) | - | 来源类型(字典:crm_lead_source) |
| activity_name | varchar(100) | - | 活动名称 |
| referrer_name | varchar(100) | - | 推荐人 |
| industry | varchar(100) | - | 行业(字典:crm_industry) |
| company_scale | varchar(100) | - | 公司规模(字典:crm_scale) |
| store_count | int | - | 门店数 |
| intent_level | varchar(20) | - | AI意向等级(字典:crm_intent_level) |
| ai_score | decimal(5,2) | - | AI评分 |
| risk_level | varchar(20) | - | 风险等级(字典:crm_risk_level) |
| owner_user_id | bigint | - | 负责人(关联 sys_user) |
| lead_status | varchar(50) | - | 状态(字典:crm_lead_status) |
| converted_dealer_id | bigint | - | 转化经销商ID |
| del_flag | int | @TableLogic | 删除标志 |
继承字段: tenant_id, create_dept, create_by, create_time, update_by, update_time
关键设计:
customer_code关联 ERP 客户数据(可选,支持同步)- 如果
customer_code存在,自动从 ERP 拉取基础信息 - 线索转化时,创建
crm_dealer并关联customer_code
4.2.2 crm_lead_follow(线索跟进记录)
| 字段 | 类型 | 说明 |
|---|---|---|
| follow_id | bigint | 主键 |
| lead_id | bigint | 线索ID |
| follow_type | varchar(50) | 跟进方式(字典:crm_follow_type) |
| content | text | 跟进内容 |
| ai_summary | text | AI摘要 |
| next_follow_time | datetime | 下次跟进时间 |
| follow_user_id | bigint | 跟进人(关联 sys_user) |
| del_flag | int | 删除标志 |
4.3 接口设计
4.3.1 创建线索
API: POST /crm/lead
请求参数:
{
"customerCode": "C001", // ERP客户编码(可选)
"companyName": "XX贸易有限公司",
"contactName": "张三",
"mobile": "13800000000",
"wechat": "zhangsan",
"province": "广东省",
"city": "深圳市",
"industry": "食品",
"storeCount": 20
}
业务逻辑:
- 如果提供
customer_code,调用hzhub-erp:8082/erp/dynamic/v1/customer/detail拉取客户信息 - 自动填充客户基础信息(companyName, contactName, mobile 等)
- 校验手机号是否重复(同租户内)
- 调用 LangChain4j AI服务分析意向等级(
hzhub-ai:6039/ai/analyze/intent) - 自动生成AI评分
- 根据区域规则(sys_dept)分配销售(owner_user_id)
- 创建自动跟进任务(warm-flow)
4.3.2 线索转经销商
API: POST /crm/lead/convert
请求参数:
{
"leadId": 12345,
"dealerName": "XX贸易",
"dealerCode": "DL20260001",
"customerCode": "C001" // ERP客户编码(可选)
}
逻辑:
- 创建
crm_dealer数据 - 如果
customer_code存在,同步 ERP 客户数据 - 迁移历史跟进记录到
crm_dealer_follow - 创建初始商机(
crm_opportunity) - 更新线索状态为"已转化"
- 触发 warm-flow 工作流(经销商审批)
4.4 前端页面设计(Element Plus - 员工门户)
4.4.1 扩展现有CRM页面
路径: hzhub-portal-employee/src/pages/crm/index.vue(已存在,需扩展)
现有功能:
- 商机管道视图(Pipeline)
- 客户列表表格(使用 ERP CustomerVO)
- 新建客户对话框(基础功能)
新增功能:
1. 线索列表Tab页
在现有CRM页面添加Tab切换:
<el-tabs v-model="activeTab">
<el-tab-pane label="商机管道" name="pipeline">
<!-- 现有管道视图 -->
</el-tab-pane>
<el-tab-pane label="线索管理" name="leads">
<!-- 新增线索管理 -->
</el-tab-pane>
<el-tab-pane label="经销商" name="dealers">
<!-- 新增经销商管理 -->
</el-tab-pane>
</el-tabs>
2. 线索管理模块
筛选栏:
<div class="filter-bar">
<el-input v-model="filters.keyword" placeholder="搜索公司、联系人..." />
<el-select v-model="filters.intentLevel" placeholder="AI意向等级">
<el-option label="高意向" value="high" />
<el-option label="中意向" value="medium" />
<el-option label="低意向" value="low" />
</el-select>
<el-select v-model="filters.ownerUserId" placeholder="负责人">
<!-- 用户选择器 -->
</el-select>
<el-date-picker v-model="filters.createTimeRange" type="daterange" />
<el-button type="primary" @click="loadLeads">搜索</el-button>
</div>
线索列表(Element Plus Table):
<el-table :data="leadList" v-loading="loading">
<el-table-column prop="companyName" label="公司名称">
<template #default="{ row }">
<el-tag v-if="row.intentLevel === 'high'" type="danger" effect="plain">
{{ row.companyName }}
</el-tag>
<span v-else>{{ row.companyName }}</span>
</template>
</el-table-column>
<el-table-column prop="contactName" label="联系人" />
<el-table-column prop="mobile" label="手机">
<template #default="{ row }">
{{ maskPhone(row.mobile) }}
</template>
</el-table-column>
<el-table-column prop="intentLevel" label="AI意向">
<template #default="{ row }">
<el-badge :value="row.aiScore" :type="getIntentBadgeType(row.intentLevel)">
{{ getIntentLabel(row.intentLevel) }}
</el-badge>
</template>
</el-table-column>
<el-table-column prop="ownerUserName" label="负责人">
<template #default="{ row }">
<el-avatar :size="32">{{ row.ownerUserName?.charAt(0) }}</el-avatar>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button type="primary" link @click="showLeadDetail(row)">详情</el-button>
<el-button type="primary" link @click="showFollowDrawer(row)">跟进</el-button>
<el-button type="success" link @click="convertToDealer(row)">转经销商</el-button>
</template>
</el-table-column>
</el-table>
3. 线索详情 Drawer
<el-drawer v-model="showDetailDrawer" title="线索详情" size="50%">
<el-descriptions :column="2" border>
<el-descriptions-item label="公司名称">{{ currentLead.companyName }}</el-descriptions-item>
<el-descriptions-item label="联系人">{{ currentLead.contactName }}</el-descriptions-item>
<el-descriptions-item label="手机">{{ currentLead.mobile }}</el-descriptions-item>
<el-descriptions-item label="ERP客户编码">
<el-link v-if="currentLead.customerCode" @click="viewErpCustomer">
{{ currentLead.customerCode }}
</el-link>
</el-descriptions-item>
<!-- AI分析信息 -->
<el-descriptions-item label="AI意向等级">
<el-progress :percentage="currentLead.aiScore" :color="getIntentColor(currentLead.intentLevel)" />
</el-descriptions-item>
<el-descriptions-item label="风险等级">
<el-tag :type="getRiskTagType(currentLead.riskLevel)">
{{ getRiskLabel(currentLead.riskLevel) }}
</el-tag>
</el-descriptions-item>
</el-descriptions>
<!-- 跟进记录Timeline -->
<el-divider content-position="left">跟进记录</el-divider>
<el-timeline>
<el-timeline-item v-for="follow in followRecords" :key="follow.followId"
:timestamp="follow.createTime" placement="top">
<el-card>
<div class="follow-header">
<span class="follow-type">{{ getFollowTypeLabel(follow.followType) }}</span>
<span class="follow-user">{{ follow.followUserName }}</span>
</div>
<div class="follow-content">{{ follow.content }}</div>
<div v-if="follow.aiSummary" class="follow-ai-summary">
<el-icon><MagicStick /></el-icon> AI摘要:{{ follow.aiSummary }}
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</el-drawer>
4. 新建线索 Dialog
<el-dialog v-model="showAddLeadDialog" title="新建线索" width="600px">
<el-form :model="leadForm" label-width="100px">
<el-form-item label="ERP客户">
<el-select v-model="leadForm.customerCode" filterable placeholder="选择ERP客户(可选)">
<!-- 从ERP拉取客户列表 -->
</el-select>
</el-form-item>
<el-form-item label="公司名称" required>
<el-input v-model="leadForm.companyName" />
</el-form-item>
<el-form-item label="联系人" required>
<el-input v-model="leadForm.contactName" />
</el-form-item>
<el-form-item label="手机号" required>
<el-input v-model="leadForm.mobile" />
</el-form-item>
<!-- 其他字段 -->
</el-form>
<template #footer>
<el-button @click="showAddLeadDialog = false">取消</el-button>
<el-button type="primary" @click="handleAddLead">创建线索</el-button>
</template>
</el-dialog>
4.4.2 AI分析侧边栏(Element Plus Drawer)
右侧固定展示:
<el-drawer v-model="showAiDrawer" title="AI分析" size="40%" direction="rtl">
<div class="ai-analysis">
<el-card class="ai-card">
<div class="ai-score">
<el-progress type="dashboard" :percentage="aiScore" :color="getAiColor" />
<span class="ai-label">AI意向评分</span>
</div>
</el-card>
<el-alert v-if="riskLevel === 'high'" title="高风险提示" type="error" :closable="false">
{{ riskReason }}
</el-alert>
<el-collapse>
<el-collapse-item title="推荐动作" name="actions">
<el-steps :active="recommendedStep" direction="vertical">
<el-step title="首次拜访" description="建议本周完成首次拜访" />
<el-step title="发送招商政策" description="发送返点政策文档" />
<el-step title="样品测试" description="寄送样品进行测试" />
</el-steps>
</el-collapse-item>
<el-collapse-item title="推荐销售话术" name="scripts">
<div v-html="recommendedScript"></div>
</el-collapse-item>
</el-collapse>
</div>
</el-drawer>
AI服务调用: 通过 Gateway 调用 hzhub-ai:6039/ai/chat/analyze
5. 经销商中心模块设计
5.1 现有页面扩展
路径: hzhub-portal-employee/src/pages/dealer/index.vue(已存在,需扩展)
现有功能:
- 经销商卡片视图(使用 ERP CustomerVO)
- 筛选(销区、品牌、状态、搜索)
- 统计数据展示
新增功能:
5.1.1 关联CRM经销商数据
interface DealerVO extends CustomerVO {
// CRM扩展字段
dealerId?: number; // CRM经销商ID
level?: string; // 经销商等级
lifecycle?: string; // 生命周期
totalOrderAmount?: number; // 累计订单金额
totalPaymentAmount?: number; // 累计回款金额
activityScore?: number; // 活跃评分
riskScore?: number; // 风险评分
tags?: DealerTagVO[]; // AI标签
}
5.1.2 经销商详情 Dialog
<el-dialog v-model="showDealerDetail" title="经销商详情" width="800px">
<el-tabs>
<el-tab-pane label="基础档案">
<el-descriptions :column="2" border>
<el-descriptions-item label="ERP客户编码">{{ dealer.customerCode }}</el-descriptions-item>
<el-descriptions-item label="经销商等级">
<el-tag>{{ dealer.level }}</el-tag>
</el-descriptions-item>
<!-- ... -->
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="商机管理">
<!-- 商机列表 -->
</el-tab-pane>
<el-tab-pane label="拜访记录">
<el-timeline>
<!-- 拜访Timeline -->
</el-timeline>
</el-tab-pane>
<el-tab-pane label="AI画像">
<el-row :gutter="20">
<el-col :span="12">
<el-card>
<div class="ai-metric">
<span class="metric-label">活跃度评分</span>
<el-progress :percentage="dealer.activityScore" />
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<div class="ai-metric">
<span class="metric-label">风险评分</span>
<el-progress :percentage="dealer.riskScore" :color="getRiskColor" />
</div>
</el-card>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</el-dialog>
5.2 数据表设计
5.2.1 crm_dealer(经销商表)
| 字段 | 类型 | 说明 |
|---|---|---|
| dealer_id | bigint | 主键 |
| customer_code | varchar(100) | ERP客户编码(关联) |
| dealer_name | varchar(200) | 经销商名称 |
| dealer_code | varchar(100) | 编码 |
| contact_name | varchar(100) | 联系人 |
| mobile | varchar(50) | 手机 |
| province | varchar(50) | 省 |
| city | varchar(50) | 市 |
| level | varchar(50) | 等级(字典:crm_dealer_level) |
| lifecycle | varchar(50) | 生命周期(字典:crm_lifecycle) |
| signed_at | datetime | 签约时间 |
| store_count | int | 门店数 |
| team_size | int | 团队规模 |
| total_order_amount | decimal(18,2) | 累计订单金额 |
| total_payment_amount | decimal(18,2) | 累计回款金额 |
| activity_score | decimal(5,2) | 活跃评分 |
| risk_score | decimal(5,2) | 飆险评分 |
| owner_user_id | bigint | 负责人(关联 sys_user) |
| del_flag | int | 删除标志 |
6. API 接口设计(员工门户适配)
6.1 前端 API 定义
路径: hzhub-portal-employee/src/api/crm/(新建目录)
创建:
index.ts(API调用)types.ts(类型定义)
API示例
import request from '@/utils/request';
// 线索列表
export function getLeadList(params: LeadQueryParams) {
return request.get<TableDataInfo<LeadVO>>('/crm/lead/list', params).json();
}
// 创建线索
export function createLead(data: LeadForm) {
return request.post<R<void>>('/crm/lead', data).json();
}
// 线索详情
export function getLeadDetail(leadId: number) {
return request.get<R<LeadVO>>(`/crm/lead/${leadId}`).json();
}
// 线索跟进记录
export function getLeadFollowRecords(leadId: number) {
return request.get<R<LeadFollowVO[]>>(`/crm/lead/follow/${leadId}`).json();
}
// 添加跟进记录
export function addLeadFollow(data: LeadFollowForm) {
return request.post<R<void>>('/crm/lead/follow', data).json();
}
// 线索转经销商
export function convertLeadToDealer(data: ConvertForm) {
return request.post<R<void>>('/crm/lead/convert', data).json();
}
6.2 后端接口设计(hzhub-system)
Controller规范
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/crm/lead")
public class CrmLeadController extends BaseController {
private final ICrmLeadService leadService;
/**
* 获取线索列表
*/
@GetMapping("/list")
public TableDataInfo<CrmLeadVo> list(CrmLeadBo lead, PageQuery pageQuery) {
return leadService.selectPageLeadList(lead, pageQuery);
}
/**
* 新增线索
*/
@Log(title = "线索管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated @RequestBody CrmLeadBo lead) {
return R.ok(leadService.insertLead(lead));
}
/**
* 线索详情
*/
@GetMapping("/{leadId}")
public R<CrmLeadVo> detail(@PathVariable Long leadId) {
return R.ok(leadService.selectLeadById(leadId));
}
/**
* 线索跟进记录
*/
@GetMapping("/follow/{leadId}")
public R<List<CrmLeadFollowVo>> followRecords(@PathVariable Long leadId) {
return R.ok(leadService.selectFollowRecordsByLeadId(leadId));
}
/**
* 添加跟进记录
*/
@Log(title = "线索跟进", businessType = BusinessType.INSERT)
@PostMapping("/follow")
public R<Void> addFollow(@Validated @RequestBody CrmLeadFollowBo follow) {
return R.ok(leadService.insertFollowRecord(follow));
}
/**
* 线索转经销商
*/
@Log(title = "线索转化", businessType = BusinessType.INSERT)
@PostMapping("/convert")
public R<Void> convert(@Validated @RequestBody CrmLeadConvertBo convert) {
return R.ok(leadService.convertToDealer(convert));
}
}
7. ERP数据集成设计
7.1 数据同步策略
同步方式
方式1:关联查询(实时)
线索/经销商表存储 customer_code,实时调用 ERP 动态API 拉取客户信息。
public CrmLeadVo selectLeadById(Long leadId) {
CrmLead lead = leadMapper.selectById(leadId);
CrmLeadVo vo = BeanUtil.toBean(lead, CrmLeadVo.class);
// 如果有ERP客户编码,拉取ERP数据补充
if (StringUtils.isNotBlank(lead.getCustomerCode())) {
CustomerVO erpCustomer = erpService.getCustomerDetail(lead.getCustomerCode());
vo.setErpCustomerName(erpCustomer.getCustomerName());
vo.setErpSalesAreaName(erpCustomer.getSalesAreaName());
// ...
}
return vo;
}
方式2:定时同步(批量)
使用 XXL-Job 定时任务同步 ERP 客户数据到 CRM 表。
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点
public void syncErpCustomers() {
// 调用 hzhub-erp:8082/erp/dynamic/v1/customer/list
// 批量更新 crm_dealer 表
}
7.2 ERP动态API调用
hzhub-system 服务调用 ERP:
@Service
public class ErpIntegrationService {
@Value("${erp.base-url}")
private String erpBaseUrl; // http://localhost:8082
/**
* 获取ERP客户详情
*/
public CustomerVO getCustomerDetail(String customerCode) {
String url = erpBaseUrl + "/erp/dynamic/v1/customer/detail?customerCode=" + customerCode;
ResponseEntity<R<CustomerVO>> response = restTemplate.getForEntity(url, R.class);
return response.getBody().getData();
}
/**
* 获取ERP客户列表
*/
public List<CustomerVO> getCustomerList(CustomerQueryParam param) {
String url = erpBaseUrl + "/erp/dynamic/v1/customer/list";
// ...
}
}
8. 企业微信集成(员工门户)
8.1 企业微信侧边栏
展示内容:
- 经销商画像(从 CRM + ERP 拉取)
- 最近订单
- 最近拜访
- 商机阶段
- AI风险
实现:
- 企业微信应用配置(应用ID、Secret)
- 后端接口:
GET /crm/wecom/sidebar/{externalUserId} - 前端嵌入企业微信侧边栏(H5页面)
8.2 移动端H5页面
员工门户支持企业微信H5:
// 企业微信环境判断
if (window.location.href.includes('wework')) {
// 使用企业微信JS-SDK
wx.config({
beta: true,
appId: 'YOUR_APPID',
// ...
});
}
移动端页面:
/crm/mobile/visit- 拜访记录(语音录入)/crm/mobile/follow- 快速跟进
9. AI能力集成设计
9.1 AI服务调用(LangChain4j)
调用 hzhub-ai 服务:
@Service
public class CrmAiService {
@Autowired
private ChatClient chatClient; // LangChain4j
/**
* AI意向分析
*/
public LeadIntentAnalysis analyzeIntent(CrmLead lead) {
String prompt = String.format(
"分析以下线索的意向等级和风险:%s,联系人:%s,行业:%s",
lead.getCompanyName(), lead.getContactName(), lead.getIndustry()
);
AiMessage response = chatClient.generate(prompt);
// 解析AI响应,提取意向等级、评分、风险等级
return parseIntentAnalysis(response.text());
}
/**
* AI跟进摘要生成
*/
public String generateFollowSummary(String followContent) {
String prompt = "请为以下跟进记录生成摘要:" + followContent;
AiMessage response = chatClient.generate(prompt);
return response.text();
}
}
9.2 向量检索(Weaviate)
使用 Weaviate 存储历史线索案例:
@Service
public class LeadSimilarityService {
/**
* 查找相似线索案例
*/
public List<LeadCase> findSimilarLeads(CrmLead newLead) {
// 将新线索信息转为向量
// 在 Weaviate 中检索相似案例
// 返回历史成功案例供参考
}
}
10. 自动化工作流设计(warm-flow)
10.1 线索分配流程
线索创建
-> AI意向分析
-> 自动分配规则(根据区域)
-> warm-flow审批流程
-> 销售确认接手
实现:
// 触发warm-flow流程
workflowService.startProcessInstanceByKey("crm_lead_assign_flow", leadId);
10.2 线索转化流程
线索转化申请
-> warm-flow审批流程(区域经理审批)
-> 创建经销商数据
-> 创建商机
-> 更新线索状态
11. 权限与组织设计(Sa-Token)
11.1 数据权限层级
总部(sys_dept: root)
-> 大区(sys_dept: level 1)
-> 区域(sys_dept: level 2)
-> 城市(sys_dept: level 3)
-> 销售(sys_user)
实现: 使用 sys_dept 表的树形结构,通过 DataPermissionHelper 实现数据隔离。
11.2 权限控制点
| 模块 | 权限标识 | Sa-Token 注解 |
|---|---|---|
| 线索 | crm:lead:list, crm:lead:add, crm:lead:edit, crm:lead:remove | @SaCheckPermission |
| 经销商 | crm:dealer:list, crm:dealer:edit | - |
| 合同 | crm:contract:approve, crm:contract:amount-edit | - |
| 回款 | crm:payment:list, crm:payment:verify | - |
| BI | crm:bi:view(区域数据隔离) | - |
注意: 员工门户不需要 Sa-Token注解,权限由 Gateway 统一控制。
12. 前端开发规范(Element Plus)
12.1 页面结构规范
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { getLeadList, type LeadVO } from '@/api/crm';
import { ElMessage } from 'element-plus';
// 数据
const leadList = ref<LeadVO[]>([]);
const loading = ref(false);
// 方法
async function loadLeads() {
loading.value = true;
try {
const res = await getLeadList({ pageNum: 1, pageSize: 10 });
leadList.value = res.rows || [];
} catch (error: any) {
ElMessage.error(error?.message || '加载失败');
} finally {
loading.value = false;
}
}
onMounted(() => {
loadLeads();
});
</script>
<template>
<div class="crm-page">
<!-- Element Plus组件 -->
</div>
</template>
<style scoped lang="scss">
.crm-page {
padding: 20px;
}
</style>
12.2 目录结构
hzhub-portal-employee/src/
├── api/
│ └── crm/
│ │ ├── index.ts # CRM API调用
│ │ └── types.ts # 类型定义
├── pages/
│ └── crm/
│ │ ├── index.vue # CRM主页(扩展)
│ │ ├── LeadDetailDrawer.vue # 线索详情组件
│ │ ├── FollowDrawer.vue # 跟进记录组件
│ │ └── ConvertDialog.vue # 转化对话框
│ └── dealer/
│ │ ├── index.vue # 经销商主页(扩展)
│ │ ├── DealerDetailDialog.vue # 经销商详情
13. 实施计划(员工门户)
第一阶段(1-2个月)
建设内容:
- 扩展员工门户现有CRM页面(线索管理Tab)
- 后端CRM基础接口(hzhub-system)
- ERP数据关联(customer_code)
- 线索跟进记录(Timeline展示)
- warm-flow审批流程(线索分配)
技术栈:
- 后端:Spring Boot + MyBatis-Plus + Sa-Token + warm-flow
- 前端:Vue3 + Element Plus + TypeScript
- ERP集成:hzhub-erp 动态API
第二阶段(2-3个月)
建设内容:
- AI意向分析(LangChain4j)
- AI跟进摘要生成
- AI风险分析
- 企业微信侧边栏集成
- 移动端H5拜访页面
技术栈:
- AI:LangChain4j + hzhub-ai 服务
- 向量:Weaviate(案例检索)
- 移动端:企业微信JS-SDK
第三阶段(3-4个月)
建设内容:
- AI预测模型(成交预测、流失预测)
- AI Copilot(LangGraph4j)
- BI仪表盘(扩展现有
/bi页面) - 自动化工作流(XXL-Job)
技术栈:
- AI:LangGraph4j + hzhub-ai 服务
- 定时任务:XXL-Job
14. 与 HZHub 项目的集成要点
14.1 Gateway 路由配置
位置: hzhub-gateway/src/main/resources/application.yml
spring:
cloud:
gateway:
routes:
# CRM 路由(添加到现有路由列表)
- id: hzhub-crm
uri: lb://hzhub-system
predicates:
- Path=/crm/**
filters:
- StripPrefix=1
14.2 前端路由扩展
位置: hzhub-portal-employee/src/routers/modules/staticRouter.ts
现有路由(已存在):
{
path: '/crm',
name: 'crm',
component: () => import('@/pages/crm/index.vue'),
meta: {
title: '销售CRM',
subtitle: '客户关系管理',
icon: 'TrendCharts',
},
},
{
path: '/dealer',
name: 'dealer',
component: () => import('@/pages/dealer/index.vue'),
meta: {
title: '经销商管理',
subtitle: '经销商信息管理',
icon: 'Shop',
},
},
无需修改,直接扩展现有页面即可。
14.3 数据库初始化
SQL 文件: hzhub-system/src/main/resources/db/crm_init.sql
包含:
- CRM 表结构(crm_lead, crm_dealer, crm_opportunity 等)
- 数据字典(crm_lead_source, crm_opportunity_stage 等)
- 菜单配置(sys_menu - 告知管理员在后台配置)
15. 核心差异总结(员工门户 vs 管理后台)
| 方面 | 管理后台(V2) | 员工门户(V3) |
|---|---|---|
| 前端项目 | hzhub-admin | hzhub-portal-employee |
| UI框架 | Vben Admin + Ant Design Vue | Element Plus |
| 现有基础 | 无,需要新建 | 已有CRM和经销商页面 |
| 开发方式 | 新建独立页面 | 扩展现有页面 |
| 数据来源 | 独立CRM表 | ERP客户数据 + CRM表 |
| 用户角色 | 管理员 + 销售 | 企业员工 + 销售人员 |
| 权限控制 | Sa-Token注解 | Gateway统一控制 |
| 移动端 | 企业微信H5(新建) | 企业微信H5(员工门户支持) |
总结
本文档将 CRM 销售自动化系统完全适配到 员工门户(hzhub-portal-employee),充分利用:
- 现有页面:
/crm(销售CRM)和/dealer(经销商)已存在,直接扩展 - ERP数据集成:关联
customer_code,实时拉取 ERP 客户信息 - Element Plus UI:使用卡片式、Timeline、Drawer等组件
- Vue3 Composition API:
<script setup>+ TypeScript - hook-fetch请求:统一API调用方式
核心改动:
- 前端项目:hzhub-portal-employee(不是 hzhub-admin)
- UI组件:Element Plus(不是 Ant Design Vue)
- 开发方式:扩展现有页面(不是新建)
- 数据关联:ERP Customer + CRM Lead(双数据源)
- 路由配置:无需修改(直接使用现有路由)
后续实施时,严格按照本文档执行,确保与员工门户现有功能的一致性。