ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteFileService.java
@@ -7,8 +7,11 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; /** * 文件服务 @@ -29,4 +32,8 @@ @PostMapping(value = "/obs/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R<String> obsUpload(@RequestPart("file") MultipartFile file); @PostMapping("/obs/upload/stream") public R<String> obsUpload(@RequestParam("code") String code, @RequestParam("stream") InputStream stream); } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/AuctionSalesroomGoods.java
@@ -53,6 +53,15 @@ @ApiModelProperty(value = "拍品数量") private Integer salesroomStock; @ApiModelProperty(value = "可中拍人数") private Integer bidNum; @ApiModelProperty(value = "最高出价金额") private BigDecimal maxAmount; @ApiModelProperty(value = "一次性每人成交数量") private Integer dealQuantity; @ApiModelProperty(value = "兜底成交个数") @TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED) private Integer guaranteedTradeVolume; ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/GoodsSku.java
@@ -59,6 +59,12 @@ @ApiModelProperty(value = "商品价格") private BigDecimal price; @ApiModelProperty(value = "普通会员价格") private BigDecimal vipPrice; @ApiModelProperty(value = "超级会员价格") private BigDecimal superVipPrice; @ApiModelProperty(value = "库存") private Integer stock; @@ -118,7 +124,7 @@ @ApiModelProperty(value = "删除标志(0代表存在 1代表删除)") @TableLogic private Integer delFlag; @ApiModelProperty(value = "商品封面图(大屏)") private String screenCoverPic; ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/Member.java
@@ -82,6 +82,9 @@ @ApiModelProperty(value = "支付宝openid") private String zfbOpenid; @ApiModelProperty(value = "会员分类(1:普通用户;2:会员用户;3:超级会员用户)") private Integer vipClassify; @ApiModelProperty(value = "创建者") @TableField(value = "create_by", fill = FieldFill.INSERT) private String createBy; ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/AuctionFallbackFactory.java
@@ -110,6 +110,11 @@ Set<Long> auctionSalesroomGoodsSet, String source) { return R.fail("获取商品信息失败" + cause.getMessage()); } @Override public R<AuctionGoods> getAuctionBySkuId(Long goodsSkuId, String source) { return R.fail("获取拍卖商品失败" + cause.getMessage()); } }; } } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteFileFallbackFactory.java
@@ -9,6 +9,8 @@ import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; /** * 文件服务降级处理 * @@ -35,6 +37,11 @@ public R<String> obsUpload(MultipartFile file) { return R.fail("obs上传文件失败:" + throwable.getMessage()); } @Override public R<String> obsUpload(String code, InputStream stream) { return R.fail("obs上传文件失败:" + throwable.getMessage()); } }; } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/feignClient/AuctionClient.java
@@ -108,4 +108,8 @@ R<List<GoodsSku>> getGoodsSkuByAuctionSalesroomGoodsSet( @RequestBody Set<Long> auctionSalesroomGoodsSet, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); @GetMapping("/auction-goods/getAuctionBySkuId/{goodsSkuId}") R<AuctionGoods> getAuctionBySkuId(@PathVariable("goodsSkuId") Long goodsSkuId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); } ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/SecurityUtils.java
@@ -3,6 +3,7 @@ import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.constant.TokenConstants; import com.ruoyi.common.core.context.SecurityContextHolder; import com.ruoyi.common.core.exception.auth.NotLoginException; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.system.api.model.LoginUser; @@ -71,6 +72,21 @@ } /** * 判断用户是否登录 */ public static boolean isLogin() { String token = SecurityUtils.getToken(); if (token == null) { return false; } LoginUser loginUser = SecurityUtils.getLoginUser(); return loginUser != null; } /** * 裁剪token前缀 */ public static String replaceTokenPrefix(String token) ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/controller/inner/AuctionGoodsController.java
@@ -1,6 +1,7 @@ package com.ruoyi.auction.controller.inner; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.ruoyi.auction.service.IAuctionGoodsService; import com.ruoyi.common.core.domain.R; @@ -100,4 +101,14 @@ R<List<GoodsSku>> getGoodsSkuByAuctionGoodsIdSet(@RequestBody Set<Long> auctionGoodsIdSet) { return R.ok(auctionGoodsService.getGoodsSkuByAuctionGoodsIdSet(auctionGoodsIdSet)); } /** * 根据商品id获取拍卖商品 */ @InnerAuth @GetMapping("/getAuctionBySkuId/{goodsSkuId}") R<AuctionGoods> getAuctionBySkuId(@PathVariable("goodsSkuId") Long goodsSkuId) { return R.ok(auctionGoodsService.getOne(new LambdaQueryWrapper<AuctionGoods>() .eq(AuctionGoods::getGoodsSkuId, goodsSkuId))); } } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/controller/management/MgtAuctionGoodsController.java
@@ -4,22 +4,20 @@ import com.ruoyi.auction.controller.management.dto.MgtAuctionGoodsDTO; import com.ruoyi.auction.controller.management.dto.MgtAuctionGoodsQuery; import com.ruoyi.auction.controller.management.vo.MgtAuctionGoodsVO; import com.ruoyi.auction.mapper.AuctionBidRecordMapper; import com.ruoyi.auction.service.IAuctionGoodsService; import com.ruoyi.auction.service.IAuctionSalesroomGoodsService; import com.ruoyi.auction.service.IAuctionSalesroomService; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.page.PageDTO; import com.ruoyi.system.api.domain.dto.ListStatusDTO; import com.ruoyi.system.api.feignClient.GoodsSkuClient; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.*; /** * <p> @@ -100,4 +98,7 @@ return R.ok(); } } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/controller/management/MgtAuctionSalesroomController.java
@@ -1,28 +1,52 @@ package com.ruoyi.auction.controller.management; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.util.DateUtils; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.google.zxing.WriterException; import com.ruoyi.auction.controller.management.dto.MgtAuctionSaleroomBidRecordQuery; import com.ruoyi.auction.controller.management.dto.MgtAuctionSalesroomDTO; import com.ruoyi.auction.controller.management.dto.MgtAuctionSalesroomQuery; import com.ruoyi.auction.controller.management.vo.AuctionBidRecordVO; import com.ruoyi.auction.controller.management.vo.MgtAuctionBidRecordVO; import com.ruoyi.auction.controller.management.vo.MgtAuctionSalesroomVO; import com.ruoyi.auction.domain.AuctionBidRecord; import com.ruoyi.auction.mapper.AuctionBidRecordMapper; import com.ruoyi.auction.service.IAuctionSalesroomGoodsService; import com.ruoyi.auction.service.IAuctionSalesroomService; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.enums.AuctionOrderTypeEnum; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.page.BeanUtils; import com.ruoyi.common.core.utils.page.PageDTO; import com.ruoyi.system.api.domain.AuctionSalesroom; import com.ruoyi.system.api.domain.AuctionSalesroomGoods; import com.ruoyi.system.api.domain.GoodsSku; import com.ruoyi.system.api.feignClient.GoodsSkuClient; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import java.io.IOException; import java.math.BigDecimal; import java.net.URLEncoder; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; /** * <p> @@ -40,6 +64,9 @@ public class MgtAuctionSalesroomController { private final IAuctionSalesroomService auctionSalesroomService; private final AuctionBidRecordMapper auctionBidRecordMapper; private final IAuctionSalesroomGoodsService auctionSalesroomGoodsService; private final GoodsSkuClient goodsSkuClient; /** * 分页查询拍卖场 @@ -114,4 +141,125 @@ @Validated @RequestBody MgtAuctionSaleroomBidRecordQuery query) { return R.ok(auctionSalesroomService.getAuctionSalesroomBidRecordList(query)); } /** * 删除拍卖场 */ @DeleteMapping("/{id}") @ApiOperation(value = "删除拍卖场", notes = "删除拍卖场") public R<?> deleteAuctionSalesroom(@PathVariable("id") Long id){ auctionSalesroomService.removeById(id); return R.ok(); } /** * 导出列表 */ @ApiOperation("导出列表") @PostMapping("/export") @ApiImplicitParam(name = "ids", value = "查询条件", required = true) public void export(@RequestBody String query, HttpServletResponse response) { // 验证输入是否为空或格式不正确 if (StringUtils.isEmpty(query)) { throw new ServiceException("查询条件不能为空"); } JSONObject jsonObject = JSONObject.parseObject(query); List<String> ids = jsonObject.getList("ids", String.class); // 验证ids是否为空 if (CollectionUtils.isEmpty(ids)) { throw new ServiceException("ids不能为空"); } List<AuctionBidRecord> auctionBidRecordList = auctionBidRecordMapper.selectList( new LambdaQueryWrapper<AuctionBidRecord>() .in(!CollectionUtils.isEmpty(ids),AuctionBidRecord::getAuctionSalesroomId, ids) .eq(AuctionBidRecord::getAuctionType, AuctionOrderTypeEnum.AUCTION_ITEMS) ); if (CollectionUtils.isEmpty(auctionBidRecordList)) { return; } // 提取 goodsIds 和 auctionSalesroomIds Set<Long> goodsIds = auctionBidRecordList.stream() .map(AuctionBidRecord::getTargetId) .collect(Collectors.toSet()); Set<Long> auctionSalesroomIds = auctionBidRecordList.stream() .map(AuctionBidRecord::getAuctionSalesroomId) .collect(Collectors.toSet()); // 查询拍卖销售室商品信息 List<AuctionSalesroomGoods> salesroomGoodss = auctionSalesroomGoodsService.list( new LambdaQueryWrapper<AuctionSalesroomGoods>() .in(AuctionSalesroomGoods::getAuctionSalesroomId, auctionSalesroomIds) .in(AuctionSalesroomGoods::getGoodsSkuId, goodsIds) ); Map<String, AuctionSalesroomGoods> roomMap = salesroomGoodss.stream() .collect(Collectors.toMap( i -> String.format("%s-%s", i.getAuctionSalesroomId(), i.getGoodsSkuId()), i -> i )); // 查询拍卖场信息 List<AuctionSalesroom> auctionSalesroomList = auctionSalesroomService.listByIds(auctionSalesroomIds); Map<Long, AuctionSalesroom> auctionSalesroomMap = auctionSalesroomList.stream() .collect(Collectors.toMap(AuctionSalesroom::getId, e -> e)); // 查询商品信息 R<List<GoodsSku>> goodsListByIdsR = goodsSkuClient.getGoodsListByIds(goodsIds, SecurityConstants.INNER); if (R.isError(goodsListByIdsR)) { throw new ServiceException("查询商品信息失败"); } List<GoodsSku> goodsSkuList = goodsListByIdsR.getData(); Map<Long, GoodsSku> goodsSkuMap = goodsSkuList.stream().collect(Collectors.toMap(GoodsSku::getId, e -> e)); // 构建结果列表 List<AuctionBidRecordVO> result = auctionBidRecordList.stream().map(auctionBidRecord -> { AuctionBidRecordVO auctionBidRecordVO = BeanUtils.copyBean(auctionBidRecord, AuctionBidRecordVO.class); auctionBidRecordVO.setNum(auctionBidRecordList.indexOf(auctionBidRecord) + 1); AuctionSalesroomGoods salesroomGoods = roomMap.get(String.format("%s-%s", auctionBidRecord .getAuctionSalesroomId(), auctionBidRecord.getTargetId())); if (salesroomGoods != null) { BigDecimal totalAmount = auctionBidRecord.getLastBidAmount().multiply(new BigDecimal(salesroomGoods .getDealQuantity())); auctionBidRecordVO.setTotalAmount(totalAmount); } AuctionSalesroom auctionSalesroom = auctionSalesroomMap.get(auctionBidRecord.getAuctionSalesroomId()); if (auctionSalesroom != null) { auctionBidRecordVO.setAuctionSalesroomName(auctionSalesroom.getSalesroomName()); } GoodsSku goodsSku = goodsSkuMap.get(auctionBidRecord.getTargetId()); if (goodsSku != null) { auctionBidRecordVO.setGoodsSkuName(goodsSku.getSkuName()); } return auctionBidRecordVO; }).collect(Collectors.toList()); response.setContentType( "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 try { String fileName = URLEncoder.encode( "优惠券领取明细" + DateUtils.format(new Date(), "yyyyMMddHHmmss"), "UTF-8") .replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), AuctionBidRecordVO.class) .sheet("优惠券领取明细") .doWrite(result); } catch (IOException e) { throw new RuntimeException(e); } } } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/controller/management/vo/AuctionBidRecordVO.java
New file @@ -0,0 +1,34 @@ package com.ruoyi.auction.controller.management.vo; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data public class AuctionBidRecordVO { @ExcelProperty(value = "序号") private Integer num; @ExcelProperty(value = "姓名") private String nickname; @ExcelProperty(value = "电话") private String phone; @ExcelProperty(value = "单品出价金额") private BigDecimal lastBidAmount; @ExcelProperty(value = "总价") private BigDecimal totalAmount; @ExcelProperty(value = "出价时间") private LocalDateTime lastBidTime; @ExcelProperty(value = "拍卖会名称") private String auctionSalesroomName; @ExcelProperty(value = "拍品名称") private String goodsSkuName; } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/domain/AuctionBidRecord.java
@@ -1,22 +1,18 @@ package com.ruoyi.auction.domain; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.*; import com.ruoyi.common.core.enums.AuctionOrderTypeEnum; import com.ruoyi.common.core.enums.BidStatusEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; /** * <p> * 出价记录表 ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/service/IAuctionGoodsService.java
@@ -81,4 +81,6 @@ List<AuctionGoods> getAuctionGoodsBySkuId(Long id); List<GoodsSku> getGoodsSkuByAuctionGoodsIdSet(Set<Long> auctionGoodsIdSet); } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/util/weChat/AES.java
New file @@ -0,0 +1,72 @@ package com.ruoyi.auction.util.weChat; import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.*; /** * AES加密 * @author pzb * @Date 2021/12/3 15:43 */ public class AES { public static boolean initialized = false; /** * AES解密 * * @param content * 密文 * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchProviderException */ public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException { initialize(); try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); Key sKeySpec = new SecretKeySpec(keyByte, "AES"); cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化 byte[] result = cipher.doFinal(content); return result; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (NoSuchProviderException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public static void initialize() { if (initialized) return; Security.addProvider(new BouncyCastleProvider()); initialized = true; } // 生成iv public static AlgorithmParameters generateIV(byte[] iv) throws Exception { AlgorithmParameters params = AlgorithmParameters.getInstance("AES"); params.init(new IvParameterSpec(iv)); return params; } } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/util/weChat/EnvVersion.java
New file @@ -0,0 +1,35 @@ package com.ruoyi.auction.util.weChat; /** * @author zhibing.pu * @Date 2024/12/10 15:56 */ public enum EnvVersion { /** * 开发版 */ DEVELOP("develop"), /** * 体验版 */ TRIAL("trial"), /** * 线上版本 */ RELEASE("release"); EnvVersion(String version) { this.version = version; } private String version; public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/util/weChat/WXCore.java
New file @@ -0,0 +1,48 @@ package com.ruoyi.auction.util.weChat; import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Value; public class WXCore { private static final String WATERMARK = "watermark"; @Value("${wx.appletsAppid}") private static String appid ; /** * 解密数据 * @return * @throws Exception */ public static String decrypt(String encryptedData, String sessionKey, String iv){ String result = ""; try { AES aes = new AES(); byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv)); if(null != resultByte && resultByte.length > 0){ result = new String(WxPKCS7Encoder.decode(resultByte), "UTF-8"); // JSONObject jsonObject = JSON.parseObject(result); // String decryptAppid = jsonObject.getJSONObject(WATERMARK).getString("appid"); // if(!appid.equals(decryptAppid)){ // result = ""; // } } } catch (Exception e) { result = ""; e.printStackTrace(); } return result; } public static void main(String[] args) throws Exception{ String appId = "wx4f4bc4dec97d474b"; String encryptedData = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew=="; String sessionKey = "tiihtNczf5v6AKRyjwEUhQ=="; String iv = "r7BXXKkLb8qrSNn05n0qiA=="; System.out.println(decrypt(encryptedData, sessionKey, iv)); } } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/util/weChat/WeChatUtil.java
New file @@ -0,0 +1,243 @@ package com.ruoyi.auction.util.weChat; import cn.hutool.http.Header; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.system.api.RemoteFileService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; /** * 微信工具类 */ @Slf4j @Component public class WeChatUtil { @Value("${wx.appletsAppid}") private String wxAppletsAppid; @Value("${wx.appletsAppSecret}") private String wxAppletsAppSecret; // @Value("${wx.appid}") private String webAppId; // @Value("${wx.appSecret}") private String webAppSecret; @Resource private RedisService redisService; @Resource private RemoteFileService remoteFileService; /** * 小程序使用jscode获取openid * @param jscode * @return */ public Map<String, Object> code2Session(String jscode) { String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxAppletsAppid + "&secret=" + wxAppletsAppSecret + "&js_code=" + jscode + "&grant_type=authorization_code"; HttpRequest get = HttpUtil.createGet(url); HttpResponse response = get.execute(); int status = response.getStatus(); if(200 != status){ throw new RuntimeException(response.body()); } JSONObject jsonObject = JSON.parseObject(response.body()); int errcode = jsonObject.getIntValue("errcode"); Map<String, Object> map = new HashMap<>(); map.put("errcode", errcode); if(errcode == 0){//成功 map.put("openid", jsonObject.getString("openid")); map.put("sessionKey", jsonObject.getString("session_key")); map.put("unionid", jsonObject.getString("unionid")); return map; } if(errcode == -1){//系统繁忙,此时请开发者稍候再试 map.put("msg", jsonObject.getString("errmsg")); return map; } if(errcode == 40029){//code 无效 map.put("msg", jsonObject.getString("errmsg")); return map; } if(errcode == 45011){//频率限制,每个用户每分钟100次 map.put("msg", jsonObject.getString("errmsg")); return map; } return null; } public String getWxAppletsAccessToken(){ Object wxAppletsAccessToken = redisService.getCacheObject("wxAppletsAccessToken"); if(null != wxAppletsAccessToken){ return wxAppletsAccessToken.toString(); } String appletsAccessToken = getAppletsAccessToken(); redisService.setCacheObject("wxAppletsAccessToken", appletsAccessToken, 7200L, TimeUnit.SECONDS); return appletsAccessToken; } /** * 获取微信小程序token * @return */ public String getAppletsAccessToken() { String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + wxAppletsAppid + "&secret=" + wxAppletsAppSecret; HttpRequest get = HttpUtil.createGet(url); HttpResponse response = get.execute(); if(response.getStatus() != 200){ return ""; } JSONObject jsonObject = JSON.parseObject(response.body()); return jsonObject.getString("access_token"); } /** * 网站应用登录 * @param code * @return */ public Map<String, String> webAccessToken(String code) throws Exception{ String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + webAppId + "&secret=" + webAppSecret + "&code=" + code + "&grant_type=authorization_code"; HttpRequest get = HttpUtil.createGet(url); HttpResponse response = get.execute(); if(response.getStatus() != 200){ return null; } JSONObject jsonObject = JSON.parseObject(response.body()); int errcode = jsonObject.getIntValue("errcode"); Map<String, String> map = new HashMap<>(); if(errcode == 0){//成功 map.put("access_token", jsonObject.getString("access_token")); map.put("openid", jsonObject.getString("openid")); map.put("refresh_token", jsonObject.getString("refresh_token")); map.put("unionid", jsonObject.getString("unionid")); return map; } if(errcode == -1){//系统繁忙,此时请开发者稍候再试 map.put("msg", jsonObject.getString("errmsg")); return map; } if(errcode == 40029){//code 无效 map.put("msg", jsonObject.getString("errmsg")); return map; } if(errcode == 45011){//频率限制,每个用户每分钟100次 map.put("msg", jsonObject.getString("errmsg")); return map; } return map; } /** * 获取微信个人信息 * @param access_token * @param openid * @return */ public Map<String, Object> getUserInfo(String access_token, String openid) throws Exception{ String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid; HttpRequest get = HttpUtil.createGet(url); HttpResponse response = get.execute(); if(response.getStatus() != 200){ return null; } JSONObject jsonObject = JSON.parseObject(response.body()); int errcode = jsonObject.getIntValue("errcode"); Map<String, Object> map = new HashMap<>(); if(errcode == 0){//成功 map.put("nickname", jsonObject.getString("nickname")); map.put("openid", jsonObject.getString("openid")); map.put("sex", jsonObject.getString("sex")); map.put("headimgurl", jsonObject.getString("headimgurl")); return map; } if(errcode == -1){//系统繁忙,此时请开发者稍候再试 map.put("msg", jsonObject.getString("errmsg")); return map; } if(errcode == 40029){//code 无效 map.put("msg", jsonObject.getString("errmsg")); return map; } if(errcode == 45011){//频率限制,每个用户每分钟100次 map.put("msg", jsonObject.getString("errmsg")); return map; } return map; } /** * 获取小程序二维码 * @param page 跳转页 例如 pages/index/index * @param scene 参数 a=1&b=2 */ public InputStream getwxacodeunlimit(String page, String scene, EnvVersion env_version){ try { String token = getWxAppletsAccessToken(); if(StringUtils.isEmpty(token)){ System.err.println("获取接口调用凭证失败"); } String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token; Map<String, Object> param = new HashMap<>(); param.put("scene", scene); param.put("page", page); param.put("env_version", env_version.getVersion()); HttpRequest post = HttpUtil.createPost(url); post.header(Header.CONTENT_TYPE, "application/json;charset=UTF-8"); post.body(JSON.toJSONString(param)); HttpResponse execute = post.execute(); byte[] bytes = execute.bodyBytes(); String body1 = execute.body(); System.err.println(body1); System.err.println(Base64.encodeBase64String(bytes)); return new ByteArrayInputStream(bytes); }catch (Exception e){ e.printStackTrace(); } return null; } /** * 获取微信小程序二维码 * @param page * @param scene * @param filePath * @return */ public String getwxacodeunlimit(String page, String scene, EnvVersion env_version, String filePath){ InputStream getwxacodeunlimit = getwxacodeunlimit(page, scene, env_version); // File file = FileUtil.writeFromStream(getwxacodeunlimit, new File(filePath)); // return file.getPath(); return remoteFileService.obsUpload("png", getwxacodeunlimit).getData(); } } ruoyi-modules/ruoyi-auction/src/main/java/com/ruoyi/auction/util/weChat/WxPKCS7Encoder.java
New file @@ -0,0 +1,63 @@ package com.ruoyi.auction.util.weChat; import java.nio.charset.Charset; import java.util.Arrays; /** * 微信小程序加解密 * @author pzb * @Date 2021/12/3 15:43 */ public class WxPKCS7Encoder { private static final Charset CHARSET = Charset.forName("utf-8"); private static final int BLOCK_SIZE = 32; /** * 获得对明文进行补位填充的字节. * * @param count * 需要进行填充补位操作的明文字节个数 * @return 补齐用的字节数组 */ public static byte[] encode(int count) { // 计算需要填充的位数 int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); if (amountToPad == 0) { amountToPad = BLOCK_SIZE; } // 获得补位所用的字符 char padChr = chr(amountToPad); String tmp = new String(); for (int index = 0; index < amountToPad; index++) { tmp += padChr; } return tmp.getBytes(CHARSET); } /** * 删除解密后明文的补位字符 * * @param decrypted * 解密后的明文 * @return 删除补位字符后的明文 */ public static byte[] decode(byte[] decrypted) { int pad = decrypted[decrypted.length - 1]; if (pad < 1 || pad > 32) { pad = 0; } return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); } /** * 将数字转化成ASCII码对应的字符,用于对明文进行补码 * * @param a * 需要转化的数字 * @return 转化得到的字符 */ public static char chr(int a) { byte target = (byte) (a & 0xFF); return (char) target; } } ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/management/MgtGoodsSkuController.java
@@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.page.PageDTO; import com.ruoyi.goods.controller.management.dto.GoodsInfoTitleQuery; @@ -19,20 +20,16 @@ import com.ruoyi.goods.service.IGoodsInfoTitleService; import com.ruoyi.goods.service.IGoodsSeriesService; import com.ruoyi.goods.service.IGoodsSkuService; import com.ruoyi.system.api.domain.AuctionGoods; import com.ruoyi.system.api.domain.dto.ListStatusDTO; import com.ruoyi.system.api.feignClient.AuctionClient; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.*; /** * <p> @@ -55,7 +52,7 @@ private final IGoodsCategoryService goodsCategoryService; private final IGoodsInfoTitleService goodsInfoTitleService; private final IGoodsFlavorTypeService goodsFlavorTypeService; private final AuctionClient auctionClient; /** * 获取商品分类列表的接口 该接口不需要接收任何参数,调用后返回商品分类的列表信息。 * @@ -169,4 +166,18 @@ public R<GoodsSkuVO> getGoodsDetail(@PathVariable("id") Long id) { return R.ok(goodsSkuService.getGoodsDetail(id)); } /** * 删除商品 */ @ApiOperation("删除商品") @DeleteMapping("/delete/{id}") public R<Void> delete(@PathVariable("id") Long id) { R<AuctionGoods> auctionR = auctionClient.getAuctionBySkuId(id, SecurityConstants.INNER); if (auctionR.getData() != null){ return R.fail("该商品正在拍卖中,无法删除"); } goodsSkuService.removeById(id); return R.ok(); } } ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/management/dto/GoodsSkuDTO.java
@@ -53,6 +53,15 @@ @NotNull(message = "商品价格不能为空") private BigDecimal price; @ApiModelProperty(value = "普通会员价格") @NotNull(message = "普通会员价格不能为空") private BigDecimal vipPrice; @ApiModelProperty(value = "超级会员价格") @NotNull(message = "超级会员价格不能为空") private BigDecimal superVipPrice; @ApiModelProperty(value = "库存") @NotNull(message = "库存不能为空") private Integer stock; ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/management/vo/GoodsSkuVO.java
@@ -5,11 +5,13 @@ import com.ruoyi.system.api.domain.vo.GoodsInfoTitleValueVO; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; import lombok.Data; /** * @author mitao * @date 2024/5/20 @@ -45,6 +47,12 @@ @ApiModelProperty(value = "商品价格") private BigDecimal price; @ApiModelProperty(value = "普通会员价格") private BigDecimal vipPrice; @ApiModelProperty(value = "超级会员价格") private BigDecimal superVipPrice; @ApiModelProperty(value = "库存") private Integer stock; ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/GoodsSkuServiceImpl.java
@@ -8,16 +8,16 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.enums.AuctionOrderTypeEnum; import com.ruoyi.common.core.enums.ListingStatusEnum; import com.ruoyi.common.core.enums.OrderFromEnum; import com.ruoyi.common.core.enums.StartStatusEnum; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.enums.*; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.page.BeanUtils; import com.ruoyi.common.core.utils.page.Checker; import com.ruoyi.common.core.utils.page.CollUtils; import com.ruoyi.common.core.utils.page.PageDTO; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.goods.controller.management.dto.GoodsInfoTitleValueDTO; import com.ruoyi.goods.controller.management.dto.GoodsSkuDTO; import com.ruoyi.goods.controller.management.dto.GoodsSkuQuery; @@ -33,17 +33,7 @@ import com.ruoyi.goods.service.IGoodsInfoTitleValueService; import com.ruoyi.goods.service.IGoodsSkuService; import com.ruoyi.goods.service.IMemberGoodsCollectionService; import com.ruoyi.system.api.domain.AuctionGoods; import com.ruoyi.system.api.domain.AuctionSalesroom; import com.ruoyi.system.api.domain.AuctionSalesroomGoods; import com.ruoyi.system.api.domain.GoodsBrand; import com.ruoyi.system.api.domain.GoodsCategory; import com.ruoyi.system.api.domain.GoodsFlavorType; import com.ruoyi.system.api.domain.GoodsGroupPurchase; import com.ruoyi.system.api.domain.GoodsSeckill; import com.ruoyi.system.api.domain.GoodsSeries; import com.ruoyi.system.api.domain.GoodsSku; import com.ruoyi.system.api.domain.Order; import com.ruoyi.system.api.domain.*; import com.ruoyi.system.api.domain.dto.GoodsStockUpdDTO; import com.ruoyi.system.api.domain.dto.HomeGoodsSkuDTO; import com.ruoyi.system.api.domain.dto.ListStatusDTO; @@ -53,7 +43,10 @@ import com.ruoyi.system.api.domain.vo.getHomeGoodsSkuXxiVO; import com.ruoyi.system.api.feignClient.AuctionClient; import com.ruoyi.system.api.feignClient.GoodsSkuClient; import com.ruoyi.system.api.feignClient.MemberClient; import com.ruoyi.system.api.feignClient.OrderClient; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -69,6 +62,7 @@ import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -105,8 +99,13 @@ @Resource private IMemberGoodsCollectionService iMemberGoodsCollectionService; @Resource private MemberClient memberClient; private static final ObjectMapper objectMapper = new ObjectMapper(); @Autowired private TokenService tokenService; /** * 保存商品SKU信息。 @@ -341,6 +340,11 @@ @Override public PageDTO<HomeGoodsSkuListVO> getHomeGoodsSkuVOList(HomeGoodsSkuDTO homeGoodsSkuDTO) { Long userId = SecurityUtils.getUserId(); R<Member> memberR = memberClient.getMemberByUserId(userId, SecurityConstants.INNER); Member member = memberR.getData(); Integer vipClassify = member.getVipClassify(); Page<GoodsSku> page = new Page<>(); page.setSize(homeGoodsSkuDTO.getPageSize()); page.setCurrent(homeGoodsSkuDTO.getPageCurr()); @@ -439,10 +443,13 @@ wrapper3.last(",IF(isnull(sort_num),1,0), sort_num DESC,create_time DESC" ); } Page<GoodsSku> page1 = this.page(page, wrapper3); PageDTO<HomeGoodsSkuListVO> articleCommentsVOPageDTO = PageDTO.of(page1, HomeGoodsSkuListVO.class); return articleCommentsVOPageDTO; for (GoodsSku record : page1.getRecords()) { // 获取会员价格 BigDecimal vipPrice = getVipPrice(record.getId()); record.setPrice(vipPrice); } return PageDTO.of(page1, HomeGoodsSkuListVO.class); } @@ -468,7 +475,6 @@ if (data3!=null) { homeGoodsSkuInfoVO.setFlavorType(data3.getFlavorTypeName()); } homeGoodsSkuInfoVO.setPrice(byId.getPrice()); homeGoodsSkuInfoVO.setSoldQuantity(byId.getSoldQuantity()); homeGoodsSkuInfoVO.setUnit(byId.getUnit()); homeGoodsSkuInfoVO.setSpec(byId.getSpec()); @@ -513,7 +519,9 @@ "=============================没有查询到团购信息============================="); homeGoodsSkuInfoVO.setIsGoodsGroupPurchase(1); } // 获取会员价格 BigDecimal vipPrice = getVipPrice(byId.getId()); homeGoodsSkuInfoVO.setPrice(vipPrice); LambdaQueryWrapper<MemberGoodsCollection> wrapper3= Wrappers.lambdaQuery(); wrapper3.eq(MemberGoodsCollection::getDelFlag,0); @@ -547,7 +555,7 @@ wrapper4.ge(GoodsBrowseRecord::getCreateTime, newTime7) .le(GoodsBrowseRecord::getCreateTime,now ); List<GoodsBrowseRecord> list2 = iGoodsBrowseRecordService.list(wrapper4); if (list2.size()==0){ if (list2.isEmpty()){ GoodsBrowseRecord auctionBrowseRecord=new GoodsBrowseRecord(); auctionBrowseRecord.setMemberId(homeGoodsSkuDTO.getMemberId()); auctionBrowseRecord.setGoodsSkuId(homeGoodsSkuDTO.getGoodsSkuId()); @@ -558,6 +566,26 @@ return homeGoodsSkuInfoVO; } private BigDecimal getVipPrice(Long goodsSkuId){ if (SecurityUtils.isLogin()) { Long userId = SecurityUtils.getUserId(); GoodsSku byId = getById(goodsSkuId); Member member = memberClient.getMemberByUserId(userId, SecurityConstants.INNER).getData(); Integer vipClassify = member.getVipClassify(); if (MemberVipClassifyEnum.NORMAL.getCode().equals(vipClassify)) { return byId.getPrice(); }else if (MemberVipClassifyEnum.VIP.getCode().equals(vipClassify)){ return byId.getVipPrice(); }else if (MemberVipClassifyEnum.SUPER_VIP.getCode().equals(vipClassify)){ return byId.getSuperVipPrice(); } }else { return getById(goodsSkuId).getPrice(); } throw new ServiceException("会员等级错误"); } @Override public List<getHomeGoodsSkuXxiVO> getHomeGoodsSkuXxi(HomeGoodsSkuDTO homeGoodsSkuDTO) { List<getHomeGoodsSkuXxiVO> homeGoodsSkuXxiVOS=new ArrayList<>(); ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java
@@ -573,6 +573,7 @@ @Override public MemberTiOrderVO updMemberOrder(MemberOrderDTO memberOrderDTO) { Order order = baseMapper.selectById(memberOrderDTO.getId()); if(memberOrderDTO.getOrderRemark()!=null){ order.setOrderRemark(memberOrderDTO.getOrderRemark());