Files
mp-java/docs/ai/后端实现指南.md
赵忠林 9c929301b9 feat(credit): 添加客户跟进七步骤功能
- 在CreditMpCustomer实体类中添加七个跟进步骤相关字段
- 实现跟进步骤审核功能,包括单个和批量审核接口
- 添加待审核步骤查询接口和客户跟进统计功能
- 实现流程结束功能和详细的步骤状态管理
- 创建相应的DTO和VO数据传输对象
- 在Mapper层添加待审核步骤查询SQL实现
2026-03-22 22:32:02 +08:00

16 KiB
Raw Blame History

客户跟进7步骤后端实现指南

📋 概述

本指南详细说明如何实现客户跟进7个步骤功能的后端代码包括数据库设计、Java后端实现和API接口。

🗄️ 数据库设计

1. 修改 credit_mp_customer 表结构

-- 为第5-7步添加字段第1-4步字段已存在
-- 第5步合同签订
ALTER TABLE credit_mp_customer ADD COLUMN follow_step5_submitted TINYINT DEFAULT 0 COMMENT '是否已提交';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step5_submitted_at VARCHAR(255) COMMENT '提交时间';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step5_contracts TEXT COMMENT '合同信息JSON数组';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step5_need_approval TINYINT DEFAULT 1 COMMENT '是否需要审核';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step5_approved TINYINT DEFAULT 0 COMMENT '是否审核通过';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step5_approved_at VARCHAR(255) COMMENT '审核时间';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step5_approved_by BIGINT COMMENT '审核人ID';

-- 第6步订单回款
ALTER TABLE credit_mp_customer ADD COLUMN follow_step6_submitted TINYINT DEFAULT 0 COMMENT '是否已提交';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step6_submitted_at VARCHAR(255) COMMENT '提交时间';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step6_payment_records TEXT COMMENT '财务录入的回款记录JSON数组';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step6_expected_payments TEXT COMMENT '预计回款JSON数组';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step6_need_approval TINYINT DEFAULT 1 COMMENT '是否需要审核';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step6_approved TINYINT DEFAULT 0 COMMENT '是否审核通过';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step6_approved_at VARCHAR(255) COMMENT '审核时间';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step6_approved_by BIGINT COMMENT '审核人ID';

-- 第7步电话回访
ALTER TABLE credit_mp_customer ADD COLUMN follow_step7_submitted TINYINT DEFAULT 0 COMMENT '是否已提交';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step7_submitted_at VARCHAR(255) COMMENT '提交时间';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step7_visit_records TEXT COMMENT '回访记录JSON数组';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step7_need_approval TINYINT DEFAULT 1 COMMENT '是否需要审核';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step7_approved TINYINT DEFAULT 0 COMMENT '是否审核通过';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step7_approved_at VARCHAR(255) COMMENT '审核时间';
ALTER TABLE credit_mp_customer ADD COLUMN follow_step7_approved_by BIGINT COMMENT '审核人ID';

-- 添加流程结束相关字段
ALTER TABLE credit_mp_customer ADD COLUMN follow_process_ended TINYINT DEFAULT 0 COMMENT '流程是否已结束';
ALTER TABLE credit_mp_customer ADD COLUMN follow_process_end_time VARCHAR(255) COMMENT '流程结束时间';
ALTER TABLE credit_mp_customer ADD COLUMN follow_process_end_reason TEXT COMMENT '流程结束原因';

2. 创建审核记录表(可选)

CREATE TABLE credit_follow_approval (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  customer_id BIGINT NOT NULL COMMENT '客户ID',
  step TINYINT NOT NULL COMMENT '步骤号',
  approved TINYINT NOT NULL COMMENT '是否通过',
  remark TEXT COMMENT '审核备注',
  approved_by BIGINT COMMENT '审核人ID',
  approved_at VARCHAR(255) COMMENT '审核时间',
  created_at VARCHAR(255) COMMENT '创建时间',
  INDEX idx_customer_step (customer_id, step),
  INDEX idx_approved_by (approved_by)
) COMMENT='跟进步骤审核记录';

Java后端实现

1. 实体类修改

