package com.cyksj.service.mange.group; import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.cyksj.common.EnvCommonService; import com.cyksj.common.constant.Constant; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.task.GlobalThreadPoolTaskExecutor; import com.cyksj.dto.RedisKey; import com.cyksj.mapper.*; import com.cyksj.mapper.manage.GroupsTripsAccountReplaceRecordMapper; import com.cyksj.mapper.manage.cms.CmsUserMapper; import com.cyksj.model.entity.*; import com.cyksj.model.manage.views.AccountView; import com.cyksj.model.request.ReplaceTripsAccountReq; import com.cyksj.model.views.GroupsAccountView; import com.cyksj.redis.RedisService; import com.cyksj.service.mange.AccountCommonService; import com.cyksj.service.mange.CmsGroupService; import com.cyksj.service.sms.SmsService; import com.ejlchina.searcher.BeanSearcher; import com.ejlchina.searcher.param.Operator; import com.ejlchina.searcher.util.MapBuilder; import com.ejlchina.searcher.util.MapUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; /** * @author chan * @date 2022/9/27 6:27 PM */ @Slf4j @Service @RequiredArgsConstructor public class CmsGroupServiceImpl extends ServiceImpl implements CmsGroupService { private final GoodsDonSkuMapper skuMapper; private final GroupsRelationMapper relationMapper; private final OrderDonMapper orderDonMapper; private final AccountMapper accountMapper; private final BeanSearcher beanSearcher; private final GroupsTripsAccountReplaceRecordMapper replaceRecordMapper; private final CmsUserMapper cmsUserMapper; private final GoodsDonMapper goodsDonMapper; private final SmsService smsService; private final EnvCommonService envCommonService; private final RedisService redisService; private final GroupsMapper groupsMapper; private final AccountCommonService accountCommonService; private final GroupsRelationAlertMapper alertMapper; private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance(); @Override public GroupsTrips issuance(GroupsTrips groups, String verifyCodes) { GoodsDonSku sku = skuMapper.selectById(groups.getSkuId()); if (sku == null) { throw new BusinessRuntimeException("该商品规格不存在!"); } List verifyCodeList = null; if (StrUtil.isNotBlank(verifyCodes)) { verifyCodes = verifyCodes.replaceAll("\n", ""); String[] verifyCodeArray = verifyCodes.split("\\*"); verifyCodeList = Arrays.stream(verifyCodeArray).filter(str -> StrUtil.isNotBlank(str)).map(str -> str.trim()).collect(Collectors.toList()); } groups.setNum(sku.getNum()); groups.setAvailableNum(sku.getNum()); if (groups.getAccountId() == null || accountMapper.selectById(groups.getAccountId()) == null) { throw new BusinessRuntimeException("该账号不存在"); } groups.setStatus(GroupsTrips.Status.validity); this.save(groups); for (Integer i = 1; i <= groups.getNum(); i++) { GroupsRelation relation = new GroupsRelation(); relation.setGroupsId(groups.getId()); relation.setStatus(GroupsRelation.Status.none); relation.setNum(i); if (verifyCodeList != null && verifyCodeList.size() > 0 && verifyCodeList.size() >= i) { relation.setVerifyCode(verifyCodeList.get(i - 1)); } relationMapper.insert(relation); } Integer alertCount = alertMapper.selectCount(Wrappers.lambdaQuery(GroupsRelationAlert.class) .eq(GroupsRelationAlert::getSkuId, sku.getId()) .last("limit 1")); if (alertCount > 0) { alertMapper.update(null, Wrappers.lambdaUpdate(GroupsRelationAlert.class) .set(GroupsRelationAlert::getIsReset, true) .eq(GroupsRelationAlert::getSkuId, sku.getId()) .eq(GroupsRelationAlert::getIsReset, false)); } return groups; } @Override public void close(Long groupId) { GroupsTrips groupsTrips = this.getById(groupId); if(groupsTrips == null){ throw new BusinessRuntimeException("非法参数.车队不存在"); } Integer count = relationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class) .eq(GroupsRelation::getGroupsId, groupId) .ne(GroupsRelation::getUserId, 0) .ne(GroupsRelation::getStatus, GroupsRelation.Status.none)); if (count > 0) { throw BusinessRuntimeException.getInstance("请移除该车队下的用户再进行删掉操作"); } //可强制删除 //后台记录 // if (count > 0) { // List groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class) // .eq(GroupsRelation::getGroupsId, groupId) // .ne(GroupsRelation::getStatus, GroupsRelation.Status.none)); // if (groupsRelations.size() > 0) { // Account account = accountMapper.selectById(groupsTrips.getAccountId()); // TASK_EXECUTOR.execute(() -> { // if (redisService.setNx(String.format("%s-%s", groupId, groupsTrips.getAccount()), groupId, 10l)) { // groupsRelations.forEach(data -> { // DelGroupsTripsRecord delGroupsTripsRecord = new DelGroupsTripsRecord(); // delGroupsTripsRecord.setGroupsId(groupId); // delGroupsTripsRecord.setGroupsStatus(groupsTrips.getStatus().name()); // if (account != null) { // delGroupsTripsRecord.setAccount(account.getAccount()); // delGroupsTripsRecord.setPassword(account.getPassword()); // } // delGroupsTripsRecord.setRelationId(data.getId()); // delGroupsTripsRecord.setSkuId(groupsTrips.getSkuId()); // delGroupsTripsRecord.setUserId(data.getUserId()); // delGroupsTripsRecord.setStartTime(data.getStartTime()); // delGroupsTripsRecord.setExpiryTime(data.getExpiryTime()); // delGroupsTripsRecord.setRelationStatus(data.getStatus().name()); // delGroupsTripsRecord.setType("delete"); // delGroupsTripsRecordMapper.insert(delGroupsTripsRecord); // }); // } // }); // } // } relationMapper.delete(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId,groupId)); this.removeById(groupId); } @Override @Transactional(rollbackFor = Throwable.class) public void setAccount(GroupsTrips groupsTrips) throws Exception { int count = count(Wrappers.lambdaQuery(GroupsTrips.class).eq(GroupsTrips::getAccountId, groupsTrips.getAccountId())); if (count > 0) { throw new BusinessRuntimeException("该账号已发车.请选择未发车账户"); } Account account = accountMapper.selectById(groupsTrips.getAccountId()); //将预备账号 类型替换掉 if (account.getType() == 2) { int update = accountMapper.update(null, Wrappers.lambdaUpdate(Account.class) .set(Account::getType, 1) .eq(Account::getId, account.getId()) .eq(Account::getType, 2)); if (update == 0) { throw BusinessRuntimeException.getInstance("该账号已配置车队"); } } List groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsTrips.getId()).eq(GroupsRelation::getStatus, GroupsRelation.Status.validity)); GroupsTrips trips = beanSearcher.searchFirst(GroupsTrips.class, MapUtils.builder().field(GroupsTrips::getId, groupsTrips.getId()).onlySelect(GroupsTrips::getTitle).build()); String title = "车票"; if (trips != null && StrUtil.isNotBlank(trips.getTitle())) { title = trips.getTitle(); } String msg = String.format(Constant.CHANGE_GROUPS_TRIPS_ACCOUNT, title); //配置midJourney安全码 String verifyCodes = groupsTrips.getVerifyCodes(); List verifyCodeList = null; if (StrUtil.isNotBlank(verifyCodes)) { verifyCodes = verifyCodes.replaceAll("\n", ""); String[] verifyCodesArray = verifyCodes.split("\\*"); verifyCodeList = Arrays.stream(verifyCodesArray).filter(str -> StrUtil.isNotBlank(str)).map(str -> str.trim()).collect(Collectors.toList()); } Boolean isPrdEnv = envCommonService.isPrdEnv(); for (int i = 0; i < groupsRelations.size(); i++) { GroupsRelation relation = groupsRelations.get(i); if (relation.getExpiryTime() == null) { List orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, relation.getUserId()).eq(OrderDon::getRelationId, relation.getId()).eq(OrderDon::getStatus, OrderDon.Status.hasPayment)); //加购车票 if (orderDonList.isEmpty()) { GoodsDonSku donSku = skuMapper.selectById(groupsTrips.getSkuId()); Date expiryTime = Optional.ofNullable(relation.getExpiryTime()).orElse(new Date()); Date newDate; if (donSku.getDays() != null && donSku.getDays() > 0) { newDate = DateUtil.offsetDay(expiryTime, donSku.getDays() * 1); } else { newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * 1); } relation.setExpiryTime(newDate); relation.setStartTime(relation.getStartTime() == null ? new Date() : null); relationMapper.updateById(relation); return; } orderDonList.forEach((orderDon) -> { //如果续费增加时间,如果首次则设置当前时间为初始时间 Date expiryTime = Optional.ofNullable(relation.getExpiryTime()).orElse(new Date()); log.info("设置账号,该用户 {} 初始时间:{} ", orderDon.getUserId(), DateUtil.format(expiryTime, "yyyy-MM-dd HH:mm:ss")); GoodsDonSku donSku = skuMapper.selectById(orderDon.getSkuId()); Date newDate; if (donSku.getDays() != null && donSku.getDays() > 0) { newDate = DateUtil.offsetDay(expiryTime, donSku.getDays() * orderDon.getNum()); } else { newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * orderDon.getNum()); } relation.setExpiryTime(newDate); log.info("设置账号,该用户 {} 过期时间:{} ", orderDon.getUserId(), DateUtil.format(newDate, "yyyy-MM-dd HH:mm:ss")); relation.setStartTime(relation.getStartTime() == null ? new Date() : null); relationMapper.updateById(relation); orderDon.setStatus(OrderDon.Status.complete); orderDonMapper.updateById(orderDon); }); } if (relation.getUserId() != 0 && isPrdEnv && relation.getYhsId() == 0) { //发送短信 smsService.sendSmsToRelationUser(relation.getUserId(), msg); } if (verifyCodeList != null && verifyCodeList.size() > 0 && i < verifyCodeList.size()) { relation.setVerifyCode(verifyCodeList.get(i)); relationMapper.updateById(relation); } } if (groupsRelations.isEmpty() && verifyCodeList != null && verifyCodeList.size() > 0) { groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsTrips.getId())); for (int i = 0; i < groupsRelations.size(); i++) { GroupsRelation relation = groupsRelations.get(i); if (i < verifyCodeList.size()) { relation.setVerifyCode(verifyCodeList.get(i)); relationMapper.updateById(relation); } } } groupsTrips.setStatus(GroupsTrips.Status.validity); GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId()); //下架上过车的POE,PS AI账号 if (Constant.DOWN_GOODS_PAY.contains(sku.getGoodsId())) { Number number = beanSearcher.searchCount(GroupsRelation.class, MapUtils.builder() .field(GroupsRelation::getGroupsId, groupsTrips.getId()) .field(GroupsRelation::getUserId, 0).op(Operator.NotEqual) .field(GroupsRelation::getStatus, GroupsRelation.Status.validity.name()) .build()); if (number.intValue() > 0) { groupsTrips.setStatus(GroupsTrips.Status.down); } } updateById(groupsTrips); Integer alertCount = alertMapper.selectCount(Wrappers.lambdaQuery(GroupsRelationAlert.class) .eq(GroupsRelationAlert::getSkuId, sku.getId()) .last("limit 1")); if (alertCount > 0) { alertMapper.update(null, Wrappers.lambdaUpdate(GroupsRelationAlert.class) .set(GroupsRelationAlert::getIsReset, true) .eq(GroupsRelationAlert::getSkuId, sku.getId()) .eq(GroupsRelationAlert::getIsReset, false)); } } @Override @Transactional(rollbackFor = Throwable.class) public void replaceTripsAccount(ReplaceTripsAccountReq req) { Long groupsId = req.getGroupsId(); String account = req.getAccount().trim(); String password = req.getPassword().trim(); String remark = req.getRemark(); Date afterStartTime = req.getStartTime(); Date afterExpiryTime = req.getExpiryTime(); GroupsAccountView groupsAccountView = beanSearcher.searchFirst(GroupsAccountView.class, MapUtils.builder() .field(GroupsAccountView::getGroupsId, groupsId) .build()); if (groupsId == null) { throw BusinessRuntimeException.getInstance("车队已不存在"); } Long accountId = groupsAccountView.getAccountId(); if (accountId == null) { throw BusinessRuntimeException.getInstance("该车队暂未配置账号"); } Long goodsId = groupsAccountView.getGoodsId(); if (!account.contains("客服")) { if (accountCommonService.checkIsDupAccount(goodsId, account)) { throw BusinessRuntimeException.getInstance("该平台下已生成该账号"); } } if (afterStartTime == null) { afterStartTime = groupsAccountView.getStartTime(); } if (afterExpiryTime == null) { afterExpiryTime = groupsAccountView.getExpiryTime(); } log.info("原账号accountId:{}", accountId); //替换账号 int update = accountMapper.update(null, Wrappers.lambdaUpdate(Account.class) .set(Account::getAccount, account) .set(Account::getPassword, password) .set(Account::getRemark, remark) .set(Account::getStartTime, afterStartTime) .set(Account::getExpiryTime, afterExpiryTime) .set(Account::getGptRefreshToken, StrUtil.EMPTY) .eq(Account::getId, accountId)); if (update == 0) { log.info("替换原账号oldAccount:{}至新账号newAccount:{}失败", groupsAccountView.getAccount(), account); throw BusinessRuntimeException.getInstance("替换账号失败"); } if (StrUtil.isNotBlank(groupsAccountView.getGptRefreshToken())) { //清除gpt token redisService.del(RedisKey.CHATGPT_ACCESS_TOKEN + groupsAccountView.getAccount()); redisService.del(RedisService.key.CHAT_GPT_TOKEN_EXCEPTION_KEY.getName() + groupsAccountView.getAccount()); } //时间有效 if (afterExpiryTime != null && afterExpiryTime.after(DateTime.now())) { groupsMapper.update(null, Wrappers.lambdaUpdate(GroupsTrips.class) .set(GroupsTrips::getStatus, GroupsTrips.Status.validity) .eq(GroupsTrips::getAccountId, accountId) .eq(GroupsTrips::getStatus, GroupsTrips.Status.down)); } //保存替换记录 GroupsTripsAccountReplaceRecord replaceRecord = new GroupsTripsAccountReplaceRecord(); replaceRecord.setGroupsId(groupsId); replaceRecord.setOldAccountId(accountId); replaceRecord.setOldAccount(groupsAccountView.getAccount()); replaceRecord.setOldPassword(groupsAccountView.getPassword()); replaceRecord.setOldStartTime(groupsAccountView.getStartTime()); replaceRecord.setOldExpiryTime(groupsAccountView.getExpiryTime()); Long adminId = req.getAdminId(); Optional.ofNullable(cmsUserMapper.selectById(adminId)).ifPresent(admin -> replaceRecord.setOperator(admin.getNickname())); replaceRecord.setNewAccount(account); replaceRecord.setNewPassword(password); replaceRecord.setNewStartTime(afterStartTime); replaceRecord.setNewExpiryTime(afterExpiryTime); replaceRecord.setRemark(remark); replaceRecordMapper.insert(replaceRecord); TASK_EXECUTOR.execute(() -> sendChangeAccountMsg(groupsId, goodsId));; } @Override public Integer getAvailableRelation(Long goodsId, Long skuId) { //chatGPT GoodsDonSku sku = skuMapper.selectById(skuId); goodsId = sku.getGoodsId(); Integer skuNum = sku.getNum(); if (Constant.AI_goodsIds.contains(sku.getGoodsId()) && sku.getNum() > 1) { Integer extraNum = Constant.AI_EXTRACT_NUM; Integer maxNum = skuNum + extraNum; DateTime tenExpiry = DateUtil.offsetDay(DateTime.now(), 10); Integer available = relationMapper.selectAvailableRelation(skuId); //额外硬塞 Integer special_available = relationMapper.selectSpecialGroupsRelationAvailable(skuId, maxNum, extraNum, tenExpiry); available += special_available; available = getAvailableAfterPreAccount(available, skuId, maxNum, goodsId); return available; } Integer available = relationMapper.selectAvailableRelation(skuId); available = getAvailableAfterPreAccount(available, skuId, skuNum, goodsId); return available; } private void sendChangeAccountMsg(Long groupsId, Long goodsId) { GoodsDon goodsDon = goodsDonMapper.selectById(goodsId); String title = goodsDon != null ? goodsDon.getTitle() : "车票"; DateTime now = DateTime.now(); Boolean isPrd = envCommonService.isPrdEnv(); List groupsRelations = beanSearcher.searchAll(GroupsRelation.class, MapUtils.builder().field(GroupsRelation::getGroupsId, groupsId).build()); groupsRelations.forEach(relation -> { if (relation.getExpiryTime() == null) { return; } //账号有效期小于5天的人,不发账号替换/改密码短信提醒 if (now.after(DateUtil.offsetDay(relation.getExpiryTime(), -5))) { return; } if (Constant.CHANGE_ACCOUNT_PWD_FILTER_GIDS.contains(goodsId)) { return; } if (relation.getUserId() != 0 && isPrd && relation.getYhsId() == 0) { String msg = String.format(Constant.CHANGE_GROUPS_TRIPS_ACCOUNT, title); try { smsService.sendSmsToRelationUser(relation.getUserId(), msg); } catch (Exception e) { } } }); } public Integer getAvailableAfterPreAccount(Integer available, Long skuId, Integer maxNum, Long goodsId) { MapBuilder builder = MapUtils.builder(); if (goodsId == 26) { builder.field(AccountView::getPreSkuId, skuId); } Number preAccount = beanSearcher.searchCount(AccountView.class, builder .field(AccountView::getGoodsId, goodsId) .field(AccountView::getAccountType, 2) .field(AccountView::getGroupsId).op(Operator.IsNull) .build()); //计算上预发布账号车位数 if (preAccount.intValue() > 0) { available += preAccount.intValue() * maxNum; } return available; } }