Commit 0ea9475cd0e64181774958455704a7f5cd2c712f

Authored by 张志伟
1 parent e001d1e4

:construction: 离职分配优化

fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/CommonController.java
@@ -3,13 +3,16 @@ package cn.fw.valhalla.controller.app; @@ -3,13 +3,16 @@ package cn.fw.valhalla.controller.app;
3 import cn.fw.data.base.domain.common.Message; 3 import cn.fw.data.base.domain.common.Message;
4 import cn.fw.security.auth.client.annotation.Authorization; 4 import cn.fw.security.auth.client.annotation.Authorization;
5 import cn.fw.security.auth.client.annotation.IgnoreAuth; 5 import cn.fw.security.auth.client.annotation.IgnoreAuth;
  6 +import cn.fw.security.auth.client.annotation.IgnoreUserToken;
6 import cn.fw.security.auth.client.enums.AuthType; 7 import cn.fw.security.auth.client.enums.AuthType;
7 import cn.fw.valhalla.domain.vo.PostUserVO; 8 import cn.fw.valhalla.domain.vo.PostUserVO;
8 import cn.fw.valhalla.service.bus.CommonService; 9 import cn.fw.valhalla.service.bus.CommonService;
  10 +import cn.fw.valhalla.service.bus.LeaveNeedDoBizService;
9 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
10 import org.springframework.beans.factory.annotation.Autowired; 12 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.validation.annotation.Validated; 13 import org.springframework.validation.annotation.Validated;
12 import org.springframework.web.bind.annotation.GetMapping; 14 import org.springframework.web.bind.annotation.GetMapping;
  15 +import org.springframework.web.bind.annotation.PutMapping;
13 import org.springframework.web.bind.annotation.RequestMapping; 16 import org.springframework.web.bind.annotation.RequestMapping;
14 import org.springframework.web.bind.annotation.RestController; 17 import org.springframework.web.bind.annotation.RestController;
15 18
@@ -31,17 +34,20 @@ import static cn.fw.valhalla.common.constant.MessageStr.SAVE_FAILURE; @@ -31,17 +34,20 @@ import static cn.fw.valhalla.common.constant.MessageStr.SAVE_FAILURE;
31 @RestController 34 @RestController
32 @Authorization(AuthType.APP) 35 @Authorization(AuthType.APP)
33 @Validated 36 @Validated
34 -@IgnoreAuth  
35 @RequestMapping("/app/common") 37 @RequestMapping("/app/common")
36 public class CommonController { 38 public class CommonController {
37 private final CommonService commonService; 39 private final CommonService commonService;
  40 + private final LeaveNeedDoBizService leaveNeedDoBizService;
38 41
39 @Autowired 42 @Autowired
40 - public CommonController(final CommonService commonService) { 43 + public CommonController(final CommonService commonService,
  44 + final LeaveNeedDoBizService leaveNeedDoBizService) {
41 this.commonService = commonService; 45 this.commonService = commonService;
  46 + this.leaveNeedDoBizService = leaveNeedDoBizService;
42 } 47 }
43 48
44 @GetMapping("/staff/list") 49 @GetMapping("/staff/list")
  50 + @IgnoreAuth
45 public Message<List<PostUserVO>> list(@NotNull(message = "服务站ID不能为空") final Long shopId, 51 public Message<List<PostUserVO>> list(@NotNull(message = "服务站ID不能为空") final Long shopId,
46 @NotNull(message = "跟进类型不能为空") final Integer type) { 52 @NotNull(message = "跟进类型不能为空") final Integer type) {
47 final String msg = "查询跟进人员[app/common/staff/list]"; 53 final String msg = "查询跟进人员[app/common/staff/list]";
@@ -54,4 +60,19 @@ public class CommonController { @@ -54,4 +60,19 @@ public class CommonController {
54 return failureWithMessage(SAVE_FAILURE); 60 return failureWithMessage(SAVE_FAILURE);
55 } 61 }
56 } 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 + }
57 } 78 }
fw-valhalla-server/src/main/resources/application-gray.yml
@@ -51,3 +51,4 @@ follow: @@ -51,3 +51,4 @@ follow:
51 RMCode: 'Zb33mjtjVy' 51 RMCode: 'Zb33mjtjVy'
52 IRCode: 'RsavIrkhZm' 52 IRCode: 'RsavIrkhZm'
53 ACCode: 'gWPMkrjkjH' 53 ACCode: 'gWPMkrjkjH'
  54 + leave2do: 'uF08Vd38fi'
