Files
hzhub/docs/CRM销售模块详细设计说明书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

33 KiB
Raw Blame History

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) - 手机号
wechat 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
}

业务逻辑:

  1. 如果提供 customer_code,调用 hzhub-erp:8082/erp/dynamic/v1/customer/detail 拉取客户信息
  2. 自动填充客户基础信息companyName, contactName, mobile 等)
  3. 校验手机号是否重复(同租户内)
  4. 调用 LangChain4j AI服务分析意向等级hzhub-ai:6039/ai/analyze/intent
  5. 自动生成AI评分
  6. 根据区域规则sys_dept分配销售owner_user_id
  7. 创建自动跟进任务warm-flow

4.3.2 线索转经销商

API POST /crm/lead/convert

请求参数:

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

逻辑:

  1. 创建 crm_dealer 数据
  2. 如果 customer_code 存在,同步 ERP 客户数据
  3. 迁移历史跟进记录到 crm_dealer_follow
  4. 创建初始商机(crm_opportunity
  5. 更新线索状态为"已转化"
  6. 触发 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.tsAPI调用
  • 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风险

实现:

  1. 企业微信应用配置应用ID、Secret
  2. 后端接口:GET /crm/wecom/sidebar/{externalUserId}
  3. 前端嵌入企业微信侧边栏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拜访页面

技术栈:

  • AILangChain4j + hzhub-ai 服务
  • 向量Weaviate案例检索
  • 移动端企业微信JS-SDK

第三阶段3-4个月

建设内容:

  • AI预测模型成交预测、流失预测
  • AI CopilotLangGraph4j
  • BI仪表盘扩展现有 /bi 页面)
  • 自动化工作流XXL-Job

技术栈:

  • AILangGraph4j + 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,充分利用:

  1. 现有页面/crm销售CRM/dealer(经销商)已存在,直接扩展
  2. ERP数据集成:关联 customer_code,实时拉取 ERP 客户信息
  3. Element Plus UI使用卡片式、Timeline、Drawer等组件
  4. Vue3 Composition API<script setup> + TypeScript
  5. hook-fetch请求统一API调用方式

核心改动:

  1. 前端项目:hzhub-portal-employee(不是 hzhub-admin
  2. UI组件Element Plus(不是 Ant Design Vue
  3. 开发方式:扩展现有页面(不是新建)
  4. 数据关联:ERP Customer + CRM Lead(双数据源)
  5. 路由配置:无需修改(直接使用现有路由)

后续实施时,严格按照本文档执行,确保与员工门户现有功能的一致性。