package cc.mrbird.febs.mall.service.impl; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.enumerates.*; import cc.mrbird.febs.common.exception.FebsException; import cc.mrbird.febs.common.utils.LoginUserUtil; import cc.mrbird.febs.common.utils.MallUtils; import cc.mrbird.febs.common.utils.ShareCodeUtil; import cc.mrbird.febs.mall.dto.*; import cc.mrbird.febs.mall.entity.*; import cc.mrbird.febs.mall.mapper.*; import cc.mrbird.febs.mall.service.HappyActivityService; import cc.mrbird.febs.mall.service.IApiMallMemberWalletService; import cc.mrbird.febs.mall.vo.*; import cc.mrbird.febs.mall.dto.ApiOperateDoDto; import cc.mrbird.febs.pay.model.BrandWCPayRequestData; import cc.mrbird.febs.pay.service.IXcxPayService; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor @Transactional public class HappyActivityServiceImpl extends ServiceImpl implements HappyActivityService { private final HappyFollowMapper happyFollowMapper; private final MallMemberMapper mallMemberMapper; private final HappyActivityOptionMapper happyActivityOptionMapper; private final HappyActivityConnectMapper happyActivityConnectMapper; private final HappyActivityOrderMapper happyActivityOrderMapper; private final HappyActivityOrderItemMapper happyActivityOrderItemMapper; private final IXcxPayService iXcxPayService; private final IApiMallMemberWalletService iApiMallMemberWalletService; @Override public FebsResponse activityList(ApiActivityInfoDto dto) { // 创建分页对象,传入当前页和每页大小 Page page = new Page<>(dto.getPageNow(), dto.getPageSize()); // 调用Mapper方法获取活动分页数据 Page happyActivityPage = this.baseMapper.selectActivityPage(page, dto); // 检查分页结果是否包含数据 if(CollUtil.isNotEmpty(happyActivityPage.getRecords())){ List records = happyActivityPage.getRecords(); // 使用Stream流操作records,获取所有活动的ID List ids = records.stream().map(ApiActivityInfoVo::getId).collect(Collectors.toList()); // 查询关注点赞转发记录,筛选出关注活动类型且未删除的关注记录,并按ID升序排序,限制结果数量为3 List happyFollows = happyFollowMapper.selectList( new LambdaQueryWrapper() .select(HappyFollow::getMemberId) .eq(HappyFollow::getSourceType, StateUpDownEnum.SOURCE_TYPE_ACTIVITY.getCode()) .in(HappyFollow::getSourceId, ids) .eq(HappyFollow::getDeleteFlag, StateUpDownEnum.DOWN.getCode()) .orderByAsc(HappyFollow::getId) .last("limit 3") ); // 检查关注记录是否不为空 if(CollUtil.isNotEmpty(happyFollows)){ // 使用Stream流操作关注记录,获取所有成员ID的集合 Set memberIds = happyFollows.stream().collect(Collectors.mapping(HappyFollow::getMemberId, Collectors.toSet())); // 查询成员信息,获取成员的ID和头像 List mallMembers = mallMemberMapper.selectList( new LambdaQueryWrapper() .select(MallMember::getId,MallMember::getAvatar) .in(MallMember::getId, memberIds) ); // 使用Stream流操作成员信息,生成一个以成员ID为键,成员信息为值的Map Map memberMap = mallMembers.stream() .collect(Collectors.toMap(MallMember::getId, member -> member)); // 使用Stream流操作关注记录,生成一个以活动ID为键,成员ID列表为值的Map Map> followMap = happyFollows.stream() .collect(Collectors.groupingBy( HappyFollow::getSourceId, Collectors.mapping(HappyFollow::getMemberId, Collectors.toList()) )); // 遍历活动记录,为每个活动添加成员头像信息 records.forEach(record -> { List memberIdsForRecord = followMap.get(record.getId()); if (CollUtil.isNotEmpty(memberIdsForRecord)) { List memberAvatars = memberIdsForRecord.stream() .map(memberMap::get) .filter(member -> member != null) .map(MallMember::getAvatar) .collect(Collectors.toList()); record.setMemberAvatars(memberAvatars); } }); } } // 返回成功响应,包含活动分页数据 return new FebsResponse().success().data(happyActivityPage); } @Override public FebsResponse activityInfo(ApiActivityDto dto) { ApiActivityVo apiActivityVo = new ApiActivityVo(); HappyActivity happyActivity = this.baseMapper.selectOne( new LambdaQueryWrapper() .eq(HappyActivity::getId, dto.getId()) .eq(HappyActivity::getType, dto.getType()) .eq(HappyActivity::getDeleteFlag, StateUpDownEnum.DOWN.getCode()) .ne(HappyActivity::getState, StateUpDownEnum.ACTIVITY_STATE_NOT_START.getCode()) ); if(happyActivity != null){ BeanUtil.copyProperties(happyActivity,apiActivityVo); } return new FebsResponse().success().data(apiActivityVo); } @Override public FebsResponse voteOptionList(Long id) { ArrayList apiActivityOptionListVos = new ArrayList<>(); HappyActivity happyActivity = this.baseMapper.selectById(id); if(StateUpDownEnum.ACTIVITY_TYPE_VOTE.getCode() != happyActivity.getType()){ throw new FebsException("投票活动才可获取投票选项"); } List happyActivityOptions = happyActivityOptionMapper.selectList( new LambdaQueryWrapper() .select( HappyActivityOption::getId, HappyActivityOption::getOptionName, HappyActivityOption::getRank, HappyActivityOption::getLikesCnt, HappyActivityOption::getImage ) .eq(HappyActivityOption::getActivityId,id) .eq(HappyActivityOption::getState,StateUpDownEnum.VOTE_OPTION_STATE_AUDIT_SUCCESS.getCode()) .eq(HappyActivityOption::getDeleteFlag,StateUpDownEnum.DOWN.getCode()) .orderByAsc(HappyActivityOption::getRank) ); if(CollUtil.isNotEmpty(happyActivityOptions)){ happyActivityOptions.forEach(option -> { ApiActivityOptionListVo apiActivityOptionListVo = new ApiActivityOptionListVo(); BeanUtil.copyProperties(option, apiActivityOptionListVo); apiActivityOptionListVos.add(apiActivityOptionListVo); }); } return new FebsResponse().success().data(apiActivityOptionListVos); } @Override public FebsResponse voteOption(Long id) { ApiActivityOptionVo apiActivityOptionVo = new ApiActivityOptionVo(); HappyActivityOption happyActivityOption = happyActivityOptionMapper.selectById(id); if(happyActivityOption != null){ BeanUtil.copyProperties(happyActivityOption, apiActivityOptionVo); } return new FebsResponse().success().data(apiActivityOptionVo); } @Override public FebsResponse operateDo(ApiOperateDoDto dto) { Long memberId = LoginUserUtil.getLoginUser().getId(); Integer sourceType = dto.getSourceType(); Long sourceId = dto.getSourceId(); Integer type = dto.getType(); try { if (StateUpDownEnum.SOURCE_TYPE_ACTIVITY.getCode() == sourceType) { // 活动点赞或关注 HappyActivity happyActivity = this.baseMapper.selectById(sourceId); if (happyActivity == null) { throw new FebsException("活动不存在"); } if (StateUpDownEnum.ACTIVITY_TYPE_VOTE.getCode() == happyActivity.getType()) { Long sourceOptionId = dto.getSourceOptionId(); if (sourceOptionId == null) { throw new FebsException("选项ID不能为空"); } this.operateDoVote(memberId, StateUpDownEnum.SOURCE_TYPE_ACTIVITY.getCode(), sourceId, sourceOptionId, type); this.addLikeCnt(sourceOptionId); } else { this.operateDo(memberId, StateUpDownEnum.SOURCE_TYPE_ACTIVITY.getCode(), sourceId, type); } } else if (StateUpDownEnum.SOURCE_TYPE_SOCIAL_CIRCLE.getCode() == sourceType) { // 朋友圈点赞或关注 this.operateDo(memberId, StateUpDownEnum.SOURCE_TYPE_SOCIAL_CIRCLE.getCode(), sourceId, type); } else { throw new FebsException("不支持的操作类型"); } } catch (Exception e) { // 捕获异常并返回错误信息 log.error("操作失败:{}", e.getMessage()); throw new FebsException("操作失败"); } return new FebsResponse().success(); } @Override public void operateDoVote(Long memberId, int code, Long sourceId, Long sourceOptionId, Integer type) { HappyFollow happyFollow = new HappyFollow(); happyFollow.setMemberId(memberId); happyFollow.setSourceType(code); happyFollow.setSourceId(sourceId); happyFollow.setSourceOptionId(sourceOptionId); happyFollow.setType(type); happyFollowMapper.insert(happyFollow); } @Override public void operateDo(Long memberId, int code, Long sourceId, Integer type) { HappyFollow happyFollow = new HappyFollow(); happyFollow.setMemberId(memberId); happyFollow.setSourceType(code); happyFollow.setSourceId(sourceId); happyFollow.setType(type); happyFollowMapper.insert(happyFollow); } @Override public FebsResponse operateVote(ApiOperateVoteDto dto) { Long memberId = LoginUserUtil.getLoginUser().getId(); Long sourceId = dto.getSourceId(); Long sourceOptionId = dto.getSourceOptionId(); Integer sourceType = dto.getSourceType(); Integer type = StateUpDownEnum.VOTE.getCode(); HappyActivity happyActivity = this.baseMapper.selectById(sourceId); if(StateUpDownEnum.ACTIVITY_TYPE_VOTE.getCode() != happyActivity.getType()){ throw new FebsException("当前活动无法投票"); } HappyActivityOption happyActivityOption = happyActivityOptionMapper.selectById(sourceOptionId); if (happyActivityOption == null) { throw new FebsException("投票对象不存在"); } if (StateUpDownEnum.VOTE_OPTION_STATE_AUDIT_SUCCESS.getCode() != happyActivityOption.getState()) { throw new FebsException("请重新选择投票对象"); } //验证当前登录人员今日是否已经投票 List happyFollows = happyFollowMapper.selectList( new LambdaQueryWrapper() .eq(HappyFollow::getMemberId, memberId) .eq(HappyFollow::getSourceId, sourceId) .eq(HappyFollow::getSourceOptionId, sourceOptionId) .eq(HappyFollow::getType, type) .gt(HappyFollow::getCreatedTime, DateUtil.beginOfDay(new Date())) ); if (CollUtil.isNotEmpty(happyFollows) && happyFollows.size() >= happyActivity.getVoteCnt()){ throw new FebsException("今日已经投票"); } this.operateDoVote(memberId, sourceType, sourceId, sourceOptionId, type); this.addLikeCnt(sourceOptionId); return new FebsResponse().success(); } @Override public FebsResponse voteRecordInPage(ApiVoteRecordInPageDto dto) { // 创建分页对象,传入当前页和每页大小 Page page = new Page<>(dto.getPageNow(), dto.getPageSize()); Page voteRecordInPage = this.baseMapper.getVoteRecordInPage(page, dto); List records = voteRecordInPage.getRecords(); if(CollUtil.isNotEmpty(records)){ //stream流操作records,获取全部的memberId(全部投票人) Set memberIds = records.stream().map(ApiVoteRecordInPageVo::getMemberId).collect(Collectors.toSet()); if(CollUtil.isEmpty(memberIds)){ List mallMembers = mallMemberMapper.selectList( new LambdaQueryWrapper() .select(MallMember::getId, MallMember::getName, MallMember::getAvatar) .in(MallMember::getId,memberIds) ); //stream流操作mallMembers得到一个Map的map对象 Map mallMemberMap = mallMembers.stream().collect(Collectors.toMap(MallMember::getId, mallMember -> mallMember)); records.forEach(record -> { MallMember mallMember = mallMemberMap.get(record.getMemberId()); record.setName(mallMember.getName()); record.setAvatar(mallMember.getAvatar()); }); } } return new FebsResponse().success().data(voteRecordInPage); } @Override public FebsResponse operateRegister(ApiOperateRegisterActivityDto dto) { Long memberId = LoginUserUtil.getLoginUser().getId(); return null; } @Override public FebsResponse addConnect(ApiOperateRegisterUserDto dto) { Long memberId = LoginUserUtil.getLoginUser().getId(); HappyActivityConnect happyActivityConnect = new HappyActivityConnect(); happyActivityConnect.setMemberId(memberId); happyActivityConnect.setName(dto.getName()); happyActivityConnect.setPhone(dto.getPhone()); happyActivityConnect.setAddress(dto.getAddress()); happyActivityConnectMapper.insert(happyActivityConnect); return new FebsResponse().success(); } @Override public FebsResponse connectList(ApiConnectListDto dto) { Long memberId = LoginUserUtil.getLoginUser().getId(); dto.setMemberId(memberId); // 创建分页对象,传入当前页和每页大小 Page page = new Page<>(dto.getPageNow(), dto.getPageSize()); Page voteRecordInPage = happyActivityConnectMapper.selectConnectListPage(page, dto); return new FebsResponse().success().data(voteRecordInPage); } @Override public FebsResponse connectInfo(Long id) { Long memberId = LoginUserUtil.getLoginUser().getId(); HappyActivityConnect happyActivityConnect = happyActivityConnectMapper.selectById(id); ApiConnectListInPageVo apiConnectListInPageVo = new ApiConnectListInPageVo(); BeanUtil.copyProperties(happyActivityConnect,apiConnectListInPageVo); return new FebsResponse().success().data(apiConnectListInPageVo); } @Override public FebsResponse connectDel(Long id) { Long memberId = LoginUserUtil.getLoginUser().getId(); happyActivityConnectMapper.deleteById(id); return new FebsResponse().success(); } @Override public FebsResponse connectSave(ApiConnectSaveDto dto) { Long memberId = LoginUserUtil.getLoginUser().getId(); Long id = dto.getId(); HappyActivityConnect happyActivityConnect = happyActivityConnectMapper.selectById(id); if (happyActivityConnect == null) { throw new FebsException("记录不存在"); } happyActivityConnect.setName(dto.getName()); happyActivityConnect.setPhone(dto.getPhone()); happyActivityConnect.setAddress(dto.getAddress()); happyActivityConnectMapper.updateById(happyActivityConnect); return new FebsResponse().success(); } @Override public FebsResponse createOrder(ApiCreateOrderDto dto) { Long memberId = LoginUserUtil.getLoginUser().getId(); if(CollUtil.isEmpty(dto.getConnectIds())){ throw new FebsException("请选择报名人"); } List connectIds = dto.getConnectIds(); Integer numCnt = dto.getNumCnt(); if(numCnt != connectIds.size()){ throw new FebsException("报名人数与票的数量不匹配"); } Long activityId = dto.getActivityId(); HappyActivity happyActivity = this.baseMapper.selectById(activityId); if (ObjectUtil.isEmpty(happyActivity)) { throw new FebsException("活动不存在"); } Integer joinCnt = happyActivity.getJoinCnt(); if(joinCnt < numCnt){ throw new FebsException("报名额度剩下"+joinCnt+",请减少报名人数"); } //支付总金额 BigDecimal amount = happyActivity.getPayAmount().multiply(new BigDecimal(dto.getNumCnt())).setScale(2, RoundingMode.DOWN); if(amount.compareTo(BigDecimal.ZERO) < 0){ throw new FebsException("支付金额错误"); } HappyActivityOrder happyActivityOrder = new HappyActivityOrder(); happyActivityOrder.setOrderNo(MallUtils.getOrderNum()); happyActivityOrder.setMemberId(memberId); happyActivityOrder.setActivityId(dto.getActivityId()); happyActivityOrder.setPrice(happyActivity.getPayAmount()); happyActivityOrder.setNumCnt(dto.getNumCnt()); happyActivityOrder.setAmount(amount); happyActivityOrder.setPayState(StateUpDownEnum.PAY_STATE_NOT_PAY.getCode()); happyActivityOrderMapper.insert(happyActivityOrder); for(Long connectId : connectIds){ HappyActivityConnect happyActivityConnect = happyActivityConnectMapper.selectById(connectId); HappyActivityOrderItem happyActivityOrderItem = new HappyActivityOrderItem(); happyActivityOrderItem.setMemberId(memberId); happyActivityOrderItem.setActivityId(dto.getActivityId()); happyActivityOrderItem.setOrderId(happyActivityOrder.getId()); happyActivityOrderItem.setConnectId(connectId); happyActivityOrderItem.setPrice(happyActivity.getPayAmount()); happyActivityOrderItem.setName(happyActivityConnect.getName()); happyActivityOrderItem.setPhone(happyActivityConnect.getPhone()); happyActivityOrderItem.setAddress(happyActivityConnect.getAddress()); happyActivityOrderItem.setState(StateUpDownEnum.DOWN.getCode()); happyActivityOrderItemMapper.insert(happyActivityOrderItem); } this.substructJoinCnt(activityId, happyActivityOrder.getNumCnt()); HashMap stringObjectHashMap = new HashMap<>(); stringObjectHashMap.put("orderId",happyActivityOrder.getId()); stringObjectHashMap.put("amount",amount); return new FebsResponse().success().data(stringObjectHashMap); } /** * 支付订单函数,根据传入的支付订单数据对象处理不同支付类型的订单支付逻辑。 * * @param dto 包含支付订单相关信息的数据传输对象,包括订单ID和支付类型等信息。 * - orderId: 订单ID,用于查询订单信息。 * - payType: 支付类型,决定支付逻辑的分支。 * - tradePwd: 交易密码(可选),用于余额或积分支付时验证。 * @return FebsResponse 返回支付结果的响应对象,包含支付状态、订单信息等数据。 * - orderInfo: 支付结果信息,可能是预支付ID或其他支付相关数据。 * - orderNo: 订单编号。 * - orderId: 订单ID。 * - wxResultStr: 微信支付相关的结果字符串(仅在微信支付时返回)。 * @throws FebsException 如果订单不存在、已支付、支付失败或支付类型不支持,则抛出异常。 */ @Override public FebsResponse payOrder(ApiPayOrderDto dto) { // 获取当前登录用户的ID Long memberId = LoginUserUtil.getLoginUser().getId(); Long orderId = dto.getOrderId(); Integer payType = dto.getPayType(); // 查询订单信息,确保订单存在且未支付 HappyActivityOrder happyActivityOrder = happyActivityOrderMapper.selectById(orderId); if (ObjectUtil.isEmpty(happyActivityOrder)) { throw new FebsException("订单不存在"); } if (happyActivityOrder.getPayState() == StateUpDownEnum.PAY_STATE_PAY_SUCCESS.getCode()) { throw new FebsException("订单已支付"); } String payResultStr = ""; String wxResultStr = ""; try { // 根据支付类型处理不同的支付逻辑 if (StateUpDownEnum.PAY_METHOD_NO_PAY.getCode() == payType) { // 处理无需支付的订单逻辑 processNoPayOrder(happyActivityOrder, orderId); } else if (StateUpDownEnum.PAY_METHOD_WECHAT.getCode() == payType) { // 处理微信支付逻辑,生成支付请求数据并更新订单状态 BrandWCPayRequestData brandWCPayRequestData = iXcxPayService.startPaymentActivity(happyActivityOrder); wxResultStr = JSONUtil.toJsonStr(brandWCPayRequestData); payResultStr = brandWCPayRequestData.getPrepay_id(); updateOrderState(happyActivityOrder, payType, StateUpDownEnum.PAY_STATE_NOT_PAY.getCode()); } else if (StateUpDownEnum.PAY_METHOD_BALANCE.getCode() == payType || StateUpDownEnum.PAY_METHOD_INTEGRAL.getCode() == payType) { // 处理余额或积分支付逻辑,验证交易密码并完成支付 String payMethod = StateUpDownEnum.PAY_METHOD_BALANCE.getCode() == payType ? "balance" : "prizeScore"; payResultStr = balancePay(happyActivityOrder, dto.getTradePwd(), payMethod); processPaidOrder(happyActivityOrder, orderId, payType); } else { // 如果支付类型不支持,抛出异常 throw new FebsException("不支持的支付类型"); } } catch (Exception e) { // 捕获支付过程中的异常,记录日志并抛出自定义异常 log.error("支付失败,订单ID:{},支付类型:{}", orderId, payType, e); throw new FebsException("支付失败:" + e.getMessage()); } // todo 支付失败要把对应的人数加回来 // 构造返回结果,包含支付相关信息 Map map = new HashMap<>(); map.put("orderInfo", payResultStr); map.put("orderNo", happyActivityOrder.getOrderNo()); map.put("orderId", happyActivityOrder.getId()); map.put("wxResultStr", wxResultStr); return new FebsResponse().success().data(map).message("支付成功"); } @Override public void addLikeCnt(Long sourceOptionId) { HappyActivityOption happyActivityOption = happyActivityOptionMapper.selectById(sourceOptionId); happyActivityOption.setLikesCnt(happyActivityOption.getLikesCnt() + 1); happyActivityOptionMapper.updateById(happyActivityOption); } @Override public void substructJoinCnt(Long activityId, Integer numCnt) { HappyActivity happyActivity = this.baseMapper.selectById(activityId); if(ObjectUtil.isNotEmpty(happyActivity)){ happyActivity.setJoinCnt(happyActivity.getJoinCnt() -numCnt); this.baseMapper.updateById(happyActivity); } } // 处理未支付订单 private void processNoPayOrder(HappyActivityOrder order, Long orderId) { updateOrderState(order, StateUpDownEnum.PAY_METHOD_NO_PAY.getCode(), StateUpDownEnum.PAY_STATE_PAY_SUCCESS.getCode()); generateOrderItemCodes(orderId); } // 处理已支付订单 private void processPaidOrder(HappyActivityOrder order, Long orderId, Integer payType) { updateOrderState(order, payType, StateUpDownEnum.PAY_STATE_PAY_SUCCESS.getCode()); generateOrderItemCodes(orderId); } // 更新订单状态 private void updateOrderState(HappyActivityOrder order, Integer payType, Integer payState) { order.setPayState(payState); order.setPayType(payType); if (payState == StateUpDownEnum.PAY_STATE_PAY_SUCCESS.getCode()) { order.setPayTime(new Date()); } happyActivityOrderMapper.updateById(order); } // 批量生成订单项编码 private void generateOrderItemCodes(Long orderId) { List items = happyActivityOrderItemMapper.selectList( new LambdaQueryWrapper() .eq(HappyActivityOrderItem::getOrderId, orderId) ); if (CollUtil.isNotEmpty(items)) { for (HappyActivityOrderItem item : items) { String code = ShareCodeUtil.toSerialCode(item.getOrderId()) + MallUtils.getRandomNum(8); item.setCode(code); happyActivityOrderItemMapper.updateById(item); } } } private String balancePay(HappyActivityOrder happyActivityOrder, String tradePwd, String field) { if (StrUtil.isBlank(tradePwd)) { throw new FebsException("支付密码错误"); } MallMember mallMember = mallMemberMapper.selectById(happyActivityOrder.getMemberId()); if (StrUtil.isBlank(mallMember.getTradePassword())) { throw new FebsException("未设置支付密码"); } if (!SecureUtil.md5(tradePwd).equals(mallMember.getTradePassword())) { throw new FebsException("支付密码错误"); } int reduce = iApiMallMemberWalletService.reduce(happyActivityOrder.getAmount(), mallMember.getId(), field); if (reduce == 2) { throw new FebsException("余额不足"); } return happyActivityOrder.getOrderNo(); } public static void main(String[] args) { Date date = new Date(); //获取今日的凌晨的时间 DateTime dateTime = DateUtil.beginOfDay(date); System.out.println(dateTime); } }