// CreditMpCustomer.java 添加字段
public class CreditMpCustomer {
    // ... 现有字段
    
    // 第5步字段
    private Integer followStep5Submitted;
    private String followStep5SubmittedAt;
    private String followStep5Contracts;
    private Integer followStep5NeedApproval;
    private Integer followStep5Approved;
    private String followStep5ApprovedAt;
    private Long followStep5ApprovedBy;
    
    // 第6步字段
    private Integer followStep6Submitted;
    private String followStep6SubmittedAt;
    private String followStep6PaymentRecords;
    private String followStep6ExpectedPayments;
    private Integer followStep6NeedApproval;
    private Integer followStep6Approved;
    private String followStep6ApprovedAt;
    private Long followStep6ApprovedBy;
    
    // 第7步字段
    private Integer followStep7Submitted;
    private String followStep7SubmittedAt;
    private String followStep7VisitRecords;
    private Integer followStep7NeedApproval;
    private Integer followStep7Approved;
    private String followStep7ApprovedAt;
    private Long followStep7ApprovedBy;
    
    // 流程结束字段
    private Integer followProcessEnded;
    private String followProcessEndTime;
    private String followProcessEndReason;
    
    // getter/setter 方法...
}

2. DTO类创建

// FollowStepApprovalDTO.java
@Data
public class FollowStepApprovalDTO {
    private Long customerId;
    private Integer step;
    private Boolean approved;
    private String remark;
}

// BatchFollowStepApprovalDTO.java
@Data
public class BatchFollowStepApprovalDTO {
    private List<FollowStepApprovalDTO> approvals;
}

// FollowStatisticsDTO.java
@Data
public class FollowStatisticsDTO {
    private Integer totalSteps;
    private Integer completedSteps;
    private Integer currentStep;
    private Double progress;
    private List<FollowStepDetailDTO> stepDetails;
}

// FollowStepDetailDTO.java
@Data
public class FollowStepDetailDTO {
    private Integer step;
    private String title;
    private String status; // pending, submitted, approved, rejected
    private String submittedAt;
    private String approvedAt;
}

3. Service层实现

// CreditMpCustomerServiceImpl.java 添加方法

@Service
public class CreditMpCustomerServiceImpl implements CreditMpCustomerService {
    
    /**
     * 审核跟进步骤
     */
    @Override
    @Transactional
    public void approveFollowStep(FollowStepApprovalDTO dto) {
        CreditMpCustomer customer = getById(dto.getCustomerId());
        if (customer == null) {
            throw new ServiceException("客户不存在");
        }
        
        // 验证步骤是否已提交
        if (!isStepSubmitted(customer, dto.getStep())) {
            throw new ServiceException("该步骤尚未提交,无法审核");
        }
        
        // 更新审核状态
        updateStepApproval(customer, dto);
        
        // 记录审核日志
        saveApprovalLog(dto);
        
        // 如果审核通过,更新客户步骤状态
        if (dto.getApproved()) {
            updateCustomerStep(customer, dto.getStep());
        }
    }
    
    /**
     * 批量审核跟进步骤
     */
    @Override
    @Transactional
    public void batchApproveFollowSteps(BatchFollowStepApprovalDTO dto) {
        for (FollowStepApprovalDTO approval : dto.getApprovals()) {
            approveFollowStep(approval);
        }
    }
    
    /**
     * 获取待审核的跟进步骤列表
     */
    @Override
    public List<PendingApprovalStepVO> getPendingApprovalSteps(FollowStepQueryDTO query) {
        return baseMapper.selectPendingApprovalSteps(query);
    }
    
