“mitao”
2025-12-20 8832646742aff7d8ad37471f41350cd8950caf67
小程序订单我的订单
7个文件已添加
10个文件已修改
637 ■■■■■ 已修改文件
pom.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/UserIndexController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/resources/application-prod.yml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/resources/application-test.yml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/AppletOrderMapper.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/AppletOrderListQuery.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/AppletOrderService.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AppletOrderServiceImpl.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ICBCNotifyServiceImpl.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCommissionTransactionFlowServiceImpl.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/AppletOrderDetailVO.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/AppletOrderListVO.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/AppletOrderMapper.xml 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -10,7 +10,7 @@
    <name>ruoyi</name>
    <url>http://www.ruoyi.vip</url>
    <description>若依管理系统</description>
    <description>嘉视达</description>
    
    <properties>
        <ruoyi.version>3.8.6</ruoyi.version>
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java
@@ -1,14 +1,19 @@
package com.ruoyi.web.controller.api;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.dto.BigGiftPlaceOrderDTO;
import com.ruoyi.system.dto.FinalPaymentDTO;
import com.ruoyi.system.dto.PhysicalGoodsPlaceOrderDTO;
import com.ruoyi.system.model.TAppUser;
import com.ruoyi.system.query.AppletOrderListQuery;
import com.ruoyi.system.service.AppletOrderService;
import com.ruoyi.system.service.TAppUserService;
import com.ruoyi.system.service.TBigGiftPackageOrderService;
import com.ruoyi.system.service.TPhysicalGoodsOrderService;
import com.ruoyi.system.vo.AppletOrderDetailVO;
import com.ruoyi.system.vo.AppletOrderListVO;
import com.ruoyi.system.vo.PlaceOrderVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -16,10 +21,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.validation.annotation.Validated;
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.validation.Valid;
@@ -41,6 +43,21 @@
    private final TAppUserService appUserService;
    private final TBigGiftPackageOrderService bigGiftPackageOrderService;
    private final TPhysicalGoodsOrderService physicalGoodsOrderService;
    private final AppletOrderService appletOrderService;
    /**
     * 订单列表分页查询
     *
     * @param query 查询条件
     * @return 订单列表
     */
    @ApiOperation(value = "订单列表分页查询", response = AppletOrderListVO.class)
    @PostMapping("/list")
    public R<Page<AppletOrderListVO>> getOrderList(@RequestBody AppletOrderListQuery query) {
        Integer userId = tokenService.getLoginUserApplet().getUserId();
        Page<AppletOrderListVO> page = appletOrderService.getOrderList(query, userId);
        return R.ok(page);
    }
    /**
     * 大礼包商品下单
@@ -110,4 +127,66 @@
        PlaceOrderVO result = bigGiftPackageOrderService.payFinalPayment(dto.getOrderId(), userId, appUser.getOpenid());
        return R.ok(result);
    }
    /**
     * 实物商品订单详情
     *
     * @param id 订单ID
     * @return 订单详情
     */
    @ApiOperation(value = "实物商品订单详情", response = AppletOrderDetailVO.class)
    @GetMapping("/physical/detail/{id}")
    public R<AppletOrderDetailVO> getPhysicalOrderDetail(@PathVariable Integer id) {
        Integer userId = tokenService.getLoginUserApplet().getUserId();
        AppletOrderDetailVO detail = appletOrderService.getPhysicalOrderDetail(id, userId);
        if (detail == null) {
            return R.fail("订单不存在或无权查看");
        }
        return R.ok(detail);
    }
    /**
     * 大礼包订单详情
     *
     * @param id 订单ID
     * @return 订单详情
     */
    @ApiOperation(value = "大礼包订单详情", response = AppletOrderDetailVO.class)
    @GetMapping("/big-gift/detail/{id}")
    public R<AppletOrderDetailVO> getBigGiftOrderDetail(@PathVariable Integer id) {
        Integer userId = tokenService.getLoginUserApplet().getUserId();
        AppletOrderDetailVO detail = appletOrderService.getBigGiftOrderDetail(id, userId);
        if (detail == null) {
            return R.fail("订单不存在或无权查看");
        }
        return R.ok(detail);
    }
    /**
     * 实物商品确认收货
     *
     * @param id 订单ID
     * @return 操作结果
     */
    @ApiOperation(value = "实物商品确认收货")
    @PostMapping("/physical/confirm/{id}")
    public R<Void> confirmPhysicalOrder(@PathVariable Integer id) {
        Integer userId = tokenService.getLoginUserApplet().getUserId();
        boolean success = appletOrderService.confirmPhysicalOrder(id, userId);
        return success ? R.ok() : R.fail("确认收货失败,订单不存在或状态不正确");
    }
    /**
     * 大礼包确认收货
     *
     * @param id 订单ID
     * @return 操作结果
     */
    @ApiOperation(value = "大礼包确认收货")
    @PostMapping("/big-gift/confirm/{id}")
    public R<Void> confirmBigGiftOrder(@PathVariable Integer id) {
        Integer userId = tokenService.getLoginUserApplet().getUserId();
        boolean success = appletOrderService.confirmBigGiftOrder(id, userId);
        return success ? R.ok() : R.fail("确认收货失败,订单不存在或状态不正确");
    }
}
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/UserIndexController.java
@@ -8,6 +8,7 @@
import com.ruoyi.system.dto.UpdateUserDto;
import com.ruoyi.system.model.TAppUser;
import com.ruoyi.system.service.TAppUserService;
import com.ruoyi.system.service.TCommissionTransactionFlowService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
@@ -27,12 +28,15 @@
    private final TAppUserService tAppUserService;
    private final TokenService tokenService;
    private final TCommissionTransactionFlowService commissionTransactionFlowService;
    @ApiOperation(value = "个人中心--用户信息",response = TAppUser.class)
    @GetMapping(value = "/getUserInfo")
    public R<TAppUser> getUserInfo() {
        Integer userId = tokenService.getLoginUserApplet().getUserId();
        return R.ok(tAppUserService.getById(userId));
        TAppUser appUser = tAppUserService.getById(userId);
        return R.ok();
    }
    @ApiOperation(value = "个人中心--修改手机号")
ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -24,8 +24,10 @@
import com.ruoyi.system.utils.wx.body.resp.Code2SessionRespBody;
import com.ruoyi.system.utils.wx.body.resq.Code2SessionResqBody;
import com.ruoyi.system.utils.wx.model.WeixinProperties;
import com.ruoyi.system.utils.wx.pojo.AppletUserDecodeData;
import com.ruoyi.system.utils.wx.pojo.AppletUserEncrypteData;
import com.ruoyi.system.utils.wx.tools.WxAppletTools;
import com.ruoyi.system.utils.wx.tools.WxUtils;
import com.ruoyi.web.controller.tool.MsgUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -149,20 +151,20 @@
        String openid = body.getOpenid();
        String sessionKey = body.getSessionKey();
        // 用户信息解密 数据验签