fw-valhalla-server/src/main/resources/application-prd.yml
@@ -50,3 +50,4 @@ follow: @@ -50,3 +50,4 @@ follow:
50 RMCode: 'Zb33mjtjVy' 50 RMCode: 'Zb33mjtjVy'
51 IRCode: 'RsavIrkhZm' 51 IRCode: 'RsavIrkhZm'
52 ACCode: 'gWPMkrjkjH' 52 ACCode: 'gWPMkrjkjH'
  53 + leave2do: 'uF08Vd38fi'
fw-valhalla-server/src/main/resources/application.yml
@@ -127,3 +127,4 @@ follow: @@ -127,3 +127,4 @@ follow:
127 RMCode: 'Zb33mjtjVy' 127 RMCode: 'Zb33mjtjVy'
128 IRCode: 'RsavIrkhZm' 128 IRCode: 'RsavIrkhZm'
129 ACCode: 'gWPMkrjkjH' 129 ACCode: 'gWPMkrjkjH'
  130 + leave2do: 'kLKIpyNNQf'
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/LeaveNeedDoBizService.java
@@ -5,21 +5,28 @@ import cn.fw.common.data.mybatis.pagination.PageData; @@ -5,21 +5,28 @@ import cn.fw.common.data.mybatis.pagination.PageData;
5 import cn.fw.common.page.AppPage; 5 import cn.fw.common.page.AppPage;
6 import cn.fw.common.web.auth.LoginAuthBean; 6 import cn.fw.common.web.auth.LoginAuthBean;
7 import cn.fw.data.base.domain.common.Message; 7 import cn.fw.data.base.domain.common.Message;
8 -import cn.fw.erp.sdk.api.result.UserRoleInfo;  
9 import cn.fw.third.push.sdk.api.ImSendMessage; 8 import cn.fw.third.push.sdk.api.ImSendMessage;
10 import cn.fw.third.push.sdk.api.para.im.MsgPara; 9 import cn.fw.third.push.sdk.api.para.im.MsgPara;
11 import cn.fw.valhalla.common.constant.RoleCode; 10 import cn.fw.valhalla.common.constant.RoleCode;
12 import cn.fw.valhalla.common.enums.AllocationTypeEnum; 11 import cn.fw.valhalla.common.enums.AllocationTypeEnum;
  12 +import cn.fw.valhalla.common.utils.DateUtil;
13 import cn.fw.valhalla.domain.db.LeaveNeedDo; 13 import cn.fw.valhalla.domain.db.LeaveNeedDo;
14 import cn.fw.valhalla.domain.db.customer.Customer; 14 import cn.fw.valhalla.domain.db.customer.Customer;
15 import cn.fw.valhalla.domain.db.follow.FollowRecord; 15 import cn.fw.valhalla.domain.db.follow.FollowRecord;
16 import cn.fw.valhalla.domain.db.follow.FollowTask; 16 import cn.fw.valhalla.domain.db.follow.FollowTask;
17 import cn.fw.valhalla.domain.dto.LeaveAllocationDTO; 17 import cn.fw.valhalla.domain.dto.LeaveAllocationDTO;
18 import cn.fw.valhalla.domain.enums.FollowTypeEnum; 18 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
  19 +import cn.fw.valhalla.domain.enums.LeaveReasonEnum;
  20 +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum;
