feat(credit): 添加客户跟进七步骤功能
- 在CreditMpCustomer实体类中添加七个跟进步骤相关字段 - 实现跟进步骤审核功能,包括单个和批量审核接口 - 添加待审核步骤查询接口和客户跟进统计功能 - 实现流程结束功能和详细的步骤状态管理 - 创建相应的DTO和VO数据传输对象 - 在Mapper层添加待审核步骤查询SQL实现
This commit is contained in:
458
docs/ai/后端实现指南.md
Normal file
458
docs/ai/后端实现指南.md
Normal file
@@ -0,0 +1,458 @@
|
||||
# 客户跟进7步骤后端实现指南
|
||||
|
||||
## 📋 概述
|
||||
|
||||
本指南详细说明如何实现客户跟进7个步骤功能的后端代码,包括数据库设计、Java后端实现和API接口。
|
||||
|
||||
## 🗄️ 数据库设计
|
||||
|
||||
### 1. 修改 credit_mp_customer 表结构
|
||||
|
||||
```sql
|
||||
-- 为第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. 创建审核记录表(可选)
|
||||
|
||||
```sql
|
||||
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. 实体类修改
|
||||
|
||||
```java
|
||||
// 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类创建
|
||||
|
||||
```java
|
||||
// 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层实现
|
||||
|
||||
```java
|
||||
// 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层实现
|
||||
|
||||
```java
|
||||
// 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
|
||||
|
||||
```xml
|
||||
<!-- 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. **性能优化**:大量数据时考虑分页和索引优化
|
||||
|
||||
## 🔄 后续扩展
|
||||
|
||||
可以考虑的功能:
|
||||
- 跟进模板和标准化流程
|
||||
- 自动提醒和通知
|
||||
- 数据统计和报表
|
||||
- 跟进效率分析
|
||||
- 客户满意度评估
|
||||
@@ -4,6 +4,12 @@ import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.credit.service.CreditMpCustomerService;
|
||||
import com.gxwebsoft.credit.entity.CreditMpCustomer;
|
||||
import com.gxwebsoft.credit.param.CreditMpCustomerParam;
|
||||
import com.gxwebsoft.credit.param.BatchFollowStepApprovalDTO;
|
||||
import com.gxwebsoft.credit.param.EndFollowProcessDTO;
|
||||
import com.gxwebsoft.credit.param.FollowStepApprovalDTO;
|
||||
import com.gxwebsoft.credit.param.FollowStepQueryDTO;
|
||||
import com.gxwebsoft.credit.vo.FollowStatisticsDTO;
|
||||
import com.gxwebsoft.credit.vo.PendingApprovalStepVO;
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
@@ -126,4 +132,47 @@ public class CreditMpCustomerController extends BaseController {
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('credit:creditMpCustomer:update')")
|
||||
@OperationLog
|
||||
@Operation(summary = "审核跟进步骤")
|
||||
@PostMapping("/approve-follow-step")
|
||||
public ApiResult<?> approveFollowStep(@RequestBody FollowStepApprovalDTO dto) {
|
||||
creditMpCustomerService.approveFollowStep(dto);
|
||||
return success("审核成功");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('credit:creditMpCustomer:update')")
|
||||
@OperationLog
|
||||
@Operation(summary = "批量审核跟进步骤")
|
||||
@PostMapping("/batch-approve-follow-steps")
|
||||
public ApiResult<?> batchApproveFollowSteps(@RequestBody BatchFollowStepApprovalDTO dto) {
|
||||
creditMpCustomerService.batchApproveFollowSteps(dto);
|
||||
return success("批量审核成功");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('credit:creditMpCustomer:list')")
|
||||
@Operation(summary = "获取待审核的跟进步骤")
|
||||
@GetMapping("/pending-approval-steps")
|
||||
public ApiResult<List<PendingApprovalStepVO>> getPendingApprovalSteps(FollowStepQueryDTO query) {
|
||||
List<PendingApprovalStepVO> list = creditMpCustomerService.getPendingApprovalSteps(query);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('credit:creditMpCustomer:list')")
|
||||
@Operation(summary = "获取客户跟进统计")
|
||||
@GetMapping("/follow-statistics/{customerId}")
|
||||
public ApiResult<FollowStatisticsDTO> getFollowStatistics(@PathVariable Long customerId) {
|
||||
FollowStatisticsDTO statistics = creditMpCustomerService.getFollowStatistics(customerId);
|
||||
return success(statistics);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('credit:creditMpCustomer:update')")
|
||||
@OperationLog
|
||||
@Operation(summary = "结束客户跟进流程")
|
||||
@PostMapping("/end-follow-process")
|
||||
public ApiResult<?> endFollowProcess(@RequestBody EndFollowProcessDTO dto) {
|
||||
creditMpCustomerService.endFollowProcess(dto);
|
||||
return success("流程结束成功");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -110,4 +110,159 @@ public class CreditMpCustomer implements Serializable {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
// 第1步:案件受理字段
|
||||
@Schema(description = "第1步是否已提交")
|
||||
private Integer followStep1Submitted;
|
||||
|
||||
@Schema(description = "第1步提交时间")
|
||||
private String followStep1SubmittedAt;
|
||||
|
||||
@Schema(description = "第1步是否需要审核")
|
||||
private Integer followStep1NeedApproval;
|
||||
|
||||
@Schema(description = "第1步是否审核通过")
|
||||
private Integer followStep1Approved;
|
||||
|
||||
@Schema(description = "第1步审核时间")
|
||||
private String followStep1ApprovedAt;
|
||||
|
||||
@Schema(description = "第1步审核人ID")
|
||||
private Long followStep1ApprovedBy;
|
||||
|
||||
// 第2步:材料准备字段
|
||||
@Schema(description = "第2步是否已提交")
|
||||
private Integer followStep2Submitted;
|
||||
|
||||
@Schema(description = "第2步提交时间")
|
||||
private String followStep2SubmittedAt;
|
||||
|
||||
@Schema(description = "第2步是否需要审核")
|
||||
private Integer followStep2NeedApproval;
|
||||
|
||||
@Schema(description = "第2步是否审核通过")
|
||||
private Integer followStep2Approved;
|
||||
|
||||
@Schema(description = "第2步审核时间")
|
||||
private String followStep2ApprovedAt;
|
||||
|
||||
@Schema(description = "第2步审核人ID")
|
||||
private Long followStep2ApprovedBy;
|
||||
|
||||
// 第3步:案件办理字段
|
||||
@Schema(description = "第3步是否已提交")
|
||||
private Integer followStep3Submitted;
|
||||
|
||||
@Schema(description = "第3步提交时间")
|
||||
private String followStep3SubmittedAt;
|
||||
|
||||
@Schema(description = "第3步是否需要审核")
|
||||
private Integer followStep3NeedApproval;
|
||||
|
||||
@Schema(description = "第3步是否审核通过")
|
||||
private Integer followStep3Approved;
|
||||
|
||||
@Schema(description = "第3步审核时间")
|
||||
private String followStep3ApprovedAt;
|
||||
|
||||
@Schema(description = "第3步审核人ID")
|
||||
private Long followStep3ApprovedBy;
|
||||
|
||||
// 第4步:送达签收字段
|
||||
@Schema(description = "第4步是否已提交")
|
||||
private Integer followStep4Submitted;
|
||||
|
||||
@Schema(description = "第4步提交时间")
|
||||
private String followStep4SubmittedAt;
|
||||
|
||||
@Schema(description = "第4步是否需要审核")
|
||||
private Integer followStep4NeedApproval;
|
||||
|
||||
@Schema(description = "第4步是否审核通过")
|
||||
private Integer followStep4Approved;
|
||||
|
||||
@Schema(description = "第4步审核时间")
|
||||
private String followStep4ApprovedAt;
|
||||
|
||||
@Schema(description = "第4步审核人ID")
|
||||
private Long followStep4ApprovedBy;
|
||||
|
||||
// 第5步:合同签订字段
|
||||
@Schema(description = "第5步是否已提交")
|
||||
private Integer followStep5Submitted;
|
||||
|
||||
@Schema(description = "第5步提交时间")
|
||||
private String followStep5SubmittedAt;
|
||||
|
||||
@Schema(description = "第5步合同信息JSON数组")
|
||||
private String followStep5Contracts;
|
||||
|
||||
@Schema(description = "第5步是否需要审核")
|
||||
private Integer followStep5NeedApproval;
|
||||
|
||||
@Schema(description = "第5步是否审核通过")
|
||||
private Integer followStep5Approved;
|
||||
|
||||
@Schema(description = "第5步审核时间")
|
||||
private String followStep5ApprovedAt;
|
||||
|
||||
@Schema(description = "第5步审核人ID")
|
||||
private Long followStep5ApprovedBy;
|
||||
|
||||
// 第6步:订单回款字段
|
||||
@Schema(description = "第6步是否已提交")
|
||||
private Integer followStep6Submitted;
|
||||
|
||||
@Schema(description = "第6步提交时间")
|
||||
private String followStep6SubmittedAt;
|
||||
|
||||
@Schema(description = "第6步财务录入的回款记录JSON数组")
|
||||
private String followStep6PaymentRecords;
|
||||
|
||||
@Schema(description = "第6步预计回款JSON数组")
|
||||
private String followStep6ExpectedPayments;
|
||||
|
||||
@Schema(description = "第6步是否需要审核")
|
||||
private Integer followStep6NeedApproval;
|
||||
|
||||
@Schema(description = "第6步是否审核通过")
|
||||
private Integer followStep6Approved;
|
||||
|
||||
@Schema(description = "第6步审核时间")
|
||||
private String followStep6ApprovedAt;
|
||||
|
||||
@Schema(description = "第6步审核人ID")
|
||||
private Long followStep6ApprovedBy;
|
||||
|
||||
// 第7步:电话回访字段
|
||||
@Schema(description = "第7步是否已提交")
|
||||
private Integer followStep7Submitted;
|
||||
|
||||
@Schema(description = "第7步提交时间")
|
||||
private String followStep7SubmittedAt;
|
||||
|
||||
@Schema(description = "第7步回访记录JSON数组")
|
||||
private String followStep7VisitRecords;
|
||||
|
||||
@Schema(description = "第7步是否需要审核")
|
||||
private Integer followStep7NeedApproval;
|
||||
|
||||
@Schema(description = "第7步是否审核通过")
|
||||
private Integer followStep7Approved;
|
||||
|
||||
@Schema(description = "第7步审核时间")
|
||||
private String followStep7ApprovedAt;
|
||||
|
||||
@Schema(description = "第7步审核人ID")
|
||||
private Long followStep7ApprovedBy;
|
||||
|
||||
// 流程结束字段
|
||||
@Schema(description = "流程是否已结束")
|
||||
private Integer followProcessEnded;
|
||||
|
||||
@Schema(description = "流程结束时间")
|
||||
private String followProcessEndTime;
|
||||
|
||||
@Schema(description = "流程结束原因")
|
||||
private String followProcessEndReason;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.gxwebsoft.credit.entity.CreditMpCustomer;
|
||||
import com.gxwebsoft.credit.param.CreditMpCustomerParam;
|
||||
import com.gxwebsoft.credit.param.FollowStepQueryDTO;
|
||||
import com.gxwebsoft.credit.vo.PendingApprovalStepVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
@@ -34,4 +36,12 @@ public interface CreditMpCustomerMapper extends BaseMapper<CreditMpCustomer> {
|
||||
*/
|
||||
List<CreditMpCustomer> selectListRel(@Param("param") CreditMpCustomerParam param);
|
||||
|
||||
/**
|
||||
* 获取待审核的跟进步骤列表
|
||||
*
|
||||
* @param query 查询参数
|
||||
* @return 待审核步骤列表
|
||||
*/
|
||||
List<PendingApprovalStepVO> selectPendingApprovalSteps(@Param("param") FollowStepQueryDTO query);
|
||||
|
||||
}
|
||||
|
||||
@@ -92,4 +92,128 @@
|
||||
<include refid="selectSql"></include>
|
||||
</select>
|
||||
|
||||
<!-- 获取待审核的跟进步骤列表 -->
|
||||
<select id="selectPendingApprovalSteps" resultType="com.gxwebsoft.credit.vo.PendingApprovalStepVO">
|
||||
SELECT
|
||||
c.id as customerId,
|
||||
c.to_user as customerName,
|
||||
1 as step,
|
||||
'案件受理' as stepTitle,
|
||||
c.follow_step1_submitted_at as submittedAt,
|
||||
u.real_name as submittedBy,
|
||||
c.comments as content
|
||||
FROM credit_mp_customer c
|
||||
LEFT JOIN sys_user u ON c.user_id = u.user_id
|
||||
WHERE c.follow_step1_submitted = 1
|
||||
AND c.follow_step1_approved = 0
|
||||
AND c.deleted = 0
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
c.id as customerId,
|
||||
c.to_user as customerName,
|
||||
2 as step,
|
||||
'材料准备' as stepTitle,
|
||||
c.follow_step2_submitted_at as submittedAt,
|
||||
u.real_name as submittedBy,
|
||||
c.comments as content
|
||||
FROM credit_mp_customer c
|
||||
LEFT JOIN sys_user u ON c.user_id = u.user_id
|
||||
WHERE c.follow_step2_submitted = 1
|
||||
AND c.follow_step2_approved = 0
|
||||
AND c.deleted = 0
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
c.id as customerId,
|
||||
c.to_user as customerName,
|
||||
3 as step,
|
||||
'案件办理' as stepTitle,
|
||||
c.follow_step3_submitted_at as submittedAt,
|
||||
u.real_name as submittedBy,
|
||||
c.comments as content
|
||||
FROM credit_mp_customer c
|
||||
LEFT JOIN sys_user u ON c.user_id = u.user_id
|
||||
WHERE c.follow_step3_submitted = 1
|
||||
AND c.follow_step3_approved = 0
|
||||
AND c.deleted = 0
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
c.id as customerId,
|
||||
c.to_user as customerName,
|
||||
4 as step,
|
||||
'送达签收' as stepTitle,
|
||||
c.follow_step4_submitted_at as submittedAt,
|
||||
u.real_name as submittedBy,
|
||||
c.comments as content
|
||||
FROM credit_mp_customer c
|
||||
LEFT JOIN sys_user u ON c.user_id = u.user_id
|
||||
WHERE c.follow_step4_submitted = 1
|
||||
AND c.follow_step4_approved = 0
|
||||
AND c.deleted = 0
|
||||
|
||||
UNION ALL
|
||||
|
||||
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="param.step != null">
|
||||
HAVING step = #{param.step}
|
||||
</if>
|
||||
<if test="param.customerId != null">
|
||||
HAVING customerId = #{param.customerId}
|
||||
</if>
|
||||
<if test="param.userId != null">
|
||||
HAVING customerId IN (SELECT id FROM credit_mp_customer WHERE user_id = #{param.userId})
|
||||
</if>
|
||||
ORDER BY submittedAt DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.gxwebsoft.credit.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 批量跟进步骤审核DTO
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-03-22
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "BatchFollowStepApprovalDTO对象", description = "批量跟进步骤审核DTO")
|
||||
public class BatchFollowStepApprovalDTO {
|
||||
|
||||
@Schema(description = "审核列表", required = true)
|
||||
@NotNull(message = "审核列表不能为空")
|
||||
@Valid
|
||||
private List<FollowStepApprovalDTO> approvals;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.gxwebsoft.credit.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 结束跟进流程DTO
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-03-22
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "EndFollowProcessDTO对象", description = "结束跟进流程DTO")
|
||||
public class EndFollowProcessDTO {
|
||||
|
||||
@Schema(description = "客户ID", required = true)
|
||||
@NotNull(message = "客户ID不能为空")
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "结束原因")
|
||||
private String reason;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.gxwebsoft.credit.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.Max;
|
||||
|
||||
/**
|
||||
* 跟进步骤审核DTO
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-03-22
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "FollowStepApprovalDTO对象", description = "跟进步骤审核DTO")
|
||||
public class FollowStepApprovalDTO {
|
||||
|
||||
@Schema(description = "客户ID", required = true)
|
||||
@NotNull(message = "客户ID不能为空")
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "步骤号", required = true, example = "5")
|
||||
@NotNull(message = "步骤号不能为空")
|
||||
@Min(value = 1, message = "步骤号最小为1")
|
||||
@Max(value = 7, message = "步骤号最大为7")
|
||||
private Integer step;
|
||||
|
||||
@Schema(description = "是否审核通过", required = true)
|
||||
@NotNull(message = "审核状态不能为空")
|
||||
private Boolean approved;
|
||||
|
||||
@Schema(description = "审核备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.gxwebsoft.credit.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.Max;
|
||||
|
||||
/**
|
||||
* 跟进步骤查询DTO
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-03-22
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "FollowStepQueryDTO对象", description = "跟进步骤查询DTO")
|
||||
public class FollowStepQueryDTO {
|
||||
|
||||
@Schema(description = "步骤号", example = "5")
|
||||
@Min(value = 1, message = "步骤号最小为1")
|
||||
@Max(value = 7, message = "步骤号最大为7")
|
||||
private Integer step;
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
}
|
||||
@@ -4,6 +4,12 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.credit.entity.CreditMpCustomer;
|
||||
import com.gxwebsoft.credit.param.CreditMpCustomerParam;
|
||||
import com.gxwebsoft.credit.param.BatchFollowStepApprovalDTO;
|
||||
import com.gxwebsoft.credit.param.EndFollowProcessDTO;
|
||||
import com.gxwebsoft.credit.param.FollowStepApprovalDTO;
|
||||
import com.gxwebsoft.credit.param.FollowStepQueryDTO;
|
||||
import com.gxwebsoft.credit.vo.FollowStatisticsDTO;
|
||||
import com.gxwebsoft.credit.vo.PendingApprovalStepVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -39,4 +45,41 @@ public interface CreditMpCustomerService extends IService<CreditMpCustomer> {
|
||||
*/
|
||||
CreditMpCustomer getByIdRel(Integer id);
|
||||
|
||||
/**
|
||||
* 审核跟进步骤
|
||||
*
|
||||
* @param dto 审核参数
|
||||
*/
|
||||
void approveFollowStep(FollowStepApprovalDTO dto);
|
||||
|
||||
/**
|
||||
* 批量审核跟进步骤
|
||||
*
|
||||
* @param dto 批量审核参数
|
||||
*/
|
||||
void batchApproveFollowSteps(BatchFollowStepApprovalDTO dto);
|
||||
|
||||
/**
|
||||
* 获取待审核的跟进步骤列表
|
||||
*
|
||||
* @param query 查询参数
|
||||
* @return 待审核步骤列表
|
||||
*/
|
||||
List<PendingApprovalStepVO> getPendingApprovalSteps(FollowStepQueryDTO query);
|
||||
|
||||
/**
|
||||
* 获取客户跟进统计
|
||||
*
|
||||
* @param customerId 客户ID
|
||||
* @return 跟进统计信息
|
||||
*/
|
||||
FollowStatisticsDTO getFollowStatistics(Long customerId);
|
||||
|
||||
/**
|
||||
* 结束客户跟进流程
|
||||
*
|
||||
* @param dto 结束流程参数
|
||||
*/
|
||||
void endFollowProcess(EndFollowProcessDTO dto);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
package com.gxwebsoft.credit.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.credit.mapper.CreditMpCustomerMapper;
|
||||
import com.gxwebsoft.credit.service.CreditMpCustomerService;
|
||||
import com.gxwebsoft.credit.entity.CreditMpCustomer;
|
||||
import com.gxwebsoft.credit.param.CreditMpCustomerParam;
|
||||
import com.gxwebsoft.credit.param.BatchFollowStepApprovalDTO;
|
||||
import com.gxwebsoft.credit.param.EndFollowProcessDTO;
|
||||
import com.gxwebsoft.credit.param.FollowStepApprovalDTO;
|
||||
import com.gxwebsoft.credit.param.FollowStepQueryDTO;
|
||||
import com.gxwebsoft.credit.vo.FollowStatisticsDTO;
|
||||
import com.gxwebsoft.credit.vo.FollowStepDetailDTO;
|
||||
import com.gxwebsoft.credit.vo.PendingApprovalStepVO;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -20,6 +33,8 @@ import java.util.List;
|
||||
@Service
|
||||
public class CreditMpCustomerServiceImpl extends ServiceImpl<CreditMpCustomerMapper, CreditMpCustomer> implements CreditMpCustomerService {
|
||||
|
||||
private final BaseController baseController = new BaseController();
|
||||
|
||||
@Override
|
||||
public PageResult<CreditMpCustomer> pageRel(CreditMpCustomerParam param) {
|
||||
PageParam<CreditMpCustomer, CreditMpCustomerParam> page = new PageParam<>(param);
|
||||
@@ -44,4 +59,201 @@ public class CreditMpCustomerServiceImpl extends ServiceImpl<CreditMpCustomerMap
|
||||
return param.getOne(baseMapper.selectListRel(param));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void approveFollowStep(FollowStepApprovalDTO dto) {
|
||||
CreditMpCustomer customer = getById(dto.getCustomerId());
|
||||
if (customer == null) {
|
||||
throw new BusinessException("客户不存在");
|
||||
}
|
||||
|
||||
// 验证步骤是否已提交
|
||||
if (!isStepSubmitted(customer, dto.getStep())) {
|
||||
throw new BusinessException("该步骤尚未提交,无法审核");
|
||||
}
|
||||
|
||||
// 更新审核状态
|
||||
updateStepApproval(customer, 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 BusinessException("客户不存在");
|
||||
}
|
||||
|
||||
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(EndFollowProcessDTO dto) {
|
||||
CreditMpCustomer customer = getById(dto.getCustomerId());
|
||||
if (customer == null) {
|
||||
throw new BusinessException("客户不存在");
|
||||
}
|
||||
|
||||
customer.setFollowProcessEnded(1);
|
||||
customer.setFollowProcessEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
customer.setFollowProcessEndReason(dto.getReason());
|
||||
|
||||
updateById(customer);
|
||||
}
|
||||
|
||||
// 私有辅助方法
|
||||
private boolean isStepSubmitted(CreditMpCustomer customer, Integer step) {
|
||||
switch (step) {
|
||||
case 1: return customer.getFollowStep1Submitted() != null && customer.getFollowStep1Submitted() == 1;
|
||||
case 2: return customer.getFollowStep2Submitted() != null && customer.getFollowStep2Submitted() == 1;
|
||||
case 3: return customer.getFollowStep3Submitted() != null && customer.getFollowStep3Submitted() == 1;
|
||||
case 4: return customer.getFollowStep4Submitted() != null && customer.getFollowStep4Submitted() == 1;
|
||||
case 5: return customer.getFollowStep5Submitted() != null && customer.getFollowStep5Submitted() == 1;
|
||||
case 6: return customer.getFollowStep6Submitted() != null && customer.getFollowStep6Submitted() == 1;
|
||||
case 7: return customer.getFollowStep7Submitted() != null && customer.getFollowStep7Submitted() == 1;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStepApproval(CreditMpCustomer customer, FollowStepApprovalDTO dto) {
|
||||
String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
Integer currentUserId = baseController.getLoginUserId();
|
||||
|
||||
switch (dto.getStep()) {
|
||||
case 5:
|
||||
customer.setFollowStep5Approved(dto.getApproved() ? 1 : 0);
|
||||
customer.setFollowStep5ApprovedAt(currentTime);
|
||||
customer.setFollowStep5ApprovedBy(currentUserId != null ? currentUserId.longValue() : null);
|
||||
break;
|
||||
case 6:
|
||||
customer.setFollowStep6Approved(dto.getApproved() ? 1 : 0);
|
||||
customer.setFollowStep6ApprovedAt(currentTime);
|
||||
customer.setFollowStep6ApprovedBy(currentUserId != null ? currentUserId.longValue() : null);
|
||||
break;
|
||||
case 7:
|
||||
customer.setFollowStep7Approved(dto.getApproved() ? 1 : 0);
|
||||
customer.setFollowStep7ApprovedAt(currentTime);
|
||||
customer.setFollowStep7ApprovedBy(currentUserId != null ? currentUserId.longValue() : null);
|
||||
break;
|
||||
}
|
||||
|
||||
updateById(customer);
|
||||
}
|
||||
|
||||
private void updateCustomerStep(CreditMpCustomer customer, Integer step) {
|
||||
// 更新客户的总体步骤状态
|
||||
if (step >= customer.getStep()) {
|
||||
customer.setStep(step + 1);
|
||||
updateById(customer);
|
||||
}
|
||||
}
|
||||
|
||||
private FollowStepDetailDTO getStepDetail(CreditMpCustomer customer, Integer step) {
|
||||
FollowStepDetailDTO detail = new FollowStepDetailDTO();
|
||||
detail.setStep(step);
|
||||
|
||||
// 设置步骤标题
|
||||
String[] stepTitles = {"", "案件受理", "材料准备", "案件办理", "送达签收", "合同签订", "订单回款", "电话回访"};
|
||||
detail.setTitle(stepTitles[step]);
|
||||
|
||||
// 获取步骤状态
|
||||
boolean submitted = isStepSubmitted(customer, step);
|
||||
boolean approved = isStepApproved(customer, step);
|
||||
|
||||
if (approved) {
|
||||
detail.setStatus("approved");
|
||||
detail.setApprovedAt(getStepApprovedAt(customer, step));
|
||||
} else if (submitted) {
|
||||
detail.setStatus("submitted");
|
||||
detail.setSubmittedAt(getStepSubmittedAt(customer, step));
|
||||
} else {
|
||||
detail.setStatus("pending");
|
||||
}
|
||||
|
||||
return detail;
|
||||
}
|
||||
|
||||
private boolean isStepApproved(CreditMpCustomer customer, Integer step) {
|
||||
switch (step) {
|
||||
case 1: return customer.getFollowStep1Approved() != null && customer.getFollowStep1Approved() == 1;
|
||||
case 2: return customer.getFollowStep2Approved() != null && customer.getFollowStep2Approved() == 1;
|
||||
case 3: return customer.getFollowStep3Approved() != null && customer.getFollowStep3Approved() == 1;
|
||||
case 4: return customer.getFollowStep4Approved() != null && customer.getFollowStep4Approved() == 1;
|
||||
case 5: return customer.getFollowStep5Approved() != null && customer.getFollowStep5Approved() == 1;
|
||||
case 6: return customer.getFollowStep6Approved() != null && customer.getFollowStep6Approved() == 1;
|
||||
case 7: return customer.getFollowStep7Approved() != null && customer.getFollowStep7Approved() == 1;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDateTime getStepSubmittedAt(CreditMpCustomer customer, Integer step) {
|
||||
String submittedAt = null;
|
||||
switch (step) {
|
||||
case 1: submittedAt = customer.getFollowStep1SubmittedAt(); break;
|
||||
case 2: submittedAt = customer.getFollowStep2SubmittedAt(); break;
|
||||
case 3: submittedAt = customer.getFollowStep3SubmittedAt(); break;
|
||||
case 4: submittedAt = customer.getFollowStep4SubmittedAt(); break;
|
||||
case 5: submittedAt = customer.getFollowStep5SubmittedAt(); break;
|
||||
case 6: submittedAt = customer.getFollowStep6SubmittedAt(); break;
|
||||
case 7: submittedAt = customer.getFollowStep7SubmittedAt(); break;
|
||||
}
|
||||
return submittedAt != null ? LocalDateTime.parse(submittedAt, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null;
|
||||
}
|
||||
|
||||
private LocalDateTime getStepApprovedAt(CreditMpCustomer customer, Integer step) {
|
||||
String approvedAt = null;
|
||||
switch (step) {
|
||||
case 1: approvedAt = customer.getFollowStep1ApprovedAt(); break;
|
||||
case 2: approvedAt = customer.getFollowStep2ApprovedAt(); break;
|
||||
case 3: approvedAt = customer.getFollowStep3ApprovedAt(); break;
|
||||
case 4: approvedAt = customer.getFollowStep4ApprovedAt(); break;
|
||||
case 5: approvedAt = customer.getFollowStep5ApprovedAt(); break;
|
||||
case 6: approvedAt = customer.getFollowStep6ApprovedAt(); break;
|
||||
case 7: approvedAt = customer.getFollowStep7ApprovedAt(); break;
|
||||
}
|
||||
return approvedAt != null ? LocalDateTime.parse(approvedAt, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.gxwebsoft.credit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 客户跟进统计DTO
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-03-22
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "FollowStatisticsDTO对象", description = "客户跟进统计DTO")
|
||||
public class FollowStatisticsDTO {
|
||||
|
||||
@Schema(description = "总步骤数")
|
||||
private Integer totalSteps;
|
||||
|
||||
@Schema(description = "已完成步骤数")
|
||||
private Integer completedSteps;
|
||||
|
||||
@Schema(description = "当前步骤")
|
||||
private Integer currentStep;
|
||||
|
||||
@Schema(description = "进度百分比")
|
||||
private Double progress;
|
||||
|
||||
@Schema(description = "步骤详情列表")
|
||||
private List<FollowStepDetailDTO> stepDetails;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.gxwebsoft.credit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 跟进步骤详情DTO
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-03-22
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "FollowStepDetailDTO对象", description = "跟进步骤详情DTO")
|
||||
public class FollowStepDetailDTO {
|
||||
|
||||
@Schema(description = "步骤号")
|
||||
private Integer step;
|
||||
|
||||
@Schema(description = "步骤标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "状态: pending, submitted, approved, rejected")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "提交时间")
|
||||
private LocalDateTime submittedAt;
|
||||
|
||||
@Schema(description = "审核时间")
|
||||
private LocalDateTime approvedAt;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.gxwebsoft.credit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 待审核跟进步骤VO
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-03-22
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "PendingApprovalStepVO对象", description = "待审核跟进步骤VO")
|
||||
public class PendingApprovalStepVO {
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "客户名称")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "步骤号")
|
||||
private Integer step;
|
||||
|
||||
@Schema(description = "步骤标题")
|
||||
private String stepTitle;
|
||||
|
||||
@Schema(description = "提交时间")
|
||||
private LocalDateTime submittedAt;
|
||||
|
||||
@Schema(description = "提交人")
|
||||
private String submittedBy;
|
||||
|
||||
@Schema(description = "内容")
|
||||
private String content;
|
||||
}
|
||||
Reference in New Issue
Block a user