CmsGroupServiceImpl.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. package com.cyksj.service.mange.group;
  2. import cn.hutool.core.date.DateField;
  3. import cn.hutool.core.date.DateTime;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.util.StrUtil;
  6. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  7. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  8. import com.cyksj.common.EnvCommonService;
  9. import com.cyksj.common.constant.Constant;
  10. import com.cyksj.common.exception.BusinessRuntimeException;
  11. import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
  12. import com.cyksj.dto.RedisKey;
  13. import com.cyksj.mapper.*;
  14. import com.cyksj.mapper.manage.GroupsTripsAccountReplaceRecordMapper;
  15. import com.cyksj.mapper.manage.cms.CmsUserMapper;
  16. import com.cyksj.model.entity.*;
  17. import com.cyksj.model.manage.views.AccountView;
  18. import com.cyksj.model.request.ReplaceTripsAccountReq;
  19. import com.cyksj.model.views.GroupsAccountView;
  20. import com.cyksj.redis.RedisService;
  21. import com.cyksj.service.mange.AccountCommonService;
  22. import com.cyksj.service.mange.CmsGroupService;
  23. import com.cyksj.service.sms.SmsService;
  24. import com.ejlchina.searcher.BeanSearcher;
  25. import com.ejlchina.searcher.param.Operator;
  26. import com.ejlchina.searcher.util.MapBuilder;
  27. import com.ejlchina.searcher.util.MapUtils;
  28. import lombok.RequiredArgsConstructor;
  29. import lombok.extern.slf4j.Slf4j;
  30. import org.springframework.stereotype.Service;
  31. import org.springframework.transaction.annotation.Transactional;
  32. import java.util.Arrays;
  33. import java.util.Date;
  34. import java.util.List;
  35. import java.util.Optional;
  36. import java.util.stream.Collectors;
  37. /**
  38. * @author chan
  39. * @date 2022/9/27 6:27 PM
  40. */
  41. @Slf4j
  42. @Service
  43. @RequiredArgsConstructor
  44. public class CmsGroupServiceImpl extends ServiceImpl<GroupsMapper,GroupsTrips> implements CmsGroupService {
  45. private final GoodsDonSkuMapper skuMapper;
  46. private final GroupsRelationMapper relationMapper;
  47. private final OrderDonMapper orderDonMapper;
  48. private final AccountMapper accountMapper;
  49. private final BeanSearcher beanSearcher;
  50. private final GroupsTripsAccountReplaceRecordMapper replaceRecordMapper;
  51. private final CmsUserMapper cmsUserMapper;
  52. private final GoodsDonMapper goodsDonMapper;
  53. private final SmsService smsService;
  54. private final EnvCommonService envCommonService;
  55. private final RedisService redisService;
  56. private final GroupsMapper groupsMapper;
  57. private final AccountCommonService accountCommonService;
  58. private final GroupsRelationAlertMapper alertMapper;
  59. private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
  60. @Override
  61. public GroupsTrips issuance(GroupsTrips groups, String verifyCodes) {
  62. GoodsDonSku sku = skuMapper.selectById(groups.getSkuId());
  63. if (sku == null) {
  64. throw new BusinessRuntimeException("该商品规格不存在!");
  65. }
  66. List<String> verifyCodeList = null;
  67. if (StrUtil.isNotBlank(verifyCodes)) {
  68. verifyCodes = verifyCodes.replaceAll("\n", "");
  69. String[] verifyCodeArray = verifyCodes.split("\\*");
  70. verifyCodeList = Arrays.stream(verifyCodeArray).filter(str -> StrUtil.isNotBlank(str)).map(str -> str.trim()).collect(Collectors.toList());
  71. }
  72. groups.setNum(sku.getNum());
  73. groups.setAvailableNum(sku.getNum());
  74. if (groups.getAccountId() == null || accountMapper.selectById(groups.getAccountId()) == null) {
  75. throw new BusinessRuntimeException("该账号不存在");
  76. }
  77. groups.setStatus(GroupsTrips.Status.validity);
  78. this.save(groups);
  79. for (Integer i = 1; i <= groups.getNum(); i++) {
  80. GroupsRelation relation = new GroupsRelation();
  81. relation.setGroupsId(groups.getId());
  82. relation.setStatus(GroupsRelation.Status.none);
  83. relation.setNum(i);
  84. if (verifyCodeList != null && verifyCodeList.size() > 0 && verifyCodeList.size() >= i) {
  85. relation.setVerifyCode(verifyCodeList.get(i - 1));
  86. }
  87. relationMapper.insert(relation);
  88. }
  89. Integer alertCount = alertMapper.selectCount(Wrappers.lambdaQuery(GroupsRelationAlert.class)
  90. .eq(GroupsRelationAlert::getSkuId, sku.getId())
  91. .last("limit 1"));
  92. if (alertCount > 0) {
  93. alertMapper.update(null, Wrappers.lambdaUpdate(GroupsRelationAlert.class)
  94. .set(GroupsRelationAlert::getIsReset, true)
  95. .eq(GroupsRelationAlert::getSkuId, sku.getId())
  96. .eq(GroupsRelationAlert::getIsReset, false));
  97. }
  98. return groups;
  99. }
  100. @Override
  101. public void close(Long groupId) {
  102. GroupsTrips groupsTrips = this.getById(groupId);
  103. if(groupsTrips == null){
  104. throw new BusinessRuntimeException("非法参数.车队不存在");
  105. }
  106. Integer count = relationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class)
  107. .eq(GroupsRelation::getGroupsId, groupId)
  108. .ne(GroupsRelation::getUserId, 0)
  109. .ne(GroupsRelation::getStatus, GroupsRelation.Status.none));
  110. if (count > 0) {
  111. throw BusinessRuntimeException.getInstance("请移除该车队下的用户再进行删掉操作");
  112. }
  113. //可强制删除
  114. //后台记录
  115. // if (count > 0) {
  116. // List<GroupsRelation> groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class)
  117. // .eq(GroupsRelation::getGroupsId, groupId)
  118. // .ne(GroupsRelation::getStatus, GroupsRelation.Status.none));
  119. // if (groupsRelations.size() > 0) {
  120. // Account account = accountMapper.selectById(groupsTrips.getAccountId());
  121. // TASK_EXECUTOR.execute(() -> {
  122. // if (redisService.setNx(String.format("%s-%s", groupId, groupsTrips.getAccount()), groupId, 10l)) {
  123. // groupsRelations.forEach(data -> {
  124. // DelGroupsTripsRecord delGroupsTripsRecord = new DelGroupsTripsRecord();
  125. // delGroupsTripsRecord.setGroupsId(groupId);
  126. // delGroupsTripsRecord.setGroupsStatus(groupsTrips.getStatus().name());
  127. // if (account != null) {
  128. // delGroupsTripsRecord.setAccount(account.getAccount());
  129. // delGroupsTripsRecord.setPassword(account.getPassword());
  130. // }
  131. // delGroupsTripsRecord.setRelationId(data.getId());
  132. // delGroupsTripsRecord.setSkuId(groupsTrips.getSkuId());
  133. // delGroupsTripsRecord.setUserId(data.getUserId());
  134. // delGroupsTripsRecord.setStartTime(data.getStartTime());
  135. // delGroupsTripsRecord.setExpiryTime(data.getExpiryTime());
  136. // delGroupsTripsRecord.setRelationStatus(data.getStatus().name());
  137. // delGroupsTripsRecord.setType("delete");
  138. // delGroupsTripsRecordMapper.insert(delGroupsTripsRecord);
  139. // });
  140. // }
  141. // });
  142. // }
  143. // }
  144. relationMapper.delete(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId,groupId));
  145. this.removeById(groupId);
  146. }
  147. @Override
  148. @Transactional(rollbackFor = Throwable.class)
  149. public void setAccount(GroupsTrips groupsTrips) throws Exception {
  150. int count = count(Wrappers.lambdaQuery(GroupsTrips.class).eq(GroupsTrips::getAccountId, groupsTrips.getAccountId()));
  151. if (count > 0) {
  152. throw new BusinessRuntimeException("该账号已发车.请选择未发车账户");
  153. }
  154. Account account = accountMapper.selectById(groupsTrips.getAccountId());
  155. //将预备账号 类型替换掉
  156. if (account.getType() == 2) {
  157. int update = accountMapper.update(null, Wrappers.lambdaUpdate(Account.class)
  158. .set(Account::getType, 1)
  159. .eq(Account::getId, account.getId())
  160. .eq(Account::getType, 2));
  161. if (update == 0) {
  162. throw BusinessRuntimeException.getInstance("该账号已配置车队");
  163. }
  164. }
  165. List<GroupsRelation> groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsTrips.getId()).eq(GroupsRelation::getStatus, GroupsRelation.Status.validity));
  166. GroupsTrips trips = beanSearcher.searchFirst(GroupsTrips.class, MapUtils.builder().field(GroupsTrips::getId, groupsTrips.getId()).onlySelect(GroupsTrips::getTitle).build());
  167. String title = "车票";
  168. if (trips != null && StrUtil.isNotBlank(trips.getTitle())) {
  169. title = trips.getTitle();
  170. }
  171. String msg = String.format(Constant.CHANGE_GROUPS_TRIPS_ACCOUNT, title);
  172. //配置midJourney安全码
  173. String verifyCodes = groupsTrips.getVerifyCodes();
  174. List<String> verifyCodeList = null;
  175. if (StrUtil.isNotBlank(verifyCodes)) {
  176. verifyCodes = verifyCodes.replaceAll("\n", "");
  177. String[] verifyCodesArray = verifyCodes.split("\\*");
  178. verifyCodeList = Arrays.stream(verifyCodesArray).filter(str -> StrUtil.isNotBlank(str)).map(str -> str.trim()).collect(Collectors.toList());
  179. }
  180. Boolean isPrdEnv = envCommonService.isPrdEnv();
  181. for (int i = 0; i < groupsRelations.size(); i++) {
  182. GroupsRelation relation = groupsRelations.get(i);
  183. if (relation.getExpiryTime() == null) {
  184. List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, relation.getUserId()).eq(OrderDon::getRelationId, relation.getId()).eq(OrderDon::getStatus, OrderDon.Status.hasPayment));
  185. //加购车票
  186. if (orderDonList.isEmpty()) {
  187. GoodsDonSku donSku = skuMapper.selectById(groupsTrips.getSkuId());
  188. Date expiryTime = Optional.ofNullable(relation.getExpiryTime()).orElse(new Date());
  189. Date newDate;
  190. if (donSku.getDays() != null && donSku.getDays() > 0) {
  191. newDate = DateUtil.offsetDay(expiryTime, donSku.getDays() * 1);
  192. } else {
  193. newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * 1);
  194. }
  195. relation.setExpiryTime(newDate);
  196. relation.setStartTime(relation.getStartTime() == null ? new Date() : null);
  197. relationMapper.updateById(relation);
  198. return;
  199. }
  200. orderDonList.forEach((orderDon) -> {
  201. //如果续费增加时间,如果首次则设置当前时间为初始时间
  202. Date expiryTime = Optional.ofNullable(relation.getExpiryTime()).orElse(new Date());
  203. log.info("设置账号,该用户 {} 初始时间:{} ", orderDon.getUserId(), DateUtil.format(expiryTime, "yyyy-MM-dd HH:mm:ss"));
  204. GoodsDonSku donSku = skuMapper.selectById(orderDon.getSkuId());
  205. Date newDate;
  206. if (donSku.getDays() != null && donSku.getDays() > 0) {
  207. newDate = DateUtil.offsetDay(expiryTime, donSku.getDays() * orderDon.getNum());
  208. } else {
  209. newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * orderDon.getNum());
  210. }
  211. relation.setExpiryTime(newDate);
  212. log.info("设置账号,该用户 {} 过期时间:{} ", orderDon.getUserId(), DateUtil.format(newDate, "yyyy-MM-dd HH:mm:ss"));
  213. relation.setStartTime(relation.getStartTime() == null ? new Date() : null);
  214. relationMapper.updateById(relation);
  215. orderDon.setStatus(OrderDon.Status.complete);
  216. orderDonMapper.updateById(orderDon);
  217. });
  218. }
  219. if (relation.getUserId() != 0 && isPrdEnv && relation.getYhsId() == 0) {
  220. //发送短信
  221. smsService.sendSmsToRelationUser(relation.getUserId(), msg);
  222. }
  223. if (verifyCodeList != null && verifyCodeList.size() > 0 && i < verifyCodeList.size()) {
  224. relation.setVerifyCode(verifyCodeList.get(i));
  225. relationMapper.updateById(relation);
  226. }
  227. }
  228. if (groupsRelations.isEmpty() && verifyCodeList != null && verifyCodeList.size() > 0) {
  229. groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsTrips.getId()));
  230. for (int i = 0; i < groupsRelations.size(); i++) {
  231. GroupsRelation relation = groupsRelations.get(i);
  232. if (i < verifyCodeList.size()) {
  233. relation.setVerifyCode(verifyCodeList.get(i));
  234. relationMapper.updateById(relation);
  235. }
  236. }
  237. }
  238. groupsTrips.setStatus(GroupsTrips.Status.validity);
  239. GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId());
  240. //下架上过车的POE,PS AI账号
  241. if (Constant.DOWN_GOODS_PAY.contains(sku.getGoodsId())) {
  242. Number number = beanSearcher.searchCount(GroupsRelation.class, MapUtils.builder()
  243. .field(GroupsRelation::getGroupsId, groupsTrips.getId())
  244. .field(GroupsRelation::getUserId, 0).op(Operator.NotEqual)
  245. .field(GroupsRelation::getStatus, GroupsRelation.Status.validity.name())
  246. .build());
  247. if (number.intValue() > 0) {
  248. groupsTrips.setStatus(GroupsTrips.Status.down);
  249. }
  250. }
  251. updateById(groupsTrips);
  252. Integer alertCount = alertMapper.selectCount(Wrappers.lambdaQuery(GroupsRelationAlert.class)
  253. .eq(GroupsRelationAlert::getSkuId, sku.getId())
  254. .last("limit 1"));
  255. if (alertCount > 0) {
  256. alertMapper.update(null, Wrappers.lambdaUpdate(GroupsRelationAlert.class)
  257. .set(GroupsRelationAlert::getIsReset, true)
  258. .eq(GroupsRelationAlert::getSkuId, sku.getId())
  259. .eq(GroupsRelationAlert::getIsReset, false));
  260. }
  261. }
  262. @Override
  263. @Transactional(rollbackFor = Throwable.class)
  264. public void replaceTripsAccount(ReplaceTripsAccountReq req) {
  265. Long groupsId = req.getGroupsId();
  266. String account = req.getAccount().trim();
  267. String password = req.getPassword().trim();
  268. String remark = req.getRemark();
  269. Date afterStartTime = req.getStartTime();
  270. Date afterExpiryTime = req.getExpiryTime();
  271. GroupsAccountView groupsAccountView = beanSearcher.searchFirst(GroupsAccountView.class, MapUtils.builder()
  272. .field(GroupsAccountView::getGroupsId, groupsId)
  273. .build());
  274. if (groupsId == null) {
  275. throw BusinessRuntimeException.getInstance("车队已不存在");
  276. }
  277. Long accountId = groupsAccountView.getAccountId();
  278. if (accountId == null) {
  279. throw BusinessRuntimeException.getInstance("该车队暂未配置账号");
  280. }
  281. Long goodsId = groupsAccountView.getGoodsId();
  282. if (!account.contains("客服")) {
  283. if (accountCommonService.checkIsDupAccount(goodsId, account)) {
  284. throw BusinessRuntimeException.getInstance("该平台下已生成该账号");
  285. }
  286. }
  287. if (afterStartTime == null) {
  288. afterStartTime = groupsAccountView.getStartTime();
  289. }
  290. if (afterExpiryTime == null) {
  291. afterExpiryTime = groupsAccountView.getExpiryTime();
  292. }
  293. log.info("原账号accountId:{}", accountId);
  294. //替换账号
  295. int update = accountMapper.update(null, Wrappers.lambdaUpdate(Account.class)
  296. .set(Account::getAccount, account)
  297. .set(Account::getPassword, password)
  298. .set(Account::getRemark, remark)
  299. .set(Account::getStartTime, afterStartTime)
  300. .set(Account::getExpiryTime, afterExpiryTime)
  301. .set(Account::getGptRefreshToken, StrUtil.EMPTY)
  302. .eq(Account::getId, accountId));
  303. if (update == 0) {
  304. log.info("替换原账号oldAccount:{}至新账号newAccount:{}失败", groupsAccountView.getAccount(), account);
  305. throw BusinessRuntimeException.getInstance("替换账号失败");
  306. }
  307. if (StrUtil.isNotBlank(groupsAccountView.getGptRefreshToken())) {
  308. //清除gpt token
  309. redisService.del(RedisKey.CHATGPT_ACCESS_TOKEN + groupsAccountView.getAccount());
  310. redisService.del(RedisService.key.CHAT_GPT_TOKEN_EXCEPTION_KEY.getName() + groupsAccountView.getAccount());
  311. }
  312. //时间有效
  313. if (afterExpiryTime != null && afterExpiryTime.after(DateTime.now())) {
  314. groupsMapper.update(null, Wrappers.lambdaUpdate(GroupsTrips.class)
  315. .set(GroupsTrips::getStatus, GroupsTrips.Status.validity)
  316. .eq(GroupsTrips::getAccountId, accountId)
  317. .eq(GroupsTrips::getStatus, GroupsTrips.Status.down));
  318. }
  319. //保存替换记录
  320. GroupsTripsAccountReplaceRecord replaceRecord = new GroupsTripsAccountReplaceRecord();
  321. replaceRecord.setGroupsId(groupsId);
  322. replaceRecord.setOldAccountId(accountId);
  323. replaceRecord.setOldAccount(groupsAccountView.getAccount());
  324. replaceRecord.setOldPassword(groupsAccountView.getPassword());
  325. replaceRecord.setOldStartTime(groupsAccountView.getStartTime());
  326. replaceRecord.setOldExpiryTime(groupsAccountView.getExpiryTime());
  327. Long adminId = req.getAdminId();
  328. Optional.ofNullable(cmsUserMapper.selectById(adminId)).ifPresent(admin -> replaceRecord.setOperator(admin.getNickname()));
  329. replaceRecord.setNewAccount(account);
  330. replaceRecord.setNewPassword(password);
  331. replaceRecord.setNewStartTime(afterStartTime);
  332. replaceRecord.setNewExpiryTime(afterExpiryTime);
  333. replaceRecord.setRemark(remark);
  334. replaceRecordMapper.insert(replaceRecord);
  335. TASK_EXECUTOR.execute(() -> sendChangeAccountMsg(groupsId, goodsId));;
  336. }
  337. @Override
  338. public Integer getAvailableRelation(Long goodsId, Long skuId) {
  339. //chatGPT
  340. GoodsDonSku sku = skuMapper.selectById(skuId);
  341. goodsId = sku.getGoodsId();
  342. Integer skuNum = sku.getNum();
  343. if (Constant.AI_goodsIds.contains(sku.getGoodsId()) && sku.getNum() > 1) {
  344. Integer extraNum = Constant.AI_EXTRACT_NUM;
  345. Integer maxNum = skuNum + extraNum;
  346. DateTime tenExpiry = DateUtil.offsetDay(DateTime.now(), 10);
  347. Integer available = relationMapper.selectAvailableRelation(skuId);
  348. //额外硬塞
  349. Integer special_available = relationMapper.selectSpecialGroupsRelationAvailable(skuId, maxNum, extraNum, tenExpiry);
  350. available += special_available;
  351. available = getAvailableAfterPreAccount(available, skuId, maxNum, goodsId);
  352. return available;
  353. }
  354. Integer available = relationMapper.selectAvailableRelation(skuId);
  355. available = getAvailableAfterPreAccount(available, skuId, skuNum, goodsId);
  356. return available;
  357. }
  358. private void sendChangeAccountMsg(Long groupsId, Long goodsId) {
  359. GoodsDon goodsDon = goodsDonMapper.selectById(goodsId);
  360. String title = goodsDon != null ? goodsDon.getTitle() : "车票";
  361. DateTime now = DateTime.now();
  362. Boolean isPrd = envCommonService.isPrdEnv();
  363. List<GroupsRelation> groupsRelations = beanSearcher.searchAll(GroupsRelation.class, MapUtils.builder().field(GroupsRelation::getGroupsId, groupsId).build());
  364. groupsRelations.forEach(relation -> {
  365. if (relation.getExpiryTime() == null) {
  366. return;
  367. }
  368. //账号有效期小于5天的人,不发账号替换/改密码短信提醒
  369. if (now.after(DateUtil.offsetDay(relation.getExpiryTime(), -5))) {
  370. return;
  371. }
  372. if (Constant.CHANGE_ACCOUNT_PWD_FILTER_GIDS.contains(goodsId)) {
  373. return;
  374. }
  375. if (relation.getUserId() != 0 && isPrd && relation.getYhsId() == 0) {
  376. String msg = String.format(Constant.CHANGE_GROUPS_TRIPS_ACCOUNT, title);
  377. try {
  378. smsService.sendSmsToRelationUser(relation.getUserId(), msg);
  379. } catch (Exception e) {
  380. }
  381. }
  382. });
  383. }
  384. public Integer getAvailableAfterPreAccount(Integer available, Long skuId, Integer maxNum, Long goodsId) {
  385. MapBuilder builder = MapUtils.builder();
  386. if (goodsId == 26) {
  387. builder.field(AccountView::getPreSkuId, skuId);
  388. }
  389. Number preAccount = beanSearcher.searchCount(AccountView.class, builder
  390. .field(AccountView::getGoodsId, goodsId)
  391. .field(AccountView::getAccountType, 2)
  392. .field(AccountView::getGroupsId).op(Operator.IsNull)
  393. .build());
  394. //计算上预发布账号车位数
  395. if (preAccount.intValue() > 0) {
  396. available += preAccount.intValue() * maxNum;
  397. }
  398. return available;
  399. }
  400. }