Commit 19f83b45a38ebfb131f0c814b9d7130658dc1b24

Authored by 张志伟
2 parents b5de3269 3b48f164

Merge remote-tracking branch 'origin/test'

Showing 75 changed files with 2406 additions and 537 deletions
doc/sql/data处理sql.sql renamed to doc/v1.0.0/data处理sql.sql
1 1 -- 订单数据处理
  2 +DELETE FROM follow_task WHERE type = 1;
  3 +DELETE FROM follow_record WHERE type = 1;
  4 +DELETE FROM follow_notice_record WHERE follow_type = 1;
  5 +DELETE FROM original_data WHERE type = 1;
  6 +
2 7 insert into fw_valhalla.original_data(type, customer_id, generate_time, detail_id, solved, group_id, create_time,
3 8 update_time)
4 9 SELECT 1,
... ... @@ -9,81 +14,97 @@ SELECT 1,
9 14 w1.group_id,
10 15 now(),
11 16 now()
12   -from `fw_order_v2.9.7`.car_order w1
13   - inner JOIN `fw_order_v2.9.7`.car_delivery_info w2 on w1.id = w2.order_id
14   -where w1.id in (
  17 +from `fw_valhalla`.car_order w1
  18 + inner JOIN `fw_valhalla`.car_delivery_info w2 on w1.id = w2.order_id
  19 + INNER JOIN fw_valhalla.customer w3 on w1.car_vin = w3.frame_no
  20 +where w3.adviser_id is not NULL and w1.id in (
15 21 select max(w1.id) as id
16   - from `fw_order_v2.9.7`.car_order w1
17   - inner JOIN `fw_order_v2.9.7`.car_delivery_info w2 on w1.id = w2.order_id
  22 + from `fw_valhalla`.car_order w1
  23 + inner JOIN `fw_valhalla`.car_delivery_info w2 on w1.id = w2.order_id
18 24 where w2.delivery_done = 1
19 25 and w1.group_id = 2
20 26 and w1.order_canceled = 0
21   - and w2.delivery_date >= DATE_ADD(NOW(), INTERVAL - 9 MONTH)
  27 + and w2.delivery_date >= DATE_ADD(NOW(), INTERVAL - 61 DAY )
22 28 group by w1.cust_archive_id
23 29 );
24 30  
25 31 -- 保险数据处理
  32 +DELETE FROM follow_task WHERE type = 4;
  33 +DELETE FROM follow_record WHERE type = 4;
  34 +DELETE FROM follow_notice_record WHERE follow_type = 4;
  35 +DELETE FROM original_data WHERE type = 4;
  36 +
26 37 insert into fw_valhalla.original_data(type, customer_id, generate_time, detail_id, solved, group_id, create_time,
27 38 update_time)
28 39 SELECT 4,
29   - w1.cus_id,
30   - DATE_ADD(w1.effective_date, INTERVAL + 1 YEAR),
31 40 w1.id,
32   - 0,
  41 + w1.buy_date,
  42 + -1 * w1.id,
  43 + 1,
33 44 w1.group_id,
34 45 now(),
35 46 now()
36   -from fw_angel.insurance_policy w1
37   -where w1.id in (
38   - select max(w1.id) as id
39   - from fw_angel.insurance_policy w1
40   - where w1.issue_date >= DATE_ADD(NOW(), INTERVAL - 4 MONTH)
41   - group by w1.cus_id
42   -);
  47 +from fw_valhalla.customer w1 WHERE w1.yn=1;
  48 +
  49 +UPDATE original_data
  50 +SET generate_time = DATE_ADD( generate_time, INTERVAL + 1 YEAR )
  51 +WHERE
  52 + type=4 and
  53 + generate_time < DATE_ADD(
  54 + NOW(),
  55 + INTERVAL - 304 DAY);
  56 +
  57 +
43 58  
44 59 -- 售后工单首保处理
  60 +DELETE FROM original_data WHERE type = 2;
45 61 insert into fw_valhalla.original_data(type, customer_id, generate_time, detail_id, solved, group_id, create_time,
46 62 update_time)
47 63 SELECT 2,
48   - customer_id,
49   - actual_pickup_time,
50   - id,
  64 + t1.customer_id,
  65 + t1.actual_pickup_time,
  66 + t1.id,
51 67 0,
52   - group_id,
  68 + t1.group_id,
53 69 now(),
54 70 now()
55   -from fw_cas.`order`
56   -where id in (
57   - select max(id) as id
58   - from fw_cas.`order`
59   - where metal_sheet = 0
60   - and `status` = 9
61   - and (FIND_IN_SET(2, type) or FIND_IN_SET(2, type))
62   - and customer_id is not null
63   - and actual_pickup_time >= DATE_ADD(NOW(), INTERVAL - 5 MONTH)
64   - group by customer_id
  71 +from fw_cas.`order` t1 inner join fw_valhalla.customer t2 on t1.customer_id = t2.id
  72 +where t2.adviser_id is not null and t1.id in (
  73 + select max(t3.id) as id
  74 + from fw_cas.`order` t3
  75 + where t3.metal_sheet = 0
  76 + and t3.`status` = 9
  77 + and (FIND_IN_SET(2, t3.type) or FIND_IN_SET(2, t3.type))
  78 + and t3.customer_id is not null
  79 + and t3.actual_pickup_time >= DATE_ADD(NOW(), INTERVAL - 65 DAY )
  80 + group by t3.customer_id
65 81 );
66 82  
67 83  
68 84 -- 流失客户数据处理
  85 +DELETE FROM follow_task WHERE type = 2;
  86 +DELETE FROM follow_record WHERE type = 2;
  87 +DELETE FROM follow_notice_record WHERE follow_type = 2;
  88 +DELETE FROM original_data WHERE type = 5;
  89 +
69 90 insert into fw_valhalla.original_data(type, customer_id, generate_time, detail_id, solved, group_id, create_time,
70 91 update_time)
71 92 SELECT 5,
72   - customer_id,
73   - actual_pickup_time,
74   - id,
  93 + t1.customer_id,
  94 + t1.actual_pickup_time,
  95 + t1.id,
75 96 0,
76   - group_id,
  97 + t2.group_id,
77 98 now(),
78 99 now()
79   -from fw_cas.`order`
80   -where id in (
81   - select max(id) as id
82   - from fw_cas.`order`
83   - where `status` = 9
84   - and customer_id is not null
85   - and actual_pickup_time >= DATE_ADD(NOW(), INTERVAL - 5 MONTH)
86   - group by customer_id
  100 +from fw_cas.`order` t1 inner join fw_valhalla.customer t2 on t1.customer_id = t2.id
  101 +where t2.adviser_id is not null and t1.id in (
  102 + select max(t3.id) as id
  103 + from fw_cas.`order` t3
  104 + where t3.`status` = 9
  105 + and t3.customer_id is not null
  106 + and t3.actual_pickup_time >= DATE_ADD(NOW(), INTERVAL - 120 DAY )
  107 + group by t3.customer_id
87 108 );
88 109  
89 110  
... ...
doc/fw-valhalla.json renamed to doc/v1.0.0/fw-valhalla.json
doc/sql/fw-valhalla.sql renamed to doc/v1.0.0/fw-valhalla.sql
doc/售后CRM.drawio renamed to doc/v1.0.0/售后CRM.drawio
doc/sql/档案数据处理.sql renamed to doc/v1.0.0/档案数据处理.sql
doc/v1.0.1/v1.0.1.sql 0 → 100644
  1 +-- accident_pool changes
  2 +alter table accident_pool
  3 + add report_mobile varchar(128) not null comment '报案手机号' after mobile;
  4 +
  5 +alter table accident_pool
  6 + modify shop_id bigint not null comment '服务站id';
  7 +
  8 +alter table accident_pool
  9 + drop column user_id;
  10 +
  11 +alter table accident_pool
  12 + add shop_name varchar(255) not null comment '所属服务站名称' after shop_id;
  13 +
  14 +alter table accident_pool
  15 + add address varchar(255) null comment '报案地址' after shop_name;
  16 +
  17 +alter table accident_pool
  18 + add sms varchar(512) null comment '短信详情' after group_id;
  19 +
  20 +drop index report_num_group_index on accident_pool;
  21 +
  22 +-- approve_record changes
  23 +alter table approve_record
  24 + add type int(3) default 1 not null comment '1: 跟进战败 2:其他' after reason;
  25 +
  26 +-- leave_need_do
  27 +create table leave_need_do
  28 +(
  29 + id bigint auto_increment,
  30 + user_id bigint not null comment '用户id',
  31 + user_name varchar(225) null comment '用户名',
  32 + type int(3) not null comment '待办类型 10:客户待分配 20: 其他',
  33 + shop_id bigint not null comment '用户所属服务站',
  34 + reason int(3) not null comment '产生此条待办原因 1:离职 2:调岗 3:其他',
  35 + effective_time datetime null comment '变动生效时间',
  36 + done tinyint(1) default '0' not null comment '是否已处理 ',
  37 + create_time datetime null,
  38 + update_time datetime null,
  39 + constraint leave_need_do_pk
  40 + primary key (id)
  41 +)
  42 + comment '人员变动待办事项';
  43 +
  44 +create index leave_need_do_index
  45 + on leave_need_do (user_id, user_name, shop_id);
  46 +
  47 +
  48 +
... ...
doc/v1.0.1/升级事项.md 0 → 100644
  1 +##### 新增角色:
  2 +
  3 + |名称|角色码|备注|
  4 + | --|--|--|
  5 + |保有客分配 |BYKFP |一个服务站一个|
  6 +
  7 +
  8 +##### 资源路径:
  9 + ASCustomerDistribute 保有客分配 菜单
  10 + /app/leave2do/customer/** 保有客分配url
  11 + AsCrmOwnFollowUpPool 跟进池 菜单
  12 + /app/pool/follow/** 跟进池列表请求url
  13 +
  14 +##### 其他配置:
  15 +- 待办
  16 + |待办项|待办路径| 通知对象|
  17 + | --|--|--|
  18 + |保有客离职分配|ASCustomerDistribute| 保有客分配|
  19 +
  20 +##### 升级内容:
  21 +
  22 +1. 去掉战败池和成交池
  23 +2. 跟进池调整(菜单只能看自己的)
  24 +3. 事故车线索新增备案手机号
  25 +4. 新增离职分配功能(需等人事下个版本)
  26 +4. 跟进算法调整
  27 +5. 首保设置新增项目
  28 +7. 报表
  29 +8. 成交、战败 逻辑调整
... ...
fw-valhalla-common/src/main/java/cn/fw/valhalla/common/constant/RoleCode.java
... ... @@ -16,15 +16,11 @@ public interface RoleCode {
16 16 */
17 17 String SGCGJ = "SGCGJ";
18 18 /**
19   - * 首保跟进
20   - */
21   - String SBGJ = "SBGJ";
22   - /**
23 19 * 续保跟进
24 20 */
25 21 String XBGJ = "XBGJ";
26 22 /**
27   - * 流失客户跟进
  23 + * 保有客分配
28 24 */
29   - String LSKHGJ = "LSKHGJ";
  25 + String BYKFP = "BYKFP";
30 26 }
31 27 \ No newline at end of file
... ...
fw-valhalla-common/src/main/java/cn/fw/valhalla/common/enums/AllocationTypeEnum.java 0 → 100644
  1 +package cn.fw.valhalla.common.enums;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonCreator;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * @author : kurisu
  8 + * @className : AllocationTypeEnum
  9 + * @description : 分配方式
  10 + * @date: 2020-10-16 17:56
  11 + */
  12 +public enum AllocationTypeEnum {
  13 + /**
  14 + * 指定人员
  15 + */
  16 + ONE(1, "指定人员"),
  17 + /**
  18 + * 平均分配
  19 + */
  20 + ALL(2, "平均分配");
  21 +
  22 + /**
  23 + * 值
  24 + */
  25 + private final Integer value;
  26 + /**
  27 + * 名称
  28 + */
  29 + @Getter
  30 + private final String name;
  31 +
  32 + AllocationTypeEnum(final Integer value, final String name) {
  33 + this.value = value;
  34 + this.name = name;
  35 + }
  36 +
  37 + /**
  38 + * 根据枚举值获取枚举对象
  39 + */
  40 + @JsonCreator
  41 + public static AllocationTypeEnum ofValue(final Integer value) {
  42 + for (final AllocationTypeEnum typeEnum : AllocationTypeEnum.values()) {
  43 + if (typeEnum.value.equals(value)) {
  44 + return typeEnum;
  45 + }
  46 + }
  47 + return null;
  48 + }
  49 +}
... ...
fw-valhalla-common/src/main/java/cn/fw/valhalla/common/enums/DefeatTypeEnum.java 0 → 100644
  1 +package cn.fw.valhalla.common.enums;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonCreator;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * @author : kurisu
  8 + * @className : DefeatTypeEnum
  9 + * @description : 战败类型
  10 + * @date: 2020-10-16 17:56
  11 + */
  12 +public enum DefeatTypeEnum {
  13 + /**
  14 + * 主动战败
  15 + */
  16 + A(1, "主动战败"),
  17 + /**
  18 + * 到期划走
  19 + */
  20 + B(2, "到期划走"),
  21 + /**
  22 + * 到期战败
  23 + */
  24 + C(3, "到期战败");
  25 +
  26 + /**
  27 + * 值
  28 + */
  29 + private final Integer value;
  30 + /**
  31 + * 名称
  32 + */
  33 + @Getter
  34 + private final String name;
  35 +
  36 + DefeatTypeEnum(final Integer value, final String name) {
  37 + this.value = value;
  38 + this.name = name;
  39 + }
  40 +
  41 + /**
  42 + * 根据枚举值获取枚举对象
  43 + */
  44 + @JsonCreator
  45 + public static DefeatTypeEnum ofValue(final Integer value) {
  46 + for (final DefeatTypeEnum typeEnum : DefeatTypeEnum.values()) {
  47 + if (typeEnum.value.equals(value)) {
  48 + return typeEnum;
  49 + }
  50 + }
  51 + return null;
  52 + }
  53 +}
... ...
fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/DateUtil.java
... ... @@ -7,6 +7,7 @@ import java.time.*;
7 7 import java.time.temporal.TemporalAdjusters;
8 8 import java.util.Calendar;
9 9 import java.util.Date;
  10 +import java.util.Objects;
10 11  
11 12 /**
12 13 * 日期处理工具
... ... @@ -453,9 +454,79 @@ public final class DateUtil {
453 454 return (int) result;
454 455 }
455 456  
  457 + /**
  458 + * 判断是否是凌晨
  459 + *
  460 + * @param date
  461 + * @return
  462 + */
  463 + public static boolean isBeforeDawn(Date date) {
  464 + if (Objects.isNull(date)) {
  465 + return false;
  466 + }
  467 + LocalDateTime dateTime = date2LocalDateTime(date);
  468 + SimpleDateFormat df = new SimpleDateFormat("HH");
  469 + String str = df.format(localDateTime2Date(dateTime));
  470 + int a = Integer.parseInt(str);
  471 + return a >= 0 && a <= 6;
  472 + }
  473 +
  474 + /**
  475 + * 判断是否是上午
  476 + *
  477 + * @param date
  478 + * @return
  479 + */
  480 + public static boolean isMorning(Date date) {
  481 + if (Objects.isNull(date)) {
  482 + return false;
  483 + }
  484 + LocalDateTime dateTime = date2LocalDateTime(date);
  485 + SimpleDateFormat df = new SimpleDateFormat("HH");
  486 + String str = df.format(localDateTime2Date(dateTime));
  487 + int a = Integer.parseInt(str);
  488 + return a > 6 && a <= 12;
  489 + }
  490 +
  491 + /**
  492 + * 判断是否是下午
  493 + *
  494 + * @param date
  495 + * @return
  496 + */
  497 + public static boolean isAfternoon(Date date) {
  498 + if (Objects.isNull(date)) {
  499 + return false;
  500 + }
  501 + LocalDateTime dateTime = date2LocalDateTime(date);
  502 + SimpleDateFormat df = new SimpleDateFormat("HH");
  503 + String str = df.format(localDateTime2Date(dateTime));
  504 + int a = Integer.parseInt(str);
  505 + return a > 12 && a <= 18;
  506 + }
  507 +
  508 + /**
  509 + * 判断是否是晚上
  510 + *
  511 + * @param date
  512 + * @return
  513 + */
  514 + public static boolean isEvening(Date date) {
  515 + if (Objects.isNull(date)) {
  516 + return false;
  517 + }
  518 + LocalDateTime dateTime = date2LocalDateTime(date);
  519 + SimpleDateFormat df = new SimpleDateFormat("HH");
  520 + String str = df.format(localDateTime2Date(dateTime));
  521 + int a = Integer.parseInt(str);
  522 + return a > 18 && a <= 23;
  523 + }
  524 +
456 525 public static void main(String[] args) throws ParseException {
457 526 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
458   - Date date = format.parse("2020-09-09 09:45:30");
  527 + Date date = format.parse("2020-09-19 09:45:30");
459 528 System.out.println(startDate(getNowExpiredDay(-1)));
  529 +
  530 + System.out.println(sub(date, new Date(), "d"));
460 531 }
461 532 }
... ...
fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/StringUtils.java
1 1 package cn.fw.valhalla.common.utils;
2 2  
  3 +
3 4 import java.io.IOException;
4 5 import java.io.UnsupportedEncodingException;
5 6 import java.util.ArrayList;
... ... @@ -519,8 +520,8 @@ public final class StringUtils {
519 520 System.out.println(toUUID("1"));
520 521 System.out.println(removePrefix("abcd123", "ab"));
521 522 System.out.println(removeSuffix("abcd123", "123"));
522   - System.out.println(toColumnName("usernameid"));
523   - System.out.println(getFieldString(toColumnName("userNameId")));
  523 + System.out.println(toColumnName("usernameId"));
  524 + System.out.println(getFieldString("user_name_id"));
524 525 System.out.println(repeat("?", 10, ","));
525 526 length("AAA中国()111222bb");
526 527 }
... ...
fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/FollowTaskMapper.java
... ... @@ -18,29 +18,12 @@ import java.util.List;
18 18 @Repository
19 19 public interface FollowTaskMapper extends BaseMapper<FollowTask> {
20 20 /**
21   - * 战败池
22   - * @param startIndex
23   - * @param pageSize
24   - * @param queryVO
25   - * @return
26   - */
27   - List<FollowPoolDTO> defeatList(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize, @Param("condition") FollowPoolQueryVO queryVO);
28   -
29   - /**
30 21 * 跟进池
  22 + *
31 23 * @param startIndex
32 24 * @param pageSize
33 25 * @param queryVO
34 26 * @return
35 27 */
36 28 List<FollowPoolDTO> followList(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize, @Param("condition") FollowPoolQueryVO queryVO);
37   -
38   - /**
39   - * 成交池
40   - * @param startIndex
41   - * @param pageSize
42   - * @param queryVO
43   - * @return
44   - */
45   - List<FollowPoolDTO> completeList(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize, @Param("condition") FollowPoolQueryVO queryVO);
46 29 }
... ...
fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/LeaveNeedDoMapper.java 0 → 100644
  1 +package cn.fw.valhalla.dao.mapper;
  2 +
  3 +import cn.fw.valhalla.domain.db.LeaveNeedDo;
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.springframework.stereotype.Repository;
  6 +
  7 +/**
  8 + * @author : kurisu
  9 + * @className : LeaveNeedDoMapper
  10 + * @description : 人员变动待处理事件
  11 + * @date: 2020-10-16 17:00
  12 + */
  13 +@Repository
  14 +public interface LeaveNeedDoMapper extends BaseMapper<LeaveNeedDo> {
  15 +}
... ...
fw-valhalla-dao/src/main/resources/mapper/FollowTaskMapper.xml
... ... @@ -2,119 +2,138 @@
2 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 3 <mapper namespace="cn.fw.valhalla.dao.mapper.FollowTaskMapper">
4 4 <select
5   - id="defeatList"
  5 + id="followList"
6 6 resultType="cn.fw.valhalla.domain.dto.FollowPoolDTO"
7 7 parameterType="cn.fw.valhalla.domain.query.FollowPoolQueryVO"
8 8 >
9   - SELECT t1.id, t1.type, t1.finished, t1.origin_user, t1.origin_time, t1.finish_user,
10   - t1.origin_shop, t1.finish_shop, t1.finish_time, t1.changed, t1.deadline,
11   - ifnull(t2.plate_no, t3.plate_no) plate_no, t1.follow_user, t1.follow_shop follow_shop,
12   - t2.id customer_id, t1.state
  9 + select *
  10 + from (SELECT t1.id,
  11 + ifnull(t2.plate_no, t3.plate_no) plate_no,
  12 + t1.type type,
  13 + t1.changed redistribution,
  14 + case t1.finished when 1 then t1.finish_user when 0 then t1.follow_user end user_id,
  15 + case t1.finished when 1 then t1.finish_shop when 0 then t1.follow_shop end shop_id,
  16 + (select count(1) from follow_record t4
  17 + where t4.task_id = t1.id
  18 + and t4.user_id = if(t1.finished = 1, t1.finish_user, t1.follow_user)
  19 + and t4.follow_time is not null ) times,
  20 + TIMESTAMPDIFF(HOUR, now(), t1.deadline) remaining,
  21 + case t1.finished
  22 + when 1 then 2
  23 + when 0 then 3
  24 + end state,
  25 + t1.finish_time finish_time,
  26 + case t1.finished when 1 then null when 0 then t1.deadline end defeat_time,
  27 + if((select count(1) from approve_record t5
  28 + where t5.data_id = t1.id and t5.passed = 1) != 0, 1, 3) initiative,
  29 + t1.group_id group_id,
  30 + t2.id customer_id,
  31 + t1.origin_shop,
  32 + t1.finish_shop,
  33 + t1.finished,
  34 + t1.state origin_state
13 35 FROM follow_task t1
14 36 left join customer t2 on t1.customer_id = t2.id
15 37 left join accident_pool t3 on t1.customer_id = t3.id
16   - <where>
17   - t1.group_id = #{condition.groupId}
18   - and ((t1.state in (2, 3) and t1.origin_user != t1.follow_user)
19   - or (t1.state = 3 and t1.finished = 0))
20   - <if test="condition.kw != null and condition.kw !='' ">
21   - and (t2.plate_no like concat('%', #{condition.kw}, '%')
22   - or t3.plate_no like concat('%', #{condition.kw}, '%'))
23   - </if>
24   - <if test="condition.type !=null">
25   - and t1.type = #{condition.type}
26   - </if>
27   - <if test="condition.userId !=null">
28   - and (t1.origin_user = #{condition.userId} or t1.follow_user = #{condition.userId})
29   - </if>
30   - <if test="condition.shopList != null and condition.shopList.size > 0 ">
31   - and (
32   - t1.origin_shop in
33   - <foreach collection="condition.shopList" item ="shopId" index="i" open="(" close=")" separator=",">
34   - #{shopId}
35   - </foreach>
36   - or t1.follow_shop in
37   - <foreach collection="condition.shopList" item ="shopId" index="i" open="(" close=")" separator=",">
38   - #{shopId}
39   - </foreach>
40   - )
41   - </if>
42   - </where>
43   - order by t1.id asc
44   - limit #{startIndex},#{pageSize};
45   - </select>
  38 + where t1.state = 3
  39 + and ((t1.finished = 0 and
  40 + t1.deadline >= #{condition.startTime} and t1.deadline &lt; #{condition.endTime}) or
  41 + (t1.finished = 1 and
  42 + t1.finish_time >= #{condition.startTime} and t1.finish_time &lt; #{condition.endTime}))
46 43  
47   - <select
48   - id="followList"
49   - resultType="cn.fw.valhalla.domain.dto.FollowPoolDTO"
50   - parameterType="cn.fw.valhalla.domain.query.FollowPoolQueryVO"
51   - >
52   - SELECT t1.id, t1.type, t1.finished, t1.origin_user, t1.origin_time, t1.finish_user,
53   - t1.origin_shop, t1.finish_shop, t1.finish_time, t1.changed, t1.deadline,
54   - ifnull(t2.plate_no, t3.plate_no) plate_no, t1.follow_user, t1.follow_shop follow_shop,
55   - t2.id customer_id, t1.state
  44 + union
  45 + SELECT t1.id,
  46 + ifnull(t2.plate_no, t3.plate_no) plate_no,
  47 + t1.type type,
  48 + 0 redistribution,
  49 + t1.origin_user user_id,
  50 + t1.origin_shop shop_id,
  51 + (select count(1) from follow_record t4
  52 + where t4.task_id = t1.id
  53 + and t4.user_id = t1.origin_user
  54 + and t4.follow_time is not null) times,
  55 + TIMESTAMPDIFF(HOUR, now(), t1.deadline) remaining,
  56 + case t1.changed
  57 + when 1 then 3
  58 + when 0 then if(t1.finished = 0, 3, 2)
  59 + end state,
  60 + t1.finish_time finish_time,
  61 + t1.change_user_time defeat_time,
  62 + if((select count(1) from approve_record t5
  63 + where t5.data_id = t1.id and t5.passed = 1) != 0, 1, 2) initiative,
  64 + t1.group_id group_id,
  65 + t2.id customer_id,
  66 + t1.origin_shop,
  67 + t1.finish_shop,
  68 + t1.finished,
  69 + t1.state origin_state
56 70 FROM follow_task t1
57 71 left join customer t2 on t1.customer_id = t2.id
58 72 left join accident_pool t3 on t1.customer_id = t3.id
59   - <where>
60   - t1.group_id = #{condition.groupId}
61   - and t1.state = 2
62   - and t1.finished = 0
63   - <if test="condition.kw != null and condition.kw !='' ">
64   - and (t2.plate_no like concat('%', #{condition.kw}, '%')
65   - or t3.plate_no like concat('%', #{condition.kw}, '%'))
66   - </if>
67   - <if test="condition.type !=null">
68   - and t1.type = #{condition.type}
69   - </if>
70   - <if test="condition.userId !=null">
71   - and t1.follow_user = #{condition.userId}
72   - </if>
73   - <if test="condition.shopList != null and condition.shopList.size > 0 ">
74   - and t1.follow_shop in
75   - <foreach collection="condition.shopList" item ="shopId" index="i" open="(" close=")" separator=",">
76   - #{shopId}
77   - </foreach>
78   - </if>
79   - </where>
80   - order by t1.id asc
81   - limit #{startIndex},#{pageSize};
82   - </select>
  73 + where t1.state = 3
  74 + and t1.type != 3
  75 + and ((t1.finished = 0 and
  76 + t1.deadline >= #{condition.startTime} and t1.deadline &lt; #{condition.endTime}) or
  77 + (t1.finished = 1 and
  78 + t1.finish_time >= #{condition.startTime} and t1.finish_time &lt; #{condition.endTime}))
83 79  
84   - <select
85   - id="completeList"
86   - resultType="cn.fw.valhalla.domain.dto.FollowPoolDTO"
87   - parameterType="cn.fw.valhalla.domain.query.FollowPoolQueryVO"
88   - >
89   - SELECT t1.id, t1.type, t1.finished, t1.origin_user, t1.origin_time, t1.finish_user,
90   - t1.origin_shop, t1.finish_shop, t1.finish_time, t1.changed, t1.deadline,
91   - ifnull(t2.plate_no, t3.plate_no) plate_no, t1.follow_user, t1.follow_shop follow_shop,
92   - t2.id customer_id, t1.state
  80 + union
  81 + SELECT t1.id,
  82 + ifnull(t2.plate_no, t3.plate_no) plate_no,
  83 + t1.type type,
  84 + t1.changed redistribution,
  85 + t1.follow_user user_id,
  86 + t1.follow_shop shop_id,
  87 + (select count(1) from follow_record t4
  88 + where t4.task_id = t1.id
  89 + and t4.user_id = t1.follow_user
  90 + and t4.follow_time is not null) times,
  91 + TIMESTAMPDIFF(HOUR, now(), t1.deadline) remaining,
  92 + 1 state,
  93 + t1.finish_time finish_time,
  94 + null defeat_time,
  95 + null initiative,
  96 + t1.group_id group_id,
  97 + t2.id customer_id,
  98 + t1.origin_shop,
  99 + t1.finish_shop,
  100 + t1.finished,
  101 + t1.state origin_state
93 102 FROM follow_task t1
94 103 left join customer t2 on t1.customer_id = t2.id
95 104 left join accident_pool t3 on t1.customer_id = t3.id
  105 + where t1.state = 2
  106 + and t1.begin_time &lt; #{condition.endTime}
  107 + and t1.deadline >= #{condition.endTime}) followPool
96 108 <where>
97   - t1.group_id = #{condition.groupId}
98   - and t1.state = 3
99   - and t1.finished = 1
100   - <if test="condition.kw != null and condition.kw !='' ">
101   - and (t2.plate_no like concat('%', #{condition.kw}, '%')
102   - or t3.plate_no like concat('%', #{condition.kw}, '%'))
  109 + <if test="condition.groupId !=null">
  110 + and followPool.group_id = #{condition.groupId}
  111 + </if>
  112 + <if test="condition.plateNo != null and condition.plateNo !='' ">
  113 + and followPool.plate_no like concat('%', #{condition.plateNo}, '%')
103 114 </if>
104 115 <if test="condition.type !=null">
105   - and t1.type = #{condition.type}
  116 + and followPool.type = #{condition.type}
  117 + </if>
  118 + <if test="condition.shopId !=null">
  119 + and followPool.shop_id = #{condition.shopId}
106 120 </if>
107 121 <if test="condition.userId !=null">
108   - and t1.finish_user = #{condition.userId}
  122 + and followPool.user_id = #{condition.userId}
  123 + </if>
  124 + <if test="condition.redistribution !=null">
  125 + and followPool.redistribution = #{condition.redistribution}
  126 + </if>
  127 + <if test="condition.state !=null">
  128 + and followPool.state = #{condition.state}
109 129 </if>
110   - <if test="condition.shopList != null and condition.shopList.size > 0 ">
111   - and t1.finish_shop in
112   - <foreach collection="condition.shopList" item ="shopId" index="i" open="(" close=")" separator=",">
113   - #{shopId}
114   - </foreach>
  130 + <if test="condition.initiative !=null">
  131 + and followPool.initiative = #{condition.initiative}
115 132 </if>
116 133 </where>
117   - order by t1.id asc
  134 + <if test="condition.orderString != null and condition.orderString !='' ">
  135 + ${condition.orderString}
  136 + </if>
118 137 limit #{startIndex},#{pageSize};
119 138 </select>
120 139 </mapper>
... ...
fw-valhalla-dao/src/main/resources/mapper/LeaveNeedDoMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.fw.valhalla.dao.mapper.LeaveNeedDoMapper">
  4 +
  5 +</mapper>
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/ApproveRecord.java
... ... @@ -2,6 +2,7 @@ package cn.fw.valhalla.domain.db;
2 2  
3 3 import cn.fw.common.data.entity.BaseAuditableTimeEntity;
4 4 import cn.fw.valhalla.domain.enums.ApproveStateEnum;
  5 +import cn.fw.valhalla.domain.enums.ApproveTypeEnum;
5 6 import lombok.Data;
6 7 import lombok.EqualsAndHashCode;
7 8 import lombok.ToString;
... ... @@ -40,4 +41,8 @@ public class ApproveRecord extends BaseAuditableTimeEntity&lt;ApproveRecord, Long&gt;
40 41 * 通过与否
41 42 */
42 43 private Boolean passed;
  44 + /**
  45 + * 审批类型
  46 + */
  47 + private ApproveTypeEnum type;
43 48 }
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/LeaveNeedDo.java 0 → 100644
  1 +package cn.fw.valhalla.domain.db;
  2 +
  3 +import cn.fw.common.data.entity.BaseAuditableTimeEntity;
  4 +import cn.fw.valhalla.domain.enums.LeaveReasonEnum;
  5 +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +
  10 +import java.util.Date;
  11 +
  12 +/**
  13 + * @author : kurisu
  14 + * @className : LeaveNeedDo
  15 + * @description : 人员变动待处理事项
  16 + * @date: 2020-10-16 16:47
  17 + */
  18 +@Data
  19 +@ToString(callSuper = true)
  20 +@EqualsAndHashCode(callSuper = true)
  21 +public class LeaveNeedDo extends BaseAuditableTimeEntity<LeaveNeedDo, Long> {
  22 + /**
  23 + * 用户id
  24 + */
  25 + private Long userId;
  26 + /**
  27 + * 用户名
  28 + */
  29 + private String userName;
  30 + /**
  31 + * 事件类型
  32 + */
  33 + private LeaveTodoTypeEnum type;
  34 + /**
  35 + * 用户所属门店
  36 + */
  37 + private Long shopId;
  38 + /**
  39 + * 用户变动原因
  40 + */
  41 + private LeaveReasonEnum reason;
  42 + /**
  43 + * 生效时间
  44 + */
  45 + private Date effectiveTime;
  46 + /**
  47 + * 是否已完成处理
  48 + */
  49 + private Boolean done;
  50 +}
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/customer/AccidentPool.java
... ... @@ -23,6 +23,10 @@ public class AccidentPool extends BaseAuditableTimeEntity&lt;AccidentPool, Long&gt; {
23 23 */
24 24 private String mobile;
25 25 /**
  26 + * 报案手机号
  27 + */
  28 + private String reportMobile;
  29 + /**
26 30 * 车牌号
27 31 */
28 32 private String plateNo;
... ... @@ -63,15 +67,23 @@ public class AccidentPool extends BaseAuditableTimeEntity&lt;AccidentPool, Long&gt; {
63 67 */
64 68 private String reportNum;
65 69 /**
66   - * 服务站id
  70 + * 所属门店id
67 71 */
68 72 private Long shopId;
69 73 /**
70   - * 集团id
  74 + * 所属门店
71 75 */
72   - private Long groupId;
  76 + private String shopName;
  77 + /**
  78 + * 报案地点
  79 + */
  80 + private String address;
73 81 /**
74   - * 跟进人id
  82 + * 短信
75 83 */
76   - private Long userId;
  84 + private String sms;
  85 + /**
  86 + * 集团id
  87 + */
  88 + private Long groupId;
77 89 }
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/AccidentPoolDTO.java
... ... @@ -23,9 +23,13 @@ public class AccidentPoolDTO {
23 23 /**
24 24 * 电话号码
25 25 */
26   - @NotBlank(message = "电话号码不能为空")
27 26 private String mobile;
28 27 /**
  28 + * 报案手机号
  29 + */
  30 + @NotBlank(message = "报案手机号不能为空")
  31 + private String reportMobile;
  32 + /**
29 33 * 车牌号
30 34 */
31 35 @NotBlank(message = "车牌号不能为空")
... ... @@ -63,7 +67,11 @@ public class AccidentPoolDTO {
63 67 */
64 68 private String insurerName;
65 69 /**
66   - * 门店id
  70 + * 所属门店id
67 71 */
68 72 private Long shopId;
  73 + /**
  74 + * 报案地点
  75 + */
  76 + private String address;
69 77 }
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/FollowPoolDTO.java
... ... @@ -25,55 +25,55 @@ public class FollowPoolDTO {
25 25 */
26 26 private Integer type;
27 27 /**
28   - * 原始数据产生时间
  28 + * 二次跟进
29 29 */
30   - private Date originTime;
  30 + private Boolean redistribution;
31 31 /**
32   - * 任务开始时间
  32 + * 人员id
33 33 */
34   - private Date beginTime;
  34 + private Long userId;
35 35 /**
36   - * 原始跟进顾问id
  36 + * 门店id
37 37 */
38   - private Long originUser;
  38 + private Long shopId;
39 39 /**
40   - * 原始跟进门店
41   - */
42   - private Long originShop;
43   - /**
44   - * 完成人
  40 + * 跟进次数
45 41 */
46   - private Long finishUser;
  42 + private Integer times;
47 43 /**
48   - * 完成门店
  44 + * 剩余天数
49 45 */
50   - private Long finishShop;
  46 + private Integer remaining;
51 47 /**
52   - * 状态
  48 + * 状态 1:进行中 2:已成交 3:战败
53 49 */
54 50 private Integer state;
55 51 /**
56   - * 完成人员更换
  52 + * 成交时间
57 53 */
58   - private Boolean changed;
  54 + private Date finishTime;
59 55 /**
60   - * 当前跟进服务顾问id
  56 + * 战败时间
61 57 */
62   - private Long followUser;
  58 + private Date defeatTime;
63 59 /**
64   - * 当前跟进服务站
  60 + * 战败类型
65 61 */
66   - private Long followShop;
  62 + private Integer initiative;
67 63 /**
68   - * 截止日期
  64 + * 集团id
69 65 */
70   - private Date deadline;
  66 + private Long groupId;
  67 +
  68 +
  69 + private Integer originState;
  70 + private Boolean finished;
71 71 /**
72   - * 是否完成任务
  72 + * 原始跟进门店
73 73 */
74   - private Boolean finished;
  74 + private Long originShop;
75 75 /**
76   - * 完成时间
  76 + * 完成门店
77 77 */
78   - private Date finishTime;
  78 + private Long finishShop;
79 79 }
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/LeaveAllocationDTO.java 0 → 100644
  1 +package cn.fw.valhalla.domain.dto;
  2 +
  3 +import cn.fw.valhalla.common.enums.AllocationTypeEnum;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotNull;
  7 +
  8 +/**
  9 + * @author : kurisu
  10 + * @className : LeaveAllocationDTO
  11 + * @description : 离职分配DTO
  12 + * @date: 2020-10-16 17:52
  13 + */
  14 +@Data
  15 +public class LeaveAllocationDTO {
  16 + @NotNull(message = "记录id不能为空")
  17 + private Long id;
  18 +
  19 + @NotNull(message = "分配方式不能为空")
  20 + private Integer allocationType;
  21 +
  22 + /**
  23 + * 指定人员id
  24 + */
  25 + private Long userId;
  26 +
  27 + /**
  28 + * 门店id (前端无关)
  29 + */
  30 + private Long shopId;
  31 +
  32 + /**
  33 + * 分配方式 (前端无关)
  34 + */
  35 + private AllocationTypeEnum type;
  36 + /**
  37 + * 顾问id (前端无关)
  38 + */
  39 + private Long adviserId;
  40 +}
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveStateEnum.java
... ... @@ -20,6 +20,10 @@ public enum ApproveStateEnum implements IEnum&lt;Integer&gt; {
20 20 * 完成回调
21 21 */
22 22 DONE(2, "完成回调"),
  23 + /**
  24 + * 已取消
  25 + */
  26 + CANCELED(3, "已取消"),
23 27 ;
24 28  
25 29 /**
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveTypeEnum.java 0 → 100644
  1 +package cn.fw.valhalla.domain.enums;
  2 +
  3 +import com.baomidou.mybatisplus.core.enums.IEnum;
  4 +import com.fasterxml.jackson.annotation.JsonCreator;
  5 +import com.fasterxml.jackson.annotation.JsonValue;
  6 +import lombok.Getter;
  7 +
  8 +/**
  9 + * @author : kurisu
  10 + * @className : ApproveTypeEnum
  11 + * @description : 审批类型
  12 + * @date: 2020-10-15 17:37
  13 + */
  14 +public enum ApproveTypeEnum implements IEnum<Integer> {
  15 + /**
  16 + * 等待回调
  17 + */
  18 + FOLLOW_DEFEAT(1, "跟进战败"),
  19 + /**
  20 + * 完成回调
  21 + */
  22 + OTHER(2, "其他"),
  23 + ;
  24 +
  25 + /**
  26 + * 值
  27 + */
  28 + private final Integer value;
  29 + /**
  30 + * 名称
  31 + */
  32 + @Getter
  33 + private final String name;
  34 +
  35 + ApproveTypeEnum(final Integer value, final String name) {
  36 + this.value = value;
  37 + this.name = name;
  38 + }
  39 +
  40 + /**
  41 + * 根据枚举值获取枚举对象
  42 + */
  43 + @JsonCreator
  44 + public static ApproveTypeEnum ofValue(final Integer value) {
  45 + for (final ApproveTypeEnum typeEnum : ApproveTypeEnum.values()) {
  46 + if (typeEnum.value.equals(value)) {
  47 + return typeEnum;
  48 + }
  49 + }
  50 + return null;
  51 + }
  52 +
  53 + /**
  54 + * 获取值
  55 + *
  56 + * @return 值
  57 + */
  58 + @JsonValue
  59 + @Override
  60 + public Integer getValue() {
  61 + return value;
  62 + }
  63 +
  64 + /**
  65 + * 获取描述
  66 + *
  67 + * @return 值
  68 + */
  69 + @JsonCreator
  70 + public static String getNameByVale(final Integer value) {
  71 + for (final ApproveTypeEnum typeEnum : ApproveTypeEnum.values()) {
  72 + if (typeEnum.value.equals(value)) {
  73 + return typeEnum.getName();
  74 + }
  75 + }
  76 + return "";
  77 + }
  78 +}
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/LeaveReasonEnum.java 0 → 100644
  1 +package cn.fw.valhalla.domain.enums;
  2 +
  3 +import com.baomidou.mybatisplus.core.enums.IEnum;
  4 +import com.fasterxml.jackson.annotation.JsonCreator;
  5 +import com.fasterxml.jackson.annotation.JsonValue;
  6 +import lombok.Getter;
  7 +
  8 +/**
  9 + * @author : kurisu
  10 + * @className : LeaveReasonEnum
  11 + * @description : 人员变动类型
  12 + * @date: 2020-08-11 17:37
  13 + */
  14 +public enum LeaveReasonEnum implements IEnum<Integer> {
  15 + /**
  16 + * 离职
  17 + */
  18 + LEAVE(1, "离职"),
  19 + /**
  20 + * 调岗
  21 + */
  22 + CHANGE(2, "调岗"),
  23 + /**
  24 + * 其他
  25 + */
  26 + OTHER(3, "其他"),
  27 + ;
  28 +
  29 + /**
  30 + * 值
  31 + */
  32 + private final Integer value;
  33 + /**
  34 + * 名称
  35 + */
  36 + @Getter
  37 + private final String name;
  38 +
  39 + LeaveReasonEnum(final Integer value, final String name) {
  40 + this.value = value;
  41 + this.name = name;
  42 + }
  43 +
  44 + /**
  45 + * 根据枚举值获取枚举对象
  46 + */
  47 + @JsonCreator
  48 + public static LeaveReasonEnum ofValue(final Integer value) {
  49 + for (final LeaveReasonEnum typeEnum : LeaveReasonEnum.values()) {
  50 + if (typeEnum.value.equals(value)) {
  51 + return typeEnum;
  52 + }
  53 + }
  54 + return null;
  55 + }
  56 +
  57 + /**
  58 + * 获取值
  59 + *
  60 + * @return 值
  61 + */
  62 + @JsonValue
  63 + @Override
  64 + public Integer getValue() {
  65 + return value;
  66 + }
  67 +
  68 + /**
  69 + * 获取描述
  70 + *
  71 + * @return 值
  72 + */
  73 + @JsonCreator
  74 + public static String getNameByVale(final Integer value) {
  75 + for (final LeaveReasonEnum typeEnum : LeaveReasonEnum.values()) {
  76 + if (typeEnum.value.equals(value)) {
  77 + return typeEnum.getName();
  78 + }
  79 + }
  80 + return "";
  81 + }
  82 +}
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/LeaveTodoTypeEnum.java 0 → 100644
  1 +package cn.fw.valhalla.domain.enums;
  2 +
  3 +import com.baomidou.mybatisplus.core.enums.IEnum;
  4 +import com.fasterxml.jackson.annotation.JsonCreator;
  5 +import com.fasterxml.jackson.annotation.JsonValue;
  6 +import lombok.Getter;
  7 +
  8 +/**
  9 + * @author : kurisu
  10 + * @className : LeaveTodoTypeEnum
  11 + * @description : 人员变动待处理事件类型
  12 + * @date: 2020-08-11 17:37
  13 + */
  14 +public enum LeaveTodoTypeEnum implements IEnum<Integer> {
  15 + /**
  16 + * 客户待分配
  17 + */
  18 + CUSTOMER(10, "客户待分配"),
  19 + /**
  20 + * 其他
  21 + */
  22 + OTHER(20, "其他"),
  23 + ;
  24 +
  25 + /**
  26 + * 值
  27 + */
  28 + private final Integer value;
  29 + /**
  30 + * 名称
  31 + */
  32 + @Getter
  33 + private final String name;
  34 +
  35 + LeaveTodoTypeEnum(final Integer value, final String name) {
  36 + this.value = value;
  37 + this.name = name;
  38 + }
  39 +
  40 + /**
  41 + * 根据枚举值获取枚举对象
  42 + */
  43 + @JsonCreator
  44 + public static LeaveTodoTypeEnum ofValue(final Integer value) {
  45 + for (final LeaveTodoTypeEnum typeEnum : LeaveTodoTypeEnum.values()) {
  46 + if (typeEnum.value.equals(value)) {
  47 + return typeEnum;
  48 + }
  49 + }
  50 + return null;
  51 + }
  52 +
  53 + /**
  54 + * 获取值
  55 + *
  56 + * @return 值
  57 + */
  58 + @JsonValue
  59 + @Override
  60 + public Integer getValue() {
  61 + return value;
  62 + }
  63 +
  64 + /**
  65 + * 获取描述
  66 + *
  67 + * @return 值
  68 + */
  69 + @JsonCreator
  70 + public static String getNameByVale(final Integer value) {
  71 + for (final LeaveTodoTypeEnum typeEnum : LeaveTodoTypeEnum.values()) {
  72 + if (typeEnum.value.equals(value)) {
  73 + return typeEnum.getName();
  74 + }
  75 + }
  76 + return "";
  77 + }
  78 +}
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingTypeEnum.java
... ... @@ -44,6 +44,10 @@ public enum SettingTypeEnum implements IEnum&lt;Integer&gt; {
44 44 * 提醒次数
45 45 */
46 46 NOTICE_TIMES(8, "提醒次数", 8),
  47 + /**
  48 + * 首保集团标准最低值(首保用)
  49 + */
  50 + REVISE_RATIO(9, "集团标准最低值", 9),
47 51 ;
48 52  
49 53 /**
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingUnitEnum.java
... ... @@ -32,6 +32,10 @@ public enum SettingUnitEnum implements IEnum&lt;Integer&gt; {
32 32 * 月
33 33 */
34 34 MONTH(5, "月"),
  35 + /**
  36 + * 百分比
  37 + */
  38 + RATIO(9, "%"),
35 39 ;
36 40  
37 41 /**
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/FollowPoolQueryVO.java
1 1 package cn.fw.valhalla.domain.query;
2 2  
3 3 import cn.fw.common.page.BasePageQuery;
4   -import cn.fw.valhalla.common.utils.StringUtils;
  4 +import cn.fw.valhalla.common.utils.DateUtil;
5 5 import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
7 7 import lombok.ToString;
8   -import org.springframework.util.CollectionUtils;
  8 +import org.apache.commons.lang3.StringUtils;
  9 +import org.apache.commons.lang3.math.NumberUtils;
9 10  
10   -import java.util.Arrays;
11   -import java.util.List;
12   -import java.util.stream.Collectors;
  11 +import java.time.Instant;
  12 +import java.time.LocalDateTime;
  13 +import java.time.ZoneId;
  14 +import java.util.Date;
  15 +import java.util.Objects;
13 16  
14 17 /**
15 18 * 档案查询条件
... ... @@ -22,20 +25,60 @@ import java.util.stream.Collectors;
22 25 @EqualsAndHashCode(callSuper = true)
23 26 public class FollowPoolQueryVO extends BasePageQuery {
24 27 private Integer type;
25   - private String kw;
  28 + private String plateNo;
26 29 private Long userId;
27   - private String shopIds;
  30 + private Long shopId;
  31 + /**
  32 + * 跟进状态
  33 + */
  34 + private Integer state;
  35 + /**
  36 + * 二次分配
  37 + */
  38 + private Integer redistribution;
  39 + /**
  40 + * 主动放弃
  41 + */
  42 + private Integer initiative;
  43 + private String startTime;
  44 + private String endTime;
  45 +
  46 + /**
  47 + * 1升序 2降序
  48 + */
  49 + private Integer order;
  50 + private String orderAtt;
  51 +
  52 + private String orderString;
28 53 private Long groupId;
29   - private List<Long> shopList;
30 54  
31   - public List<Long> getShopList() {
32   - if (StringUtils.isEmpty(this.shopIds)) {
  55 + public Integer getInitiative() {
  56 + if (Objects.isNull(initiative)) {
33 57 return null;
34 58 }
35   - List<Long> list = Arrays.stream(this.shopIds.split(",")).filter(StringUtils::isValid).map(Long::valueOf).collect(Collectors.toList());
36   - if (CollectionUtils.isEmpty(list)) {
  59 + return initiative == 1 ? initiative : 0;
  60 + }
  61 +
  62 + public Integer getRedistribution() {
  63 + if (Objects.isNull(redistribution)) {
37 64 return null;
38 65 }
39   - return list;
  66 + return redistribution == 1 ? redistribution : 0;
  67 + }
  68 +
  69 + public Date getStartTime() {
  70 + if (StringUtils.isNotBlank(startTime) && NumberUtils.isDigits(startTime)) {
  71 + LocalDateTime localDateTime = Instant.ofEpochMilli(NumberUtils.toLong(startTime)).atZone(ZoneId.systemDefault()).toLocalDateTime();
  72 + return DateUtil.getBeginInTime(DateUtil.localDateTime2Date(localDateTime));
  73 + }
  74 + return DateUtil.getMonthFirstDay();
  75 + }
  76 +
  77 + public Date getEndTime() {
  78 + if (StringUtils.isNotBlank(endTime) && NumberUtils.isDigits(endTime)) {
  79 + LocalDateTime localDateTime = Instant.ofEpochMilli(NumberUtils.toLong(endTime)).atZone(ZoneId.systemDefault()).toLocalDateTime();
  80 + return DateUtil.getEndInTime(DateUtil.localDateTime2Date(localDateTime));
  81 + }
  82 + return new Date();
40 83 }
41 84 }
42 85 \ No newline at end of file
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/LeaveQueryVO.java 0 → 100644
  1 +package cn.fw.valhalla.domain.query;
  2 +
  3 +import cn.fw.common.page.BasePageQuery;
  4 +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.util.Objects;
  10 +
  11 +/**
  12 + * 档案查询条件
  13 + *
  14 + * @author kurisu
  15 + */
  16 +
  17 +@Data
  18 +@ToString(callSuper = true)
  19 +@EqualsAndHashCode(callSuper = true)
  20 +public class LeaveQueryVO extends BasePageQuery {
  21 + private Integer type;
  22 +
  23 + public LeaveTodoTypeEnum getType() {
  24 + if (Objects.isNull(type)) {
  25 + return null;
  26 + }
  27 + return LeaveTodoTypeEnum.ofValue(type);
  28 + }
  29 +}
0 30 \ No newline at end of file
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/LeaveNeedDoVO.java 0 → 100644
  1 +package cn.fw.valhalla.domain.vo;
  2 +
  3 +import cn.fw.valhalla.domain.db.LeaveNeedDo;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +import org.springframework.lang.NonNull;
  7 +
  8 +import java.util.Date;
  9 +
  10 +/**
  11 + * @author : kurisu
  12 + * @className : LeaveNeedDoVO
  13 + * @description : 保有客待分配列表
  14 + * @date: 2020-10-16 16:56
  15 + */
  16 +@Data
  17 +@ToString(callSuper = true)
  18 +public class LeaveNeedDoVO {
  19 + private Long id;
  20 + /**
  21 + * 用户id
  22 + */
  23 + private Long userId;
  24 + /**
  25 + * 用户名
  26 + */
  27 + private String userName;
  28 + /**
  29 + * 用户所属门店
  30 + */
  31 + private Long shopId;
  32 + /**
  33 + * 用户变动原因
  34 + */
  35 + private Integer reason;
  36 + /**
  37 + * 生效时间
  38 + */
  39 + private Date effectiveTime;
  40 + /**
  41 + * 是否已完成处理
  42 + */
  43 + private Boolean done;
  44 + /**
  45 + * 保有客数量
  46 + */
  47 + private Integer customerNum;
  48 +
  49 + public static LeaveNeedDoVO with(@NonNull LeaveNeedDo db, int i) {
  50 + LeaveNeedDoVO vo = new LeaveNeedDoVO();
  51 + vo.setId(db.getId());
  52 + vo.setUserId(db.getUserId());
  53 + vo.setUserName(db.getUserName());
  54 + vo.setShopId(db.getShopId());
  55 + vo.setReason(db.getReason().getValue());
  56 + vo.setEffectiveTime(db.getEffectiveTime());
  57 + vo.setDone(db.getDone());
  58 + vo.setCustomerNum(i);
  59 + return vo;
  60 + }
  61 +}
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/PostUserVO.java 0 → 100644
  1 +package cn.fw.valhalla.domain.vo;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +
  7 +import java.io.Serializable;
  8 +
  9 +/**
  10 + * @author kurisu
  11 + */
  12 +@Data
  13 +@AllArgsConstructor
  14 +@NoArgsConstructor
  15 +public class PostUserVO implements Serializable {
  16 + private static final long serialVersionUID = -6108591548534160179L;
  17 + /**
  18 + * 用户id
  19 + */
  20 + private Long userId;
  21 +
  22 + /**
  23 + * 用户姓名
  24 + */
  25 + private String userName;
  26 +}
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/customer/CustomerDetailVO.java
... ... @@ -5,6 +5,7 @@ import cn.fw.valhalla.common.utils.StringUtils;
5 5 import lombok.Data;
6 6  
7 7 import java.util.Arrays;
  8 +import java.util.Date;
8 9 import java.util.List;
9 10 import java.util.stream.Collectors;
10 11  
... ... @@ -97,6 +98,10 @@ public class CustomerDetailVO {
97 98 * 专属服务顾问名称
98 99 */
99 100 private String adviserName;
  101 + /**
  102 + * 购车日期
  103 + */
  104 + private Date buyDate;
100 105  
101 106 public List<String> getTags() {
102 107 if (StringUtils.isValid(this.tags)) {
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/ACDetailVO.java
... ... @@ -18,39 +18,27 @@ import java.util.Date;
18 18 @EqualsAndHashCode(callSuper = true)
19 19 public class ACDetailVO extends FollowDetailVO {
20 20 /**
21   - * 报案号
22   - */
23   - private String reportNum;
24   - /**
25 21 * 地址
26 22 */
27 23 private String address;
28 24 /**
29   - * 纬度
30   - */
31   - private BigDecimal lat;
32   - /**
33   - * 经度
34   - */
35   - private BigDecimal lng;
36   - /**
37   - * 事故原因
  25 + * 交强险保险公司名称
38 26 */
39   - private String reason;
  27 + private String insComName;
40 28 /**
41   - * 交强险保险公司名称
  29 + * 报案手机号
42 30 */
43   - private String tclInsComName;
  31 + private String reportMobile;
44 32 /**
45   - * 交强险保险到期时间
  33 + * 所属门店
46 34 */
47   - private Date tclInsExpiration;
  35 + private Long shopId;
48 36 /**
49   - * 商业险保险公司名称
  37 + * 所属门店
50 38 */
51   - private String busInsComName;
  39 + private String shopName;
52 40 /**
53   - * 商业险保险到期时间
  41 + * 短信详情
54 42 */
55   - private Date busInsExpiration;
  43 + private String sms;
56 44 }
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowDetailVO.java
1 1 package cn.fw.valhalla.domain.vo.follow;
2 2  
3 3 import cn.fw.common.json.MaskMobilePhone;
  4 +import cn.fw.valhalla.common.utils.StringUtils;
4 5 import lombok.Data;
5 6  
  7 +import java.util.Arrays;
6 8 import java.util.Date;
  9 +import java.util.List;
7 10 import java.util.Objects;
  11 +import java.util.stream.Collectors;
8 12  
9 13 /**
10 14 * @author : kurisu
... ... @@ -77,4 +81,13 @@ public class FollowDetailVO {
77 81 long ms = deadline.getTime() - System.currentTimeMillis();
78 82 return ms / 1000;
79 83 }
  84 +
  85 + public List<String> getTags() {
  86 + if (StringUtils.isValid(this.tags)) {
  87 + return Arrays.stream(this.tags.split(","))
  88 + .filter(StringUtils::isValid)
  89 + .collect(Collectors.toList());
  90 + }
  91 + return null;
  92 + }
80 93 }
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowPoolListVO.java
1 1 package cn.fw.valhalla.domain.vo.follow;
2 2  
  3 +import cn.fw.valhalla.domain.enums.FollowTypeEnum;
3 4 import lombok.Data;
4 5  
5 6 import java.util.Date;
  7 +import java.util.Objects;
6 8  
7 9 /**
8 10 * @author : kurisu
... ... @@ -12,6 +14,7 @@ import java.util.Date;
12 14 */
13 15 @Data
14 16 public class FollowPoolListVO {
  17 + private Long id;
15 18 /**
16 19 * 车牌
17 20 */
... ... @@ -41,11 +44,37 @@ public class FollowPoolListVO {
41 44 */
42 45 private Integer remaining;
43 46 /**
44   - * 战败类型
  47 + * 跟进状态
45 48 */
46   - private String defeatType;
  49 + private Integer state;
47 50 /**
48 51 * 成交时间
49 52 */
50 53 private Date finishTime;
  54 + /**
  55 + * 战败时间
  56 + */
  57 + private Date defeatTime;
  58 + /**
  59 + * 战败类型
  60 + */
  61 + private String defeatType;
  62 + /**
  63 + * 战败描述 (客户流向)
  64 + */
  65 + private String defeatDesc;
  66 +
  67 + public String getRemaining() {
  68 + if (Objects.isNull(remaining)) {
  69 + return null;
  70 + }
  71 + StringBuilder sb = new StringBuilder();
  72 + int num = remaining <= 0 ? 0 : remaining;
  73 + if (FollowTypeEnum.AC.getValue().equals(type)) {
  74 + sb.append(num).append("小时");
  75 + } else {
  76 + sb.append(num / 24).append("天");
  77 + }
  78 + return sb.toString();
  79 + }
51 80 }
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/IRDetailVO.java
... ... @@ -17,10 +17,6 @@ import java.util.Date;
17 17 @EqualsAndHashCode(callSuper = true)
18 18 public class IRDetailVO extends FollowDetailVO {
19 19 /**
20   - * 购车价
21   - */
22   - private Long buyPrice;
23   - /**
24 20 * 交强险保险公司名称
25 21 */
26 22 private String tclInsComName;
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/setting/SettingVO.java
1 1 package cn.fw.valhalla.domain.vo.setting;
2 2  
3 3 import cn.fw.valhalla.domain.db.setting.FollowSettingDetail;
  4 +import cn.fw.valhalla.domain.enums.SettingTypeEnum;
4 5 import lombok.Data;
5 6 import lombok.ToString;
6 7  
... ... @@ -40,6 +41,9 @@ public class SettingVO {
40 41 SettingVO vo = new SettingVO();
41 42 vo.setId(detail.getId());
42 43 vo.setDetailValue(detail.getDetailValue());
  44 + if (SettingTypeEnum.REVISE_RATIO.equals(detail.getType())) {
  45 + vo.setDetailValue(detail.getDetailValue() / 100);
  46 + }
43 47 vo.setSettingId(detail.getSettingId());
44 48 vo.setType(detail.getType().getValue());
45 49 vo.setUnit(detail.getUnit().getValue());
... ...
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/erp/UserRoleRpcService.java
... ... @@ -5,6 +5,7 @@ import cn.fw.erp.sdk.api.UserRoleApi;
5 5 import cn.fw.erp.sdk.api.result.UserRoleDataRange;
6 6 import cn.fw.erp.sdk.api.result.UserRoleInfo;
7 7 import com.alibaba.fastjson.JSON;
  8 +import com.alibaba.fastjson.JSONObject;
8 9 import lombok.extern.slf4j.Slf4j;
9 10 import org.springframework.stereotype.Service;
10 11  
... ... @@ -31,11 +32,11 @@ public class UserRoleRpcService {
31 32 }
32 33  
33 34 /**
34   - * 获取用户管理的门店
  35 + * 查询用户角色的数据权限范围(门店)
35 36 *
36 37 * @param userId 用户id
37 38 * @param roleCode 角色码
38   - * @return 用户管理门店
  39 + * @return 门店ids
39 40 */
40 41 public List<Long> getManageShopIds(Long userId, String roleCode) {
41 42 if (userId == null) {
... ... @@ -43,7 +44,7 @@ public class UserRoleRpcService {
43 44 }
44 45 try {
45 46 Message<List<UserRoleDataRange>> msg = userRoleApi.queryUserRoleDataRange(userId, roleCode);
46   - log.warn("调用ERP系统查询用户数据范围,userId:{},roleCode:{}, result:{}", userId, roleCode, msg);
  47 + log.warn("调用ERP系统查询用户数据范围,userId:{},roleCode:{}, result:{}", userId, roleCode, JSONObject.toJSONString(msg));
47 48 if (!msg.isSuccess()) {
48 49 return Collections.emptyList();
49 50 }
... ...
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/flow/FlowApproveRpc.java
... ... @@ -10,6 +10,7 @@ import org.springframework.beans.BeanUtils;
10 10 import org.springframework.beans.factory.annotation.Autowired;
11 11 import org.springframework.stereotype.Service;
12 12  
  13 +import java.util.Collections;
13 14 import java.util.Objects;
14 15  
15 16 import static cn.fw.common.businessvalidator.Validator.BV;
... ... @@ -45,4 +46,15 @@ public class FlowApproveRpc {
45 46 return data.getOrderNo();
46 47 }
47 48  
  49 + public boolean cancel(final String orderNo) {
  50 + try {
  51 + Message<Boolean> msg = flowApi.cancelApproval(Collections.singletonList(orderNo));
  52 + log.info("取消审批FlowApproveRpc.cancelApproval, 参数:[{}] 结果:{}", orderNo, msg.getResult());
  53 + return msg.isSuccess() && Objects.equals(Boolean.TRUE, msg.getData());
  54 + } catch (Exception e) {
  55 + log.error("取消审批失败, 参数:[{}]", orderNo);
  56 + e.printStackTrace();
  57 + }
  58 + return false;
  59 + }
48 60 }
... ...
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/AccidentCarController.java
... ... @@ -45,7 +45,7 @@ public class AccidentCarController {
45 45 @PostMapping("/pool/save")
46 46 public Message<Void> save(@CurrentUser LoginAuthBean currentUser,
47 47 @RequestBody @Valid final AccidentPoolDTO accidentPoolDTO) {
48   - final String msg = "手动新增事故池[/pool/save]";
  48 + final String msg = "手动新增事故池[app/accident/pool/save]";
49 49 try {
50 50 log.info("{}: param[{}]", msg, accidentPoolDTO);
51 51 accidentPoolBizService.add2Pool(currentUser, accidentPoolDTO);
... ...
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/CommonController.java 0 → 100644
  1 +package cn.fw.valhalla.controller.app;
  2 +
  3 +import cn.fw.data.base.domain.common.Message;
  4 +import cn.fw.security.auth.client.annotation.Authorization;
  5 +import cn.fw.security.auth.client.annotation.IgnoreAuth;
  6 +import cn.fw.security.auth.client.annotation.IgnoreUserToken;
  7 +import cn.fw.security.auth.client.enums.AuthType;
  8 +import cn.fw.valhalla.domain.vo.PostUserVO;
  9 +import cn.fw.valhalla.service.bus.CommonService;
  10 +import cn.fw.valhalla.service.bus.LeaveNeedDoBizService;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +import org.springframework.beans.factory.annotation.Autowired;
  13 +import org.springframework.validation.annotation.Validated;
  14 +import org.springframework.web.bind.annotation.GetMapping;
  15 +import org.springframework.web.bind.annotation.PutMapping;
  16 +import org.springframework.web.bind.annotation.RequestMapping;
  17 +import org.springframework.web.bind.annotation.RestController;
  18 +
  19 +import javax.validation.constraints.NotNull;
  20 +import java.util.List;
  21 +
  22 +import static cn.fw.common.web.util.ExceptionHandler.handleException;
  23 +import static cn.fw.common.web.util.ResultBuilder.failureWithMessage;
  24 +import static cn.fw.common.web.util.ResultBuilder.success;
  25 +import static cn.fw.valhalla.common.constant.MessageStr.SAVE_FAILURE;
  26 +
  27 +/**
  28 + * @author : kurisu
  29 + * @className : CommonController
  30 + * @description : 公共接口
  31 + * @date: 2020-10-22 11:06
  32 + */
  33 +@Slf4j
  34 +@RestController
  35 +@Authorization(AuthType.APP)
  36 +@Validated
  37 +@RequestMapping("/app/common")
  38 +public class CommonController {
  39 + private final CommonService commonService;
  40 + private final LeaveNeedDoBizService leaveNeedDoBizService;
  41 +
  42 + @Autowired
  43 + public CommonController(final CommonService commonService,
  44 + final LeaveNeedDoBizService leaveNeedDoBizService) {
  45 + this.commonService = commonService;
  46 + this.leaveNeedDoBizService = leaveNeedDoBizService;
  47 + }
  48 +
  49 + @GetMapping("/staff/list")
  50 + @IgnoreAuth
  51 + public Message<List<PostUserVO>> list(@NotNull(message = "服务站ID不能为空") final Long shopId,
  52 + @NotNull(message = "跟进类型不能为空") final Integer type) {
  53 + final String msg = "查询跟进人员[app/common/staff/list]";
  54 + try {
  55 + log.info("{}: param[shopId: {} type: {}]", msg, shopId, type);
  56 + List<PostUserVO> list = commonService.getUsers(shopId, type);
  57 + return success(list, data -> log.info("{}", data));
  58 + } catch (Exception ex) {
  59 + handleException(ex, e -> log.error("{}失败:param[shopId: {} type: {}]", msg, shopId, type, e));
  60 + return failureWithMessage(SAVE_FAILURE);
  61 + }
  62 + }
  63 +
  64 + @PutMapping("/leave/add")
  65 + @Authorization(AuthType.NONE)
  66 + public Message<Void> add(@NotNull(message = "服务站ID不能为空") final Long shopId,
  67 + @NotNull(message = "用户ID不能为空") final Long userId) {
  68 + final String msg = "添加离职待分配数据[app/common/leave/add]";
  69 + try {
  70 + log.info("{}: param[shopId: {} userId: {}]", msg, shopId, userId);
  71 + leaveNeedDoBizService.add(userId, shopId);
  72 + return success();
  73 + } catch (Exception ex) {
  74 + handleException(ex, e -> log.error("{}失败:param[shopId: {} userId: {}]", msg, shopId, userId, e));
  75 + return failureWithMessage(SAVE_FAILURE);
  76 + }
  77 + }
  78 +}
... ...
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowController.java
... ... @@ -98,6 +98,7 @@ public class FollowController {
98 98 }
99 99  
100 100 @GetMapping("/todo/record")
  101 + @IgnoreAuth
101 102 public Message<List<FollowRecordVO>> todoRecord(@NotNull(message = "跟进任务id不能为空") final Long taskId,
102 103 @NotNull(message = "跟进类型不能为空") final Integer type) {
103 104 final String msg = "查询跟进历史记录[follow/todo/record]";
... ...
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowPoolController.java
... ... @@ -9,7 +9,9 @@ import cn.fw.security.auth.client.annotation.IgnoreAuth;
9 9 import cn.fw.security.auth.client.enums.AuthType;
10 10 import cn.fw.valhalla.domain.query.FollowPoolQueryVO;
11 11 import cn.fw.valhalla.domain.vo.customer.PublicPoolVO;
  12 +import cn.fw.valhalla.domain.vo.follow.FollowDetailVO;
12 13 import cn.fw.valhalla.domain.vo.follow.FollowPoolListVO;
  14 +import cn.fw.valhalla.service.bus.follow.FollowBizService;
13 15 import cn.fw.valhalla.service.bus.follow.FollowPoolBizService;
14 16 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
15 17 import lombok.extern.slf4j.Slf4j;
... ... @@ -19,6 +21,8 @@ import org.springframework.web.bind.annotation.GetMapping;
19 21 import org.springframework.web.bind.annotation.RequestMapping;
20 22 import org.springframework.web.bind.annotation.RestController;
21 23  
  24 +import javax.validation.constraints.NotNull;
  25 +
22 26 import static cn.fw.common.web.util.ExceptionHandler.handleException;
23 27 import static cn.fw.common.web.util.ResultBuilder.failureWithMessage;
24 28 import static cn.fw.common.web.util.ResultBuilder.success;
... ... @@ -39,19 +43,21 @@ import static cn.fw.valhalla.common.constant.MessageStr.QUERY_FAILURE;
39 43 public class FollowPoolController {
40 44  
41 45 private final FollowPoolBizService followPoolBizService;
  46 + private final FollowBizService followBizService;
42 47  
43 48 @Autowired
44   - public FollowPoolController(final FollowPoolBizService followPoolBizService) {
  49 + public FollowPoolController(final FollowPoolBizService followPoolBizService,
  50 + final FollowBizService followBizService) {
45 51 this.followPoolBizService = followPoolBizService;
  52 + this.followBizService = followBizService;
46 53 }
47 54  
48   - @GetMapping("/defeat/list")
49   - public Message<AppPage<FollowPoolListVO>> defeatList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) {
50   - final String msg = "查询战败池列表[follow/pool/defeat/list]";
  55 + @GetMapping("/follow/own/list")
  56 + public Message<AppPage<FollowPoolListVO>> ownFollowList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) {
  57 + final String msg = "查询自己的跟进池列表[pool/own/follow/list]";
51 58 try {
52 59 log.info("{}: param[{}]", msg, queryVO);
53   - queryVO.setGroupId(currentUser.getGroupId());
54   - AppPage<FollowPoolListVO> page = followPoolBizService.defeatList(currentUser, queryVO);
  60 + AppPage<FollowPoolListVO> page = followPoolBizService.followList(currentUser, queryVO);
55 61 return success(page, data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size()));
56 62 } catch (Exception ex) {
57 63 handleException(ex, e -> log.error("{}失败:param[{}]", msg, queryVO.getType(), e));
... ... @@ -60,12 +66,13 @@ public class FollowPoolController {
60 66 }
61 67  
62 68 @GetMapping("/follow/list")
  69 + @IgnoreAuth
63 70 public Message<AppPage<FollowPoolListVO>> followList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) {
64   - final String msg = "查询跟进池列表[follow/pool/defeat/list]";
  71 + final String msg = "查询跟进池列表[pool/follow/list]";
65 72 try {
66 73 log.info("{}: param[{}]", msg, queryVO);
67 74 queryVO.setGroupId(currentUser.getGroupId());
68   - AppPage<FollowPoolListVO> page = followPoolBizService.followList(currentUser, queryVO);
  75 + AppPage<FollowPoolListVO> page = followPoolBizService.followList(null, queryVO);
69 76 return success(page, data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size()));
70 77 } catch (Exception ex) {
71 78 handleException(ex, e -> log.error("{}失败:param[{}]", msg, queryVO.getType(), e));
... ... @@ -73,13 +80,14 @@ public class FollowPoolController {
73 80 }
74 81 }
75 82  
76   - @GetMapping("/complete/list")
77   - public Message<AppPage<FollowPoolListVO>> completeList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) {
78   - final String msg = "查询成交池列表[follow/pool/defeat/list]";
  83 + @GetMapping("/public/list")
  84 + @IgnoreAuth
  85 + public Message<AppPage<PublicPoolVO>> publicList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) {
  86 + final String msg = "查询公共池列表[pool/public/list]";
79 87 try {
80 88 log.info("{}: param[{}]", msg, queryVO);
81 89 queryVO.setGroupId(currentUser.getGroupId());
82   - AppPage<FollowPoolListVO> page = followPoolBizService.completeList(currentUser, queryVO);
  90 + AppPage<PublicPoolVO> page = followPoolBizService.publicList(queryVO);
83 91 return success(page, data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size()));
84 92 } catch (Exception ex) {
85 93 handleException(ex, e -> log.error("{}失败:param[{}]", msg, queryVO.getType(), e));
... ... @@ -87,16 +95,16 @@ public class FollowPoolController {
87 95 }
88 96 }
89 97  
90   - @GetMapping("/public/list")
91   - public Message<AppPage<PublicPoolVO>> publicList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) {
92   - final String msg = "查询公共池列表[follow/pool/public/list]";
  98 + @GetMapping("/follow/detail")
  99 + @IgnoreAuth
  100 + public Message<FollowDetailVO> detail(@NotNull(message = "跟进池id不能为空") final Long taskId) {
  101 + final String msg = "查询跟进池详情[pool/follow/detail]";
93 102 try {
94   - log.info("{}: param[{}]", msg, queryVO);
95   - queryVO.setGroupId(currentUser.getGroupId());
96   - AppPage<PublicPoolVO> page = followPoolBizService.publicList(queryVO);
97   - return success(page, data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size()));
  103 + log.info("{}: param[{}]", msg, taskId);
  104 + FollowDetailVO detailVO = followBizService.followPoolDetail(taskId);
  105 + return success(detailVO, data -> log.info("{}", data));
98 106 } catch (Exception ex) {
99   - handleException(ex, e -> log.error("{}失败:param[{}]", msg, queryVO.getType(), e));
  107 + handleException(ex, e -> log.error("{}失败:param[{}]", msg, taskId, e));
100 108 return failureWithMessage(QUERY_FAILURE);
101 109 }
102 110 }
... ...
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/LeaveNeedDoController.java 0 → 100644
  1 +package cn.fw.valhalla.controller.app;
  2 +
  3 +import cn.fw.common.page.AppPage;
  4 +import cn.fw.common.web.auth.LoginAuthBean;
  5 +import cn.fw.common.web.auth.annotation.CurrentUser;
  6 +import cn.fw.data.base.domain.common.Message;
  7 +import cn.fw.security.auth.client.annotation.Authorization;
  8 +import cn.fw.security.auth.client.enums.AuthType;
  9 +import cn.fw.valhalla.domain.dto.LeaveAllocationDTO;
  10 +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum;
  11 +import cn.fw.valhalla.domain.query.LeaveQueryVO;
  12 +import cn.fw.valhalla.domain.vo.LeaveNeedDoVO;
  13 +import cn.fw.valhalla.service.bus.LeaveNeedDoBizService;
  14 +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
  15 +import lombok.extern.slf4j.Slf4j;
  16 +import org.springframework.beans.factory.annotation.Autowired;
  17 +import org.springframework.validation.annotation.Validated;
  18 +import org.springframework.web.bind.annotation.*;
  19 +
  20 +import javax.validation.Valid;
  21 +
  22 +import static cn.fw.common.web.util.ExceptionHandler.handleException;
  23 +import static cn.fw.common.web.util.ResultBuilder.failureWithMessage;
  24 +import static cn.fw.common.web.util.ResultBuilder.success;
  25 +import static cn.fw.valhalla.common.constant.MessageStr.QUERY_FAILURE;
  26 +import static cn.fw.valhalla.common.constant.MessageStr.SAVE_FAILURE;
  27 +
  28 +/**
  29 + * @author : kurisu
  30 + * @className : LeaveNeedDoController
  31 + * @description : 人员变动待处理事件
  32 + * @date: 2020-08-15 14:52
  33 + */
  34 +@Slf4j
  35 +@RestController
  36 +@Authorization(AuthType.APP)
  37 +@Validated
  38 +@RequestMapping("/app/leave2do")
  39 +public class LeaveNeedDoController {
  40 +
  41 + private final LeaveNeedDoBizService leaveNeedDoBizService;
  42 +
  43 + @Autowired
  44 + public LeaveNeedDoController(final LeaveNeedDoBizService leaveNeedDoBizService) {
  45 + this.leaveNeedDoBizService = leaveNeedDoBizService;
  46 + }
  47 +
  48 + @GetMapping("/customer/list")
  49 + public Message<AppPage<LeaveNeedDoVO>> save(@CurrentUser LoginAuthBean currentUser, final LeaveQueryVO queryVO) {
  50 + final String msg = "保有客档案待分配人员列表[app/leave2do/customer/list]";
  51 + try {
  52 + queryVO.setType(LeaveTodoTypeEnum.CUSTOMER.getValue());
  53 + log.info("{}: param[{}]", msg, queryVO);
  54 + return success(leaveNeedDoBizService.getList(currentUser, queryVO),
  55 + data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size()));
  56 + } catch (Exception ex) {
  57 + handleException(ex, e -> log.error("{}失败: param[{}]", msg, queryVO, e));
  58 + return failureWithMessage(QUERY_FAILURE);
  59 + }
  60 + }
  61 +
  62 +
  63 + @PostMapping("/customer/allocation")
  64 + public Message<Void> allocation(@CurrentUser LoginAuthBean currentUser, @RequestBody @Valid LeaveAllocationDTO dto) {
  65 + final String msg = "保有客档案分配[app/leave2do/customer/allocation]";
  66 + try {
  67 + log.info("{}: param[{}]", msg, dto);
  68 + leaveNeedDoBizService.allocation(currentUser, dto);
  69 + return success();
  70 + } catch (Exception ex) {
  71 + handleException(ex, e -> log.error("{}失败: param[{}]", msg, dto, e));
  72 + return failureWithMessage(SAVE_FAILURE);
  73 + }
  74 + }
  75 +}
... ...
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/task/FollowTaskDealTask.java
... ... @@ -2,16 +2,18 @@ package cn.fw.valhalla.controller.task;
2 2  
3 3 import cn.fw.valhalla.common.utils.DateUtil;
4 4 import cn.fw.valhalla.domain.db.follow.FollowTask;
  5 +import cn.fw.valhalla.domain.enums.ApproveTypeEnum;
5 6 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
6 7 import cn.fw.valhalla.domain.enums.TaskStateEnum;
7 8 import cn.fw.valhalla.service.bus.cust.CustomerBizService;
8 9 import cn.fw.valhalla.service.bus.cust.CustomerChangeBizService;
9 10 import cn.fw.valhalla.service.bus.follow.FollowBizService;
10 11 import cn.fw.valhalla.service.data.FollowTaskService;
  12 +import cn.fw.valhalla.service.event.CancelApproveEvent;
11 13 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
12 14 import org.springframework.beans.factory.annotation.Autowired;
13 15 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
14   -import org.springframework.scheduling.annotation.Async;
  16 +import org.springframework.context.ApplicationEventPublisher;
15 17 import org.springframework.scheduling.annotation.Scheduled;
16 18 import org.springframework.stereotype.Component;
17 19 import org.springframework.transaction.annotation.Transactional;
... ... @@ -21,6 +23,8 @@ import java.time.LocalDateTime;
21 23 import java.util.List;
22 24 import java.util.Objects;
23 25  
  26 +import static cn.fw.valhalla.common.utils.DateUtil.getNowExpiredDay;
  27 +
24 28 /**
25 29 * @author : kurisu
26 30 * @className : FollowTask
... ... @@ -34,16 +38,19 @@ public class FollowTaskDealTask {
34 38 private final FollowBizService followBizService;
35 39 private final CustomerChangeBizService customerChangeBizService;
36 40 private final CustomerBizService customerBizService;
  41 + private final ApplicationEventPublisher eventPublisher;
37 42  
38 43 @Autowired
39 44 public FollowTaskDealTask(final FollowTaskService followTaskService,
40 45 final FollowBizService followBizService,
41 46 final CustomerChangeBizService customerChangeBizService,
42   - final CustomerBizService customerBizService) {
  47 + final CustomerBizService customerBizService,
  48 + final ApplicationEventPublisher eventPublisher) {
43 49 this.followTaskService = followTaskService;
44 50 this.followBizService = followBizService;
45 51 this.customerChangeBizService = customerChangeBizService;
46 52 this.customerBizService = customerBizService;
  53 + this.eventPublisher = eventPublisher;
47 54 }
48 55  
49 56 /**
... ... @@ -54,6 +61,7 @@ public class FollowTaskDealTask {
54 61 public void startTask() {
55 62 List<FollowTask> list = followTaskService.list(Wrappers.<FollowTask>lambdaQuery()
56 63 .eq(FollowTask::getState, TaskStateEnum.WAITING)
  64 + .ge(FollowTask::getBeginTime, DateUtil.startDate(getNowExpiredDay(-7)))
57 65 .le(FollowTask::getBeginTime, DateUtil.localDateTime2Date(LocalDateTime.now()))
58 66 .eq(FollowTask::getFinished, Boolean.FALSE)
59 67 .last("limit 0, 500")
... ... @@ -85,10 +93,12 @@ public class FollowTaskDealTask {
85 93 if (CollectionUtils.isEmpty(list)) {
86 94 return;
87 95 }
88   - list.forEach(r -> {
  96 + for (FollowTask r : list) {
89 97 r.setState(TaskStateEnum.END);
90 98 customerBizService.abandon(r);
91   - });
  99 + CancelApproveEvent event = new CancelApproveEvent(r.getId(), ApproveTypeEnum.FOLLOW_DEFEAT);
  100 + eventPublisher.publishEvent(event);
  101 + }
92 102 followTaskService.updateBatchById(list);
93 103 }
94 104  
... ... @@ -110,9 +120,9 @@ public class FollowTaskDealTask {
110 120 }
111 121 list.forEach(task -> {
112 122 if (FollowTypeEnum.IR.equals(task.getType())) {
113   - customerChangeBizService.changeInsFollowUser(task);
  123 + customerChangeBizService.changeInsFollowUser(task, true);
114 124 } else {
115   - customerChangeBizService.changeFollowUser(task);
  125 + customerChangeBizService.changeFollowUser(task, true);
116 126 }
117 127 });
118 128 }
... ...
fw-valhalla-server/src/main/resources/application-gray.yml
... ... @@ -51,3 +51,4 @@ follow:
51 51 RMCode: 'Zb33mjtjVy'
52 52 IRCode: 'RsavIrkhZm'
53 53 ACCode: 'gWPMkrjkjH'
  54 + leave2do: 'uF08Vd38fi'
... ...
fw-valhalla-server/src/main/resources/application-prd.yml
... ... @@ -50,3 +50,4 @@ follow:
50 50 RMCode: 'Zb33mjtjVy'
51 51 IRCode: 'RsavIrkhZm'
52 52 ACCode: 'gWPMkrjkjH'
  53 + leave2do: 'uF08Vd38fi'
... ...
fw-valhalla-server/src/main/resources/application-test.yml
... ... @@ -53,4 +53,5 @@ follow:
53 53 FMCode: '50rmamxGp7'
54 54 RMCode: 'Zb33mjtjVy'
55 55 IRCode: 'RsavIrkhZm'
56   - ACCode: 'gWPMkrjkjH'
57 56 \ No newline at end of file
  57 + ACCode: 'gWPMkrjkjH'
  58 + leave2do: 'kLKIpyNNQf'
58 59 \ No newline at end of file
... ...
fw-valhalla-server/src/main/resources/application.yml
... ... @@ -127,3 +127,4 @@ follow:
127 127 RMCode: 'Zb33mjtjVy'
128 128 IRCode: 'RsavIrkhZm'
129 129 ACCode: 'gWPMkrjkjH'
  130 + leave2do: 'kLKIpyNNQf'
... ...
fw-valhalla-server/src/test/java/cn/fw/valhalla/ValhallaAppTests.java
... ... @@ -27,9 +27,11 @@ class ValhallaAppTests {
27 27  
28 28 @Test
29 29 public void exampleTest() throws Exception {
30   - this.mvc.perform(get("/test/todo").header("Authorization", "9E6864D1C56A0A6090AEFECF477A8519B407D23ECDC0763C4AD3F5D069B8DEB30025FC54917666CD0639489E2AB7D3C2"))
  30 + this.mvc.perform(
  31 + get("/app/accident/demo")
  32 + .header("Authorization", "4B70342B7CC9709C7D76A982217570ADB407D23ECDC0763C4AD3F5D069B8DEB33C5FCE9E493D9F6DE05D532E7A8B5DD1")
  33 + .param("val", "12345"))
31 34 .andExpect(status().isOk())
32   - .andExpect(content().string("ok"))
33 35 .andDo(MockMvcResultHandlers.print());
34 36 }
35 37  
... ...
fw-valhalla-server/src/test/java/cn/fw/valhalla/demo.lua 0 → 100644
  1 +--
  2 +-- Created by IntelliJ IDEA.
  3 +-- User: kurisu
  4 +-- Date: 2020/10/10
  5 +-- Time: 16:53
  6 +-- To change this template use File | Settings | File Templates.
  7 +
  8 +-- 解锁
  9 + if redis.call('get',KEYS[1]) == ARGV[1] then
  10 + return redis.call('del',KEYS[1]) == 1
  11 + else
  12 + return false
  13 + end
  14 +
  15 +
  16 +-- 设置锁
  17 + if redis.call('exists',KEYS[1]) == 1 then
  18 + return redis.call('get',KEYS[1])
  19 + else
  20 + return redis.call('set',KEYS[1], ARGV[1])
  21 + end
0 22 \ No newline at end of file
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CommonService.java 0 → 100644
  1 +package cn.fw.valhalla.service.bus;
  2 +
  3 +import cn.fw.valhalla.common.constant.RoleCode;
  4 +import cn.fw.valhalla.domain.enums.FollowTypeEnum;
  5 +import cn.fw.valhalla.domain.vo.PostUserVO;
  6 +import cn.fw.valhalla.rpc.erp.UserService;
  7 +import cn.fw.valhalla.rpc.erp.dto.PostUserDTO;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.stereotype.Service;
  11 +
  12 +import java.util.List;
  13 +import java.util.stream.Collectors;
  14 +
  15 +import static cn.fw.common.businessvalidator.Validator.BV;
  16 +
  17 +/**
  18 + * @author : kurisu
  19 + * @className : CommonService
  20 + * @description : 公共服务
  21 + * @date: 2020-10-22 11:07
  22 + */
  23 +@Service
  24 +@Slf4j
  25 +public class CommonService {
  26 + private final UserService userService;
  27 +
  28 + @Autowired
  29 + public CommonService(final UserService userService) {
  30 + this.userService = userService;
  31 + }
  32 +
  33 + public List<PostUserVO> getUsers(final Long shopId, final Integer type) {
  34 + FollowTypeEnum typeEnum = FollowTypeEnum.ofValue(type);
  35 + BV.notNull(typeEnum, () -> "跟进类型错误");
  36 + List<PostUserDTO> userByRole = userService.getUserByRole(shopId, getRoleCode(typeEnum));
  37 + return userByRole.stream().map(user -> new PostUserVO(user.getUserId(), user.getUserName())).collect(Collectors.toList());
  38 + }
  39 +
  40 + private String getRoleCode(FollowTypeEnum followTypeEnum) {
  41 + switch (followTypeEnum) {
  42 + case AC:
  43 + return RoleCode.SGCGJ;
  44 + case IR:
  45 + return RoleCode.XBGJ;
  46 + case FM:
  47 + case RM:
  48 + default:
  49 + return RoleCode.FWGW;
  50 + }
  51 + }
  52 +}
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CustomEventListener.java
1 1 package cn.fw.valhalla.service.bus;
2 2  
  3 +import cn.fw.valhalla.domain.db.ApproveRecord;
3 4 import cn.fw.valhalla.domain.db.follow.FollowTask;
  5 +import cn.fw.valhalla.domain.enums.ApproveStateEnum;
  6 +import cn.fw.valhalla.domain.enums.ApproveTypeEnum;
4 7 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
5 8 import cn.fw.valhalla.domain.vo.setting.SettingVO;
  9 +import cn.fw.valhalla.rpc.flow.FlowApproveRpc;
6 10 import cn.fw.valhalla.service.bus.follow.FollowBizService;
7 11 import cn.fw.valhalla.service.bus.setting.SettingBizService;
8   -import cn.fw.valhalla.service.event.PublicPoolEvent;
9   -import cn.fw.valhalla.service.event.SettingChangeEvent;
10   -import cn.fw.valhalla.service.event.StopTaskEvent;
11   -import cn.fw.valhalla.service.event.TaskCancelEvent;
  12 +import cn.fw.valhalla.service.data.ApproveRecordService;
  13 +import cn.fw.valhalla.service.event.*;
  14 +import com.baomidou.mybatisplus.core.toolkit.Wrappers;
12 15 import lombok.extern.slf4j.Slf4j;
13 16 import org.springframework.beans.factory.annotation.Autowired;
14 17 import org.springframework.context.event.EventListener;
... ... @@ -29,12 +32,18 @@ import java.util.Optional;
29 32 public class CustomEventListener {
30 33 private final SettingBizService settingBizService;
31 34 private final FollowBizService followBizService;
  35 + private final ApproveRecordService approveRecordService;
  36 + private final FlowApproveRpc flowApproveRpc;
32 37  
33 38 @Autowired
34 39 public CustomEventListener(final SettingBizService settingBizService,
35   - final FollowBizService followBizService) {
  40 + final FollowBizService followBizService,
  41 + final ApproveRecordService approveRecordService,
  42 + final FlowApproveRpc flowApproveRpc) {
36 43 this.settingBizService = settingBizService;
37 44 this.followBizService = followBizService;
  45 + this.approveRecordService = approveRecordService;
  46 + this.flowApproveRpc = flowApproveRpc;
38 47 }
39 48  
40 49 /**
... ... @@ -83,4 +92,27 @@ public class CustomEventListener {
83 92 FollowTask task = event.getTask();
84 93 followBizService.stopTask(task);
85 94 }
  95 +
  96 + /**
  97 + * 取消审批
  98 + * @param event
  99 + */
  100 + @EventListener(CancelApproveEvent.class)
  101 + public void cancelApprove(final CancelApproveEvent event) {
  102 + Long taskId = event.getTaskId();
  103 + ApproveTypeEnum typeEnum = event.getTypeEnum();
  104 + ApproveRecord approveRecord = approveRecordService.getOne(Wrappers.<ApproveRecord>lambdaQuery()
  105 + .eq(ApproveRecord::getDataId, taskId)
  106 + .eq(ApproveRecord::getType, typeEnum)
  107 + .eq(ApproveRecord::getState, ApproveStateEnum.WAIT)
  108 + .last("limit 1")
  109 + );
  110 + if (Objects.isNull(approveRecord)) {
  111 + return;
  112 + }
  113 + //FIXME 优化项 处理审批取消失败的场景
  114 + boolean canceled = flowApproveRpc.cancel(approveRecord.getOrderNo());
  115 + approveRecord.setState(ApproveStateEnum.CANCELED);
  116 + approveRecordService.updateById(approveRecord);
  117 + }
86 118 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/LeaveNeedDoBizService.java 0 → 100644
  1 +package cn.fw.valhalla.service.bus;
  2 +
  3 +import cn.fw.common.cache.locker.DistributedLocker;
  4 +import cn.fw.common.data.mybatis.pagination.PageData;
  5 +import cn.fw.common.page.AppPage;
  6 +import cn.fw.common.web.auth.LoginAuthBean;
  7 +import cn.fw.data.base.domain.common.Message;
  8 +import cn.fw.third.push.sdk.api.ImSendMessage;
  9 +import cn.fw.third.push.sdk.api.para.im.MsgPara;
  10 +import cn.fw.valhalla.common.constant.RoleCode;
  11 +import cn.fw.valhalla.common.enums.AllocationTypeEnum;
  12 +import cn.fw.valhalla.common.utils.DateUtil;
  13 +import cn.fw.valhalla.domain.db.LeaveNeedDo;
  14 +import cn.fw.valhalla.domain.db.customer.Customer;
  15 +import cn.fw.valhalla.domain.db.follow.FollowRecord;
  16 +import cn.fw.valhalla.domain.db.follow.FollowTask;
  17 +import cn.fw.valhalla.domain.dto.LeaveAllocationDTO;
  18 +import cn.fw.valhalla.domain.enums.FollowTypeEnum;
  19 +import cn.fw.valhalla.domain.enums.LeaveReasonEnum;
  20 +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum;
  21 +import cn.fw.valhalla.domain.enums.TaskStateEnum;
  22 +import cn.fw.valhalla.domain.query.LeaveQueryVO;
  23 +import cn.fw.valhalla.domain.vo.LeaveNeedDoVO;
  24 +import cn.fw.valhalla.rpc.erp.TodoRpcService;
  25 +import cn.fw.valhalla.rpc.erp.UserService;
  26 +import cn.fw.valhalla.rpc.erp.dto.BackLogItemDTO;
  27 +import cn.fw.valhalla.rpc.erp.dto.PostUserDTO;
  28 +import cn.fw.valhalla.rpc.erp.dto.UserInfoDTO;
  29 +import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO;
  30 +import cn.fw.valhalla.service.data.CustomerService;
  31 +import cn.fw.valhalla.service.data.FollowRecordService;
  32 +import cn.fw.valhalla.service.data.FollowTaskService;
  33 +import cn.fw.valhalla.service.data.LeaveNeedDoService;
  34 +import com.alibaba.fastjson.JSONObject;
  35 +import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  36 +import lombok.Getter;
  37 +import lombok.extern.slf4j.Slf4j;
  38 +import org.apache.commons.lang3.tuple.Pair;
  39 +import org.redisson.api.RLock;
  40 +import org.springframework.beans.factory.annotation.Autowired;
  41 +import org.springframework.beans.factory.annotation.Value;
  42 +import org.springframework.data.redis.core.BoundListOperations;
  43 +import org.springframework.data.redis.core.StringRedisTemplate;
  44 +import org.springframework.stereotype.Service;
  45 +import org.springframework.transaction.annotation.Transactional;
  46 +import org.springframework.util.Assert;
  47 +import org.springframework.util.CollectionUtils;
  48 +
  49 +import java.util.*;
  50 +import java.util.concurrent.TimeUnit;
  51 +import java.util.stream.Collectors;
  52 +
  53 +import static cn.fw.common.businessvalidator.Validator.BV;
  54 +
  55 +/**
  56 + * @author : kurisu
  57 + * @className : LeaveNeedDoBizService
  58 + * @description : 人员变动处理
  59 + * @date: 2020-10-16 17:04
  60 + */
  61 +@Service
  62 +@Slf4j
  63 +public class LeaveNeedDoBizService {
  64 + private final LeaveNeedDoService leaveNeedDoService;
  65 + private final CustomerService customerService;
  66 + private final UserService userService;
  67 + private final FollowTaskService followTaskService;
  68 + private final FollowRecordService followRecordService;
  69 + private final DistributedLocker distributedLocker;
  70 + private final ImSendMessage imSendMessage;
  71 + private final TodoRpcService todoRpcService;
  72 + /**
  73 + * Redis工具
  74 + */
  75 + private final StringRedisTemplate redisTemplate;
  76 +
  77 + @Value("${spring.cache.custom.global-prefix}:LeaveNeedDo")
  78 + @Getter
  79 + private String keyPrefix;
  80 +
  81 + @Value("${follow.todo.leave2do}")
  82 + @Getter
  83 + private String leave2doCode;
  84 +
  85 + @Autowired
  86 + public LeaveNeedDoBizService(final LeaveNeedDoService leaveNeedDoService,
  87 + final CustomerService customerService,
  88 + final UserService userService,
  89 + final FollowTaskService followTaskService,
  90 + final FollowRecordService followRecordService,
  91 + final DistributedLocker distributedLocker,
  92 + final ImSendMessage imSendMessage,
  93 + final TodoRpcService todoRpcService,
  94 + final StringRedisTemplate redisTemplate) {
  95 + this.leaveNeedDoService = leaveNeedDoService;
  96 + this.customerService = customerService;
  97 + this.userService = userService;
  98 + this.followTaskService = followTaskService;
  99 + this.followRecordService = followRecordService;
  100 + this.distributedLocker = distributedLocker;
  101 + this.imSendMessage = imSendMessage;
  102 + this.todoRpcService = todoRpcService;
  103 + this.redisTemplate = redisTemplate;
  104 + }
  105 +
  106 +
  107 + @Transactional(rollbackFor = Exception.class)
  108 + public void add(final Long userId, final Long shopId) {
  109 + String lockKey = String.format("%s:add:lock:%s:%s", getKeyPrefix(), shopId, userId);
  110 + Pair<Boolean, RLock> pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 30);
  111 + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交");
  112 + try {
  113 + List<PostUserDTO> postUserDTOS = userService.getUserByRole(shopId, RoleCode.BYKFP);
  114 + BV.isFalse(CollectionUtils.isEmpty(postUserDTOS), () -> "该门店没有配置保有客分配人员");
  115 + LeaveNeedDo db = addable(userId, shopId);
  116 + leaveNeedDoService.save(db);
  117 + push2Todo(db.getId(), postUserDTOS.get(0).getUserId());
  118 + } catch (Exception e) {
  119 + distributedLocker.unlock(lockKey);
  120 + throw e;
  121 + }
  122 + }
  123 +
  124 + public AppPage<LeaveNeedDoVO> getList(LoginAuthBean currentUser, LeaveQueryVO queryVO) {
  125 + List<UserRoleDataRangeDTO> dataRange = userService.getUserRoleDataRange(currentUser.getUserId(), RoleCode.BYKFP);
  126 + List<Long> shopIds = dataRange.stream().map(UserRoleDataRangeDTO::getRangeValue).collect(Collectors.toList());
  127 + BV.isFalse(CollectionUtils.isEmpty(shopIds), () -> "无权限操作,请检查角色权限是否正确");
  128 + PageData<LeaveNeedDo> pageData = leaveNeedDoService.page(new PageData<>(queryVO), Wrappers.<LeaveNeedDo>lambdaQuery()
  129 + .in(LeaveNeedDo::getShopId, shopIds)
  130 + .eq(LeaveNeedDo::getDone, Boolean.FALSE)
  131 + .eq(Objects.nonNull(queryVO.getType()), LeaveNeedDo::getType, queryVO.getType())
  132 + );
  133 + AppPage<LeaveNeedDoVO> page = AppPage.empty(queryVO);
  134 + List<LeaveNeedDoVO> list = new ArrayList<>();
  135 + List<LeaveNeedDo> records = Optional.ofNullable(pageData.getRecords()).orElse(new ArrayList<>());
  136 + for (LeaveNeedDo needDo : records) {
  137 + int i = customerService.count(Wrappers.<Customer>lambdaQuery()
  138 + .eq(Customer::getAdviserId, needDo.getUserId())
  139 + .eq(Customer::getYn, Boolean.TRUE)
  140 + );
  141 + list.add(LeaveNeedDoVO.with(needDo, i));
  142 + }
  143 + page.setData(list);
  144 + return page;
  145 + }
  146 +
  147 + @Transactional(rollbackFor = Exception.class)
  148 + public void allocation(LoginAuthBean user, LeaveAllocationDTO dto) {
  149 + final String key = generateKey(dto.getId());
  150 + final String lockKey = getLockKey(dto.getId());
  151 + Pair<Boolean, RLock> pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 30);
  152 + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交");
  153 + try {
  154 + //准备分配 常规校验
  155 + prepareAllocation(dto);
  156 + //变更档案
  157 + List<Customer> customerList = doAllocation(dto, key);
  158 + //分配跟进任务
  159 + dealFollowTask(customerList);
  160 + //完成分配发送消息提醒等
  161 + finish(user.getUserName(), dto.getId(), key);
  162 + } catch (Exception e) {
  163 + clearKey(key);
  164 + distributedLocker.unlock(lockKey);
  165 + throw e;
  166 + }
  167 + }
  168 +
  169 + private void prepareAllocation(LeaveAllocationDTO dto) {
  170 + AllocationTypeEnum typeEnum = AllocationTypeEnum.ofValue(dto.getAllocationType());
  171 + BV.notNull(typeEnum, () -> "分配方式不正确,请重试");
  172 + dto.setType(typeEnum);
  173 + LeaveNeedDo needDo = leaveNeedDoService.queryProcessableById(dto.getId());
  174 + BV.notNull(needDo, () -> "该条记录已处理或不存在,请刷新后重试");
  175 + dto.setAdviserId(needDo.getUserId());
  176 + if (AllocationTypeEnum.ONE.equals(typeEnum)) {
  177 + BV.notNull(dto.getUserId(), () -> "指定人员不能为空");
  178 + List<UserRoleDataRangeDTO> dataRange = userService.getUserRoleDataRange(dto.getUserId(), RoleCode.FWGW);
  179 + List<Long> shopIdList = dataRange.stream().map(UserRoleDataRangeDTO::getRangeValue).collect(Collectors.toList());
  180 + BV.isNotEmpty(shopIdList, () -> "指定人员非服务顾问角色,请核对");
  181 + Long shopId = shopIdList.get(0);
  182 + BV.isTrue(needDo.getShopId().equals(shopId), () -> "指定人员所属门店与档案归属门店不符");
  183 + dto.setShopId(shopId);
  184 + }
  185 +
  186 + if (AllocationTypeEnum.ALL.equals(dto.getType())) {
  187 + dto.setShopId(needDo.getShopId());
  188 + }
  189 + }
  190 +
  191 + /**
  192 + * 处理数据
  193 + *
  194 + * @param dto
  195 + * @return 处理完的档案
  196 + */
  197 + private List<Customer> doAllocation(LeaveAllocationDTO dto, String key) {
  198 + List<Customer> customerList = customerService.queryByAdviserId(dto.getAdviserId());
  199 + if (CollectionUtils.isEmpty(customerList)) {
  200 + return null;
  201 + }
  202 + if (AllocationTypeEnum.ONE.equals(dto.getType())) {
  203 + allocation(key, customerList, dto);
  204 + }
  205 + if (AllocationTypeEnum.ALL.equals(dto.getType())) {
  206 + allocation(key, customerList, dto.getShopId());
  207 + }
  208 + return customerList;
  209 + }
  210 +
  211 + /**
  212 + * 分配给指定人员
  213 + *
  214 + * @param list
  215 + * @param dto
  216 + */
  217 + private void allocation(String key, List<Customer> list, LeaveAllocationDTO dto) {
  218 + for (Customer customer : list) {
  219 + customer.setShopId(dto.getShopId());
  220 + customer.setAdviserId(dto.getUserId());
  221 + }
  222 + customerService.updateBatchById(list);
  223 + setToCache(key, new UserInfo(dto.getUserId(), "", list.size()));
  224 + }
  225 +
  226 + /**
  227 + * 门店内平均分配
  228 + *
  229 + * @param list
  230 + * @param shopId
  231 + */
  232 + private void allocation(String key, List<Customer> list, Long shopId) {
  233 + List<PostUserDTO> users = userService.getUserByRole(shopId, RoleCode.FWGW);
  234 + BV.isNotEmpty(users, () -> "该门店没有服务顾问,请检查配置是否正确");
  235 + LinkedList<UserInfo> queue = new LinkedList<>();
  236 + for (PostUserDTO user : users) {
  237 + queue.offer(new UserInfo(user.getUserId(), user.getUserName()));
  238 + }
  239 + for (Customer customer : list) {
  240 + UserInfo info = queue.poll();
  241 + customer.setShopId(shopId);
  242 + customer.setAdviserId(Objects.requireNonNull(info, "服务顾问信息获取异常,请重试").getUserId());
  243 + info.setCount(info.getCount() + 1);
  244 + queue.offer(info);
  245 + }
  246 + customerService.updateBatchById(list);
  247 + setToCache(key, queue);
  248 + }
  249 +
  250 + /**
  251 + * 完成分配的后续处理逻辑
  252 + *
  253 + * @param list
  254 + */
  255 + private void dealFollowTask(List<Customer> list) {
  256 + List<FollowTypeEnum> enumList = Arrays.asList(FollowTypeEnum.FM, FollowTypeEnum.RM);
  257 + if (!CollectionUtils.isEmpty(list)) {
  258 + //处理待办等信息
  259 + for (Customer customer : list) {
  260 + final Long customerId = customer.getId();
  261 + final Long shopId = customer.getShopId();
  262 + final Long adviserId = customer.getAdviserId();
  263 + List<FollowTask> taskList = followTaskService.getListByCustomerId(customerId, enumList);
  264 + taskList.forEach(task -> {
  265 + task.setFollowUser(adviserId);
  266 + task.setFollowShop(shopId);
  267 + if (TaskStateEnum.WAITING.equals(task.getState())) {
  268 + task.setOriginUser(adviserId);
  269 + task.setOriginShop(shopId);
  270 + } else {
  271 + task.setChanged(Boolean.TRUE);
  272 + }
  273 + });
  274 + List<FollowRecord> recordList = followRecordService.getRecordListByCustomer(customerId, enumList);
  275 + recordList.forEach(record -> {
  276 + record.setUserId(adviserId);
  277 + record.setShopId(shopId);
  278 + });
  279 + if (taskList.size() > 0) {
  280 + followTaskService.updateBatchById(taskList);
  281 + }
  282 + if (recordList.size() > 0) {
  283 + followRecordService.updateBatchById(recordList);
  284 + }
  285 + }
  286 + }
  287 + }
  288 +
  289 + private void finish(String userName, Long leaveId, String key) {
  290 + leaveNeedDoService.dealById(leaveId);
  291 + List<UserInfo> list = getAllFromCache(key);
  292 + for (UserInfo info : list) {
  293 + try {
  294 + String text = String.format("%s通过资源分配给你%s台保有客", userName, info.getCount());
  295 + final MsgPara msgPara = MsgPara.getOfflineTxetPara(text, null, "保有客分配",
  296 + "保有客分配", null, info.getUserId()).build();
  297 + final Message<Integer> msg = imSendMessage.sendMsg(msgPara);
  298 + log.info("给[{}]推送im消息结果:[{}]", info, msg.getResult());
  299 + } catch (Exception e) {
  300 + log.error("给[{}]推送im消息失败:]", info, e);
  301 + }
  302 + }
  303 + clearKey(key);
  304 + BackLogItemDTO backLogItemDTO = new BackLogItemDTO(null, getLeave2doCode(), String.valueOf(leaveId), new Date());
  305 + todoRpcService.complete(backLogItemDTO);
  306 + }
  307 +
  308 + private String getLockKey(final Long leaveId) {
  309 + BV.notNull(leaveId, "leaveId cannot be null");
  310 +
  311 + return String.format("%s:lock:%s", getKeyPrefix(), leaveId);
  312 + }
  313 +
  314 + private String generateKey(final Long leaveId) {
  315 + Assert.notNull(leaveId, "leaveId cannot be null");
  316 +
  317 + return String.format("%s:allocation:%s", getKeyPrefix(), leaveId);
  318 + }
  319 +
  320 + public List<UserInfo> getAllFromCache(final String key) {
  321 + try {
  322 + Boolean hasKey = redisTemplate.hasKey(key);
  323 + if (!Boolean.TRUE.equals(hasKey)) {
  324 + return new ArrayList<>();
  325 + }
  326 + BoundListOperations<String, String> ops = redisTemplate.boundListOps(key);
  327 + List<String> stringList = ops.range(0, -1);
  328 + if (CollectionUtils.isEmpty(stringList)) {
  329 + return new ArrayList<>();
  330 + }
  331 + List<UserInfo> dtos = stringList.stream().map(str -> JSONObject.parseObject(str, UserInfo.class)).collect(Collectors.toList());
  332 + redisTemplate.delete(key);
  333 + return dtos;
  334 + } catch (Exception e) {
  335 + log.error("缓存设置信息失败 key[{}]", key, e);
  336 + return new ArrayList<>();
  337 + }
  338 + }
  339 +
  340 + private void setToCache(final String key, final UserInfo userInfo) {
  341 + try {
  342 + BoundListOperations<String, String> ops = redisTemplate.boundListOps(key);
  343 + String jsonString = JSONObject.toJSONString(userInfo);
  344 + ops.rightPush(jsonString);
  345 + } catch (Exception e) {
  346 + log.error("缓存设置信息失败 key[{}]", key, e);
  347 + }
  348 + }
  349 +
  350 + private void setToCache(final String key, final LinkedList<UserInfo> userInfos) {
  351 + try {
  352 + if (CollectionUtils.isEmpty(userInfos)) {
  353 + return;
  354 + }
  355 + BoundListOperations<String, String> ops = redisTemplate.boundListOps(key);
  356 + String[] users = userInfos.stream().map(JSONObject::toJSONString).toArray(String[]::new);
  357 + ops.rightPushAll(users);
  358 + } catch (Exception e) {
  359 + log.error("缓存设置信息失败 key[{}]", key, e);
  360 + }
  361 + }
  362 +
  363 + private void clearKey(final String key) {
  364 + try {
  365 + redisTemplate.delete(key);
  366 + } catch (Exception e) {
  367 + log.error("清空缓存信息失败 key[{}]", key, e);
  368 + }
  369 + }
  370 +
  371 + private LeaveNeedDo addable(final Long userId, final Long shopId) {
  372 + List<UserRoleDataRangeDTO> dataRange = userService.getUserRoleDataRange(userId, RoleCode.FWGW);
  373 + boolean ok = CollectionUtils.isEmpty(dataRange) || !Objects.equals(dataRange.get(0).getRangeValue(), shopId);
  374 + BV.isTrue(ok, () -> "请先移除对对应服务站服务顾问角色后操作");
  375 + int count = leaveNeedDoService.count(Wrappers.<LeaveNeedDo>lambdaQuery()
  376 + .eq(LeaveNeedDo::getUserId, userId)
  377 + .eq(LeaveNeedDo::getShopId, shopId)
  378 + .eq(LeaveNeedDo::getDone, Boolean.FALSE)
  379 + );
  380 + BV.isTrue(count == 0, () -> "已存在待分配记录,请勿重复添加");
  381 + UserInfoDTO user = userService.user(userId);
  382 + BV.notNull(user, () -> "用户不存在");
  383 + boolean bool = customerService.count(Wrappers.<Customer>lambdaQuery()
  384 + .eq(Customer::getAdviserId, userId)
  385 + .eq(Customer::getShopId, shopId)
  386 + .eq(Customer::getYn, Boolean.TRUE)
  387 + ) > 0;
  388 + BV.isTrue(bool, () -> "该顾问没有可用档案无需分配保有客");
  389 + LeaveNeedDo db = new LeaveNeedDo();
  390 + db.setDone(Boolean.FALSE);
  391 + db.setEffectiveTime(DateUtil.getMonthEndDay(new Date()));
  392 + db.setReason(LeaveReasonEnum.OTHER);
  393 + db.setType(LeaveTodoTypeEnum.CUSTOMER);
  394 + db.setShopId(shopId);
  395 + db.setUserId(userId);
  396 + db.setUserName(user.getUserName());
  397 + db.setCreateTime(new Date());
  398 + db.setUpdateTime(new Date());
  399 + return db;
  400 + }
  401 +
  402 + private void push2Todo(Long id, Long userId) {
  403 + BackLogItemDTO dto = new BackLogItemDTO(userId, getLeave2doCode(), String.valueOf(id), new Date());
  404 + todoRpcService.push(dto);
  405 + }
  406 +
  407 + static class UserInfo {
  408 + private Long userId;
  409 + private String userName;
  410 + private int count;
  411 +
  412 + public UserInfo() {
  413 + }
  414 +
  415 + public UserInfo(Long userId, String userName) {
  416 + this.userId = userId;
  417 + this.userName = userName;
  418 + }
  419 +
  420 + public UserInfo(Long userId, String userName, int count) {
  421 + this.userId = userId;
  422 + this.userName = userName;
  423 + this.count = count;
  424 + }
  425 +
  426 + public Long getUserId() {
  427 + return userId;
  428 + }
  429 +
  430 + public void setUserId(Long userId) {
  431 + this.userId = userId;
  432 + }
  433 +
  434 + public String getUserName() {
  435 + return userName;
  436 + }
  437 +
  438 + public void setUserName(String userName) {
  439 + this.userName = userName;
  440 + }
  441 +
  442 + public int getCount() {
  443 + return count;
  444 + }
  445 +
  446 + public void setCount(int count) {
  447 + this.count = count;
  448 + }
  449 +
  450 + @Override
  451 + public String toString() {
  452 + return "UserInfo{" +
  453 + "userId=" + userId +
  454 + ", userName='" + userName + '\'' +
  455 + ", count=" + count +
  456 + '}';
  457 + }
  458 + }
  459 +}
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/AccidentPoolBizService.java
... ... @@ -82,12 +82,14 @@ public class AccidentPoolBizService {
82 82 public void add2Pool(LoginAuthBean currentUser, AccidentPoolDTO poolDTO) {
83 83 final String lockKey = getLockKey(poolDTO.getPlateNo(), currentUser.getGroupId());
84 84 Pair<Boolean, RLock> pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 15);
  85 + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交");
85 86 try {
86 87 BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交");
87 88 boolean repetition = isRepetition(currentUser.getGroupId(), poolDTO.getPlateNo());
88 89 BV.isFalse(repetition, () -> "该记录已存在,请勿重复添加");
89 90 AccidentPool pool = conversion2db(poolDTO, currentUser);
90 91 pool.setShopId(poolDTO.getShopId());
  92 + pool.setShopName(poolDTO.getName());
91 93 accidentPoolService.save(pool);
92 94 createAccPoolTask(pool);
93 95 } catch (Exception e) {
... ... @@ -141,7 +143,6 @@ public class AccidentPoolBizService {
141 143 private AccidentPool conversion2db(AccidentPoolDTO dto, LoginAuthBean currentUser) {
142 144 AccidentPool pool = new AccidentPool();
143 145 BeanUtils.copyProperties(dto, pool);
144   - pool.setUserId(currentUser.getUserId());
145 146 pool.setCreateTime(new Date());
146 147 pool.setUpdateTime(new Date());
147 148 pool.setGroupId(currentUser.getGroupId());
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/CustomerChangeBizService.java
... ... @@ -20,9 +20,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord;
20 20 import cn.fw.valhalla.domain.db.follow.FollowTask;
21 21 import cn.fw.valhalla.domain.dto.CustomerChangeDto;
22 22 import cn.fw.valhalla.domain.dto.CustomerDetailDto;
23   -import cn.fw.valhalla.domain.enums.CustomerChangeTypeEnum;
24   -import cn.fw.valhalla.domain.enums.DefeatReasonEnum;
25   -import cn.fw.valhalla.domain.enums.TaskStateEnum;
  23 +import cn.fw.valhalla.domain.enums.*;
26 24 import cn.fw.valhalla.domain.vo.customer.CustomerChangeInfoVO;
27 25 import cn.fw.valhalla.domain.vo.customer.CustomerChangeQrCodeVO;
28 26 import cn.fw.valhalla.rpc.angel.dto.InsuranceDTO;
... ... @@ -39,11 +37,13 @@ import cn.fw.valhalla.service.data.AffiliationRecordService;
39 37 import cn.fw.valhalla.service.data.FollowRecordService;
40 38 import cn.fw.valhalla.service.data.FollowTaskService;
41 39 import cn.fw.valhalla.service.data.PublicPoolService;
  40 +import cn.fw.valhalla.service.event.CancelApproveEvent;
42 41 import com.alibaba.fastjson.JSON;
43 42 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
44 43 import lombok.extern.slf4j.Slf4j;
45 44 import org.springframework.beans.BeanUtils;
46 45 import org.springframework.beans.factory.annotation.Autowired;
  46 +import org.springframework.context.ApplicationEventPublisher;
47 47 import org.springframework.stereotype.Service;
48 48 import org.springframework.transaction.annotation.Transactional;
49 49 import org.springframework.util.CollectionUtils;
... ... @@ -74,6 +74,7 @@ public class CustomerChangeBizService extends AbstractCustomerService {
74 74 private final FollowRecordService followRecordService;
75 75 private final AffiliationRecordService affiliationRecordService;
76 76 private final PublicPoolService publicPoolService;
  77 + private final ApplicationEventPublisher eventPublisher;
77 78  
78 79  
79 80 @Autowired
... ... @@ -83,7 +84,8 @@ public class CustomerChangeBizService extends AbstractCustomerService {
83 84 final FollowTaskService followTaskService,
84 85 final FollowRecordService followRecordService,
85 86 final AffiliationRecordService affiliationRecordService,
86   - final PublicPoolService publicPoolService) {
  87 + final PublicPoolService publicPoolService,
  88 + final ApplicationEventPublisher eventPublisher) {
87 89 this.redisUtil = redisUtil;
88 90 this.passportService = passportService;
89 91 this.memberRpcService = memberRpcService;
... ... @@ -91,6 +93,7 @@ public class CustomerChangeBizService extends AbstractCustomerService {
91 93 this.followRecordService = followRecordService;
92 94 this.affiliationRecordService = affiliationRecordService;
93 95 this.publicPoolService = publicPoolService;
  96 + this.eventPublisher = eventPublisher;
94 97 }
95 98  
96 99 /**
... ... @@ -290,7 +293,7 @@ public class CustomerChangeBizService extends AbstractCustomerService {
290 293 return true;
291 294 }
292 295 Long adviserId = changeAdviserReq.getAdviserId();
293   - if (changeAdviserReq.getAdviserId().equals(customer.getAdviserId())) {
  296 + if (changeAdviserReq.getAdviserId().equals(customer.getAdviserId())) {
294 297 return true;
295 298 }
296 299 List<UserRoleDataRangeDTO> dataRange = userService.getUserRoleDataRange(adviserId, RoleCode.FWGW);
... ... @@ -363,6 +366,15 @@ public class CustomerChangeBizService extends AbstractCustomerService {
363 366 }
364 367 }
365 368  
  369 + @Transactional(rollbackFor = Exception.class)
  370 + public void changeFollowUser(FollowTask task, boolean needCancelApprove) {
  371 + changeFollowUser(task);
  372 + if (needCancelApprove) {
  373 + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT);
  374 + eventPublisher.publishEvent(event);
  375 + }
  376 + }
  377 +
366 378  
367 379 /**
368 380 * 更换跟进人
... ... @@ -429,6 +441,15 @@ public class CustomerChangeBizService extends AbstractCustomerService {
429 441 }
430 442 }
431 443  
  444 + @Transactional(rollbackFor = Exception.class)
  445 + public void changeInsFollowUser(FollowTask task, boolean needCancelApprove) {
  446 + changeInsFollowUser(task);
  447 + if (needCancelApprove) {
  448 + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT);
  449 + eventPublisher.publishEvent(event);
  450 + }
  451 + }
  452 +
432 453  
433 454 /**
434 455 * 修改档案
... ... @@ -543,7 +564,8 @@ public class CustomerChangeBizService extends AbstractCustomerService {
543 564 }
544 565  
545 566 private void changeFirstFollower(Long customerId, Long follower, Long shopId) {
546   - List<FollowTask> list = followTaskService.getWaitListByCustomerId(customerId);
  567 + List<FollowTypeEnum> enumList = Arrays.asList(FollowTypeEnum.FM, FollowTypeEnum.RM);
  568 + List<FollowTask> list = followTaskService.getWaitListByCustomerId(customerId, enumList);
547 569 if (CollectionUtils.isEmpty(list)) {
548 570 return;
549 571 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowBizService.java
1 1 package cn.fw.valhalla.service.bus.follow;
2 2  
  3 +import cn.fw.common.cache.locker.DistributedLocker;
3 4 import cn.fw.common.page.AppPage;
4 5 import cn.fw.common.web.auth.LoginAuthBean;
5 6 import cn.fw.valhalla.common.utils.DateUtil;
... ... @@ -9,6 +10,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord;
9 10 import cn.fw.valhalla.domain.db.follow.FollowTask;
10 11 import cn.fw.valhalla.domain.dto.FollowAttachmentDTO;
11 12 import cn.fw.valhalla.domain.enums.ApproveStateEnum;
  13 +import cn.fw.valhalla.domain.enums.ApproveTypeEnum;
12 14 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
13 15 import cn.fw.valhalla.domain.enums.TaskStateEnum;
14 16 import cn.fw.valhalla.domain.query.FollowQueryVO;
... ... @@ -29,6 +31,8 @@ import cn.fw.valhalla.service.event.TaskCancelEvent;
29 31 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
30 32 import lombok.Getter;
31 33 import lombok.extern.slf4j.Slf4j;
  34 +import org.apache.commons.lang3.tuple.Pair;
  35 +import org.redisson.api.RLock;
32 36 import org.springframework.beans.factory.annotation.Autowired;
33 37 import org.springframework.beans.factory.annotation.Value;
34 38 import org.springframework.stereotype.Service;
... ... @@ -38,6 +42,7 @@ import org.springframework.util.CollectionUtils;
38 42  
39 43 import java.time.LocalDateTime;
40 44 import java.util.*;
  45 +import java.util.concurrent.TimeUnit;
41 46 import java.util.stream.Collectors;
42 47  
43 48 import static cn.fw.common.businessvalidator.Validator.BV;
... ... @@ -60,24 +65,31 @@ public class FollowBizService {
60 65 private final FollowTaskService followTaskService;
61 66 private final FollowRecordService followRecordService;
62 67 private final UserService userService;
  68 + private final DistributedLocker distributedLocker;
63 69  
64 70 @Value("${follow.flowNo}")
65 71 @Getter
66 72 private String flowNo;
67 73  
  74 + @Value("${spring.cache.custom.global-prefix}:defeat")
  75 + @Getter
  76 + private String keyPrefix;
  77 +
68 78 @Autowired
69 79 public FollowBizService(final List<FollowStrategy> followStrategyList,
70 80 final FlowApproveRpc flowApproveRpc,
71 81 final ApproveRecordService approveRecordService,
72 82 final FollowTaskService followTaskService,
73 83 final FollowRecordService followRecordService,
74   - final UserService userService) {
  84 + final UserService userService,
  85 + final DistributedLocker distributedLocker) {
75 86 this.followMap = followStrategyList.stream().collect(Collectors.toMap(FollowStrategy::getFollowType, v -> v));
76 87 this.flowApproveRpc = flowApproveRpc;
77 88 this.approveRecordService = approveRecordService;
78 89 this.followTaskService = followTaskService;
79 90 this.followRecordService = followRecordService;
80 91 this.userService = userService;
  92 + this.distributedLocker = distributedLocker;
81 93 }
82 94  
83 95 /**
... ... @@ -126,6 +138,20 @@ public class FollowBizService {
126 138 }
127 139  
128 140 /**
  141 + * 查询跟进池详情
  142 + *
  143 + * @param taskId
  144 + * @return
  145 + */
  146 + public FollowDetailVO followPoolDetail(Long taskId) {
  147 + FollowTask task = followTaskService.getById(taskId);
  148 + BV.notNull(task, () -> "跟进线索不存在,请刷新列表");
  149 + FollowStrategy strategy = followMap.get(task.getType());
  150 + Assert.notNull(strategy, "strategy cannot be null");
  151 + return strategy.followPoolDetail(task);
  152 + }
  153 +
  154 + /**
129 155 * 完成跟进
130 156 *
131 157 * @param id
... ... @@ -173,28 +199,54 @@ public class FollowBizService {
173 199 */
174 200 @Transactional(rollbackFor = Exception.class)
175 201 public void defeat(LoginAuthBean currentUser, String reason, Long recordId) {
176   - FollowRecord record = followRecordService.getById(recordId);
177   - BV.notNull(record, () -> "跟进记录不存在");
178   - FollowTask task = followTaskService.getById(record.getTaskId());
179   - BV.notNull(task, () -> "跟进信息不存在");
180   - FlowDto flowDto = FlowDto.create(currentUser.getGroupId(), getFlowNo(), currentUser.getUserId(), currentUser.getUserName(), task.getFollowShop());
181   - HashMap<String, String> param = new HashMap<>(2);
182   - param.put("recordId", recordId.toString());
183   - param.put("type", task.getType().getValue().toString());
184   - flowDto.setParam(param);
185   - List<String> list = Collections.singletonList("跟进类型: " + task.getType().getName());
186   - flowDto.setBriefContentList(list);
187   - String orderNo = flowApproveRpc.initiate(flowDto);
188   - ApproveRecord approveRecord = new ApproveRecord();
189   - approveRecord.setDataId(task.getId());
190   - approveRecord.setUserId(currentUser.getUserId());
191   - approveRecord.setOrderNo(orderNo);
192   - approveRecord.setReason(reason);
193   - approveRecord.setState(ApproveStateEnum.WAIT);
194   - approveRecord.setPassed(Boolean.FALSE);
195   - approveRecord.setCreateTime(DateUtil.localDateTime2Date(LocalDateTime.now()));
196   - approveRecord.setUpdateTime(DateUtil.localDateTime2Date(LocalDateTime.now()));
197   - approveRecordService.save(approveRecord);
  202 + final String lockKey = getLockKey(recordId);
  203 + Pair<Boolean, RLock> pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 15);
  204 + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交");
  205 + try {
  206 + FollowRecord record = followRecordService.getById(recordId);
  207 + BV.notNull(record, () -> "跟进记录不存在");
  208 + FollowTask task = followTaskService.getById(record.getTaskId());
  209 + BV.notNull(task, () -> "跟进信息不存在");
  210 + boolean repetition = isRepetition(record.getTaskId().toString());
  211 + BV.isFalse(repetition, () -> "正在审批处理中,请勿重复申请");
  212 + FlowDto flowDto = FlowDto.create(currentUser.getGroupId(), getFlowNo(), currentUser.getUserId(), currentUser.getUserName(), task.getFollowShop());
  213 + HashMap<String, String> param = new HashMap<>(2);
  214 + param.put("recordId", recordId.toString());
  215 + param.put("type", task.getType().getValue().toString());
  216 + flowDto.setParam(param);
  217 + String name = "";
  218 + String plate = "";
  219 + FollowStrategy strategy = followMap.get(task.getType());
  220 + Assert.notNull(strategy, "strategy cannot be null");
  221 + FollowDetailVO vo = strategy.followPoolDetail(task);
  222 + if (Objects.nonNull(vo)) {
  223 + name = vo.getName();
  224 + plate = vo.getPlateNo();
  225 + }
  226 + List<String> list = Arrays.asList(
  227 + "申请人: " + currentUser.getUserName(),
  228 + "客户: " + name,
  229 + "车辆: " + plate,
  230 + "跟进类型: " + task.getType().getName(),
  231 + "战败原因: " + reason
  232 + );
  233 + flowDto.setBriefContentList(list);
  234 + String orderNo = flowApproveRpc.initiate(flowDto);
  235 + ApproveRecord approveRecord = new ApproveRecord();
  236 + approveRecord.setDataId(task.getId());
  237 + approveRecord.setUserId(currentUser.getUserId());
  238 + approveRecord.setOrderNo(orderNo);
  239 + approveRecord.setReason(reason);
  240 + approveRecord.setState(ApproveStateEnum.WAIT);
  241 + approveRecord.setType(ApproveTypeEnum.FOLLOW_DEFEAT);
  242 + approveRecord.setPassed(Boolean.FALSE);
  243 + approveRecord.setCreateTime(DateUtil.localDateTime2Date(LocalDateTime.now()));
  244 + approveRecord.setUpdateTime(DateUtil.localDateTime2Date(LocalDateTime.now()));
  245 + approveRecordService.save(approveRecord);
  246 + } catch (Exception e) {
  247 + distributedLocker.unlock(lockKey);
  248 + throw e;
  249 + }
198 250 }
199 251  
200 252 /**
... ... @@ -332,4 +384,24 @@ public class FollowBizService {
332 384 return null;
333 385 }
334 386 }
  387 +
  388 + private String getLockKey(Long recordId) {
  389 + BV.notNull(recordId, "recordId cannot be null");
  390 +
  391 + return String.format("%s:lock:%s", getKeyPrefix(), recordId);
  392 + }
  393 +
  394 + /**
  395 + * 审批防重
  396 + *
  397 + * @param taskId
  398 + * @return
  399 + */
  400 + private boolean isRepetition(String taskId) {
  401 + return approveRecordService.count(Wrappers.<ApproveRecord>lambdaQuery()
  402 + .eq(ApproveRecord::getDataId, taskId)
  403 + .eq(ApproveRecord::getType, ApproveTypeEnum.FOLLOW_DEFEAT)
  404 + .eq(ApproveRecord::getState, ApproveStateEnum.WAIT)
  405 + ) > 0;
  406 + }
335 407 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowPoolBizService.java
... ... @@ -2,23 +2,19 @@ package cn.fw.valhalla.service.bus.follow;
2 2  
3 3 import cn.fw.common.page.AppPage;
4 4 import cn.fw.common.web.auth.LoginAuthBean;
5   -import cn.fw.valhalla.common.constant.RoleCode;
  5 +import cn.fw.valhalla.common.enums.DefeatTypeEnum;
6 6 import cn.fw.valhalla.common.utils.DateUtil;
7 7 import cn.fw.valhalla.common.utils.StringUtils;
8 8 import cn.fw.valhalla.domain.db.PublicPool;
9   -import cn.fw.valhalla.domain.db.follow.FollowRecord;
10 9 import cn.fw.valhalla.domain.dto.FollowPoolDTO;
11   -import cn.fw.valhalla.domain.enums.FollowTypeEnum;
12 10 import cn.fw.valhalla.domain.enums.TaskStateEnum;
13 11 import cn.fw.valhalla.domain.query.FollowPoolQueryVO;
14 12 import cn.fw.valhalla.domain.vo.customer.PublicPoolVO;
15 13 import cn.fw.valhalla.domain.vo.follow.FollowPoolListVO;
16 14 import cn.fw.valhalla.rpc.erp.UserService;
17 15 import cn.fw.valhalla.rpc.erp.dto.UserInfoDTO;
18   -import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO;
19 16 import cn.fw.valhalla.rpc.oop.OopService;
20 17 import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
21   -import cn.fw.valhalla.service.data.FollowRecordService;
22 18 import cn.fw.valhalla.service.data.FollowTaskService;
23 19 import cn.fw.valhalla.service.data.PublicPoolService;
24 20 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
... ... @@ -29,11 +25,9 @@ import org.springframework.beans.BeanUtils;
29 25 import org.springframework.beans.factory.annotation.Autowired;
30 26 import org.springframework.stereotype.Service;
31 27  
32   -import java.time.LocalDateTime;
33 28 import java.util.ArrayList;
34 29 import java.util.List;
35 30 import java.util.Objects;
36   -import java.util.stream.Collectors;
37 31  
38 32 import static cn.fw.common.businessvalidator.Validator.BV;
39 33  
... ... @@ -47,70 +41,34 @@ import static cn.fw.common.businessvalidator.Validator.BV;
47 41 @Service
48 42 public class FollowPoolBizService {
49 43 private final FollowTaskService followTaskService;
50   - private final FollowRecordService followRecordService;
51 44 private final PublicPoolService publicPoolService;
52 45 private final OopService oopService;
53 46 private final UserService userService;
  47 + private final static Integer MONTH_DAY = 31;
54 48  
55 49 @Autowired
56 50 public FollowPoolBizService(final FollowTaskService followTaskService,
57   - final FollowRecordService followRecordService,
58 51 final PublicPoolService publicPoolService,
59 52 final OopService oopService,
60 53 final UserService userService) {
61 54 this.followTaskService = followTaskService;
62   - this.followRecordService = followRecordService;
63 55 this.publicPoolService = publicPoolService;
64 56 this.oopService = oopService;
65 57 this.userService = userService;
66 58 }
67 59  
68 60 /**
69   - * 战败池
70   - *
71   - * @param currentUser
72   - * @param queryVO
73   - * @return
74   - */
75   - public AppPage<FollowPoolListVO> defeatList(LoginAuthBean currentUser, FollowPoolQueryVO queryVO) {
76   - if (CollectionUtils.isEmpty(queryVO.getShopList())) {
77   - queryVO.setUserId(currentUser.getUserId());
78   - }
79   - List<FollowPoolDTO> list = followTaskService.defeatList(queryVO);
80   - List<FollowPoolListVO> defeatList = new ArrayList<>();
81   - for (FollowPoolDTO followPoolDTO : list) {
82   - FollowPoolListVO vo1 = transform4Origin(followPoolDTO);
83   - defeatList.add(vo1);
84   - if (!FollowTypeEnum.AC.getValue().equals(followPoolDTO.getType())) {
85   - FollowPoolListVO vo2 = transform4FinishUser(followPoolDTO);
86   - if (Objects.nonNull(vo2)) {
87   - defeatList.add(vo2);
88   - }
89   - }
90   - }
91   - AppPage<FollowPoolListVO> page = AppPage.empty(queryVO);
92   - page.setData(defeatList);
93   - return page;
94   - }
95   -
96   - /**
97 61 * 跟进池
98 62 *
99   - * @param currentUser
100 63 * @param queryVO
101 64 * @return
102 65 */
103   - public AppPage<FollowPoolListVO> followList(LoginAuthBean currentUser, FollowPoolQueryVO queryVO) {
104   - if (CollectionUtils.isEmpty(queryVO.getShopList())) {
105   - queryVO.setUserId(currentUser.getUserId());
106   - }
  66 + public AppPage<FollowPoolListVO> followList(LoginAuthBean user, FollowPoolQueryVO queryVO) {
  67 + prepareParams(user, queryVO);
107 68 List<FollowPoolDTO> list = followTaskService.followList(queryVO);
108 69 List<FollowPoolListVO> followList = new ArrayList<>();
109 70 for (FollowPoolDTO followPoolDTO : list) {
110   - FollowPoolListVO vo = trans2Pool(followPoolDTO, followPoolDTO.getFollowUser(), followPoolDTO.getFollowShop());
111   - vo.setRedistribution(Boolean.TRUE.equals(followPoolDTO.getChanged()));
112   - Integer days = DateUtil.sub(followPoolDTO.getDeadline(), DateUtil.localDateTime2Date(LocalDateTime.now()), "d");
113   - vo.setRemaining(days);
  71 + FollowPoolListVO vo = trans2Pool(followPoolDTO);
114 72 followList.add(vo);
115 73 }
116 74 AppPage<FollowPoolListVO> page = AppPage.empty(queryVO);
... ... @@ -118,31 +76,6 @@ public class FollowPoolBizService {
118 76 return page;
119 77 }
120 78  
121   -
122   - /**
123   - * 成交池
124   - *
125   - * @param currentUser
126   - * @param queryVO
127   - * @return
128   - */
129   - public AppPage<FollowPoolListVO> completeList(LoginAuthBean currentUser, FollowPoolQueryVO queryVO) {
130   - if (CollectionUtils.isEmpty(queryVO.getShopList())) {
131   - queryVO.setUserId(currentUser.getUserId());
132   - }
133   - List<FollowPoolDTO> list = followTaskService.completeList(queryVO);
134   - List<FollowPoolListVO> completeList = new ArrayList<>();
135   - for (FollowPoolDTO followPoolDTO : list) {
136   - FollowPoolListVO vo = trans2Pool(followPoolDTO, followPoolDTO.getFinishUser(), followPoolDTO.getFinishShop());
137   - vo.setRedistribution(!followPoolDTO.getOriginUser().equals(followPoolDTO.getFinishUser()));
138   - vo.setFinishTime(followPoolDTO.getFinishTime());
139   - completeList.add(vo);
140   - }
141   - AppPage<FollowPoolListVO> page = AppPage.empty(queryVO);
142   - page.setData(completeList);
143   - return page;
144   - }
145   -
146 79 /**
147 80 * 公共池
148 81 *
... ... @@ -152,8 +85,7 @@ public class FollowPoolBizService {
152 85 public AppPage<PublicPoolVO> publicList(FollowPoolQueryVO queryVO) {
153 86 Page<PublicPool> opage = new Page<>(queryVO.getCurrent(), queryVO.getPageSize());
154 87 opage = publicPoolService.page(opage, Wrappers.<PublicPool>lambdaQuery()
155   - .eq(StringUtils.isValid(queryVO.getKw()), PublicPool::getPlateNo, "%" + queryVO.getKw() + "%")
156   - .in(CollectionUtils.isNotEmpty(queryVO.getShopList()), PublicPool::getShopId, queryVO.getShopList())
  88 + .eq(StringUtils.isValid(queryVO.getPlateNo()), PublicPool::getPlateNo, "%" + queryVO.getPlateNo() + "%")
157 89 .eq(Objects.nonNull(queryVO.getType()), PublicPool::getType, queryVO.getType())
158 90 .eq(Objects.nonNull(queryVO.getGroupId()), PublicPool::getGroupId, queryVO.getGroupId())
159 91 );
... ... @@ -174,55 +106,52 @@ public class FollowPoolBizService {
174 106 }
175 107  
176 108  
177   - private FollowPoolListVO trans2Pool(FollowPoolDTO poolDTO, Long userId, Long shopId) {
  109 + private FollowPoolListVO trans2Pool(FollowPoolDTO poolDTO) {
178 110 FollowPoolListVO vo = new FollowPoolListVO();
179   - vo.setPlateNo(poolDTO.getPlateNo());
180   - vo.setType(poolDTO.getType());
181   - UserInfoDTO user = userService.user(userId);
  111 + BeanUtils.copyProperties(poolDTO, vo);
  112 + UserInfoDTO user = userService.user(poolDTO.getUserId());
182 113 if (Objects.nonNull(user)) {
183 114 vo.setFollower(user.getUserName());
184 115 }
185   - ShopDTO shop = oopService.shop(shopId);
  116 + ShopDTO shop = oopService.shop(poolDTO.getShopId());
186 117 if (Objects.nonNull(shop)) {
187 118 vo.setShopName(shop.getShopName());
188 119 }
189   - int count = followRecordService.count(Wrappers.<FollowRecord>lambdaQuery()
190   - .eq(FollowRecord::getTaskId, poolDTO.getId())
191   - .eq(FollowRecord::getUserId, userId)
192   - .isNotNull(FollowRecord::getFollowTime)
193   - );
194   - vo.setTimes(count);
195   - return vo;
196   - }
197   -
198   - private FollowPoolListVO transform4Origin(FollowPoolDTO poolDTO) {
199   - FollowPoolListVO vo = trans2Pool(poolDTO, poolDTO.getOriginUser(), poolDTO.getOriginShop());
200   - vo.setRedistribution(false);
  120 + DefeatTypeEnum defeatTypeEnum = DefeatTypeEnum.ofValue(poolDTO.getInitiative());
  121 + if (Objects.nonNull(defeatTypeEnum) && poolDTO.getState() == 3) {
  122 + vo.setDefeatType(defeatTypeEnum.getName());
  123 + }
201 124  
202   - if (Boolean.TRUE.equals(poolDTO.getFinished())) {
203   - if (Boolean.TRUE.equals(poolDTO.getChanged()) || !poolDTO.getOriginUser().equals(poolDTO.getFinishUser())) {
204   - vo.setDefeatType("集团内战败");
205   - }
206   - } else {
207   - vo.setDefeatType("到期未成交");
  125 + if (Boolean.TRUE.equals(poolDTO.getFinished()) && !poolDTO.getOriginShop().equals(poolDTO.getFinishShop())) {
  126 + vo.setDefeatDesc("集团内战败");
  127 + }
  128 + if (poolDTO.getState() == 3 && DefeatTypeEnum.B.equals(defeatTypeEnum)) {
  129 + vo.setDefeatDesc("系统划走");
208 130 }
  131 +
209 132 return vo;
210 133 }
211 134  
212   - private FollowPoolListVO transform4FinishUser(FollowPoolDTO poolDTO) {
213   - FollowPoolListVO vo = trans2Pool(poolDTO, poolDTO.getFollowUser(), poolDTO.getFollowShop());
214   - vo.setRedistribution(true);
215   - if (TaskStateEnum.END.getValue().equals(poolDTO.getState())) {
216   - vo.setDefeatType("到期未成交");
  135 + private void prepareParams(LoginAuthBean user, FollowPoolQueryVO queryVO) {
  136 + if (Objects.nonNull(user)) {
  137 + queryVO.setUserId(user.getUserId());
  138 + queryVO.setGroupId(user.getGroupId());
217 139 } else {
218   - return null;
  140 + BV.isFalse(Objects.isNull(queryVO.getShopId()) && Objects.isNull(queryVO.getUserId()), () -> "请选择服务站或者人员");
  141 + }
  142 + boolean inSection = DateUtil.sub(queryVO.getEndTime(), queryVO.getStartTime(), "d") <= MONTH_DAY;
  143 + BV.isTrue(inSection, () -> "暂不支持查询超过一个月区间的数据");
  144 + boolean d = DateUtil.sub(queryVO.getEndTime(), queryVO.getStartTime(), "d") >= 0;
  145 + BV.isTrue(d, () -> "截止时间必须大于开始时间");
  146 + if (Objects.nonNull(queryVO.getOrder()) && StringUtils.isValid(queryVO.getOrderAtt())) {
  147 + StringBuilder sb = new StringBuilder(" order by ");
  148 + sb.append(StringUtils.toColumnName(queryVO.getOrderAtt()).toLowerCase());
  149 + if (queryVO.getOrder() == 1) {
  150 + sb.append(" asc ");
  151 + } else {
  152 + sb.append(" desc ");
  153 + }
  154 + queryVO.setOrderString(sb.toString());
219 155 }
220   - return vo;
221   - }
222   -
223   - private String queryShopId(Long userId, String code) {
224   - List<UserRoleDataRangeDTO> range = userService.getUserRoleDataRange(userId, code);
225   - BV.isTrue(CollectionUtils.isNotEmpty(range), () -> "非管理岗位必须选择服务站");
226   - return range.stream().map(UserRoleDataRangeDTO::getRangeValue).map(String::valueOf).collect(Collectors.joining(","));
227 156 }
228 157 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java
... ... @@ -12,6 +12,7 @@ import cn.fw.valhalla.domain.db.follow.FollowTask;
12 12 import cn.fw.valhalla.domain.dto.CustomerDetailDto;
13 13 import cn.fw.valhalla.domain.dto.FollowAttachmentDTO;
14 14 import cn.fw.valhalla.domain.enums.*;
  15 +import cn.fw.valhalla.domain.vo.follow.FollowDetailVO;
15 16 import cn.fw.valhalla.domain.vo.follow.FollowRecordVO;
16 17 import cn.fw.valhalla.domain.vo.setting.SettingVO;
17 18 import cn.fw.valhalla.rpc.angel.InsurerRpcService;
... ... @@ -192,7 +193,7 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
192 193 record.setTaskId(task.getId());
193 194 record.setCustomerId(task.getCustomerId());
194 195 record.setType(task.getType());
195   - record.setUserId(customer.getAdviserId());
  196 + record.setUserId(task.getFollowUser());
196 197 record.setPlanTime(task.getBeginTime());
197 198  
198 199 settingBizService.querySettingByType(task.getType(), SettingTypeEnum.EFFECTIVE_TIME, task.getGroupId())
... ... @@ -311,6 +312,8 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
311 312 return dto;
312 313 }
313 314  
  315 + abstract public FollowDetailVO assemble(Long customerId);
  316 +
314 317 /**
315 318 * 查询档案正在生效的保险信息
316 319 *
... ... @@ -369,6 +372,32 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
369 372 }
370 373  
371 374 /**
  375 + * 完成生成的跟进待办
  376 + *
  377 + * @param taskId
  378 + */
  379 + protected void completeTodo(Long taskId) {
  380 + List<FollowRecord> list = Optional.ofNullable(followRecordService.list(Wrappers.<FollowRecord>lambdaQuery()
  381 + .eq(FollowRecord::getTaskId, taskId)
  382 + .eq(FollowRecord::getOutTime, Boolean.FALSE)
  383 + .isNull(FollowRecord::getFollowTime)
  384 + .ge(FollowRecord::getDeadline, new Date())
  385 + )).orElse(new ArrayList<>());
  386 + if (CollectionUtils.isEmpty(list)) {
  387 + return;
  388 + }
  389 + for (FollowRecord record : list) {
  390 + if (Boolean.TRUE.equals(record.getAddTodo())) {
  391 + BackLogItemDTO dto = new BackLogItemDTO(record.getUserId(), getItemCode(record.getType()), String.valueOf(record.getId()), record.getPlanTime());
  392 + todoRpcService.complete(dto);
  393 + }
  394 + record.setFollowTime(new Date());
  395 + record.setOutTime(Boolean.FALSE);
  396 + }
  397 + followRecordService.updateBatchById(list);
  398 + }
  399 +
  400 + /**
372 401 * 回滚完成的跟进
373 402 *
374 403 * @param task
... ... @@ -565,6 +594,7 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
565 594 return null;
566 595 }
567 596 Integer value = vo.getDetailValue();
  597 + SettingUnitEnum unit = Objects.requireNonNull(SettingUnitEnum.ofValue(vo.getUnit()));
568 598 if (value == null || value <= 0) {
569 599 log.info("关键设置数据异常,请检查数据 : settingType[{}] settingId[{}]", vo.getType(), vo.getId());
570 600 return null;
... ... @@ -572,7 +602,12 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
572 602 if (reverse) {
573 603 value = -1 * value;
574 604 }
575   - return DateUtil.getExpired(origin, value, getCalendarType(Objects.requireNonNull(SettingUnitEnum.ofValue(vo.getUnit()))));
  605 + Timestamp expired = DateUtil.getExpired(origin, value, getCalendarType(unit));
  606 + DateUtil.date2LocalDateTime(expired);
  607 + if (SettingUnitEnum.DAY.equals(unit) && !DateUtil.isBeforeDawn(expired)) {
  608 + expired = DateUtil.getExpired(DateUtil.startDate(expired), 1, Calendar.DATE);
  609 + }
  610 + return expired;
576 611 }
577 612  
578 613 protected String getItemCode(FollowTypeEnum type) {
... ... @@ -684,8 +719,8 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
684 719  
685 720 private Timestamp getValidTime(SettingVO setting, Date origin) {
686 721 Timestamp timestamp = calDate(setting, origin, false);
687   - if (!Objects.requireNonNull(timestamp).after(DateUtil.localDateTime2Date(LocalDateTime.now()))) {
688   - return calDate(setting, DateUtil.localDateTime2Date(LocalDateTime.now()), false);
  722 + while (!timestamp.after(DateUtil.localDateTime2Date(LocalDateTime.now()))) {
  723 + timestamp = calDate(setting, timestamp, false);
689 724 }
690 725 return timestamp;
691 726 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/FollowStrategy.java
... ... @@ -115,4 +115,12 @@ public interface FollowStrategy {
115 115 * @param task
116 116 */
117 117 void stopFollowTask(FollowTask task);
  118 +
  119 + /**
  120 + * 查询跟进池详情
  121 + *
  122 + * @param task
  123 + * @return
  124 + */
  125 + FollowDetailVO followPoolDetail(FollowTask task);
118 126 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/ACFollowStrategy.java
... ... @@ -12,6 +12,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecordAttachments;
12 12 import cn.fw.valhalla.domain.db.follow.FollowTask;
13 13 import cn.fw.valhalla.domain.dto.CustomerDetailDto;
14 14 import cn.fw.valhalla.domain.dto.FollowAttachmentDTO;
  15 +import cn.fw.valhalla.domain.enums.ApproveTypeEnum;
15 16 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
16 17 import cn.fw.valhalla.domain.enums.TaskStateEnum;
17 18 import cn.fw.valhalla.domain.vo.follow.*;
... ... @@ -20,6 +21,7 @@ import cn.fw.valhalla.rpc.angel.dto.InsuranceDTO;
20 21 import cn.fw.valhalla.rpc.erp.dto.BackLogItemDTO;
21 22 import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy;
22 23 import cn.fw.valhalla.service.data.AccidentPoolService;
  24 +import cn.fw.valhalla.service.event.CancelApproveEvent;
23 25 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
24 26 import lombok.extern.slf4j.Slf4j;
25 27 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -81,36 +83,10 @@ public class ACFollowStrategy extends AbstractFollowStrategy {
81 83 public FollowDetailVO getDetail(Long id) {
82 84 FollowRecord followRecord = followRecordService.getById(id);
83 85 BV.notNull(followRecord, "跟进记录不存在");
84   - AccidentPool accidentPool = accidentPoolService.getById(followRecord.getCustomerId());
85   - BV.notNull(accidentPool, "事故车信息不存在");
86   - Customer customer = customerService.queryByPlateNo(accidentPool.getPlateNo(), accidentPool.getGroupId());
87   - ACDetailVO vo = new ACDetailVO();
  86 + ACDetailVO vo = assemble(followRecord.getCustomerId());
88 87 vo.setId(followRecord.getId());
89   - vo.setName(accidentPool.getName());
90   - vo.setMobile(accidentPool.getMobile());
91   - vo.setRegion(MobileUtil.attribution(accidentPool.getMobile()));
92   - vo.setRealMobile(accidentPool.getMobile());
93 88 vo.setTaskId(followRecord.getTaskId());
94 89 vo.setDeadline(followRecord.getDeadline());
95   - vo.setPlateNo(accidentPool.getPlateNo());
96   - vo.setTclInsComName(accidentPool.getInsurerName());
97   - vo.setBusInsComName(accidentPool.getInsurerName());
98   - vo.setCarModel(accidentPool.getBrandName() + " " + accidentPool.getSeriesName());
99   - vo.setReportNum(accidentPool.getReportNum());
100   - if (Objects.nonNull(customer)) {
101   - CustomerDetailDto customerDetailDto = queryCustomerInfo(customer.getId());
102   - vo.setCustomerId(customer.getId());
103   - vo.setAdviserId(customerDetailDto.getAdviserId());
104   - vo.setAdviserName(customerDetailDto.getAdviserName());
105   - vo.setVin(customerDetailDto.getFrameNo());
106   - Optional<InsuranceDTO> insuranceDTO = queryInsuInfo(customer.getId());
107   - insuranceDTO.ifPresent(ins -> {
108   - vo.setTclInsComName(ins.getTciInsurerName());
109   - vo.setTclInsExpiration(ins.getTciExpiryDate());
110   - vo.setBusInsComName(ins.getInsurerName());
111   - vo.setBusInsExpiration(ins.getExpiryDate());
112   - });
113   - }
114 90 return vo;
115 91 }
116 92  
... ... @@ -172,7 +148,9 @@ public class ACFollowStrategy extends AbstractFollowStrategy {
172 148 return true;
173 149 }
174 150 if (task.getFinished()) {
175   - cancelFollowTodo(task.getId());
  151 + completeTodo(task.getId());
  152 + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT);
  153 + eventPublisher.publishEvent(event);
176 154 }
177 155 return followTaskService.updateById(task);
178 156 }
... ... @@ -189,7 +167,7 @@ public class ACFollowStrategy extends AbstractFollowStrategy {
189 167 record.setTaskId(task.getId());
190 168 record.setCustomerId(task.getCustomerId());
191 169 record.setType(task.getType());
192   - record.setUserId(task.getOriginUser());
  170 + record.setUserId(task.getFollowUser());
193 171 record.setPlanTime(task.getBeginTime());
194 172 record.setDeadline(task.getDeadline());
195 173 record.setOutTime(Boolean.FALSE);
... ... @@ -209,6 +187,13 @@ public class ACFollowStrategy extends AbstractFollowStrategy {
209 187 followRecordService.overdue(record.getId());
210 188 }
211 189  
  190 + @Override
  191 + public FollowDetailVO followPoolDetail(FollowTask task) {
  192 + ACDetailVO vo = assemble(task.getCustomerId());
  193 + vo.setTaskId(task.getId());
  194 + return vo;
  195 + }
  196 +
212 197 /**
213 198 * 处理跟进任务
214 199 *
... ... @@ -249,4 +234,33 @@ public class ACFollowStrategy extends AbstractFollowStrategy {
249 234 }
250 235 return task;
251 236 }
  237 +
  238 + @Override
  239 + public ACDetailVO assemble(Long customerId) {
  240 + AccidentPool accidentPool = accidentPoolService.getById(customerId);
  241 + BV.notNull(accidentPool, "事故车信息不存在");
  242 + Customer customer = customerService.queryByPlateNo(accidentPool.getPlateNo(), accidentPool.getGroupId());
  243 + ACDetailVO vo = new ACDetailVO();
  244 + vo.setName(accidentPool.getName());
  245 + vo.setMobile(accidentPool.getMobile());
  246 + vo.setRegion(MobileUtil.attribution(accidentPool.getMobile()));
  247 + vo.setRealMobile(accidentPool.getReportMobile());
  248 + vo.setReportMobile(accidentPool.getReportMobile());
  249 + vo.setAddress(accidentPool.getAddress());
  250 + vo.setShopId(accidentPool.getShopId());
  251 + vo.setShopName(accidentPool.getShopName());
  252 + vo.setSms(accidentPool.getSms());
  253 + vo.setPlateNo(accidentPool.getPlateNo());
  254 + vo.setCarModel(accidentPool.getBrandName() + " " + accidentPool.getSeriesName());
  255 + if (Objects.nonNull(customer)) {
  256 + CustomerDetailDto customerDetailDto = queryCustomerInfo(customer.getId());
  257 + vo.setCustomerId(customer.getId());
  258 + vo.setAdviserId(customerDetailDto.getAdviserId());
  259 + vo.setAdviserName(customerDetailDto.getAdviserName());
  260 + vo.setVin(customerDetailDto.getFrameNo());
  261 + Optional<InsuranceDTO> insuranceDTO = queryInsuInfo(customer.getId());
  262 + insuranceDTO.ifPresent(ins -> vo.setInsComName(ins.getTciInsurerName()));
  263 + }
  264 + return vo;
  265 + }
252 266 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/FMFollowStrategy.java
... ... @@ -8,6 +8,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord;
8 8 import cn.fw.valhalla.domain.db.follow.FollowTask;
9 9 import cn.fw.valhalla.domain.dto.CustomerDetailDto;
10 10 import cn.fw.valhalla.domain.dto.FollowAttachmentDTO;
  11 +import cn.fw.valhalla.domain.enums.ApproveTypeEnum;
11 12 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
12 13 import cn.fw.valhalla.domain.enums.SettingTypeEnum;
13 14 import cn.fw.valhalla.domain.enums.TaskStateEnum;
... ... @@ -16,6 +17,7 @@ import cn.fw.valhalla.domain.vo.setting.SettingVO;
16 17 import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
17 18 import cn.fw.valhalla.sdk.enums.DataTypeEnum;
18 19 import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy;
  20 +import cn.fw.valhalla.service.event.CancelApproveEvent;
19 21 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
20 22 import lombok.extern.slf4j.Slf4j;
21 23 import org.springframework.stereotype.Component;
... ... @@ -69,24 +71,11 @@ public class FMFollowStrategy extends AbstractFollowStrategy {
69 71 public FollowDetailVO getDetail(Long id) {
70 72 FollowRecord followRecord = followRecordService.getById(id);
71 73 BV.notNull(followRecord, "跟进记录不存在");
72   - CustomerDetailDto customerDetailDto = queryCustomerInfo(followRecord.getCustomerId());
73   - FMDetailVO vo = new FMDetailVO();
74   - vo.setId(followRecord.getId());
75   - vo.setVin(customerDetailDto.getFrameNo());
76   - vo.setCustomerId(followRecord.getCustomerId());
77   - vo.setName(customerDetailDto.getName());
78   - vo.setMobile(customerDetailDto.getMobile());
79   - vo.setRegion(MobileUtil.attribution(customerDetailDto.getMobile()));
80   - vo.setRealMobile(customerDetailDto.getMobile());
81   - vo.setTaskId(followRecord.getTaskId());
82   - vo.setDeadline(followRecord.getDeadline());
83   - vo.setPlateNo(customerDetailDto.getPlateNo());
84   - vo.setAdviserId(customerDetailDto.getAdviserId());
85   - vo.setAdviserName(customerDetailDto.getAdviserName());
86   - vo.setCarModel(customerDetailDto.getBrandName() + " " + customerDetailDto.getSeriesName());
87   - vo.setBuyDate(customerDetailDto.getBuyDate());
88 74 FollowTask followTask = followTaskService.getById(followRecord.getTaskId());
89 75 BV.notNull(followTask, "跟进信息不存在");
  76 + FMDetailVO vo = assemble(followRecord.getCustomerId());
  77 + vo.setId(followRecord.getId());
  78 + vo.setTaskId(followRecord.getTaskId());
90 79 vo.setFMExpiration(followTask.getDeadline());
91 80 return vo;
92 81 }
... ... @@ -159,6 +148,14 @@ public class FMFollowStrategy extends AbstractFollowStrategy {
159 148 }
160 149  
161 150 @Override
  151 + public FollowDetailVO followPoolDetail(FollowTask task) {
  152 + FMDetailVO vo = assemble(task.getCustomerId());
  153 + vo.setTaskId(task.getId());
  154 + vo.setFMExpiration(task.getDeadline());
  155 + return vo;
  156 + }
  157 +
  158 + @Override
162 159 @Transactional(rollbackFor = Exception.class)
163 160 public boolean origin2task(OriginalData originalData) {
164 161 Customer customer = customerService.queryById(originalData.getCustomerId());
... ... @@ -217,15 +214,16 @@ public class FMFollowStrategy extends AbstractFollowStrategy {
217 214 if (TaskStateEnum.WAITING.equals(task.getState())) {
218 215 idList.add(task.getId());
219 216 }
220   -
221 217 if (TaskStateEnum.ONGOING.equals(task.getState())) {
222 218 task.setFinished(Boolean.TRUE);
223 219 task.setFinishTime(completeTime);
224 220 task.setState(TaskStateEnum.END);
225 221 task.setFinishShop(customer.getShopId());
226 222 task.setFinishUser(customer.getAdviserId());
227   - cancelFollowTodo(task.getId());
  223 + completeTodo(task.getId());
228 224 taskList.add(task);
  225 + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT);
  226 + eventPublisher.publishEvent(event);
229 227 }
230 228 }
231 229 List<Long> ids = list.stream().map(FollowTask::getId).collect(Collectors.toList());
... ... @@ -237,4 +235,22 @@ public class FMFollowStrategy extends AbstractFollowStrategy {
237 235 followTaskService.updateBatchById(taskList);
238 236 }
239 237 }
  238 +
  239 + @Override
  240 + public FMDetailVO assemble(Long customerId) {
  241 + CustomerDetailDto customerDetailDto = queryCustomerInfo(customerId);
  242 + FMDetailVO vo = new FMDetailVO();
  243 + vo.setVin(customerDetailDto.getFrameNo());
  244 + vo.setCustomerId(customerId);
  245 + vo.setName(customerDetailDto.getName());
  246 + vo.setMobile(customerDetailDto.getMobile());
  247 + vo.setRegion(MobileUtil.attribution(customerDetailDto.getMobile()));
  248 + vo.setRealMobile(customerDetailDto.getMobile());
  249 + vo.setPlateNo(customerDetailDto.getPlateNo());
  250 + vo.setAdviserId(customerDetailDto.getAdviserId());
  251 + vo.setAdviserName(customerDetailDto.getAdviserName());
  252 + vo.setCarModel(customerDetailDto.getBrandName() + " " + customerDetailDto.getSeriesName());
  253 + vo.setBuyDate(customerDetailDto.getBuyDate());
  254 + return vo;
  255 + }
240 256 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java
... ... @@ -19,6 +19,7 @@ import cn.fw.valhalla.rpc.erp.dto.PostUserDTO;
19 19 import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO;
20 20 import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
21 21 import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy;
  22 +import cn.fw.valhalla.service.event.CancelApproveEvent;
22 23 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
23 24 import lombok.extern.slf4j.Slf4j;
24 25 import org.springframework.stereotype.Component;
... ... @@ -76,29 +77,10 @@ public class IRFollowStrategy extends AbstractFollowStrategy {
76 77 public FollowDetailVO getDetail(Long id) {
77 78 FollowRecord followRecord = followRecordService.getById(id);
78 79 BV.notNull(followRecord, "跟进记录不存在");
79   - CustomerDetailDto detailDto = queryCustomerInfo(followRecord.getCustomerId());
80   - IRDetailVO vo = new IRDetailVO();
  80 + IRDetailVO vo = assemble(followRecord.getCustomerId());
81 81 vo.setId(followRecord.getId());
82   - vo.setCustomerId(followRecord.getCustomerId());
83   - vo.setAdviserId(detailDto.getAdviserId());
84   - vo.setAdviserName(detailDto.getAdviserName());
85   - vo.setVin(detailDto.getFrameNo());
86   - vo.setName(detailDto.getName());
87   - vo.setMobile(detailDto.getMobile());
88   - vo.setRegion(MobileUtil.attribution(detailDto.getMobile()));
89   - vo.setRealMobile(detailDto.getMobile());
90 82 vo.setTaskId(followRecord.getTaskId());
91 83 vo.setDeadline(followRecord.getDeadline());
92   - vo.setPlateNo(detailDto.getPlateNo());
93   - vo.setBuyPrice(detailDto.getBuyPrice() / 100);
94   - vo.setCarModel(detailDto.getBrandName() + " " + detailDto.getSeriesName());
95   - Optional<InsuranceDTO> insuranceDTO = queryInsuInfo(followRecord.getCustomerId());
96   - insuranceDTO.ifPresent(ins -> {
97   - vo.setTclInsComName(ins.getTciInsurerName());
98   - vo.setTclInsExpiration(ins.getTciExpiryDate());
99   - vo.setBusInsComName(ins.getInsurerName());
100   - vo.setBusInsExpiration(ins.getExpiryDate());
101   - });
102 84 return vo;
103 85 }
104 86  
... ... @@ -319,6 +301,13 @@ public class IRFollowStrategy extends AbstractFollowStrategy {
319 301 super.overdueProcessing(record);
320 302 }
321 303  
  304 + @Override
  305 + public FollowDetailVO followPoolDetail(FollowTask task) {
  306 + IRDetailVO vo = assemble(task.getCustomerId());
  307 + vo.setTaskId(task.getId());
  308 + return vo;
  309 + }
  310 +
322 311 /**
323 312 * 生成消息推送
324 313 *
... ... @@ -374,8 +363,10 @@ public class IRFollowStrategy extends AbstractFollowStrategy {
374 363 task.setFinished(Boolean.TRUE);
375 364 task.setState(TaskStateEnum.END);
376 365 task.setFinishTime(completeTime);
377   - cancelFollowTodo(task.getId());
  366 + completeTodo(task.getId());
378 367 taskList.add(task);
  368 + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT);
  369 + eventPublisher.publishEvent(event);
379 370 }
380 371 }
381 372 List<Long> ids = list.stream().map(FollowTask::getId).collect(Collectors.toList());
... ... @@ -387,4 +378,28 @@ public class IRFollowStrategy extends AbstractFollowStrategy {
387 378 followTaskService.updateBatchById(taskList);
388 379 }
389 380 }
  381 +
  382 + @Override
  383 + public IRDetailVO assemble(Long customerId) {
  384 + CustomerDetailDto detailDto = queryCustomerInfo(customerId);
  385 + IRDetailVO vo = new IRDetailVO();
  386 + vo.setCustomerId(customerId);
  387 + vo.setAdviserId(detailDto.getAdviserId());
  388 + vo.setAdviserName(detailDto.getAdviserName());
  389 + vo.setVin(detailDto.getFrameNo());
  390 + vo.setName(detailDto.getName());
  391 + vo.setMobile(detailDto.getMobile());
  392 + vo.setRegion(MobileUtil.attribution(detailDto.getMobile()));
  393 + vo.setRealMobile(detailDto.getMobile());
  394 + vo.setPlateNo(detailDto.getPlateNo());
  395 + vo.setCarModel(detailDto.getBrandName() + " " + detailDto.getSeriesName());
  396 + Optional<InsuranceDTO> insuranceDTO = queryInsuInfo(customerId);
  397 + insuranceDTO.ifPresent(ins -> {
  398 + vo.setTclInsComName(ins.getTciInsurerName());
  399 + vo.setTclInsExpiration(ins.getTciExpiryDate());
  400 + vo.setBusInsComName(ins.getInsurerName());
  401 + vo.setBusInsExpiration(ins.getExpiryDate());
  402 + });
  403 + return vo;
  404 + }
390 405 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/RMFollowStrategy.java
... ... @@ -8,6 +8,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord;
8 8 import cn.fw.valhalla.domain.db.follow.FollowTask;
9 9 import cn.fw.valhalla.domain.dto.CustomerDetailDto;
10 10 import cn.fw.valhalla.domain.dto.FollowAttachmentDTO;
  11 +import cn.fw.valhalla.domain.enums.ApproveTypeEnum;
11 12 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
12 13 import cn.fw.valhalla.domain.enums.SettingTypeEnum;
13 14 import cn.fw.valhalla.domain.enums.TaskStateEnum;
... ... @@ -17,6 +18,7 @@ import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
17 18 import cn.fw.valhalla.sdk.enums.DataTypeEnum;
18 19 import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy;
19 20 import cn.fw.valhalla.service.data.OriginalDataService;
  21 +import cn.fw.valhalla.service.event.CancelApproveEvent;
20 22 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
21 23 import lombok.extern.slf4j.Slf4j;
22 24 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -90,32 +92,10 @@ public class RMFollowStrategy extends AbstractFollowStrategy {
90 92 public FollowDetailVO getDetail(Long id) {
91 93 FollowRecord followRecord = followRecordService.getById(id);
92 94 BV.notNull(followRecord, "跟进记录不存在");
93   - CustomerDetailDto customerDetailDto = queryCustomerInfo(followRecord.getCustomerId());
94   - RMDetailVO vo = new RMDetailVO();
  95 + RMDetailVO vo = assemble(followRecord.getCustomerId());
95 96 vo.setId(followRecord.getId());
96   - vo.setCustomerId(followRecord.getCustomerId());
97   - vo.setName(customerDetailDto.getName());
98   - vo.setMobile(customerDetailDto.getMobile());
99   - vo.setRegion(MobileUtil.attribution(customerDetailDto.getMobile()));
100   - vo.setRealMobile(customerDetailDto.getMobile());
101 97 vo.setTaskId(followRecord.getTaskId());
102 98 vo.setDeadline(followRecord.getDeadline());
103   - vo.setPlateNo(customerDetailDto.getPlateNo());
104   - vo.setVin(customerDetailDto.getFrameNo());
105   - vo.setAdviserId(customerDetailDto.getAdviserId());
106   - vo.setAdviserName(customerDetailDto.getAdviserName());
107   - vo.setCarModel(customerDetailDto.getBrandName() + " " + customerDetailDto.getSeriesName());
108   - vo.setLastMileage(customerDetailDto.getCurrentMileage());
109   - OriginalData originalData = originalDataService.getOne(Wrappers.<OriginalData>lambdaQuery()
110   - .eq(OriginalData::getCustomerId, followRecord.getCustomerId())
111   - .eq(OriginalData::getType, DataTypeEnum.FS)
112   - .eq(OriginalData::getGroupId, followRecord.getGroupId())
113   - .orderByDesc(OriginalData::getGenerateTime)
114   - .last("limit 1")
115   - );
116   - if (Objects.nonNull(originalData)) {
117   - vo.setDeliveryTime(originalData.getGenerateTime());
118   - }
119 99 return vo;
120 100 }
121 101  
... ... @@ -226,6 +206,13 @@ public class RMFollowStrategy extends AbstractFollowStrategy {
226 206 super.overdueProcessing(record);
227 207 }
228 208  
  209 + @Override
  210 + public FollowDetailVO followPoolDetail(FollowTask task) {
  211 + RMDetailVO vo = assemble(task.getCustomerId());
  212 + vo.setTaskId(task.getId());
  213 + return vo;
  214 + }
  215 +
229 216 /**
230 217 * 完成之前的跟进
231 218 *
... ... @@ -248,8 +235,10 @@ public class RMFollowStrategy extends AbstractFollowStrategy {
248 235 task.setState(TaskStateEnum.END);
249 236 task.setFinishUser(customer.getAdviserId());
250 237 task.setFinishShop(customer.getShopId());
251   - cancelFollowTodo(task.getId());
  238 + completeTodo(task.getId());
252 239 taskList.add(task);
  240 + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT);
  241 + eventPublisher.publishEvent(event);
253 242 }
254 243 List<Long> ids = list.stream().map(FollowTask::getId).collect(Collectors.toList());
255 244 followNoticeRecordService.removeByTaskIds(ids);
... ... @@ -257,4 +246,32 @@ public class RMFollowStrategy extends AbstractFollowStrategy {
257 246 followTaskService.updateBatchById(taskList);
258 247 }
259 248 }
  249 +
  250 + @Override
  251 + public RMDetailVO assemble(Long customerId) {
  252 + CustomerDetailDto customerDetailDto = queryCustomerInfo(customerId);
  253 + RMDetailVO vo = new RMDetailVO();
  254 + vo.setCustomerId(customerId);
  255 + vo.setName(customerDetailDto.getName());
  256 + vo.setMobile(customerDetailDto.getMobile());
  257 + vo.setRegion(MobileUtil.attribution(customerDetailDto.getMobile()));
  258 + vo.setRealMobile(customerDetailDto.getMobile());
  259 + vo.setPlateNo(customerDetailDto.getPlateNo());
  260 + vo.setVin(customerDetailDto.getFrameNo());
  261 + vo.setAdviserId(customerDetailDto.getAdviserId());
  262 + vo.setAdviserName(customerDetailDto.getAdviserName());
  263 + vo.setCarModel(customerDetailDto.getBrandName() + " " + customerDetailDto.getSeriesName());
  264 + vo.setLastMileage(customerDetailDto.getCurrentMileage());
  265 + OriginalData originalData = originalDataService.getOne(Wrappers.<OriginalData>lambdaQuery()
  266 + .eq(OriginalData::getCustomerId, customerId)
  267 + .eq(OriginalData::getType, DataTypeEnum.FS)
  268 + .eq(OriginalData::getGroupId, customerDetailDto.getGroupId())
  269 + .orderByDesc(OriginalData::getGenerateTime)
  270 + .last("limit 1")
  271 + );
  272 + if (Objects.nonNull(originalData)) {
  273 + vo.setDeliveryTime(originalData.getGenerateTime());
  274 + }
  275 + return vo;
  276 + }
260 277 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/setting/strategy/AbstractSettingStrategy.java
... ... @@ -127,8 +127,8 @@ public abstract class AbstractSettingStrategy implements SettingStrategy {
127 127 protected boolean saveOrUpdate(final FollowTypeEnum type, final Long groupId, final List<SettingDTO> list) {
128 128 String lockKey = getLockKey(groupId, type);
129 129 Pair<Boolean, RLock> pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 15);
  130 + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), "请勿重复提交");
130 131 try {
131   - BV.isTrue(Boolean.TRUE.equals(pair.getKey()), "请勿重复提交");
132 132 final String key = generateKey(groupId, type);
133 133 FollowSetting setting = settingService.getOne(Wrappers.<FollowSetting>lambdaQuery()
134 134 .eq(FollowSetting::getCategory, type)
... ... @@ -148,6 +148,9 @@ public abstract class AbstractSettingStrategy implements SettingStrategy {
148 148 detail.setSettingId(setting.getId());
149 149 detail.setId(settingDTO.getId());
150 150 detail.setDetailValue(settingDTO.getDetailValue());
  151 + if (SettingTypeEnum.REVISE_RATIO.getValue().equals(settingDTO.getType())) {
  152 + detail.setDetailValue(settingDTO.getDetailValue() * 100);
  153 + }
151 154 detail.setType(SettingTypeEnum.ofValue(settingDTO.getType()));
152 155 detail.setUnit(SettingUnitEnum.ofValue(settingDTO.getUnit()));
153 156 detail.setYn(Boolean.TRUE);
... ... @@ -263,6 +266,7 @@ public abstract class AbstractSettingStrategy implements SettingStrategy {
263 266  
264 267 /**
265 268 * 防重锁
  269 + *
266 270 * @param groupId
267 271 * @param type
268 272 * @return
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/CustomerService.java
... ... @@ -5,6 +5,8 @@ import cn.fw.valhalla.domain.db.customer.Customer;
5 5 import com.baomidou.mybatisplus.extension.service.IService;
6 6 import cn.fw.valhalla.domain.vo.customer.CustomerListVO;
7 7 import cn.fw.valhalla.domain.query.CustomerQueryVO;
  8 +import org.springframework.lang.NonNull;
  9 +import org.springframework.lang.Nullable;
8 10  
9 11 import java.util.List;
10 12  
... ... @@ -73,4 +75,12 @@ public interface CustomerService extends IService&lt;Customer&gt; {
73 75 * @param customerId
74 76 */
75 77 void forbiddenPlate(Long customerId);
  78 +
  79 + /**
  80 + * 查询服务顾问所有档案
  81 + * @param adviserId
  82 + * @return
  83 + */
  84 + @Nullable
  85 + List<Customer> queryByAdviserId(@NonNull Long adviserId);
76 86 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowRecordService.java
1 1 package cn.fw.valhalla.service.data;
2 2  
3 3 import cn.fw.valhalla.domain.db.follow.FollowRecord;
  4 +import cn.fw.valhalla.domain.enums.FollowTypeEnum;
4 5 import com.baomidou.mybatisplus.extension.service.IService;
5 6  
6 7 import java.util.List;
... ... @@ -51,4 +52,12 @@ public interface FollowRecordService extends IService&lt;FollowRecord&gt; {
51 52 * @return
52 53 */
53 54 boolean removeByTaskIds(List<Long> idList);
  55 +
  56 + /**
  57 + * 查询档案对应的跟进任务
  58 + * @param customerId
  59 + * @param list
  60 + * @return
  61 + */
  62 + List<FollowRecord> getRecordListByCustomer(final Long customerId, List<FollowTypeEnum> list);
54 63 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowTaskService.java
... ... @@ -2,6 +2,7 @@ package cn.fw.valhalla.service.data;
2 2  
3 3 import cn.fw.valhalla.domain.db.follow.FollowTask;
4 4 import cn.fw.valhalla.domain.dto.FollowPoolDTO;
  5 +import cn.fw.valhalla.domain.enums.FollowTypeEnum;
5 6 import cn.fw.valhalla.domain.query.FollowPoolQueryVO;
6 7 import com.baomidou.mybatisplus.extension.service.IService;
7 8  
... ... @@ -18,29 +19,25 @@ public interface FollowTaskService extends IService&lt;FollowTask&gt; {
18 19 * 根据档案id查询
19 20 *
20 21 * @param customerId
  22 + * @param list
21 23 * @return
22 24 */
23   - List<FollowTask> getWaitListByCustomerId(Long customerId);
24   -
25   - /**
26   - * 战败池查询
27   - *
28   - * @param queryVO
29   - * @return
30   - */
31   - List<FollowPoolDTO> defeatList(FollowPoolQueryVO queryVO);
  25 + List<FollowTask> getWaitListByCustomerId(Long customerId, List<FollowTypeEnum> list);
32 26  
33 27 /**
34 28 * 跟进池查询
  29 + *
35 30 * @param queryVO
36 31 * @return
37 32 */
38 33 List<FollowPoolDTO> followList(FollowPoolQueryVO queryVO);
39 34  
40 35 /**
41   - * 成交池查询
42   - * @param queryVO
  36 + * 查询客户所有的跟进信息
  37 + *
  38 + * @param customerId
  39 + * @param list
43 40 * @return
44 41 */
45   - List<FollowPoolDTO> completeList(FollowPoolQueryVO queryVO);
  42 + List<FollowTask> getListByCustomerId(Long customerId, List<FollowTypeEnum> list);
46 43 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/LeaveNeedDoService.java 0 → 100644
  1 +package cn.fw.valhalla.service.data;
  2 +
  3 +import cn.fw.valhalla.domain.db.LeaveNeedDo;
  4 +import com.baomidou.mybatisplus.extension.service.IService;
  5 +import org.springframework.lang.NonNull;
  6 +import org.springframework.lang.Nullable;
  7 +
  8 +/**
  9 + * @author : kurisu
  10 + * @className : LeaveNeedDoService
  11 + * @description : 人员变动待处理事件
  12 + * @date: 2020-10-16 17:02
  13 + */
  14 +public interface LeaveNeedDoService extends IService<LeaveNeedDo> {
  15 + /**
  16 + * 通过id查询可处理数据
  17 + *
  18 + * @param id
  19 + * @return
  20 + */
  21 + @Nullable
  22 + LeaveNeedDo queryProcessableById(@NonNull Long id);
  23 +
  24 + /**
  25 + * 处理数据
  26 + *
  27 + * @param id
  28 + */
  29 + void dealById(@NonNull Long id);
  30 +}
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/CustomerServiceImpl.java
... ... @@ -8,6 +8,8 @@ import cn.fw.valhalla.service.data.CustomerService;
8 8 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
9 9 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
10 10 import lombok.extern.slf4j.Slf4j;
  11 +import org.springframework.lang.NonNull;
  12 +import org.springframework.lang.Nullable;
11 13 import org.springframework.stereotype.Service;
12 14 import org.springframework.util.CollectionUtils;
13 15  
... ... @@ -80,4 +82,13 @@ public class CustomerServiceImpl extends ServiceImpl&lt;CustomerMapper, Customer&gt; i
80 82 updateById(customer);
81 83 }
82 84 }
  85 +
  86 + @Override
  87 + @Nullable
  88 + public List<Customer> queryByAdviserId(@NonNull Long adviserId) {
  89 + return this.list(Wrappers.<Customer>lambdaQuery()
  90 + .eq(Customer::getAdviserId, adviserId)
  91 + .eq(Customer::getYn, Boolean.TRUE)
  92 + );
  93 + }
83 94 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowRecordServiceImpl.java
... ... @@ -2,6 +2,7 @@ package cn.fw.valhalla.service.data.impl;
2 2  
3 3 import cn.fw.valhalla.dao.mapper.FollowRecordMapper;
4 4 import cn.fw.valhalla.domain.db.follow.FollowRecord;
  5 +import cn.fw.valhalla.domain.enums.FollowTypeEnum;
5 6 import cn.fw.valhalla.service.data.FollowRecordService;
6 7 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
7 8 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
... ... @@ -10,7 +11,9 @@ import lombok.extern.slf4j.Slf4j;
10 11 import org.springframework.stereotype.Service;
11 12 import org.springframework.transaction.annotation.Transactional;
12 13  
  14 +import java.util.ArrayList;
13 15 import java.util.List;
  16 +import java.util.Optional;
14 17  
15 18 /**
16 19 * @author : kurisu
... ... @@ -72,4 +75,14 @@ public class FollowRecordServiceImpl extends ServiceImpl&lt;FollowRecordMapper, Fol
72 75 .isNull(FollowRecord::getFollowTime)
73 76 );
74 77 }
  78 +
  79 + @Override
  80 + public List<FollowRecord> getRecordListByCustomer(Long customerId, List<FollowTypeEnum> list) {
  81 + return Optional.ofNullable(list(Wrappers.<FollowRecord>lambdaQuery()
  82 + .eq(FollowRecord::getCustomerId, customerId)
  83 + .eq(FollowRecord::getOutTime, Boolean.FALSE)
  84 + .eq(FollowRecord::getAddTodo, Boolean.FALSE)
  85 + .in(!CollectionUtils.isEmpty(list), FollowRecord::getType, list)
  86 + )).orElse(new ArrayList<>());
  87 + }
75 88 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowTaskServiceImpl.java
... ... @@ -11,8 +11,10 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
11 11 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
12 12 import lombok.extern.slf4j.Slf4j;
13 13 import org.springframework.stereotype.Service;
  14 +import org.springframework.util.CollectionUtils;
14 15  
15 16 import java.util.ArrayList;
  17 +import java.util.Arrays;
16 18 import java.util.List;
17 19 import java.util.Optional;
18 20  
... ... @@ -26,24 +28,16 @@ import java.util.Optional;
26 28 @Slf4j
27 29 public class FollowTaskServiceImpl extends ServiceImpl<FollowTaskMapper, FollowTask> implements FollowTaskService {
28 30 @Override
29   - public List<FollowTask> getWaitListByCustomerId(Long customerId) {
  31 + public List<FollowTask> getWaitListByCustomerId(Long customerId, List<FollowTypeEnum> list) {
30 32 return Optional.ofNullable(list(Wrappers.<FollowTask>lambdaQuery()
31 33 .eq(FollowTask::getCustomerId, customerId)
32 34 .eq(FollowTask::getFinished, Boolean.FALSE)
33 35 .eq(FollowTask::getState, TaskStateEnum.WAITING)
34   - .ne(FollowTask::getType, FollowTypeEnum.IR)
  36 + .in(!CollectionUtils.isEmpty(list), FollowTask::getType, list)
35 37 )).orElse(new ArrayList<>());
36 38 }
37 39  
38 40 @Override
39   - public List<FollowPoolDTO> defeatList(FollowPoolQueryVO queryVO) {
40   - Integer current = queryVO.getCurrent();
41   - Integer pageSize = queryVO.getPageSize();
42   - Integer startIndex = (current-1) * pageSize;
43   - return Optional.ofNullable(getBaseMapper().defeatList(startIndex, pageSize, queryVO)).orElse(new ArrayList<>());
44   - }
45   -
46   - @Override
47 41 public List<FollowPoolDTO> followList(FollowPoolQueryVO queryVO) {
48 42 Integer current = queryVO.getCurrent();
49 43 Integer pageSize = queryVO.getPageSize();
... ... @@ -52,10 +46,12 @@ public class FollowTaskServiceImpl extends ServiceImpl&lt;FollowTaskMapper, FollowT
52 46 }
53 47  
54 48 @Override
55   - public List<FollowPoolDTO> completeList(FollowPoolQueryVO queryVO) {
56   - Integer current = queryVO.getCurrent();
57   - Integer pageSize = queryVO.getPageSize();
58   - Integer startIndex = (current-1) * pageSize;
59   - return Optional.ofNullable(getBaseMapper().completeList(startIndex, pageSize, queryVO)).orElse(new ArrayList<>());
  49 + public List<FollowTask> getListByCustomerId(Long customerId, List<FollowTypeEnum> list) {
  50 + return Optional.ofNullable(list(Wrappers.<FollowTask>lambdaQuery()
  51 + .eq(FollowTask::getCustomerId, customerId)
  52 + .eq(FollowTask::getFinished, Boolean.FALSE)
  53 + .ne(FollowTask::getState, TaskStateEnum.END)
  54 + .in(!CollectionUtils.isEmpty(list), FollowTask::getType, list)
  55 + )).orElse(new ArrayList<>());
60 56 }
61 57 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/LeaveNeedDoServiceImpl.java 0 → 100644
  1 +package cn.fw.valhalla.service.data.impl;
  2 +
  3 +import cn.fw.valhalla.dao.mapper.LeaveNeedDoMapper;
  4 +import cn.fw.valhalla.domain.db.LeaveNeedDo;
  5 +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum;
  6 +import cn.fw.valhalla.service.data.LeaveNeedDoService;
  7 +import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  8 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.lang.NonNull;
  11 +import org.springframework.lang.Nullable;
  12 +import org.springframework.stereotype.Service;
  13 +import org.springframework.util.CollectionUtils;
  14 +
  15 +import java.util.List;
  16 +
  17 +/**
  18 + * @author : kurisu
  19 + * @className : LeaveNeedDoServiceImpl
  20 + * @description : 人员变动待处理事件
  21 + * @date: 2020-08-12 11:05
  22 + */
  23 +@Service
  24 +@Slf4j
  25 +public class LeaveNeedDoServiceImpl extends ServiceImpl<LeaveNeedDoMapper, LeaveNeedDo> implements LeaveNeedDoService {
  26 +
  27 + @Override
  28 + @Nullable
  29 + public LeaveNeedDo queryProcessableById(@NonNull Long id) {
  30 + List<LeaveNeedDo> list = list(Wrappers.<LeaveNeedDo>lambdaQuery()
  31 + .eq(LeaveNeedDo::getId, id)
  32 + .eq(LeaveNeedDo::getDone, Boolean.FALSE)
  33 + .eq(LeaveNeedDo::getType, LeaveTodoTypeEnum.CUSTOMER)
  34 + );
  35 + if (CollectionUtils.isEmpty(list)) {
  36 + return null;
  37 + }
  38 + return list.get(0);
  39 + }
  40 +
  41 + @Override
  42 + public void dealById(@NonNull Long id) {
  43 + update(Wrappers.<LeaveNeedDo>lambdaUpdate()
  44 + .set(LeaveNeedDo::getDone, Boolean.TRUE)
  45 + .eq(LeaveNeedDo::getId, id)
  46 + );
  47 + }
  48 +}
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/event/CancelApproveEvent.java 0 → 100644
  1 +package cn.fw.valhalla.service.event;
  2 +
  3 +import cn.fw.valhalla.domain.enums.ApproveTypeEnum;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +
  7 +/**
  8 + * @author : kurisu
  9 + * @className : CancelApproveEvent
  10 + * @description : 取消审批事件
  11 + * @date: 2020-10-15 17:26
  12 + */
  13 +@Data
  14 +@AllArgsConstructor
  15 +public class CancelApproveEvent {
  16 + private Long taskId;
  17 + private ApproveTypeEnum typeEnum;
  18 +}
... ...