瀏覽代碼

Merge branch 'master' into feature_bjws

luolinsong 1 月之前
父節點
當前提交
16c1d160be
共有 39 個文件被更改,包括 1031 次插入95 次删除
  1. 2 4
      fs-admin/src/main/java/com/fs/company/controller/CompanyStatisticsController.java
  2. 60 0
      fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java
  3. 6 0
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java
  4. 9 2
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java
  5. 15 15
      fs-admin/src/main/java/com/fs/live/controller/OrderController.java
  6. 1 1
      fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java
  7. 9 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptRoleController.java
  8. 3 0
      fs-company/src/main/java/com/fs/company/controller/live/OrderController.java
  9. 2 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  10. 49 0
      fs-service/src/main/java/com/fs/course/enums/MiniProgramAgreementEnum.java
  11. 32 0
      fs-service/src/main/java/com/fs/course/param/MiniProgramAgreementParam.java
  12. 6 0
      fs-service/src/main/java/com/fs/fastGpt/domain/FastGptRole.java
  13. 5 1
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptRoleMapper.java
  14. 2 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastGptRoleService.java
  15. 7 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptRoleServiceImpl.java
  16. 3 0
      fs-service/src/main/java/com/fs/his/config/AgreementConfig.java
  17. 104 0
      fs-service/src/main/java/com/fs/his/domain/MiniProgramAgreement.java
  18. 23 0
      fs-service/src/main/java/com/fs/his/mapper/MiniProgramAgreementMapper.java
  19. 17 0
      fs-service/src/main/java/com/fs/his/service/MiniProgramAgreementService.java
  20. 28 0
      fs-service/src/main/java/com/fs/his/service/impl/MiniProgramAgreementServiceImpl.java
  21. 7 1
      fs-service/src/main/java/com/fs/his/vo/FsIntegralOrderListVO.java
  22. 5 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java
  23. 29 0
      fs-service/src/main/java/com/fs/hisStore/param/CartPurchaseLimitCheckParam.java
  24. 2 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderItemScrmService.java
  25. 18 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java
  26. 5 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderItemScrmServiceImpl.java
  27. 12 8
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  28. 102 22
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductPurchaseLimitScrmServiceImpl.java
  29. 5 16
      fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java
  30. 19 19
      fs-service/src/main/java/com/fs/live/vo/MergedOrderVO.java
  31. 2 2
      fs-service/src/main/resources/application-config-druid-bjzm.yml
  32. 1 1
      fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml
  33. 10 1
      fs-service/src/main/resources/mapper/fastGpt/FastGptRoleMapper.xml
  34. 39 0
      fs-service/src/main/resources/mapper/his/MiniProgramAgreementMapper.xml
  35. 12 2
      fs-service/src/main/resources/mapper/hisStore/MergedOrderMapper.xml
  36. 89 0
      fs-user-app/src/main/java/com/fs/app/controller/H5Controller.java
  37. 21 0
      fs-user-app/src/main/java/com/fs/app/controller/live/LiveController.java
  38. 249 0
      fs-user-app/src/main/java/com/fs/app/controller/store/ProductScrmController.java
  39. 21 0
      fs-user-app/src/main/resources/templates/commonAgreement.html

+ 2 - 4
fs-admin/src/main/java/com/fs/company/controller/CompanyStatisticsController.java

@@ -784,10 +784,8 @@ public class CompanyStatisticsController extends BaseController
     @PostMapping("/syncYesterday")
     public AjaxResult syncYesterday() {
         try {
-            Date startDate = DateUtils.parseDate("2026-01-07");
-            Date endDate = DateUtils.parseDate("2026-01-07");
-            finishCourseStatisticsSyncService.syncDailyStatistics(startDate, endDate);
-            return AjaxResult.success("同步指定范围数据成功");
+            finishCourseStatisticsSyncService.syncMultiDimensionStatistics();
+            return AjaxResult.success("同步昨天数据成功");
         } catch (Exception e) {
             return AjaxResult.error("同步失败:" + e.getMessage());
         }

+ 60 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java

@@ -1,6 +1,7 @@
 package com.fs.course.controller;
 
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -19,11 +20,15 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.bean.BeanUtils;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.enums.MiniProgramAgreementEnum;
 import com.fs.course.param.FsCoursePlaySourceConfigCreateParam;
 import com.fs.course.param.FsCoursePlaySourceConfigEditParam;
+import com.fs.course.param.MiniProgramAgreementParam;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.course.vo.FsCoursePlaySourceConfigVO;
 import com.fs.framework.web.service.TokenService;
+import com.fs.his.domain.MiniProgramAgreement;
+import com.fs.his.service.MiniProgramAgreementService;
 import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import lombok.AllArgsConstructor;
@@ -42,6 +47,7 @@ public class FsCoursePlaySourceConfigController extends BaseController {
     private final IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
     private final TokenService tokenService;
     private final ISysConfigService configService;
+    private final MiniProgramAgreementService miniProgramAgreementService;
 
 //    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:list')")
     @GetMapping("/list")
@@ -183,4 +189,58 @@ public class FsCoursePlaySourceConfigController extends BaseController {
         }
         return R.ok().put("data", fsCoursePlaySourceConfigService.list(queryWrapper));
     }
+
+
+    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:agreement')")
+    @Log(title = "小程序协议配置", businessType = BusinessType.UPDATE)
+    @PostMapping("/updateAgreementConfig")
+    public AjaxResult updateAgreementConfig(@RequestBody MiniProgramAgreementParam agreement) {
+        Map<String, String> map = (Map<String, String>) JSON.parse(agreement.getAgreementData());
+
+        List<MiniProgramAgreement> list = new ArrayList<>();
+        for (MiniProgramAgreementEnum agreementEnum : MiniProgramAgreementEnum.values()) {
+            String content = map.get(agreementEnum.getCode());
+            if (content != null) {
+                MiniProgramAgreement update = new MiniProgramAgreement();
+                update.setAppId(agreement.getAppId());
+                update.setAgreementType(agreementEnum.getCode());
+                update.setAgreementContent(content);
+
+                list.add(update);
+            }
+        }
+
+        if (!list.isEmpty()) {
+            miniProgramAgreementService.batchUpsertAgreements(list);
+        }
+
+        return AjaxResult.success();
+    }
+
+
+
+    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:agreement')")
+    @GetMapping("/queryAgreementConfig")
+    public AjaxResult queryAgreementConfig(@RequestParam(required = true) String appid) {
+        // 查询协议数据
+        QueryWrapper<MiniProgramAgreement> queryWrapper = new QueryWrapper<MiniProgramAgreement>()
+                .eq("app_id", appid);
+        List<MiniProgramAgreement> agreements = miniProgramAgreementService.list(queryWrapper);
+
+        // 按agreementType分组
+        Map<String, String> agreementMap = new HashMap<>();
+        for (MiniProgramAgreement agreement : agreements) {
+            agreementMap.put(agreement.getAgreementType(), agreement.getAgreementContent());
+        }
+
+        // 转换为JSON串返回
+        String agreementData = JSON.toJSONString(agreementMap);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("agreementData", agreementData);
+        result.put("appId", appid);
+
+        return AjaxResult.success(result);
+    }
+
 }

+ 6 - 0
fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java

@@ -174,6 +174,9 @@ public class FsIntegralOrderController extends BaseController
                             if (goods != null && goods.getString("goodsName") != null) {
                                 vo.setGoodsName(goods.getString("goodsName"));
                             }
+                            if (goods != null && goods.getString("barCode") != null) {
+                                vo.setBarCode(goods.getString("barCode"));
+                            }
                         }
                     } else if (vo.getItemJson().startsWith("{")) {
                         // 对象格式
@@ -181,6 +184,9 @@ public class FsIntegralOrderController extends BaseController
                         if (goods != null && goods.getString("goodsName") != null) {
                             vo.setGoodsName(goods.getString("goodsName"));
                         }
+                        if (goods != null && goods.getString("barCode") != null) {
+                            vo.setGoodsName(goods.getString("barCode"));
+                        }
                     }
                 } catch (Exception e) {
                     // 解析失败时保持goodsName为空,避免导出出错

+ 9 - 2
fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java

@@ -56,6 +56,7 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.web.bind.annotation.*;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.HashMap;
@@ -197,7 +198,7 @@ public class FsStorePaymentScrmController extends BaseController
     }
 
     @PreAuthorize("@ss.hasPermi('store:storePayment:refund')")