19 import cn.fw.valhalla.domain.enums.TaskStateEnum; 21 import cn.fw.valhalla.domain.enums.TaskStateEnum;
20 import cn.fw.valhalla.domain.query.LeaveQueryVO; 22 import cn.fw.valhalla.domain.query.LeaveQueryVO;
21 import cn.fw.valhalla.domain.vo.LeaveNeedDoVO; 23 import cn.fw.valhalla.domain.vo.LeaveNeedDoVO;
22 -import cn.fw.valhalla.rpc.erp.UserRoleRpcService; 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;
23 import cn.fw.valhalla.service.data.CustomerService; 30 import cn.fw.valhalla.service.data.CustomerService;
24 import cn.fw.valhalla.service.data.FollowRecordService; 31 import cn.fw.valhalla.service.data.FollowRecordService;
25 import cn.fw.valhalla.service.data.FollowTaskService; 32 import cn.fw.valhalla.service.data.FollowTaskService;
@@ -56,11 +63,12 @@ import static cn.fw.common.businessvalidator.Validator.BV; @@ -56,11 +63,12 @@ import static cn.fw.common.businessvalidator.Validator.BV;
56 public class LeaveNeedDoBizService { 63 public class LeaveNeedDoBizService {
57 private final LeaveNeedDoService leaveNeedDoService; 64 private final LeaveNeedDoService leaveNeedDoService;
58 private final CustomerService customerService; 65 private final CustomerService customerService;
59 - private final UserRoleRpcService userRoleRpcService; 66 + private final UserService userService;
60 private final FollowTaskService followTaskService; 67 private final FollowTaskService followTaskService;
61 private final FollowRecordService followRecordService; 68 private final FollowRecordService followRecordService;
62 private final DistributedLocker distributedLocker; 69 private final DistributedLocker distributedLocker;
63 private final ImSendMessage imSendMessage; 70 private final ImSendMessage imSendMessage;
  71 + private final TodoRpcService todoRpcService;
64 /** 72 /**
65 * Redis工具 73 * Redis工具
66 */ 74 */
@@ -70,27 +78,52 @@ public class LeaveNeedDoBizService { @@ -70,27 +78,52 @@ public class LeaveNeedDoBizService {
70 @Getter 78 @Getter
71 private String keyPrefix; 79 private String keyPrefix;
72 80
  81 + @Value("${follow.todo.leave2do}")
  82 + @Getter
  83 + private String leave2doCode;
  84 +
73 @Autowired 85 @Autowired
74 public LeaveNeedDoBizService(final LeaveNeedDoService leaveNeedDoService, 86 public LeaveNeedDoBizService(final LeaveNeedDoService leaveNeedDoService,
75 final CustomerService customerService, 87 final CustomerService customerService,
76 - final UserRoleRpcService userRoleRpcService, 88 + final UserService userService,
77 final FollowTaskService followTaskService, 89 final FollowTaskService followTaskService,
78 final FollowRecordService followRecordService, 90 final FollowRecordService followRecordService,
79 final DistributedLocker distributedLocker, 91 final DistributedLocker distributedLocker,
80 final ImSendMessage imSendMessage, 92 final ImSendMessage imSendMessage,
  93 + final TodoRpcService todoRpcService,
81 final StringRedisTemplate redisTemplate) { 94 final StringRedisTemplate redisTemplate) {
82 this.leaveNeedDoService = leaveNeedDoService; 95 this.leaveNeedDoService = leaveNeedDoService;
83 this.customerService = customerService; 96 this.customerService = customerService;
84 - this.userRoleRpcService = userRoleRpcService; 97 + this.userService = userService;
85 this.followTaskService = followTaskService; 98 this.followTaskService = followTaskService;
86 this.followRecordService = followRecordService; 99 this.followRecordService = followRecordService;
87 this.distributedLocker = distributedLocker; 100 this.distributedLocker = distributedLocker;
88 this.imSendMessage = imSendMessage; 101 this.imSendMessage = imSendMessage;
  102 + this.todoRpcService = todoRpcService;
89 this.redisTemplate = redisTemplate; 103 this.redisTemplate = redisTemplate;
90 } 104 }
91 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 +
92 public AppPage<LeaveNeedDoVO> getList(LoginAuthBean currentUser, LeaveQueryVO queryVO) { 124 public AppPage<LeaveNeedDoVO> getList(LoginAuthBean currentUser, LeaveQueryVO queryVO) {
93 - List<Long> shopIds = userRoleRpcService.getManageShopIds(currentUser.getUserId(), RoleCode.BYKFP); 125 + List<UserRoleDataRangeDTO> dataRange = userService.getUserRoleDataRange(currentUser.getUserId(), RoleCode.BYKFP);
  126 + List<Long> shopIds = dataRange.stream().map(UserRoleDataRangeDTO::getRangeValue).collect(Collectors.toList());
94 BV.isFalse(CollectionUtils.isEmpty(shopIds), () -> "无权限操作,请检查角色权限是否正确"); 127 BV.isFalse(CollectionUtils.isEmpty(shopIds), () -> "无权限操作,请检查角色权限是否正确");
95 PageData<LeaveNeedDo> pageData = leaveNeedDoService.page(new PageData<>(queryVO), Wrappers.<LeaveNeedDo>lambdaQuery() 128 PageData<LeaveNeedDo> pageData = leaveNeedDoService.page(new PageData<>(queryVO), Wrappers.<LeaveNeedDo>lambdaQuery()
96 .in(LeaveNeedDo::getShopId, shopIds) 129 .in(LeaveNeedDo::getShopId, shopIds)
@@ -142,7 +175,8 @@ public class LeaveNeedDoBizService { @@ -142,7 +175,8 @@ public class LeaveNeedDoBizService {
142 dto.setAdviserId(needDo.getUserId()); 175 dto.setAdviserId(needDo.getUserId());
143 if (AllocationTypeEnum.ONE.equals(typeEnum)) { 176 if (AllocationTypeEnum.ONE.equals(typeEnum)) {
144 BV.notNull(dto.getUserId(), () -> "指定人员不能为空"); 177 BV.notNull(dto.getUserId(), () -> "指定人员不能为空");
145 - List<Long> shopIdList = userRoleRpcService.getManageShopIds(dto.getUserId(), RoleCode.FWGW); 178 + List<UserRoleDataRangeDTO> dataRange = userService.getUserRoleDataRange(dto.getUserId(), RoleCode.FWGW);
  179 + List<Long> shopIdList = dataRange.stream().map(UserRoleDataRangeDTO::getRangeValue).collect(Collectors.toList());
146 BV.isNotEmpty(shopIdList, () -> "指定人员非服务顾问角色,请核对"); 180 BV.isNotEmpty(shopIdList, () -> "指定人员非服务顾问角色,请核对");
147 Long shopId = shopIdList.get(0); 181 Long shopId = shopIdList.get(0);
148 BV.isTrue(needDo.getShopId().equals(shopId), () -> "指定人员所属门店与档案归属门店不符"); 182 BV.isTrue(needDo.getShopId().equals(shopId), () -> "指定人员所属门店与档案归属门店不符");
@@ -196,10 +230,10 @@ public class LeaveNeedDoBizService { @@ -196,10 +230,10 @@ public class LeaveNeedDoBizService {
196 * @param shopId 230 * @param shopId
197 */ 231 */
198 private void allocation(String key, List<Customer> list, Long shopId) { 232 private void allocation(String key, List<Customer> list, Long shopId) {
199 - List<UserRoleInfo> users = userRoleRpcService.getUsers(shopId, RoleCode.FWGW); 233 + List<PostUserDTO> users = userService.getUserByRole(shopId, RoleCode.FWGW);
200 BV.isNotEmpty(users, () -> "该门店没有服务顾问,请检查配置是否正确"); 234 BV.isNotEmpty(users, () -> "该门店没有服务顾问,请检查配置是否正确");
201 LinkedList<UserInfo> queue = new LinkedList<>(); 235 LinkedList<UserInfo> queue = new LinkedList<>();
202 - for (UserRoleInfo user : users) { 236 + for (PostUserDTO user : users) {
203 queue.offer(new UserInfo(user.getUserId(), user.getUserName())); 237 queue.offer(new UserInfo(user.getUserId(), user.getUserName()));
204 } 238 }
205 for (Customer customer : list) { 239 for (Customer customer : list) {
@@ -278,7 +312,7 @@ public class LeaveNeedDoBizService { @@ -278,7 +312,7 @@ public class LeaveNeedDoBizService {
278 private String generateKey(final Long leaveId) { 312 private String generateKey(final Long leaveId) {
279 Assert.notNull(leaveId, "leaveId cannot be null"); 313 Assert.notNull(leaveId, "leaveId cannot be null");
280 314
281 - return String.format("%s:message:%s", getKeyPrefix(), leaveId); 315 + return String.format("%s:allocation:%s", getKeyPrefix(), leaveId);
282 } 316 }
283 317
284 public List<UserInfo> getAllFromCache(final String key) { 318 public List<UserInfo> getAllFromCache(final String key) {
@@ -332,6 +366,42 @@ public class LeaveNeedDoBizService { @@ -332,6 +366,42 @@ public class LeaveNeedDoBizService {
332 } 366 }
333 } 367 }
334 368
  369 + private LeaveNeedDo addable(final Long userId, final Long shopId) {
  370 + List<UserRoleDataRangeDTO> dataRange = userService.getUserRoleDataRange(userId, RoleCode.FWGW);
  371 + boolean ok = CollectionUtils.isEmpty(dataRange) || !Objects.equals(dataRange.get(0).getRangeValue(), shopId);
  372 + BV.isTrue(ok, () -> "请先移除对对应服务站服务顾问角色后操作");
  373 + int count = leaveNeedDoService.count(Wrappers.<LeaveNeedDo>lambdaQuery()
  374 + .eq(LeaveNeedDo::getUserId, userId)
  375 + .eq(LeaveNeedDo::getShopId, shopId)
  376 + .eq(LeaveNeedDo::getDone, Boolean.FALSE)
  377 + );
  378 + BV.isTrue(count == 0, () -> "已存在待分配记录,请勿重复添加");
  379 + UserInfoDTO user = userService.user(userId);
  380 + BV.notNull(user, () -> "用户不存在");
  381 + boolean bool = customerService.count(Wrappers.<Customer>lambdaQuery()
  382 + .eq(Customer::getAdviserId, userId)
  383 + .eq(Customer::getShopId, shopId)
  384 + .eq(Customer::getYn, Boolean.TRUE)
  385 + ) > 0;
  386 + BV.isTrue(bool, () -> "该顾问没有可用档案无需分配保有客");
  387 + LeaveNeedDo db = new LeaveNeedDo();
  388 + db.setDone(Boolean.FALSE);
  389 + db.setEffectiveTime(DateUtil.getMonthEndDay(new Date()));
  390 + db.setReason(LeaveReasonEnum.OTHER);
  391 + db.setType(LeaveTodoTypeEnum.CUSTOMER);
  392 + db.setShopId(shopId);
  393 + db.setUserId(userId);
  394 + db.setUserName(user.getUserName());
  395 + db.setCreateTime(new Date());
  396 + db.setUpdateTime(new Date());
  397 + return db;
  398 + }
  399 +
  400 + private void push2Todo(Long id, Long userId) {
  401 + BackLogItemDTO dto = new BackLogItemDTO(userId, getLeave2doCode(), String.valueOf(id), new Date());
  402 + todoRpcService.push(dto);
  403 + }
  404 +
335 static class UserInfo { 405 static class UserInfo {
336 private Long userId; 406 private Long userId;
337 private String userName; 407 private String userName;
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/LeaveNeedDoService.java
@@ -14,15 +14,17 @@ import org.springframework.lang.Nullable; @@ -14,15 +14,17 @@ import org.springframework.lang.Nullable;
14 public interface LeaveNeedDoService extends IService<LeaveNeedDo> { 14 public interface LeaveNeedDoService extends IService<LeaveNeedDo> {
15 /** 15 /**
16 * 通过id查询可处理数据 16 * 通过id查询可处理数据
  17 + *
17 * @param id 18 * @param id
18 * @return 19 * @return
19 */ 20 */
20 @Nullable 21 @Nullable
21 - LeaveNeedDo queryProcessableById(@NonNull Long id); 22 + LeaveNeedDo queryProcessableById(@NonNull Long id);
22 23
23 /** 24 /**
24 * 处理数据 25 * 处理数据
  26 + *
25 * @param id 27 * @param id
26 */ 28 */
27 - void dealById(@NonNull Long id); 29 + void dealById(@NonNull Long id);
28 } 30 }