From b82e78ceb8f52b05203f05eb4b14151b1ab408a2 Mon Sep 17 00:00:00 2001
From: “mitao” <“2763622819@qq.com”>
Date: 星期三, 24 十二月 2025 18:52:23 +0800
Subject: [PATCH] feat:下单功能联调及短信对接

---
 ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/WxQrCodeUtil.java                               |    1 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentBigGiftPackageOrderController.java |  123 ++++++++
 ruoyi-system/src/main/java/com/ruoyi/system/enums/BigGiftPackageOrderStatusEnum.java                 |   26 +
 ruoyi-system/src/main/java/com/ruoyi/system/query/BigGiftPackageOrderQuery.java                      |    3 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java                                 |    8 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java                         |   37 ++
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java                   |  115 +++++++-
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java                   |    7 
 ruoyi-applet/src/main/resources/application-prod.yml                                                 |   10 
 ruoyi-system/src/main/java/com/ruoyi/system/model/TBigGiftPackageOrder.java                          |    9 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TPhysicalGoodsOrderServiceImpl.java         |   72 ++++
 ruoyi-system/src/main/java/com/ruoyi/system/service/TAppUserService.java                             |    7 
 ruoyi-system/src/main/java/com/ruoyi/system/service/TPhysicalGoodsOrderService.java                  |    9 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/MsgUtils.java                               |  108 +++---
 ruoyi-system/src/main/java/com/ruoyi/system/query/ProfitPageListQuery.java                           |    1 
 ruoyi-system/src/main/resources/mapper/system/TBigGiftPackageOrderMapper.xml                         |    5 
 ruoyi-applet/src/main/resources/application-test.yml                                                 |   13 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/IndexController.java                         |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserServiceImpl.java                    |   21 +
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentCompanyController.java             |   65 ++++
 ruoyi-system/src/main/java/com/ruoyi/system/enums/PhysicalGoodsOrderStatusEnum.java                  |   25 +
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserVisitServiceImpl.java               |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/query/PromotionPageListQuery.java                        |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ICBCNotifyServiceImpl.java                  |   27 +
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBigGiftPackageOrderServiceImpl.java        |   83 +++++
 ruoyi-system/src/main/java/com/ruoyi/system/utils/ICBCPayUtil.java                                   |    7 
 ruoyi-system/src/main/java/com/ruoyi/system/service/TBigGiftPackageOrderService.java                 |   10 
 27 files changed, 682 insertions(+), 117 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentBigGiftPackageOrderController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentBigGiftPackageOrderController.java
new file mode 100644
index 0000000..c7b0002
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentBigGiftPackageOrderController.java
@@ -0,0 +1,123 @@
+package com.ruoyi.web.controller.api.agent;
+
+
+import cn.afterturn.easypoi.excel.ExcelExportUtil;
+import cn.afterturn.easypoi.excel.entity.ExportParams;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.basic.PageInfo;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.WebUtils;
+import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.dto.TransferOrderDto;
+import com.ruoyi.system.export.TBigGiftPackageOrderExport;
+import com.ruoyi.system.model.*;
+import com.ruoyi.system.query.AppUserListQuery;
+import com.ruoyi.system.query.BigGiftPackageOrderQuery;
+import com.ruoyi.system.query.OrderTransferQuery;
+import com.ruoyi.system.service.*;
+import com.ruoyi.system.vo.TOrderTransferDetailVo;
+import com.ruoyi.system.vo.TOrderTransferVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * 大礼包订单 前端控制器
+ * </p>
+ *
+ * @author xiaochen
+ * @since 2025-12-08
+ */
+@RestController
+@RequestMapping("/agent/t-big-gift-package-order")
+@Api(tags = "(嘉视达)供应商大礼包订单")
+@RequiredArgsConstructor(onConstructor_ = @Lazy)
+public class AgentBigGiftPackageOrderController {
+
+    private final TBigGiftPackageOrderService tBigGiftPackageOrderService;
+    private final TAppUserService tAppUserService;
+    private final TCompanyService tCompanyService;
+    private final TBigGiftPackageService tBigGiftPackageService;
+
+
+    @ApiOperation(value = "大礼包订单列表")
+    @PostMapping(value = "/pageList")
+    public R<Page<TBigGiftPackageOrder>> pageList(@RequestBody BigGiftPackageOrderQuery query) {
+        if (!SecurityUtils.isAgentUser()) {
+            throw new ServiceException("请使用经销商/股东帐号访问");
+        }
+        Page<TBigGiftPackageOrder> tBigGiftPackageOrderPage = new Page<>(query.getPageNum(), query.getPageSize());
+        query.setCompanyId(SecurityUtils.getLoginUser().getUser().getCompanyId());
+        List<TBigGiftPackageOrder> list = tBigGiftPackageOrderService.pageList(tBigGiftPackageOrderPage, query);
+        tBigGiftPackageOrderPage.setRecords(list);
+        return R.ok(tBigGiftPackageOrderPage);
+    }
+
+    @ApiOperation(value = "大礼包订单详情")
+    @PostMapping(value = "/detail/{id}")
+    public R<TBigGiftPackageOrder> detail(@PathVariable Integer id) {
+        if (!SecurityUtils.isAgentUser()) {
+            throw new ServiceException("请使用经销商/股东帐号访问");
+        }
+        TBigGiftPackageOrder tBigGiftPackageOrder = tBigGiftPackageOrderService.getById(id);
+        Integer appUserId = tBigGiftPackageOrder.getAppUserId();
+        TAppUser appUser = tAppUserService.getById(appUserId);
+        Integer referrerUserId = appUser.getReferrerUserId();
+        if(referrerUserId!=null){
+            // 上级用户
+            TAppUser lastUser = tAppUserService.getById(referrerUserId);
+            if (lastUser != null && lastUser.getUserType()==2){
+                tBigGiftPackageOrder.setSaleName(lastUser.getName());
+                if(lastUser.getReferrerUserId()!=null){
+                    // 上上级
+                    TAppUser lastLastUser = tAppUserService.getById(lastUser.getReferrerUserId());
+                    if (lastLastUser != null && lastLastUser.getUserType()==1){
+                        tBigGiftPackageOrder.setPartnerName(lastLastUser.getName());
+                    }
+                }
+            }
+            if (lastUser != null && lastUser.getUserType()==1){
+                tBigGiftPackageOrder.setPartnerName(lastUser.getName());
+            }
+        }
+        Integer bigGiftPackageId = tBigGiftPackageOrder.getBigGiftPackageId();
+        TBigGiftPackage tBigGiftPackage = tBigGiftPackageService.getById(bigGiftPackageId);
+        tBigGiftPackageOrder.setBigGiftPackageName(tBigGiftPackage.getName());
+        tBigGiftPackageOrder.setBigGiftPackageCover(tBigGiftPackage.getCoverImage());
+        tBigGiftPackageOrder.setBigGiftPackagePrice(tBigGiftPackage.getTotalPrice());
+        tBigGiftPackageOrder.setBigGiftPackageIntro(tBigGiftPackage.getIntroduction());
+        // 销量
+        long count = tBigGiftPackageOrderService.count(new LambdaQueryWrapper<TBigGiftPackageOrder>().eq(TBigGiftPackageOrder::getBigGiftPackageId, bigGiftPackageId).ne(TBigGiftPackageOrder::getStatus, 5));
+        tBigGiftPackageOrder.setBigGiftPackageSales((int)count);
+
+
+        Integer companyId = appUser.getCompanyId();
+        if(companyId!=null){
+            TCompany tCompany = tCompanyService.getById(companyId);
+            tBigGiftPackageOrder.setCompanyName(tCompany.getName());
+        }
+        return R.ok(tBigGiftPackageOrder);
+    }
+
+
+}
+
+
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentCompanyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentCompanyController.java
index 452394c..f04b665 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentCompanyController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/agent/AgentCompanyController.java
@@ -1,19 +1,31 @@
 package com.ruoyi.web.controller.api.agent;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.BasePage;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.system.model.TCompany;
