TbClueServiceImpl.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. package com.huike.clues.service.impl;
  2. import java.util.ArrayList;
  3. import java.util.Date;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Map;
  7. import java.util.stream.Collectors;
  8. import com.huike.clues.domain.dto.ImportResultDTO;
  9. import com.huike.clues.strategy.Rule;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.stereotype.Service;
  12. import org.springframework.transaction.annotation.Transactional;
  13. import com.huike.clues.domain.TbActivity;
  14. import com.huike.clues.domain.TbAssignRecord;
  15. import com.huike.clues.domain.TbClue;
  16. import com.huike.clues.domain.TbClueTrackRecord;
  17. import com.huike.clues.domain.TbRulePool;
  18. import com.huike.clues.domain.vo.TbClueExcelVo;
  19. import com.huike.clues.mapper.SysDictDataMapper;
  20. import com.huike.clues.mapper.SysUserMapper;
  21. import com.huike.clues.mapper.TbActivityMapper;
  22. import com.huike.clues.mapper.TbAssignRecordMapper;
  23. import com.huike.clues.mapper.TbClueMapper;
  24. import com.huike.clues.service.ITbActivityService;
  25. import com.huike.clues.service.ITbClueService;
  26. import com.huike.clues.service.ITbRulePoolService;
  27. import com.huike.clues.utils.HuiKeCrmDateUtils;
  28. import com.huike.clues.utils.JobUtils;
  29. import com.huike.common.annotation.DataScope;
  30. import com.huike.common.constant.Constants;
  31. import com.huike.common.core.domain.entity.SysUser;
  32. import com.huike.common.exception.CustomException;
  33. import com.huike.common.utils.DateUtils;
  34. import com.huike.common.utils.SecurityUtils;
  35. import com.huike.common.utils.StringUtils;
  36. import com.huike.common.utils.bean.BeanUtils;
  37. /**
  38. * 线索管理Service业务层处理
  39. *
  40. * @date 2021-04-02
  41. */
  42. @Service
  43. public class TbClueServiceImpl implements ITbClueService {
  44. @Autowired
  45. private Rule rule;
  46. @Autowired
  47. private TbClueMapper tbClueMapper;
  48. @Autowired
  49. private TbAssignRecordMapper assignRecordMapper;
  50. @Autowired
  51. private SysUserMapper userMapper;
  52. @Autowired
  53. ITbRulePoolService rulePoolService;
  54. @Autowired
  55. SysDictDataMapper sysDictDataMapper;
  56. @Autowired
  57. private TbActivityMapper tbActivityMapper;
  58. @Autowired
  59. private ITbActivityService activityService;
  60. @Autowired
  61. private ITbClueService tbClueService;
  62. /**
  63. * 查询线索管理
  64. *
  65. * @param id 线索管理ID
  66. * @return 线索管理
  67. */
  68. @Override
  69. public TbClue selectTbClueById(Long id) {
  70. TbClue tbClue = tbClueMapper.selectTbClueById(id);
  71. if (tbClue != null && tbClue.getActivityId() != null) {
  72. TbActivity activity = tbActivityMapper.selectTbActivityById(tbClue.getActivityId());
  73. if (activity != null) {
  74. tbClue.setActivityInfo(activity.getCode() + ":" + activity.getName() + ":" + activity.getInfo());
  75. }
  76. }
  77. // 查询专派遣信息
  78. TbAssignRecord assignRecord = assignRecordMapper.selectAssignRecordByAssignId(tbClue.getId(), "0");
  79. //证明是待分配数据
  80. if(assignRecord==null){
  81. return tbClue;
  82. }
  83. tbClue.setOwner(assignRecord.getUserName());
  84. tbClue.setOwnerTime(assignRecord.getCreateTime());
  85. return tbClue;
  86. }
  87. /**
  88. * 查询线索管理列表
  89. *
  90. * @param tbClue 线索管理
  91. * @return 线索管理
  92. */
  93. @Override
  94. @DataScope(deptAlias = "r", userAlias = "r")
  95. public List<TbClue> selectTbClueList(TbClue tbClue) {
  96. return tbClueMapper.selectTbClueList(tbClue);
  97. }
  98. @Override
  99. public List<TbClue> selectTbCluePool(TbClue tbClue) {
  100. List<TbClue> clueList = tbClueMapper.selectTbCluePoll(tbClue);
  101. clueList.forEach(d -> {
  102. if (d.getActivityId() != null) {
  103. TbActivity activity = tbActivityMapper.selectTbActivityById(d.getActivityId());
  104. if (activity != null) {
  105. d.setActivityName(activity.getName());
  106. }
  107. }
  108. });
  109. return clueList;
  110. }
  111. /**
  112. * 新增线索管理
  113. *
  114. * @param tbClue 线索管理
  115. * @return 结果
  116. */
  117. @Override
  118. @Transactional
  119. public int insertTbClue(TbClue tbClue) {
  120. tbClue.setCreateBy(SecurityUtils.getUsername());
  121. Date now = DateUtils.getNowDate();
  122. tbClue.setCreateTime(now);
  123. tbClueMapper.insertTbClue(tbClue);
  124. TbAssignRecord tbAssignRecord = new TbAssignRecord();
  125. tbAssignRecord.setAssignId(tbClue.getId());
  126. tbAssignRecord.setUserId(SecurityUtils.getUserId());
  127. tbAssignRecord.setUserName(SecurityUtils.getUsername());
  128. tbAssignRecord.setDeptId(SecurityUtils.getDeptId());
  129. tbAssignRecord.setCreateBy(SecurityUtils.getUsername());
  130. tbAssignRecord.setCreateTime(now);
  131. int rows = assignRecordMapper.insertAssignRecord(tbAssignRecord);
  132. // 线索池规则支持
  133. Date endDate = HuiKeCrmDateUtils.getEndDateByRule(tbAssignRecord);
  134. tbClueMapper.updateClueEndTimeById(tbClue.getId(), endDate);
  135. return rows;
  136. }
  137. /**
  138. * 修改线索管理
  139. *
  140. * @param tbClue 线索管理
  141. * @return 结果
  142. */
  143. @Override
  144. public int updateTbClue(TbClue tbClue) {
  145. return tbClueMapper.updateTbClue(tbClue);
  146. }
  147. /**
  148. * 批量删除线索管理
  149. *
  150. * @param ids 需要删除的线索管理ID
  151. * @return 结果
  152. */
  153. @Override
  154. public int deleteTbClueByIds(Long[] ids) {
  155. return tbClueMapper.deleteTbClueByIds(ids);
  156. }
  157. /**
  158. * 删除线索管理信息
  159. *
  160. * @param id 线索管理ID
  161. * @return 结果
  162. */
  163. @Override
  164. public int deleteTbClueById(Long id) {
  165. return tbClueMapper.deleteTbClueById(id);
  166. }
  167. @Override
  168. @Transactional
  169. public Map<String, Integer> importClues(List<TbClue> clueList) {
  170. if (StringUtils.isNull(clueList) || clueList.size() == 0) {
  171. throw new CustomException("导入用户数据不能为空!");
  172. }
  173. Map<String, Integer> map = new HashMap<>();
  174. List<TbClue> toAssignlist = new ArrayList<>();
  175. int successNum = 0;
  176. int failureNum = 0;
  177. for (TbClue clue : clueList) {
  178. try {
  179. if (StringUtils.isBlank(clue.getPhone())) {
  180. failureNum++;
  181. continue;
  182. }
  183. if (StringUtils.isBlank(clue.getChannel())) {
  184. failureNum++;
  185. continue;
  186. }
  187. // 验证是否存在这个用户
  188. TbClue dbcule = tbClueMapper.selectTbClueByPhone(clue.getPhone());
  189. if (dbcule == null) {
  190. // 特殊字段处理
  191. String channel = sysDictDataMapper.selectDictValue(TbClue.ImportDictType.CHANNEL.getDictType(),
  192. clue.getChannel());
  193. clue.setChannel(channel);
  194. if (StringUtils.isNoneBlank(clue.getSubject())) {
  195. String subject = sysDictDataMapper.selectDictValue(TbClue.ImportDictType.SUBJECT.getDictType(),
  196. clue.getSubject());
  197. clue.setSubject(subject);
  198. }
  199. if (StringUtils.isNoneBlank(clue.getLevel())) {
  200. String level = sysDictDataMapper.selectDictValue(TbClue.ImportDictType.LEVEL.getDictType(),
  201. clue.getLevel());
  202. clue.setLevel(level);
  203. }
  204. if (StringUtils.isNoneBlank(clue.getSex())) {
  205. String sex = sysDictDataMapper.selectDictValue(TbClue.ImportDictType.SEX.getDictType(),
  206. clue.getSex());
  207. clue.setSex(sex);
  208. }
  209. if (StringUtils.isNoneBlank(clue.getActivityName())) {
  210. String sex = sysDictDataMapper.selectDictValue(TbClue.ImportDictType.SEX.getDictType(),
  211. clue.getSex());
  212. clue.setSex(sex);
  213. }
  214. clue.setStatus(TbClue.StatusType.UNFOLLOWED.getValue());
  215. tbClueMapper.insertTbClue(clue);
  216. // 默认分配超级管理员
  217. //如果线索添加成功,利用策略将线索分配给具体的人
  218. rule.loadRule(clue);
  219. successNum++;
  220. toAssignlist.add(clue);
  221. } else {
  222. failureNum++;
  223. }
  224. } catch (Exception e) {
  225. e.printStackTrace();
  226. failureNum++;
  227. }
  228. }
  229. map.put("successNum", successNum);
  230. map.put("failureNum", failureNum);
  231. return map;
  232. }
  233. @Override
  234. public String assign(Long[] clueIds, Long userId) {
  235. TbRulePool rulePool = rulePoolService.selectTbRulePoolByType(Constants.rule_type_clue);
  236. // TbAssignRecord tbAssignRecord =new TbAssignRecord();
  237. // 统计当前分配人所有线索
  238. int assignRecords = assignRecordMapper.countAssignCluesByUser(userId);
  239. if (assignRecords >= rulePool.getMaxNunmber()) {
  240. throw new CustomException("分配失败!最大保有量(" + rulePool.getMaxNunmber() + "),剩余可以分配"
  241. + Math.abs(rulePool.getMaxNunmber() - assignRecords) + "条线索");
  242. }
  243. for (int i = 0; i < clueIds.length; i++) {
  244. Long clueId = clueIds[i];
  245. // 超过最大保有量
  246. if (assignRecords + i >= rulePool.getMaxNunmber()) {
  247. // return "超过当前用户最大保有量,部分分配成功";
  248. throw new CustomException("分配失败!保有量达到上线,最多选择" + rulePool.getMaxNunmber() + "条线索");
  249. }
  250. // 从新分配
  251. updateStatus(clueId, TbClue.StatusType.UNFOLLOWED.getValue());
  252. TbAssignRecord tbAssignRecord = addNewRecord(clueId, userId);
  253. Date endDate = HuiKeCrmDateUtils.getEndDateByRule(tbAssignRecord);
  254. tbClueMapper.updateClueEndTimeById(clueId, endDate);
  255. }
  256. return "全部分配";
  257. }
  258. @Override
  259. public String gain(Long[] clueIds, Long userId) {
  260. // 是否批量捞取
  261. boolean isBatch = clueIds.length > 1 ? true : false;
  262. TbRulePool rulePool = rulePoolService.selectTbRulePoolByType(TbRulePool.RuleType.CLUES.getValue());
  263. // 统计当前分配人所有线索
  264. int asignRecords = assignRecordMapper.countAssignCluesByUser(userId);
  265. if (asignRecords >= rulePool.getMaxNunmber()) {
  266. throw new CustomException("捞取失败!最大保有量(" + rulePool.getMaxNunmber() + "),剩余可以捞取"+ Math.abs(rulePool.getMaxNunmber() - asignRecords)+"条线索");
  267. }
  268. for (int i = 0; i < clueIds.length; i++) {
  269. Long clueId = clueIds[i];
  270. // 超过最大保有量
  271. if (asignRecords + i >= rulePool.getMaxNunmber()) {
  272. throw new CustomException("捞取失败!保有量达到上线,最多选择" + rulePool.getMaxNunmber() + "条线索");
  273. }
  274. // 最近捞取记录
  275. TbAssignRecord assignRecord = assignRecordMapper.selectAssignRecordByAssignId(clueId,
  276. TbAssignRecord.RecordType.CLUES.getValue());
  277. if (assignRecord != null && assignRecord.getUserId().equals(userId)) {
  278. Date repeatGetTime = JobUtils.getDate(rulePool.getRepeatGetTime().intValue(), rulePool.getRepeatType(),
  279. assignRecord.getCreateTime());
  280. // 捞取限制时间内,不让捞取
  281. if (DateUtils.getNowDate().before(repeatGetTime)) {
  282. // 批量捞取跳过
  283. if (isBatch) {
  284. continue;
  285. } else {
  286. throw new CustomException("捞取失败!需要在 " + DateUtils.dateTimeHm(repeatGetTime) + " 后捞取");
  287. }
  288. }
  289. }
  290. // 捞取后下次跟进时间,及状态重置
  291. tbClueMapper.resetNextTimeAndStatus(clueId, TbClue.StatusType.UNFOLLOWED.getValue());
  292. // 新建分配记录
  293. TbAssignRecord tbAssignRecord = addNewRecord(clueId, userId);
  294. Date endDate = HuiKeCrmDateUtils.getEndDateByRule(tbAssignRecord);
  295. tbClueMapper.updateClueEndTimeById(clueId, endDate);
  296. }
  297. return "全部捞取成功";
  298. }
  299. public TbAssignRecord addNewRecord(Long id, Long userId) {
  300. // 保留上一条分配记录
  301. assignRecordMapper.updateLatest(id, TbAssignRecord.RecordType.CLUES.getValue());
  302. // 新建分配记录
  303. TbAssignRecord tbAssignRecord = new TbAssignRecord();
  304. tbAssignRecord.setAssignId(id);
  305. SysUser sysUser = userMapper.selectUserById(userId);
  306. tbAssignRecord.setUserId(userId);
  307. tbAssignRecord.setDeptId(sysUser.getDeptId());
  308. tbAssignRecord.setUserName(sysUser.getUserName());
  309. Date now = DateUtils.getNowDate();
  310. tbAssignRecord.setCreateTime(now);
  311. tbAssignRecord.setCreateBy(SecurityUtils.getUsername());
  312. tbAssignRecord.setType(TbAssignRecord.RecordType.CLUES.getValue());
  313. assignRecordMapper.insertAssignRecord(tbAssignRecord);
  314. return tbAssignRecord;
  315. }
  316. @Override
  317. @Transactional
  318. public int updateStatus(Long clueId, String status) {
  319. return tbClueMapper.resetNextTimeAndStatus(clueId, status);
  320. }
  321. /**
  322. * 批量导入
  323. */
  324. @Override
  325. public Map<String, Integer> addTbClue(List<TbClueExcelVo> cluevoList) {
  326. List<TbClue> clueList = cluevoList.stream().map(vo -> {
  327. TbClue tbClue = new TbClue();
  328. BeanUtils.copyProperties(vo, tbClue);
  329. tbClue.setCreateBy(SecurityUtils.getUsername());
  330. tbClue.setCreateTime(DateUtils.getNowDate());
  331. String activityCode = vo.getActivityCode();
  332. // 关联活动
  333. if (StringUtils.isNoneBlank(activityCode)) {
  334. TbActivity activity = activityService.selectTbActivityByCode(activityCode);
  335. if (activity != null) {
  336. tbClue.setActivityId(activity.getId());
  337. }
  338. }
  339. return tbClue;
  340. }).collect(Collectors.toList());
  341. return tbClueService.importClues(clueList);
  342. }
  343. /**
  344. * 校验线索手机号是否存在
  345. */
  346. @Override
  347. public boolean checkCluePhoneExis(String phone) {
  348. // 验证是否存在这个用户
  349. TbClue dbcule = tbClueMapper.selectTbClueByPhone(phone);
  350. if (dbcule == null) {
  351. return true;
  352. } else {
  353. return false;
  354. }
  355. }
  356. /**
  357. * 线索数据添加入库
  358. *
  359. * @param data
  360. * @return
  361. */
  362. @Override
  363. public ImportResultDTO importCluesData(TbClueExcelVo data) {
  364. //===============校验线索数据,封装属性,插入数据库,根据规则进行分配======================
  365. /**
  366. * 1 判断活动编号对应的活动是否存在
  367. * 1.1 如果活动编号不存在 即错误数据,不进行添加操作,返回错误 ImportResultDTO.error()
  368. * 1.2 如果活动编号存在 设置活动id
  369. */
  370. //TODO 补全上述逻辑代码
  371. /**
  372. * 校验手机号和渠道是否为空
  373. * 如果为空证明是错误数据,不进行添加 返回error
  374. * return ImportResultDTO.error();
  375. */
  376. //TODO 补全上述逻辑代码
  377. /**
  378. * 字典值的替换
  379. * 因为excel里传入的是中文名,需要替换成对应的字典值
  380. * 需要处理 学科 性别 意向级别
  381. */
  382. //TODO 补全上述逻辑代码
  383. /**
  384. * 设置数据状态为待跟进
  385. * clue.setStatus(TbClue.StatusType.UNFOLLOWED.getValue());
  386. */
  387. //TODO 补全上述逻辑代码
  388. /**
  389. * 将线索数据入库
  390. * 参考添加线索接口调用的mapper
  391. * 仅仅只插入到线索表中
  392. */
  393. //TODO 补全上述逻辑代码
  394. /**
  395. * 根据规则动态分配线索给具体的销售人员
  396. * 利用策略模式来进行实现
  397. * rule.loadRule(clue);
  398. */
  399. //TODO 补全上述逻辑代码
  400. /**
  401. *分配完成 返回成功
  402. * 这个方法免费提供
  403. */
  404. return ImportResultDTO.success();
  405. }
  406. }