-    @PostMapping("refundStorePayment")
+    @PostMapping("/refundStorePayment")
     @Transactional
     public R refundStorePayment(@RequestBody FsStorePaymentScrm fsStorePayment)
     {
@@ -238,7 +239,13 @@ public class FsStorePaymentScrmController extends BaseController
                 }
                 V2TradePaymentScanpayRefundRequest request = new V2TradePaymentScanpayRefundRequest();
                 request.setHuifuId(huifuId);
-                request.setOrdAmt(payment.getPayMoney().toString());
+
+                if (("易行健".equals(cloudHostProper.getCompanyName()))){
+                    request.setOrdAmt(fsStorePayment.getRefundMoney().setScale(2, RoundingMode.DOWN).toString());
+                }else {
+                    request.setOrdAmt(payment.getPayMoney().toString());
+                }
+
                 request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
                 request.setReqSeqId("refund-"+payment.getPayCode());
                 request.setAppId(payment.getAppId());

+ 15 - 15
fs-admin/src/main/java/com/fs/live/controller/OrderController.java

@@ -88,12 +88,12 @@ public class OrderController extends BaseController
         // 先查询数据,限制查询20001条,用于判断是否超过限制
         PageHelper.startPage(1, maxExportCount + 1);
         List<MergedOrderVO> list = mergedOrderService.selectMergedOrderList(param);
-        list = list.stream().filter(item -> StringUtils.isNotEmpty(item.getBankTransactionId())).collect(Collectors.toList());
-        
         // 如果查询结果超过20000条,返回错误提示
         if (list != null && list.size() > maxExportCount) {
             return AjaxResult.error("导出数据量超过限制,最多只能导出" + maxExportCount + "条数据,请缩小查询范围后重试");
         }
+        list = list.stream().filter(item -> StringUtils.isNotEmpty(item.getBankTransactionId())).collect(Collectors.toList());
+
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 
         for (MergedOrderVO vo : list) {
@@ -109,7 +109,7 @@ public class OrderController extends BaseController
 
         // 转换为导出VO
         List<MergedOrderExportVO> exportList = convertToExportVO(list, false,loginUser);
-        
+
         // 如果数据量在限制范围内,正常导出
         ExcelUtil<MergedOrderExportVO> util = new ExcelUtil<>(MergedOrderExportVO.class);
         return util.exportExcel(exportList, "合并订单数据");
@@ -127,12 +127,12 @@ public class OrderController extends BaseController
         // 先查询数据,限制查询20001条,用于判断是否超过限制
         PageHelper.startPage(1, maxExportCount + 1);
         List<MergedOrderVO> list = mergedOrderService.selectMergedOrderList(param);
-        list = list.stream().filter(item -> StringUtils.isNotEmpty(item.getBankTransactionId())).collect(Collectors.toList());
-
         // 如果查询结果超过20000条,返回错误提示
         if (list != null && list.size() > maxExportCount) {
             return AjaxResult.error("导出数据量超过限制,最多只能导出" + maxExportCount + "条数据,请缩小查询范围后重试");
         }
+        list = list.stream().filter(item -> StringUtils.isNotEmpty(item.getBankTransactionId())).collect(Collectors.toList());
+
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 
         for (MergedOrderVO vo : list) {
@@ -235,13 +235,13 @@ public class OrderController extends BaseController
 
         return list.stream().map(vo -> {
             MergedOrderExportVO exportVO = new MergedOrderExportVO();
-            
+
             // 订单基本信息(参考 FsStoreOrderItemExportVO 的顺序)
             exportVO.setOrderTypeName(vo.getOrderTypeName());
             exportVO.setOrderCode(vo.getOrderCode());
             exportVO.setStatus(vo.getStatus() != null ? String.valueOf(vo.getStatus()) : null);
             exportVO.setUserId(vo.getUserId());
-            
+
             // 产品信息
             exportVO.setProductName(StringUtils.isEmpty(vo.getProductName()) ? "产品被删除" : vo.getProductName());
             exportVO.setBarCode(vo.getBarCode());
@@ -261,7 +261,7 @@ public class OrderController extends BaseController
                 exportVO.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
                 exportVO.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
             }
-            
+
             // 时间信息
             exportVO.setCreateTime(vo.getCreateTime());
             exportVO.setPayTime(vo.getPayTime());
@@ -271,25 +271,25 @@ public class OrderController extends BaseController
             exportVO.setDeliverySn(vo.getDeliveryCode()); // 快递公司编号,合并订单暂无此字段
             exportVO.setDeliveryName(vo.getDeliveryName()); // 快递公司,合并订单暂无此字段
             exportVO.setDeliveryId(vo.getDeliveryId());
-            
+
             // 公司和销售信息
             exportVO.setCompanyName(vo.getCompanyName());
             exportVO.setCompanyUserNickName(vo.getCompanyUserNickName());
-            
+
             // 套餐信息
             exportVO.setPackageName(null); // 套餐名称,合并订单暂无此字段
             exportVO.setGroupBarCode(null); // 组合码,合并订单暂无此字段
-            
+
             // 凭证信息
             exportVO.setIsUpload(null); // 是否上传凭证,合并订单暂无此字段
             exportVO.setUploadTime(null); // 上传时间,合并订单暂无此字段
-            
+
             // 档期信息
             exportVO.setScheduleName(null); // 归属档期,合并订单暂无此字段
-            
+
             // 银行交易流水号
             exportVO.setBankTransactionId(vo.getBankTransactionId());
-            
+
             // 金额信息
             exportVO.setTotalPrice(vo.getTotalPrice());
             exportVO.setPayPrice(vo.getPayPrice());
@@ -304,7 +304,7 @@ public class OrderController extends BaseController
                 vo.setFPrice(BigDecimal.ZERO);
                 vo.setBankTransactionId("");
             }
-            
+
             return exportVO;
         }).collect(Collectors.toList());
     }

+ 1 - 1
fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java

@@ -377,7 +377,7 @@ public class qwTask {
     /**
      * 特殊处理(木易完课统计数据)
      */
-    private  void  syncMultiDimensionStatistics(){
+    public  void  syncMultiDimensionStatistics(){
         finishCourseStatisticsSyncService.syncMultiDimensionStatistics();
     }
 }

+ 9 - 0
fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptRoleController.java

@@ -8,6 +8,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.service.IFastGptRoleService;
 import com.fs.fastGpt.vo.FastGptRoleVO;
@@ -78,6 +79,14 @@ public class FastGptRoleController extends BaseController
         return util.exportExcel(list, "应用数据");
     }
 
+    @GetMapping("/getAllCourseList")
+    public R getAllCourseList()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        List<FsUserCourseVideo> list = fastGptRoleService.selectAllCourseList(loginUser.getCompany().getCompanyId());
+        return R.ok().put("data",list);
+    }
+
     /**
      * 获取应用详细信息
      */

+ 3 - 0
fs-company/src/main/java/com/fs/company/controller/live/OrderController.java

@@ -68,6 +68,9 @@ public class OrderController extends BaseController
         }
         CompanyUser user = SecurityUtils.getLoginUser().getUser();
         param.setCompanyId(user.getCompanyId());