+import com.ruoyi.system.query.CompanyUserQuery;
+import com.ruoyi.system.query.ProfitPageListQuery;
+import com.ruoyi.system.query.PromotionPageListQuery;
+import com.ruoyi.system.service.ISysUserService;
+import com.ruoyi.system.service.TAppUserService;
+import com.ruoyi.system.service.TBigGiftPackageOrderService;
 import com.ruoyi.system.service.TCompanyService;
+import com.ruoyi.system.vo.ProfitPageListVo;
+import com.ruoyi.system.vo.PromotionPageListVo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
 import org.springframework.context.annotation.Lazy;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
 
 /**
  * 经销商管理后台 - 公司信息 前端控制器
@@ -28,15 +40,17 @@
 public class AgentCompanyController extends BaseController {
 
     private final TCompanyService companyService;
-
+    private final ISysUserService userService;
+    private final TAppUserService appUserService;
+    private final TBigGiftPackageOrderService bigGiftPackageOrderService;
     @ApiOperation(value = "获取当前用户所属公司详情")
     @GetMapping("/detail")
     public R<TCompany> getDetail() {
         // 获取当前登录用户
         LoginUser loginUser = SecurityUtils.getLoginUser();
         SysUser user = loginUser.getUser();
-        if (!user.getRoleType().equals(2)) {
-            return R.fail("请使用经销商账号访问");
+        if (!SecurityUtils.isAgentUser()) {
+            throw new ServiceException("请使用经销商/股东帐号访问");
         }
         // 获取用户所属公司ID
         Integer companyId = user.getCompanyId();
@@ -53,4 +67,43 @@
         return R.ok(company);
     }
 
+    @ApiOperation(value = "公司详情-管理人员列表")
+    @PostMapping(value = "/getCompanyUserList")
+    public R<Page<SysUser>> getCompanyUserList(@RequestBody BasePage pageReq) {
+        if (!SecurityUtils.isAgentUser()) {
+            throw new ServiceException("请使用经销商/股东帐号访问");
+        }
+        // 获取当前登录用户
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Integer companyId = loginUser.getUser().getCompanyId();
+        Page<SysUser> page = new Page<>(pageReq.getPageNum(), pageReq.getPageSize());
+        List<SysUser> list =  userService.getCompanyUserList(page,companyId);
+        page.setRecords(list);
+        return R.ok(page);
+    }
+
+    @ApiOperation(value = "推广记录")
+    @PostMapping("/promotionPageList")
+    public R<Page<PromotionPageListVo>> promotionPageList(@RequestBody @Valid PromotionPageListQuery query) {
+        if (!SecurityUtils.isAgentUser()) {
+            throw new ServiceException("请使用经销商/股东帐号访问");
+        }
+        Page<PromotionPageListVo> page = new Page<>(query.getPageNum(), query.getPageSize());
+        query.setCompanyId(SecurityUtils.getLoginUser().getUser().getCompanyId());
+        List<PromotionPageListVo> list = appUserService.promotionPageList(page,query);
+        page.setRecords(list);
+        return R.ok(page);
+    }
+
+    @ApiOperation(value = "收益明细")
+    @PostMapping("/profitPageList")
+    public R<Page<ProfitPageListVo>> profitPageList(@RequestBody @Valid ProfitPageListQuery query) {
+        if (!SecurityUtils.isAgentUser()) {
+            throw new ServiceException("请使用经销商/股东帐号访问");
+        }
+        Page<ProfitPageListVo> page = new Page<>(query.getPageNum(), query.getPageSize());
+        List<ProfitPageListVo> list = bigGiftPackageOrderService.profitPageList(page,query);
+        page.setRecords(list);
+        return R.ok(page);
+    }
 }
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/IndexController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/IndexController.java
index fe3e731..c64f2b3 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/IndexController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/IndexController.java
@@ -46,7 +46,7 @@
 
     @ApiOperation("根据推广码获取上级用户信息")
     @GetMapping("/getSuperiorInfo")
-    public R<SupervisorUserVO> getSuperiorInfo(@ApiParam(name = "superiorType", value = "上级类型 1:股东;2:营销员")
+    public R<SupervisorUserVO> getSuperiorInfo(@ApiParam(name = "superiorType", value = "上级类型 1:股东;2:营销员/合伙人")
                                                @NotNull(message = "上级类型不能为空") @RequestParam Integer superiorType,
                                                @ApiParam(name = "spreadCode", value = "推广码")
                                                @NotNull(message = "推广码不能为空") @RequestParam String spreadCode) {
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java
index 721ebfc..0960f95 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java
@@ -189,4 +189,41 @@
         boolean success = appletOrderService.confirmBigGiftOrder(id, userId);
         return success ? R.ok() : R.fail("确认收货失败,订单不存在或状态不正确");
     }
+
+    /**
+     * 实物商品立即支付(从Redis获取缓存的支付参数)
+     *
+     * @param id 订单ID
+     * @return 支付参数
+     */
+    @ApiOperation(value = "实物商品待支付订单立即支付", response = PlaceOrderVO.class)
+    @GetMapping("/physical/pay-now/{id}")
+    public R<PlaceOrderVO> physicalPayNow(@PathVariable Integer id) {
+        Integer userId = tokenService.getLoginUserApplet().getUserId();
+        PlaceOrderVO result = physicalGoodsOrderService.payNow(id, userId);
+        return R.ok(result);
+    }
+
+    /**
+     * 大礼包立即支付(生成新的支付参数)
+     *
+     * @param id 订单ID
+     * @return 支付参数
+     */
+    @ApiOperation(value = "大礼包待支付订单立即支付", response = PlaceOrderVO.class)
+    @GetMapping("/big-gift/pay-now/{id}")
+    public R<PlaceOrderVO> bigGiftPayNow(@PathVariable Integer id) {
+        // 获取当前登录用户
+        Integer userId = tokenService.getLoginUserApplet().getUserId();
+        TAppUser appUser = appUserService.getById(userId);
+        if (appUser == null) {
+            return R.fail("用户不存在");
+        }
+        if (appUser.getOpenid() == null || appUser.getOpenid().isEmpty()) {
+            return R.fail("用户未绑定微信");
+        }
+
+        PlaceOrderVO result = bigGiftPackageOrderService.payNow(id, userId, appUser.getOpenid());
+        return R.ok(result);
+    }
 }
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
index 59ac191..07efa17 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -14,6 +14,7 @@
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.redis.service.RedisService;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.ip.IpUtils;
 import com.ruoyi.framework.web.service.SysLoginService;
 import com.ruoyi.framework.web.service.SysPermissionService;
 import com.ruoyi.framework.web.service.TokenService;
@@ -43,10 +44,11 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
 
 /**
  * 登录验证
- * 
+ *
  * @author ruoyi
  */
 @Slf4j