//        if (StringUtils.isNotBlank(data.getSignature())) {
//            WxUtils.verifySignature(data.getRawData(), sessionKey, data.getSignature());
//        }
//        if(StringUtils.isEmpty(data.getEncryptedData()) || StringUtils.isEmpty(data.getIv())){
//            return R.fail("已拒绝授权");
//        }
//        AppletUserDecodeData appletUserDecodeData = WxUtils.encryptedData(data.getEncryptedData(), sessionKey,  data.getIv());
//        appletUserDecodeData.setOpenId(openid);
       if (StringUtils.hasLength(data.getSignature())) {
           WxUtils.verifySignature(data.getRawData(), sessionKey, data.getSignature());
       }
       if(StringUtils.isEmpty(data.getEncryptedData()) || StringUtils.isEmpty(data.getIv())){
           return R.fail("已拒绝授权");
       }
       AppletUserDecodeData appletUserDecodeData = WxUtils.encryptedData(data.getEncryptedData(), sessionKey,  data.getIv());
       appletUserDecodeData.setOpenId(openid);
        // 先使用openId和当前手机号进行查询
        TAppUser sysAppUser = appUserService.getOne(Wrappers.lambdaQuery(TAppUser.class)
                .and(e->e.eq(TAppUser::getOpenid, openid)));
        if (sysAppUser==null){
            sysAppUser = new TAppUser();
//            sysAppUser.setPhoneNumber(appletUserDecodeData.getPhoneNumber());
           sysAppUser.setPhone(appletUserDecodeData.getPhoneNumber());
            sysAppUser.setOpenid(openid);
            // 手机号中间四位替换为*
//            sysAppUser.setNickName(appletUserDecodeData.getPhoneNumber().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
ruoyi-applet/src/main/resources/application-prod.yml
@@ -249,7 +249,7 @@
    order-refund-url: "https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/refundqry/V1"
    # 完整的回调通知地址,支付完成后通知商户的URL
    notify-url: ""
    notify-url: "/icbc-notify/"
    # 回调方法的路径
    notify-url-method: "/icbc-notify/"
@@ -258,13 +258,13 @@
  keys:
    # 我方私钥,用于签名请求
    my-private-key: ""
    my-private-key: "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDKTiDDXWHil2veWR9nCzAkSlQIt9qyILoeLfhV/dIZ0YoqHTnIefARnSIaDP0y1Pqc7orTcNifKBQBaV8AbXIjow+VZpsysoyN4rnjmW3xOx600CaxQLKnXnl4eWkH/mHlkSb+Khv/hsmrNTwMtpf6ZE+NlVQFAXYgJZ5+JlaM4tgfdavXYXk053MffuPE/M+GZEvpFkrCpP1PJovwRvYZCeyTuNC6OEKgpkphfF7uJBbUV5GkgiG3Lzvt8WqgNo9ANzidfDGfKfrSMm3lF8YF1wt1u7ieZ99oasiR8q5nhSqXt2slAMSYpUdfsM4//6Tj8qkjnDdl0DquMBqX3S3XAgMBAAECggEAAODS8pYqsR2gKcBwSvW4+UdbUwhdSi2rMStY6yKlcVhABcvHru+ck67/cWaCCOD0z46XirBwOEynvZPUBj/zYWU5UZg270LoKkuELBFD8WqkyPsoV9ekjuZxl4zLYG4BxcnaBftv0K2onXYnMxTt1vftgntV+ImXli8jn3+SG510gIqzdp4qoQgySMmu+ew2I8Ank3yacg+ThYuJuG2T/RWyCoQKzw4vIRqilLnnqiM83AJniI5cM56EgMRCFOxsXR4fED5BHMaFJNlxNhWGVp8PE4s2S3aRsozJfMeH+SX/4/6u8fcG0w2eMFeJieNK56cOYgoXFkj6buQZCCt9XQKBgQDTcr6qYZsSk2tuXkFZiQ0JKe6FglQp8byBDU+40ESVtVLs8+ztQFE6/0lHgvwwtif2CkN6tFCcbfWfNF4g9Sgf/8G2MiCywFO8igbn7eRFePs4Ow2xdKbRP1GhRtL9nv5HGFT7O/puCxhkPZ4OVUg+e7E4eS0o+IiU8DSL5sa8YwKBgQD07jggN5H9LDbluZ7u6zvA/xBAM06Py/CCcmBCSK7Ekso7Rb0zBdTd+qhuErQEydgjRDeYGTsv0kBAPLb3nud7z/6R1pm2ofrCOT7QoJsNPcRAdyiMoRpxe+VhRbVIsSfsDQpO7uYiSpC3+kcMBPaS/3YMP9QsO7sUFpZlgkcA/QKBgAYrOtTNtDB+jIvTxCRQk0jJKGRMwRfYLZ+2O7Uwnk+f0qOHGkpxre0CtaiYcbMaHWBYPE/AIvntW1Uhuf1MKbeFRqmCHOIaKlc9z6XEkvxT40BouKWMubExH7iM0GsF0HVSiGgr/8pmGHgUNCBG7Kyl/y2em2qulY2C1IWgXfvxAoGBAMA3U4S1F7UARfTzP29w3GwRv8cifL0M56r35+Mc90r9iAgMKvcn1G6AkD4SH4TCgwTqPFb5NiHJdvLyswSRiEj6amY5bFiPtiNGma1Q3V3+401UNlZm+EGnYdR8yFBL93Cgqz5W7fRrYDeCCs+79WZXZWUnknNETQTu1QjEvMRhAoGBAKxtYlqPMBQ9KiBLipaj/jAx7xlPmhphgcGHPf7sBgDplq9vTO9dq+XK4Fhj1fV9OEmNDC0muk9l9WXBkhww7ji6k7zhY4H7DAPhe1MD/rqkcq7SKA4zeHNbt2TScAzzYpKmN8lSA7G4MgcG4IQcYpwxNzsR7Pf4W0cM0Qf4LgyZ"
    # 对方(即工行)网关公钥,用于验证返回的签名
    api-gw-public-key: ""
    api-gw-public-key: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMpjaWjngB4E3ATh+G1DVAmQnIpiPEFAEDqRfNGAVvvH35yDetqewKi0l7OEceTMN1C6NPym3zStvSoQayjYV+eIcZERkx31KhtFu9clZKgRTyPjdKMIth/wBtPKjL/5+PYalLdomM4ONthrPgnkN4x4R0+D4+EBpXo8gNiAFsNwIDAQAB"
  # APP的编号,应用在API开放平台注册时生成
  app-id: ""
  app-id: "11000000000000018953"
  # 商户编号,用于标识商户账户
  mer-id: ""
@@ -273,15 +273,14 @@
  mer-prtcl-no: ""
  # 设备号,设备的唯一标识符
  decive-info: ""
  decive-info: "013467007045764"
  # 微信APP的编号,便于与微信支付接口对接
  wx-app-id: ""
  wx-app-id: "wx87744e4e4094a829"
  # 微信公众号的APP编号,供公众号支付使用
  wx-gzh-app-id: ""
  # 订单超时时间,单位为分钟
  expire-time: "60"
ruoyi-applet/src/main/resources/application-test.yml
@@ -248,13 +248,13 @@
  keys:
    # 我方私钥,用于签名请求
    my-private-key: ""
    my-private-key: "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDKTiDDXWHil2veWR9nCzAkSlQIt9qyILoeLfhV/dIZ0YoqHTnIefARnSIaDP0y1Pqc7orTcNifKBQBaV8AbXIjow+VZpsysoyN4rnjmW3xOx600CaxQLKnXnl4eWkH/mHlkSb+Khv/hsmrNTwMtpf6ZE+NlVQFAXYgJZ5+JlaM4tgfdavXYXk053MffuPE/M+GZEvpFkrCpP1PJovwRvYZCeyTuNC6OEKgpkphfF7uJBbUV5GkgiG3Lzvt8WqgNo9ANzidfDGfKfrSMm3lF8YF1wt1u7ieZ99oasiR8q5nhSqXt2slAMSYpUdfsM4//6Tj8qkjnDdl0DquMBqX3S3XAgMBAAECggEAAODS8pYqsR2gKcBwSvW4+UdbUwhdSi2rMStY6yKlcVhABcvHru+ck67/cWaCCOD0z46XirBwOEynvZPUBj/zYWU5UZg270LoKkuELBFD8WqkyPsoV9ekjuZxl4zLYG4BxcnaBftv0K2onXYnMxTt1vftgntV+ImXli8jn3+SG510gIqzdp4qoQgySMmu+ew2I8Ank3yacg+ThYuJuG2T/RWyCoQKzw4vIRqilLnnqiM83AJniI5cM56EgMRCFOxsXR4fED5BHMaFJNlxNhWGVp8PE4s2S3aRsozJfMeH+SX/4/6u8fcG0w2eMFeJieNK56cOYgoXFkj6buQZCCt9XQKBgQDTcr6qYZsSk2tuXkFZiQ0JKe6FglQp8byBDU+40ESVtVLs8+ztQFE6/0lHgvwwtif2CkN6tFCcbfWfNF4g9Sgf/8G2MiCywFO8igbn7eRFePs4Ow2xdKbRP1GhRtL9nv5HGFT7O/puCxhkPZ4OVUg+e7E4eS0o+IiU8DSL5sa8YwKBgQD07jggN5H9LDbluZ7u6zvA/xBAM06Py/CCcmBCSK7Ekso7Rb0zBdTd+qhuErQEydgjRDeYGTsv0kBAPLb3nud7z/6R1pm2ofrCOT7QoJsNPcRAdyiMoRpxe+VhRbVIsSfsDQpO7uYiSpC3+kcMBPaS/3YMP9QsO7sUFpZlgkcA/QKBgAYrOtTNtDB+jIvTxCRQk0jJKGRMwRfYLZ+2O7Uwnk+f0qOHGkpxre0CtaiYcbMaHWBYPE/AIvntW1Uhuf1MKbeFRqmCHOIaKlc9z6XEkvxT40BouKWMubExH7iM0GsF0HVSiGgr/8pmGHgUNCBG7Kyl/y2em2qulY2C1IWgXfvxAoGBAMA3U4S1F7UARfTzP29w3GwRv8cifL0M56r35+Mc90r9iAgMKvcn1G6AkD4SH4TCgwTqPFb5NiHJdvLyswSRiEj6amY5bFiPtiNGma1Q3V3+401UNlZm+EGnYdR8yFBL93Cgqz5W7fRrYDeCCs+79WZXZWUnknNETQTu1QjEvMRhAoGBAKxtYlqPMBQ9KiBLipaj/jAx7xlPmhphgcGHPf7sBgDplq9vTO9dq+XK4Fhj1fV9OEmNDC0muk9l9WXBkhww7ji6k7zhY4H7DAPhe1MD/rqkcq7SKA4zeHNbt2TScAzzYpKmN8lSA7G4MgcG4IQcYpwxNzsR7Pf4W0cM0Qf4LgyZ"
    # 对方(即工行)网关公钥,用于验证返回的签名
    api-gw-public-key: ""
    api-gw-public-key: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMpjaWjngB4E3ATh+G1DVAmQnIpiPEFAEDqRfNGAVvvH35yDetqewKi0l7OEceTMN1C6NPym3zStvSoQayjYV+eIcZERkx31KhtFu9clZKgRTyPjdKMIth/wBtPKjL/5+PYalLdomM4ONthrPgnkN4x4R0+D4+EBpXo8gNiAFsNwIDAQAB"
  # APP的编号,应用在API开放平台注册时生成
  app-id: ""
  app-id: "11000000000000018953"
  # 商户编号,用于标识商户账户
  mer-id: ""
@@ -263,10 +263,10 @@
  mer-prtcl-no: ""
  # 设备号,设备的唯一标识符
  decive-info: ""
  decive-info: "013467007045764"
  # 微信APP的编号,便于与微信支付接口对接
  wx-app-id: ""
  wx-app-id: "wx87744e4e4094a829"
  # 微信公众号的APP编号,供公众号支付使用
  wx-gzh-app-id: ""
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
@@ -1,11 +1,17 @@
package com.ruoyi.framework.config;
import java.util.TimeZone;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
/**
 * 程序注解配置
@@ -19,12 +25,20 @@
@MapperScan("com.ruoyi.**.mapper")
public class ApplicationConfig
{
    private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final String DATE_PATTERN = "yyyy-MM-dd";
    /**
     * 时区配置
     * 时区配置 + LocalDateTime全局格式化
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
    {
        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
        return builder -> builder
                .timeZone(TimeZone.getDefault())
                .serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)))
                .deserializers(new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)))
                .serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_PATTERN)))
                .deserializers(new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_PATTERN)));
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
@@ -5,6 +5,7 @@
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.entity.TAppUserResp;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.model.LoginUserApplet;
import com.ruoyi.common.core.redis.RedisCache;
@@ -23,6 +24,7 @@
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.TAppUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
@@ -199,13 +201,19 @@
            throw new UserNotExistsException();
        }
        // 用户验证
        TAppUser user = tAppUserService.getOne(Wrappers.<TAppUser>lambdaQuery().eq(TAppUser::getPhone,username));
        TAppUser user = tAppUserService.getOne(Wrappers.<TAppUser>lambdaQuery().eq(TAppUser::getPhone,username).ne(TAppUser::getStatus,3));
        if (StringUtils.isNull(user)){
            log.info("登录用户:{} 不存在.", username);
            throw new ServiceException(MessageUtils.message("user.not.exists"));
        } else if (user.getStatus().equals(3)) {
            log.info("登录用户:{} 已被删除.", username);
            throw new ServiceException(MessageUtils.message("user.password.delete"));
            log.info("登录用户:{} 不存在.创建一个新用户", username);
            user = new TAppUser();
            user.setPhone(username);
            user.setStatus(1);
            tAppUserService.save(user);
            // throw new ServiceException(MessageUtils.message("user.not.exists"));
        } else {
            if (user.getStatus().equals(2)) {
                log.info("登录用户:{} 已被停用.", username);
                throw new ServiceException(MessageUtils.message("user.blocked"));
            }
        }
        if ("test".equals(env) || "dev".equals(env)) {
            if (!code.equals("111111")) {
@@ -224,6 +232,9 @@
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUserApplet loginUser = new LoginUserApplet(user.getId(), null, null, null);
        recordAppLoginInfo(loginUser.getUserId().toString());
        TAppUserResp sysUserResp = new TAppUserResp();
        BeanUtils.copyProperties(user, sysUserResp);
        loginUser.setUser(sysUserResp);
        // 生成token
        return loginUser;
    }
ruoyi-system/src/main/java/com/ruoyi/system/mapper/AppletOrderMapper.java
New file
@@ -0,0 +1,29 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.system.query.AppletOrderListQuery;
import com.ruoyi.system.vo.AppletOrderListVO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * 小程序端订单Mapper
 *
 * @author mitao
 * @since 2025-12-20
 */
public interface AppletOrderMapper {
    /**
     * 分页查询订单列表
     *
     * @param page      分页参数
     * @param query     查询条件
     * @param appUserId 用户ID
     * @return 订单列表
     */
    List<AppletOrderListVO> selectOrderList(Page<AppletOrderListVO> page,
                                            @Param("query") AppletOrderListQuery query,
                                            @Param("appUserId") Integer appUserId);
}
ruoyi-system/src/main/java/com/ruoyi/system/query/AppletOrderListQuery.java
New file
@@ -0,0 +1,22 @@
package com.ruoyi.system.query;
import com.ruoyi.common.core.domain.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 小程序端订单列表查询条件
 *
 * @author mitao
 * @since 2025-12-20
 */
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "AppletOrderListQuery", description = "小程序端订单列表查询条件")
public class AppletOrderListQuery extends BasePage {
    @ApiModelProperty(value = "订单状态筛选(null=全部,1=待支付,2=已付定金,3=已支付)")
    private Integer status;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/AppletOrderService.java
New file
@@ -0,0 +1,60 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.system.query.AppletOrderListQuery;
import com.ruoyi.system.vo.AppletOrderDetailVO;
import com.ruoyi.system.vo.AppletOrderListVO;
/**
 * 小程序端订单Service
 *
 * @author mitao
 * @since 2025-12-20
 */
public interface AppletOrderService {
    /**
     * 分页查询订单列表
     *
     * @param query     查询条件
     * @param appUserId 用户ID
     * @return 分页结果
     */
    Page<AppletOrderListVO> getOrderList(AppletOrderListQuery query, Integer appUserId);
    /**
     * 获取实物商品订单详情
     *
     * @param orderId   订单ID
     * @param appUserId 用户ID
     * @return 订单详情
     */
    AppletOrderDetailVO getPhysicalOrderDetail(Integer orderId, Integer appUserId);
    /**
     * 获取大礼包订单详情
     *
     * @param orderId   订单ID
     * @param appUserId 用户ID
     * @return 订单详情
     */
    AppletOrderDetailVO getBigGiftOrderDetail(Integer orderId, Integer appUserId);
    /**
     * 实物商品确认收货
     *
     * @param orderId   订单ID
     * @param appUserId 用户ID
     * @return 是否成功
     */
    boolean confirmPhysicalOrder(Integer orderId, Integer appUserId);
    /**
     * 大礼包确认收货
     *
     * @param orderId   订单ID
     * @param appUserId 用户ID
     * @return 是否成功
     */
    boolean confirmBigGiftOrder(Integer orderId, Integer appUserId);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AppletOrderServiceImpl.java
New file
@@ -0,0 +1,115 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.system.mapper.AppletOrderMapper;
import com.ruoyi.system.model.TBigGiftPackage;
import com.ruoyi.system.model.TBigGiftPackageOrder;
import com.ruoyi.system.model.TPhysicalGoods;
import com.ruoyi.system.model.TPhysicalGoodsOrder;
import com.ruoyi.system.query.AppletOrderListQuery;
import com.ruoyi.system.service.AppletOrderService;
import com.ruoyi.system.service.TBigGiftPackageOrderService;
import com.ruoyi.system.service.TPhysicalGoodsOrderService;
import com.ruoyi.system.vo.AppletOrderDetailVO;
import com.ruoyi.system.vo.AppletOrderListVO;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
/**
 * 小程序端订单Service实现
 *
 * @author mitao
 * @since 2025-12-20
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class AppletOrderServiceImpl implements AppletOrderService {
    private final AppletOrderMapper appletOrderMapper;
    private final TPhysicalGoodsOrderService physicalGoodsOrderService;
    private final TBigGiftPackageOrderService bigGiftPackageOrderService;
    @Override
    public Page<AppletOrderListVO> getOrderList(AppletOrderListQuery query, Integer appUserId) {
        Page<AppletOrderListVO> page = new Page<>(query.getPageNum(), query.getPageSize());
        List<AppletOrderListVO> list = appletOrderMapper.selectOrderList(page, query, appUserId);
        page.setRecords(list);
        return page;
    }
    @Override
    public AppletOrderDetailVO getPhysicalOrderDetail(Integer orderId, Integer appUserId) {
        TPhysicalGoodsOrder order = physicalGoodsOrderService.getById(orderId);
        if (order == null || !order.getAppUserId().equals(appUserId)) {
            return null;
        }
        AppletOrderDetailVO vo = BeanUtil.copyProperties(order, AppletOrderDetailVO.class);
        vo.setOrderType(2); // 实物商品
        // 解析商品JSON
        if (order.getPhysicalGoods() != null) {
            TPhysicalGoods goods = JSON.parseObject(order.getPhysicalGoods(), TPhysicalGoods.class);
            if (goods != null) {
                vo.setGoodsName(goods.getName());
                vo.setGoodsIntro(goods.getIntroduction());
                vo.setGoodsCover(goods.getCoverImage());
                vo.setGoodsPrice(goods.getTotalPrice());
            }
        }
        return vo;
    }
    @Override
    public AppletOrderDetailVO getBigGiftOrderDetail(Integer orderId, Integer appUserId) {
        TBigGiftPackageOrder order = bigGiftPackageOrderService.getById(orderId);
        if (order == null || !order.getAppUserId().equals(appUserId)) {
            return null;
        }
        AppletOrderDetailVO vo = BeanUtil.copyProperties(order, AppletOrderDetailVO.class);
        vo.setOrderType(1); // 大礼包
        // 解析商品JSON
        if (order.getBigGiftPackage() != null) {
            TBigGiftPackage goods = JSON.parseObject(order.getBigGiftPackage(), TBigGiftPackage.class);
            if (goods != null) {
                vo.setGoodsName(goods.getName());
                vo.setGoodsIntro(goods.getIntroduction());
                vo.setGoodsCover(goods.getCoverImage());
                vo.setGoodsPrice(goods.getTotalPrice());
            }
        }
        return vo;
    }
    @Override
    public boolean confirmPhysicalOrder(Integer orderId, Integer appUserId) {
        TPhysicalGoodsOrder order = physicalGoodsOrderService.getById(orderId);
        // 校验订单存在、归属、状态(2=完成支付才能确认收货)
        if (order == null || !order.getAppUserId().equals(appUserId) || order.getStatus() != 2) {
            return false;
        }
        order.setStatus(3); // 确认收货
        order.setDeliveryTime(LocalDateTime.now());
        return physicalGoodsOrderService.updateById(order);
    }
    @Override
    public boolean confirmBigGiftOrder(Integer orderId, Integer appUserId) {
        TBigGiftPackageOrder order = bigGiftPackageOrderService.getById(orderId);
        // 校验订单存在、归属、状态(3=完成支付才能确认收货)
        if (order == null || !order.getAppUserId().equals(appUserId) || order.getStatus() != 3) {
            return false;
        }
        order.setStatus(4); // 确认收货
        order.setDeliveryTime(LocalDateTime.now());
        return bigGiftPackageOrderService.updateById(order);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ICBCNotifyServiceImpl.java
@@ -11,15 +11,13 @@
import com.ruoyi.system.config.ICBCConfig;
import com.ruoyi.system.model.TBigGiftPackageOrder;
import com.ruoyi.system.model.TPhysicalGoodsOrder;
import com.ruoyi.system.service.ICBCNotifyService;
import com.ruoyi.system.service.TBigGiftPackageOrderService;
import com.ruoyi.system.service.TCommissionTransactionFlowService;
import com.ruoyi.system.service.TPhysicalGoodsOrderService;
import com.ruoyi.system.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@@ -36,19 +34,16 @@
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class ICBCNotifyServiceImpl implements ICBCNotifyService {
    @Resource
    private ICBCConfig icbcConfig;
    private final ICBCConfig icbcConfig;
    @Resource
    private TBigGiftPackageOrderService bigGiftPackageOrderService;
    private final TBigGiftPackageOrderService bigGiftPackageOrderService;
    @Resource
    private TPhysicalGoodsOrderService physicalGoodsOrderService;
    private final TPhysicalGoodsOrderService physicalGoodsOrderService;
    @Resource
    private TCommissionTransactionFlowService commissionTransactionFlowService;
    private final TCommissionTransactionFlowService commissionTransactionFlowService;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -217,14 +212,6 @@
                    physicalGoodsOrderService.updateById(order);
                    log.info("订单{}状态更新为完成支付", orderCode);
                    // 实物商品支付完成后,立即计算分佣
                    commissionTransactionFlowService.calculateAndSaveCommission(
                            order.getId(),
                            2, // 订单类型:2=实物商品
                            order.getOrderPrice(),
                            order.getAppUserId()
                    );
                    log.info("订单{}分佣计算完成", orderCode);
                } else {
                    log.error("订单{}【工商银行】实物商品支付失败,错误信息:{}", orderCode, bizContent.getString("return_msg"));
                }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCommissionTransactionFlowServiceImpl.java
@@ -1,18 +1,19 @@
package com.ruoyi.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.mapper.TCommissionTransactionFlowMapper;
import com.ruoyi.system.model.TAppUser;
import com.ruoyi.system.model.TCommissionTransactionFlow;
import com.ruoyi.system.mapper.TCommissionTransactionFlowMapper;
import com.ruoyi.system.model.THtmlConfig;
import com.ruoyi.system.service.TAppUserService;
import com.ruoyi.system.service.TCommissionTransactionFlowService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.service.THtmlConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
@@ -27,13 +28,12 @@
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class TCommissionTransactionFlowServiceImpl extends ServiceImpl<TCommissionTransactionFlowMapper, TCommissionTransactionFlow> implements TCommissionTransactionFlowService {
    @Resource
    private TAppUserService appUserService;
    private final TAppUserService appUserService;
    @Resource
    private THtmlConfigService htmlConfigService;
    private final THtmlConfigService htmlConfigService;
    @Override
    public void calculateAndSaveCommission(Integer orderId, Integer orderType, BigDecimal orderPrice, Integer appUserId) {
@@ -202,6 +202,15 @@
        save(flow);
        log.info("保存佣金流水成功,用户ID:{},佣金金额:{}", userId, commissionAmount);
        // 更新用户累计积分(佣金金额1:1转积分)
        TAppUser user = appUserService.getById(userId);
        if (user != null) {
            int currentIntegral = user.getAccumulativeIntegral() != null ? user.getAccumulativeIntegral() : 0;
            user.setAccumulativeIntegral(currentIntegral + commissionAmount.intValue());
            appUserService.updateById(user);
            log.info("更新用户累计积分成功,用户ID:{},新增积分:{},累计积分:{}", userId, commissionAmount.intValue(), user.getAccumulativeIntegral());
        }
    }
    /**
ruoyi-system/src/main/java/com/ruoyi/system/vo/AppletOrderDetailVO.java
New file
@@ -0,0 +1,81 @@
package com.ruoyi.system.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * 小程序端订单详情VO
 *
 * @author mitao
 * @since 2025-12-20
 */
@Data
@ApiModel(value = "AppletOrderDetailVO", description = "小程序端订单详情VO")
public class AppletOrderDetailVO {
    // ========== 订单基础信息 ==========
    @ApiModelProperty(value = "订单ID")
    private Integer id;
    @ApiModelProperty(value = "订单编号")
    private String code;
    @ApiModelProperty(value = "订单类型(1=大礼包,2=实物商品)")
    private Integer orderType;
    @ApiModelProperty(value = "订单状态")
    private Integer status;
    @ApiModelProperty(value = "下单时间")
    private LocalDateTime createTime;
    // ========== 商品信息(从JSON解析) ==========
    @ApiModelProperty(value = "商品名称")
    private String goodsName;
    @ApiModelProperty(value = "商品简介")
    private String goodsIntro;
    @ApiModelProperty(value = "商品封面图")
    private String goodsCover;
    @ApiModelProperty(value = "商品总价")
    private BigDecimal goodsPrice;
    // ========== 金额信息 ==========
    @ApiModelProperty(value = "订单价格")
    private BigDecimal orderPrice;
    @ApiModelProperty(value = "支付金额")
    private BigDecimal paymentPrice;
    @ApiModelProperty(value = "订金(大礼包)")
    private BigDecimal deposit;
    @ApiModelProperty(value = "尾款(大礼包)")
    private BigDecimal finalPayment;
    @ApiModelProperty(value = "支付方式(1=订金+尾款,2=全款)(大礼包)")
    private Integer paymentType;
    // ========== 时间信息 ==========
    @ApiModelProperty(value = "付款时间(实物商品)")
    private LocalDateTime paymentTime;
    @ApiModelProperty(value = "订金付款时间(大礼包)")
    private LocalDateTime depositTime;
    @ApiModelProperty(value = "尾款付款时间(大礼包)")
    private LocalDateTime finalPaymentTime;
    @ApiModelProperty(value = "确认收货时间")
    private LocalDateTime deliveryTime;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/AppletOrderListVO.java
New file
@@ -0,0 +1,46 @@
package com.ruoyi.system.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * 小程序端订单列表VO
 *
 * @author mitao
 * @since 2025-12-20
 */
@Data
@ApiModel(value = "AppletOrderListVO", description = "小程序端订单列表VO")
public class AppletOrderListVO {
    @ApiModelProperty(value = "订单ID")
    private Integer id;
    @ApiModelProperty(value = "订单编号")
    private String code;
    @ApiModelProperty(value = "商品名称")
    private String goodsName;
    @ApiModelProperty(value = "商品简介")
    private String goodsIntro;
    @ApiModelProperty(value = "商品封面图")
    private String goodsCover;
    @ApiModelProperty(value = "商品总价")
    private BigDecimal goodsPrice;
    @ApiModelProperty(value = "下单时间")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "订单类型(1=大礼包,2=实物商品)")
    private Integer orderType;
    @ApiModelProperty(value = "订单状态(1=待支付,2=已付定金,3=已支付)")
    private Integer status;
}
ruoyi-system/src/main/resources/mapper/system/AppletOrderMapper.xml
New file
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.AppletOrderMapper">
    <select id="selectOrderList" resultType="com.ruoyi.system.vo.AppletOrderListVO">
        SELECT t.id, t.code, t.goodsName, t.goodsIntro, t.goodsCover, t.goodsPrice, t.createTime, t.orderType, t.status
        FROM (
            SELECT
                o.id,
                o.code,
                JSON_UNQUOTE(JSON_EXTRACT(o.big_gift_package, '$.name')) AS goodsName,
                JSON_UNQUOTE(JSON_EXTRACT(o.big_gift_package, '$.introduction')) AS goodsIntro,
                JSON_UNQUOTE(JSON_EXTRACT(o.big_gift_package, '$.coverImage')) AS goodsCover,
                JSON_UNQUOTE(JSON_EXTRACT(o.big_gift_package, '$.totalPrice')) AS goodsPrice,
                o.create_time AS createTime,
                1 AS orderType,
                o.status
            FROM t_big_gift_package_order o
            WHERE o.del_flag = 0 AND o.app_user_id = #{appUserId}
            UNION ALL
            SELECT
                o.id,
                o.code,
                JSON_UNQUOTE(JSON_EXTRACT(o.physical_goods, '$.name')) AS goodsName,
                JSON_UNQUOTE(JSON_EXTRACT(o.physical_goods, '$.introduction')) AS goodsIntro,
                JSON_UNQUOTE(JSON_EXTRACT(o.physical_goods, '$.coverImage')) AS goodsCover,
                JSON_UNQUOTE(JSON_EXTRACT(o.physical_goods, '$.totalPrice')) AS goodsPrice,
                o.create_time AS createTime,
                2 AS orderType,
                CASE WHEN o.status = 2 THEN 3 ELSE o.status END AS status
            FROM t_physical_goods_order o
            WHERE o.del_flag = 0 AND o.app_user_id = #{appUserId}
        ) t
        <where>
            <if test="query.status != null">
                <choose>
                    <when test="query.status == 3">
                        AND (t.status = 3 OR (t.orderType = 1 AND t.status = 4))
                    </when>
                    <otherwise>
                        AND t.status = #{query.status}
                    </otherwise>
                </choose>
            </if>
        </where>
        ORDER BY t.createTime DESC
    </select>
</mapper>