    /**
     * 获取客户跟进统计
     */
    @Override
    public FollowStatisticsDTO getFollowStatistics(Long customerId) {
        CreditMpCustomer customer = getById(customerId);
        if (customer == null) {
            throw new ServiceException("客户不存在");
        }
        
        FollowStatisticsDTO statistics = new FollowStatisticsDTO();
        statistics.setTotalSteps(7);
        
        List<FollowStepDetailDTO> stepDetails = new ArrayList<>();
        int completedSteps = 0;
        int currentStep = 1;
        
        for (int i = 1; i <= 7; i++) {
            FollowStepDetailDTO detail = getStepDetail(customer, i);
            stepDetails.add(detail);
            
            if ("approved".equals(detail.getStatus())) {
                completedSteps++;
                currentStep = i + 1;
            } else if ("submitted".equals(detail.getStatus()) && currentStep == 1) {
                currentStep = i;
            }
        }
        
        statistics.setCompletedSteps(completedSteps);
        statistics.setCurrentStep(Math.min(currentStep, 7));
        statistics.setProgress((double) completedSteps / 7 * 100);
        statistics.setStepDetails(stepDetails);
        
        return statistics;
    }
    
    /**
     * 结束客户跟进流程
     */
    @Override
    @Transactional
    public void endFollowProcess(Long customerId, String reason) {
        CreditMpCustomer customer = getById(customerId);
        if (customer == null) {
            throw new ServiceException("客户不存在");
        }
        
        customer.setFollowProcessEnded(1);
        customer.setFollowProcessEndTime(DateUtil.formatDateTime(new Date()));
        customer.setFollowProcessEndReason(reason);
        
        updateById(customer);
    }
    
    // 私有辅助方法...
    private boolean isStepSubmitted(CreditMpCustomer customer, Integer step) {
        switch (step) {
            case 1: return customer.getFollowStep1Submitted() == 1;
            case 2: return customer.getFollowStep2Submitted() == 1;
            // ... 其他步骤
            case 7: return customer.getFollowStep7Submitted() == 1;
            default: return false;
        }
    }
    
    private void updateStepApproval(CreditMpCustomer customer, FollowStepApprovalDTO dto) {
        String currentTime = DateUtil.formatDateTime(new Date());
        Long currentUserId = SecurityFrameworkUtils.getLoginUserId();
        
        switch (dto.getStep()) {
            case 5:
                customer.setFollowStep5Approved(dto.getApproved() ? 1 : 0);
                customer.setFollowStep5ApprovedAt(currentTime);
                customer.setFollowStep5ApprovedBy(currentUserId);
                break;
            case 6:
                customer.setFollowStep6Approved(dto.getApproved() ? 1 : 0);
                customer.setFollowStep6ApprovedAt(currentTime);
                customer.setFollowStep6ApprovedBy(currentUserId);
                break;
            case 7:
                customer.setFollowStep7Approved(dto.getApproved() ? 1 : 0);
                customer.setFollowStep7ApprovedAt(currentTime);
                customer.setFollowStep7ApprovedBy(currentUserId);
                break;
        }
        
        updateById(customer);
    }
}

4. Controller层实现

// CreditMpCustomerController.java 添加接口

@RestController
@RequestMapping("/credit/credit-mp-customer")
public class CreditMpCustomerController {
    
    @PostMapping("/approve-follow-step")
    @OperLog(title = "审核跟进步骤", businessType = BusinessType.UPDATE)
    public R<Void> approveFollowStep(@RequestBody FollowStepApprovalDTO dto) {
        creditMpCustomerService.approveFollowStep(dto);
        return R.ok();
    }
    
    @PostMapping("/batch-approve-follow-steps")
    @OperLog(title = "批量审核跟进步骤", businessType = BusinessType.UPDATE)
    public R<Void> batchApproveFollowSteps(@RequestBody BatchFollowStepApprovalDTO dto) {
        creditMpCustomerService.batchApproveFollowSteps(dto);
        return R.ok();
    }
    
    @GetMapping("/pending-approval-steps")
    @OperLog(title = "获取待审核跟进步骤", businessType = BusinessType.SELECT)
    public R<List<PendingApprovalStepVO>> getPendingApprovalSteps(FollowStepQueryDTO query) {
        List<PendingApprovalStepVO> list = creditMpCustomerService.getPendingApprovalSteps(query);
        return R.ok(list);
    }
    
    @GetMapping("/follow-statistics/{customerId}")
    @OperLog(title = "获取客户跟进统计", businessType = BusinessType.SELECT)
    public R<FollowStatisticsDTO> getFollowStatistics(@PathVariable Long customerId) {
        FollowStatisticsDTO statistics = creditMpCustomerService.getFollowStatistics(customerId);
        return R.ok(statistics);
    }
    