+       if (user.getUserType().equals("01")){
+           param.setUserId(user.getUserId());
+       }
         startPage();
         List<MergedOrderVO> list = mergedOrderService.selectMergedOrderList(param);
         for (MergedOrderVO vo : list) {

+ 2 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -699,6 +699,7 @@ public class CompanyServiceImpl implements ICompanyService
                 log.setBalance(company.getMoney());
                 log.setCreateTime(new Date());
                 log.setBusinessId(order.getId().toString());
+                log.setType(0);
                 moneyLogsMapper.insertCompanyMoneyLogs(log);
                 FsStoreOrderScrm fsStoreOrder = new FsStoreOrderScrm();
                 fsStoreOrder.setId(order.getId());
@@ -735,6 +736,7 @@ public class CompanyServiceImpl implements ICompanyService
                 log.setBalance(company.getMoney());
                 log.setCreateTime(new Date());
                 log.setBusinessId(order.getOrderId().toString());
+                log.setType(1);
                 moneyLogsMapper.insertCompanyMoneyLogs(log);
                 LiveOrder liveOrder = new LiveOrder();
                 liveOrder.setOrderId(order.getOrderId());

+ 49 - 0
fs-service/src/main/java/com/fs/course/enums/MiniProgramAgreementEnum.java

@@ -0,0 +1,49 @@
+package com.fs.course.enums;
+
+public enum MiniProgramAgreementEnum {
+
+    DOCTOR_REGISTER("doctorRegister", "医生注册协议"),
+    DOCTOR_FILING("doctorFiling", "医生多机构备案协议"),
+    USER_REGISTER("userRegister", "用户协议"),
+    USER_PRIVACY("userPrivacy", "隐私协议"),
+    USER_HEALTH("userHealth", "健康客服协议"),
+    VIP_SERVICE("vipService", "会员服务协议"),
+    VIP_AUTOMATIC_SERVICE("vipAutomaticService", "会员自动续费协议"),
+    USER_REMOVE_SERVICE("userRemoveService", "用户注销协议");
+    private String code;
+    private String message;
+    MiniProgramAgreementEnum(String code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public static MiniProgramAgreementEnum getEnum(String code) {
+        for (MiniProgramAgreementEnum value : MiniProgramAgreementEnum.values()) {
+            if (value.getCode().equals(code)) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+
+    public static String getMessage(String code) {
+        for (MiniProgramAgreementEnum value : MiniProgramAgreementEnum.values()) {
+            if (value.getCode().equals(code)) {
+                return value.getMessage();
+            }
+        }
+        return null;
+    }
+
+
+
+}

+ 32 - 0
fs-service/src/main/java/com/fs/course/param/MiniProgramAgreementParam.java

@@ -0,0 +1,32 @@
+package com.fs.course.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class MiniProgramAgreementParam {
+
+    // 小程序id
+    private String appId;
+
+    private String agreementData;
+
+//    // 医生注册协议
+//    private String doctorRegister;
+//    // 医生多机构备案协议
+//    private String doctorFiling;
+//    // 用户协议
+//    private String userRegister;
+//    // 隐私协议
+//    private String userPrivacy;
+//    // 健康客服协议
+//    private String userHealth;
+//    // 会员服务协议
+//    private String vipService;
+//    // 会员自动续费协议
+//    private String vipAutomaticService;
+//    // 用户注销协议
+//    private String userRemoveService;
+}

+ 6 - 0
fs-service/src/main/java/com/fs/fastGpt/domain/FastGptRole.java

@@ -78,4 +78,10 @@ public class FastGptRole extends BaseEntity
      * 是否禁止时段回复 0是不开启禁止  1是开启禁止 默认为1
      */
     private Integer forbidStatus;
+
+    //是否给新客户发送课程 0不发 1发
+    private Integer sendCourseStatus;
+
+    //课程Id
+    private Long courseId;
 }

+ 5 - 1
fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptRoleMapper.java

@@ -1,6 +1,8 @@
 package com.fs.fastGpt.mapper;
 
 import java.util.List;
+
+import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.vo.FastGptRoleVO;
 import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
@@ -88,7 +90,7 @@ public interface FastGptRoleMapper
 
     @Select("select id dictValue,name dictLabel from fastgpt_role_type ")
     List<OptionsVO> selectFastGptRoleType();
-    @Select("select r.role_id, r.role_name,t.contact_info,r.company_id, r.create_time, r.update_time, r.role_type, r.mode_config_json, r.mode, r.kf_id, r.kf_url, r.avatar, r.kf_media_id,r.reminder_words, r.bind_corp_id,r.channel_type from fastgpt_role r LEFT JOIN fastgpt_role_type t on t.id =r.role_type where role_id = #{roleId}")
+    @Select("select r.role_id, r.role_name,t.contact_info,r.company_id, r.create_time, r.update_time, r.role_type, r.mode_config_json, r.mode, r.kf_id, r.kf_url, r.avatar, r.kf_media_id,r.reminder_words, r.bind_corp_id,r.channel_type,r.send_course_status,r.course_id from fastgpt_role r LEFT JOIN fastgpt_role_type t on t.id =r.role_type where role_id = #{roleId}")
     FastGptRole selectFastGptRoleTypeByRoleId(Long roleId);
 
     List<FastGptRole> selectFastGptRoleByRoleIds(@Param("roleIds") List<Long> roleIds);
@@ -114,4 +116,6 @@ public interface FastGptRoleMapper
             "        </where>" +
             "</script> ")
     List<FastGptRoleVO> selectFastGptRoleListVONew(FastGptRole fastGptRole);
+
+    List<FsUserCourseVideo> selectAllCourseList(@Param("companyId") Long companyId);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/fastGpt/service/IFastGptRoleService.java

@@ -3,6 +3,7 @@ package com.fs.fastGpt.service;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
+import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.vo.FastGptRoleDataVO;
 import com.fs.fastGpt.vo.FastGptRoleVO;
@@ -83,4 +84,5 @@ public interface IFastGptRoleService
 
     List<FastGptRoleVO> selectFastGptRoleListVONew(FastGptRole fastGptRole);
 
+    List<FsUserCourseVideo> selectAllCourseList(Long companyId);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptRoleServiceImpl.java

@@ -10,6 +10,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.fastGpt.domain.FastGptRoleTag;
 import com.fs.fastGpt.mapper.FastGptRoleTagMapper;
 import com.fs.fastGpt.vo.FastGptRoleDataVO;
@@ -58,6 +59,7 @@ public class FastGptRoleServiceImpl implements IFastGptRoleService
 
         FastGptRole role = fastGptRoleMapper.selectFastGptRoleByRoleId(roleId);
 
+        role.setSendCourseStatus(role.getSendCourseStatus() == null?0:role.getSendCourseStatus());
         FastGptRoleTag fastGptRoleTag=new FastGptRoleTag();
         fastGptRoleTag.setRoleId(roleId);
 
@@ -253,5 +255,10 @@ public class FastGptRoleServiceImpl implements IFastGptRoleService
         return fastGptRoleMapper.selectFastGptRoleListVONew(fastGptRole);
     }
 
+    @Override
+    public List<FsUserCourseVideo> selectAllCourseList(Long companyId) {
+        return fastGptRoleMapper.selectAllCourseList(companyId);
+    }
+
 
 }

+ 3 - 0
fs-service/src/main/java/com/fs/his/config/AgreementConfig.java

@@ -12,4 +12,7 @@ public class AgreementConfig implements Serializable {
     String vipService;
     String vipAutomaticService;
     String userRemoveService;
+    String doctorRegister;
+    String doctorFiling;
+
 }

+ 104 - 0
fs-service/src/main/java/com/fs/his/domain/MiniProgramAgreement.java

@@ -0,0 +1,104 @@
+package com.fs.his.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 小程序用户协议信息表
+ * @TableName fs_mini_program_agreement
+ */
+@TableName(value ="fs_mini_program_agreement")
+@Data
+public class MiniProgramAgreement {
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 小程序ID
+     */
+    private String appId;
+
+    /**
+     * 协议类型
+     */
+    private String agreementType;
+
+    /**
+     * 协议内容
+     */
+    private String agreementContent;
+
+    /**
+     * 是否生效(0:否,1:是)
+     */
+    private Integer isActive;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        MiniProgramAgreement other = (MiniProgramAgreement) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getAppId() == null ? other.getAppId() == null : this.getAppId().equals(other.getAppId()))
+            && (this.getAgreementType() == null ? other.getAgreementType() == null : this.getAgreementType().equals(other.getAgreementType()))
+            && (this.getAgreementContent() == null ? other.getAgreementContent() == null : this.getAgreementContent().equals(other.getAgreementContent()))
+            && (this.getIsActive() == null ? other.getIsActive() == null : this.getIsActive().equals(other.getIsActive()))
+            && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()))
+            && (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getAppId() == null) ? 0 : getAppId().hashCode());
+        result = prime * result + ((getAgreementType() == null) ? 0 : getAgreementType().hashCode());
+        result = prime * result + ((getAgreementContent() == null) ? 0 : getAgreementContent().hashCode());
+        result = prime * result + ((getIsActive() == null) ? 0 : getIsActive().hashCode());
+        result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
+        result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", appId=").append(appId);
+        sb.append(", agreementType=").append(agreementType);
+        sb.append(", agreementContent=").append(agreementContent);
+        sb.append(", isActive=").append(isActive);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 23 - 0
fs-service/src/main/java/com/fs/his/mapper/MiniProgramAgreementMapper.java

@@ -0,0 +1,23 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.MiniProgramAgreement;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+
+/**
+* @author Administrator
+* @description 针对表【fs_mini_program_agreement(小程序用户协议信息表)】的数据库操作Mapper
+* @createDate 2026-01-08 17:17:17
+* @Entity generator.domain.MiniProgramAgreement
+*/
+public interface MiniProgramAgreementMapper extends BaseMapper<MiniProgramAgreement> {
+
+    void batchUpsertAgreements(@Param("agreements") List<MiniProgramAgreement> agreements);
+}
+
+
+
+

+ 17 - 0
fs-service/src/main/java/com/fs/his/service/MiniProgramAgreementService.java