@@ -80,6 +82,28 @@
     private TAppUserService appUserService;
 
     /**
+     * 手机号正则表达式(11位数字,以1开头)
+     */
+    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
+
+    /**
+     * Redis Key 前缀
+     */
+    private static final String SMS_LIMIT_PHONE_KEY = "sms_limit:phone:";
+    private static final String SMS_LIMIT_PHONE_DAILY_KEY = "sms_limit:phone_daily:";
+    private static final String SMS_LIMIT_IP_KEY = "sms_limit:ip:";
+    private static final String SMS_LIMIT_IP_HOURLY_KEY = "sms_limit:ip_hourly:";
+
+    /**
+     * 限制参数
+     */
+    private static final int PHONE_LIMIT_SECONDS = 60;           // 手机号60秒限制
+    private static final int PHONE_DAILY_LIMIT = 10;             // 手机号每日最多10次
+    private static final int PHONE_DAILY_EXPIRE_HOURS = 24;      // 手机号每日限制过期时间
+    private static final int IP_LIMIT_PER_MINUTE = 5;            // IP每分钟最多5次
+    private static final int IP_LIMIT_PER_HOUR = 20;             // IP每小时最多20次
+
+    /**
      * 获取验证码
      *
      * @param phone 手机号
@@ -89,20 +113,83 @@
     @GetMapping("/getCode")
     public AjaxResult getCode(@RequestParam String phone)
     {
-        // 发送验证码并存储到redis
-        if (StringUtils.hasLength(phone)) {
-
-            String code = String.valueOf((int) (Math.random() * 1000000));
-            redisCache.setCacheObject(phone, code,5*60, TimeUnit.SECONDS);
-            try {
-                //TODO 待对接
-//                smsUtil.sendSms(phone, "2369926", new String[]{code});
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-            return AjaxResult.success("发送短信验证码成功!5分钟内有效");
+        // 1. 校验手机号格式
+        if (!StringUtils.hasLength(phone) || !PHONE_PATTERN.matcher(phone).matches()) {
+            return AjaxResult.error(500, "手机号格式不正确");
         }
-        return AjaxResult.error(500, "发送短信验证码失败,请确认手机号码!");
+
+        // 2. 获取客户端IP
+        String clientIp = IpUtils.getIpAddr();
+
+        // 3. 检查手机号60秒限制
+        String phoneKey = SMS_LIMIT_PHONE_KEY + phone;
+        if (redisCache.hasKey(phoneKey)) {
+            Long ttl = redisCache.getExpire(phoneKey);
+            return AjaxResult.error(500, "请求过于频繁,请" + ttl + "秒后再试");
+        }
+
+        // 4. 检查手机号24小时限制
+        String phoneDailyKey = SMS_LIMIT_PHONE_DAILY_KEY + phone;
+        Integer phoneDailyCount = redisCache.getCacheObject(phoneDailyKey);
+        if (phoneDailyCount != null && phoneDailyCount >= PHONE_DAILY_LIMIT) {
+            return AjaxResult.error(500, "该手机号今日获取验证码次数已达上限");
+        }
+
+        // 5. 检查IP每分钟限制
+        String ipKey = SMS_LIMIT_IP_KEY + clientIp;
+        Integer ipCount = redisCache.getCacheObject(ipKey);
+        if (ipCount != null && ipCount >= IP_LIMIT_PER_MINUTE) {
+            return AjaxResult.error(500, "请求过于频繁,请稍后再试");
+        }
+
+        // 6. 检查IP每小时限制
+        String ipHourlyKey = SMS_LIMIT_IP_HOURLY_KEY + clientIp;
+        Integer ipHourlyCount = redisCache.getCacheObject(ipHourlyKey);
+        if (ipHourlyCount != null && ipHourlyCount >= IP_LIMIT_PER_HOUR) {
+            return AjaxResult.error(500, "请求次数过多,请1小时后再试");
+        }
+
+        // 7. 生成并发送验证码
+        String code = String.valueOf((int) (Math.random() * 900000) + 100000);
+        redisCache.setCacheObject(phone, code, 5 * 60, TimeUnit.SECONDS);
+        try {
+            msgUtils.sendMsg(phone, code);
+        } catch (Exception e) {
+            log.error("发送短信验证码失败,手机号:{},错误:{}", phone, e.getMessage());
+            return AjaxResult.error(500, "发送短信验证码失败,请稍后重试");
+        }
+
+        // 8. 更新限制计数器
+        // 手机号60秒限制
+        redisCache.setCacheObject(phoneKey, 1, PHONE_LIMIT_SECONDS, TimeUnit.SECONDS);
+
+        // 手机号每日限制
+        if (phoneDailyCount == null) {
+            redisCache.setCacheObject(phoneDailyKey, 1, PHONE_DAILY_EXPIRE_HOURS, TimeUnit.HOURS);
+        } else {
+            redisCache.setCacheObject(phoneDailyKey, phoneDailyCount + 1, PHONE_DAILY_EXPIRE_HOURS, TimeUnit.HOURS);
+        }
+
+        // IP每分钟限制
+        if (ipCount == null) {
+            redisCache.setCacheObject(ipKey, 1, 1, TimeUnit.MINUTES);
+        } else {
+            // 保持原有过期时间
+            Long ipTtl = redisCache.getExpire(ipKey);
+            redisCache.setCacheObject(ipKey, ipCount + 1, ipTtl.intValue() > 0 ? ipTtl.intValue() : 60, TimeUnit.SECONDS);
+        }
+
+        // IP每小时限制
+        if (ipHourlyCount == null) {
+            redisCache.setCacheObject(ipHourlyKey, 1, 1, TimeUnit.HOURS);
+        } else {
+            // 保持原有过期时间
+            Long ipHourlyTtl = redisCache.getExpire(ipHourlyKey);
+            redisCache.setCacheObject(ipHourlyKey, ipHourlyCount + 1, ipHourlyTtl.intValue() > 0 ? ipHourlyTtl.intValue() : 3600, TimeUnit.SECONDS);
+        }
+
+        log.info("验证码发送成功,手机号:{},IP:{}", phone, clientIp);
+        return AjaxResult.success("发送短信验证码成功!5分钟内有效");
     }
 
     /**
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/MsgUtils.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/MsgUtils.java
index c38d11f..5f7e372 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/MsgUtils.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/MsgUtils.java
@@ -13,58 +13,58 @@
 @Slf4j
 public class MsgUtils {
 
-//    @Value("${code.config.accessKeyId}")
-//    private  String accessKeyId;
-//    @Value("${code.config.accessKeySecret}")
-//    private  String accessKeySecret;
-//    @Value("${code.config.signName}")
-//    private  String signName;
-//    @Value("${code.config.templateCode}")
-//    private  String templateCode;
-//    @Value("${code.config.signNameTest}")
-//    private  String signNameTest;
-//    @Value("${code.config.templateCodeTest}")
-//    private  String templateCodeTest;
-//
-//    /**
-//     * 使用AK&SK初始化账号Client
-//     * @param accessKeyId
-//     * @param accessKeySecret
-//     * @return Client
-//     * @throws Exception
-//     */
-//    public static com.aliyun.dysmsapi20170525.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
-//        Config config = new Config()
-//                // 您的 AccessKey ID
-//                .setAccessKeyId(accessKeyId)
-//                // 您的 AccessKey Secret
-//                .setAccessKeySecret(accessKeySecret);
-//        // 访问的域名
-//        config.endpoint = "dysmsapi.aliyuncs.com";
-//        return new com.aliyun.dysmsapi20170525.Client(config);
-//    }
-//
-//    public void sendMsg(String phone,String code) throws Exception {
-//        com.aliyun.dysmsapi20170525.Client client = MsgUtils.createClient(accessKeyId,accessKeySecret);
-//        SendSmsRequest sendSmsRequest = new SendSmsRequest()
-//                .setSignName(signName)
-//                .setTemplateCode(templateCode)
-//                .setPhoneNumbers(phone)
-//                .setTemplateParam("{\"code\":\""+code+"\"}");
-//        RuntimeOptions runtime = new RuntimeOptions();
-//        try {
-//            // 复制代码运行请自行打印 API 的返回值
-//            SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);
-//            log.info("短信发送成功:{},{}",sendSmsResponse.getBody().getMessage(),sendSmsResponse.getStatusCode());
-//        } catch (TeaException error) {
-//            // 如有需要,请打印 error
-//            com.aliyun.teautil.Common.assertAsString(error.message);
-//            log.info("短信发送失败:{}",error.message);
-//        } catch (Exception _error) {
-//            TeaException error = new TeaException(_error.getMessage(), _error);
-//            // 如有需要,请打印 error
-//            com.aliyun.teautil.Common.assertAsString(error.message);
-//            log.info("短信发送失败:{}",error.message);
-//        }
-//    }
+   @Value("${code.config.accessKeyId}")
+   private  String accessKeyId;
+   @Value("${code.config.accessKeySecret}")
+   private  String accessKeySecret;
+   @Value("${code.config.signName}")
+   private  String signName;
+   @Value("${code.config.templateCode}")
+   private  String templateCode;
+   @Value("${code.config.signNameTest}")
+   private  String signNameTest;
+   @Value("${code.config.templateCodeTest}")
+   private  String templateCodeTest;
+
+   /**
+    * 使用AK&SK初始化账号Client
+    * @param accessKeyId
+    * @param accessKeySecret
+    * @return Client
+    * @throws Exception
+    */
+   public static com.aliyun.dysmsapi20170525.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
+       Config config = new Config()
+               // 您的 AccessKey ID
+               .setAccessKeyId(accessKeyId)
+               // 您的 AccessKey Secret
+               .setAccessKeySecret(accessKeySecret);
+       // 访问的域名
+       config.endpoint = "dysmsapi.aliyuncs.com";
+       return new com.aliyun.dysmsapi20170525.Client(config);
+   }
+
+   public void sendMsg(String phone,String code) throws Exception {
+       com.aliyun.dysmsapi20170525.Client client = MsgUtils.createClient(accessKeyId,accessKeySecret);
+       SendSmsRequest sendSmsRequest = new SendSmsRequest()
+               .setSignName(signName)
+               .setTemplateCode(templateCode)
+               .setPhoneNumbers(phone)
+               .setTemplateParam("{\"code\":\""+code+"\"}");
+       RuntimeOptions runtime = new RuntimeOptions();
+       try {
+           // 复制代码运行请自行打印 API 的返回值
+           SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);
+           log.info("短信发送成功:{},{}",sendSmsResponse.getBody().getMessage(),sendSmsResponse.getStatusCode());
+       } catch (TeaException error) {
+           // 如有需要,请打印 error
+           com.aliyun.teautil.Common.assertAsString(error.message);
+           log.info("短信发送失败:{}",error.message);
+       } catch (Exception _error) {
+           TeaException error = new TeaException(_error.getMessage(), _error);
+           // 如有需要,请打印 error
+           com.aliyun.teautil.Common.assertAsString(error.message);
+           log.info("短信发送失败:{}",error.message);
+       }
+   }
 }
