ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constants/NotificationTypeConstant.java
@@ -13,4 +13,8 @@ String AUCTION_SALESROOM = "auction_salesroom"; String AUCTION_SALESROOM_GOODS = "auction_salesroom_goods"; /** * 拍卖弹窗 */ String AUCTION_POPUP = "auction_popup"; } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/Member.java
@@ -111,6 +111,7 @@ @ApiModelProperty(value = "用户消费金额") private BigDecimal money; @ApiModelProperty(value = "会员分类(1:普通用户;2:会员用户;3:超级会员用户;)") private Integer vipClassify; } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/WebsocketMessageDTO.java
@@ -29,4 +29,8 @@ * 消息 */ private String message; /** * 用户id */ private Long userId; } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/dto/SmsSendDTO.java
New file @@ -0,0 +1,29 @@ package com.ruoyi.system.api.domain.dto; import io.swagger.annotations.ApiModel; import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; /** * @author mitao * @date 2025/2/11 */ @Data @Builder @AllArgsConstructor @NoArgsConstructor @ApiModel("短信发送数据传输对象") public class SmsSendDTO { /** * 电话列表 */ private List<String> mobileList; /** * 发送内容 */ private String content; } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/AuthFallbackFactory.java
@@ -1,6 +1,7 @@ package com.ruoyi.system.api.factory; import com.ruoyi.common.core.domain.R; import com.ruoyi.system.api.domain.dto.SmsSendDTO; import com.ruoyi.system.api.feignClient.AuthClient; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; @@ -15,6 +16,11 @@ public R<?> logout(String token, String source) { return R.fail("强制下线失败:" + cause.getMessage()); } @Override public R<?> sendSms(SmsSendDTO smsSendDTO, String source) { return R.fail("批量发送短信失败" + cause.getMessage()); } }; } } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/OrderFallbackFactory.java
@@ -35,7 +35,7 @@ @Override public R<Boolean> saveOrderOne(OrderDTO orderDTO, String source) { public R<Long> saveOrderOne(OrderDTO orderDTO, String source) { return R.fail("保存订单失败:" + cause.getMessage()); } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/SysUserFallbackFactory.java
@@ -113,6 +113,12 @@ return R.fail("向所有用户发送websocket消息失败:" + cause.getMessage()); } @Override public R<?> pushBatch(WebsocketMessageDTO dto, String source) { return R.fail("批量向指定用户发送websocket消息失败:" + cause.getMessage()); } }; } } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/feignClient/AuthClient.java
@@ -3,9 +3,12 @@ import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.system.api.domain.dto.SmsSendDTO; import com.ruoyi.system.api.factory.AuthFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; @@ -19,4 +22,8 @@ @GetMapping("/inner/logout") R<?> logout(@RequestParam("token") String token, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); @PostMapping("/sms/send") R<?> sendSms(@RequestBody SmsSendDTO smsSendDTO, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/feignClient/OrderClient.java
@@ -36,7 +36,7 @@ public interface OrderClient { @PostMapping("/order/saveOrderOne") R<Boolean> saveOrderOne(@RequestBody OrderDTO orderDTO, R<Long> saveOrderOne(@RequestBody OrderDTO orderDTO, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/feignClient/SysUserClient.java
@@ -112,4 +112,14 @@ @GetMapping("/websocket/push-all/{message}") R<?> pushAll(@PathVariable("message") String message, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); /** * 批量向指定用户推送消息 * @param dto * @return */ @PostMapping("/websocket/push-batch") R<?> pushBatch(@RequestBody WebsocketMessageDTO dto, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); } ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java
@@ -25,6 +25,7 @@ import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.domain.dto.AppMiniLoginDTO; import com.ruoyi.system.api.domain.dto.SmsSendDTO; import com.ruoyi.system.api.feignClient.MemberClient; import com.ruoyi.system.api.feignClient.SysUserClient; import com.ruoyi.system.api.model.LoginUser; @@ -241,6 +242,13 @@ } return AjaxResult.success(memberList); } @InnerAuth @PostMapping("/sms/send") public R<?> sendSms(@RequestBody SmsSendDTO smsSendDTO) { JuTongDaSMSUtil.smsSendBatch(smsSendDTO.getMobileList(), smsSendDTO.getContent(), "", ""); return R.ok(); } } ruoyi-auth/src/main/java/com/ruoyi/auth/utils/JuTongDaSMSUtil.java
@@ -10,6 +10,8 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Base64; import java.util.List; import lombok.extern.slf4j.Slf4j; /** * 聚通达短信发送工具类 @@ -17,6 +19,7 @@ * @author mitao * @date 2024/6/17 */ @Slf4j public class JuTongDaSMSUtil { private static final String UID = "201000"; @@ -67,7 +70,41 @@ return errMess; } public static void smsSendBatch(List<String> mobileList, String content, String ext, String attime) { for (String mobile : mobileList) { String errMess = ""; StringBuffer sendData = new StringBuffer(""); try { sendData.append("uid=").append(UID); // 用户名 String pwd = getMD5(PWD);// 原始密码做MD5加密,32位大写格式 sendData.append("&password=").append(pwd); // 密码 sendData.append("&encode=").append("GBK"); // encode=GBK或者encode=utf8 content = template.replace("${code}", content); String contentBase64 = Base64.getEncoder() .encodeToString(content.getBytes("gbk"));// 先用encode中定义的格式编码,再用base64加密内容 sendData.append("&encodeType=base64"); // 固定 sendData.append("&content=").append(contentBase64); // base64加密后的内容 sendData.append("&mobile=").append(mobile); // 手机号 // sendData.append("&cid=").append("45955855252252555"); // 唯一标识,选填,如果不填系统自动生成作为当前批次的唯一标识 if (!StringUtils.isNotBlank(ext)) { sendData.append("&extNumber=").append(ext); // 扩展 } if (!StringUtils.isNotBlank(attime)) { sendData.append("&schtime=").append(attime); // 定时时间,选填,格式2008-06-09 12:00:00 } errMess = sendPost("https://sms3api.jvtd.cn/jtdsms/smsSend", sendData.toString());// 普通短信 // errMess =sendPost("http://ip:8090/jtdsms/sendData.do", sendData.toString());//个性短信 } catch (Exception e) { log.error("发送短信异常:", e); errMess = "-601"; } } } public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/controller/forepart/ForepartAuctionSalesroomController.java
@@ -220,7 +220,7 @@ auctionSalesroom.setIsState(1); auctionBondJlMapper.updateById(auctionSalesroom); } return R.ok( ); return R.ok(); } /** ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/domain/AuctionBidRecord.java
@@ -88,5 +88,6 @@ @ApiModelProperty(value = "用户名") private String nickname; @ApiModelProperty("关联订单id") private Long orderId; } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/service/impl/AuctionGoodsServiceImpl.java
@@ -1,5 +1,6 @@ package com.ruoyi.auction.service.impl; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -57,11 +58,13 @@ import com.ruoyi.system.api.domain.dto.MemberAuctionSalesroomDTO; import com.ruoyi.system.api.domain.dto.OrderDTO; import com.ruoyi.system.api.domain.dto.RefundDTO; import com.ruoyi.system.api.domain.dto.SmsSendDTO; import com.ruoyi.system.api.domain.vo.AuctionGoodsListVO; import com.ruoyi.system.api.domain.vo.AuctionGoodsinfoVO; import com.ruoyi.system.api.domain.vo.GoodsInfoTitleValueVO; import com.ruoyi.system.api.domain.vo.getHomeGoodsSkuXxiVO; import com.ruoyi.system.api.feignClient.AuctionClient; import com.ruoyi.system.api.feignClient.AuthClient; import com.ruoyi.system.api.feignClient.GoodsSkuClient; import com.ruoyi.system.api.feignClient.MemberClient; import com.ruoyi.system.api.feignClient.OrderClient; @@ -73,6 +76,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -120,6 +124,10 @@ @Resource private AuctionBondJlMapper auctionBondJlMapper; @Resource private AuthClient authClient; private static final String SUCCESS_TEMPLATE = "【酒鼎老酒】恭喜!您参与的“content”竞拍已中拍!"; private static final String FAILED_TEMPLATE = "【酒鼎老酒】很遗憾!您参与的”content“竞拍未中拍!"; /** * 获取拍卖商品列表的分页数据 @@ -358,13 +366,12 @@ SecurityConstants.INNER); } auctionBidRecordService.updateBatchById(auctionBidRecordList); // 创建待支付订单 CustomConfig moneyConfig = sysUserClient.getconfig( ConfigEnum.MEMBER_POINTS_MONEY.getKey()).getData(); CustomConfig pointsConfig = sysUserClient.getconfig( ConfigEnum.MEMBER_POINTS_POINTS.getKey()).getData(); Map<Long, String> orderIdMap = new HashMap<>(); for (AuctionBidRecord auctionBidRecord : auctionBidRecordList) { BigDecimal lastBidAmount = auctionBidRecord.getLastBidAmount(); BigDecimal divide = lastBidAmount.divide( @@ -397,7 +404,52 @@ } orderDTO.setOrderTimeSx(auctionGoods.getEndTime()); orderDTO.setGoodsId(auctionGoods.getGoodsSkuId()); orderClient.saveOrderOne(orderDTO, SecurityConstants.INNER); Long orderId = orderClient.saveOrderOne(orderDTO, SecurityConstants.INNER) .getData(); if (Objects.nonNull(orderId)) { orderIdMap.put(auctionBidRecord.getMemberId(), orderId.toString()); auctionBidRecord.setOrderId(orderId); } } // 更新出价记录 auctionBidRecordService.updateBatchById(auctionBidRecordList); List<Long> successMemberIdList = auctionBidRecords.stream() .filter(auctionBidRecord -> auctionBidRecord.getStatus() .equals(BidStatusEnum.SUCCESSFUL)) .map(AuctionBidRecord::getMemberId) .collect(Collectors.toList()); List<Long> failedMemberIdList = auctionBidRecords.stream() .filter(auctionBidRecord -> !auctionBidRecord.getStatus() .equals(BidStatusEnum.SUCCESSFUL)) .map(AuctionBidRecord::getMemberId) .collect(Collectors.toList()); if (CollUtils.isNotEmpty(successMemberIdList)) { List<Member> successMemberList = memberClient.getMemberListByIds( successMemberIdList, SecurityConstants.INNER).getData(); if (CollUtils.isNotEmpty(successMemberList)) { // 推送websocket消息 sendWebsocketMsg(id, successMemberList, goodsSku, 1, orderIdMap); // 发送短信通知 List<String> mobileList = successMemberList.stream().map(Member::getPhone) .collect(Collectors.toList()); authClient.sendSms(SmsSendDTO.builder().mobileList(mobileList) .content(SUCCESS_TEMPLATE.replace("content", goodsSku.getSkuName())) .build(), SecurityConstants.INNER); } } if (CollUtils.isNotEmpty(failedMemberIdList)) { List<Member> failedMemberList = memberClient.getMemberListByIds( failedMemberIdList, SecurityConstants.INNER).getData(); if (CollUtils.isNotEmpty(failedMemberList)) { // 推送websocket消息 sendWebsocketMsg(id, failedMemberList, goodsSku, 0, orderIdMap); // 发送短信通知 List<String> mobileList = failedMemberList.stream().map(Member::getPhone) .collect(Collectors.toList()); authClient.sendSms(SmsSendDTO.builder().mobileList(mobileList) .content(FAILED_TEMPLATE.replace("content", goodsSku.getSkuName())) .build(), SecurityConstants.INNER); } } } else { // 没有人出价,退回拍卖商品库存 @@ -460,6 +512,31 @@ SecurityConstants.INNER); } } } } /** * 发送websocket通知 * @param id * @param memberList * @param goodsSku * @param successFlag // 中标状态 1:中标 0:未中标 */ private void sendWebsocketMsg(Long id, List<Member> memberList, GoodsSku goodsSku, Integer successFlag, Map<Long, String> userIdMap) { for (Member member : memberList) { Map<String, Object> map = new ConcurrentHashMap<>(); map.put("notification_type", NotificationTypeConstant.AUCTION_POPUP); map.put("notification_time", DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss")); map.put("target_id", id); map.put("goods_name", goodsSku.getSkuName()); map.put("success_flag", successFlag); map.put("order_id", successFlag == 1 ? userIdMap.getOrDefault(member.getId(), "") : ""); String msg = JSONObject.toJSONString(map); sysUserClient.pushBatch( WebsocketMessageDTO.builder().message(msg).userId(member.getUserId()).build(), SecurityConstants.INNER); log.info("===================>发送websocket通知,消息体{}", msg); } } @@ -793,13 +870,12 @@ SecurityConstants.INNER); } auctionBidRecordService.updateBatchById(auctionBidRecordList); // 创建待支付订单 CustomConfig moneyConfig = sysUserClient.getconfig( ConfigEnum.MEMBER_POINTS_MONEY.getKey()).getData(); CustomConfig pointsConfig = sysUserClient.getconfig( ConfigEnum.MEMBER_POINTS_POINTS.getKey()).getData(); Map<Long, String> orderIdMap = new HashMap<>(); for (AuctionBidRecord auctionBidRecord : auctionBidRecordList) { BigDecimal lastBidAmount = auctionBidRecord.getLastBidAmount(); BigDecimal divide = lastBidAmount.divide( @@ -832,7 +908,56 @@ } orderDTO.setOrderTimeSx(auctionGoods.getEndTime()); orderDTO.setGoodsId(auctionGoods.getGoodsSkuId()); orderClient.saveOrderOne(orderDTO, SecurityConstants.INNER); Long orderId = orderClient.saveOrderOne(orderDTO, SecurityConstants.INNER) .getData(); if (Objects.nonNull(orderId)) { orderIdMap.put(auctionBidRecord.getMemberId(), orderId.toString()); auctionBidRecord.setOrderId(orderId); } } // 更新出价记录 auctionBidRecordService.updateBatchById(auctionBidRecordList); List<Long> successMemberIdList = auctionBidRecords.stream() .filter(auctionBidRecord -> auctionBidRecord.getStatus() .equals(BidStatusEnum.SUCCESSFUL)) .map(AuctionBidRecord::getMemberId) .collect(Collectors.toList()); List<Long> failedMemberIdList = auctionBidRecords.stream() .filter(auctionBidRecord -> !auctionBidRecord.getStatus() .equals(BidStatusEnum.SUCCESSFUL)) .map(AuctionBidRecord::getMemberId) .collect(Collectors.toList()); if (CollUtils.isNotEmpty(successMemberIdList)) { List<Member> successMemberList = memberClient.getMemberListByIds( successMemberIdList, SecurityConstants.INNER).getData(); if (CollUtils.isNotEmpty(successMemberList)) { // 推送websocket消息 sendWebsocketMsg(id, successMemberList, goodsSku, 1, orderIdMap); // 发送短信通知 List<String> mobileList = successMemberList.stream() .map(Member::getPhone) .collect(Collectors.toList()); authClient.sendSms(SmsSendDTO.builder().mobileList(mobileList) .content(SUCCESS_TEMPLATE.replace("content", goodsSku.getSkuName())) .build(), SecurityConstants.INNER); } } if (CollUtils.isNotEmpty(failedMemberIdList)) { List<Member> failedMemberList = memberClient.getMemberListByIds( failedMemberIdList, SecurityConstants.INNER).getData(); if (CollUtils.isNotEmpty(failedMemberList)) { // 推送websocket消息 sendWebsocketMsg(id, failedMemberList, goodsSku, 0, orderIdMap); // 发送短信通知 List<String> mobileList = failedMemberList.stream() .map(Member::getPhone) .collect(Collectors.toList()); authClient.sendSms(SmsSendDTO.builder().mobileList(mobileList) .content(FAILED_TEMPLATE.replace("content", goodsSku.getSkuName())) .build(), SecurityConstants.INNER); } } } else { // 没有人出价,退回拍卖商品库存 @@ -954,13 +1079,7 @@ } public static void main(String[] args) throws JsonProcessingException { Map<String, Object> map = new ConcurrentHashMap<>(); map.put("notification_type", NotificationTypeConstant.AUCTION_GOODS); map.put("notification_time", DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss")); map.put("target_id", 1); map.put("message_type", "end"); String msg = objectMapper.writeValueAsString(map); System.out.println(msg); System.out.println(SUCCESS_TEMPLATE.replace("content", "剑南春")); } @Override ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/service/impl/AuctionSalesroomGoodsServiceImpl.java
@@ -1,5 +1,6 @@ package com.ruoyi.auction.service.impl; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -23,6 +24,7 @@ import com.ruoyi.common.core.enums.OrderFromEnum; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.core.utils.page.CollUtils; import com.ruoyi.system.api.constants.NotificationTypeConstant; import com.ruoyi.system.api.domain.AuctionBondJl; import com.ruoyi.system.api.domain.AuctionSalesroom; @@ -36,17 +38,20 @@ import com.ruoyi.system.api.domain.Member; import com.ruoyi.system.api.domain.MemberAddress; import com.ruoyi.system.api.domain.Order; import com.ruoyi.system.api.domain.WebsocketMessageDTO; import com.ruoyi.system.api.domain.dto.AuctionSalesroomDTO; import com.ruoyi.system.api.domain.dto.AuctionSalesroomGoodsInfoDTO; import com.ruoyi.system.api.domain.dto.GoodsStockUpdDTO; import com.ruoyi.system.api.domain.dto.OrderAuctionBondDTO; import com.ruoyi.system.api.domain.dto.OrderDTO; import com.ruoyi.system.api.domain.dto.SmsSendDTO; import com.ruoyi.system.api.domain.vo.AuctionBidRecordVO; import com.ruoyi.system.api.domain.vo.AuctionSalesroomGoodsInfoVO; import com.ruoyi.system.api.domain.vo.AuctionSalesroomVO; import com.ruoyi.system.api.domain.vo.ForepartAuctionSalesroomGoodsVO; import com.ruoyi.system.api.domain.vo.GoodsInfoTitleValueVO; import com.ruoyi.system.api.domain.vo.getHomeGoodsSkuXxiVO; import com.ruoyi.system.api.feignClient.AuthClient; import com.ruoyi.system.api.feignClient.GoodsSkuClient; import com.ruoyi.system.api.feignClient.MemberClient; import com.ruoyi.system.api.feignClient.OrderClient; @@ -57,12 +62,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -74,6 +83,7 @@ * @author mitao * @since 2024-05-16 */ @Slf4j @Service public class AuctionSalesroomGoodsServiceImpl extends ServiceImpl<AuctionSalesroomGoodsMapper, AuctionSalesroomGoods> implements IAuctionSalesroomGoodsService { @Resource @@ -86,7 +96,7 @@ private AuctionBidRecordMapper auctionBidRecordMapper; @Resource private MemberClient emberClient; private MemberClient memberClient; @Resource private OrderClient orderClient; @@ -104,11 +114,12 @@ @Resource private AuctionBondJlMapper auctionBondJlMapper; @Resource private AuthClient authClient; private static final ObjectMapper objectMapper = new ObjectMapper(); private static final String SUCCESS_TEMPLATE = "【酒鼎老酒】恭喜!您参与的“content”竞拍已中拍!"; private static final String FAILED_TEMPLATE = "【酒鼎老酒】很遗憾!您参与的”content“竞拍未中拍!"; /** @@ -504,15 +515,21 @@ wrapper.orderByDesc(AuctionBidRecord::getLastBidAmount); wrapper.orderByAsc(AuctionBidRecord::getLastBidTime); auctionBidRecordList = auctionBidRecordMapper.selectList(wrapper); Map<Long, String> orderIdMap = new HashMap<>(); if(auctionBidRecordList.size()>0){ //判断 if (auctionBidRecordList.size() >= auctionSalesroomGoods.getSalesroomStock()) { for (int i = 0; i < auctionSalesroomGoods.getSalesroomStock(); i++) { AuctionBidRecord auctionBidRecord = auctionBidRecordList.get(i); auctionBidRecord.setStatus(BidStatusEnum.SUCCESSFUL); auctionBidRecordMapper.updateById(auctionBidRecord); AddOrder(auctionBidRecord.getTargetId(), auctionBidRecord.getMemberId(), Long orderId = AddOrder(auctionBidRecord.getTargetId(), auctionBidRecord.getMemberId(), auctionBidRecord.getLastBidAmount(), auctionSalesroom.getBond()); if (Objects.nonNull(orderId)) { orderIdMap.put(auctionBidRecord.getMemberId(), orderId.toString()); auctionBidRecord.setOrderId(orderId); } auctionBidRecordMapper.updateById(auctionBidRecord); } } else { GoodsStockUpdDTO goodsStockUpdDTO = new GoodsStockUpdDTO(); @@ -525,10 +542,57 @@ for (int i = 0; i < auctionBidRecordList.size(); i++) { AuctionBidRecord auctionBidRecord = auctionBidRecordList.get(i); auctionBidRecord.setStatus(BidStatusEnum.SUCCESSFUL); auctionBidRecordMapper.updateById(auctionBidRecord); AddOrder(auctionBidRecord.getTargetId(), auctionBidRecord.getMemberId(), Long orderId = AddOrder(auctionBidRecord.getTargetId(), auctionBidRecord.getMemberId(), auctionBidRecord.getLastBidAmount(), auctionSalesroom.getBond()); if (Objects.nonNull(orderId)) { orderIdMap.put(auctionBidRecord.getMemberId(), orderId.toString()); auctionBidRecord.setOrderId(orderId); } auctionBidRecordMapper.updateById(auctionBidRecord); } } } GoodsSku goodsSku = goodsSkuClient.getGoodsSkuOne(auctionSalesroomGoods.getGoodsSkuId(), SecurityConstants.INNER).getData(); List<Long> successMemberIdList = auctionBidRecordList.stream() .filter(auctionBidRecord -> auctionBidRecord.getStatus() .equals(BidStatusEnum.SUCCESSFUL)) .map(AuctionBidRecord::getMemberId) .collect(Collectors.toList()); List<Long> failedMemberIdList = auctionBidRecordList.stream() .filter(auctionBidRecord -> !auctionBidRecord.getStatus() .equals(BidStatusEnum.SUCCESSFUL)) .map(AuctionBidRecord::getMemberId) .collect(Collectors.toList()); if (CollUtils.isNotEmpty(successMemberIdList)) { List<Member> successMemberList = memberClient.getMemberListByIds( successMemberIdList, SecurityConstants.INNER).getData(); if (CollUtils.isNotEmpty(successMemberList)) { // 推送websocket消息 sendWebsocketMsg(auctionSalesroomGoods.getId(), successMemberList, goodsSku, 1, orderIdMap); // 发送短信通知 List<String> mobileList = successMemberList.stream().map(Member::getPhone) .collect(Collectors.toList()); authClient.sendSms(SmsSendDTO.builder().mobileList(mobileList) .content(SUCCESS_TEMPLATE.replace("content", goodsSku.getSkuName())) .build(), SecurityConstants.INNER); } } if (CollUtils.isNotEmpty(failedMemberIdList)) { List<Member> failedMemberList = memberClient.getMemberListByIds( failedMemberIdList, SecurityConstants.INNER).getData(); if (CollUtils.isNotEmpty(failedMemberList)) { // 推送websocket消息 sendWebsocketMsg(auctionSalesroomGoods.getId(), failedMemberList, goodsSku, 0, orderIdMap); // 发送短信通知 List<String> mobileList = failedMemberList.stream().map(Member::getPhone) .collect(Collectors.toList()); authClient.sendSms(SmsSendDTO.builder().mobileList(mobileList) .content(FAILED_TEMPLATE.replace("content", goodsSku.getSkuName())) .build(), SecurityConstants.INNER); } } } @@ -554,6 +618,30 @@ } /** * 发送websocket通知 * @param id * @param memberList * @param goodsSku * @param successFlag // 中标状态 1:中标 0:未中标 */ private void sendWebsocketMsg(Long id, List<Member> memberList, GoodsSku goodsSku, Integer successFlag, Map<Long, String> userIdMap) { for (Member member : memberList) { Map<String, Object> map = new ConcurrentHashMap<>(); map.put("notification_type", NotificationTypeConstant.AUCTION_POPUP); map.put("notification_time", DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss")); map.put("target_id", id); map.put("goods_name", Objects.nonNull(goodsSku) ? goodsSku.getSkuName() : ""); map.put("success_flag", successFlag); map.put("order_id", successFlag == 1 ? userIdMap.getOrDefault(member.getId(), "") : ""); String msg = JSONObject.toJSONString(map); sysUserClient.pushBatch( WebsocketMessageDTO.builder().message(msg).userId(member.getUserId()).build(), SecurityConstants.INNER); log.info("===================>发送websocket通知,消息体{}", msg); } } @Override public AuctionSalesroomGoodsInfoVO getAuctionSalesroomGoodsInfo(AuctionSalesroomGoodsInfoDTO auctionSalesroomGoodsInfoDTO) { AuctionSalesroom byId = auctionSalesroomMapper.selectById(auctionSalesroomGoodsInfoDTO.getAuctionSalesroomId()); @@ -727,7 +815,7 @@ auctionBidRecordVO.setSort(Integer.valueOf(count.intValue())); auctionBidRecordVO.setLastBidAmount(auctionBidRecord.getLastBidAmount()); auctionBidRecordVO.setLastBidTime(auctionBidRecord.getLastBidTime()); Member data = emberClient.getMembeOne(auctionBidRecord.getMemberId(), Member data = memberClient.getMembeOne(auctionBidRecord.getMemberId(), SecurityConstants.INNER).getData(); if (data!=null){ auctionBidRecordVO.setMemberName(data.getNickname()); @@ -755,7 +843,8 @@ } public void AddOrder(Long goodsSkuId, Long memberId, BigDecimal lastBidAmount,BigDecimal bound) { public Long AddOrder(Long goodsSkuId, Long memberId, BigDecimal lastBidAmount, BigDecimal bound) { OrderDTO order=new OrderDTO(); order.setGoodsSkuId(goodsSkuId); order.setOrderTime(LocalDateTime.now()); @@ -767,7 +856,7 @@ order.setTotalAmount(lastBidAmount); order.setAuctionSalesroomId(auctionSalesroomGoods.getAuctionSalesroomId()); R<MemberAddress> memberAddressR = emberClient.getMemberAddressOne(memberId, R<MemberAddress> memberAddressR = memberClient.getMemberAddressOne(memberId, SecurityConstants.INNER); MemberAddress memberAddress=memberAddressR.getData(); @@ -799,7 +888,7 @@ order.setCoverPic(goodsSku.getCoverPic()); order.setPrice(lastBidAmount); order.setGoodsId(auctionSalesroomGoods.getGoodsSkuId()); orderClient.saveOrderOne(order,SecurityConstants.INNER); return orderClient.saveOrderOne(order, SecurityConstants.INNER).getData(); } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/service/impl/AuctionSalesroomServiceImpl.java
@@ -49,6 +49,7 @@ import com.ruoyi.common.core.enums.ClientTypeEnum; import com.ruoyi.common.core.enums.OrderFromEnum; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.core.utils.IDhelper; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.page.BeanUtils; @@ -82,12 +83,14 @@ import com.ruoyi.system.api.domain.dto.OrderAuctionBondDTO; import com.ruoyi.system.api.domain.dto.OrderDTO; import com.ruoyi.system.api.domain.dto.RefundDTO; import com.ruoyi.system.api.domain.dto.SmsSendDTO; import com.ruoyi.system.api.domain.vo.ForepartAuctionSalesroomGoodsVO; import com.ruoyi.system.api.domain.vo.ForepartAuctionSalesroomVO; import com.ruoyi.system.api.domain.vo.MemberAuctionSalesroomInfoVO; import com.ruoyi.system.api.domain.vo.MemberAuctionSalesroomVO; import com.ruoyi.system.api.domain.vo.PayInfoVO; import com.ruoyi.system.api.domain.vo.WdMemberAuctionSalesroomVO; import com.ruoyi.system.api.feignClient.AuthClient; import com.ruoyi.system.api.feignClient.GoodsSkuClient; import com.ruoyi.system.api.feignClient.MemberClient; import com.ruoyi.system.api.feignClient.OrderClient; @@ -105,6 +108,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -182,6 +186,11 @@ @Resource private RedissonClient redissonClient; @Resource private AuthClient authClient; private static final String SUCCESS_TEMPLATE = "【酒鼎老酒】恭喜!您参与的“content”竞拍已中拍!"; private static final String FAILED_TEMPLATE = "【酒鼎老酒】很遗憾!您参与的”content“竞拍未中拍!"; public static RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).build(); // 配置您申请的KEY,在个人中心->我的数据,接口名称上方查看 public static final String APPKEY = ""; @@ -1490,19 +1499,32 @@ .orderByAsc(AuctionBidRecord::getLastBidTime)); if (CollUtils.isNotEmpty(auctionBidRecordList)) { List<AuctionBidRecord> auctionBidRecords = new ArrayList<>(); Map<Long, String> orderIdMap = new HashMap<>(); if (auctionBidRecordList.size() >= auctionSalesroomGoods.getSalesroomStock()) { for (int i = 0; i < auctionSalesroomGoods.getSalesroomStock(); i++) { AuctionBidRecord auctionBidRecord = auctionBidRecordList.get(i); auctionBidRecord.setStatus(BidStatusEnum.SUCCESSFUL); auctionBidRecordMapper.updateById(auctionBidRecord); auctionBidRecords.add(auctionBidRecord); Long orderId = addOrder(auctionBidRecord.getTargetId(), auctionBidRecord.getMemberId(), auctionBidRecord.getLastBidAmount(), auctionSalesroom.getBond()); orderIdMap.put(auctionBidRecord.getMemberId(), orderId.toString()); auctionBidRecord.setOrderId(orderId); auctionBidRecordMapper.updateById(auctionBidRecord); } } else { for (int i = 0; i < auctionBidRecordList.size(); i++) { AuctionBidRecord auctionBidRecord = auctionBidRecordList.get(i); auctionBidRecord.setStatus(BidStatusEnum.SUCCESSFUL); auctionBidRecordMapper.updateById(auctionBidRecord); auctionBidRecords.add(auctionBidRecord); Long orderId = addOrder(auctionBidRecord.getTargetId(), auctionBidRecord.getMemberId(), auctionBidRecord.getLastBidAmount(), auctionSalesroom.getBond()); orderIdMap.put(auctionBidRecord.getMemberId(), orderId.toString()); auctionBidRecord.setOrderId(orderId); auctionBidRecordMapper.updateById(auctionBidRecord); } // 没有出价记录,回退库存 GoodsStockUpdDTO goodsStockUpdDTO = new GoodsStockUpdDTO(); @@ -1513,10 +1535,54 @@ goodsSkuClient.updGoodsStock(Lists.newArrayList(goodsStockUpdDTO), SecurityConstants.INNER); } for (AuctionBidRecord auctionBidRecord : auctionBidRecords) { addOrder(auctionBidRecord.getTargetId(), auctionBidRecord.getMemberId(), auctionBidRecord.getLastBidAmount(), auctionSalesroom.getBond()); GoodsSku goodsSku = goodsSkuClient.getGoodsSkuOne( auctionSalesroomGoods.getGoodsSkuId(), SecurityConstants.INNER).getData(); List<Long> successMemberIdList = auctionBidRecordList.stream() .filter(auctionBidRecord -> auctionBidRecord.getStatus() .equals(BidStatusEnum.SUCCESSFUL)) .map(AuctionBidRecord::getMemberId) .collect(Collectors.toList()); List<Long> failedMemberIdList = auctionBidRecordList.stream() .filter(auctionBidRecord -> !auctionBidRecord.getStatus() .equals(BidStatusEnum.SUCCESSFUL)) .map(AuctionBidRecord::getMemberId) .collect(Collectors.toList()); if (CollUtils.isNotEmpty(successMemberIdList)) { List<Member> successMemberList = memberClient.getMemberListByIds( successMemberIdList, SecurityConstants.INNER).getData(); if (CollUtils.isNotEmpty(successMemberList)) { // 推送websocket消息 sendWebsocketMsg(auctionSalesroomGoods.getId(), successMemberList, goodsSku, 1, orderIdMap); // 发送短信通知 List<String> mobileList = successMemberList.stream() .map(Member::getPhone) .collect(Collectors.toList()); authClient.sendSms(SmsSendDTO.builder().mobileList(mobileList) .content(SUCCESS_TEMPLATE.replace("content", goodsSku.getSkuName())) .build(), SecurityConstants.INNER); } } if (CollUtils.isNotEmpty(failedMemberIdList)) { List<Member> failedMemberList = memberClient.getMemberListByIds( failedMemberIdList, SecurityConstants.INNER).getData(); if (CollUtils.isNotEmpty(failedMemberList)) { // 推送websocket消息 sendWebsocketMsg(auctionSalesroomGoods.getId(), failedMemberList, goodsSku, 0, orderIdMap); // 发送短信通知 List<String> mobileList = failedMemberList.stream() .map(Member::getPhone) .collect(Collectors.toList()); authClient.sendSms(SmsSendDTO.builder().mobileList(mobileList) .content(FAILED_TEMPLATE.replace("content", goodsSku.getSkuName())) .build(), SecurityConstants.INNER); } } } else { // 没有出价记录,回退库存 @@ -1545,7 +1611,32 @@ } } public void addOrder(Long goodsSkuId, Long memberId, BigDecimal lastBidAmount, /** * 发送websocket通知 * @param id * @param memberList * @param goodsSku * @param successFlag // 中标状态 1:中标 0:未中标 */ private void sendWebsocketMsg(Long id, List<Member> memberList, GoodsSku goodsSku, Integer successFlag, Map<Long, String> userIdMap) { for (Member member : memberList) { Map<String, Object> map = new ConcurrentHashMap<>(); map.put("notification_type", NotificationTypeConstant.AUCTION_POPUP); map.put("notification_time", DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss")); map.put("target_id", id); map.put("goods_name", Objects.nonNull(goodsSku) ? goodsSku.getSkuName() : ""); map.put("success_flag", successFlag); map.put("order_id", successFlag == 1 ? userIdMap.getOrDefault(member.getId(), "") : ""); String msg = com.alibaba.fastjson2.JSONObject.toJSONString(map); sysUserClient.pushBatch( WebsocketMessageDTO.builder().message(msg).userId(member.getUserId()).build(), SecurityConstants.INNER); log.info("===================>发送websocket通知,消息体{}", msg); } } public Long addOrder(Long goodsSkuId, Long memberId, BigDecimal lastBidAmount, BigDecimal bound) { OrderDTO order = new OrderDTO(); order.setGoodsSkuId(goodsSkuId); @@ -1596,7 +1687,7 @@ order.setCoverPic(goodsSku.getCoverPic()); order.setPrice(lastBidAmount); order.setGoodsId(auctionSalesroomGoods.getGoodsSkuId()); orderClient.saveOrderOne(order, SecurityConstants.INNER); return orderClient.saveOrderOne(order, SecurityConstants.INNER).getData(); } /** * 开始下一拍卖商品 ruoyi-modules/ruoyi-member/src/main/java/com/ruoyi/member/controller/management/MgtMemberController.java
@@ -10,6 +10,7 @@ import com.ruoyi.member.service.IMemberService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import javax.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; @@ -23,6 +24,7 @@ * @author mitao * @date 2024/5/27 */ @Validated @RestController @RequestMapping("/mgt/member") @RequiredArgsConstructor @@ -39,7 +41,7 @@ */ @ApiOperation(value = "获取会员管理分页列表", notes = "获取会员管理分页列表") @PostMapping("/page") public R<PageDTO<MgtMemberVO>> getMemberPage(@Validated @RequestBody MgtMemberQuery query) { public R<PageDTO<MgtMemberVO>> getMemberPage(@Valid @RequestBody MgtMemberQuery query) { return R.ok(memberService.getMemberPage(query)); } @@ -58,7 +60,7 @@ @ApiOperation("查看详情-积分明细") @PostMapping("/points/detail") public R<PageDTO<MgtMemberPointsVO>> getMemberPoints( @Validated @RequestBody MgtMemberPointsQuery query) { @Valid @RequestBody MgtMemberPointsQuery query) { return R.ok(memberService.getMemberPoints(query)); } @@ -69,7 +71,7 @@ */ @ApiOperation("编辑用户会员分类") @PostMapping("/update/vipClassify") public R<?> updMemberClassify(@RequestBody MgtMemberDTO dto) { public R<?> updMemberClassify(@Valid @RequestBody MgtMemberDTO dto) { memberService.updMemberClassify(dto); return R.ok(); } ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/inner/OrderController.java
@@ -19,7 +19,6 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.formula.functions.T; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -49,7 +48,7 @@ @PostMapping("/saveOrderOne") @ResponseBody @InnerAuth public R<T> saveOrderOne(@RequestBody OrderDTO OrderDTO) { public R<Long> saveOrderOne(@RequestBody OrderDTO OrderDTO) { orderService.saveOrderOne(OrderDTO); return R.ok(); ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/IOrderService.java
@@ -32,7 +32,7 @@ */ public interface IOrderService extends IService<Order> { void saveOrderOne(OrderDTO OrderDTO); Long saveOrderOne(OrderDTO OrderDTO); /** * 获取某个商品的已购会员数 ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java
@@ -160,7 +160,7 @@ @Override public void saveOrderOne(OrderDTO OrderDTO) { public Long saveOrderOne(OrderDTO OrderDTO) { Order order=new Order(); if (OrderDTO.getOrderFrom().getCode()==1){ order.setOrderFrom(OrderFromEnum.COMMODITY_ORDER); @@ -234,7 +234,7 @@ } return order.getId(); } /** ruoyi-modules/ruoyi-promotion/src/main/resources/mapper/promotion/PromotionWishMapper.xml
@@ -41,7 +41,7 @@ FROM t_promotion_wish tpw INNER JOIN t_promotion_wish_list tpwl ON tpw.id = tpwl.wish_id <where> tpw.del_flag = 0 AND tpw.recommend_status = 1 tpw.del_flag = 0 AND tpw.recommend_status = 1 and tpw.show_flag = 1 </where> GROUP BY tpwl.wish_id,tpw.member_id </select> ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/WebSocketController.java
@@ -42,6 +42,17 @@ } /** * 批量向指定用户推送消息 * @param dto * @return */ @InnerAuth @PostMapping("/push-batch") public R<?> pushBatch(@RequestBody WebsocketMessageDTO dto) { WebSocketUsers.sendMessageToUserById(dto.getUserId(), dto.getMessage()); return R.ok(); } /** * 通过用户id推送消息 * @param type * @param msg