@@ -0,0 +1,17 @@
+package com.fs.his.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.MiniProgramAgreement;
+
+import java.util.List;
+
+
+/**
+* @author Administrator
+* @description 针对表【fs_mini_program_agreement(小程序用户协议信息表)】的数据库操作Service
+* @createDate 2026-01-08 17:17:17
+*/
+public interface MiniProgramAgreementService extends IService<MiniProgramAgreement> {
+
+    void batchUpsertAgreements(List<MiniProgramAgreement> list);
+}

+ 28 - 0
fs-service/src/main/java/com/fs/his/service/impl/MiniProgramAgreementServiceImpl.java

@@ -0,0 +1,28 @@
+package com.fs.his.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.his.domain.MiniProgramAgreement;
+import com.fs.his.mapper.MiniProgramAgreementMapper;
+import com.fs.his.service.MiniProgramAgreementService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+* @author Administrator
+* @description 针对表【fs_mini_program_agreement(小程序用户协议信息表)】的数据库操作Service实现
+* @createDate 2026-01-08 17:17:17
+*/
+@Service
+public class MiniProgramAgreementServiceImpl extends ServiceImpl<MiniProgramAgreementMapper, MiniProgramAgreement>
+    implements MiniProgramAgreementService {
+
+    @Override
+    public void batchUpsertAgreements(List<MiniProgramAgreement> list) {
+        baseMapper.batchUpsertAgreements(list);
+    }
+}
+
+
+
+

+ 7 - 1
fs-service/src/main/java/com/fs/his/vo/FsIntegralOrderListVO.java

@@ -36,6 +36,12 @@ public class FsIntegralOrderListVO {
     /** 商品信息 */
     @Excel(name = "商品信息")
     private String itemJson;
+    @Excel(name = "商品名称")
+    private String goodsName;
+
+    /** 商品条码 */
+    @Excel(name = "商品编码")
+    private String barCode;
 
     /** 支付积分 */
     @Excel(name = "支付积分")
@@ -84,5 +90,5 @@ public class FsIntegralOrderListVO {
     private String erpPhone;
 
     private String loginAccount;
-    private String goodsName;
+
 }

+ 5 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java

@@ -305,4 +305,9 @@ public interface FsStoreOrderItemScrmMapper
     List<FsStoreOrderItemVO> selectFsStoreOrderItemListByOrderIds(@Param("orderIds")List<Long> orderIds);
 
     String selectFsStoreOrderItemByOrderId(@Param("orderId") Long orderId);
+
+
+    @Select("select product_id from fs_store_order_item_scrm where order_code = #{orderCode}")
+    Long selectProductIdByOrderCode(@Param("orderCode") String orderCode);
+
 }

+ 29 - 0
fs-service/src/main/java/com/fs/hisStore/param/CartPurchaseLimitCheckParam.java

@@ -0,0 +1,29 @@
+package com.fs.hisStore.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 购物车结算前限购校验参数
+ */
+@Data
+public class CartPurchaseLimitCheckParam {
+    
+    @Data
+    public static class ProductItem {
+        @NotNull(message = "商品ID不能为空")
+        @ApiModelProperty(value = "商品ID", required = true)
+        private Long productId;
+        
+        @NotNull(message = "商品数量不能为空")
+        @ApiModelProperty(value = "商品数量", required = true)
+        private Integer num;
+    }
+    
+    @NotNull(message = "商品列表不能为空")
+    @ApiModelProperty(value = "选中的商品列表", required = true)
+    private List<ProductItem> products;
+}

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderItemScrmService.java

@@ -77,4 +77,6 @@ public interface IFsStoreOrderItemScrmService
     List<FsStoreOrderItemListDVO> selectFsStoreOrderItemListDVOByOrderId(Long orderId);
 
     String selectFsStoreOrderItemByOrderId(Long orderId);
+
+    Long selectProductIdByOrderCode(String orderCode);
 }

+ 18 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java

@@ -964,10 +964,28 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
         if(order.getTuiUserId()!=null&&order.getTuiUserId()>0){
             userService.subTuiMoney(order);
         }
+        // 删除限购记录
+        this.deletePurchaseLimitRecordsForStoreOrder(order);
         return R.ok();
     }
 
+    @Autowired
+    private IFsStoreProductPurchaseLimitScrmService purchaseLimitService;
 
+    /**
+     * 删除限购记录(用于直播订单)
+     * @param fsStoreOrderScrm 订单
+     */
+    private void deletePurchaseLimitRecordsForStoreOrder(FsStoreOrderScrm fsStoreOrderScrm) {
+        List<FsStoreOrderItemVO> fsStoreOrderItemVOS = fsStoreOrderItemMapper.selectFsStoreOrderItemListByOrderId(fsStoreOrderScrm.getId());
+        if (fsStoreOrderItemVOS != null && !fsStoreOrderItemVOS.isEmpty()) {
+            // 减少限购数量
+            for (FsStoreOrderItemVO fsStoreOrderItemVO : fsStoreOrderItemVOS) {
+                purchaseLimitService.decreasePurchaseLimit(fsStoreOrderItemVO.getProductId(), fsStoreOrderScrm.getUserId(), Math.toIntExact(fsStoreOrderItemVO.getNum()));
+            }
+        }
+
+    }
     @Autowired
     private FsJstAftersalePushScrmMapper fsJstAftersalePushMapper;
 

+ 5 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderItemScrmServiceImpl.java

@@ -136,4 +136,9 @@ public class FsStoreOrderItemScrmServiceImpl implements IFsStoreOrderItemScrmSer
     public String selectFsStoreOrderItemByOrderId(Long orderId) {
         return fsStoreOrderItemMapper.selectFsStoreOrderItemByOrderId(orderId);
     }
+
+    @Override
+    public Long selectProductIdByOrderCode(String orderCode) {
+        return fsStoreOrderItemMapper.selectProductIdByOrderCode(orderCode);
+    }
 }

+ 12 - 8
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -1096,12 +1096,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 }
                 fsStoreOrderItemMapper.insertFsStoreOrderItem(item);
                 listOrderItem.add(item);
