CusFollowService.java 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. package com.dk.mdm.service.mst;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
  5. import com.dk.common.exception.BaseBusinessException;
  6. import com.dk.common.infrastructure.annotaiton.Pagination;
  7. import com.dk.common.infrastructure.constant.Constant;
  8. import com.dk.common.infrastructure.enums.ErrorCodeEnum;
  9. import com.dk.common.infrastructure.xxl.XxlJobUtils;
  10. import com.dk.common.model.pojo.PageList;
  11. import com.dk.common.model.vo.core.StaffEntity;
  12. import com.dk.common.response.ResponseCodeEnum;
  13. import com.dk.common.response.ResponseResultUtil;
  14. import com.dk.common.response.ResponseResultVO;
  15. import com.dk.common.util.HttpUtils;
  16. import com.dk.mdm.feign.UserFeign;
  17. import com.dk.mdm.infrastructure.config.Config;
  18. import com.dk.mdm.infrastructure.convert.mst.CusFollowConvert;
  19. import com.dk.mdm.infrastructure.convert.mst.MeasureReceiptConvert;
  20. import com.dk.mdm.infrastructure.util.AuthUtils;
  21. import com.dk.mdm.mapper.mst.*;
  22. import com.dk.mdm.model.pojo.ivt.InboundItem;
  23. import com.dk.mdm.model.pojo.mst.*;
  24. import com.dk.common.service.BaseService;
  25. import com.dk.common.mapper.BaseMapper;
  26. import com.dk.mdm.model.query.mst.CusFollowQuery;
  27. import com.dk.mdm.model.query.mst.CustomerQuery;
  28. import com.dk.mdm.model.response.mst.CusFollowResponse;
  29. import com.dk.mdm.model.response.mst.CustomerResponse;
  30. import com.dk.common.model.response.mst.StaffResponse;
  31. import com.dk.mdm.model.vo.mst.CusFollowVO;
  32. import com.dk.mdm.model.vo.mst.MeasureReceiptVO;
  33. import com.dk.mdm.service.common.CommonService;
  34. import com.xxl.job.core.context.XxlJobHelper;
  35. import com.xxl.job.core.handler.annotation.XxlJob;
  36. import lombok.extern.slf4j.Slf4j;
  37. import org.apache.commons.lang.StringUtils;
  38. import org.slf4j.Logger;
  39. import org.slf4j.LoggerFactory;
  40. import org.springframework.http.ResponseEntity;
  41. import org.springframework.stereotype.Service;
  42. import org.springframework.beans.factory.annotation.Autowired;
  43. import org.springframework.transaction.annotation.Transactional;
  44. import javax.annotation.Resource;
  45. import javax.servlet.http.HttpServletRequest;
  46. import javax.servlet.http.HttpServletResponse;
  47. import java.io.IOException;
  48. import java.io.PrintWriter;
  49. import java.security.MessageDigest;
  50. import java.security.NoSuchAlgorithmException;
  51. import java.time.LocalDate;
  52. import java.time.LocalDateTime;
  53. import java.time.ZoneOffset;
  54. import java.time.format.DateTimeFormatter;
  55. import java.util.*;
  56. import java.util.stream.IntStream;
  57. @Slf4j
  58. @Service
  59. public class CusFollowService extends BaseService<CusFollow> {
  60. @Override
  61. public BaseMapper<CusFollow> getRepository() {
  62. return cusFollowMapper;
  63. }
  64. @Autowired
  65. private CusFollowMapper cusFollowMapper;
  66. @Autowired
  67. private CustomerMapper customerMapper;
  68. @Autowired
  69. private CustomerService customerService;
  70. @Autowired
  71. private CusFollowStaffMapper cusFollowStaffMapper;
  72. @Autowired
  73. private CommonService commonService;
  74. @Autowired
  75. private CusFollowConvert cusFollowConvert;
  76. @Autowired
  77. private StaffMapper staffMapper;
  78. @Autowired
  79. private AuthUtils authUtils;
  80. @Autowired
  81. private MeasureRoomService measureRoomService;
  82. @Autowired
  83. private MeasureReceiptService measureReceiptService;
  84. @Autowired
  85. private MeasureReceiptMapper measureReceiptMapper;
  86. @Autowired
  87. private MeasureRoomMapper measureRoomMapper;
  88. @Autowired
  89. private FollowPlanMapper followPlanMapper;
  90. @Autowired
  91. private XxlJobUtils xxlJobUtils;
  92. @Autowired
  93. private Config config;
  94. @Resource
  95. private UserFeign userFeign;
  96. @Autowired
  97. private MeasureReceiptConvert measureReceiptConvert;
  98. /**
  99. * @desc : 重写主键
  100. * @author : 于继渤
  101. * @date : 2024/2/29 20:29
  102. */
  103. @Override
  104. public String getPrimaryKey() {
  105. return "follow_id";
  106. }
  107. /**
  108. * @desc : 查询
  109. * @author : 于继渤
  110. * @date : 2023/1/5 9:39
  111. */
  112. @Pagination
  113. public ResponseResultVO<PageList<CusFollowResponse>> selectByCond(CusFollowQuery cusFollowQuery) {
  114. return super.mergeListWithCount(cusFollowQuery, cusFollowMapper.selectByCond(cusFollowQuery),
  115. cusFollowMapper.countByCond(cusFollowQuery));
  116. }
  117. public ResponseResultVO<List<CusFollowResponse>> selectByList(CusFollowQuery cusFollowQuery) {
  118. return ResponseResultUtil.success(cusFollowMapper.selectByList(cusFollowQuery));
  119. }
  120. /**
  121. * @desc : 跟进id查询
  122. * @author : 于继渤
  123. * @date : 2023/1/5 9:39
  124. */
  125. public ResponseResultVO<CusFollowResponse> selectById(CusFollowQuery cusFollowQuery) {
  126. CusFollowResponse cusFollowResponse = cusFollowMapper.selectByCond(cusFollowQuery).get(0);
  127. if (cusFollowResponse.getFollowId() != null && cusFollowResponse.getMeasureStatus() != null && cusFollowResponse.getMeasureStatus().equals(Constant.BasicDataConstant.MEASURE_STATUS_1.getValue())) {
  128. //已量尺
  129. MeasureReceipt measureReceipts = measureReceiptMapper.selectByFollowId(new MeasureReceipt().setFollowId(cusFollowQuery.getFollowId()));
  130. cusFollowResponse.setMeasureReceipt(measureReceipts);
  131. //查询 空间
  132. List<MeasureRoom> measureRooms = measureRoomMapper.selectByReceiptId(new MeasureRoom().setReceiptId(measureReceipts.getReceiptId()));
  133. cusFollowResponse.setMeasureRoomList(measureRooms);
  134. }
  135. return ResponseResultUtil.success(cusFollowResponse);
  136. }
  137. /**
  138. * @desc : 新建
  139. * @author : 于继渤
  140. * @date : 2023/1/5 9:39
  141. */
  142. @Transactional(
  143. rollbackFor = {Exception.class}
  144. )
  145. public ResponseResultVO<?> insert(CusFollowVO cusFollowVO) {
  146. CusFollow cusFollow = cusFollowConvert.convertToPo(cusFollowVO);
  147. //设置ID
  148. Map<String, Object> uniqueNoteCode = commonService.getUniqueNoteCode(Constant.docNameConstant.CUSTOMERFOLLOW.getName(), true);
  149. cusFollow.setFollowId(uniqueNoteCode.get("outId").toString());
  150. //跟进时间
  151. cusFollow.setFollowTime(LocalDateTime.now());
  152. //跟进人
  153. cusFollow.setFollowStaff(authUtils.getStaff().getStaffId());
  154. //跟进部门
  155. // cusFollow.setFollowOrg(authUtils.getStaff().getOrgId());
  156. if (cusFollowVO.getCusId() != null) {
  157. //查询客户
  158. Customer customer = customerMapper.selectById(cusFollowVO.getCusId());
  159. // 查询跟进人是否存在
  160. CusFollowStaff followStaff = cusFollowStaffMapper.selectByCusFollowStaffId(cusFollowVO.getCusId(), authUtils.getStaff().getStaffId());
  161. //追加跟进人表
  162. if (followStaff == null) {
  163. cusFollowStaffMapper.insert(new CusFollowStaff()
  164. .setCusId(cusFollowVO.getCusId())
  165. .setFollowStaff(authUtils.getStaff().getStaffId())
  166. .setLastFollowId(authUtils.getStaff().getStaffId())
  167. .setLastFollowTime(LocalDateTime.now())
  168. .setCpId(authUtils.getStaff().getCpId())
  169. .setLastFollowStatus(cusFollowVO.getFollowStatus())
  170. .setFollowCount(1)
  171. );
  172. }
  173. //追加跟进人
  174. List<Long> users = new ArrayList<>();
  175. Object o = customerMapper.selectFollowStaffs(cusFollowVO.getCusId());
  176. if (o != null && o instanceof Long[]) {
  177. users = Arrays.asList((Long[]) o);
  178. }
  179. if (users == null || users.size() == 0 || (users != null && users.stream().allMatch(Objects::isNull))) {
  180. users = new ArrayList<>();
  181. }
  182. //公海客户跟进后 变成潜客状态
  183. if (Constant.saleCustomerStatusConstant.SALE_STATUS_INTE.getName().equals(customer.getSaleStatus())) {
  184. customer.setSaleStatus(Constant.saleCustomerStatusConstant.SALE_STATUS_POTE.getName());
  185. }
  186. //已流失客户重新接待后应该变成潜客
  187. if (Constant.saleCustomerStatusConstant.SALE_STATUS_LOST.getName().equals(customer.getSaleStatus())) {
  188. customer.setSaleStatus(Constant.saleCustomerStatusConstant.SALE_STATUS_POTE.getName());
  189. }
  190. //放入公海客户,清除跟进人
  191. if (Constant.IntentionConstant.SEA.getValue().equals(cusFollowVO.getIntention())) {
  192. customer.setFollowStaffs(new ArrayList<>());
  193. customer.setSaleStatus(Constant.saleCustomerStatusConstant.SALE_STATUS_INTE.getName());
  194. } else {
  195. if (!users.contains(authUtils.getStaff().getStaffId())) {
  196. List arrList = new ArrayList(users);
  197. arrList.add(authUtils.getStaff().getStaffId());
  198. customer.setFollowStaffs(arrList);
  199. }
  200. }
  201. //已流失客户,修改状态为流失
  202. if (Constant.IntentionConstant.LOST.getValue().equals(cusFollowVO.getIntention())) {
  203. customer.setSaleStatus(Constant.saleCustomerStatusConstant.SALE_STATUS_LOST.getName());
  204. }
  205. //如果不是留资接待 修改客户信息
  206. if (!Constant.BasicDataConstant.FOLLOW_STATUS_4.getValue().equals(cusFollowVO.getFollowStatus())) {
  207. customer.setCusName(cusFollowVO.getCusName());
  208. customer.setCusPhone(cusFollowVO.getCusPhone());
  209. customer.setAddressName(cusFollowVO.getAddressName());
  210. customer.setAddressNo(cusFollowVO.getAddressNo());
  211. customer.setAddressGcj02(cusFollowVO.getAddressGcj02());
  212. customer.setAddressFull(cusFollowVO.getAddressFull());
  213. customer.setAddressArea(cusFollowVO.getAddressArea());
  214. }
  215. customer.setCpId(authUtils.getStaff().getCpId());
  216. // 同商户 电话不同
  217. List<CustomerResponse> cusList = customerMapper.selectByCond(
  218. new CustomerQuery().setCpId(customer.getCpId()).setCusPhone(customer.getCusPhone()).setFlgValid(true)
  219. );
  220. // if (cusList != null && cusList.size() > 0 && cusList.stream().anyMatch(a -> !a.getCusId().equals(customer.getCusId()))) {
  221. // throw new BaseBusinessException(ErrorCodeEnum.CUSTOMER_SAME_COMPANY_TELEPHONE.getCode(),
  222. // ErrorCodeEnum.CUSTOMER_SAME_COMPANY_TELEPHONE.getMessage());
  223. // }
  224. customer.setLastFollowId(cusFollow.getFollowId());
  225. customer.setLastFollowTime(cusFollow.getFollowTime());
  226. customer.setLastFollowStaff(cusFollow.getFollowStaff());
  227. //修改跟进次数
  228. customer.setFollowCount(customer.getFollowCount() + 1);
  229. customerService.updateByUuid(customer);
  230. } else if (cusFollowVO.getCusPhone() != null && cusFollowVO.getCusName() != null) {
  231. //留资接待 新建客户
  232. Customer customer = new Customer();
  233. //设置编码
  234. Map<String, Object> customerNoteCode = commonService.getUniqueNoteCode(Constant.docNameConstant.CUSTOMER.getName(), true);
  235. customer.setCusId(customerNoteCode.get("outId").toString());
  236. customer.setCusCode(customerNoteCode.get("outNote").toString());
  237. //TODO 渠道 取当前登录人员工的渠道
  238. customer.setChannelId("10112024-0302-0000-0000-00000759d8a4");
  239. customer.setCusName(cusFollowVO.getCusName());
  240. customer.setCusPhone(cusFollowVO.getCusPhone());
  241. customer.setAddressName(cusFollowVO.getAddressName());
  242. customer.setAddressNo(cusFollowVO.getAddressNo());
  243. customer.setAddressGcj02(cusFollowVO.getAddressGcj02());
  244. customer.setAddressFull(cusFollowVO.getAddressFull());
  245. customer.setAddressArea(cusFollowVO.getAddressArea());
  246. customer.setReportStaff(authUtils.getStaff().getStaffId());
  247. customer.setReportTime(LocalDateTime.now());
  248. customer.setCpId(authUtils.getStaff().getCpId());
  249. customer.setStaffId(authUtils.getStaff().getStaffId());
  250. customer.setOrgId(cusFollowVO.getFollowOrg());
  251. customer.setFollowCount(1);
  252. customer.setLastFollowId(cusFollow.getFollowId());
  253. customer.setLastFollowTime(cusFollow.getFollowTime());
  254. customer.setLastFollowStaff(cusFollow.getFollowStaff());
  255. cusFollow.setCusId(customer.getCusId());
  256. // 同商户 电话不同
  257. Long count = customerMapper.countByCond(
  258. new CustomerQuery().setCpId(customer.getCpId()).setCusPhone(customer.getCusPhone()).setFlgValid(true)
  259. );
  260. // if (count > 0) {
  261. // return ResponseResultUtil.error(ErrorCodeEnum.CUSTOMER_SAME_COMPANY_TELEPHONE.getCode(),
  262. // ErrorCodeEnum.CUSTOMER_SAME_COMPANY_TELEPHONE.getMessage());
  263. // }
  264. //放入公海客户,清除跟进人
  265. if (Constant.IntentionConstant.SEA.getValue().equals(cusFollowVO.getIntention())) {
  266. customer.setFollowStaffs(new ArrayList<>());
  267. customer.setSaleStatus(Constant.saleCustomerStatusConstant.SALE_STATUS_INTE.getName());
  268. } else {
  269. //当前跟进人(业务员)
  270. customer.setFollowStaffs(new ArrayList<String>() {{
  271. add(authUtils.getStaff().getStaffId());
  272. }});
  273. customer.setSaleStatus(Constant.saleCustomerStatusConstant.SALE_STATUS_POTE.getName());
  274. }
  275. //新建客户或编辑客户
  276. customerMapper.insert(customer);
  277. }
  278. // 约量尺
  279. if (Constant.BasicDataConstant.FOLLOW_STATUS_3.getValue().equals(cusFollow.getFollowStatus())) {
  280. // 量尺状态:待量尺
  281. cusFollow.setMeasureStatus(Constant.BasicDataConstant.MEASURE_STATUS_2.getValue());
  282. }
  283. if (cusFollow.getFollowData() == null) {
  284. cusFollow.setFollowData("无");
  285. }
  286. super.insert(cusFollow);
  287. //设计师
  288. StaffResponse designStaff = null;
  289. if (cusFollow.getDesignStaff() != null) {
  290. designStaff = staffMapper.selectById(cusFollow.getDesignStaff());
  291. }
  292. // 只要有跟进日期
  293. if (cusFollow.getNextFollowTime() != null) {
  294. // 保存跟进信息
  295. saveToXxlJob(cusFollow);
  296. }
  297. return ResponseResultUtil.success();
  298. }
  299. /**
  300. * @desc : 客户跟进提醒回调
  301. * @author : 姜永辉
  302. * @date : 2022-06-29 14:22
  303. */
  304. @Transactional(rollbackFor = {Exception.class})
  305. @XxlJob("customer-reminder")
  306. public ResponseResultVO customerReminder() {
  307. log.info("@XxlJob(\"customer-reminder\")");
  308. log.info("followPlan id: {}", XxlJobHelper.getJobParam());
  309. // String planid = "10112024-0715-0000-0000-0004a8b4d1e6";
  310. FollowPlan followPlan = followPlanMapper.selectById(XxlJobHelper.getJobParam());
  311. if (followPlan != null) {
  312. CusFollow follow = cusFollowMapper.selectById(followPlan.getFollowId());
  313. if (follow != null) {
  314. FollowPlan plan = new FollowPlan().setPlanId(followPlan.getPlanId());
  315. try {
  316. //发消息
  317. String msg = sendFollowMessage(follow, followPlan);
  318. if (msg == null) {
  319. plan.setCallStatus(Constant.CallStatus.CALL_STATUS_DONE.getName() + "");
  320. } else {
  321. plan.setCallStatus(Constant.CallStatus.CALL_STATUS_ERROR.getName() + "").setRemarks(msg);
  322. }
  323. } catch (Exception e) {
  324. e.printStackTrace();
  325. log.error("客户跟进发送消息异常:{}", e.getMessage());
  326. plan.setCallStatus(Constant.CallStatus.CALL_STATUS_ERROR.getName() + "").setRemarks(e.getMessage());
  327. }
  328. //修改状态
  329. followPlanMapper.update(plan,
  330. new UpdateWrapper<FollowPlan>().lambda()
  331. .eq(FollowPlan::getPlanId, UUID.fromString(plan.getPlanId())));
  332. //删除任务
  333. xxlJobUtils.delete(followPlan.getXxlJobId());
  334. }
  335. }
  336. return null;
  337. }
  338. /**
  339. * @desc : 客户计划任务提醒回调
  340. * @author : jyh
  341. * @date : 2022-06-29 14:22
  342. */
  343. @Transactional(rollbackFor = {Exception.class})
  344. @XxlJob("plan-reminder")
  345. public void planReminder() {
  346. log.info("@XxlJob(\"plan-reminder\")");
  347. log.info("followPlan id: {}", XxlJobHelper.getJobParam());
  348. // String planid = "10112024-0715-0000-0000-0004a8b4d1e6";
  349. FollowPlan followPlan = followPlanMapper.selectById(XxlJobHelper.getJobParam());
  350. if (followPlan != null && followPlan.getFlgValid()) {
  351. FollowPlan plan = new FollowPlan().setPlanId(followPlan.getPlanId());
  352. try {
  353. //发消息
  354. String msg = sendFollowPlanMessage(followPlan);
  355. if (msg == null) {
  356. plan.setCallStatus(Constant.CallStatus.CALL_STATUS_DONE.getName() + "");
  357. } else {
  358. plan.setCallStatus(Constant.CallStatus.CALL_STATUS_ERROR.getName() + "").setRemarks(msg);
  359. }
  360. } catch (Exception e) {
  361. e.printStackTrace();
  362. log.error("跟进任务发送消息异常:{}", e.getMessage());
  363. plan.setCallStatus(Constant.CallStatus.CALL_STATUS_ERROR.getName() + "").setRemarks(e.getMessage());
  364. }
  365. //修改状态
  366. followPlanMapper.updateById(plan);
  367. //删除任务
  368. xxlJobUtils.delete(followPlan.getXxlJobId());
  369. }
  370. }
  371. /**
  372. * @desc : 发送跟进消息
  373. * @author : 姜永辉
  374. * @date : 2022-05-27 09:34
  375. */
  376. public String sendFollowMessage(CusFollow follow, FollowPlan followPlan) {
  377. log.info("sendFollowMessage:{}", JSONObject.toJSONString(follow));
  378. // 跟进人
  379. StaffResponse followStaff = staffMapper.selectById(followPlan.getFollowUser());
  380. //查到跟进人
  381. if (followStaff != null) {
  382. log.info("sendFollowMessage:{}", JSONObject.toJSONString(followStaff));
  383. Customer customer = customerMapper.selectById(follow.getCusId());
  384. if (customer != null) {
  385. String loginType = "4";
  386. List<String> list = new ArrayList<>();
  387. if (Constant.BasicDataConstant.FOLLOW_STATUS_4.getValue().equals(follow.getFollowStatus()) ||
  388. Constant.BasicDataConstant.FOLLOW_STATUS_1.getValue().equals(follow.getFollowStatus())) {
  389. list.add("您有客户需要跟进");
  390. loginType = "4";
  391. } else if (Constant.BasicDataConstant.FOLLOW_STATUS_6.getValue().equals(follow.getFollowStatus())) {
  392. list.add("您有客户需要量尺服务");
  393. loginType = "6";
  394. } else if (Constant.BasicDataConstant.FOLLOW_STATUS_2.getValue().equals(follow.getFollowStatus())) {
  395. list.add("您有客户邀约进店");
  396. loginType = "2";
  397. } else if (Constant.BasicDataConstant.FOLLOW_STATUS_3.getValue().equals(follow.getFollowStatus())) {
  398. list.add("您有客户需要约尺服务");
  399. loginType = "3";
  400. }
  401. list.add(customer.getCusName());
  402. list.add(customer.getCusPhone());
  403. // 查询跟进人的openid和publicOpenId
  404. ResponseResultVO<?> resultVO = userFeign.getUser(followStaff.getWxUserId());
  405. // 如果没有成功返回,状态设置为待审
  406. if (resultVO.getCode() != ResponseCodeEnum.SUCCESS.getCode()) {
  407. log.error("客户查询异常:为空{}", follow.getCusId());
  408. return ResponseCodeEnum.SELECT_NULL.getMessage();
  409. } else {
  410. Map<String, Object> user = (Map<String, Object>) resultVO.getData();
  411. if (user != null) {
  412. // 发送消息
  413. Map<String, Object> mapMessage = new HashMap<>();
  414. mapMessage.put("loginType", loginType);
  415. mapMessage.put("otherParam", follow);
  416. mapMessage.put("publicOpenId", user.get("publicOpenId"));
  417. mapMessage.put("first", "客户跟进提醒");
  418. mapMessage.put("keywordList", list);
  419. mapMessage.put("remark", "客户跟进备注");
  420. sendUniformMessage(mapMessage);
  421. }
  422. }
  423. return null;
  424. } else {
  425. log.error("客户查询异常:为空{}", follow.getCusId());
  426. return ResponseCodeEnum.SELECT_NULL.getMessage();
  427. }
  428. } else {
  429. log.error("跟进人异常:为空{}", followPlan.getFollowUser());
  430. return ResponseCodeEnum.SELECT_NULL.getMessage();
  431. }
  432. }
  433. /**
  434. * @author : sh4wmoo
  435. * @date : 2021-7-20 13:49
  436. * @desc : iBOSS推送公众号消息卡片
  437. */
  438. public ResponseResultVO sendUniformMessage(Map<String, Object> map) {
  439. log.info("推送参数:{}", JSON.toJSONString(map));
  440. // 3.获取token 231011
  441. String token = this.getWxPublicAccountToken(); //this.getToken();
  442. log.info("当前token:{}", token);
  443. // 4.发送模板卡片 230927 地址发生变化
  444. ResponseResultVO<JSONObject> res = HttpUtils.post(config.getUniformSend() + token, new HashMap<String, Object>(4) {{
  445. // 新加POST数据示例如下 240712
  446. put("touser", map.get("publicOpenId") + "");
  447. put("template_id", config.getTemplateId());
  448. put("miniprogram", new HashMap<String, Object>(4) {{
  449. put("appid", config.getAppId());
  450. //用户点击公众号推送消息跳转小程序单据详情页 orderType 里面存放json字符串数据
  451. //判断InvoiceParam
  452. if (map.containsKey("otherParam")) {
  453. put("pagepath", "pages/login/login?loginType=" + map.get("loginType").toString() + "&otherParam=" + map.get("otherParam").toString());
  454. } else {
  455. put("pagepath", "pages/login/login?loginType=" + map.get("loginType").toString());
  456. }
  457. }});
  458. put("data", new HashMap<String, Object>(16) {{
  459. put("first", new HashMap<String, Object>(4) {{
  460. put("value", map.get("first").toString());
  461. put("color", "#173177");
  462. }});
  463. List<String> keywordList = (List<String>) map.get("keywordList");
  464. //lambda foreach 取下标
  465. IntStream.range(0, keywordList.size()).forEach(i -> {
  466. String keyIndex = "keyword" + (i + 1);
  467. put(keyIndex, new HashMap<String, Object>(4) {{
  468. put("value", keywordList.get(i));
  469. put("color", "#173177");
  470. }});
  471. });
  472. put("remark", new HashMap<String, Object>(4) {{
  473. put("value", map.get("remark").toString());
  474. put("color", "#173177");
  475. }});
  476. }});
  477. }});
  478. if (res.getCode() == ResponseCodeEnum.SUCCESS.getCode() && res.getData().getString("errcode").equals("0")) {
  479. log.info("推送成功:{}");
  480. return ResponseResultUtil.success();
  481. } else {
  482. log.error("推送失败:{}", res.getData().toJSONString());
  483. return ResponseResultUtil.error(res.getData().toJSONString());
  484. }
  485. }
  486. /**
  487. * @author : jyh
  488. * @date : 2023-10-11 16:23
  489. * @desc : 调用中控服务获取公众号的token
  490. */
  491. public String getWxPublicAccountToken() {
  492. JSONObject json = new JSONObject();
  493. //有效期30天,最大可设置30天
  494. json.put("appId", config.getWxPublicAccountAppId());
  495. json.put("appSecret", config.getWxPublicAccountAppSecret());
  496. ResponseResultVO<JSONObject> res = HttpUtils.post(config.getWechatUrlToken(),
  497. new HashMap<String, Object>() {{
  498. put("appId", config.getWxPublicAccountAppId());
  499. put("appSecret", config.getWxPublicAccountAppSecret());
  500. }});
  501. // ResponseResultVO<JSONObject> res = HttpUtils.post(config.getWechatUrlToken(),json);
  502. if (res.getCode() == 200 && JSON.parseObject(JSON.toJSONString(res.getData())).get("code").toString().equals("200")) {
  503. return JSON.parseObject(JSON.toJSONString(res.getData())).get("data").toString();
  504. } else {
  505. throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), res.getMessage());
  506. }
  507. }
  508. /**
  509. * @desc : 发送跟进任务消息
  510. * @author : 姜永辉
  511. * @date : 2022-06-30 19:24
  512. */
  513. public String sendFollowPlanMessage(FollowPlan followPlan) {
  514. log.info("sendFollowMessage:{}", JSONObject.toJSONString(followPlan));
  515. // 跟进人
  516. StaffResponse followStaff = staffMapper.selectById(followPlan.getFollowUser());
  517. Customer customer = customerMapper.selectById(new CustomerQuery().setCusId(followPlan.getCusId()));
  518. if (customer != null) {
  519. // 小程序消息
  520. return null;
  521. } else {
  522. return ResponseCodeEnum.SELECT_NULL.getMessage();
  523. }
  524. }
  525. /**
  526. * @desc : 保存跟进信息到xxl job
  527. * @author : 于继渤海
  528. * @date : 2022-05-27 09:53
  529. */
  530. @Transactional(rollbackFor = {Exception.class})
  531. public void saveToXxlJob(CusFollow cusFollow) {
  532. //设置ID
  533. Map<String, Object> uniqueNoteCode = commonService.getUniqueNoteCode(Constant.docNameConstant.FOLLOWPLAN.getName(), true);
  534. String nextId = uniqueNoteCode.get("outId").toString();
  535. // 约量尺 && 接受邀约
  536. // 预约量尺,邀约结果接受,通知设计师提醒时间是(服务时间);邀约结果拒绝,通知创建者提醒时间是(提醒时间)
  537. if (Constant.BasicDataConstant.FOLLOW_STATUS_3.getValue().equals(cusFollow.getFollowStatus()) &&
  538. Constant.BasicDataConstant.FOLLOW_INVITE_RESULT.getValue().equals(cusFollow.getInviteResult())) {
  539. cusFollow.setNextFollowTime(cusFollow.getInviteTime()).setFollowStaff(cusFollow.getDesignStaff());
  540. }
  541. int id = xxlJobUtils.create(Math.toIntExact(
  542. (cusFollow.getNextFollowTime().toInstant(ZoneOffset.of("+8")).toEpochMilli() - System.currentTimeMillis()) / 1000
  543. ), nextId, Constant.XxlJobInfo.FOLLOW.getValue());
  544. // 生成主键
  545. followPlanMapper.insert(
  546. new FollowPlan().setPlanId(nextId).setCusId(cusFollow.getCusId())
  547. .setPlanType(Constant.IntegerConstant.PLAN_TYPE_FOLLOW.getValue())
  548. .setFollowId(cusFollow.getFollowId())
  549. .setFollowUser(cusFollow.getFollowStaff())
  550. .setNextFollowPlan(cusFollow.getNextFollowPlan())
  551. .setNextFollowTime(cusFollow.getNextFollowTime())
  552. .setCallStatus(Constant.CallStatus.CALL_STATUS_UN_DONE.getName() + "")
  553. .setXxlJobId(id)
  554. .setOpAppCode(Constant.AppCode.WEIXIN.getCode() + "")
  555. .setCpId(cusFollow.getCpId())
  556. );
  557. }
  558. /**
  559. * @desc : 新建量尺回执
  560. * @author : 于继渤
  561. * @date : 2023/1/5 9:39
  562. */
  563. @Transactional(
  564. rollbackFor = {Exception.class}
  565. )
  566. public ResponseResultVO<?> saveMeasure(CusFollowVO cusFollowVO) {
  567. CusFollow cusFollow = cusFollowConvert.convertToPo(cusFollowVO);
  568. //更新总单
  569. // int update = cusFollowMapper.updateMeasure(cusFollow);
  570. //更新客户信息
  571. Customer customer = new Customer();
  572. customer.setCusId(cusFollowVO.getCusId());
  573. customer.setCusName(cusFollowVO.getCusName());
  574. customer.setCusPhone(cusFollowVO.getCusPhone());
  575. customer.setAddressName(cusFollowVO.getAddressName());
  576. customer.setAddressNo(cusFollowVO.getAddressNo());
  577. customer.setAddressFull(cusFollowVO.getAddressFull()); //全路径地址
  578. customer.setAddressArea(cusFollowVO.getAddressArea()); //省市区
  579. customer.setAddressGcj02(cusFollowVO.getAddressGcj02());//经纬度
  580. customerService.updateByUuid(customer);
  581. CusFollow Follow = cusFollowMapper.selectById(cusFollowVO.getFollowId());
  582. if (Follow == null) {
  583. return ResponseResultUtil.error(ResponseCodeEnum.SELECT_NULL);
  584. } else if (Constant.BasicDataConstant.MEASURE_STATUS_1.getValue().equals(Follow.getMeasureStatus())) {
  585. return ResponseResultUtil.error(ErrorCodeEnum.CUSTOMER_FOLLOW_MEASURE_STATUS_DONE.getCode(),
  586. ErrorCodeEnum.CUSTOMER_FOLLOW_MEASURE_STATUS_DONE.getMessage());
  587. }
  588. StaffEntity staff = authUtils.getStaff();
  589. //设置id
  590. Map<String, Object> uniqueNoteCode = commonService.getUniqueNoteCode(Constant.docNameConstant.RECEIPT.getName(), true);
  591. // 新建一条量尺记录
  592. MeasureReceipt measureReceipt = new MeasureReceipt();
  593. if (cusFollowVO.getFlgAgainMeasure() != null) {
  594. measureReceipt.setFlgAgainMeasure(cusFollowVO.getFlgAgainMeasure());
  595. } else {
  596. measureReceipt.setFlgAgainMeasure(false);
  597. }
  598. measureReceipt.setReceiptId(uniqueNoteCode.get("outId").toString());
  599. measureReceipt.setCusId(cusFollowVO.getCusId());
  600. measureReceipt.setFollowId(cusFollowVO.getFollowId());
  601. measureReceipt.setMeasureStatus(Constant.BasicDataConstant.MEASURE_STATUS_1.getValue());
  602. measureReceipt.setMeasureTime(LocalDateTime.now());
  603. measureReceipt.setMeasureRemarks(cusFollowVO.getMeasureRemarks());
  604. //剩下参数有前台传
  605. measureReceiptService.insert(measureReceipt);
  606. // 新建空间
  607. if (cusFollowVO.getMeasureRoomList() != null && cusFollowVO.getMeasureRoomList().size() > 0) {
  608. for (MeasureRoom measureRoom : cusFollowVO.getMeasureRoomList()) {
  609. //设置ID
  610. Map<String, Object> uniqueNoteCode1 = commonService.getUniqueNoteCode(Constant.docNameConstant.ROOM.getName(), true);
  611. measureRoom.setRoomId(uniqueNoteCode1.get("outId").toString());
  612. measureRoom.setFollowId(cusFollowVO.getFollowId());
  613. measureRoom.setCusId(cusFollowVO.getCusId());
  614. measureRoom.setCpId(authUtils.getStaff().getCpId());
  615. measureRoom.setReceiptId(measureReceipt.getReceiptId());
  616. measureRoomService.insert(measureRoom);
  617. }
  618. }
  619. //修改量尺状态为 已量尺
  620. cusFollow.setMeasureStatus(Constant.BasicDataConstant.MEASURE_STATUS_1.getValue());
  621. //修改跟进
  622. super.updateByUuid(cusFollow);
  623. return ResponseResultUtil.success();
  624. }
  625. /**
  626. * @desc : 编辑量尺回执
  627. * @author : 于继渤
  628. * @date : 2023/1/5 9:39
  629. */
  630. @Transactional(
  631. rollbackFor = {Exception.class}
  632. )
  633. public ResponseResultVO<?> updateMeasure(MeasureReceiptVO measureReceipt) {
  634. // 新建空间
  635. if (measureReceipt.getMeasureRoomList() != null && measureReceipt.getMeasureRoomList().size() > 0) {
  636. for (MeasureRoom measureRoom : measureReceipt.getMeasureRoomList()) {
  637. if (measureRoom.getRoomId() != null) {
  638. measureRoomMapper.deleteByUuid(measureRoom.getRoomId());
  639. //设置ID
  640. Map<String, Object> uniqueNoteCode1 = commonService.getUniqueNoteCode(Constant.docNameConstant.ROOM.getName(), true);
  641. measureRoom.setRoomId(uniqueNoteCode1.get("outId").toString());
  642. measureRoom.setFollowId(measureReceipt.getFollowId());
  643. measureRoom.setCusId(measureReceipt.getCusId());
  644. measureRoom.setCpId(authUtils.getStaff().getCpId());
  645. measureRoom.setReceiptId(measureReceipt.getReceiptId());
  646. measureRoomService.insert(measureRoom);
  647. }
  648. }
  649. MeasureReceipt measureReceipt1 = measureReceiptConvert.convertToPo(measureReceipt);
  650. measureReceiptService.updateByUuid(measureReceipt1);
  651. }
  652. return ResponseResultUtil.success();
  653. }
  654. /**
  655. * @desc : 编辑
  656. * @author : 于继渤
  657. * @date : 2024-03-13 17:03
  658. */
  659. @Transactional(rollbackFor = {Exception.class})
  660. public ResponseResultVO<?> update(CusFollowVO cusFollowVO) {
  661. CusFollow cusFollow = cusFollowConvert.convertToPo(cusFollowVO);
  662. //编辑时更改客户意向要把对应客户也需要更改
  663. if (cusFollowVO.getSaleStatus() != null && (cusFollowVO.getSaleStatus().equals(Constant.saleCustomerStatusConstant.SALE_STATUS_INTE.getName()) || cusFollowVO.getSaleStatus().equals(Constant.saleCustomerStatusConstant.SALE_STATUS_LOST.getName()))) {
  664. //公海客户清空跟进人
  665. if (cusFollowVO.getSaleStatus().equals(Constant.saleCustomerStatusConstant.SALE_STATUS_INTE.getName())) {
  666. customerMapper.updateFollowStaffs(new Customer().setCusId(cusFollowVO.getCusId()).setFollowStaffs(null));
  667. }
  668. }
  669. if (cusFollowVO.getCusId() != null) {
  670. Customer customer = new Customer();
  671. customer.setCusId(cusFollowVO.getCusId());
  672. customer.setAddressName(cusFollowVO.getAddressName());
  673. customer.setAddressNo(cusFollowVO.getAddressNo());
  674. customer.setCusPhone(cusFollowVO.getCusPhone());
  675. customer.setCusName(cusFollowVO.getCusName());
  676. customer.setOrgId(cusFollowVO.getFollowOrg());
  677. customer.setAddressFull(cusFollowVO.getAddressFull());
  678. customer.setAddressArea(cusFollowVO.getAddressArea());
  679. customer.setSaleStatus(cusFollowVO.getSaleStatus());
  680. customer.setAddressGcj02(cusFollowVO.getAddressGcj02());
  681. //更新客户信息
  682. customerService.updateByUuid(customer);
  683. } else {
  684. //不是陌生接待
  685. if (!cusFollowVO.getFollowStatus().equals(Constant.BasicDataConstant.FOLLOW_STATUS_4.getValue())) {
  686. StaffEntity staff = authUtils.getStaff();
  687. Customer customer = new Customer();
  688. customer.setCusName(cusFollowVO.getCusName());
  689. customer.setCusPhone(cusFollowVO.getCusPhone());
  690. customer.setAddressName(cusFollowVO.getAddressName());
  691. customer.setAddressNo(cusFollowVO.getAddressNo());
  692. customer.setOrgId(cusFollowVO.getFollowOrg());
  693. customer.setAddressFull(cusFollowVO.getAddressFull());
  694. customer.setAddressArea(cusFollowVO.getAddressArea());
  695. customer.setSaleStatus(cusFollowVO.getSaleStatus());
  696. customer.setAddressGcj02(cusFollowVO.getAddressGcj02());
  697. customer.setReportStaff(cusFollowVO.getFollowStaff());
  698. customer.setReportTime(LocalDateTime.now());
  699. customer.setCpId(staff.getCpId());
  700. List<String> list = new ArrayList<>();
  701. list.add(staff.getStaffId());
  702. customer.setFollowStaffs(list);
  703. customer.setSaleStatus("客成状态-潜客");
  704. customer.setChannelId(cusFollowVO.getChannelId());
  705. Map<String, Object> customerNoteCode = commonService.getUniqueNoteCode(Constant.docNameConstant.CUSTOMER.getName(), true);
  706. customer.setCusId(customerNoteCode.get("outId").toString());
  707. //新建客户
  708. customerMapper.insert(customer);
  709. cusFollow.setCusId(customer.getCusId());
  710. }
  711. }
  712. //更新总单
  713. super.updateByUuid(cusFollow);
  714. return ResponseResultUtil.success();
  715. }
  716. public ResponseResultVO<List<Map>> selectCusFollow(CusFollowQuery cusFollowQuery) {
  717. return ResponseResultUtil.success(cusFollowMapper.selectCusFollow(cusFollowQuery));
  718. }
  719. public ResponseResultVO<?> wxMessagePush(HttpServletRequest request) {
  720. // 获取微信Token
  721. String wxToken = getWxToken();
  722. Map<String, Object> params = new HashMap<>();
  723. // 接口调用凭证
  724. params.put("access_token", wxToken);
  725. // 所需下发的订阅模板id
  726. params.put("template_id", "z3REuwft6NLPxVW8s5HN1RH_gVxN9KPH7boGh92shYs");
  727. // 点击模板卡片后的跳转页面
  728. params.put("page", "pages/login/login");
  729. // 接收者(用户)的 openid
  730. params.put("touser", "oNIC56z-NuTQYlzfnupF_ZEo9agc");
  731. // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;
  732. params.put("miniprogram_state", "developer");
  733. // 构造对应的显示信息 和模板数据结构对应
  734. JSONObject data = new JSONObject();
  735. data.put("time4", createDataItem("value", "2024年07月18日"));
  736. data.put("thing1", createDataItem("value", "ly"));
  737. data.put("phone_number2", createDataItem("value", "19841226666"));
  738. data.put("time7", createDataItem("value", "2024年07月18日"));
  739. data.put("thing5", createDataItem("value", "666"));
  740. params.put("data", data);
  741. ResponseResultVO<JSONObject> post = HttpUtils.post("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + wxToken, params);
  742. return post;
  743. }
  744. private static Map<String, Object> createDataItem(String name, String value) {
  745. Map<String, Object> item = new HashMap<>();
  746. item.put("value", value);
  747. return item;
  748. }
  749. public void wxMessageTest(HttpServletRequest request, HttpServletResponse response) {
  750. String signature = request.getParameter("signature");
  751. String timestamp = request.getParameter("timestamp");
  752. String nonce = request.getParameter("nonce");
  753. String echostr = request.getParameter("echostr");
  754. // 和小程序后台配置的token保持一致
  755. String token = "dPM4EILWQqeEsEmft9pKMIll4VGZ6pJK";
  756. // 将下面三个参数拼接成字符串
  757. StringBuffer content = new StringBuffer();
  758. content.append(timestamp);
  759. content.append(nonce);
  760. content.append(token);
  761. PrintWriter out = null;
  762. try {
  763. out = response.getWriter();
  764. MessageDigest md = MessageDigest.getInstance("SHA-1");
  765. // 对拼接好的字符串进行sha1加密
  766. byte[] digest = md.digest(content.toString().getBytes());
  767. String tmpStr = byteToStr(digest);
  768. //获得加密后的字符串与signature对比
  769. if (tmpStr != null && tmpStr.equals(signature.toUpperCase())){
  770. out.print(echostr);
  771. out.flush();
  772. }
  773. } catch (NoSuchAlgorithmException e) {
  774. e.printStackTrace();
  775. } catch (IOException e) {
  776. e.printStackTrace();
  777. } finally {
  778. out.close();
  779. }
  780. }
  781. private String getWxToken(){
  782. String appId = config.getAppId();
  783. String appSecret = config.getAppSecret();
  784. ResponseResultVO<JSONObject> tokenRes = HttpUtils.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret);
  785. JSONObject data = tokenRes.getData();
  786. return String.valueOf(data.get("access_token"));
  787. }
  788. private static String byteToStr(byte[] byteArray) {
  789. String strDigest = "";
  790. for (int i = 0; i < byteArray.length; i++) {
  791. strDigest += byteToHexStr(byteArray[i]);
  792. }
  793. return strDigest;
  794. }
  795. private static String byteToHexStr(byte mByte) {
  796. char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
  797. 'B', 'C', 'D', 'E', 'F' };
  798. char[] tempArr = new char[2];
  799. tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
  800. tempArr[1] = Digit[mByte & 0X0F];
  801. String s = new String(tempArr);
  802. return s;
  803. }
  804. }