Commit 364db3cc508d4797829ca51afb36214f47b60dbd

Authored by 张志伟
1 parent 073324d4

:sparkles: feature(*): 公共池跟进逻辑

- 公共池跟进逻辑
Showing 19 changed files with 509 additions and 85 deletions
doc/v2.0/update.sql
... ... @@ -2,6 +2,47 @@ drop table if exists customer_clue_pool;
2 2  
3 3 drop table if exists follow_task;
4 4  
  5 +# 续保跟进模式
  6 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  7 + create_time, update_time)
  8 +VALUES (4, -1, 99, 1, 11, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  9 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  10 + create_time, update_time)
  11 +VALUES (8, -1, 99, 1, 11, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  12 +
  13 +# 统一设置待办时长[事故车除外]
  14 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  15 + create_time, update_time)
  16 +VALUES (9, -1, 2, 36, 3, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  17 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  18 + create_time, update_time)
  19 +VALUES (10, -1, 2, 36, 3, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  20 +
  21 +# 转换率最低要求
  22 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  23 + create_time, update_time)
  24 +VALUES (9, -1, 13, 2000, 9, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  25 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  26 + create_time, update_time)
  27 +VALUES (10, -1, 13, 2000, 9, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  28 +
  29 +# 公共池线索初始值
  30 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  31 + create_time, update_time)
  32 +VALUES (9, -1, 14, 50, 10, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  33 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  34 + create_time, update_time)
  35 +VALUES (10, -1, 14, 50, 10, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  36 +
  37 +
  38 +# 公共池线索增量
  39 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  40 + create_time, update_time)
  41 +VALUES (9, -1, 15, 10, 10, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  42 +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
  43 + create_time, update_time)
  44 +VALUES (10, -1, 15, 10, 10, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32');
  45 +
5 46  
6 47 CREATE TABLE IF NOT EXISTS fw_valhalla.pub_stand_staff_info
7 48 (
... ... @@ -16,13 +57,14 @@ CREATE TABLE IF NOT EXISTS fw_valhalla.pub_stand_staff_info
16 57 id_code varchar(255) null comment '识别码 站岗类型为公共池类型时为空',
17 58 stand_rang int(3) not null comment '站岗范围 1:本门店范围 2:区域范围',
18 59 reason_of_no_lining varchar(255) null comment '不在队列原因',
  60 + area_code varchar(16) not null comment '门店区域码',
19 61 shop_id bigint not null comment '门店id',
20 62 shop_name varchar(255) null comment '门店名称',
21 63 group_id bigint not null comment '集团id',
22 64 create_time datetime not null,
23 65 update_time datetime null,
24 66 constraint pub_stand_staff_info_staff_id_group_id_uindex
25   - unique (staff_id,group_id) comment '集团用户'
  67 + unique (staff_id, group_id) comment '集团用户'
26 68 )
27 69 comment '公共池站岗配置';
28 70  
... ... @@ -38,4 +80,54 @@ where t1.vin is null
38 80 and t2.id = t1.customer_id;
39 81  
40 82 alter table public_clue_pool
41   - modify vin varchar(128) not null comment '车架号'
42 83 \ No newline at end of file
  84 + modify vin varchar(128) not null comment '车架号';
  85 +
  86 +
  87 +# 公共池数据表调整
  88 +update public_pool t1, customer t2
  89 +set t1.frame_no = ifnull(t2.frame_no, '')
  90 +where t1.frame_no is null
  91 + and t2.yn = 1
  92 + and t2.id = t1.customer_id;
  93 +
  94 +update public_pool t1
  95 +set t1.frame_no = concat_ws('-', t1.plate_no, t1.customer_id)
  96 +where t1.frame_no is null;
  97 +
  98 +alter table public_pool
  99 + modify frame_no varchar(64) not null comment '车架号';
  100 +
  101 +alter table public_pool
  102 + modify plate_no varchar(32) null comment '车牌号';
  103 +
  104 +alter table public_pool
  105 + modify shop_id bigint not null comment '最后所在服务站';
  106 +
  107 +alter table public_pool
  108 + modify shop_name varchar(128) null comment '最后所在服务站名';
  109 +
  110 +create unique index public_pool_frame_no_group_id_uindex
  111 + on public_pool (frame_no, group_id);
  112 +
  113 +
  114 +create table if not exists fw_valhalla.pub_clue_pool
  115 +(
  116 + id bigint auto_increment
  117 + primary key,
  118 + vin varchar(128) not null comment '车架号',
  119 + start_time datetime not null comment '开始时间',
  120 + deadline datetime not null comment '转换截止时间',
  121 + close_time datetime null comment '关闭时间',
  122 + state int(3) not null comment '状态: 1、转换中 2、已转换 3、转换失败',
  123 + adviser_id bigint not null comment '顾问id',
  124 + adviser_name varchar(32) null comment '顾问名称',
  125 + shop_id bigint not null comment '门店id',
  126 + shop_name varchar(128) null comment '门店名称',
  127 + group_id bigint not null comment '集团id',
  128 + create_time datetime null,
  129 + update_time datetime null,
  130 + constraint pub_clue_pool_customer_id_adviser_id_uindex
  131 + unique (vin, adviser_id)
  132 +)
  133 + comment '公共池线索跟进池';
  134 +
... ...
fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/PublicPoolMapper.java
... ... @@ -34,4 +34,11 @@ public interface PublicPoolMapper extends BaseMapper<PublicPool> {
34 34 * @return
35 35 */
36 36 Long publicListCount(@Param("condition") PublicPoolQueryVO queryVO);
  37 +
  38 + /**
  39 + * 根据门店列表查询vin
  40 + * @param shopIds
  41 + * @return
  42 + */
  43 + List<String> queryIdListByShops(@Param("shopIds") List<Long> shopIds);
37 44 }
... ...
fw-valhalla-dao/src/main/resources/mapper/PublicPoolMapper.xml
... ... @@ -6,26 +6,26 @@
6 6 resultType="cn.fw.valhalla.domain.dto.PublicPoolDTO"
7 7 parameterType="cn.fw.valhalla.domain.query.PublicPoolQueryVO"
8 8 >
9   - SELECT t1.id id,
10   - t1.customer_id customer_id,
  9 + SELECT t1.id id,
  10 + t1.customer_id customer_id,
11 11 t1.customer_name customer_name,
12   - t1.frame_no frame_no,
13   - t1.plate_no plate_no,
14   - t1.brand_id brand_id,
15   - t1.brand_name brand_name,
16   - t1.series_id series_id,
17   - t1.series_name series_name,
18   - t1.spec_id spec_id,
19   - t1.spec_name spec_name,
20   - t1.address address,
21   - t1.company company,
22   - t1.type type,
23   - t1.shop_id shop_id,
24   - t1.shop_name shop_name,
25   - t1.times times,
26   - t1.reason reason,
27   - t1.group_id group_id,
28   - t2.tags tags
  12 + t1.frame_no frame_no,
  13 + t1.plate_no plate_no,
  14 + t1.brand_id brand_id,
  15 + t1.brand_name brand_name,
  16 + t1.series_id series_id,
  17 + t1.series_name series_name,
  18 + t1.spec_id spec_id,
  19 + t1.spec_name spec_name,
  20 + t1.address address,
  21 + t1.company company,
  22 + t1.type type,
  23 + t1.shop_id shop_id,
  24 + t1.shop_name shop_name,
  25 + t1.times times,
  26 + t1.reason reason,
  27 + t1.group_id group_id,
  28 + t2.tags tags
29 29 FROM public_pool t1
30 30 left join customer t2 on t1.customer_id = t2.id
31 31 <where>
... ... @@ -52,7 +52,7 @@
52 52 and t1.type = #{condition.type}
53 53 </if>
54 54 <if test="condition.shopIds !=null">
55   - and t1.shop_id in
  55 + and t1.shop_id in
56 56 <foreach collection="condition.shopIds" item="id" index="index" open="(" close=")" separator=",">
57 57 #{id}
58 58 </foreach>
... ... @@ -61,7 +61,7 @@
61 61 and t1.shop_name like concat('%', #{condition.shopName}, '%')
62 62 </if>
63 63 <if test="condition.ignoreCustIds !=null">
64   - and t1.customer_id not in
  64 + and t1.customer_id not in
65 65 <foreach collection="condition.ignoreCustIds" item="id" index="index" open="(" close=")" separator=",">
66 66 #{id}
67 67 </foreach>
... ... @@ -121,7 +121,7 @@
121 121 and t1.type = #{condition.type}
122 122 </if>
123 123 <if test="condition.shopIds !=null">
124   - and t1.shop_id in
  124 + and t1.shop_id in
125 125 <foreach collection="condition.shopIds" item="id" index="index" open="(" close=")" separator=",">
126 126 #{id}
127 127 </foreach>
... ... @@ -130,7 +130,7 @@
130 130 and t1.shop_name like concat('%', #{condition.shopName}, '%')
131 131 </if>
132 132 <if test="condition.ignoreCustIds !=null">
133   - and t1.customer_id not in
  133 + and t1.customer_id not in
134 134 <foreach collection="condition.ignoreCustIds" item="id" index="index" open="(" close=")" separator=",">
135 135 #{id}
136 136 </foreach>
... ... @@ -149,4 +149,20 @@
149 149 </if>
150 150 </where>
151 151 </select>
  152 +
  153 + <select
  154 + id="queryIdListByShops"
  155 + resultType="java.lang.String"
  156 + >
  157 + SELECT frame_no
  158 + FROM public_pool
  159 + <where>
  160 + <if test="shopIds !=null">
  161 + shop_id in
  162 + <foreach collection="shopIds" item="id" index="index" open="(" close=")" separator=",">
  163 + #{id}
  164 + </foreach>
  165 + </if>
  166 + </where>
  167 + </select>
152 168 </mapper>
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/pub/PubStandStaffInfo.java
... ... @@ -51,6 +51,10 @@ public class PubStandStaffInfo extends BaseAuditableTimeEntity&lt;PubStandStaffInfo
51 51 */
52 52 private String reasonOfNoLining;
53 53 /**
  54 + * 门店地区编号
  55 + */
  56 + private String areaCode;
  57 + /**
54 58 * 门店id
55 59 */
56 60 private Long shopId;
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/FollowTypeEnum.java
... ... @@ -29,8 +29,12 @@ public enum FollowTypeEnum implements IEnum&lt;Integer&gt; {
29 29 */
30 30 IR(4, "续保"),
31 31 /**
  32 + * 公共池跟进
  33 + */
  34 + PL(10, "公共池"),
  35 + /**
32 36 * 其他
33   - * 目前只用于设置,并不参与具体跟进业务
  37 + * 配置通用设置
34 38 */
35 39 OT(99, "其他"),
36 40 ;
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingTypeEnum.java
... ... @@ -61,6 +61,13 @@ public enum SettingTypeEnum implements IEnum&lt;Integer&gt; {
61 61 * 公共客户线索池保留最大时长
62 62 */
63 63 PUBLIC_VALID_DAY(12, "公共客户线索池保留时间", 11),
  64 + /**
  65 + * 公共客户线索最低转换率
  66 + */
  67 + MINIMUM_CONVERSION_RATE(13, "公共客户线索最低转换率", 12),
  68 + MINIMUM_CLUE_COUNT(14, "公共客户线索分配初始数", 13),
  69 + INCREASE_COUNT(15, "公共客户线增量数", 14),
  70 + MODE(99, "续保跟进模式", 1000),
64 71 ;
65 72  
66 73 /**
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingUnitEnum.java
... ... @@ -36,6 +36,11 @@ public enum SettingUnitEnum implements IEnum&lt;Integer&gt; {
36 36 * 百分比
37 37 */
38 38 RATIO(9, "%"),
  39 + /**
  40 + * 数量
  41 + */
  42 + QUANTITY(10, "个"),
  43 + UNAPPLICABLE(11, "不适用"),
39 44 ;
40 45  
41 46 /**
... ...
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/erp/UserService.java
... ... @@ -17,11 +17,9 @@ import org.springframework.stereotype.Service;
17 17 import org.springframework.util.Assert;
18 18 import org.springframework.util.CollectionUtils;
19 19  
20   -import java.util.ArrayList;
21   -import java.util.Collections;
22   -import java.util.List;
23   -import java.util.Objects;
  20 +import java.util.*;
24 21 import java.util.concurrent.TimeUnit;
  22 +import java.util.stream.Collectors;
25 23  
26 24 /**
27 25 * 用户服务
... ... @@ -121,6 +119,43 @@ public class UserService extends AbsBaseRpcService {
121 119 return Collections.emptyList();
122 120 }
123 121  
  122 + /**
  123 + * 门店内拥有多个角色的人员
  124 + * @param shopId
  125 + * @param roleCode
  126 + * @return
  127 + */
  128 + public List<PostUserDTO> getShopRolesUser(Long shopId, String... roleCode) {
  129 + if (roleCode.length == 0 || Objects.isNull(shopId)) {
  130 + return Collections.emptyList();
  131 + }
  132 + String key = generateKey(shopId, String.join(",", roleCode));
  133 + List<PostUserDTO> dtos = getListFromCache(key, PostUserDTO.class);
  134 + if (!CollectionUtils.isEmpty(dtos)) {
  135 + return dtos;
  136 + }
  137 + try {
  138 + List<String> roleCodeList = Arrays.stream(roleCode).collect(Collectors.toList());
  139 + Message<List<UserRoleInfo>> msg = userRoleApi.queryRoleUsers(roleCodeList, shopId);
  140 + List<UserRoleInfo> userRoleInfos = msg.getData();
  141 + if (!msg.isSuccess() || CollectionUtils.isEmpty(userRoleInfos)) {
  142 + return Collections.emptyList();
  143 + }
  144 + List<PostUserDTO> list = new ArrayList<>(userRoleInfos.size());
  145 + for (UserRoleInfo datum : userRoleInfos) {
  146 + PostUserDTO dto = new PostUserDTO();
  147 + BeanUtils.copyProperties(datum, dto);
  148 + list.add(dto);
  149 + setListToCache(key, JSONObject.toJSONString(dto));
  150 + }
  151 + getQueue(key).expire(10, TimeUnit.MINUTES);
  152 + return list;
  153 + } catch (Exception e) {
  154 + e.printStackTrace();
  155 + }
  156 + return Collections.emptyList();
  157 + }
  158 +
124 159 private String generateKey(final Long shopId, final String roleCOde) {
125 160 Assert.notNull(shopId, "id cannot be null");
126 161 Assert.hasLength(roleCOde, "roleCOde cannot be null");
... ...
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/oop/OopService.java
... ... @@ -185,6 +185,31 @@ public class OopService extends AbsBaseRpcService {
185 185 }
186 186  
187 187 /**
  188 + * 根据区域code查询该地区门店列表
  189 + * @param areaCode
  190 + * @return
  191 + */
  192 + public List<ShopDTO> areaShops(final String areaCode) {
  193 + if (StringUtils.isEmpty(areaCode)) {
  194 + return Collections.emptyList();
  195 + }
  196 +// try {
  197 +// Message<List<ShopInfoVo>> msg = shopApiService.getShopInfoList(new ArrayList<>());
  198 +// if (!msg.isSuccess() || CollectionUtils.isEmpty(msg.getData())) {
  199 +// return Collections.emptyList();
  200 +// }
  201 +// return msg.getData().stream().map(item -> {
  202 +// final ShopDTO shop = new ShopDTO();
  203 +// BeanUtils.copyProperties(item, shop);
  204 +// return shop;
  205 +// }).collect(Collectors.toList());
  206 +// } catch (Exception e) {
  207 +// e.printStackTrace();
  208 +// }
  209 + return Collections.emptyList();
  210 + }
  211 +
  212 + /**
188 213 * 根据ID获取商家信息
189 214 *
190 215 * @param dealerId 商家ID
... ...
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/shirasawa/ShirasawaRpcService.java
... ... @@ -115,10 +115,10 @@ public class ShirasawaRpcService {
115 115 * @param userId
116 116 * @return
117 117 */
118   - public boolean hasOngoingFollow(Long userId) {
  118 + public Boolean hasOngoingFollow(Long userId) {
119 119 try {
120 120 if (Objects.isNull(userId)) {
121   - return true;
  121 + return null;
122 122 }
123 123 Message<Long> message = followApiService.queryRecordRemaining(userId, BusinessTypeEnum.AS.getValue());
124 124 log.info("followApiService.queryRecordRemaining: msg.code={}, msg.result={}", message.getCode(), message.getResult());
... ... @@ -129,6 +129,6 @@ public class ShirasawaRpcService {
129 129 } catch (Exception e) {
130 130 log.error("查询未完成的待办失败。userId: [{}]", userId, e);
131 131 }
132   - return true;
  132 + return null;
133 133 }
134 134 }
... ...
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/task/PubStandTask.java
... ... @@ -71,7 +71,7 @@ public class PubStandTask {
71 71 while ((id = ops.leftPop()) != null) {
72 72 if (StringUtils.isNumber(id)) {
73 73 try {
74   - Boolean distributed = pubDistributeBizService.distribute(Long.valueOf(id));
  74 + Boolean distributed = pubDistributeBizService.distribute(Long.parseLong(id));
75 75 if (!Boolean.TRUE.equals(distributed)) {
76 76 failList.add(id);
77 77 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java
... ... @@ -349,13 +349,13 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
349 349 @Override
350 350 @Transactional(rollbackFor = Exception.class)
351 351 public void createNextFollowTodo(FollowClue clue) {
352   - FollowTypeEnum clueType = clue.getClueType();
353 352 Long brandId = COMMON_BRAND_ID;
354 353 Customer customer = customerService.queryByFrameNo(clue.getVin(), clue.getGroupId());
355 354 if (Objects.nonNull(customer)) {
356 355 brandId = customer.getBrandId();
357 356 }
358   - SettingVO efsetting = settingBizService.querySettingByType(clueType, SettingTypeEnum.EFFECTIVE_TIME, clue.getGroupId(), brandId).orElse(null);
  357 + // 除事故车以外,其他待办跟进时长统一配置
  358 + SettingVO efsetting = settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.EFFECTIVE_TIME, clue.getGroupId(), brandId).orElse(null);
359 359 BV.notNull(efsetting, () -> MessageFormatUtil.MessageFormatTransfer("关键设置数据异常,请检查数据: settingType: {0} groupId: {1}", SettingTypeEnum.EFFECTIVE_TIME.getName(), clue.getGroupId()));
360 360  
361 361 ClueTask clueTask = clueTaskService.queryOngoingTaskByClueId(clue.getId());
... ... @@ -629,7 +629,8 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
629 629 if (Objects.nonNull(shop)) {
630 630 followInitDTO.setShopName(shop.getShopName());
631 631 }
632   - settingBizService.querySettingByType(clueTask.getType(), SettingTypeEnum.EFFECTIVE_TIME, clueTask.getGroupId(), brandId)
  632 + // 除事故车以外,其他待办跟进时长统一配置
  633 + settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.EFFECTIVE_TIME, clueTask.getGroupId(), brandId)
633 634 .ifPresent(r -> {
634 635 LocalDateTime dateTime = calTime(clueTask.getBeginTime(), Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit())), r.getDetailValue());
635 636 followInitDTO.setFirstRecordDeadline(DateUtil.localDateTime2Date(dateTime.minusSeconds(1L)));
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java
... ... @@ -8,6 +8,7 @@ import cn.fw.valhalla.domain.db.follow.ClueTask;
8 8 import cn.fw.valhalla.domain.db.follow.FollowClue;
9 9 import cn.fw.valhalla.domain.dto.CustomerDetailDto;
10 10 import cn.fw.valhalla.domain.enums.*;
  11 +import cn.fw.valhalla.domain.vo.setting.SettingVO;
11 12 import cn.fw.valhalla.rpc.erp.dto.PostUserDTO;
12 13 import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
13 14 import cn.fw.valhalla.rpc.shirasawa.dto.FollowInitDTO;
... ... @@ -26,6 +27,7 @@ import java.util.*;
26 27 import java.util.stream.Collectors;
27 28  
28 29 import static cn.fw.common.businessvalidator.Validator.BV;
  30 +import static cn.fw.valhalla.service.bus.setting.strategy.SettingStrategy.COMMON_BRAND_ID;
29 31  
30 32 /**
31 33 * @author : kurisu
... ... @@ -86,10 +88,18 @@ public class IRFollowStrategy extends AbstractFollowStrategy {
86 88 followClueService.removeById(followClue.getId());
87 89 return;
88 90 }
  91 + Optional<SettingVO> settingVO = settingBizService.querySettingByType(getFollowType(), SettingTypeEnum.MODE, followClue.getGroupId(), COMMON_BRAND_ID);
  92 + // 模式 1、续保角色 2、续保角色+服务接待/新车销售
  93 + final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1);
89 94 followClue.setPlateNo(customer.getPlateNo());
90 95 final ClueTask clueTask = createNewTask(followClue);
91   - List<PostUserDTO> userByRole = userService.getUserByRole(clueTask.getFollowShop(), RoleCode.XBGJ);
92   - BV.isNotEmpty(userByRole, () -> "该门店没有【续保跟进】人员");
  96 + List<PostUserDTO> userByRole = new ArrayList<>();
  97 + if (mode == 1) {
  98 + userByRole = userService.getShopRolesUser(clueTask.getFollowShop(), RoleCode.XBGJ);
  99 + } else {
  100 + userByRole = userService.getShopRolesUser(clueTask.getFollowShop(), RoleCode.XBGJ, RoleCode.FWGW);
  101 + }
  102 + BV.isNotEmpty(userByRole, () -> String.format("该门店[mode: %s]没有【跟进】人员", mode));
93 103 fillTaskUser(clueTask, userByRole);
94 104 clueTaskService.save(clueTask);
95 105 followClue.setClueState(ClueStatusEnum.ONGOING);
... ... @@ -238,7 +248,7 @@ public class IRFollowStrategy extends AbstractFollowStrategy {
238 248 redistributionTask.setCloseTime(null);
239 249 redistributionTask.setFinishUserName(null);
240 250 redistributionTask.setReason(null);
241   - redistributionTask.setRpcSuccess(Boolean.FALSE);
  251 + redistributionTask.setRpcSuccess(Boolean.FALSE);// todo 销售顾问跟进的场景
242 252 List<PostUserDTO> userByRole = userService.getUserByRole(oldTask.getFollowShop(), RoleCode.XBGJ);
243 253 BV.isNotEmpty(userByRole, () -> "该门店没有【续保跟进】人员");
244 254 List<PostUserDTO> newUserRole = userByRole.stream().filter(userDTO -> !userDTO.getUserId().equals(oldTask.getFollowUser())).collect(Collectors.toList());
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubDistributeBizService.java 0 → 100644
  1 +package cn.fw.valhalla.service.bus.pub;
  2 +
  3 +import cn.fw.valhalla.domain.db.customer.Customer;
  4 +import cn.fw.valhalla.domain.db.pub.PubStandStaffInfo;
  5 +import cn.fw.valhalla.domain.enums.PubStandRang;
  6 +import cn.fw.valhalla.domain.enums.PubStandType;
  7 +import cn.fw.valhalla.rpc.ehr.EhrRpcService;
  8 +import cn.fw.valhalla.rpc.oop.OopService;
  9 +import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
  10 +import cn.fw.valhalla.rpc.shirasawa.ShirasawaRpcService;
  11 +import cn.fw.valhalla.service.data.CustomerService;
  12 +import cn.fw.valhalla.service.data.PubStandStaffInfoService;
  13 +import cn.fw.valhalla.service.data.PublicPoolService;
  14 +import cn.hutool.core.collection.ListUtil;
  15 +import lombok.RequiredArgsConstructor;
  16 +import lombok.extern.slf4j.Slf4j;
  17 +import org.springframework.stereotype.Service;
  18 +import org.springframework.transaction.annotation.Transactional;
  19 +import org.springframework.util.CollectionUtils;
  20 +import org.springframework.util.StringUtils;
  21 +
  22 +import java.util.List;
  23 +import java.util.Objects;
  24 +import java.util.Optional;
  25 +import java.util.stream.Collectors;
  26 +
  27 +/**
  28 + * 公共池站岗分配
  29 + *
  30 + * @author : kurisu
  31 + * @version : 1.0
  32 + * @className : PubDBizService
  33 + * @description : 公共池站岗分配
  34 + * @date : 2023-03-11 15:55
  35 + */
  36 +@RequiredArgsConstructor
  37 +@Service
  38 +@Slf4j
  39 +public class PubDistributeBizService {
  40 + private final EhrRpcService ehrRpcService;
  41 + private final OopService oopService;
  42 + private final ShirasawaRpcService shirasawaRpcService;
  43 + private final PublicPoolService publicPoolService;
  44 + private final CustomerService customerService;
  45 + private final PubStandStaffInfoService pubStandStaffInfoService;
  46 +
  47 + /**
  48 + * 分配
  49 + *
  50 + * @param id
  51 + * @return
  52 + */
  53 + @Transactional(rollbackFor = Exception.class)
  54 + public Boolean distribute(Long id) {
  55 + PubStandStaffInfo staffInfo = pubStandStaffInfoService.getById(id);
  56 + if (Objects.isNull(staffInfo)) {
  57 + return true;
  58 + }
  59 + if (staffInfo.getNoInvolved() || !staffInfo.getLining()) {
  60 + return true;
  61 + }
  62 + Boolean checked = checkStaff(staffInfo);
  63 + if (null == checked) {
  64 + return false;
  65 + } else if (!checked) {
  66 + return true;
  67 + }
  68 + List<Long> list = getShopIds(staffInfo);
  69 + if (CollectionUtils.isEmpty(list)) {
  70 + return false;
  71 + }
  72 + List<String> vinList = publicPoolService.queryIdListByShops(list);
  73 + if (CollectionUtils.isEmpty(vinList)) {
  74 + return false;
  75 + }
  76 + String vin = getBeDistributeVin(staffInfo, vinList);
  77 + if (StringUtils.isEmpty(vin)) {
  78 + return false;
  79 + }
  80 + return createClue(vin, staffInfo);
  81 + }
  82 +
  83 + /**
  84 + * 检查人员状态
  85 + *
  86 + * @return
  87 + */
  88 + public Boolean checkStaff(PubStandStaffInfo staffInfo) {
  89 + Boolean aBoolean = shirasawaRpcService.hasOngoingFollow(staffInfo.getStaffId());
  90 + if (null == aBoolean) {
  91 + return null;
  92 + }
  93 + if (Boolean.TRUE.equals(aBoolean)) {
  94 + staffInfo.setLining(false);
  95 + staffInfo.setReasonOfNoLining("有未完成的跟进待办");
  96 + pubStandStaffInfoService.updateById(staffInfo);
  97 + return false;
  98 + }
  99 + return true;
  100 + }
  101 +
  102 + /**
  103 + * 查询门店
  104 + *
  105 + * @param staffInfo
  106 + * @return
  107 + */
  108 + private List<Long> getShopIds(final PubStandStaffInfo staffInfo) {
  109 + List<Long> shopIdList = ListUtil.toList();
  110 + PubStandRang standRang = Optional.ofNullable(staffInfo.getStandRang()).orElse(PubStandRang.SHOP);
  111 + switch (standRang) {
  112 + case SHOP:
  113 + shopIdList = ListUtil.toList(staffInfo.getShopId());
  114 + break;
  115 + case AREA:
  116 + shopIdList = oopService.areaShops(staffInfo.getAreaCode())
  117 + .stream().map(ShopDTO::getId)
  118 + .filter(r -> !r.equals(staffInfo.getShopId()))
  119 + .collect(Collectors.toList());
  120 + break;
  121 + default:
  122 + break;
  123 + }
  124 + return shopIdList;
  125 + }
  126 +
  127 + /**
  128 + * 分配给人员 档案
  129 + *
  130 + * @param staffInfo
  131 + * @param vinList
  132 + * @return
  133 + */
  134 + private String getBeDistributeVin(PubStandStaffInfo staffInfo, List<String> vinList) {
  135 + String vin = null;
  136 + PubStandType standType = Optional.ofNullable(staffInfo.getStandType()).orElse(PubStandType.PUB);
  137 + switch (standType) {
  138 + case PUB:
  139 + vin = vinList.get(0);
  140 + break;
  141 + case ACTIVITY:
  142 + vin = determineMkt(vinList, staffInfo);
  143 + break;
  144 + default:
  145 + break;
  146 + }
  147 + return vin;
  148 + }
  149 +
  150 + /**
  151 + * 查询档案用户能否参与活动
  152 + *
  153 + * @param vinList
  154 + * @param staffInfo
  155 + * @return
  156 + */
  157 + private String determineMkt(List<String> vinList, PubStandStaffInfo staffInfo) {
  158 + for (String vin : vinList) {
  159 + // todo: 查询活动判断能否参与
  160 + if (!vin.isEmpty()) {
  161 + return vin;
  162 + }
  163 + }
  164 + return null;
  165 + }
  166 +
  167 + /**
  168 + * 创建线索和分配记录
  169 + * @param vin
  170 + * @param staffInfo
  171 + * @return
  172 + */
  173 + public boolean createClue(String vin, PubStandStaffInfo staffInfo) {
  174 + // TODO: 2023/3/17 创建线索
  175 + Customer customer = customerService.queryByFrameNo(vin, staffInfo.getGroupId());
  176 + if (Objects.isNull(customer)) {
  177 + publicPoolService.removeByVin(vin, staffInfo.getGroupId());
  178 + return false;
  179 + }
  180 + return true;
  181 + }
  182 +}
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubDistributeBizService.kt deleted
1   -package cn.fw.valhalla.service.bus.pub;
2   -
3   -import cn.fw.valhalla.domain.db.pub.PubStandStaffInfo
4   -import cn.fw.valhalla.rpc.ehr.EhrRpcService
5   -import cn.fw.valhalla.service.data.PubStandStaffInfoService
6   -import lombok.extern.slf4j.Slf4j
7   -import org.springframework.stereotype.Service
8   -
9   -/**
10   - * 公共池站岗分配
11   - *
12   - * @author : kurisu
13   - * @version : 1.0
14   - * @className : PubDBizService
15   - * @description : 公共池站岗分配
16   - * @date : 2023-03-11 15:55
17   - */
18   -@Service
19   -@Slf4j
20   -class PubDistributeBizService(
21   - private val ehrRpcService: EhrRpcService,
22   - private val pubStandStaffInfoService: PubStandStaffInfoService
23   -) {
24   -
25   - /**
26   - * 执行分配
27   - *
28   - * @param id
29   - */
30   - fun distribute(id: Long): Boolean {
31   - val staffInfo: PubStandStaffInfo = pubStandStaffInfoService.getById(id) ?: return true
32   - if (staffInfo.noInvolved || !staffInfo.lining) {
33   - return true
34   - }
35   -
36   - // TODO: 2023/3/15 分配
37   - return true;
38   - }
39   -
40   -}
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubFollowBizService.java 0 → 100644
  1 +package cn.fw.valhalla.service.bus.pub;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.springframework.stereotype.Service;
  5 +
  6 +/**
  7 + * 公共池跟进处理
  8 + *
  9 + * @author : kurisu
  10 + * @version : 1.0
  11 + * @className : PubFollowBizService
  12 + * @description : 公共池跟进处理
  13 + * @date : 2023-03-17 17:23
  14 + */
  15 +@Service
  16 +@Slf4j
  17 +public class PubFollowBizService {
  18 +}
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubStandBizService.java
... ... @@ -95,7 +95,6 @@ public class PubStandBizService {
95 95 *
96 96 * @param staffId
97 97 */
98   - @Transactional(rollbackFor = Exception.class)
99 98 public void join(final Long staffId) {
100 99 this.join(staffId, true);
101 100 }
... ... @@ -118,7 +117,7 @@ public class PubStandBizService {
118 117 ShopDTO shop = oopService.shop(shopId);
119 118 BV.notNull(shop, () -> "门店信息读取失败,请稍后重试");
120 119 final String shopName = shop.getShortName();
121   - boolean hasTodo = shirasawaRpcService.hasOngoingFollow(staffId);
  120 + boolean hasTodo = Boolean.FALSE.equals(shirasawaRpcService.hasOngoingFollow(staffId));
122 121 BV.isFalse(hasTodo, () -> "还有未完成的跟进待办,无法站岗");
123 122 final Long groupId = user.getGroupId();
124 123  
... ... @@ -153,8 +152,31 @@ public class PubStandBizService {
153 152 staffInfo.ifPresent(r -> {
154 153 r.setLining(Boolean.FALSE);
155 154 r.setNoInvolved(Boolean.FALSE);
156   - pubStandStaffInfoService.updateById(r);
157   - CompletableFuture.runAsync(() -> syncQueue(groupId));
  155 + r.setReasonOfNoLining("主动退出");
  156 + boolean updated = pubStandStaffInfoService.updateById(r);
  157 + if (updated) {
  158 + CompletableFuture.runAsync(() -> syncQueue(groupId));
  159 + }
  160 + });
  161 + }
  162 +
  163 + /**
  164 + * 退出队列
  165 + *
  166 + * @param userId
  167 + * @param groupId
  168 + */
  169 + @Transactional(rollbackFor = Exception.class)
  170 + public void exitStand(final Long userId, final Long groupId, final String reason) {
  171 + Optional<PubStandStaffInfo> staffInfo = pubStandStaffInfoService.queryStaffByGroupId(userId, groupId);
  172 + staffInfo.ifPresent(r -> {
  173 + r.setLining(Boolean.FALSE);
  174 + r.setNoInvolved(Boolean.FALSE);
  175 + r.setReasonOfNoLining(reason);
  176 + boolean updated = pubStandStaffInfoService.updateById(r);
  177 + if (updated) {
  178 + CompletableFuture.runAsync(() -> syncQueue(groupId));
  179 + }
158 180 });
159 181 }
160 182  
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/PublicPoolService.java
... ... @@ -18,6 +18,7 @@ import java.util.Optional;
18 18 public interface PublicPoolService extends IService<PublicPool> {
19 19 /**
20 20 * 根据车牌号查询
  21 + *
21 22 * @param plateNo
22 23 * @param groupId
23 24 * @return
... ... @@ -26,12 +27,20 @@ public interface PublicPoolService extends IService&lt;PublicPool&gt; {
26 27  
27 28 /**
28 29 * 移除公共池
  30 + *
29 31 * @param customerId
30 32 * @param groupId
31 33 */
32 34 @Transactional(rollbackFor = Exception.class)
33 35 void removeByCustomerId(Long customerId, Long groupId);
34   -
  36 + /**
  37 + * 移除公共池
  38 + *
  39 + * @param vin
  40 + * @param groupId
  41 + */
  42 + @Transactional(rollbackFor = Exception.class)
  43 + void removeByVin(String vin, Long groupId);
35 44 /**
36 45 * 查询公共池
37 46 *
... ... @@ -47,4 +56,11 @@ public interface PublicPoolService extends IService&lt;PublicPool&gt; {
47 56 * @return
48 57 */
49 58 Long publicListCount(PublicPoolQueryVO queryVO);
  59 +
  60 + /**
  61 + * 根据门店id查询对应车架号
  62 + * @param shopIds
  63 + * @return
  64 + */
  65 + List<String> queryIdListByShops(List<Long> shopIds);
50 66 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/PublicPoolServiceImpl.java
... ... @@ -10,8 +10,10 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
10 10 import lombok.extern.slf4j.Slf4j;
11 11 import org.springframework.stereotype.Service;
12 12 import org.springframework.transaction.annotation.Transactional;
  13 +import org.springframework.util.CollectionUtils;
13 14  
14 15 import java.util.ArrayList;
  16 +import java.util.Collections;
15 17 import java.util.List;
16 18 import java.util.Optional;
17 19  
... ... @@ -43,6 +45,15 @@ public class PublicPoolServiceImpl extends ServiceImpl&lt;PublicPoolMapper, PublicP
43 45 );
44 46 }
45 47  
  48 + @Transactional(rollbackFor = Exception.class)
  49 + @Override
  50 + public void removeByVin(final String vin, final Long groupId) {
  51 + remove(Wrappers.<PublicPool>lambdaQuery()
  52 + .eq(PublicPool::getFrameNo, vin)
  53 + .eq(PublicPool::getGroupId, groupId)
  54 + );
  55 + }
  56 +
46 57 @Override
47 58 public List<PublicPoolDTO> publicList(PublicPoolQueryVO queryVO) {
48 59 Integer current = queryVO.getCurrent();
... ... @@ -55,4 +66,13 @@ public class PublicPoolServiceImpl extends ServiceImpl&lt;PublicPoolMapper, PublicP
55 66 public Long publicListCount(PublicPoolQueryVO queryVO) {
56 67 return Optional.ofNullable(getBaseMapper().publicListCount(queryVO)).orElse(0L);
57 68 }
  69 +
  70 + @Override
  71 + public List<String> queryIdListByShops(final List<Long> shopIds) {
  72 + if (CollectionUtils.isEmpty(shopIds)) {
  73 + return Collections.emptyList();
  74 + }
  75 + // mybatis plus 性能有问题 不使用
  76 + return Optional.ofNullable(this.getBaseMapper().queryIdListByShops(shopIds)).orElse(Collections.emptyList());
  77 + }
58 78 }
... ...