-                
-                // 记录限购数量(订单创建成功后记录)
-                FsStoreProductScrm product = productService.selectFsStoreProductById(vo.getProductId());
-                if (product != null && product.getPurchaseLimit() != null && product.getPurchaseLimit() > 0) {
-                    purchaseLimitService.increasePurchaseLimit(vo.getProductId(), userId, vo.getCartNum());
-                }
+
             }
             if (listOrderItem.size() > 0) {
                 String itemJson = JSONUtil.toJsonStr(listOrderItem);
@@ -1297,8 +1292,6 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             this.refundCoupon(order);
             //退回库存
             this.refundStock(order);
-            // 删除限购记录
-            this.deletePurchaseLimitRecords(order);
             fsStoreOrderMapper.cancelOrder(orderId);
             //添加记录
             orderStatusService.create(order.getId(), OrderLogEnum.CANCEL_ORDER.getValue(),
@@ -2052,7 +2045,18 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         if (storeOrder.getCompanyId() != null) {
             addOrderAudit(order);
         }
+        try {
+            // 记录限购数量(订单创建成功后记录)
+            List<FsStoreOrderItemVO> fsStoreOrderItemVOS = storeOrderItemService.selectFsStoreOrderItemListByOrderId(order.getId());
+            if (fsStoreOrderItemVOS != null && !fsStoreOrderItemVOS.isEmpty()) {
+                for (FsStoreOrderItemVO fsStoreOrderItemVO : fsStoreOrderItemVOS) {
+                    purchaseLimitService.increasePurchaseLimit(fsStoreOrderItemVO.getProductId(), order.getUserId(), Math.toIntExact(fsStoreOrderItemVO.getNum()));
+                }
+            }
 
+        } catch (Exception e) {
+            log.error("创建限购商品失败:{}",e.getMessage());
+        }
 
     return "SUCCESS";
 

+ 102 - 22
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductPurchaseLimitScrmServiceImpl.java

@@ -1,10 +1,22 @@
 package com.fs.hisStore.service.impl;
 
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import com.fs.common.constant.LiveKeysConstant;
+import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
+import com.fs.hisStore.domain.FsStoreProductAttrScrm;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
 import com.fs.hisStore.domain.FsStoreProductPurchaseLimitScrm;
+import com.fs.hisStore.domain.FsStoreProductScrm;
+import com.fs.hisStore.mapper.FsStoreProductAttrScrmMapper;
+import com.fs.hisStore.mapper.FsStoreProductAttrValueScrmMapper;
 import com.fs.hisStore.mapper.FsStoreProductPurchaseLimitScrmMapper;
+import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
 import com.fs.hisStore.service.IFsStoreProductPurchaseLimitScrmService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -21,6 +33,16 @@ public class FsStoreProductPurchaseLimitScrmServiceImpl implements IFsStoreProdu
     @Autowired
     private FsStoreProductPurchaseLimitScrmMapper fsStoreProductPurchaseLimitMapper;
 
+    @Autowired
+    private RedisCache redisCache;
+    @Autowired
+    private FsStoreProductScrmMapper fsStoreProductScrmMapper;
+    @Autowired
+    private FsStoreProductAttrScrmMapper fsStoreProductAttrScrmMapper;
+    @Autowired
+    private FsStoreProductAttrValueScrmMapper fsStoreProductAttrValueScrmMapper;
+
+
     /**
      * 查询商品限购
      *
@@ -119,19 +141,48 @@ public class FsStoreProductPurchaseLimitScrmServiceImpl implements IFsStoreProdu
     @Override
     public int increasePurchaseLimit(Long productId, Long userId, Integer num)
     {
-        FsStoreProductPurchaseLimitScrm limit = selectByProductIdAndUserId(productId, userId);
-        if (limit == null) {
-            // 创建新记录
-            limit = new FsStoreProductPurchaseLimitScrm();
-            limit.setProductId(productId);
-            limit.setUserId(userId);
-            limit.setNum(num);
-            return insertFsStoreProductPurchaseLimit(limit);
+        String cacheKey = String.format(LiveKeysConstant.PRODUCT_DETAIL_CACHE, productId);
+        Map<String, Object> cachedData = redisCache.getCacheObject(cacheKey);
+
+        FsStoreProductScrm product;
+        List<FsStoreProductAttrScrm> productAttr;
+        List<FsStoreProductAttrValueScrm> productValues;
+
+        if (cachedData != null) {
+            // 从缓存中获取数据
+            product = (FsStoreProductScrm) cachedData.get("product");
         } else {
-            // 更新现有记录
-            limit.setNum(limit.getNum() + num);
-            return updateFsStoreProductPurchaseLimit(limit);
+            // 缓存中没有,从数据库查询
+            product = fsStoreProductScrmMapper.selectFsStoreProductById(productId);
+            if(product==null){
+                return -1;
+            }
+            productAttr = fsStoreProductAttrScrmMapper.selectFsStoreProductAttrByProductId(productId);
+            productValues = fsStoreProductAttrValueScrmMapper.selectFsStoreProductAttrValueByProductId(productId);
+
+            // 将数据存入缓存
+            Map<String, Object> cacheData = new HashMap<>();
+            cacheData.put("product", product);
+            cacheData.put("productAttr", productAttr);
+            cacheData.put("productValues", productValues);
+            redisCache.setCacheObject(cacheKey, cacheData, LiveKeysConstant.PRODUCT_DETAIL_CACHE_EXPIRE, TimeUnit.SECONDS);
         }
+        if (product != null && product.getPurchaseLimit() != null && product.getPurchaseLimit() > 0) {
+            FsStoreProductPurchaseLimitScrm limit = selectByProductIdAndUserId(productId, userId);
+            if (limit == null) {
+                // 创建新记录
+                limit = new FsStoreProductPurchaseLimitScrm();
+                limit.setProductId(productId);
+                limit.setUserId(userId);
+                limit.setNum(num);
+                return insertFsStoreProductPurchaseLimit(limit);
+            } else {
+                // 更新现有记录
+                limit.setNum(limit.getNum() + num);
+                return updateFsStoreProductPurchaseLimit(limit);
+            }
+        }
+        return -1;
     }
 
     /**
@@ -145,19 +196,48 @@ public class FsStoreProductPurchaseLimitScrmServiceImpl implements IFsStoreProdu
     @Override
     public int decreasePurchaseLimit(Long productId, Long userId, Integer num)
     {
-        FsStoreProductPurchaseLimitScrm limit = selectByProductIdAndUserId(productId, userId);
-        if (limit != null) {
-            int newNum = limit.getNum() - num;
-            if (newNum <= 0) {
-                // 如果数量为0或负数,删除记录
-                return deleteFsStoreProductPurchaseLimitById(limit.getId());
-            } else {
-                // 更新数量
-                limit.setNum(newNum);
-                return updateFsStoreProductPurchaseLimit(limit);
+        String cacheKey = String.format(LiveKeysConstant.PRODUCT_DETAIL_CACHE, productId);
+        Map<String, Object> cachedData = redisCache.getCacheObject(cacheKey);
+
+        FsStoreProductScrm product;
+        List<FsStoreProductAttrScrm> productAttr;
+        List<FsStoreProductAttrValueScrm> productValues;
+
+        if (cachedData != null) {
+            // 从缓存中获取数据
+            product = (FsStoreProductScrm) cachedData.get("product");
+        } else {
+            // 缓存中没有,从数据库查询
+            product = fsStoreProductScrmMapper.selectFsStoreProductById(productId);
+            if(product==null){
+                return -1;
+            }
+            productAttr = fsStoreProductAttrScrmMapper.selectFsStoreProductAttrByProductId(productId);
+            productValues = fsStoreProductAttrValueScrmMapper.selectFsStoreProductAttrValueByProductId(productId);
+
+            // 将数据存入缓存
+            Map<String, Object> cacheData = new HashMap<>();
+            cacheData.put("product", product);
+            cacheData.put("productAttr", productAttr);
+            cacheData.put("productValues", productValues);
+            redisCache.setCacheObject(cacheKey, cacheData, LiveKeysConstant.PRODUCT_DETAIL_CACHE_EXPIRE, TimeUnit.SECONDS);
+        }
+        if (product != null && product.getPurchaseLimit() != null && product.getPurchaseLimit() > 0) {
+            FsStoreProductPurchaseLimitScrm limit = selectByProductIdAndUserId(productId, userId);
+            if (limit != null) {
+                int newNum = limit.getNum() - num;
+                if (newNum <= 0) {
+                    // 如果数量为0或负数,删除记录
+                    return deleteFsStoreProductPurchaseLimitById(limit.getId());
+                } else {
+                    // 更新数量
+                    limit.setNum(newNum);
+                    return updateFsStoreProductPurchaseLimit(limit);
+                }
             }
+            return 0;
         }
-        return 0;
+        return -1;
     }
 }
 

+ 5 - 16
fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -786,6 +786,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             baseMapper.updateLiveOrder(order);
             try {
                 this.updateLiveWatchLog(order);
+                // 记录限购数量(订单创建成功后记录)
+                purchaseLimitService.increasePurchaseLimit(order.getProductId(), Long.valueOf(order.getUserId()), Integer.valueOf(order.getTotalNum()));
                 this.createOmsOrderCall(order);
             } catch (Exception e) {
                 log.error("推送erp失败:{}",e.getMessage());
@@ -1431,6 +1433,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 userService.subTuiMoney(storeOrder);
             }
         }
+        // 删除限购记录
+        deletePurchaseLimitRecordsForLiveOrder(order);
 
         return R.ok();
     }
@@ -3817,11 +3821,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 liveOrderItem.setNum(Long.valueOf(liveOrder.getTotalNum()));
                 liveOrderItem.setJsonInfo(JSON.toJSONString(dto));
                 liveOrderItemMapper.insertLiveOrderItem(liveOrderItem);
-                
-                // 记录限购数量(订单创建成功后记录)
-                if (fsStoreProduct.getPurchaseLimit() != null && fsStoreProduct.getPurchaseLimit() > 0) {
-                    purchaseLimitService.increasePurchaseLimit(liveOrder.getProductId(), userId, purchaseNum);
-                }
+
                 
                 redisCache.deleteObject("orderKey:" + liveOrder.getOrderKey());
                 //添加支付到期时间
@@ -4059,17 +4059,6 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
      * @param liveOrder 订单
      */
     private void deletePurchaseLimitRecordsForLiveOrder(LiveOrder liveOrder) {
-        // 查询商品信息
-        FsStoreProductScrm product = fsStoreProductService.selectFsStoreProductById(liveOrder.getProductId());
-        if (product == null) {
-            return;
-        }
-        
-        // 如果商品没有设置限购,跳过
-        if (product.getPurchaseLimit() == null || product.getPurchaseLimit() <= 0) {
-            return;
-        }
-        
         // 减少限购数量
         Long userId = Long.parseLong(liveOrder.getUserId());
         Integer num = Integer.parseInt(liveOrder.getTotalNum());

+ 19 - 19
fs-service/src/main/java/com/fs/live/vo/MergedOrderVO.java

@@ -20,40 +20,39 @@ import java.util.List;
 public class MergedOrderVO implements Serializable
 {
     private static final long serialVersionUID = 1L;
-
+    @Excel(name = "订单ID")
     /** 订单ID */
     private Long id;
-
+    @Excel(name = "订单ID(直播订单使用)")
     /** 订单ID(直播订单使用) */
     private Long orderId;
-
+    @Excel(name = "直播ID")
     /** 直播ID(直播订单使用) */
     private Long liveId;
-
+    @Excel(name = "售后ID")
     /** 售后ID(直播订单使用) */
     private Long afterSalesId;
-
+    @Excel(name = "订单号")
     /** 订单号 */
     private String orderCode;
-
+    @Excel(name = "实际支付金额")
     /** 实际支付金额 */
     private BigDecimal payPrice;
-
     /** 会员等级 */
     private Integer userLevel;
-
+    @Excel(name = "实付金额")
     /** 实付金额 */
     private BigDecimal payMoney;
-
+    @Excel(name = "优惠金额")
     /** 优惠金额(直播订单使用) */
     private Integer discountMoney;
-
+    @Excel(name = "运费")
     /** 运费 */
     private BigDecimal payDelivery;
 
     /** 运费 */
     private BigDecimal payPostage;
-
+    @Excel(name = "成本价")
     /** 成本价 */
     private BigDecimal cost;
 
@@ -61,7 +60,7 @@ public class MergedOrderVO implements Serializable
     /** 订单状态 */
     @Excel(name = "订单状态",dictType="sys_live_order_status")
     private Integer status;
-
+    @Excel(name = "订单状态")
     /** 订单总价 */
     private BigDecimal totalPrice;
 
@@ -73,13 +72,13 @@ public class MergedOrderVO implements Serializable
 
     /** 商品JSON */
     private String itemJson;
-
+    @Excel(name = "物流单号")
     /** 物流单号 */
     private String deliveryId;
-
+    @Excel(name = "物流公司编码")
     /** 物流公司编码 */
     private String deliveryCode;
-
+    @Excel(name = "物流公司名称")
     /** 物流公司名称 */
     private String deliveryName;
 
@@ -97,7 +96,7 @@ public class MergedOrderVO implements Serializable
     /** 支付时间 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date payTime;
-
+    @Excel(name = "发货时间")
     /** 发货时间 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date deliverySendTime;
@@ -111,13 +110,13 @@ public class MergedOrderVO implements Serializable
     private Integer orderType;
 //    汇付商户订单号
     private String hfshh;
-
+    @Excel(name = "订单类型名称")
     /** 订单类型名称 */
     private String orderTypeName;
-
+    @Excel(name = "公司名称")
     /** 公司名称 */
     private String companyName;
-
+    @Excel(name = "销售名称")
     /** 销售名称(company_user表的user_name) */
     private String salesName;
 
@@ -167,6 +166,7 @@ public class MergedOrderVO implements Serializable
     private String productSpec;
 
     /** 商品编码 */
+    @Excel(name = "商品编码")
     private String barCode;
 
     /** 商品分类 */

+ 2 - 2
fs-service/src/main/resources/application-config-druid-bjzm.yml

@@ -10,8 +10,8 @@ logging:
 wx:
   miniapp:
     configs:
-      - appid: wxd791d5933ed42218   #北京卓美
-        secret: 3d2e220de33d67aeb2140edeec692b73 #北京卓美
+      - appid: wxe67df00c8a1e6bed   #北京卓美
+        secret: 7ded976d7aa1901cf5e73e8da70fb37d #北京卓美
         token: cbnd7lJvkripVOpyTFAna6NAWCxCrvC
         aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
         msgDataFormat: JSON

+ 1 - 1
fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml

@@ -646,7 +646,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </select>
     <select id="selectQwUserListLikeName" resultType="com.fs.qw.vo.QwOptionsVO">
         select
-        concat(qw.qw_user_name,'(',qw.id,')') as dictLabel,
+        qw.qw_user_name as dictLabel,
         qw.id as dictValue
         from qw_user qw
         <where>

+ 10 - 1
fs-service/src/main/resources/mapper/fastGpt/FastGptRoleMapper.xml

@@ -25,12 +25,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="forbidSendStart"    column="forbid_send_start"    />
         <result property="forbidSendEnd"    column="forbid_send_end"    />
         <result property="forbidStatus"    column="forbid_status"    />
+        <result property="sendCourseStatus"    column="send_course_status"    />
+        <result property="courseId"    column="course_id"    />
     </resultMap>
 
     <sql id="selectFastGptRoleVo">
         select role_id, role_name,contact_info,company_id, create_time, update_time, role_type, mode_config_json,
                mode, kf_id, kf_url, avatar, kf_media_id,reminder_words, bind_corp_id,channel_type,logistics,forbid_send_start,
-               forbid_send_end,forbid_status
+               forbid_send_end,forbid_status,send_course_status,course_id
         from fastgpt_role
     </sql>
 
@@ -85,6 +87,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             role_id as roleId,role_name as roleName,mode_config_json as appKey
         from fastgpt_role
     </select>
+    <select id="selectAllCourseList" resultType="com.fs.course.domain.FsUserCourseVideo">
+        SELECT f2.video_id,f2.title FROM `fs_user_course` f1 left join fs_user_course_video f2 on f1.course_id = f2.course_id
+        where find_in_set(#{companyId},f1.company_ids)
+        ORDER BY f1.course_id,f2.video_id
+    </select>
 
 
     <insert id="insertFastGptRole" parameterType="FastGptRole" useGeneratedKeys="true" keyProperty="roleId">
@@ -143,6 +150,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="channelType != null">channel_type = #{channelType},</if>
             <if test="logistics != null">logistics = #{logistics},</if>
             <if test="forbidStatus != null">forbid_status = #{forbidStatus},</if>
+            <if test="sendCourseStatus != null">send_course_status = #{sendCourseStatus},</if>
+            <if test="courseId != null">course_id = #{courseId},</if>
         </trim>
         where role_id = #{roleId}
     </update>

+ 39 - 0
fs-service/src/main/resources/mapper/his/MiniProgramAgreementMapper.xml

@@ -0,0 +1,39 @@
+<?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.fs.his.mapper.MiniProgramAgreementMapper">
+
+    <resultMap id="BaseResultMap" type="com.fs.his.domain.MiniProgramAgreement">
+            <id property="id" column="id" />
+            <result property="appId" column="app_id" />
+            <result property="agreementType" column="agreement_type" />
+            <result property="agreementContent" column="agreement_content" />
+            <result property="isActive" column="is_active" />
+            <result property="createTime" column="create_time" />
+            <result property="updateTime" column="update_time" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,app_id,agreement_type,agreement_content,is_active,create_time,
+        update_time
+    </sql>
+
+
+    <insert id="batchUpsertAgreements" parameterType="java.util.List">
+        INSERT INTO fs_mini_program_agreement (
+        app_id,
+        agreement_type,
+        agreement_content
+        ) VALUES
+        <foreach collection="agreements" item="item" separator=",">
+            (
+            #{item.appId},
+            #{item.agreementType},
+            #{item.agreementContent}
+            )
+        </foreach>
+        ON DUPLICATE KEY UPDATE
+        agreement_content = VALUES(agreement_content)
+    </insert>
+</mapper>

+ 12 - 2
fs-service/src/main/resources/mapper/hisStore/MergedOrderMapper.xml

@@ -46,7 +46,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         fss.store_id as storeId,
         fss.store_name as storeName,
         fspcs.cate_name as cateName,
-        GROUP_CONCAT(JSON_UNQUOTE(JSON_EXTRACT(o.item_json, '$.barCode')) SEPARATOR ',') AS barCode,
+        GROUP_CONCAT(JSON_UNQUOTE(JSON_EXTRACT(item_latest.json_info, '$.barCode')) SEPARATOR ',') AS barCode,
 
       c.company_name,
       cu.user_name AS sales_name,
@@ -82,6 +82,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           <if test="maps.status != null and maps.status != ''">
             AND o.status = #{maps.status}
           </if>
+        <if test="maps.userId != null and maps.userId != ''">
+            AND o.company_user_id = #{maps.userId}
+        </if>
+
         <if test="maps.productId != null and maps.productId != ''">
             AND fspc.product_id = #{maps.productId}
         </if>
@@ -191,7 +195,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     fss.store_id as storeId,
     fss.store_name as storeName,
     fspcs.cate_name as cateName,
-    GROUP_CONCAT(JSON_UNQUOTE(JSON_EXTRACT(o.item_json, '$.barCode')) SEPARATOR ',') AS barCode,
+    GROUP_CONCAT(JSON_UNQUOTE(JSON_EXTRACT(item_latest.json_info, '$.barCode')) SEPARATOR ',') AS barCode,
 
       c.company_name,
       cu.user_name AS sales_name,
@@ -227,6 +231,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           <if test="maps.status != null and maps.status != ''">
             AND o.status = #{maps.status}
           </if>
+        <if test="maps.userId != null and maps.userId != ''">
+            AND o.company_user_id = #{maps.userId}
+        </if>
         <if test="maps.productId != null and maps.productId != ''">
             AND fspc.product_id = #{maps.productId}
         </if>
@@ -375,6 +382,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           <if test="maps.status != null and maps.status != ''">
             AND o.status = #{maps.status}
           </if>
+        <if test="maps.userId != null and maps.userId != ''">
+            AND o.company_user_id = #{maps.userId}
+        </if>
         <if test="maps.productId != null and maps.productId != ''">
             AND fspc.product_id = #{maps.productId}
         </if>

+ 89 - 0
fs-user-app/src/main/java/com/fs/app/controller/H5Controller.java

@@ -1,14 +1,22 @@
 package com.fs.app.controller;
 
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.common.core.domain.R;
+import com.fs.course.enums.MiniProgramAgreementEnum;
 import com.fs.his.config.AgreementConfig;
+import com.fs.his.domain.MiniProgramAgreement;
+import com.fs.his.service.MiniProgramAgreementService;
 import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.servlet.ModelAndView;
 
+import java.util.Objects;
+
 @Controller
 @RequestMapping(value="/web")
 public class H5Controller
@@ -17,6 +25,9 @@ public class H5Controller
     @Autowired
     private ISysConfigService configService;
 
+    @Autowired
+    private MiniProgramAgreementService miniProgramAgreementService;
+
 
     @GetMapping("/userAgreement")
     public ModelAndView userAgreement( )
@@ -87,4 +98,82 @@ public class H5Controller
     }
 
 
+    /**
+     * @Description: 协议接口
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2026/1/9 11:31
+     */
+    @GetMapping("/getAgreementConfig")
+    public ModelAndView getAgreementConfig(@RequestParam("appId") String appId,
+                                           @RequestParam("agreementType") String agreementType) {
+        ModelAndView mv = new ModelAndView();
+
+        // 根据appId和code查询小程序用户信息
+        MiniProgramAgreement agreement = miniProgramAgreementService.getOne(
+                new QueryWrapper<MiniProgramAgreement>()
+                        .eq("app_id", appId)
+                        .eq("agreement_type", agreementType)
+        );
+
+        if (agreement != null) {
+            mv.addObject("agreementBody", agreement.getAgreementContent());
+            mv.addObject("agreementTitle", MiniProgramAgreementEnum.getMessage(agreementType));
+            mv.setViewName("commonAgreement");
+            return mv;
+        } else {// 老配置 后期不用了
+            String json = configService.selectConfigByKey("his.agreementConfig");
+            AgreementConfig config = JSONUtil.toBean(json, AgreementConfig.class);
+            MiniProgramAgreementEnum agreementEnum = MiniProgramAgreementEnum.getEnum(agreementType);
+
+            // 修复方案
+            if (agreementEnum == null) {
+                mv.addObject("agreementBody", "<div class=\"error-message\"><h3>暂未找到该协议内容</h3><p>请确认协议类型是否正确,或联系管理员配置相关协议内容。</p></div>");
+                mv.addObject("agreementTitle", agreementType);
+
+                mv.setViewName("commonAgreement");
+                return mv;
+            }
+
+
+            String data = null;
+            switch (agreementEnum) {
+                case USER_REGISTER:
+                    data = config.getUserRegister();
+                    break;
+                case USER_PRIVACY:
+                    data = config.getUserPrivacy();
+                    break;
+                case USER_HEALTH:
+                    data = config.getUserHealth();
+                    break;
+                case VIP_SERVICE:
+                    data = config.getVipService();
+                    break;
+                case VIP_AUTOMATIC_SERVICE:
+                    data = config.getVipAutomaticService();
+                    break;
+                case USER_REMOVE_SERVICE:
+                    data = config.getUserRemoveService();
+                    break;
+                case DOCTOR_REGISTER:
+                    data = config.getDoctorRegister();
+                    break;
+                case DOCTOR_FILING:
+                    data = config.getDoctorFiling();
+                    break;
+                default:
+                    agreementType="notFound";
+                    data="<div class=\"error-message\"><h3>暂未找到该协议内容</h3><p>请确认协议类型是否正确,或联系管理员配置相关协议内容。</p></div>";
+                    break;
+            }
+
+            mv.addObject("agreementBody", data);
+            mv.addObject("agreementTitle", MiniProgramAgreementEnum.getMessage(agreementType));
+            mv.setViewName("commonAgreement");
+            return mv;
+        }
+    }
+
 }

+ 21 - 0
fs-user-app/src/main/java/com/fs/app/controller/live/LiveController.java

@@ -15,10 +15,19 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.bean.BeanUtils;
 import com.fs.common.utils.http.HttpUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyMoneyLogs;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyMapper;
+import com.fs.company.mapper.CompanyMoneyLogsMapper;
 import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.hisStore.domain.FsStoreOrderScrm;
+import com.fs.hisStore.service.IFsStoreOrderScrmService;
+import com.fs.live.domain.LiveOrder;
+import java.math.BigDecimal;
+import java.util.Date;
 import com.fs.erp.domain.ErpDeliverys;
 import com.fs.erp.domain.ErpOrderQuery;
 import com.fs.erp.dto.ErpOrderQueryRequert;
@@ -90,6 +99,16 @@ public class LiveController extends AppBaseController {
     private com.fs.live.mapper.LiveUserFirstEntryMapper liveUserFirstEntryMapper;
     @Autowired
     private com.fs.live.mapper.LiveOrderMapper liveOrderMapper;
+    @Autowired
+    private ICompanyService companyService;
+    @Autowired
+    private ICompanyMoneyLogsService companyMoneyLogsService;
+    @Autowired
+    private CompanyMoneyLogsMapper companyMoneyLogsMapper;
+    @Autowired
+    private CompanyMapper companyMapper;
+    @Autowired
+    private IFsStoreOrderScrmService fsStoreOrderScrmService;
 
 	/**
 	 * 查询未结束直播间(销售专用)
@@ -393,4 +412,6 @@ public class LiveController extends AppBaseController {
 	}
 
 
+
+
 }

+ 249 - 0
fs-user-app/src/main/java/com/fs/app/controller/store/ProductScrmController.java

@@ -14,6 +14,11 @@ import com.fs.hisStore.vo.FsStoreCartVO;
 import com.fs.hisStore.vo.FsStoreProductAttrValueQueryVO;
 import com.fs.hisStore.vo.FsStoreProductListQueryVO;
 import com.fs.hisStore.vo.FsStoreProductQueryVO;
+import com.fs.hisStore.param.CartPurchaseLimitCheckParam;
+import com.fs.hisStore.domain.FsStoreOrderItemScrm;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -57,6 +62,9 @@ public class ProductScrmController extends AppBaseController {
 
     @Autowired
     private IFsStoreProductPurchaseLimitScrmService purchaseLimitService;
+    
+    @Autowired
+    private IFsStoreOrderItemScrmService orderItemService;
     /**
      * 获取用户信息
      * @param storeId
@@ -239,6 +247,50 @@ public class ProductScrmController extends AppBaseController {
                 .put("purchasedNum", purchasedNum); // 已购买数量
     }
 
+    @Login
+    @ApiOperation("检查商品限购")
+    @GetMapping("/checkPurchaseLimit")
+    public R checkPurchaseLimit(@RequestParam(value="productId") Long productId){
+        try {
+            // 查询商品信息
+            FsStoreProductScrm product = productService.selectFsStoreProductById(productId);
+            if(product == null){
+                return R.error("商品不存在");
+            }
+            
+            // 检查是否限购
+            if(product.getPurchaseLimit() == null || product.getPurchaseLimit() <= 0){
+                // 商品不限购,直接返回成功
+                return R.ok();
+            }
+            
+            // 商品有限购,查询用户已购买数量
+            String userId = getUserId();
+            if(userId == null){
+                return R.error("用户未登录");
+            }
+            
+            FsStoreProductPurchaseLimitScrm purchaseLimit = purchaseLimitService.selectByProductIdAndUserId(
+                    productId, Long.parseLong(userId));
+            int purchasedNum = 0;
+            if (purchaseLimit != null) {
+                purchasedNum = purchaseLimit.getNum();
+            }
+            
+            // 计算剩余可购买数量
+            int remainingPurchaseLimit = product.getPurchaseLimit() - purchasedNum;
+            if (remainingPurchaseLimit <= 0) {
+                // 剩余可购买数量不足
+                return R.error("该商品限购" + product.getPurchaseLimit() + "件,目前剩余可购买数量不足");
+            }
+            
+            // 剩余可购买数量充足
+            return R.ok();
+        } catch (Exception e){
+            return R.error("检查限购失败:" + e.getMessage());
+        }
+    }
+
     @Login
     @ApiOperation("添加购物车")
     @PostMapping("/addCart")
@@ -266,6 +318,7 @@ public class ProductScrmController extends AppBaseController {
     }
 
 
+
     @Login
     @ApiOperation("获取商品购物车数量")
     @GetMapping("/getCartCount")
@@ -314,6 +367,202 @@ public class ProductScrmController extends AppBaseController {
         return R.ok().put("data",listPageInfo);
     }
 
+    @Login
+    @ApiOperation("购物车结算前批量校验限购")
+    @PostMapping("/checkCartPurchaseLimit")
+    public R checkCartPurchaseLimit(@Validated @RequestBody CartPurchaseLimitCheckParam param) {
+        try {
+            String userId = getUserId();
+            if (userId == null) {
+                return R.error("用户未登录");
+            }
+            
+            if (param.getProducts() == null || param.getProducts().isEmpty()) {
+                return R.error("商品列表不能为空");
+            }
+            
+            Long userIdLong = Long.parseLong(userId);
+            List<String> errorMessages = new ArrayList<>();
+            
+            // 按productId分组,累加同一商品不同规格的数量
+            Map<Long, Integer> productNumMap = new HashMap<>();
+            Map<Long, String> productNameMap = new HashMap<>();
+            
+            for (CartPurchaseLimitCheckParam.ProductItem item : param.getProducts()) {
+                Long productId = item.getProductId();
+                Integer num = item.getNum();
+                
+                if (productId == null || num == null || num <= 0) {
+                    continue;
+                }
+                
+                // 累加同一商品的数量(不同规格算在一起)
+                productNumMap.put(productId, productNumMap.getOrDefault(productId, 0) + num);
+                
+                // 保存商品名称(用于错误提示)
+                if (!productNameMap.containsKey(productId)) {
+                    FsStoreProductScrm product = productService.selectFsStoreProductById(productId);
+                    if (product != null && product.getProductName() != null) {
+                        productNameMap.put(productId, product.getProductName());
+                    }
+                }
+            }
+            
+            // 遍历分组后的商品,检查限购
+            for (Map.Entry<Long, Integer> entry : productNumMap.entrySet()) {
+                Long productId = entry.getKey();
+                Integer totalNum = entry.getValue(); // 同一商品所有规格的总数量
+                
+                // 查询商品信息
+                FsStoreProductScrm product = productService.selectFsStoreProductById(productId);
+                if (product == null) {
+                    continue;
+                }
+                
+                // 检查是否限购
+                if (product.getPurchaseLimit() == null || product.getPurchaseLimit() <= 0) {
+                    // 商品不限购,跳过
+                    continue;
+                }
+                
+                // 商品有限购,查询用户已购买数量
+                FsStoreProductPurchaseLimitScrm purchaseLimit = purchaseLimitService.selectByProductIdAndUserId(
+                        productId, userIdLong);
+                int purchasedNum = 0;
+                if (purchaseLimit != null) {
+                    purchasedNum = purchaseLimit.getNum();
+                }
+                
+                // 计算剩余可购买数量
+                int remainingPurchaseLimit = product.getPurchaseLimit() - purchasedNum;
+                if (remainingPurchaseLimit < totalNum) {
+                    // 超过限购,添加错误信息
+                    String productName = productNameMap.getOrDefault(productId, 
+                            product.getProductName() != null ? product.getProductName() : "商品ID:" + productId);
+                    String errorMsg = String.format("商品【%s】限购%d件,您已购买%d件,本次购买%d件,超出限购数量",
+                            productName,
+                            product.getPurchaseLimit(),
+                            purchasedNum,
+                            totalNum);
+                    errorMessages.add(errorMsg);
+                }
+            }
+            
+            // 如果有错误信息,拼接并返回
+            if (!errorMessages.isEmpty()) {
+                String errorMsg = String.join(";", errorMessages);
+                return R.error(errorMsg);
+            }
+            
+            // 所有商品都通过限购检查
+            return R.ok();
+        } catch (Exception e) {
+            return R.error("检查限购失败:" + e.getMessage());
+        }
+    }
 
+    @Login
+    @ApiOperation("订单支付前校验限购(商城订单)")
+    @GetMapping("/checkOrderPurchaseLimit")
+    public R checkOrderPurchaseLimit(@RequestParam(value = "orderCode") String orderCode) {
+        try {
+            String userId = getUserId();
+            if (userId == null) {
+                return R.error("用户未登录");
+            }
+            
+            if (orderCode == null || orderCode.trim().isEmpty()) {
+                return R.error("订单号不能为空");
+            }
+            
+            Long userIdLong = Long.parseLong(userId);
+            
+            // 根据orderCode查询订单商品
+            FsStoreOrderItemScrm queryParam = new FsStoreOrderItemScrm();
+            queryParam.setOrderCode(orderCode);
+            List<FsStoreOrderItemScrm> orderItems = orderItemService.selectFsStoreOrderItemList(queryParam);
+            
+            if (orderItems == null || orderItems.isEmpty()) {
+                return R.error("订单不存在或订单中没有商品");
+            }
+            
+            List<String> errorMessages = new ArrayList<>();
+            
+            // 按productId分组,累加同一商品不同规格的数量
+            Map<Long, Integer> productNumMap = new HashMap<>();
+            Map<Long, String> productNameMap = new HashMap<>();
+            
+            for (FsStoreOrderItemScrm orderItem : orderItems) {
+                Long productId = orderItem.getProductId();
+                Integer num = orderItem.getNum();
+                
+                if (productId == null || num == null || num <= 0) {
+                    continue;
+                }
+                
+                // 累加同一商品的数量(不同规格算在一起)
+                productNumMap.put(productId, productNumMap.getOrDefault(productId, 0) + num);
+                
+                // 保存商品名称(用于错误提示)
+                if (!productNameMap.containsKey(productId)) {
+                    FsStoreProductScrm product = productService.selectFsStoreProductById(productId);
+                    if (product != null && product.getProductName() != null) {
+                        productNameMap.put(productId, product.getProductName());
+                    }
+                }
+            }
+            
+            // 遍历分组后的商品,检查限购
+            for (Map.Entry<Long, Integer> entry : productNumMap.entrySet()) {
+                Long productId = entry.getKey();
+                Integer totalNum = entry.getValue(); // 同一商品所有规格的总数量
+                
+                // 查询商品信息
+                FsStoreProductScrm product = productService.selectFsStoreProductById(productId);
+                if (product == null) {
+                    continue;
+                }
+                
+                // 检查是否限购
+                if (product.getPurchaseLimit() == null || product.getPurchaseLimit() <= 0) {
+                    // 商品不限购,跳过
+                    continue;
+                }
+                
+                // 商品有限购,查询用户已购买数量
+                FsStoreProductPurchaseLimitScrm purchaseLimit = purchaseLimitService.selectByProductIdAndUserId(
+                        productId, userIdLong);
+                int purchasedNum = 0;
+                if (purchaseLimit != null) {
+                    purchasedNum = purchaseLimit.getNum();
+                }
+                
+                // 计算剩余可购买数量(订单中的数量也要计算在内)
+                int remainingPurchaseLimit = product.getPurchaseLimit() - purchasedNum;
+                if (remainingPurchaseLimit < totalNum) {
+                    // 超过限购,添加错误信息
+                    String productName = productNameMap.getOrDefault(productId, 
+                            product.getProductName() != null ? product.getProductName() : "商品ID:" + productId);
+                    String errorMsg = String.format("商品【%s】限购%d件,您已购买%d件,订单中购买%d件,超出限购数量",
+                            productName,
+                            product.getPurchaseLimit(),
+                            purchasedNum,
+                            totalNum);
+                    errorMessages.add(errorMsg);
+                }
+            }
+            
+            // 如果有错误信息,拼接并返回
+            if (!errorMessages.isEmpty()) {
+                String errorMsg = String.join(";", errorMessages);
+                return R.error(errorMsg);
+            }
+            
+            // 所有商品都通过限购检查
+            return R.ok();
+        } catch (Exception e) {
+            return R.error("检查限购失败:" + e.getMessage());
+        }
+    }
 
 }

+ 21 - 0
fs-user-app/src/main/resources/templates/commonAgreement.html

@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <title  th:text="${agreementTitle}"></title>
+    <link  rel="stylesheet"/>
+    <style>
+        body{
+            background-color:#F8F8F8;
+        }
+    </style>
+<body>
+<div th:utext="${agreementBody}" ></div>
+<script th:inline="javascript">
+
+</script>
+
+</body>
+</html>