diff --git a/ruoyi-applet/src/main/resources/application-prod.yml b/ruoyi-applet/src/main/resources/application-prod.yml
index 6c7c771..cfa7075 100644
--- a/ruoyi-applet/src/main/resources/application-prod.yml
+++ b/ruoyi-applet/src/main/resources/application-prod.yml
@@ -209,12 +209,12 @@
 #OSS及短信配置
 code:
   config:
-    templateCodeTest: "SMS_154950909"
+    templateCodeTest: "SMS_327789258"
     signNameTest: "阿里云短信测试"
-    accessKeyId: LTAI5tAdba8HtT1C6UqtSxBt
-    accessKeySecret: 0SRb6XGkciQDPWn2rYqbJtq2qRMDY8
-    signName: "四川金达通信工程"
-    templateCode: "SMS_293985284"
+    accessKeyId: LTAI5tPoUG8ayR3efxqqaZg8
+    accessKeySecret: mF3bYUh9J6yP5ecLoCYB2vAWbrYrW4
+    signName: "嘉视达"
+    templateCode: "SMS_327789258"
 cos:
   client:
     accessKey: AKIDCF5EF2c0DE1e5JK8r4EGJF4mNsMgp26x
diff --git a/ruoyi-applet/src/main/resources/application-test.yml b/ruoyi-applet/src/main/resources/application-test.yml
index 300097d..f97d2be 100644
--- a/ruoyi-applet/src/main/resources/application-test.yml
+++ b/ruoyi-applet/src/main/resources/application-test.yml
@@ -196,6 +196,15 @@
   conf:
     appId: wx87744e4e4094a829
     secretId: c322159083d844e63dff458b5e54c4c9
+#OSS及短信配置
+code:
+  config:
+    templateCodeTest: "SMS_327789258"
+    signNameTest: "阿里云短信测试"
+    accessKeyId: LTAI5tPoUG8ayR3efxqqaZg8
+    accessKeySecret: mF3bYUh9J6yP5ecLoCYB2vAWbrYrW4
+    signName: "嘉视达"
+    templateCode: "SMS_327789258"
 payment:
   wx:
     # 微信appid
@@ -240,10 +249,10 @@
     order-refund-url: "https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/refundqry/V1"
 
     # 完整的回调通知地址,支付完成后通知商户的URL
-    notify-url: "http://221.182.45.100:7890/icbc-notify/"
+    notify-url: "https://vwpmxwbhv59i.guyubao.com/icbc-notify"
 
     # 回调方法的路径
-    notify-url-method: "/icbc-notify/"
+    notify-url-method: "/icbc-notify"
 
 
 
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
index 72e7a99..8f7a15e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
@@ -150,4 +150,12 @@
     {
         return userId != null && 1L == userId;
     }
+
+    /**
+     * 是否为供应商用户
+     * @return
+     */
+    public static boolean isAgentUser(){
+        return !getLoginUser().getUser().getRoleType().equals(1);
+    }
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
index 6464604..f1a6cae 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
@@ -220,11 +220,8 @@
                 throw new ServiceException(MessageUtils.message("user.blocked"));
             }
         }