    @PostMapping("/end-follow-process")
    @OperLog(title = "结束客户跟进流程", businessType = BusinessType.UPDATE)
    public R<Void> endFollowProcess(@RequestBody EndFollowProcessDTO dto) {
        creditMpCustomerService.endFollowProcess(dto.getCustomerId(), dto.getReason());
        return R.ok();
    }
}

5. Mapper层SQL

<!-- CreditMpCustomerMapper.xml 添加查询方法 -->

<select id="selectPendingApprovalSteps" resultType="com.your.package.PendingApprovalStepVO">
    SELECT 
        c.id as customerId,
        c.to_user as customerName,
        5 as step,
        '合同签订' as stepTitle,
        c.follow_step5_submitted_at as submittedAt,
        u.real_name as submittedBy,
        c.follow_step5_contracts as content
    FROM credit_mp_customer c
    LEFT JOIN sys_user u ON c.user_id = u.user_id
    WHERE c.follow_step5_submitted = 1 
    AND c.follow_step5_approved = 0 
    AND c.deleted = 0
    
    UNION ALL
    
    SELECT 
        c.id as customerId,
        c.to_user as customerName,
        6 as step,
        '订单回款' as stepTitle,
        c.follow_step6_submitted_at as submittedAt,
        u.real_name as submittedBy,
        c.follow_step6_expected_payments as content
    FROM credit_mp_customer c
    LEFT JOIN sys_user u ON c.user_id = u.user_id
    WHERE c.follow_step6_submitted = 1 
    AND c.follow_step6_approved = 0 
    AND c.deleted = 0
    
    UNION ALL
    
    SELECT 
        c.id as customerId,
        c.to_user as customerName,
        7 as step,
        '电话回访' as stepTitle,
        c.follow_step7_submitted_at as submittedAt,
        u.real_name as submittedBy,
        c.follow_step7_visit_records as content
    FROM credit_mp_customer c
    LEFT JOIN sys_user u ON c.user_id = u.user_id
    WHERE c.follow_step7_submitted = 1 
    AND c.follow_step7_approved = 0 
    AND c.deleted = 0
    
    <if test="step != null">
        HAVING step = #{step}
    </if>
    <if test="customerId != null">
        HAVING customerId = #{customerId}
    </if>
    ORDER BY submittedAt DESC
</select>

🔧 业务逻辑说明

1. 步骤解锁机制

  • 第一步始终可用
  • 后续步骤需要前一步审核通过才能进行
  • 前端通过 canEnterStep 逻辑控制

2. 审核流程

  • 步骤提交后设置 needApproval = 1
  • 管理员在后台审核
  • 审核通过后设置 approved = 1 并更新时间

3. 数据格式

  • 所有复杂数据使用JSON格式存储
  • 文件上传返回URL存储在JSON数组中
  • 时间统一使用 YYYY-MM-DD HH:mm:ss 格式

4. 权限控制

  • 销售只能提交和查看自己的客户
  • 管理员可以审核所有步骤
  • 财务人员可以录入第6步回款数据

📱 前端集成

前端代码已经完成,包括:

  • 7个步骤的完整页面
  • 步骤状态显示和跳转逻辑
  • 数据提交和验证
  • 客户详情页面的汇总显示

🚀 部署步骤

  1. 执行数据库迁移脚本
  2. 部署Java后端代码
  3. 更新前端API调用
  4. 测试完整流程
  5. 配置权限和审核流程

📝 注意事项

  1. 数据备份:执行数据库变更前请备份
  2. 权限配置:确保各角色权限正确配置
  3. 文件上传:确认文件上传服务正常
  4. 审核流程:测试审核流程的完整性
  5. 性能优化:大量数据时考虑分页和索引优化

🔄 后续扩展

可以考虑的功能:

  • 跟进模板和标准化流程
  • 自动提醒和通知
  • 数据统计和报表
  • 跟进效率分析
  • 客户满意度评估