-        if ("test".equals(env) || "dev".equals(env)) {
-            if (!code.equals("111111")) {
-                log.info("登录用户:{} 短信验证码错误{}", username,code);
-                throw new ServiceException("短信验证码错误");
-            }
+        if (("test".equals(env) || "dev".equals(env)) && code.equals("111111")) {
+           //直接放行
         } else {
             // 校验验证码
             Object cacheObject = redisCache.getCacheObject(user.getPhone());
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/enums/BigGiftPackageOrderStatusEnum.java b/ruoyi-system/src/main/java/com/ruoyi/system/enums/BigGiftPackageOrderStatusEnum.java
new file mode 100644
index 0000000..5ea7559
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/enums/BigGiftPackageOrderStatusEnum.java
@@ -0,0 +1,26 @@
+package com.ruoyi.system.enums;
+
+import lombok.Getter;
+import lombok.AllArgsConstructor;
+@Getter
+@AllArgsConstructor
+public enum BigGiftPackageOrderStatusEnum {
+	PENDING_PAYMENT(1, "待付款"),
+	DEPOSIT_PAID(2, "已付订金"),
+	PAID(3, "完成支付"),
+	CONFIRM_RECEIPT(4, "确认收货"),
+	REFUNDED(5, "已退款"),
+	CANCELED(6, "已取消");
+
+	private final Integer code;
+	private final String desc;
+
+	public static BigGiftPackageOrderStatusEnum getEnumByCode(Integer code) {
+		for (BigGiftPackageOrderStatusEnum e : BigGiftPackageOrderStatusEnum.values()) {
+			if (e.code.equals(code)) {
+				return e;
+			}
+		}
+		return null;
+	}
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/enums/PhysicalGoodsOrderStatusEnum.java b/ruoyi-system/src/main/java/com/ruoyi/system/enums/PhysicalGoodsOrderStatusEnum.java
new file mode 100644
index 0000000..7ce8948
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/enums/PhysicalGoodsOrderStatusEnum.java
@@ -0,0 +1,25 @@
+package com.ruoyi.system.enums;
+
+import lombok.Getter;
+import lombok.AllArgsConstructor;
+@Getter
+@AllArgsConstructor
+public enum PhysicalGoodsOrderStatusEnum {
+	PENDING_PAYMENT(1, "待付款"),
+	PAID(2, "完成支付"),
+	CONFIRM_RECEIPT(3, "确认收货"),
+	REFUNDED(4, "已退款"),
+	CANCELED(5, "已取消");
+
+	private final Integer code;
+	private final String desc;
+
+	public static PhysicalGoodsOrderStatusEnum getEnumByCode(Integer code) {
+		for (PhysicalGoodsOrderStatusEnum e : PhysicalGoodsOrderStatusEnum.values()) {
+			if (e.code.equals(code)) {
+				return e;
+			}
+		}
+		return null;
+	}
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/model/TBigGiftPackageOrder.java b/ruoyi-system/src/main/java/com/ruoyi/system/model/TBigGiftPackageOrder.java
index 1b48de3..242e29f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/model/TBigGiftPackageOrder.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/model/TBigGiftPackageOrder.java
@@ -78,7 +78,6 @@
     @ApiModelProperty(value = "支付金额")
     @TableField("payment_price")
     private BigDecimal paymentPrice;
-
     @ApiModelProperty(value = "订单状态(1=待付款,2=已付订金,3=完成支付,4=确认收货,5=已退款,6=已取消)")
     @TableField("status")
     private Integer status;
@@ -104,6 +103,10 @@
     @TableField("deposit_payment_serial_number")
     private String depositPaymentSerialNumber;
 
+    @ApiModelProperty(value = "订金付款第三方流水号")
+    @TableField("deposit_payment_third_serial_number")
+    private String depositPaymentThirdSerialNumber;
+
     @ApiModelProperty(value = "尾款付款时间")
     @TableField("final_payment_time")
     private LocalDateTime finalPaymentTime;
@@ -116,6 +119,10 @@
     @TableField("final_payment_serial_number")
     private String finalPaymentSerialNumber;
 
+    @ApiModelProperty(value = "尾款付款第三方流水号")
+    @TableField("final_payment_third_serial_number")
+    private String finalPaymentThirdSerialNumber;
+
     @ApiModelProperty(value = "支付订单号(用于工行支付,多订单合并支付时共用同一个支付订单号)")
     @TableField("pay_order_code")
     private String payOrderCode;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/query/BigGiftPackageOrderQuery.java b/ruoyi-system/src/main/java/com/ruoyi/system/query/BigGiftPackageOrderQuery.java
index f75e222..db33da2 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/query/BigGiftPackageOrderQuery.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/query/BigGiftPackageOrderQuery.java
@@ -23,5 +23,6 @@
     @ApiModelProperty(value = "1=待付款,2=已付订金,3=完成支付,4=确认收货,5=已退款")
     private Integer status;
 
-
+    @ApiModelProperty(value = "公司ID")
+    private Integer companyId;
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/query/ProfitPageListQuery.java b/ruoyi-system/src/main/java/com/ruoyi/system/query/ProfitPageListQuery.java
index 8cddbc3..983c3c4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/query/ProfitPageListQuery.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/query/ProfitPageListQuery.java
@@ -23,6 +23,5 @@
     private String createTime;
 
     @ApiModelProperty("公司id")
-    @NotNull(message = "公司id不能为空")
     private Integer companyId;
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/query/PromotionPageListQuery.java b/ruoyi-system/src/main/java/com/ruoyi/system/query/PromotionPageListQuery.java
index 81eb41c..5cf394c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/query/PromotionPageListQuery.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/query/PromotionPageListQuery.java
@@ -27,7 +27,6 @@
     private String phone;
 
     @ApiModelProperty(value = "公司id")
-    @NotNull(message = "公司id不能为空")
     private Integer companyId;
 
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/TAppUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/TAppUserService.java
index ad4ef34..75f65d1 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/TAppUserService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/TAppUserService.java
@@ -5,6 +5,7 @@
 import com.ruoyi.common.basic.PageInfo;
 import com.ruoyi.common.core.domain.model.LoginUserApplet;
 import com.ruoyi.system.model.TAppUser;
+import com.ruoyi.system.model.TCompany;
 import com.ruoyi.system.query.AppUserListQuery;
 import com.ruoyi.system.query.ProfitPageListQuery;
 import com.ruoyi.system.query.PromotionPageListQuery;
@@ -53,4 +54,10 @@
 
     List<UserPromotionPageListVo> userPromotionPageListExport(@Valid UserPromotionPageListQuery query);
 
+    /**
+     * 获取用户所属公司信息
+     * @param appUserId
+     * @return
+     */
+    TCompany getUserCompany(Integer appUserId);
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/TBigGiftPackageOrderService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/TBigGiftPackageOrderService.java
index 891b307..5f16f51 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/TBigGiftPackageOrderService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/TBigGiftPackageOrderService.java
@@ -62,4 +62,14 @@
     List<UserProfitPageListVo> profitUserPageListExport(@Valid UserProfitPageListQuery query);
 
     List<TBigGiftPackageOrder> pageOrderListExport(@Valid GoldChangeRecordQuery query);
+
+    /**
+     * 大礼包立即支付(生成新的支付参数)
+     *
+     * @param orderId   订单ID
+     * @param appUserId 用户ID
+     * @param openid    用户微信openid
+     * @return 支付参数
+     */
+    PlaceOrderVO payNow(Integer orderId, Integer appUserId, String openid);
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/TPhysicalGoodsOrderService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/TPhysicalGoodsOrderService.java
index 5b3e0f5..9c3d781 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/TPhysicalGoodsOrderService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/TPhysicalGoodsOrderService.java
@@ -34,4 +34,13 @@
      */
     PlaceOrderVO placeOrder(PhysicalGoodsPlaceOrderDTO dto, Integer appUserId, String openid);
 
+    /**
+     * 实物商品立即支付(从Redis获取缓存的支付参数)
+     *
+     * @param orderId   订单ID
+     * @param appUserId 用户ID
+     * @return 支付参数
+     */
+    PlaceOrderVO payNow(Integer orderId, Integer appUserId);
+
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ICBCNotifyServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ICBCNotifyServiceImpl.java
index 82f2ef2..e82aa95 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ICBCNotifyServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ICBCNotifyServiceImpl.java
@@ -9,6 +9,8 @@
 import com.icbc.api.utils.IcbcSignature;
 import com.icbc.api.utils.WebUtils;
 import com.ruoyi.system.config.ICBCConfig;
+import com.ruoyi.system.enums.BigGiftPackageOrderStatusEnum;
+import com.ruoyi.system.enums.PhysicalGoodsOrderStatusEnum;
 import com.ruoyi.system.model.TBigGiftPackageOrder;
 import com.ruoyi.system.model.TPhysicalGoodsOrder;
 import com.ruoyi.system.service.*;
@@ -62,7 +64,7 @@
             String payOrderCode = bizContent.getString("out_trade_no");
             String returnCode = bizContent.getString("return_code");
             msgId = bizContent.getString("msg_id");
-
+            String orderId = bizContent.getString("order_id");
             // 验签
             if (validateSignature(request, icbcConfig.getNotifyUrlMethod() + "/big-gift/pay-notify")) {
                 signResult = true;
@@ -83,12 +85,12 @@
 
                     // 处理每个订单
                     for (TBigGiftPackageOrder order : orders) {
-                        processBigGiftPayment(order);
+                        processBigGiftPayment(order, orderId);
                     }
                 } else {
                     log.error("支付订单号{}【工商银行】大礼包支付失败,错误信息:{}", payOrderCode, bizContent.getString("return_msg"));
                     //更新订单状态为已取消
-                    orders.forEach(item->item.setStatus(6));
+                    orders.forEach(item->item.setStatus(BigGiftPackageOrderStatusEnum.CANCELED.getCode()));
                     bigGiftPackageOrderService.updateBatchById(orders);
                 }
             } else {
@@ -142,9 +144,10 @@
                     }
 
                     // 更新订单状态为"完成支付"
-                    order.setStatus(3);
+                    order.setStatus(BigGiftPackageOrderStatusEnum.PAID.getCode());
                     order.setFinalPaymentTime(LocalDateTime.now());
-                    order.setFinalPaymentSerialNumber(finalPayOrderCode);
+                    order.setFinalPaymentThirdSerialNumber(orderId);
+                    order.setPaymentPrice(order.getPaymentPrice().add(order.getFinalPayment()));
                     bigGiftPackageOrderService.updateById(order);
                     log.info("订单{}状态更新为完成支付", order.getCode());
 
@@ -207,7 +210,7 @@
                     }
 
                     // 更新订单状态为"完成支付"
-                    order.setStatus(2);
+                    order.setStatus(PhysicalGoodsOrderStatusEnum.PAID.getCode());
                     order.setPaymentTime(LocalDateTime.now());
                     order.setPaymentSerialNumber(orderId);
                     physicalGoodsOrderService.updateById(order);
@@ -215,7 +218,7 @@
 
                 } else {
                     log.error("订单{}【工商银行】实物商品支付失败,错误信息:{}", orderCode, bizContent.getString("return_msg"));
-                    order.setStatus(5);
+                    order.setStatus(PhysicalGoodsOrderStatusEnum.CANCELED.getCode());
                     physicalGoodsOrderService.updateById(order);
                 }
             } else {
@@ -232,21 +235,21 @@
     /**
      * 处理大礼包支付(定金或全款)
      */
-    private void processBigGiftPayment(TBigGiftPackageOrder order) {
+    private void processBigGiftPayment(TBigGiftPackageOrder order, String orderId) {
         Integer paymentType = order.getPaymentType();
 
         if (paymentType == 1) {
             // 订金+尾款模式,更新状态为"已付订金"
-            order.setStatus(2);
+            order.setStatus(BigGiftPackageOrderStatusEnum.DEPOSIT_PAID.getCode());
             order.setDepositTime(LocalDateTime.now());
-            order.setDepositPaymentSerialNumber(order.getPayOrderCode());
+            order.setDepositPaymentThirdSerialNumber(orderId);
             bigGiftPackageOrderService.updateById(order);
             log.info("订单{}状态更新为已付订金,不计算分佣", order.getCode());
         } else if (paymentType == 2) {
             // 全款模式,更新状态为"完成支付"
-            order.setStatus(3);
+            order.setStatus(BigGiftPackageOrderStatusEnum.PAID.getCode());
             order.setDepositTime(LocalDateTime.now());
-            order.setDepositPaymentSerialNumber(order.getPayOrderCode());
+            order.setDepositPaymentThirdSerialNumber(orderId);
             bigGiftPackageOrderService.updateById(order);
             log.info("订单{}状态更新为完成支付", order.getCode());
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserServiceImpl.java
index c3134aa..9c1d1e6 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserServiceImpl.java
@@ -6,6 +6,7 @@
 import com.ruoyi.common.basic.PageInfo;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginUserApplet;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.system.mapper.TAppUserMapper;
 import com.ruoyi.system.model.*;
 import com.ruoyi.system.query.AppUserListQuery;
@@ -54,6 +55,9 @@
     @Autowired
     private TIntegralSettlementService tIntegralSettlementService;
 
+    @Autowired
+    private TCompanyService tCompanyService;
+
     @Override
     public PageInfo<TAppUser> pageList(AppUserListQuery query) {
         PageInfo<TAppUser> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
@@ -83,9 +87,10 @@
                     log.info("推广员不存在,绑定superiorId={}", superiorId);
                 }
             } else {
-                if (appUser.getReferrerStatus().equals(1)) {
+                if (Objects.isNull(appUser.getReferrerStatus()) || appUser.getReferrerStatus().equals(1)) {
                     appUser.setReferrerUserId(superiorId);
                     appUser.setReferrerTime(LocalDateTime.now());
+                    appUser.setReferrerStatus(1);
                 }
             }
             this.updateById(appUser);
@@ -94,6 +99,9 @@
 
     @Override
     public List<PromotionPageListVo> promotionPageList(Page<PromotionPageListVo> page, PromotionPageListQuery query) {
+        if (Objects.isNull(query.getCompanyId())) {
+            throw new ServiceException("公司ID不能为空");
+        }
         List<PromotionPageListVo> list = this.baseMapper.promotionPageList(page,query);
 
         if (!list.isEmpty()) {
@@ -220,4 +228,15 @@
         List<TAppUser> list = this.baseMapper.exportAppUser(query);
         return list;
     }
+
+    @Override
+    public TCompany getUserCompany(Integer appUserId) {
+        //默认返回空对象
+        TCompany company = new TCompany();
+        TAppUser appUser = this.getById(appUserId);
+        if (Objects.nonNull(appUser) && Objects.nonNull(appUser.getCompanyId())) {
+            company = tCompanyService.getById(appUser.getCompanyId());
+        }
+        return company;
+    }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserVisitServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserVisitServiceImpl.java
index 3fc7ac3..b52f2ea 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserVisitServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TAppUserVisitServiceImpl.java
@@ -7,6 +7,7 @@
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDate;
+import java.util.Objects;
 
 /**
  * <p>
@@ -21,6 +22,9 @@
 
     @Override
     public void recordVisit(Integer userId) {
+        if (Objects.isNull(userId)) {
+            return;
+        }
         LocalDate today = LocalDate.now();
         Long count = this.lambdaQuery()
                 .eq(TAppUserVisit::getAppUserId, userId)
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBigGiftPackageOrderServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBigGiftPackageOrderServiceImpl.java
index 9242efa..73b4d66 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBigGiftPackageOrderServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBigGiftPackageOrderServiceImpl.java
@@ -9,6 +9,7 @@
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.system.config.ICBCConfig;
 import com.ruoyi.system.dto.BigGiftPlaceOrderDTO;
+import com.ruoyi.system.enums.BigGiftPackageOrderStatusEnum;
 import com.ruoyi.system.mapper.TBigGiftPackageMapper;
 import com.ruoyi.system.mapper.TCommissionTransactionFlowMapper;
 import com.ruoyi.system.mapper.TBigGiftPackageOrderMapper;
@@ -22,6 +23,7 @@
 import com.ruoyi.system.query.GoldChangeRecordQuery;
 import com.ruoyi.system.query.ProfitPageListQuery;
 import com.ruoyi.system.query.UserProfitPageListQuery;
+import com.ruoyi.system.service.TAppUserService;
 import com.ruoyi.system.service.TBigGiftPackageOrderService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.system.service.TCommissionTransactionFlowService;
@@ -41,6 +43,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 /**
@@ -69,6 +72,9 @@
 
     @Autowired
     private ICBCConfig icbcConfig;
+
+    @Autowired
+    private TAppUserService appUserService;
 
     @Override
     public List<TBigGiftPackageOrder> pageList(Page<TBigGiftPackageOrder> tBigGiftPackageOrderPage, BigGiftPackageOrderQuery query) {
@@ -136,6 +142,9 @@
 
     @Override
     public List<ProfitPageListVo> profitPageList(Page<ProfitPageListVo> page, ProfitPageListQuery query) {
+        if (Objects.isNull(query.getCompanyId())) {
+            throw new ServiceException("公司ID不能为空");
+        }
         String sTime = null;
         String eTime = null;
         if(query.getCreateTime()!=null && !query.getCreateTime().isEmpty()){
@@ -341,11 +350,13 @@
         List<String> orderCodes = new ArrayList<>();
         String goodsJson = JSON.toJSONString(bigGiftPackage);
         LocalDateTime now = LocalDateTime.now();
-
+        //查询用户所属公司,获取经销商商户号
+        TCompany company = appUserService.getUserCompany(appUserId);
         for (int i = 0; i < dto.getQuantity(); i++) {
             TBigGiftPackageOrder order = new TBigGiftPackageOrder();
             String orderCode = OrderCodeGenerator.generateBigGiftOrderCode();
             order.setCode(orderCode);
+            order.setCompanyId(company.getId());
             order.setPayOrderCode(payOrderCode);
             order.setAppUserId(appUserId);
             order.setCreateTime(now);
@@ -356,8 +367,9 @@
             order.setFinalPayment(bigGiftPackage.getTotalPrice().subtract(bigGiftPackage.getDeposit()));
             order.setPaymentType(dto.getPaymentType());
             order.setEffectDayFlag(dto.getEffectDayFlag());
+            order.setPaymentPrice(dto.getPaymentType().equals(1) ? bigGiftPackage.getDeposit() : bigGiftPackage.getTotalPrice());
             // 订单状态:1=待付款
-            order.setStatus(1);
+            order.setStatus(BigGiftPackageOrderStatusEnum.PENDING_PAYMENT.getCode());
             order.setDelFlag(0);
 
             orderList.add(order);
@@ -372,10 +384,11 @@
                 .map(TBigGiftPackageOrder::getId)
                 .collect(Collectors.toList());
 
+
         // 8. 调用工行支付
         log.info("大礼包下单,支付订单号:{},业务订单号:{},支付金额:{},用户ID:{}", payOrderCode, orderCodes, paymentAmount, appUserId);
         JSONObject paymentParams = icbcPayUtil.wechatPay(payOrderCode, paymentAmount, bigGiftPackage.getName(), openid,
-                icbcConfig.getNotifyUrl() + "/big-gift/pay-notify");
+                icbcConfig.getNotifyUrl() + "/big-gift/pay-notify", company.getMerchantNumber(), company.getMerchantOpenid());
 
         // 9. 构建返回结果
         PlaceOrderVO vo = new PlaceOrderVO();
@@ -417,11 +430,14 @@
 
         // 6. 生成尾款支付订单号
         String finalPayOrderCode = OrderCodeGenerator.generateBigGiftFinalPayOrderCode();
-
+        order.setFinalPaymentSerialNumber(finalPayOrderCode);
+        this.updateById(order);
+        //查询用户所属公司,获取经销商商户号
+        TCompany company = appUserService.getUserCompany(appUserId);
         // 7. 调用工行支付
         log.info("大礼包尾款支付,订单ID:{},支付订单号:{},尾款金额:{},用户ID:{}", orderId, finalPayOrderCode, finalPayment, appUserId);
         JSONObject paymentParams = icbcPayUtil.wechatPay(finalPayOrderCode, finalPayment, "大礼包尾款", openid,
-                icbcConfig.getNotifyUrl() + "/big-gift/final-pay-notify");
+                icbcConfig.getNotifyUrl() + "/big-gift/final-pay-notify", company.getMerchantNumber(), company.getMerchantOpenid());
 
         // 8. 构建返回结果
         PlaceOrderVO vo = new PlaceOrderVO();
@@ -430,4 +446,61 @@
         vo.setPaymentParams(paymentParams);
         return vo;
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public PlaceOrderVO payNow(Integer orderId, Integer appUserId, String openid) {
+        // 1. 查询订单
+        TBigGiftPackageOrder order = this.getById(orderId);
+        if (order == null) {
+            throw new ServiceException("订单不存在");
+        }
+
+        // 2. 校验订单归属
+        if (!order.getAppUserId().equals(appUserId)) {
+            throw new ServiceException("无权操作此订单");
+        }
+
+        // 3. 校验订单状态(必须是待付款状态)
+        if (!BigGiftPackageOrderStatusEnum.PENDING_PAYMENT.getCode().equals(order.getStatus())) {
+            throw new ServiceException("订单状态不正确,无法支付");
+        }
+
+        // 4. 获取商品信息
+        TBigGiftPackage bigGiftPackage = bigGiftPackageMapper.selectById(order.getBigGiftPackageId());
+        String goodsName = bigGiftPackage != null ? bigGiftPackage.getName() : "大礼包商品";
+
+        // 5. 计算支付金额
+        BigDecimal paymentAmount;
+        if (order.getPaymentType() == 1) {
+            // 订金+尾款模式,支付订金
+            paymentAmount = order.getDeposit();
+        } else {
+            // 全款模式
+            paymentAmount = order.getOrderPrice();
+        }
+
+        // 6. 生成新的支付订单号
+        String newPayOrderCode = OrderCodeGenerator.generateBigGiftPayOrderCode();
+
+        // 7. 更新当前订单的 payOrderCode
+        order.setPayOrderCode(newPayOrderCode);
+
+        this.updateById(order);
+
+        //查询用户所属公司,获取经销商商户号
+        TCompany company = appUserService.getUserCompany(appUserId);
+
+        // 8. 调用工行支付
+        log.info("大礼包立即支付,订单ID:{},新支付订单号:{},支付金额:{},用户ID:{}", orderId, newPayOrderCode, paymentAmount, appUserId);
+        JSONObject paymentParams = icbcPayUtil.wechatPay(newPayOrderCode, paymentAmount, goodsName, openid,
+                icbcConfig.getNotifyUrl() + "/big-gift/pay-notify", company.getMerchantNumber(), company.getMerchantOpenid());
+
+        // 9. 构建返回结果
+        PlaceOrderVO vo = new PlaceOrderVO();
+        vo.setOrderIds(Collections.singletonList(orderId));
+        vo.setOrderCodes(Collections.singletonList(order.getCode()));
+        vo.setPaymentParams(paymentParams);
+        return vo;
+    }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TPhysicalGoodsOrderServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TPhysicalGoodsOrderServiceImpl.java
index 0d55c84..2bb3faf 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TPhysicalGoodsOrderServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TPhysicalGoodsOrderServiceImpl.java
@@ -7,17 +7,21 @@
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.system.config.ICBCConfig;
 import com.ruoyi.system.dto.PhysicalGoodsPlaceOrderDTO;
+import com.ruoyi.system.enums.PhysicalGoodsOrderStatusEnum;
 import com.ruoyi.system.mapper.TPhysicalGoodsMapper;
 import com.ruoyi.system.mapper.TPhysicalGoodsOrderMapper;
+import com.ruoyi.system.model.TCompany;
 import com.ruoyi.system.model.TPhysicalGoods;
 import com.ruoyi.system.model.TPhysicalGoodsOrder;
 import com.ruoyi.system.query.BigGiftPackageQuery;
+import com.ruoyi.system.service.TAppUserService;
 import com.ruoyi.system.service.TPhysicalGoodsOrderService;
 import com.ruoyi.system.utils.ICBCPayUtil;
 import com.ruoyi.system.utils.OrderCodeGenerator;
 import com.ruoyi.system.vo.PlaceOrderVO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -25,6 +29,7 @@
 import java.time.LocalDateTime;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * <p>
@@ -46,6 +51,22 @@
 
     @Autowired
     private ICBCConfig icbcConfig;
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    @Autowired
+    private TAppUserService appUserService;
+
+    /**
+     * 实物商品支付参数 Redis Key 前缀
+     */
+    private static final String PHYSICAL_ORDER_PAY_PARAMS_KEY = "physical_order_pay_params:";
+
+    /**
+     * 支付参数缓存过期时间(24小时)
+     */
+    private static final long PAY_PARAMS_EXPIRE_HOURS = 60;
 
     @Override
     public Page<TPhysicalGoodsOrder> pageList(BigGiftPackageQuery query) {
@@ -80,25 +101,68 @@
         // 支付方式:1=微信
         order.setPaymentMethod(1);
         // 订单状态:1=待付款
-        order.setStatus(1);
+        order.setStatus(PhysicalGoodsOrderStatusEnum.PENDING_PAYMENT.getCode());
         order.setDelFlag(0);
 
+        //查询用户所属公司,获取经销商商户号
+        TCompany company = appUserService.getUserCompany(appUserId);
+        order.setCompanyId(company.getId());
         this.save(order);
 
         // 3. 更新商品销量
         Integer currentSales = physicalGoods.getSales() == null ? 0 : physicalGoods.getSales();
         physicalGoods.setSales(currentSales + 1);
         physicalGoodsMapper.updateById(physicalGoods);
-
         // 4. 调用工行支付
         log.info("实物商品下单,订单号:{},支付金额:{},用户ID:{}", orderCode, physicalGoods.getTotalPrice(), appUserId);
-        JSONObject paymentParams = icbcPayUtil.wechatPay(orderCode, physicalGoods.getTotalPrice(), physicalGoods.getName(), openid,icbcConfig.getNotifyUrl()+"/physical/pay-notify");
+        JSONObject paymentParams = icbcPayUtil.wechatPay(orderCode, physicalGoods.getTotalPrice(), physicalGoods.getName(),
+                openid,icbcConfig.getNotifyUrl()+"/physical/pay-notify", company.getMerchantNumber(), company.getMerchantOpenid());
 
-        // 5. 构建返回结果
+        // 5. 缓存支付参数到 Redis(用于立即支付)
+        String redisKey = PHYSICAL_ORDER_PAY_PARAMS_KEY + order.getId();
+        redisTemplate.opsForValue().set(redisKey, paymentParams.toJSONString(), PAY_PARAMS_EXPIRE_HOURS, TimeUnit.MINUTES);
+        log.info("实物商品支付参数已缓存,订单ID:{},Redis Key:{}", order.getId(), redisKey);
+
+        // 6. 构建返回结果
         PlaceOrderVO vo = new PlaceOrderVO();
         vo.setOrderIds(Collections.singletonList(order.getId()));
         vo.setOrderCodes(Collections.singletonList(orderCode));
         vo.setPaymentParams(paymentParams);
         return vo;
     }
+
+    @Override
+    public PlaceOrderVO payNow(Integer orderId, Integer appUserId) {
+        // 1. 查询订单
+        TPhysicalGoodsOrder order = this.getById(orderId);
+        if (order == null) {
+            throw new ServiceException("订单不存在");
+        }
+
+        // 2. 校验订单所属用户
+        if (!order.getAppUserId().equals(appUserId)) {
+            throw new ServiceException("无权操作此订单");
+        }
+
+        // 3. 校验订单状态(必须是待付款)
+        if (!PhysicalGoodsOrderStatusEnum.PENDING_PAYMENT.getCode().equals(order.getStatus())) {
+            throw new ServiceException("订单状态不正确,无法支付");
+        }
+
+        // 4. 从 Redis 获取缓存的支付参数
+        String redisKey = PHYSICAL_ORDER_PAY_PARAMS_KEY + orderId;
+        Object cachedParams = redisTemplate.opsForValue().get(redisKey);
+        if (cachedParams == null) {
+            throw new ServiceException("支付参数已过期,请重新下单");
+        }
+
+        // 5. 构建返回结果
+        PlaceOrderVO vo = new PlaceOrderVO();
+        vo.setOrderIds(Collections.singletonList(order.getId()));
+        vo.setOrderCodes(Collections.singletonList(order.getCode()));
+        vo.setPaymentParams(JSON.parseObject(cachedParams.toString()));
+
+        log.info("实物商品立即支付,订单ID:{},用户ID:{}", orderId, appUserId);
+        return vo;
+    }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/ICBCPayUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/ICBCPayUtil.java
index 393e7d2..9fbf9b3 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/utils/ICBCPayUtil.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/ICBCPayUtil.java
@@ -13,6 +13,7 @@
 import com.ruoyi.system.config.ICBCConfig;
 import com.ruoyi.system.enums.ICBCRespOrderErrorEnum;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -25,11 +26,11 @@
    @Autowired
    private ICBCConfig icbcConfig;
 
-   public JSONObject wechatPay(String outTradeNo, BigDecimal totalPrice, String goodsName,String openid, String notifyUrl){
+   public JSONObject wechatPay(String outTradeNo, BigDecimal totalPrice, String goodsName,String openid, String notifyUrl, String merId, String merPrtclNo){
        CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz bizContent = new
                CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz();
-       bizContent.setMer_id(icbcConfig.getMerId());
-       bizContent.setMer_prtcl_no(icbcConfig.getMerPrtclNo());
+       bizContent.setMer_id(StringUtils.isBlank(merId) ? icbcConfig.getMerId() : merId);
+       bizContent.setMer_prtcl_no(StringUtils.isBlank(merPrtclNo) ? icbcConfig.getMerPrtclNo() : merPrtclNo);
        bizContent.setDecive_info(icbcConfig.getDeciveInfo());
        bizContent.setOut_trade_no(outTradeNo);
        bizContent.setOrig_date_time(DateUtils.getCurrentDateTimeWithT());
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/WxQrCodeUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/WxQrCodeUtil.java
index 3efadd0..7707209 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/WxQrCodeUtil.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/wx/WxQrCodeUtil.java
@@ -1,6 +1,7 @@
 package com.ruoyi.system.utils.wx;
 
 import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson2.JSONObject;
 import com.icbc.api.internal.util.internal.util.fastjson.JSON;
diff --git a/ruoyi-system/src/main/resources/mapper/system/TBigGiftPackageOrderMapper.xml b/ruoyi-system/src/main/resources/mapper/system/TBigGiftPackageOrderMapper.xml
index c82253c..5d43e42 100644
--- a/ruoyi-system/src/main/resources/mapper/system/TBigGiftPackageOrderMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/TBigGiftPackageOrderMapper.xml
@@ -41,7 +41,7 @@
         t1.deposit_payment_serial_number, t1.final_payment_time, t1.final_payment_method,
         t1.final_payment_serial_number, t1.del_flag, t1.remark,t2.phone,t2.name userName
         FROM t_big_gift_package_order t1 LEFT JOIN t_app_user t2 ON t1.app_user_id = t2.id
-        WHERE t1.del_flag = 0
+        WHERE t1.del_flag = 0 t1.status != 6
         <if test="query.phone != null and query.phone != ''">
             AND t2.phone = #{query.phone}
         </if>
@@ -54,6 +54,9 @@
         <if test="sTime !=null ">
             AND t1.create_time BETWEEN #{sTime} AND #{eTime}
         </if>
+        <if test="query.companyId != null">
+            AND t1.company_id = #{query.companyId}
+        </if>
         order by t1.create_time desc
     </select>
     <select id="export" resultType="com.ruoyi.system.model.TBigGiftPackageOrder">

--
Gitblit v1.7.1