Explorar el Código

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java

caoliqin hace 2 semanas
padre
commit
733c629d1a
Se han modificado 59 ficheros con 2923 adiciones y 199 borrados
  1. 111 0
      fs-admin/src/main/java/com/fs/his/controller/FsCourseCouponController.java
  2. 103 0
      fs-admin/src/main/java/com/fs/his/controller/FsCourseCouponUserController.java
  3. 28 0
      fs-admin/src/main/java/com/fs/his/task/userIntegralTask.java
  4. 43 2
      fs-admin/src/main/java/com/fs/third/controller/WeizouController.java
  5. 12 4
      fs-company-app/src/main/java/com/fs/app/controller/StoreProductController.java
  6. 7 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticController.java
  7. 4 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  8. 12 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  9. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCommentMapper.java
  10. 1 1
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseCommentService.java
  11. 2 2
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseCommentServiceImpl.java
  12. 78 0
      fs-service/src/main/java/com/fs/enums/WeizouOrderExpressEnum.java
  13. 2 0
      fs-service/src/main/java/com/fs/his/config/FsSysConfig.java
  14. 58 0
      fs-service/src/main/java/com/fs/his/domain/FsCourseCoupon.java
  15. 47 0
      fs-service/src/main/java/com/fs/his/domain/FsCourseCouponUser.java
  16. 40 0
      fs-service/src/main/java/com/fs/his/domain/FsIntegralCount.java
  17. 61 0
      fs-service/src/main/java/com/fs/his/mapper/FsCourseCouponMapper.java
  18. 61 0
      fs-service/src/main/java/com/fs/his/mapper/FsCourseCouponUserMapper.java
  19. 63 0
      fs-service/src/main/java/com/fs/his/mapper/FsIntegralCountMapper.java
  20. 61 0
      fs-service/src/main/java/com/fs/his/service/IFsCourseCouponService.java
  21. 61 0
      fs-service/src/main/java/com/fs/his/service/IFsCourseCouponUserService.java
  22. 63 0
      fs-service/src/main/java/com/fs/his/service/IFsIntegralCountService.java
  23. 1 1
      fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java
  24. 95 0
      fs-service/src/main/java/com/fs/his/service/impl/FsCourseCouponServiceImpl.java
  25. 94 0
      fs-service/src/main/java/com/fs/his/service/impl/FsCourseCouponUserServiceImpl.java
  26. 94 0
      fs-service/src/main/java/com/fs/his/service/impl/FsIntegralCountServiceImpl.java
  27. 291 71
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  28. 5 0
      fs-service/src/main/java/com/fs/hisStore/config/StoreConfig.java
  29. 4 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreOrderScrm.java
  30. 17 0
      fs-service/src/main/java/com/fs/hisStore/dto/ExpressCompanyDTO.java
  31. 40 0
      fs-service/src/main/java/com/fs/hisStore/dto/ExpressCompanyInfoDTO.java
  32. 3 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java
  33. 7 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsExpressScrmService.java
  34. 3 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java
  35. 29 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsExpressScrmServiceImpl.java
  36. 2 2
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java
  37. 317 37
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  38. 1 0
      fs-service/src/main/resources/application-config-dev-jnlzjk.yml
  39. 1 0
      fs-service/src/main/resources/application-config-druid-jnlzjk.yml
  40. 112 0
      fs-service/src/main/resources/application-config-druid-sxsm.yml
  41. 10 4
      fs-service/src/main/resources/application-config-druid-yxj.yml
  42. 2 2
      fs-service/src/main/resources/application-config-zlwh.yml
  43. 9 9
      fs-service/src/main/resources/application-druid-bjzm.yml
  44. 3 3
      fs-service/src/main/resources/application-druid-jnlzjk.yml
  45. 221 0
      fs-service/src/main/resources/application-druid-sxsm.yml
  46. 174 0
      fs-service/src/main/resources/application-druid-yxj-test.yml
  47. 2 1
      fs-service/src/main/resources/application-druid-yxj.yml
  48. 2 0
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticMapper.xml
  49. 1 1
      fs-service/src/main/resources/mapper/course/FsUserCourseCommentMapper.xml
  50. 99 0
      fs-service/src/main/resources/mapper/his/FsCourseCouponMapper.xml
  51. 84 0
      fs-service/src/main/resources/mapper/his/FsCourseCouponUserMapper.xml
  52. 77 0
      fs-service/src/main/resources/mapper/his/FsIntegralCountMapper.xml
  53. 1 1
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml
  54. 1 0
      fs-service/src/main/resources/mapper/hisStore/FsStoreProductScrmMapper.xml
  55. 77 7
      fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java
  56. 2 2
      fs-user-app/src/main/java/com/fs/app/controller/CourseCommentController.java
  57. 10 44
      fs-user-app/src/main/java/com/fs/app/controller/live/LiveCartController.java
  58. 2 2
      fs-user-app/src/main/java/com/fs/app/controller/store/CourseCommentScrmController.java
  59. 111 0
      fs-user-app/src/main/java/com/fs/app/controller/store/StoreProductController.java

+ 111 - 0
fs-admin/src/main/java/com/fs/his/controller/FsCourseCouponController.java

@@ -0,0 +1,111 @@
+package com.fs.his.controller;
+
+import java.util.List;
+
+import com.fs.common.exception.CustomException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.his.domain.FsCourseCoupon;
+import com.fs.his.service.IFsCourseCouponService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 课程优惠券Controller
+ * 
+ * @author fs
+ * @date 2026-05-13
+ */
+@RestController
+@RequestMapping("/his/courserCoupon")
+public class FsCourseCouponController extends BaseController
+{
+    @Autowired
+    private IFsCourseCouponService fsCourseCouponService;
+
+    /**
+     * 查询课程优惠券列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:courserCoupon:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseCoupon fsCourseCoupon)
+    {
+        startPage();
+        List<FsCourseCoupon> list = fsCourseCouponService.selectFsCourseCouponList(fsCourseCoupon);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出课程优惠券列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:courserCoupon:export')")
+    @Log(title = "课程优惠券", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseCoupon fsCourseCoupon)
+    {
+        List<FsCourseCoupon> list = fsCourseCouponService.selectFsCourseCouponList(fsCourseCoupon);
+        ExcelUtil<FsCourseCoupon> util = new ExcelUtil<FsCourseCoupon>(FsCourseCoupon.class);
+        return util.exportExcel(list, "课程优惠券数据");
+    }
+
+    /**
+     * 获取课程优惠券详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:courserCoupon:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsCourseCouponService.selectFsCourseCouponById(id));
+    }
+
+    /**
+     * 新增课程优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('his:courserCoupon:add')")
+    @Log(title = "课程优惠券", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseCoupon fsCourseCoupon)
+    {
+        return toAjax(fsCourseCouponService.insertFsCourseCoupon(fsCourseCoupon));
+    }
+
+    /**
+     * 修改课程优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('his:courserCoupon:edit')")
+    @Log(title = "课程优惠券", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseCoupon fsCourseCoupon)
+    {
+        FsCourseCoupon c = fsCourseCouponService.selectFsCourseCouponById(fsCourseCoupon.getId());
+        long l = c.getRemainNumber() + fsCourseCoupon.getNumber() - c.getNumber();
+        if (l < 0) {
+            throw new CustomException("剩余卷不足");
+        }
+        fsCourseCoupon.setRemainNumber(l);
+        return toAjax(fsCourseCouponService.updateFsCourseCoupon(fsCourseCoupon));
+    }
+
+    /**
+     * 删除课程优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('his:courserCoupon:remove')")
+    @Log(title = "课程优惠券", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsCourseCouponService.deleteFsCourseCouponByIds(ids));
+    }
+}

+ 103 - 0
fs-admin/src/main/java/com/fs/his/controller/FsCourseCouponUserController.java

@@ -0,0 +1,103 @@
+package com.fs.his.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.his.domain.FsCourseCouponUser;
+import com.fs.his.service.IFsCourseCouponUserService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 用户看课优惠券Controller
+ * 
+ * @author fs
+ * @date 2026-05-13
+ */
+@RestController
+@RequestMapping("/his/courseCouponUser")
+public class FsCourseCouponUserController extends BaseController
+{
+    @Autowired
+    private IFsCourseCouponUserService fsCourseCouponUserService;
+
+    /**
+     * 查询用户看课优惠券列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:courseCouponUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseCouponUser fsCourseCouponUser)
+    {
+        startPage();
+        List<FsCourseCouponUser> list = fsCourseCouponUserService.selectFsCourseCouponUserList(fsCourseCouponUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户看课优惠券列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:courseCouponUser:export')")
+    @Log(title = "用户看课优惠券", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseCouponUser fsCourseCouponUser)
+    {
+        List<FsCourseCouponUser> list = fsCourseCouponUserService.selectFsCourseCouponUserList(fsCourseCouponUser);
+        ExcelUtil<FsCourseCouponUser> util = new ExcelUtil<FsCourseCouponUser>(FsCourseCouponUser.class);
+        return util.exportExcel(list, "用户看课优惠券数据");
+    }
+
+    /**
+     * 获取用户看课优惠券详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:courseCouponUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsCourseCouponUserService.selectFsCourseCouponUserById(id));
+    }
+
+    /**
+     * 新增用户看课优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('his:courseCouponUser:add')")
+    @Log(title = "用户看课优惠券", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseCouponUser fsCourseCouponUser)
+    {
+        return toAjax(fsCourseCouponUserService.insertFsCourseCouponUser(fsCourseCouponUser));
+    }
+
+    /**
+     * 修改用户看课优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('his:courseCouponUser:edit')")
+    @Log(title = "用户看课优惠券", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseCouponUser fsCourseCouponUser)
+    {
+        return toAjax(fsCourseCouponUserService.updateFsCourseCouponUser(fsCourseCouponUser));
+    }
+
+    /**
+     * 删除用户看课优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('his:courseCouponUser:remove')")
+    @Log(title = "用户看课优惠券", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsCourseCouponUserService.deleteFsCourseCouponUserByIds(ids));
+    }
+}

+ 28 - 0
fs-admin/src/main/java/com/fs/his/task/userIntegralTask.java

@@ -0,0 +1,28 @@
+package com.fs.his.task;
+
+
+import com.fs.his.service.IFsIntegralCountService;
+import com.fs.his.service.IFsUserIntegralLogsService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component("userIntegralTask")
+@AllArgsConstructor
+public class userIntegralTask {
+
+    @Autowired
+    private IFsUserIntegralLogsService integralLogsService;
+
+    @Autowired
+    private IFsIntegralCountService integralCountService;
+    /**
+    * 用户积分表 每日消耗统计 除掉看课获取的
+    */
+    public void UserIntegralCount(){
+
+    }
+
+}

+ 43 - 2
fs-admin/src/main/java/com/fs/third/controller/WeizouController.java

@@ -34,7 +34,7 @@ public class WeizouController extends BaseController {
             return error("参数异常请核验参数");
         }
         fsStoreOrder.setOrderId(Long.valueOf((String) map.get("orderCode")));
-        fsStoreOrder.setOperator("微走发货同步");
+        fsStoreOrder.setOperator("-1");
 // 校验物流单号
         if (map.get("deliverySn") == null) {
             return error("参数异常请核验参数:deliverySn不能为空");
@@ -50,7 +50,48 @@ public class WeizouController extends BaseController {
             return error("参数异常请核验参数:deliveryName不能为空");
         }
         fsStoreOrder.setDeliveryName((String) map.get("deliveryName"));
+        return toAjax(fsStoreOrderService.sendGoodsWeizou(fsStoreOrder));
+    }
 
-        return toAjax(fsStoreOrderService.sendGoodsWeizou(fsStoreOrder, "微走发货同步"));
+    /**
+     * 更新快递订单
+     * @param map
+     * @return
+     */
+    @PostMapping("/cancelThirdParty")
+    public AjaxResult cancelThirdParty(@RequestBody Map map) {
+        String thirdPartySecret = (String) map.get("thirdPartySecret");
+        String s = decryptPhone(thirdPartySecret);
+        if (!s.equals("weizou_send_goods_call_back")) {
+            return error("认证失败,请核验参数");
+        }
+        FsStoreOrder fsStoreOrder = new FsStoreOrder();
+        if (map.get("orderCode") == null) {
+            return error("参数异常请核验参数");
+        }
+        fsStoreOrder.setOrderId(Long.valueOf((String) map.get("orderCode")));
+        //取消订单
+        if (map.get("operation") == null)return error("参数异常请核验参数:operator不能为空");
+        fsStoreOrder.setOperator((String) map.get("operation"));
+        return toAjax(fsStoreOrderService.sendGoodsWeizou(fsStoreOrder));
     }
+//    @PostMapping("/updateOrderLogisticsStatus")
+//    public AjaxResult updateOrderLogisticsStatus(@RequestBody Map map) {
+//        String thirdPartySecret = (String) map.get("thirdPartySecret");
+//        String s = decryptPhone(thirdPartySecret);
+//        if (!s.equals("weizou_send_goods_call_back")) {
+//            return error("认证失败,请核验参数");
+//        }
+//        FsStoreOrder fsStoreOrder = new FsStoreOrder();
+//        if (map.get("orderCode") == null) {
+//            return error("参数异常请核验参数");
+//        }
+//        fsStoreOrder.setOrderId(Long.valueOf((String) map.get("orderCode")));
+//        if (map.get("operation") == null)return error("参数异常请核验参数:operator不能为空");
+//        fsStoreOrder.setOperator((String) map.get("operation"));
+////        if (map.get("status") == null)return error("参数异常请核验参数:status不能为空");
+////        fsStoreOrder.setStatus((Integer) map.get("status"));
+//
+//        return toAjax(fsStoreOrderService.sendGoodsWeizou(fsStoreOrder, "微走更新物流状态"));
+//    }
 }

+ 12 - 4
fs-company-app/src/main/java/com/fs/app/controller/StoreProductController.java

@@ -3,8 +3,11 @@ package com.fs.app.controller;
 import com.fs.app.annotation.Login;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.StringUtils;
+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.service.IFsStoreProductAttrScrmService;
 import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
 import com.fs.hisStore.service.IFsStoreProductScrmService;
 import com.fs.hisStore.vo.FsStoreProductListVO;
@@ -32,6 +35,9 @@ public class StoreProductController extends AppBaseController {
     @Autowired
     private IFsStoreProductAttrValueScrmService attrValueService;
 
+    @Autowired
+    private IFsStoreProductAttrScrmService attrService;
+
     /**
      * 查询本公司下的商城产品列表
      */
@@ -77,10 +83,12 @@ public class StoreProductController extends AppBaseController {
             return R.error("无权查看该商品");
         }
         // 查询商品规格属性值
-        FsStoreProductAttrValueScrm attrQuery = new FsStoreProductAttrValueScrm();
-        attrQuery.setProductId(productId);
-        List<FsStoreProductAttrValueScrm> values = attrValueService.selectFsStoreProductAttrValueList(attrQuery);
-        return R.ok().put("product", product).put("values", values);
+        List<FsStoreProductAttrScrm> productAttr=attrService.selectFsStoreProductAttrByProductId(product.getProductId());
+        List<FsStoreProductAttrValueScrm> productValues=attrValueService.selectFsStoreProductAttrValueByProductId(product.getProductId());
+
+        return R.ok().put("product", product)
+                .put("productAttr",productAttr)
+                .put("productValues",productValues);
     }
 
     /**

+ 7 - 1
fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticController.java

@@ -311,7 +311,13 @@ public class CompanyVoiceRoboticController extends BaseController
      */
 	@GetMapping("/companyUserList")
     public R qwUserList(){
-        return R.ok().put("data", companyVoiceRoboticService.qwUserListCompany(new CompanyVoiceRobotic()));
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long companyId = loginUser.getCompany().getCompanyId();
+        Long userId = loginUser.getUser().getUserId();
+        CompanyVoiceRobotic robotic = new CompanyVoiceRobotic();
+        robotic.setCompanyId(companyId);
+        robotic.setCompanyUserId(userId);
+        return R.ok().put("data", companyVoiceRoboticService.qwUserListCompany(robotic));
     }
 
     /**

+ 4 - 1
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -742,11 +742,14 @@ public class CompanyServiceImpl implements ICompanyService
                 } else {
                     tuiMoney = order.getPayPrice();
                 }
+                if (Boolean.TRUE.equals(order.getNoCommission())) {
+                    tuiMoney = BigDecimal.ZERO;
+                }
                 company.setMoney(company.getMoney().add(tuiMoney));
                 companyMapper.updateCompany(company);
                 CompanyMoneyLogs log=new CompanyMoneyLogs();
                 log.setCompanyId(company.getCompanyId());
-                log.setRemark("佣金入账");
+                log.setRemark(Boolean.TRUE.equals(order.getNoCommission()) ? "佣金入账(产品不分润)" : "佣金入账");
                 log.setMoney(tuiMoney);
                 log.setLogsType(3);
                 log.setBalance(company.getMoney());

+ 12 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -931,4 +931,16 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
             "    GROUP BY user_id\n" +
             "  )")
     List<Long> selectWatchLogOutdatedInfo();
+
+    /**
+     * 查询用户最近一次看课记录(看课时长>0,按创建时间倒序取第一条)
+     * 包含手动发课(send_type=1)和SOP发课(send_type=2)
+     */
+    @Select("SELECT * FROM fs_course_watch_log " +
+            "WHERE user_id = #{userId} " +
+            "AND duration > 0 " +
+            "AND (send_type = 1 OR send_type = 2) " +
+            "ORDER BY create_time DESC " +
+            "LIMIT 1")
+    FsCourseWatchLog selectLatestWatchLogByUserId(@Param("userId") Long userId);
 }

+ 1 - 1
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCommentMapper.java

@@ -154,7 +154,7 @@ public interface FsUserCourseCommentMapper
             "</script>"})
     List<FsUserCourseCommentListUVO> selectFsUserCourseCommentListUVOAll(FsUserCourseCommentUParam param);
 
-    List<FsUserCourseComment> selectFsUserCourseCommentListByTypeAndCourseId(@Param("type") int type,@Param("courseId") Long courseId);
+    List<FsUserCourseComment> selectFsUserCourseCommentListByTypeAndCourseId(@Param("type") int type,@Param("courseId") Long courseId,@Param("videoId") Long videoId);
 
     /**
      * 按课程ID和用户ID列表批量查询评论(type=1,未删除)

+ 1 - 1
fs-service/src/main/java/com/fs/course/service/IFsUserCourseCommentService.java

@@ -82,5 +82,5 @@ public interface IFsUserCourseCommentService
     int addComment(Long parentId);
     int minusComment(Long parentId);
 
-    List<FsUserCourseComment> selectFsUserCourseCommentListByTypeAndCourseId(int i, Long courseId);
+    List<FsUserCourseComment> selectFsUserCourseCommentListByTypeAndCourseId(int i, Long courseId, Long videoId);
 }

+ 2 - 2
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseCommentServiceImpl.java

@@ -151,8 +151,8 @@ public class FsUserCourseCommentServiceImpl implements IFsUserCourseCommentServi
     }
 
     @Override
-    public List<FsUserCourseComment> selectFsUserCourseCommentListByTypeAndCourseId(int type, Long courseId) {
-        return fsUserCourseCommentMapper.selectFsUserCourseCommentListByTypeAndCourseId(type,courseId);
+    public List<FsUserCourseComment> selectFsUserCourseCommentListByTypeAndCourseId(int type, Long courseId, Long videoId) {
+        return fsUserCourseCommentMapper.selectFsUserCourseCommentListByTypeAndCourseId(type,courseId,videoId);
     }
 
     @Override

+ 78 - 0
fs-service/src/main/java/com/fs/enums/WeizouOrderExpressEnum.java

@@ -0,0 +1,78 @@
+package com.fs.enums;
+
+public enum WeizouOrderExpressEnum {
+
+    SEND_ORDER("-1","待发货"),
+
+    WAITING_PICKUP("1","待揽收"),
+
+    PICKED_UP("2","已揽收"),
+
+    IN_TRANSIT("3","运输中"),
+
+    DELIVERING("4","派送中"),
+
+    ABNORMAL("5","异常件"),
+
+    RETURNED("6","退回件"),
+
+    RETURNED_SIGNED("7","退回签收"),
+
+    FORWARDED("8","转寄件"),
+
+    CANCELLED("9","作废件"),
+
+    SIGNED("10","已签收"),
+
+    CANCELED("11","已取消");
+
+    private final String code;
+    private final String desc;
+
+    WeizouOrderExpressEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    /**
+     * 根据code获取枚举
+     */
+    public static WeizouOrderExpressEnum fromCode(String code) {
+        for (WeizouOrderExpressEnum status : values()) {
+            if (status.code.equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 根据code获取状态描述
+     */
+    public static String getDescByCode(String code) {
+        WeizouOrderExpressEnum status = fromCode(code);
+        return status != null ? status.desc : "未知状态";
+    }
+
+    /**
+     * 是否为终态
+     */
+    public boolean isFinal() {
+        return this == SIGNED || this == CANCELED;
+    }
+
+    /**
+     * 是否为异常状态
+     */
+    public boolean isAbnormal() {
+        return this == ABNORMAL || this == RETURNED;
+    }
+}

+ 2 - 0
fs-service/src/main/java/com/fs/his/config/FsSysConfig.java

@@ -14,6 +14,8 @@ public class FsSysConfig {
     String kdnUrl;
     String kdnSubscribeUrl;
     String kdnAddressUrl;
+    /** 是否开启快递单号识别(发货时调用快递鸟 2002,根据运单号识别承运商);默认关闭 */
+    private Boolean enableLogisticCodeRecognition;
     //腾讯云IM
     Long sdkAppId;
     String sdkAppKey;

+ 58 - 0
fs-service/src/main/java/com/fs/his/domain/FsCourseCoupon.java

@@ -0,0 +1,58 @@
+package com.fs.his.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 课程优惠券对象 fs_course_coupon
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsCourseCoupon extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 有效期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "有效期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date limitTime;
+
+    /** 数量 */
+    @Excel(name = "数量")
+    private Long number;
+
+    /** 剩余数量 */
+    @Excel(name = "剩余数量")
+    private Long remainNumber;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Long status;
+
+    /** 领取后有效期 */
+    @Excel(name = "领取后有效期")
+    private Long limitDay;
+
+    /** 有效期类别 1 过期时间 2 领取后有效期 */
+    @Excel(name = "有效期类别 1 过期时间 2 领取后有效期")
+    private Long limitType;
+
+    /** 每人可领取数量 */
+    @Excel(name = "每人可领取数量")
+    private Long limitCount;
+
+    /** 标题 */
+    @Excel(name = "标题")
+    private String title;
+
+
+}

+ 47 - 0
fs-service/src/main/java/com/fs/his/domain/FsCourseCouponUser.java

@@ -0,0 +1,47 @@
+package com.fs.his.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户看课优惠券对象 fs_course_coupon_user
+ *
+ * @author fs
+ * @date 2026-05-13
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsCourseCouponUser extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 优惠券id */
+    @Excel(name = "优惠券id")
+    private Long couponId;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 有效期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "有效期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date limitTime;
+
+    /** 开始时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date startTime;
+
+    /** 核销状态 0-未核销 1-已核销 */
+    @Excel(name = "核销状态 0-未核销 1-已核销")
+    private Integer status;
+
+
+}

+ 40 - 0
fs-service/src/main/java/com/fs/his/domain/FsIntegralCount.java

@@ -0,0 +1,40 @@
+package com.fs.his.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 通用积分消耗退还统计(不含看课领的积分)对象 fs_integral_count
+ *
+ * @author fs
+ * @date 2026-05-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsIntegralCount extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** $column.columnComment */
+    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    private Date consumptionDate;
+
+    /** 通用的积分消耗 */
+    @Excel(name = "通用的积分消耗")
+    private String integralConsume;
+
+    /** $column.columnComment */
+    @Excel(name = "通用的积分消耗")
+    private String integralRefund;
+
+    @Excel(name = "积分类型",dictType="sys_integral_log_type")
+    private Integer logType;
+
+
+}

+ 61 - 0
fs-service/src/main/java/com/fs/his/mapper/FsCourseCouponMapper.java

@@ -0,0 +1,61 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsCourseCoupon;
+
+/**
+ * 课程优惠券Mapper接口
+ * 
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface FsCourseCouponMapper extends BaseMapper<FsCourseCoupon>{
+    /**
+     * 查询课程优惠券
+     * 
+     * @param id 课程优惠券主键
+     * @return 课程优惠券
+     */
+    FsCourseCoupon selectFsCourseCouponById(Long id);
+
+    /**
+     * 查询课程优惠券列表
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 课程优惠券集合
+     */
+    List<FsCourseCoupon> selectFsCourseCouponList(FsCourseCoupon fsCourseCoupon);
+
+    /**
+     * 新增课程优惠券
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 结果
+     */
+    int insertFsCourseCoupon(FsCourseCoupon fsCourseCoupon);
+
+    /**
+     * 修改课程优惠券
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 结果
+     */
+    int updateFsCourseCoupon(FsCourseCoupon fsCourseCoupon);
+
+    /**
+     * 删除课程优惠券
+     * 
+     * @param id 课程优惠券主键
+     * @return 结果
+     */
+    int deleteFsCourseCouponById(Long id);
+
+    /**
+     * 批量删除课程优惠券
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsCourseCouponByIds(Long[] ids);
+}

+ 61 - 0
fs-service/src/main/java/com/fs/his/mapper/FsCourseCouponUserMapper.java

@@ -0,0 +1,61 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsCourseCouponUser;
+
+/**
+ * 用户看课优惠券Mapper接口
+ * 
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface FsCourseCouponUserMapper extends BaseMapper<FsCourseCouponUser>{
+    /**
+     * 查询用户看课优惠券
+     * 
+     * @param id 用户看课优惠券主键
+     * @return 用户看课优惠券
+     */
+    FsCourseCouponUser selectFsCourseCouponUserById(Long id);
+
+    /**
+     * 查询用户看课优惠券列表
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 用户看课优惠券集合
+     */
+    List<FsCourseCouponUser> selectFsCourseCouponUserList(FsCourseCouponUser fsCourseCouponUser);
+
+    /**
+     * 新增用户看课优惠券
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 结果
+     */
+    int insertFsCourseCouponUser(FsCourseCouponUser fsCourseCouponUser);
+
+    /**
+     * 修改用户看课优惠券
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 结果
+     */
+    int updateFsCourseCouponUser(FsCourseCouponUser fsCourseCouponUser);
+
+    /**
+     * 删除用户看课优惠券
+     * 
+     * @param id 用户看课优惠券主键
+     * @return 结果
+     */
+    int deleteFsCourseCouponUserById(Long id);
+
+    /**
+     * 批量删除用户看课优惠券
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsCourseCouponUserByIds(Long[] ids);
+}

+ 63 - 0
fs-service/src/main/java/com/fs/his/mapper/FsIntegralCountMapper.java

@@ -0,0 +1,63 @@
+package com.fs.his.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsIntegralCount;
+
+import java.util.List;
+
+/**
+ * 通用积分消耗退还统计(不含看课领的积分)Mapper接口
+ *
+ * @author fs
+ * @date 2026-05-15
+ */
+public interface FsIntegralCountMapper extends BaseMapper<FsIntegralCount> {
+    /**
+     * 查询通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param id 通用积分消耗退还统计(不含看课领的积分)主键
+     * @return 通用积分消耗退还统计(不含看课领的积分)
+     */
+    FsIntegralCount selectFsIntegralCountById(Long id);
+
+    /**
+     * 查询通用积分消耗退还统计(不含看课领的积分)列表
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 通用积分消耗退还统计(不含看课领的积分)集合
+     */
+    List<FsIntegralCount> selectFsIntegralCountList(FsIntegralCount fsIntegralCount);
+
+    /**
+     * 新增通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 结果
+     */
+    int insertFsIntegralCount(FsIntegralCount fsIntegralCount);
+
+    /**
+     * 修改通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 结果
+     */
+    int updateFsIntegralCount(FsIntegralCount fsIntegralCount);
+
+    /**
+     * 删除通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param id 通用积分消耗退还统计(不含看课领的积分)主键
+     * @return 结果
+     */
+    int deleteFsIntegralCountById(Long id);
+
+    /**
+     * 批量删除通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsIntegralCountByIds(Long[] ids);
+}

+ 61 - 0
fs-service/src/main/java/com/fs/his/service/IFsCourseCouponService.java

@@ -0,0 +1,61 @@
+package com.fs.his.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsCourseCoupon;
+
+/**
+ * 课程优惠券Service接口
+ * 
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface IFsCourseCouponService extends IService<FsCourseCoupon>{
+    /**
+     * 查询课程优惠券
+     * 
+     * @param id 课程优惠券主键
+     * @return 课程优惠券
+     */
+    FsCourseCoupon selectFsCourseCouponById(Long id);
+
+    /**
+     * 查询课程优惠券列表
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 课程优惠券集合
+     */
+    List<FsCourseCoupon> selectFsCourseCouponList(FsCourseCoupon fsCourseCoupon);
+
+    /**
+     * 新增课程优惠券
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 结果
+     */
+    int insertFsCourseCoupon(FsCourseCoupon fsCourseCoupon);
+
+    /**
+     * 修改课程优惠券
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 结果
+     */
+    int updateFsCourseCoupon(FsCourseCoupon fsCourseCoupon);
+
+    /**
+     * 批量删除课程优惠券
+     * 
+     * @param ids 需要删除的课程优惠券主键集合
+     * @return 结果
+     */
+    int deleteFsCourseCouponByIds(Long[] ids);
+
+    /**
+     * 删除课程优惠券信息
+     * 
+     * @param id 课程优惠券主键
+     * @return 结果
+     */
+    int deleteFsCourseCouponById(Long id);
+}

+ 61 - 0
fs-service/src/main/java/com/fs/his/service/IFsCourseCouponUserService.java

@@ -0,0 +1,61 @@
+package com.fs.his.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsCourseCouponUser;
+
+/**
+ * 用户看课优惠券Service接口
+ * 
+ * @author fs
+ * @date 2026-05-13
+ */
+public interface IFsCourseCouponUserService extends IService<FsCourseCouponUser>{
+    /**
+     * 查询用户看课优惠券
+     * 
+     * @param id 用户看课优惠券主键
+     * @return 用户看课优惠券
+     */
+    FsCourseCouponUser selectFsCourseCouponUserById(Long id);
+
+    /**
+     * 查询用户看课优惠券列表
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 用户看课优惠券集合
+     */
+    List<FsCourseCouponUser> selectFsCourseCouponUserList(FsCourseCouponUser fsCourseCouponUser);
+
+    /**
+     * 新增用户看课优惠券
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 结果
+     */
+    int insertFsCourseCouponUser(FsCourseCouponUser fsCourseCouponUser);
+
+    /**
+     * 修改用户看课优惠券
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 结果
+     */
+    int updateFsCourseCouponUser(FsCourseCouponUser fsCourseCouponUser);
+
+    /**
+     * 批量删除用户看课优惠券
+     * 
+     * @param ids 需要删除的用户看课优惠券主键集合
+     * @return 结果
+     */
+    int deleteFsCourseCouponUserByIds(Long[] ids);
+
+    /**
+     * 删除用户看课优惠券信息
+     * 
+     * @param id 用户看课优惠券主键
+     * @return 结果
+     */
+    int deleteFsCourseCouponUserById(Long id);
+}

+ 63 - 0
fs-service/src/main/java/com/fs/his/service/IFsIntegralCountService.java

@@ -0,0 +1,63 @@
+package com.fs.his.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsIntegralCount;
+
+import java.util.List;
+
+/**
+ * 通用积分消耗退还统计(不含看课领的积分)Service接口
+ *
+ * @author fs
+ * @date 2026-05-15
+ */
+public interface IFsIntegralCountService extends IService<FsIntegralCount> {
+    /**
+     * 查询通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param id 通用积分消耗退还统计(不含看课领的积分)主键
+     * @return 通用积分消耗退还统计(不含看课领的积分)
+     */
+    FsIntegralCount selectFsIntegralCountById(Long id);
+
+    /**
+     * 查询通用积分消耗退还统计(不含看课领的积分)列表
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 通用积分消耗退还统计(不含看课领的积分)集合
+     */
+    List<FsIntegralCount> selectFsIntegralCountList(FsIntegralCount fsIntegralCount);
+
+    /**
+     * 新增通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 结果
+     */
+    int insertFsIntegralCount(FsIntegralCount fsIntegralCount);
+
+    /**
+     * 修改通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 结果
+     */
+    int updateFsIntegralCount(FsIntegralCount fsIntegralCount);
+
+    /**
+     * 批量删除通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param ids 需要删除的通用积分消耗退还统计(不含看课领的积分)主键集合
+     * @return 结果
+     */
+    int deleteFsIntegralCountByIds(Long[] ids);
+
+    /**
+     * 删除通用积分消耗退还统计(不含看课领的积分)信息
+     *
+     * @param id 通用积分消耗退还统计(不含看课领的积分)主键
+     * @return 结果
+     */
+    int deleteFsIntegralCountById(Long id);
+}

+ 1 - 1
fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java

@@ -287,7 +287,7 @@ public interface IFsStoreOrderService
 
     void weizouPush(Long l) throws IOException;
 
-    int sendGoodsWeizou(FsStoreOrder fsStoreOrder, String opeName);
+    Integer sendGoodsWeizou(FsStoreOrder fsStoreOrder);
 
     BigDecimal selectPayPriceByYear(String userId);
 }

+ 95 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsCourseCouponServiceImpl.java

@@ -0,0 +1,95 @@
+package com.fs.his.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.his.mapper.FsCourseCouponMapper;
+import com.fs.his.domain.FsCourseCoupon;
+import com.fs.his.service.IFsCourseCouponService;
+
+/**
+ * 课程优惠券Service业务层处理
+ * 
+ * @author fs
+ * @date 2026-05-13
+ */
+@Service
+public class FsCourseCouponServiceImpl extends ServiceImpl<FsCourseCouponMapper, FsCourseCoupon> implements IFsCourseCouponService {
+
+    /**
+     * 查询课程优惠券
+     * 
+     * @param id 课程优惠券主键
+     * @return 课程优惠券
+     */
+    @Override
+    public FsCourseCoupon selectFsCourseCouponById(Long id)
+    {
+        return baseMapper.selectFsCourseCouponById(id);
+    }
+
+    /**
+     * 查询课程优惠券列表
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 课程优惠券
+     */
+    @Override
+    public List<FsCourseCoupon> selectFsCourseCouponList(FsCourseCoupon fsCourseCoupon)
+    {
+        return baseMapper.selectFsCourseCouponList(fsCourseCoupon);
+    }
+
+    /**
+     * 新增课程优惠券
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 结果
+     */
+    @Override
+    public int insertFsCourseCoupon(FsCourseCoupon fsCourseCoupon)
+    {
+        fsCourseCoupon.setCreateTime(DateUtils.getNowDate());
+        fsCourseCoupon.setRemainNumber(fsCourseCoupon.getNumber());
+        return baseMapper.insertFsCourseCoupon(fsCourseCoupon);
+    }
+
+    /**
+     * 修改课程优惠券
+     * 
+     * @param fsCourseCoupon 课程优惠券
+     * @return 结果
+     */
+    @Override
+    public int updateFsCourseCoupon(FsCourseCoupon fsCourseCoupon)
+    {
+        fsCourseCoupon.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsCourseCoupon(fsCourseCoupon);
+    }
+
+    /**
+     * 批量删除课程优惠券
+     * 
+     * @param ids 需要删除的课程优惠券主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseCouponByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsCourseCouponByIds(ids);
+    }
+
+    /**
+     * 删除课程优惠券信息
+     * 
+     * @param id 课程优惠券主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseCouponById(Long id)
+    {
+        return baseMapper.deleteFsCourseCouponById(id);
+    }
+}

+ 94 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsCourseCouponUserServiceImpl.java

@@ -0,0 +1,94 @@
+package com.fs.his.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.his.mapper.FsCourseCouponUserMapper;
+import com.fs.his.domain.FsCourseCouponUser;
+import com.fs.his.service.IFsCourseCouponUserService;
+
+/**
+ * 用户看课优惠券Service业务层处理
+ * 
+ * @author fs
+ * @date 2026-05-13
+ */
+@Service
+public class FsCourseCouponUserServiceImpl extends ServiceImpl<FsCourseCouponUserMapper, FsCourseCouponUser> implements IFsCourseCouponUserService {
+
+    /**
+     * 查询用户看课优惠券
+     * 
+     * @param id 用户看课优惠券主键
+     * @return 用户看课优惠券
+     */
+    @Override
+    public FsCourseCouponUser selectFsCourseCouponUserById(Long id)
+    {
+        return baseMapper.selectFsCourseCouponUserById(id);
+    }
+
+    /**
+     * 查询用户看课优惠券列表
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 用户看课优惠券
+     */
+    @Override
+    public List<FsCourseCouponUser> selectFsCourseCouponUserList(FsCourseCouponUser fsCourseCouponUser)
+    {
+        return baseMapper.selectFsCourseCouponUserList(fsCourseCouponUser);
+    }
+
+    /**
+     * 新增用户看课优惠券
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 结果
+     */
+    @Override
+    public int insertFsCourseCouponUser(FsCourseCouponUser fsCourseCouponUser)
+    {
+        fsCourseCouponUser.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsCourseCouponUser(fsCourseCouponUser);
+    }
+
+    /**
+     * 修改用户看课优惠券
+     * 
+     * @param fsCourseCouponUser 用户看课优惠券
+     * @return 结果
+     */
+    @Override
+    public int updateFsCourseCouponUser(FsCourseCouponUser fsCourseCouponUser)
+    {
+        fsCourseCouponUser.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsCourseCouponUser(fsCourseCouponUser);
+    }
+
+    /**
+     * 批量删除用户看课优惠券
+     * 
+     * @param ids 需要删除的用户看课优惠券主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseCouponUserByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsCourseCouponUserByIds(ids);
+    }
+
+    /**
+     * 删除用户看课优惠券信息
+     * 
+     * @param id 用户看课优惠券主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseCouponUserById(Long id)
+    {
+        return baseMapper.deleteFsCourseCouponUserById(id);
+    }
+}

+ 94 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsIntegralCountServiceImpl.java

@@ -0,0 +1,94 @@
+package com.fs.his.service.impl;
+
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.his.domain.FsIntegralCount;
+import com.fs.his.mapper.FsIntegralCountMapper;
+import com.fs.his.service.IFsIntegralCountService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 通用积分消耗退还统计(不含看课领的积分)Service业务层处理
+ *
+ * @author fs
+ * @date 2026-05-15
+ */
+@Service
+public class FsIntegralCountServiceImpl extends ServiceImpl<FsIntegralCountMapper, FsIntegralCount> implements IFsIntegralCountService {
+
+    /**
+     * 查询通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param id 通用积分消耗退还统计(不含看课领的积分)主键
+     * @return 通用积分消耗退还统计(不含看课领的积分)
+     */
+    @Override
+    public FsIntegralCount selectFsIntegralCountById(Long id)
+    {
+        return baseMapper.selectFsIntegralCountById(id);
+    }
+
+    /**
+     * 查询通用积分消耗退还统计(不含看课领的积分)列表
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 通用积分消耗退还统计(不含看课领的积分)
+     */
+    @Override
+    public List<FsIntegralCount> selectFsIntegralCountList(FsIntegralCount fsIntegralCount)
+    {
+        return baseMapper.selectFsIntegralCountList(fsIntegralCount);
+    }
+
+    /**
+     * 新增通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 结果
+     */
+    @Override
+    public int insertFsIntegralCount(FsIntegralCount fsIntegralCount)
+    {
+        fsIntegralCount.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsIntegralCount(fsIntegralCount);
+    }
+
+    /**
+     * 修改通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param fsIntegralCount 通用积分消耗退还统计(不含看课领的积分)
+     * @return 结果
+     */
+    @Override
+    public int updateFsIntegralCount(FsIntegralCount fsIntegralCount)
+    {
+        return baseMapper.updateFsIntegralCount(fsIntegralCount);
+    }
+
+    /**
+     * 批量删除通用积分消耗退还统计(不含看课领的积分)
+     *
+     * @param ids 需要删除的通用积分消耗退还统计(不含看课领的积分)主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsIntegralCountByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsIntegralCountByIds(ids);
+    }
+
+    /**
+     * 删除通用积分消耗退还统计(不含看课领的积分)信息
+     *
+     * @param id 通用积分消耗退还统计(不含看课领的积分)主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsIntegralCountById(Long id)
+    {
+        return baseMapper.deleteFsIntegralCountById(id);
+    }
+}

+ 291 - 71
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -20,7 +20,10 @@ import com.fs.common.exception.CustomException;
 import com.fs.common.exception.ServiceException;
 import com.fs.common.utils.*;
 import com.fs.common.utils.ip.IpUtils;
-import com.fs.company.domain.*;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyDept;
+import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyDivItemMapper;
 import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.mapper.CompanyMoneyLogsMapper;
@@ -36,13 +39,15 @@ import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
+import com.fs.enums.WeizouOrderExpressEnum;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
 import com.fs.erp.dto.df.*;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.erp.utils.WeizouApiClient;
-import com.fs.event.*;
-import com.fs.gtPush.service.uniPush2Service;
+import com.fs.event.TemplateBean;
+import com.fs.event.TemplateEvent;
+import com.fs.event.TemplateListenEnum;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.*;
@@ -54,9 +59,7 @@ import com.fs.his.service.*;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.*;
-import com.fs.hisStore.domain.FsPayConfigScrm;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
-import com.fs.hisStore.domain.FsStorePaymentScrm;
 import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
 import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
 import com.fs.hisStore.param.FsStoreOrderRefundByProductParam;
@@ -66,8 +69,8 @@ import com.fs.hisapi.domain.ApiResponse;
 import com.fs.hisapi.param.CreateOrderParam;
 import com.fs.hisapi.param.RecipeDetailParam;
 import com.fs.hisapi.service.HisApiService;
-import com.fs.huifuPay.domain.*;
-import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentDelaytransConfirmRequest;
+import com.fs.huifuPay.domain.HuiFuCreateOrder;
+import com.fs.huifuPay.domain.HuifuCreateOrderResult;
 import com.fs.huifuPay.sdk.opps.core.utils.HuiFuUtils;
 import com.fs.huifuPay.service.HuiFuService;
 import com.fs.im.dto.*;
@@ -78,15 +81,15 @@ import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.service.impl.QwUserServiceImpl;
 import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import com.fs.system.service.ISysConfigService;
+import com.fs.tzBankPay.TzBankService.TzBankService;
 import com.fs.tzBankPay.doman.*;
 import com.fs.ybPay.domain.CreateWxOrderResult;
 import com.fs.ybPay.domain.OrderResult;
 import com.fs.ybPay.dto.OrderQueryDTO;
 import com.fs.ybPay.dto.WxJspayDTO;
 import com.fs.ybPay.service.IPayService;
-import com.fs.system.mapper.SysConfigMapper;
-import com.fs.system.service.ISysConfigService;
-import com.fs.tzBankPay.TzBankService.TzBankService;
 import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
 import com.github.binarywang.wxpay.config.WxPayConfig;
@@ -125,6 +128,8 @@ import java.nio.charset.Charset;
 import java.sql.Timestamp;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -380,11 +385,12 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         //推送修改的互联网医院订单地址到聚水潭ERP
         try {
             pushOrderAddressToErp(fsStoreOrder);
-        }catch (Exception e){
+        } catch (Exception e) {
             log.error("修改互联网医院订单地址推送到聚水潭ERP失败,orderId: {}", fsStoreOrder.getOrderId(), e);
         }
         return fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder);
     }
+
     /**
      * 推送修改订单的最新地址到 ERP
      *
@@ -1660,7 +1666,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
     @Override
     @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
-    public R payConfirm(String orderCode, String payCode, String tradeNo, String payType, Integer type,String bankTransactionId,String bankSerialNo){
+    public R payConfirm(String orderCode, String payCode, String tradeNo, String payType, Integer type, String bankTransactionId, String bankSerialNo) {
         try {
             FsStoreOrder order = null;
             if (type.equals(1)) {
@@ -3255,12 +3261,12 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         } else {
             appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
-            if (StringUtils.isBlank(openId)){
+            if (StringUtils.isBlank(openId)) {
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                         .eq(FsUserWx::getFsUserId, param.getUserId())
                         .eq(FsUserWx::getAppId, appId);
                 FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
-                if (Objects.nonNull(fsUserWx)){
+                if (Objects.nonNull(fsUserWx)) {
                     openId = fsUserWx.getOpenId();
                 }
             }
@@ -4627,11 +4633,28 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         FsStoreOrder order = fsStoreOrderMapper.selectFsStoreOrderByOrderId(l);
         if (order.getShippingType() != null && order.getShippingType() == 2)return;
         WeizouApiPushOrderParam param = new WeizouApiPushOrderParam();
-        param.setPaid(order.getIsPay()).setRealName(order.getUserName()).setPhone(order.getUserPhone())
+        param.setRealName(order.getUserName()).setPhone(order.getUserPhone().length() > 11 ? decryptPhone(order.getUserPhone()) : order.getUserPhone())
                 .setFreightPrice(order.getFreightPrice()).setExtendOrderId(order.getOrderId().toString())
-                .setPayType(order.getPayType()==1?"02":"04")
-                .setPaymentType(order.getPayType()==1?"01":"02").setDeliveryType("顺丰快递")
         ;
+        //全款
+        if (order.getPayType().equals(1)) {
+            param.setPaymentType("01").setPaid(1)
+                    .setPayType("02").setDeliveryType("顺丰快递")
+//                    .setPayType("01").setDeliveryType("邮政快递")
+            ;
+            //部分支付
+        } else if (order.getPayType().equals(2)) {
+            param.setPaymentType("02").setPaid(2).setPrecollection(order.getPayPrice())
+                    .setPayType("04").setDeliveryType("顺丰快递")
+//                    .setPayType("03").setDeliveryType("邮政快递")
+            ;
+            //未付款
+        } else if (order.getPayType().equals(3)) {
+            param.setPaymentType("02").setPaid(0)
+                    .setPayType("04").setDeliveryType("顺丰快递")
+//                    .setPayType("03").setDeliveryType("邮政快递")
+            ;
+        }
         //商品
         FsStoreOrderItem itemMap = new FsStoreOrderItem();
         itemMap.setOrderId(order.getOrderId());
@@ -4680,66 +4703,263 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         String s = WeizouApiClient.pushOrder(param);
         log.info("微走推送结果:{}",s);
     }
+    private static final int STATUS_PENDING_SHIPMENT = 2;
+    private static final int STATUS_SHIPPED = 3;
+    private static final int STATUS_TO_EVALUATED = 4;
+    private static final String OPERATOR_CANCEL = "0";
+    private static final String OPERATOR_UPDATE = "1";
+    private static final String LOG_TYPE_DELIVERY = "delivery_goods";
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
 
     @Override
-    public int sendGoodsWeizou(FsStoreOrder fsStoreOrder, String opeName) {
-        FsStoreOrder order = fsStoreOrderMapper.selectFsStoreOrderByOrderId(fsStoreOrder.getOrderId());
-        if (order == null) throw new CustomException("订单不存在");
-        if (order.getStatus() == 2){
-            FsStoreOrder o1 = new FsStoreOrder();
-            o1.setOrderId(fsStoreOrder.getOrderId());
-            o1.setStatus(3);
-            o1.setUpdateTime(new DateTime());
-            o1.setDeliveryCode(fsStoreOrder.getDeliveryCode());
-            o1.setDeliveryName(fsStoreOrder.getDeliveryName());
-            o1.setDeliverySn(fsStoreOrder.getDeliverySn());
-            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            String dateString = formatter.format(new Date());
-            o1.setDeliveryTime(dateString);
-            int i = fsStoreOrderMapper.updateFsStoreOrder(o1);
-            if (order.getCompanyId() != null) {
-                companyService.subtractCompanyMoney(order);
-            }
-            FsStoreOrderLogs Logs = new FsStoreOrderLogs();
-            Logs.setChangeMessage(opeName+" 订单发货");
-            Logs.setOrderId(fsStoreOrder.getOrderId());
-            Logs.setChangeTime(new DateTime());
-            Logs.setChangeType("delivery_goods");
-            Optional.ofNullable(fsStoreOrder.getOperator()).ifPresent(Logs::setOperator);
-            fsStoreOrderLogsMapper.insertFsStoreOrderLogs(Logs);
-            String lastFourNumber = "";
-            if (order.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
-                lastFourNumber = order.getUserPhone();
-                if (lastFourNumber.length() == 11) {
-                    lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
-                }
-            }
-            expressService.subscribeEspress(order.getOrderCode(), fsStoreOrder.getDeliveryCode(), fsStoreOrder.getDeliverySn(), lastFourNumber);
-            return i;
+    public Integer sendGoodsWeizou(FsStoreOrder fsStoreOrder) {
+        // 1. 参数校验
+//        validateSendGoodsParams(fsStoreOrder, opeName);//controller处理了
+
+        // 2. 查询原始订单
+        FsStoreOrder originalOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderId(fsStoreOrder.getOrderId());
+        if (originalOrder == null) {
+            throw new CustomException("订单不存在");
+        }
+
+        // 3. 根据操作类型分发处理
+        if (OPERATOR_CANCEL.equals(fsStoreOrder.getOperator())) {
+            return processCancelDelivery(originalOrder, fsStoreOrder, "微走取消订单");
+        }
+        else if (WeizouOrderExpressEnum.SEND_ORDER.getCode().equals(fsStoreOrder.getOperator())){
+            return processNormalDelivery(originalOrder, fsStoreOrder, "微走发货同步订单单号更新");
         }else {
-            log.info("微走修改快递单号",fsStoreOrder.getDeliverySn());
-            FsStoreOrder o1 = new FsStoreOrder();
-            o1.setOrderId(fsStoreOrder.getOrderId());
-            o1.setDeliveryCode(fsStoreOrder.getDeliveryCode());
-            int i = fsStoreOrderMapper.updateFsStoreOrder(o1);
-            FsStoreOrderLogs Logs = new FsStoreOrderLogs();
-            Logs.setChangeMessage(opeName+"订单单号更新");
-            Logs.setOrderId(fsStoreOrder.getOrderId());
-            Logs.setChangeTime(new DateTime());
-            Logs.setChangeType("delivery_goods");
-            Logs.setOperator("微走快递单号更新");
-            fsStoreOrderLogsMapper.insertFsStoreOrderLogs(Logs);
-            String lastFourNumber = "";
-            if (order.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
-                lastFourNumber = order.getUserPhone();
-                if (lastFourNumber.length() == 11) {
-                    lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+            return processUpdateDelivery(originalOrder, fsStoreOrder, "微走订单更新");        }
+    }
+
+    /**
+     * 处理订单状态更新//todo 到货后续业务逻辑需要对接
+     */
+    private int processUpdateDelivery(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        //微走有多个状态,需要分别记录
+        if (originalOrder.getStatus() == STATUS_SHIPPED) {
+            updateOrderToEvaluated(fsStoreOrder);
+        }
+
+        // 记录日志
+        log.info("微走快递送达, 订单号: {}",
+                fsStoreOrder.getOrderId());
+        return saveOrderLog(fsStoreOrder, WeizouOrderExpressEnum.getDescByCode(fsStoreOrder.getOperator()), opeName);
+    }
+    /**
+     * 处理取消发货
+     */
+    private int processCancelDelivery(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        // 待发货状态才更新订单状态
+        if (originalOrder.getStatus() == STATUS_PENDING_SHIPMENT) {
+            updateOrderToCancelled(fsStoreOrder);
+        }
+
+        // 调用退款服务
+//        SpringUtils.getBean(IFsStoreOrderScrmService.class).refundOrder(fsStoreOrder.getOrderId());//todo 推给售后
+
+        // 记录日志
+        log.info("微走取消发货, 订单号: {}",
+                fsStoreOrder.getOrderId());
+
+        return saveOrderLog(fsStoreOrder, fsStoreOrder.getOperator(), opeName);
+    }
+
+    /**
+     * 处理正常发货/修改快递
+     */
+    private int processNormalDelivery(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        int result;
+
+        if (originalOrder.getStatus() == STATUS_PENDING_SHIPMENT) {
+            // 待发货状态:执行发货操作
+            result = executeShipOrder(originalOrder, fsStoreOrder, opeName);
+        } else {
+            // 其他状态:只更新快递信息
+            result = updateDeliveryInfo(originalOrder, fsStoreOrder, opeName);
+        }
+
+        // 订阅快递信息(两种场景都需要)
+//        subscribeExpress(originalOrder, fsStoreOrder);//2026-3-20沟通后今正用微走接口调用的方式更新物流状态
+
+        return result;
+    }
+
+    /**
+     * 执行发货操作
+     */
+    private int executeShipOrder(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        // 1. 更新订单为已发货
+        FsStoreOrder updateOrder = buildShipOrderUpdate(fsStoreOrder);
+        int result = fsStoreOrderMapper.updateFsStoreOrder(updateOrder);
+
+        // 2. 处理公司扣款
+        if (originalOrder.getCompanyId() != null) {
+            companyService.subtractCompanyMoney(originalOrder);
+        }
+
+        // 3. 记录日志
+        String logMessage = opeName + " 订单发货";
+        saveOrderLog(fsStoreOrder, opeName, logMessage);
+
+        log.info("微走订单发货成功, 订单号: {}, 快递公司: {}, 快递单号: {}",
+                fsStoreOrder.getOrderId(),
+                fsStoreOrder.getDeliveryName(),
+                fsStoreOrder.getDeliverySn());
+
+        return result;
+    }
+
+    /**
+     * 更新快递信息
+     */
+    private int updateDeliveryInfo(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        // 1. 只更新快递相关信息
+        FsStoreOrder updateOrder = buildDeliveryInfoUpdate(fsStoreOrder);
+        int result = fsStoreOrderMapper.updateFsStoreOrder(updateOrder);
+
+        // 2. 记录日志
+        String logMessage = opeName + " 订单单号更新";
+        saveOrderLog(fsStoreOrder, opeName, logMessage);
+
+        log.info("微走修改快递单号, 订单号: {}, 新快递单号: {}",
+                fsStoreOrder.getOrderId(), fsStoreOrder.getDeliverySn());
+
+        return result;
+    }
+
+    /**
+     * 更新订单为已取消状态
+     */
+    private void updateOrderToCancelled(FsStoreOrder fsStoreOrder) {
+        FsStoreOrder updateOrder = new FsStoreOrder();
+        updateOrder.setOrderId(fsStoreOrder.getOrderId());
+        updateOrder.setStatus(STATUS_SHIPPED);
+        updateOrder.setUpdateTime(new DateTime());
+        updateOrder.setDeliveryTime(getCurrentDateTimeString());
+
+        fsStoreOrderMapper.updateFsStoreOrder(updateOrder);
+    }
+    /**
+     * 更新订单为待评价状态
+     */
+    private void updateOrderToEvaluated(FsStoreOrder fsStoreOrder) {
+        FsStoreOrder updateOrder = new FsStoreOrder();
+        updateOrder.setOrderId(fsStoreOrder.getOrderId());
+        updateOrder.setStatus(STATUS_TO_EVALUATED);
+        updateOrder.setUpdateTime(new DateTime());
+        updateOrder.setDeliveryTime(getCurrentDateTimeString());
+
+        fsStoreOrderMapper.updateFsStoreOrder(updateOrder);
+    }
+
+    /**
+     * 构建发货订单更新对象
+     */
+    private FsStoreOrder buildShipOrderUpdate(FsStoreOrder fsStoreOrder) {
+        FsStoreOrder updateOrder = new FsStoreOrder();
+        updateOrder.setOrderId(fsStoreOrder.getOrderId());
+        updateOrder.setStatus(STATUS_SHIPPED);
+        updateOrder.setUpdateTime(new DateTime());
+        updateOrder.setDeliveryCode(fsStoreOrder.getDeliveryCode());
+        updateOrder.setDeliveryName(fsStoreOrder.getDeliveryName());
+        updateOrder.setDeliverySn(fsStoreOrder.getDeliverySn());
+        updateOrder.setDeliveryTime(getCurrentDateTimeString());
+
+        return updateOrder;
+    }
+
+    /**
+     * 构建快递信息更新对象
+     */
+    private FsStoreOrder buildDeliveryInfoUpdate(FsStoreOrder fsStoreOrder) {
+        FsStoreOrder updateOrder = new FsStoreOrder();
+        updateOrder.setOrderId(fsStoreOrder.getOrderId());
+        updateOrder.setDeliveryCode(fsStoreOrder.getDeliveryCode());
+        updateOrder.setDeliveryName(fsStoreOrder.getDeliveryName());
+        updateOrder.setDeliverySn(fsStoreOrder.getDeliverySn());
+        updateOrder.setUpdateTime(new DateTime());
+        // 注意:这里不更新状态和发货时间
+
+        return updateOrder;
+    }
+
+    /**
+     * 保存订单日志
+     */
+    private int saveOrderLog(FsStoreOrder fsStoreOrder, String operator, String message) {
+        FsStoreOrderLogs logs = new FsStoreOrderLogs();
+        logs.setChangeMessage(message);
+        logs.setOrderId(fsStoreOrder.getOrderId());
+        logs.setChangeTime(new DateTime());
+        logs.setChangeType(LOG_TYPE_DELIVERY);
+        logs.setOperator(operator);
+
+        return fsStoreOrderLogsMapper.insertFsStoreOrderLogs(logs);
+    }
+
+    /**
+     * 订阅快递信息
+     */
+    private void subscribeExpress(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder) {
+        String lastFourNumber = "";
+
+        // 顺丰需要手机号后四位
+        if (ShipperCodeEnum.SF.getValue().equals(fsStoreOrder.getDeliveryCode())) {
+            lastFourNumber = getLastFourPhoneNumber(originalOrder.getUserPhone());
+        }
+
+        expressService.subscribeEspress(
+                originalOrder.getOrderCode(),
+                fsStoreOrder.getDeliveryCode(),
+                fsStoreOrder.getDeliverySn(),
+                lastFourNumber
+        );
+    }
+
+    /**
+     * 获取手机号后四位
+     */
+    private String getLastFourPhoneNumber(String phone) {
+        if (phone != null && phone.length() == 11) {
+            return phone.substring(7); // 索引7开始取后4位
+        }
+        return "";
+    }
+
+    /**
+     * 获取当前时间字符串
+     */
+    private String getCurrentDateTimeString() {
+        return LocalDateTime.now().format(DATE_TIME_FORMATTER);
+    }
+
+    /**
+     * 参数校验
+     */
+    private void validateSendGoodsParams(FsStoreOrder fsStoreOrder, String opeName) {
+        if (fsStoreOrder == null) {
+            throw new IllegalArgumentException("订单参数不能为空");
+        }
+        if (fsStoreOrder.getOrderId() == null) {
+            throw new IllegalArgumentException("订单ID不能为空");
+        }
+        if (opeName == null) {
+            throw new IllegalArgumentException("备注不能为空");
+        }
+
+        // 非取消操作需要校验快递信息
+        if (!OPERATOR_CANCEL.equals(fsStoreOrder.getOperator()) ) {
+            if (!OPERATOR_UPDATE.equals(fsStoreOrder.getOperator())){
+                if (fsStoreOrder.getDeliveryCode() == null) {
+                    throw new IllegalArgumentException("快递公司编码不能为空");
                 }
             }
-            expressService.subscribeEspress(order.getOrderCode(), fsStoreOrder.getDeliveryCode(), fsStoreOrder.getDeliverySn(), lastFourNumber);
-            return i;
+            if (fsStoreOrder.getDeliverySn() == null) {
+                throw new IllegalArgumentException("快递单号不能为空");
+            }
         }
-
     }
 
     @Override

+ 5 - 0
fs-service/src/main/java/com/fs/hisStore/config/StoreConfig.java

@@ -64,4 +64,9 @@ public class StoreConfig implements Serializable {
      * 是否开启购物积分(用户实际支付金额1:1向下取整折算积分)
      */
     private Boolean enableShoppingPoints;
+
+    /**
+     * 是否开启商城订单归属绑定(开启后,orderType=0的商城订单会自动绑定归属销售)
+     */
+    private Boolean enableStoreOrderAttribution;
 }

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreOrderScrm.java

@@ -416,4 +416,8 @@ public class FsStoreOrderScrm extends BaseEntity
 
     /** 是否领取购物积分 0-未领取 1-已领取 */
     private Integer shoppingPointsClaimed;
+
+    /** 产品是否标记不分润(不入库;分佣流程传参,佣金按 0 入账并仍写公司流水) */
+    @TableField(exist = false)
+    private Boolean noCommission;
 }

+ 17 - 0
fs-service/src/main/java/com/fs/hisStore/dto/ExpressCompanyDTO.java

@@ -0,0 +1,17 @@
+package com.fs.hisStore.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class ExpressCompanyDTO {
+    @JsonProperty("ShipperName")
+    @ApiModelProperty(value = "ShipperName")
+    private String ShipperName;
+
+    @JsonProperty("ShipperCode")
+    @ApiModelProperty(value = "ShipperCode")
+    private String ShipperCode;
+
+}

+ 40 - 0
fs-service/src/main/java/com/fs/hisStore/dto/ExpressCompanyInfoDTO.java

@@ -0,0 +1,40 @@
+package com.fs.hisStore.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ExpressCompanyInfoDTO {
+
+    @JsonProperty("LogisticCode")
+    @ApiModelProperty(value = "物流运单号")
+    private String LogisticCode;
+
+    @JsonProperty("Shippers")
+    @ApiModelProperty(value = "快递公司")
+    private List<ExpressCompanyDTO> Shippers;
+
+
+
+    @JsonProperty("EBusinessID")
+    @ApiModelProperty(value = "用户ID")
+    private String EBusinessID;
+
+
+    @JsonProperty("Success")
+    @ApiModelProperty(value = "成功与否")
+    private boolean Success;
+
+
+    @JsonProperty("Reason")
+    @ApiModelProperty(value = "失败原因")
+    private String Reason;
+
+
+    @JsonProperty("Code")
+    @ApiModelProperty(value = "请求状态")
+    private String Code;
+}

+ 3 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java

@@ -1557,4 +1557,7 @@ public interface FsStoreOrderScrmMapper
      */
     @Select("SELECT * FROM fs_store_order_scrm WHERE status = 0 AND paid = 0 AND create_time < DATE_SUB(NOW(), INTERVAL #{unPayTime} MINUTE)")
     List<FsStoreOrderScrm> selectUnpayTimeoutOrderList(@Param("unPayTime") Integer unPayTime);
+
+    @Select("SELECT status FROM fs_store_order_scrm WHERE id = #{orderId}")
+    FsStoreOrderScrm selectStatusById(@Param("orderId") Long orderId);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsExpressScrmService.java

@@ -6,6 +6,7 @@ import com.fs.api.param.ExpressParam;
 import com.fs.api.vo.ExpressVO;
 import com.fs.common.core.domain.R;
 import com.fs.hisStore.domain.FsExpressScrm;
+import com.fs.hisStore.dto.ExpressCompanyInfoDTO;
 import com.fs.hisStore.dto.ExpressInfoDTO;
 import com.fs.hisStore.param.FsStoreOrderExpressParam;
 
@@ -67,6 +68,12 @@ public interface IFsExpressScrmService
 
     ExpressInfoDTO getExpressInfo(String OrderCode, String ShipperCode, String LogisticCode, String lastFourNumber);
 
+    /*
+    *
+    * 快递鸟根据订单号获取快递公司的信息
+    * */
+    ExpressCompanyInfoDTO getExpressCompanyInfo(String LogisticCode);
+
     FsExpressScrm selectFsExpressByCode(String code);
 
     FsExpressScrm selectFsExpressByOmsCode(String s);

+ 3 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java

@@ -33,6 +33,7 @@ import com.fs.hisStore.param.*;
 import com.fs.hisStore.vo.*;
 
 import com.fs.his.vo.FsPrescribeVO;
+import org.springframework.web.bind.annotation.PathVariable;
 
 /**
  * 订单Service接口
@@ -416,4 +417,6 @@ public interface IFsStoreOrderScrmService
     R zfbPayment(FsStoreOrderDoPayParam param);
 
 //    R getExpressMulti(FsStoreOrder order);
+
+    R sendExpressInfoToWx(@PathVariable Long orderId);
 }

+ 29 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsExpressScrmServiceImpl.java

@@ -20,6 +20,7 @@ import com.fs.common.utils.DateUtils;
 import com.fs.hisStore.config.StoreConfig;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.dto.ExpressAddressDTO;
+import com.fs.hisStore.dto.ExpressCompanyInfoDTO;
 import com.fs.hisStore.dto.ExpressInfoDTO;
 import com.fs.hisStore.dto.TracesDTO;
 import com.fs.hisStore.enums.ShipperCodeEnum;
@@ -167,6 +168,34 @@ public class FsExpressScrmServiceImpl implements IFsExpressScrmService
 
     }
 
+    @Override
+    public ExpressCompanyInfoDTO getExpressCompanyInfo(String LogisticCode) {
+        //处理顺丰查询轨迹需手机号码后4位
+        String requestData = "{'LogisticCode':'" + LogisticCode + "'}";
+        Map<String, Object> params = new HashMap<>();
+        try {
+            String json = this.configService.selectConfigByKey("his.config");
+            FSSysConfig sysConfig= JSON.parseObject(json,FSSysConfig.class);
+            params.put("RequestData", URLEncoder.encode(requestData, "UTF-8"));
+            params.put("EBusinessID",sysConfig.getKdnId().trim());
+            params.put("RequestType", "2002");
+            String dataSign = encrypt(requestData, sysConfig.getKdnKeyId().trim(), "UTF-8");
+            params.put("DataSign", URLEncoder.encode(dataSign, "UTF-8"));
+            params.put("DataType", "2");
+
+            String result = HttpUtil.post(sysConfig.getKdnUrl().trim(), params);
+
+            //根据公司业务处理返回的信息......
+            ExpressCompanyInfoDTO dto=JSONUtil.toBean(result,ExpressCompanyInfoDTO.class);
+            if (!dto.isSuccess()) {
+                logger.error("查询快递公司信息失败:{}:{}", result, requestData);
+            }
+            return dto;
+        } catch (Exception e) {
+            throw  new CustomException(e.getMessage());
+        }
+    }
+
     @Override
     public FsExpressScrm selectFsExpressByCode(String code) {
         return fsExpressMapper.selectFsExpressByCode(code);

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

@@ -939,8 +939,8 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
         if (order.getShoppingPointsClaimed() != null && order.getShoppingPointsClaimed() == 1
                 && order.getPayMoney() != null && order.getPayMoney().compareTo(BigDecimal.ZERO) > 0) {
             try {
-                // 计算应扣除的购物积分(与发放时一致:pay_money向下取整)
-                long pointsToDeduct = order.getPayMoney().setScale(0, BigDecimal.ROUND_DOWN).longValue();
+                // 计算应扣除的购物积分(按实际退款金额向下取整)
+                long pointsToDeduct = storeAfterSales.getRefundAmount().setScale(0, BigDecimal.ROUND_DOWN).longValue();
                 if (pointsToDeduct > 0) {
                     // 查询用户当前积分,积分不足则扣除全部积分
                     FsUserScrm user = fsUserScrmMapper.selectFsUserByUserId(order.getUserId());

+ 317 - 37
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -49,11 +49,16 @@ import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.course.dto.OrderOpenIdTransDTO;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.course.mapper.FsUserCompanyUserMapper;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
+import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
 import com.fs.erp.dto.df.*;
 import com.fs.erp.mapper.FsErpFinishPushMapper;
 import com.fs.erp.service.IErpOrderService;
+import com.fs.fastGpt.domain.FastGptRole;
+import com.fs.fastGpt.mapper.FastGptRoleMapper;
+import com.fs.fastGpt.service.IFastGptRoleService;
 import com.fs.his.config.AppConfig;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
@@ -61,10 +66,7 @@ import com.fs.his.dto.*;
 import com.fs.his.enums.*;
 import com.fs.his.mapper.*;
 import com.fs.his.param.*;
-import com.fs.his.service.IFsPrescribeService;
-import com.fs.his.service.IFsStoreOrderService;
-import com.fs.his.service.IFsUserIntegralLogsService;
-import com.fs.his.service.IFsUserWatchService;
+import com.fs.his.service.*;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.*;
 import com.fs.his.vo.FsPrescribeVO;
@@ -80,6 +82,7 @@ import com.fs.hisStore.dto.FsStoreCartDTO;
 import com.fs.hisStore.dto.StoreOrderExpressExportDTO;
 import com.fs.hisStore.dto.StorePackageProductDTO;
 import com.fs.hisStore.dto.StoreProductGroupDTO;
+import com.fs.hisStore.dto.TracesDTO;
 import com.fs.hisStore.enums.ShipperCodeEnum;
 import com.fs.hisStore.mapper.*;
 import com.fs.hisStore.param.*;
@@ -113,6 +116,11 @@ import com.fs.hisStore.constants.StoreConstants;
 import com.fs.hisStore.domain.*;
 import com.fs.hisStore.enums.*;
 import com.fs.hisStore.service.*;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.service.IQwExternalContactService;
 import com.fs.store.domain.FsStoreDelivers;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.service.ISysConfigService;
@@ -129,6 +137,11 @@ import com.fs.wx.order.mapper.FsWxExpressTaskMapper;
 import com.fs.wx.order.service.ExpressToWxHolder;
 import com.fs.wx.order.service.ExpressToWxService;
 import com.fs.wx.order.service.ShippingService;
+import com.fs.wxwork.dto.WxWorkResponseDTO;
+import com.fs.wxwork.dto.WxWorkSendTextMsgDTO;
+import com.fs.wxwork.dto.WxWorkUserId2VidDTO;
+import com.fs.wxwork.dto.WxWorkVid2UserIdRespDTO;
+import com.fs.wxwork.service.WxWorkService;
 import com.fs.ybPay.domain.OrderResult;
 import com.fs.ybPay.domain.RefundResult;
 import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
@@ -166,6 +179,8 @@ import org.redisson.api.RedissonClient;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.springframework.web.bind.annotation.PathVariable;
+
 import javax.annotation.PostConstruct;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
@@ -227,6 +242,9 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     @Autowired
     private FsUserCompanyUserMapper fsUserCompanyUserMapper;
 
+    @Autowired
+    private FsCourseWatchLogMapper fsCourseWatchLogMapper;
+
     @Autowired
     private FsUserAddressScrmMapper userAddressMapper;
 
@@ -468,6 +486,15 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     @Autowired
     private FsStoreProductActivityMapper activityMapper;
 
+    @Autowired
+    private QwExternalContactMapper qwExternalContactMapper;
+    @Autowired
+    private QwUserMapper qwUserMapper;
+    @Autowired
+    private FastGptRoleMapper fastGptRoleMapper;
+    @Autowired
+    private WxWorkService wxWorkService;
+
     @Value("${cloud_host.company_name}")
     private String companyName;
     @PostConstruct
@@ -607,9 +634,41 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             log.error("修改商城订单地址推送到聚水潭ERP失败,orderId: {}", fsStoreOrder.getId(), e);
         }
 
+        if ("北京卓美".equals(cloudHostProper.getCompanyName())) {
+            Integer newStatus = fsStoreOrder.getStatus();
+            Integer oldStatus = null;
+            Long orderId = fsStoreOrder.getId();
+            if (orderId != null && newStatus != null && (newStatus == 2 || newStatus == 3)) {
+                FsStoreOrderScrm existing = fsStoreOrderMapper.selectStatusById(orderId);
+                if (existing != null) {
+                    oldStatus = existing.getStatus();
+                }
+            }
+            int rows = fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder);
+            if (rows > 0 && orderId != null && newStatus != null && (newStatus == 2 || newStatus == 3)
+                    && (oldStatus == null || !oldStatus.equals(newStatus))) {
+                safeSendExpressInfoToWx(orderId);
+            }
+            return rows;
+        }
+
         return fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder);
     }
 
+    /**
+     * 订单状态变为待收货(2)或已完成(3)时推送企微物流消息;异常仅记录日志,不影响主流程。
+     */
+    private void safeSendExpressInfoToWx(Long orderId) {
+        if (orderId == null) {
+            return;
+        }
+        try {
+            sendExpressInfoToWx(orderId);
+        } catch (Exception e) {
+            log.error("推送企微物流消息失败,orderId:{},{}", orderId, e.getMessage(), e);
+        }
+    }
+
     @Override
     public R updateUnpaidOrderPayPostage(FsStoreOrderPayPostageEditDTO param) {
         if (param == null || param.getId() == null) {
@@ -1314,6 +1373,16 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             orderStatusService.create(storeOrder.getId(), OrderLogEnum.CREATE_ORDER.getValue(),
                     OrderLogEnum.CREATE_ORDER.getDesc());
 
+            // 商城订单归属绑定
+            if (Boolean.TRUE.equals(config.getEnableStoreOrderAttribution())
+                    && storeOrder.getOrderType() != null && storeOrder.getOrderType() == 0) {
+                try {
+                    bindStoreOrderAttribution(storeOrder, userId);
+                } catch (Exception e) {
+                    log.error("商城订单归属绑定异常,订单号:{},用户ID:{}", storeOrder.getOrderCode(), userId, e);
+                }
+            }
+
             //加入redis,24小时自动取消
             String redisKey = String.valueOf(StrUtil.format("{}{}",
                     StoreConstants.REDIS_ORDER_OUTTIME_UNPAY, storeOrder.getId()));
@@ -2109,16 +2178,59 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         return null;
     }
 
+    /**
+     * his.config 开启「单号识别」时按运单号调用快递鸟 2002;成功则按 ShipperCode 匹配本地快递公司。
+     * 失败或未开启返回 null,由调用方继续 {@link #selectExpressByOmsDeliverCode(String)}。
+     *
+     * @param deliverNameBuf 识别成功且返回快递名称时写入展示名(非空即表示需覆盖 OMS 传入名称)
+     */
+    private FsExpressScrm tryResolveExpressByLogisticCode(String deliveryId, String orderCodeForLog, StringBuilder deliverNameBuf) {
+        if (StringUtils.isBlank(deliveryId) || deliverNameBuf == null) {
+            return null;
+        }
+        try {
+            FsSysConfig hisCfg = configUtil.generateStructConfigByKey("his.config", FsSysConfig.class);
+            if (hisCfg == null || !Boolean.TRUE.equals(hisCfg.getEnableLogisticCodeRecognition())) {
+                return null;
+            }
+            ExpressCompanyInfoDTO info = expressService.getExpressCompanyInfo(deliveryId.trim());
+            if (info == null || !info.isSuccess() || !"100".equals(info.getCode())
+                    || info.getShippers() == null || info.getShippers().isEmpty()) {
+                return null;
+            }
+            ExpressCompanyDTO shipper = info.getShippers().get(0);
+            if (shipper == null || StringUtils.isBlank(shipper.getShipperCode())) {
+                return null;
+            }
+            String shipperCode = shipper.getShipperCode().trim();
+            FsExpressScrm resolved = new FsExpressScrm();
+            resolved.setCode(shipperCode);
+            resolved.setName(shipper.getShipperName());
+            deliverNameBuf.append(shipper.getShipperName().trim());
+            return resolved;
+        } catch (Exception e) {
+            log.warn("快递单号识别异常,回退 OMS 承运商编码,订单号:{},deliveryId:{},{}", orderCodeForLog, deliveryId, e.getMessage());
+            return null;
+        }
+    }
+
     @Override
     public void deliveryOrder(String orderCode, String deliveryId, String deliverCode, String deliverName) {
         FsStoreOrderScrm order = fsStoreOrderMapper.selectFsStoreOrderByOrderCode(orderCode);
         if (order != null && order.getStatus() == OrderInfoEnum.STATUS_1.getValue()) {
-            FsExpressScrm express = selectExpressByOmsDeliverCode(deliverCode);
+            StringBuilder kdnDeliverName = new StringBuilder();
+            FsExpressScrm express = tryResolveExpressByLogisticCode(deliveryId, orderCode, kdnDeliverName);
+            if (express == null) {
+                express = selectExpressByOmsDeliverCode(deliverCode);
+            }
             if (express == null) {
                 // 这里输出订单号 还有相关的物流信息,
                 log.error("发货失败:未找到快递公司,订单号:{},deliveryId:{},deliverCode:{},deliverName:{}", orderCode, deliveryId, deliverCode, deliverName);
                 return;
             }
+            if (kdnDeliverName.length() > 0) {
+                deliverName = kdnDeliverName.toString();
+            }
             if (express != null) {
                 order.setDeliveryName(deliverName);
                 order.setDeliverySn(express.getCode());
@@ -2129,7 +2241,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             //发货时间待定
             order.setDeliverySendTime(new Date());
 
-            fsStoreOrderMapper.updateFsStoreOrder(order);
+            this.updateFsStoreOrder(order);
             orderStatusService.create(order.getId(), OrderLogEnum.DELIVERY_GOODS.getValue(),
                     OrderLogEnum.DELIVERY_GOODS.getDesc());
             //订阅物流回调
@@ -2173,8 +2285,15 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     public void updateDeliveryOrder(Long id, String deliveryId, String deliverCode, String deliverName) {
         FsStoreOrderScrm order = fsStoreOrderMapper.selectFsStoreOrderById(id);
         if (order != null) {
-            FsExpressScrm express = selectExpressByOmsDeliverCode(deliverCode);
+            StringBuilder kdnDeliverName = new StringBuilder();
+            FsExpressScrm express = tryResolveExpressByLogisticCode(deliveryId, order.getOrderCode(), kdnDeliverName);
+            if (express == null) {
+                express = selectExpressByOmsDeliverCode(deliverCode);
+            }
             if (express != null) {
+                if (kdnDeliverName.length() > 0) {
+                    deliverName = kdnDeliverName.toString();
+                }
                 order.setDeliveryName(deliverName);
                 order.setDeliverySn(express.getCode());
                 order.setDeliveryId(deliveryId);
@@ -2638,39 +2757,14 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         if (order.getStatus() == OrderInfoEnum.STATUS_2.getValue()) {
             order.setFinishTime(new Date());
             order.setStatus(3);
-            fsStoreOrderMapper.updateFsStoreOrder(order);
+            this.updateFsStoreOrder(order);
             orderStatusService.create(order.getId(), OrderLogEnum.FINISH_ORDER.getValue(),
                     OrderLogEnum.FINISH_ORDER.getDesc());
             //写入公司余额 条件是只有全款订单才分,非全款后台导入
             if (order.getCompanyId() != null && order.getCompanyId() > 0 && order.getPayDelivery().compareTo(new BigDecimal(0)) == 0) {
                 if (order.getTuiMoneyStatus() == null || order.getTuiMoneyStatus() != 1) {
-                    // 检查商品是否有"不分润"标签,有则不增加公司余额
-                    boolean noCommission = false;
-                    try {
-                        if (StringUtils.isNotBlank(order.getItemJson())) {
-                            com.alibaba.fastjson.JSONArray itemArray = JSON.parseArray(order.getItemJson());
-                            if (itemArray != null && !itemArray.isEmpty()) {
-                                Long productId = itemArray.getJSONObject(0).getLong("productId");
-                                if (productId != null) {
-                                    FsStoreProductScrm product = productService.selectFsStoreProductById(productId);
-                                    if (product != null && StringUtils.isNotBlank(product.getTagInfo())) {
-                                        JSONObject tagObj = JSON.parseObject(product.getTagInfo());
-                                        Object typeObj = tagObj.get("type");
-                                        if (typeObj instanceof com.alibaba.fastjson.JSONArray) {
-                                            noCommission = ((com.alibaba.fastjson.JSONArray) typeObj).contains("no_commission");
-                                        } else if (typeObj instanceof String) {
-                                            noCommission = "no_commission".equals(typeObj);
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    } catch (Exception e) {
-                        log.error("检查商品不分润标签失败:{},订单号:{}", e.getMessage(), order.getOrderCode());
-                    }
-                    if (!noCommission) {
-                        companyService.addCompanyMoney(order);
-                    }
+                    attachNoCommissionProductFlag(order);
+                    companyService.addCompanyMoney(order);
                 }
             }
             //套餐包赠送积分
@@ -2719,6 +2813,40 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         }
     }
 
+    /**
+     * 根据订单首个商品的 tagInfo 设置不分润标记;分佣仍走 {@link ICompanyService#addCompanyMoney(FsStoreOrderScrm)},
+     * 佣金按 0 入账并写入公司资金流水。
+     */
+    private void attachNoCommissionProductFlag(FsStoreOrderScrm order) {
+        order.setNoCommission(Boolean.FALSE);
+        try {
+            if (StringUtils.isNotBlank(order.getItemJson())) {
+                com.alibaba.fastjson.JSONArray itemArray = JSON.parseArray(order.getItemJson());
+                if (itemArray != null && !itemArray.isEmpty()) {
+                    Long productId = itemArray.getJSONObject(0).getLong("productId");
+                    if (productId != null) {
+                        FsStoreProductScrm product = productService.selectFsStoreProductById(productId);
+                        if (product != null && StringUtils.isNotBlank(product.getTagInfo())) {
+                            JSONObject tagObj = JSON.parseObject(product.getTagInfo());
+                            Object typeObj = tagObj.get("type");
+                            if (typeObj instanceof com.alibaba.fastjson.JSONArray) {
+                                if (((com.alibaba.fastjson.JSONArray) typeObj).contains("no_commission")) {
+                                    order.setNoCommission(Boolean.TRUE);
+                                }
+                            } else if (typeObj instanceof String) {
+                                if ("no_commission".equals(typeObj)) {
+                                    order.setNoCommission(Boolean.TRUE);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("检查商品不分润标签失败:{},订单号:{}", e.getMessage(), order.getOrderCode());
+        }
+    }
+
     /**
      * 套餐包赠送积分
      * @param order
@@ -3555,7 +3683,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                             map.setDeliverySn(response.getOrders().get(0).getDeliverys().get(0).getExpress_code());
                             map.setDeliveryName(response.getOrders().get(0).getDeliverys().get(0).getExpress_name());
                             map.setDeliveryId(response.getOrders().get(0).getDeliverys().get(0).getMail_no());
-                            fsStoreOrderMapper.updateFsStoreOrder(map);
+                            this.updateFsStoreOrder(map);
                             orderStatusService.create(order.getId(), OrderLogEnum.DELIVERY_GOODS.getValue(),
                                     OrderLogEnum.DELIVERY_GOODS.getDesc());
                             TemplateBean templateBean = TemplateBean.builder()
@@ -3621,6 +3749,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         }
         if (order.getCompanyId() != null && order.getCompanyId() > 0 && order.getPayDelivery().compareTo(new BigDecimal(0)) == 0) {
             if (order.getTuiMoneyStatus() == null || order.getTuiMoneyStatus() != 1) {
+                attachNoCommissionProductFlag(order);
                 companyService.addCompanyMoney(order);
                 return R.ok();
             } else {
@@ -3950,6 +4079,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                         this.updateFsStoreOrder(orderMap);
                         //未分佣写入分佣
                         if (order.getCompanyId() != null && order.getCompanyId() > 0) {
+                            attachNoCommissionProductFlag(order);
                             companyService.addCompanyMoney(order);
                         }
                         successNum++;
@@ -4905,6 +5035,9 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 }
                 FsStoreScrm store = fsStoreMapper.selectFsStoreByStoreId(o.getStoreId());
                 int i = fsStoreOrderMapper.updateFsStoreOrderByOrderCode(fsStoreOrder);
+                if (i > 0) {
+                    safeSendExpressInfoToWx(o.getId());
+                }
                 String lastFourNumber = "";
                 if (fsStoreOrder.getDeliveryCode().equals(com.fs.his.enums.ShipperCodeEnum.SF.getValue())  || fsStoreOrder.getDeliveryCode().equals(ShipperCodeEnum.ZTO.getValue())) {
                     if (store.getSendPhone() != null) {
@@ -4994,7 +5127,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         String dateString = formatter.format(new Date());
         o1.setDeliveryTime(dateString);
-        int i = fsStoreOrderMapper.updateFsStoreOrder(o1);
+        int i = this.updateFsStoreOrder(o1);
         if (order.getCompanyId() != null) {
             companyService.subtractCompanyMoneyScrm(order);
         }
@@ -5029,6 +5162,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         log.info("确认收货:" + orderId);
         if (order.getCompanyId() != null && order.getTuiMoneyStatus() == 0 && "1".equals(order.getPayType())) {
             log.info("分佣:" + orderId);
+            attachNoCommissionProductFlag(order);
             companyService.addCompanyMoney(order);
             o1.setTuiMoneyTime(new Date());
         }
@@ -7220,4 +7354,150 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 //        return R.ok().put("data",result);
 //    }
 
+    /**
+     * 商城订单归属绑定逻辑
+     * 1. 查询fs_user_company_user表,获取用户绑定的销售列表(status=1正常状态)
+     * 2. 如果只绑定了一个销售,直接将该销售的companyId和companyUserId绑定到订单
+     * 3. 如果绑定了多个销售,查询用户最近看课记录(看课时长>0),将看课记录对应的销售绑定到订单
+     * 4. 如果无看课记录则不绑定归属
+     */
+    private void bindStoreOrderAttribution(FsStoreOrderScrm storeOrder, Long userId) {
+        // 查询用户绑定的正常状态的销售列表
+        FsUserCompanyUser queryParam = new FsUserCompanyUser();
+        queryParam.setUserId(userId);
+        queryParam.setStatus(1);
+        List<FsUserCompanyUser> bindList = fsUserCompanyUserMapper.selectFsUserCompanyUserList(queryParam);
+
+        if (bindList == null || bindList.isEmpty()) {
+            log.info("商城订单归属:用户{}无绑定销售,不绑定归属,订单号:{}", userId, storeOrder.getOrderCode());
+            return;
+        }
+
+        Long bindCompanyId = null;
+        Long bindCompanyUserId = null;
+
+        if (bindList.size() == 1) {
+            // 只绑定了一个销售,直接使用
+            FsUserCompanyUser bind = bindList.get(0);
+            bindCompanyId = bind.getCompanyId();
+            bindCompanyUserId = bind.getCompanyUserId();
+            log.info("商城订单归属:用户{}只绑定1个销售,直接绑定,companyId={},companyUserId={},订单号:{}",
+                    userId, bindCompanyId, bindCompanyUserId, storeOrder.getOrderCode());
+        } else {
+            // 绑定了多个销售,查询最近看课记录
+            FsCourseWatchLog latestLog = fsCourseWatchLogMapper.selectLatestWatchLogByUserId(userId);
+            if (latestLog != null && latestLog.getCompanyUserId() != null) {
+                bindCompanyId = latestLog.getCompanyId();
+                bindCompanyUserId = latestLog.getCompanyUserId();
+                log.info("商城订单归属:用户{}绑定多个销售,通过最近看课记录绑定,companyId={},companyUserId={},订单号:{}",
+                        userId, bindCompanyId, bindCompanyUserId, storeOrder.getOrderCode());
+            } else {
+                log.info("商城订单归属:用户{}绑定多个销售但无看课记录,不绑定归属,订单号:{}", userId, storeOrder.getOrderCode());
+                return;
+            }
+        }
+
+        // 绑定归属到订单
+        if (bindCompanyId != null || bindCompanyUserId != null) {
+            storeOrder.setCompanyId(bindCompanyId);
+            storeOrder.setCompanyUserId(bindCompanyUserId);
+            log.info("商城订单归属绑定成功,订单号:{},companyId={},companyUserId={}",
+                    storeOrder.getOrderCode(), bindCompanyId, bindCompanyUserId);
+        }
+    }
+
+
+    @Override
+    public R sendExpressInfoToWx(@PathVariable Long orderId) {
+        boolean isSend = redisCache.setIfAbsent("fs:express:info:send:" + orderId, "1", 2, TimeUnit.MINUTES);
+        if (isSend) {
+            FsStoreOrderScrm order = fsStoreOrderMapper.selectFsStoreOrderById(orderId);
+            if (order != null && order.getUserId() != null) {
+                List<QwExternalContact> qwExternalContact = qwExternalContactMapper.selectQwExternalContactByFsUserIdAndCompany(order.getUserId(), order.getCompanyUserId());
+                if (qwExternalContact != null && !qwExternalContact.isEmpty()) {
+                    for (QwExternalContact externalContact : qwExternalContact) {
+                        Long qwUserId = externalContact.getQwUserId();
+                        if (qwUserId != null) {
+                            QwUser qwUser = qwUserMapper.selectQwUserById(qwUserId);
+                            if (qwUser != null && qwUser.getUid() != null && qwUser.getFastGptRoleId() != null && qwUser.getServerId() != null && qwUser.getServerStatus() == 1 && qwUser.getIpadStatus() == 1) {
+                                FastGptRole fastGptRole = fastGptRoleMapper.selectFastGptRoleByRoleId(qwUser.getFastGptRoleId());
+                                if (fastGptRole.getLogistics() == 0) {
+                                    log.error("物流功能未开启,roleId:" + qwUser.getFastGptRoleId() + "订单号:" + orderId);
+                                    return R.ok();
+                                }
+                                WxWorkUserId2VidDTO wxWorkUserId2VidDTO = new WxWorkUserId2VidDTO();
+                                wxWorkUserId2VidDTO.setOpenid(Collections.singletonList(externalContact.getExternalUserId()));
+                                wxWorkUserId2VidDTO.setUuid(qwUser.getUid());
+                                WxWorkResponseDTO<List<WxWorkVid2UserIdRespDTO>> WxWorkVid2UserIdRespDTO = wxWorkService.UserId2Vid(wxWorkUserId2VidDTO, qwUser.getServerId());
+                                List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
+                                StringBuilder sBuilder = new StringBuilder();
+                                if (data != null && !data.isEmpty()) {
+                                    Long sendId = data.get(0).getUser_id();
+                                    switch (order.getStatus()) {
+                                        case -1:
+                                        case -2:
+                                        case 1:
+                                            break;
+                                        case 2:
+                                            sBuilder.append("您好,您有一个包裹正在准备发货,请耐心等待;\n");
+                                            if (order.getDeliveryId() != null && !order.getDeliveryId().isEmpty()) {
+                                                sBuilder.append(" 物流单号为:").append(order.getDeliveryId()).append("\n");
+                                            }
+                                            sBuilder.append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
+                                            break;
+                                        case 3:
+                                            String lastFourNumber = "";
+                                            if (order.getDeliverySn().equals(ShipperCodeEnum.SF.getValue()) || order.getDeliverySn().equals(ShipperCodeEnum.ZTO.getValue())) {
+                                                if("恒春来".equals(cloudHostProper.getCompanyName())
+                                                        && ObjectUtil.isNotEmpty(lastFourNumber = order.getVirtualPhone())){
+                                                    if (lastFourNumber.contains("-")) {
+                                                        lastFourNumber = lastFourNumber.length() >= 4 ? lastFourNumber.substring(lastFourNumber.length() - 4) : lastFourNumber;
+                                                    }else{
+                                                        lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+                                                    }
+                                                }
+                                                // 原逻辑
+                                                else if ((lastFourNumber = order.getUserPhone()).length() == 11) {
+                                                    lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+                                                }
+                                            }
+                                            ExpressInfoDTO express = expressService.getExpressInfo(order.getOrderCode(), order.getDeliverySn(), order.getDeliveryId(), lastFourNumber);
+                                            if (express != null && "211".equals(express.getStateEx())) {
+                                                sBuilder.append("这边查询到您有一个包裹 ");
+                                                if (express.getTraces() != null && !express.getTraces().isEmpty()) {
+                                                    List<com.fs.hisStore.dto.TracesDTO> traces = express.getTraces();
+                                                    TracesDTO tracesDTO = traces.get(traces.size() - 1);
+                                                    sBuilder.append(" 在").append(tracesDTO.getAcceptTime()).append("已经送到了\n");
+                                                    sBuilder.append(" 物流单号为:").append(order.getDeliveryId()).append("\n");
+                                                    sBuilder.append("物流信息:").append(tracesDTO.getAcceptStation()).append("\n");
+                                                } else {
+                                                    sBuilder.append(" 已经送到了\n");
+                                                }
+                                                sBuilder.append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
+                                            }
+                                            break;
+                                        case 4:
+                                        case 5:
+                                    }
+                                    if (!"".contentEquals(sBuilder)) {
+                                        String content = sBuilder.toString();
+                                        content = content.replace("(有事呼叫我,勿找平台,少一次投诉,多一份感恩)", "");
+                                        WxWorkSendTextMsgDTO wxWorkSendTextMsgDTO = new WxWorkSendTextMsgDTO();
+                                        wxWorkSendTextMsgDTO.setSend_userid(sendId);
+                                        wxWorkSendTextMsgDTO.setUuid(qwUser.getUid());
+                                        wxWorkSendTextMsgDTO.setContent(content);
+                                        wxWorkSendTextMsgDTO.setIsRoom(false);
+                                        wxWorkService.SendTextMsg(wxWorkSendTextMsgDTO, qwUser.getServerId());
+                                    }
+                                    return R.ok();
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return R.ok();
+    }
+
 }

+ 1 - 0
fs-service/src/main/resources/application-config-dev-jnlzjk.yml

@@ -90,6 +90,7 @@ cloud_host:
   volcengineUrl: https://jnlzjkvolcengine.ylrztop.com
 headerImg:
   imgUrl:
+  download_poster_url: https
 
 ipad:
   ipadUrl: http://ipadjnlzjk.ylrztop.com

+ 1 - 0
fs-service/src/main/resources/application-config-druid-jnlzjk.yml

@@ -91,6 +91,7 @@ cloud_host:
   volcengineUrl: https://jnlzjkvolcengine.ylrztop.com
 headerImg:
   imgUrl:
+  download_poster_url: https
 
 ipad:
   ipadUrl: http://ipad.ljhehualu.com

+ 112 - 0
fs-service/src/main/resources/application-config-druid-sxsm.yml

@@ -0,0 +1,112 @@
+baidu:
+  token: 12313231232
+  back-domain: https://www.xxxx.com
+#配置
+logging:
+  level:
+    org.springframework.web: INFO
+    com.github.binarywang.demo.wx.cp: DEBUG
+    me.chanjar.weixin: DEBUG
+wx:
+  miniapp:
+    configs:
+      - appid: wx41
+        secret: 58910ae7
+        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+      - appid: wxedd
+        secret: 928d296
+        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+  cp:
+    corpId: wwb2
+    appConfigs:
+      - agentId: 10
+        secret: ec7o
+        token: PPKOdAloMO
+        aesKey: PKvaxtpSvNGpfTDm7VUHIK8Wok2ESyYX24qpXJAdMP
+  pay:
+    appId: wx739 #微信公众号或者小程序等的appid
+    mchId: 1611045 #微信支付商户号
+    mchKey: 8cab12 #微信支付商户密钥
+    subAppId:  #服务商模式下的子商户公众账号ID
+    subMchId:  #服务商模式下的子商户号
+    keyPath: c:\\cert\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+    notifyUrl: https://usepp.his
+  mp:
+    useRedis: false
+    redisConfig:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 2000
+    configs:
+      - appId: wx036be2b18aa52235 # 第一个公众号的appid  //公众号名称:成都九州在线互联网医院
+        secret: 5da9ae6d354c130dc81cde1a6d097480 # 公众号的appsecret
+#      - appId: wx8e9574e8932f9e1d # 第一个公众号的appid  //公众号名称:挑宝连锁
+#        secret: 4504d4faa16d75a6551ad67a011d95cc # 公众号的appsecret
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVcw03qZy6Wllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
+  # 开放平台app微信授权配置
+  open:
+    app-id: wx974
+    secret: 32dfaa2b
+aifabu:  #爱链接
+  appKey: 7b471be905ab17ef358c610dd117601d008
+watch:
+  watchUrl: watch.ylrzcloud.com/prod-api
+#  account: tcloud
+#  password: mdf-m2h_6yw2$hq
+  account1: ccif #866655060138751
+  password1: cp-t5or_6xw7$mt
+  account2: tcloud #rt500台
+  password2: mdf-m2h_6yw2$hq
+  account3: whr
+  password3: v9xsKuqn_$d2y
+
+fs :
+  commonApi: http://172.27.0.3:8010
+  h5CommonApi: http://172.27.0.3:8010
+  jwt:
+    # 加密秘钥
+    secret: f4e2e52034348s86b67xsm581c0f9eb5
+    # token有效时长,7天,单位秒
+    expire: 31536000
+    header: AppToken
+nuonuo:
+  key: 10924508
+  secret: A2EB20764D304D16
+
+# 存储捅配置
+tencent_cloud_config:
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
+  bucket: sxsm-1323137866
+  app_id: 1323137866
+  region: ap-chongqing
+  proxy: sxsm
+cloud_host:
+  company_name: 三猫网
+  projectCode: SXSM
+  spaceName: sxsm-2114522511
+  volcengineUrl: https://sxsmvolcengine.ylrztop.com
+#看课授权时显示的头像
+headerImg:
+  imgUrl: https://sxsm-1431314362.cos.ap-chongqing.myqcloud.com/sxsm.jpg
+  #下载海报地址
+  download_poster_url: https://sxsm-1431314362.cos.ap-chongqing.myqcloud.com/sxsm.jpg
+ipad:
+  ipadUrl: http://ipad
+  aiApi: http://49.232.181.28:3000/api
+  wxIpadUrl:
+  voiceApi:
+  commonApi:
+wx_miniapp_temp:
+  pay_order_temp_id:
+  inquiry_temp_id:
+weizou:
+  baseUrl: https://api.tiaobaoliansuo.com
+  appId: 598372344571410ab2598a05ba914178
+  appSecret: c3e51122dbf749b6aef170c4b3a712c7
+  createName: wz_7f35d1f365e448f6a60a6fc39d5613a1s

+ 10 - 4
fs-service/src/main/resources/application-config-druid-yxj.yml

@@ -60,8 +60,8 @@ watch:
   password3: v9xsKuqn_$d2y
 
 fs :
-  commonApi: http://172.16.16.4:8010
-  h5CommonApi: http://172.16.16.4:8010
+  commonApi: http://172.16.16.9:8010
+  h5CommonApi: http://172.16.16.9:8010
   jwt:
     # 加密秘钥
     secret: f4y2x52034348j86b67cde581c0f9eb5
@@ -91,6 +91,7 @@ headerImg:
 ipad:
   ipadUrl: http://yxjipad.ylrztop.com
   aiApi: http://49/api
+  wxIpadUrl:
   voiceApi:
   commonApi:
 wx_miniapp_temp:
@@ -98,7 +99,12 @@ wx_miniapp_temp:
   inquiry_temp_id:
 # 聚水潭API配置
 jst:
-  app_key: 5dea3c46f0214985b1fd43d6428b2b12 #聚水潭2025-09-03
-  app_secret: 3f382758a4f4470e80932a24912be0ce #聚水潭2025-09-0
+  app_key:  #聚水潭2025-09-03
+  app_secret:  #聚水潭2025-09-0
   authorization_code: 999999
   shop_code: "18886784"
+weizou:
+  baseUrl:
+  appId:
+  appSecret:
+  createName:

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

@@ -85,8 +85,8 @@ wx:
       port: 6379
       timeout: 2000
     configs:
-      - appId: wxa414d8c8929f7bb8 #
-        secret: 10572173433311fb6baacb7971a99ee0 #
+      - appId: wx27a1f2e0b5b82309 #
+        secret: ce5e1e44245e81da29f963013486fec9 #
         token: PPKOdAlCoMO # 接口配置里的Token值
         aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
 jpush:

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

@@ -38,11 +38,11 @@ spring:
             driverClassName: com.mysql.cj.jdbc.Driver
             druid:
                 # 初始连接数
-                initialSize: 500
+                initialSize: 15
                 # 最小连接池数量
-                minIdle: 500
+                minIdle: 15
                 # 最大连接池数量
-                maxActive: 2000
+                maxActive: 120
                 # 配置获取连接等待超时的时间
                 maxWait: 60000
                 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
@@ -82,11 +82,11 @@ spring:
                   username: root
                   password: Ylrz_1q2w3e4r5t6y
                   # 初始连接数
-                  initialSize: 500
+                  initialSize: 15
                   # 最小连接池数量
-                  minIdle: 500
+                  minIdle: 15
                   # 最大连接池数量
-                  maxActive: 2000
+                  maxActive: 120
                   # 配置获取连接等待超时的时间
                   maxWait: 60000
                   # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
@@ -128,11 +128,11 @@ spring:
                     username: root
                     password: Ylrz_1q2w3e4r5t6y
                     # 初始连接数
-                    initialSize: 500
+                    initialSize: 15
                     # 最小连接池数量
-                    minIdle: 500
+                    minIdle: 15
                     # 最大连接池数量
-                    maxActive: 2000
+                    maxActive: 120
                     # 配置获取连接等待超时的时间
                     maxWait: 60000
                     # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒

+ 3 - 3
fs-service/src/main/resources/application-druid-jnlzjk.yml

@@ -46,9 +46,9 @@ spring:
                 slave:
                     # 从数据源开关/默认关闭
                     enabled: false
-                    url:
-                    username:
-                    password:
+                    url: jdbc:mysql://10.206.0.17:65535/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
+                    username: root
+                    password: Ylrz_1q2w3e4r5t6y
                 # 初始连接数
                 initialSize: 5
                 # 最小连接池数量

+ 221 - 0
fs-service/src/main/resources/application-druid-sxsm.yml

@@ -0,0 +1,221 @@
+# 数据源配置
+spring:
+    profiles:
+        include: config-druid-sxsm,common
+    # redis 配置
+    redis:
+        host: 172.27.0.12
+        port: 6379
+        # 数据库索引
+        database: 0
+        # 密码
+        password: smbmrd@#+!2026
+        # 连接超时时间
+        timeout: 10s
+        lettuce:
+            pool:
+                # 连接池中的最小空闲连接
+                min-idle: 0
+                # 连接池中的最大空闲连接
+                max-idle: 8
+                # 连接池的最大数据库连接数
+                max-active: 8
+                # #连接池最大阻塞等待时间(使用负值表示没有限制)
+                max-wait: -1ms
+    datasource:
+        #        clickhouse:
+        #            type: com.alibaba.druid.pool.DruidDataSource
+        #            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
+        #            url: jdbc:clickhouse://1.14.104.71:8123/sop_test?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
+        #            username: rt_2024
+        #            password: Yzx_19860213
+        #            initialSize: 10
+        #            maxActive: 100
+        #            minIdle: 10
+        #            maxWait: 6000
+        mysql:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://172.27.0.8:3306/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Sxdtcsxsmbm@#+!2026
+                # 从库数据源
+                slave:
+                    url: jdbc:mysql://172.27.0.10:3306/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Sxdtcsxsmbm@#+!2026
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 2000
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+        sop:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://172.27.0.8:3306/fs_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Sxdtcsxsmbm@#+!2026
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 200
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+        easycall:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://129.28.164.235:3306/easycallcenter365?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: easycallcenter365
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+rocketmq:
+    name-server: rmq-16pknjrda5.rocketmq.cd.qcloud.tencenttdmq.com:8080 # RocketMQ NameServer 地址
+    producer:
+        group: my-producer-group
+        access-key: ak16pknjrda5f27fdaa338ab # 替换为实际的 accessKey
+        secret-key: sk7d7d9b8d8d44d405 # 替换为实际的 secretKey
+    consumer:
+        group: voice-group
+        access-key: ak16pknjrda5f27fdaa338ab # 替换为实际的 accessKey
+        secret-key: sk7d7d9b8d8d44d405 # 替换为实际的 secretKey
+custom:
+    token: "1o62d3YxvdHd4LEUiltnu7sK"
+    encoding-aes-key: "UJfTQ5qKTKlegjkXtp1YuzJzxeHlUKvq5GyFbERN1iU"
+    corp-id: "ww51717e2b71d5e2d3"
+    secret: "6ODAmw-8W4t6h9mdzHh2Z4Apwj8mnsyRnjEDZOHdA7k"
+    private-key-path: "privatekey.pem"
+    webhook-url: "https://your-server.com/wecom/archive"
+# token配置
+token:
+    # 令牌自定义标识
+    header: Authorization
+    # 令牌密钥
+    secret: abcdefgsxjklmsmpqrstuvwxyz
+    # 令牌有效期(默认30分钟,秒)
+    expireTime: 86400
+openIM:
+    secret: openIM123
+    userID: imAdmin
+    url: https://
+    pushUrl: https://fc-mp-d0421385-3496-42e7-b67f-59161a36a0e4.next.bspapp.com/push
+#是否使用新im
+im:
+    type: OPENIM
+#是否为新商户,新商户不走mpOpenId
+isNewWxMerchant: false
+
+enableRedPackAccount: 0

+ 174 - 0
fs-service/src/main/resources/application-druid-yxj-test.yml

@@ -0,0 +1,174 @@
+# 数据源配置
+spring:
+    profiles:
+        include: config-druid-yxj,common
+    # redis 配置
+    redis:
+        host: 127.0.0.1
+        port: 6379
+        # 数据库索引
+        database: 0
+        # 密码
+        password:
+        # 连接超时时间
+        timeout: 10s
+        lettuce:
+            pool:
+                # 连接池中的最小空闲连接
+                min-idle: 0
+                # 连接池中的最大空闲连接
+                max-idle: 8
+                # 连接池的最大数据库连接数
+                max-active: 8
+                # #连接池最大阻塞等待时间(使用负值表示没有限制)
+                max-wait: -1ms
+    datasource:
+        #        clickhouse:
+        #            type: com.alibaba.druid.pool.DruidDataSource
+        #            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
+        #            url: jdbc:clickhouse://1.14.104.71:8123/sop_test?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
+        #            username: rt_2024
+        #            password: Yzx_19860213
+        #            initialSize: 10
+        #            maxActive: 100
+        #            minIdle: 10
+        #            maxWait: 6000
+        mysql:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://43.139.140.83:2345/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Ylrz_tM818782145I@
+                # 从库数据源
+                slave:
+                    # 从数据源开关/默认关闭
+                    url: jdbc:mysql://43.139.140.83:2345/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Ylrz_tM818782145I@
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 2000
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+        sop:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://43.139.140.83:2345/sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Ylrz_tM818782145I@
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 200
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+rocketmq:
+    name-server: rmq-1243b25nj.rocketmq.gz.public.tencenttdmq.com:8080 # RocketMQ NameServer 地址
+    producer:
+        group: my-producer-group
+        access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+        secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+    consumer:
+        group: voice-group
+        access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+        secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+custom:
+    token: "1o62d3YxvdHd4LEUiltnu7sK"
+    encoding-aes-key: "UJfTQ5qKTKlegjkXtp1YuzJzxeHlUKvq5GyFbERN1iU"
+    corp-id: "ww51717e2b71d5e2d3"
+    secret: "6ODAmw-8W4t6h9mdzHh2Z4Apwj8mnsyRnjEDZOHdA7k"
+    private-key-path: "privatekey.pem"
+    webhook-url: "https://your-server.com/wecom/archive"
+# token配置
+token:
+    # 令牌自定义标识
+    header: Authorization
+    # 令牌密钥
+    secret: abcdefghijklmnopqrstuvwxyz
+    # 令牌有效期(默认30分钟)
+    expireTime: 180
+openIM:
+    secret: openIM123
+    userID: imAdmin
+    url: https://web.im.ya.top/api
+    pushUrl:
+#是否使用新im
+im:
+    type: NONE
+#是否为新商户,新商户不走mpOpenId
+isNewWxMerchant: false
+enableRedPackAccount: 1
+

+ 2 - 1
fs-service/src/main/resources/application-druid-yxj.yml

@@ -45,7 +45,7 @@ spring:
                 # 从库数据源
                 slave:
                     # 从数据源开关/默认关闭
-                    url: jdbc:mysql://172.16.0.27:3306/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    url: jdbc:mysql://172.16.16.13:3306/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                     username: root
                     password: Ylrz_tM818782145I@
                 # 初始连接数
@@ -164,6 +164,7 @@ openIM:
     secret: openIM123
     userID: imAdmin
     url: https://web.im.ya.top/api
+    pushUrl:
 #是否使用新im
 im:
     type: NONE

+ 2 - 0
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticMapper.xml

@@ -108,6 +108,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        inner join company_user u on a.company_user_id = u.user_id
        inner join company_dept d on u.dept_id = d.dept_id
         <where>
+            <if test="companyId != null"> and a.company_id = #{companyId}</if>
+            <if test="companyUserId != null"> and a.company_user_id = #{companyUserId}</if>
             <if test="params != null">${params.dataScope}</if>
         </where>
     </select>

+ 1 - 1
fs-service/src/main/resources/mapper/course/FsUserCourseCommentMapper.xml

@@ -111,7 +111,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </update>
 
     <select id="selectFsUserCourseCommentListByTypeAndCourseId" resultType="com.fs.course.domain.FsUserCourseComment">
-        select * from fs_user_course_comment where type = #{type} and course_id = #{courseId} and is_del = 0 order by create_time desc
+        select * from fs_user_course_comment where type = #{type} and course_id = #{courseId} <if test="videoId != null"> and video_id = #{videoId} </if> and is_del = 0 order by create_time desc
     </select>
 
     <select id="selectCommentsByCourseIdAndUserIds" resultMap="FsUserCourseCommentResult">

+ 99 - 0
fs-service/src/main/resources/mapper/his/FsCourseCouponMapper.xml

@@ -0,0 +1,99 @@
+<?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.FsCourseCouponMapper">
+    
+    <resultMap type="FsCourseCoupon" id="FsCourseCouponResult">
+        <result property="id"    column="id"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="limitTime"    column="limit_time"    />
+        <result property="number"    column="number"    />
+        <result property="remainNumber"    column="remain_number"    />
+        <result property="status"    column="status"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="limitDay"    column="limit_day"    />
+        <result property="limitType"    column="limit_type"    />
+        <result property="limitCount"    column="limit_count"    />
+        <result property="title"    column="title"    />
+    </resultMap>
+
+    <sql id="selectFsCourseCouponVo">
+        select id, create_time, limit_time, number, remain_number, status, update_time, limit_day, limit_type, limit_count, title from fs_course_coupon
+    </sql>
+
+    <select id="selectFsCourseCouponList" parameterType="FsCourseCoupon" resultMap="FsCourseCouponResult">
+        <include refid="selectFsCourseCouponVo"/>
+        <where>  
+            <if test="limitTime != null "> and limit_time = #{limitTime}</if>
+            <if test="number != null "> and number = #{number}</if>
+            <if test="remainNumber != null "> and remain_number = #{remainNumber}</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="limitDay != null "> and limit_day = #{limitDay}</if>
+            <if test="limitType != null "> and limit_type = #{limitType}</if>
+            <if test="limitCount != null "> and limit_count = #{limitCount}</if>
+            <if test="title != null  and title != ''"> and title = #{title}</if>
+        </where>
+    </select>
+    
+    <select id="selectFsCourseCouponById" parameterType="Long" resultMap="FsCourseCouponResult">
+        <include refid="selectFsCourseCouponVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertFsCourseCoupon" parameterType="FsCourseCoupon" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_course_coupon
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="createTime != null">create_time,</if>
+            <if test="limitTime != null">limit_time,</if>
+            <if test="number != null">number,</if>
+            <if test="remainNumber != null">remain_number,</if>
+            <if test="status != null">status,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="limitDay != null">limit_day,</if>
+            <if test="limitType != null">limit_type,</if>
+            <if test="limitCount != null">limit_count,</if>
+            <if test="title != null">title,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="createTime != null">#{createTime},</if>
+            <if test="limitTime != null">#{limitTime},</if>
+            <if test="number != null">#{number},</if>
+            <if test="remainNumber != null">#{remainNumber},</if>
+            <if test="status != null">#{status},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="limitDay != null">#{limitDay},</if>
+            <if test="limitType != null">#{limitType},</if>
+            <if test="limitCount != null">#{limitCount},</if>
+            <if test="title != null">#{title},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsCourseCoupon" parameterType="FsCourseCoupon">
+        update fs_course_coupon
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="limitTime != null">limit_time = #{limitTime},</if>
+            <if test="number != null">number = #{number},</if>
+            <if test="remainNumber != null">remain_number = #{remainNumber},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="limitDay != null">limit_day = #{limitDay},</if>
+            <if test="limitType != null">limit_type = #{limitType},</if>
+            <if test="limitCount != null">limit_count = #{limitCount},</if>
+            <if test="title != null">title = #{title},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsCourseCouponById" parameterType="Long">
+        delete from fs_course_coupon where id = #{id}
+    </delete>
+
+    <delete id="deleteFsCourseCouponByIds" parameterType="String">
+        delete from fs_course_coupon where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 84 - 0
fs-service/src/main/resources/mapper/his/FsCourseCouponUserMapper.xml

@@ -0,0 +1,84 @@
+<?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.FsCourseCouponUserMapper">
+    
+    <resultMap type="FsCourseCouponUser" id="FsCourseCouponUserResult">
+        <result property="id"    column="id"    />
+        <result property="couponId"    column="coupon_id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="limitTime"    column="limit_time"    />
+        <result property="startTime"    column="start_time"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="status"    column="status"    />
+    </resultMap>
+
+    <sql id="selectFsCourseCouponUserVo">
+        select id, coupon_id, user_id, limit_time, start_time, create_time, update_time, status from fs_course_coupon_user
+    </sql>
+
+    <select id="selectFsCourseCouponUserList" parameterType="FsCourseCouponUser" resultMap="FsCourseCouponUserResult">
+        <include refid="selectFsCourseCouponUserVo"/>
+        <where>  
+            <if test="couponId != null "> and coupon_id = #{couponId}</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="limitTime != null "> and limit_time = #{limitTime}</if>
+            <if test="startTime != null "> and start_time = #{startTime}</if>
+            <if test="status != null "> and status = #{status}</if>
+        </where>
+    </select>
+    
+    <select id="selectFsCourseCouponUserById" parameterType="Long" resultMap="FsCourseCouponUserResult">
+        <include refid="selectFsCourseCouponUserVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertFsCourseCouponUser" parameterType="FsCourseCouponUser" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_course_coupon_user
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="couponId != null">coupon_id,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="limitTime != null">limit_time,</if>
+            <if test="startTime != null">start_time,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="status != null">status,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="couponId != null">#{couponId},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="limitTime != null">#{limitTime},</if>
+            <if test="startTime != null">#{startTime},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="status != null">#{status},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsCourseCouponUser" parameterType="FsCourseCouponUser">
+        update fs_course_coupon_user
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="couponId != null">coupon_id = #{couponId},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="limitTime != null">limit_time = #{limitTime},</if>
+            <if test="startTime != null">start_time = #{startTime},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="status != null">status = #{status},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsCourseCouponUserById" parameterType="Long">
+        delete from fs_course_coupon_user where id = #{id}
+    </delete>
+
+    <delete id="deleteFsCourseCouponUserByIds" parameterType="String">
+        delete from fs_course_coupon_user where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 77 - 0
fs-service/src/main/resources/mapper/his/FsIntegralCountMapper.xml

@@ -0,0 +1,77 @@
+<?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.FsIntegralCountMapper">
+
+    <resultMap type="FsIntegralCount" id="FsIntegralCountResult">
+        <result property="id"    column="id"    />
+        <result property="consumptionDate"    column="consumption_date"    />
+        <result property="integralConsume"    column="integral_consume"    />
+        <result property="integralRefund"    column="integral_refund"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="logType"    column="log_type"    />
+    </resultMap>
+
+    <sql id="selectFsIntegralCountVo">
+        select id, consumption_date, integral_consume, integral_refund, create_time,log_type from fs_integral_count
+    </sql>
+
+    <select id="selectFsIntegralCountList" parameterType="FsIntegralCount" resultMap="FsIntegralCountResult">
+        <include refid="selectFsIntegralCountVo"/>
+        <where>
+            <if test="consumptionDate != null "> and consumption_date = #{consumptionDate}</if>
+            <if test="integralConsume != null  and integralConsume != ''"> and integral_consume = #{integralConsume}</if>
+            <if test="integralRefund != null  and integralRefund != ''"> and integral_refund = #{integralRefund}</if>
+            <if test="logType != null  and logType != ''"> and log_type = #{logType}</if>
+        </where>
+    </select>
+
+    <select id="selectFsIntegralCountById" parameterType="Long" resultMap="FsIntegralCountResult">
+        <include refid="selectFsIntegralCountVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertFsIntegralCount" parameterType="FsIntegralCount">
+        insert into fs_integral_count
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="consumptionDate != null">consumption_date,</if>
+            <if test="integralConsume != null">integral_consume,</if>
+            <if test="integralRefund != null">integral_refund,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="logType != null">log_type,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="consumptionDate != null">#{consumptionDate},</if>
+            <if test="integralConsume != null">#{integralConsume},</if>
+            <if test="integralRefund != null">#{integralRefund},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="logType != null">#{logType},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsIntegralCount" parameterType="FsIntegralCount">
+        update fs_integral_count
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="consumptionDate != null">consumption_date = #{consumptionDate},</if>
+            <if test="integralConsume != null">integral_consume = #{integralConsume},</if>
+            <if test="integralRefund != null">integral_refund = #{integralRefund},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="logType != null">logType = #{logType},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsIntegralCountById" parameterType="Long">
+        delete from fs_integral_count where id = #{id}
+    </delete>
+
+    <delete id="deleteFsIntegralCountByIds" parameterType="String">
+        delete from fs_integral_count where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 1 - 1
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml

@@ -171,7 +171,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           AND status = 4
           AND (shopping_points_claimed IS NULL OR shopping_points_claimed = 0)
           AND create_time &gt;= #{cutoffDate}
-          AND create_time &lt;= #{sevenDaysAgo}
+          AND finish_time &lt;= #{sevenDaysAgo}
           AND pay_money &gt; 0
     </select>
 

+ 1 - 0
fs-service/src/main/resources/mapper/hisStore/FsStoreProductScrmMapper.xml

@@ -449,6 +449,7 @@
             <if test="singlePurchaseLimit != null">single_purchase_limit = #{singlePurchaseLimit},</if>
             <if test="activityType != null">activity_type = #{activityType},</if>
             <if test="tagInfo != null and tagInfo != ''">tag_info = #{tagInfo},</if>
+            <if test="tagInfo == null or tagInfo == ''">tag_info = #{tagInfo},</if>
         </trim>
         where product_id = #{productId}
     </update>

+ 77 - 7
fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java

@@ -368,6 +368,43 @@ public class AppLoginController extends AppBaseController{
     @PostMapping("/loginByApple")
     @Transactional
     public R loginByApple(@Validated @RequestBody FsUserLoginByAppleParam param) {
+//        try {
+//            if (StringUtils.isEmpty(param.getAppleKey())) {
+//                return R.error("获取苹果key失败");
+//            }
+//            // 根据苹果key查询用户
+//            FsUser user = userMapper.findUserByAppleKey(param.getAppleKey());
+//            Map<String, Object> map = new HashMap<>();
+//            if (user == null) {
+//                map.put("isNew", true);
+//                return R.ok(map);
+//            } else {
+//                if (StringUtils.isNotEmpty(param.getJpushId())) {
+//                    updateExistingUserJpushId(user, param.getJpushId());
+//                }
+//                if (StringUtils.isEmpty(user.getPhone())) {
+//                    map.put("isNew", true);
+//                    return R.ok(map);
+//                }
+//            }
+//
+//            // 更新登录设备信息
+//            updateLoginDevice(user.getUserId(), param.getLoginDevice(), param.getSource());
+//
+//            /*if (user.getStatus()==0){
+//                return R.error("登录失败,账户被禁用");
+//            }*/
+//            int isFirstLogin = userNewTaskService.performTaskOne(user.getUserId());
+//            String token = jwtUtils.generateToken(user.getUserId());
+//            redisCache.setCacheObject("userToken:" + user.getUserId(), token, 604800, TimeUnit.SECONDS);
+//            map.put("token", token);
+//            map.put("user", user);
+//            map.put("isFirst",isFirstLogin);
+//            return R.ok(map);
+//        }catch (Exception e){
+//            logger.error("zyp 苹果登录失败:{}", e.getMessage());
+//            return R.error("登录失败");
+//        }
         try {
             if (StringUtils.isEmpty(param.getAppleKey())) {
                 return R.error("获取苹果key失败");
@@ -375,22 +412,54 @@ public class AppLoginController extends AppBaseController{
             // 根据苹果key查询用户
             FsUser user = userMapper.findUserByAppleKey(param.getAppleKey());
             Map<String, Object> map = new HashMap<>();
+            // 因苹果审核问题, 如果开关打开 则创建新用户 ,若开关关闭需要校验 unionId
+            String key="appleCheckFlag";
+            Boolean flag =redisCache.getCacheObject(key);
+            if(flag==null){
+                flag =false; // 默认关闭
+            }
+
             if (user == null) {
-                map.put("isNew", true);
-                return R.ok(map);
+                if( flag){
+                    user = new FsUser();
+                    user.setLoginDevice(param.getLoginDevice()!=null ? param.getLoginDevice() : null);
+                    user.setSource(param.getSource()!=null ? param.getSource() : null);
+                    user.setAppleKey(param.getAppleKey());
+                    user.setNickName("苹果用户");
+                    user.setCreateTime(new Date());
+                    user.setAppCreateTime(new Date());
+                    user.setStatus(1);
+                    user.setAvatar("https://cos.his.cdwjyyh.com/fs/20240926/420728ee06e54575ba82665dedb4756b.png");
+                    if (StringUtils.isNotEmpty(param.getJpushId())) {
+                        user.setJpushId(param.getJpushId());
+                    }
+                    userService.insertFsUser(user);
+                }else {
+                    map.put("isNew", true); // 新账户,使用微信登录绑定appleKey
+                    return R.ok(map);
+                }
             } else {
                 if (StringUtils.isNotEmpty(param.getJpushId())) {
                     updateExistingUserJpushId(user, param.getJpushId());
+                    try {
+                        //发送注册优惠券
+                        fsUserCouponService.sendRegisterCoupon(user);
+                    } catch (Exception e) {
+                        logger.error("发送注册优惠券失败:{}",e.getMessage());
+                    }
                 }
-                if (StringUtils.isEmpty(user.getPhone())) {
+                // 审核通过后才校验
+                if (!flag && StringUtils.isEmpty(user.getUnionId())) {
                     map.put("isNew", true);
                     return R.ok(map);
                 }
             }
-
-            // 更新登录设备信息
-            updateLoginDevice(user.getUserId(), param.getLoginDevice(), param.getSource());
-
+            if(user.getAppCreateTime()== null){
+                FsUser update = new FsUser();
+                update.setAppCreateTime(new Date());
+                update.setUserId(user.getUserId());
+                userService.updateFsUser(update);
+            }
             /*if (user.getStatus()==0){
                 return R.error("登录失败,账户被禁用");
             }*/
@@ -405,6 +474,7 @@ public class AppLoginController extends AppBaseController{
             logger.error("zyp 苹果登录失败:{}", e.getMessage());
             return R.error("登录失败");
         }
+
     }
 
     private FsUser createNewAppleUser(FsUserEditPhoneParam param, String phoneNumber) {

+ 2 - 2
fs-user-app/src/main/java/com/fs/app/controller/CourseCommentController.java

@@ -112,7 +112,7 @@ public class CourseCommentController extends AppBaseController
         PageInfo<FsUserCourseComment> defaultPageInfo= new PageInfo<>(fsUserCourseComments);
         try {
             PageHelper.startPage(param.getPageNum(), param.getPageSize());
-            fsUserCourseComments = fsUserCourseCommentService.selectFsUserCourseCommentListByTypeAndCourseId(3, param.getCourseId());
+            fsUserCourseComments = fsUserCourseCommentService.selectFsUserCourseCommentListByTypeAndCourseId(3, param.getCourseId(),param.getVideoId());
             defaultPageInfo = new PageInfo<>(fsUserCourseComments);
         } catch (Exception ignore) {}
 
@@ -135,7 +135,7 @@ public class CourseCommentController extends AppBaseController
         PageInfo<FsUserCourseComment> defaultPageInfo= new PageInfo<>(fsUserCourseComments);
         try {
             PageHelper.startPage(param.getPageNum(), param.getPageSize());
-            fsUserCourseComments = fsUserCourseCommentService.selectFsUserCourseCommentListByTypeAndCourseId(3, param.getCourseId());
+            fsUserCourseComments = fsUserCourseCommentService.selectFsUserCourseCommentListByTypeAndCourseId(3, param.getCourseId(),param.getVideoId());
             defaultPageInfo = new PageInfo<>(fsUserCourseComments);
         } catch (Exception ignore) {}
         return R.ok().put("data",listPageInfo).put("defaultPageInfo",defaultPageInfo);

+ 10 - 44
fs-user-app/src/main/java/com/fs/app/controller/live/LiveCartController.java

@@ -14,12 +14,18 @@ import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
+import com.fs.erp.service.impl.JSTErpOrderServiceImpl;
 import com.fs.his.domain.FsPayConfig;
 import com.fs.his.domain.MerchantAppConfig;
 import com.fs.his.mapper.MerchantAppConfigMapper;
 import com.fs.live.domain.LiveCart;
 import com.fs.live.service.ILiveCartService;
 import com.fs.live.vo.LiveCartVo;
+import com.fs.erp.dto.ErpOrderQueryRequert;
+import com.fs.erp.dto.ErpOrderQueryResponse;
+import com.fs.erp.domain.ErpOrderQuery;
+import com.fs.erp.domain.ErpDeliverys;
+import com.fs.erp.service.IErpOrderService;
 import com.fs.hisStore.service.IFsStoreOrderScrmService;
 import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
@@ -90,6 +96,10 @@ public class LiveCartController extends AppBaseController
     @Autowired
     private CloudHostProper cloudHostProper;
 
+
+
+
+
     /**
      * 查询购物车列表
      */
@@ -194,50 +204,6 @@ public class LiveCartController extends AppBaseController
     MerchantAppConfigMapper merchantAppConfigMapper;
     @Autowired
     private WxPayService wxPayService;
-    @GetMapping("/test1")
-    public void test1() {
-        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId("wx9bb2cd1e3afe714e");
-        if (fsCoursePlaySourceConfig == null) {
-            throw new CustomException("未找到appId对应的小程序配置: " );
-        }
-        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
-        if (merchantConfigId == null || merchantConfigId <= 0) {
-            throw new CustomException("小程序没有配置商户信息");
-        }
-        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
-        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
-        WxPayConfig payConfig = new WxPayConfig();
-        payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
-        payConfig.setMchId(fsPayConfig.getWxMchId());
-        payConfig.setMchKey(fsPayConfig.getWxMchKey());
-        payConfig.setKeyPath(fsPayConfig.getKeyPath());
-        payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
-        payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
-        wxPayService.setConfig(payConfig);
-        WxPayRefundRequest refundRequest = new WxPayRefundRequest();
-        refundRequest.setOutTradeNo("live-live-" + "2017147035307872256");
-        refundRequest.setOutRefundNo("live-live-" + "2017147035307872256");
-        refundRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen("0.10"));
-        refundRequest.setRefundFee(WxPayUnifiedOrderRequest.yuanToFen("0.10"));
-        try {
-            WxPayRefundResult refundResult = wxPayService.refund(refundRequest);
-            WxPayRefundQueryResult refundQueryResult = wxPayService.refundQuery("", refundResult.getOutTradeNo(), refundResult.getOutRefundNo(), refundResult.getRefundId());
-            if(refundQueryResult!=null&&refundQueryResult.getResultCode().equals("SUCCESS")){
-                FsStorePaymentScrm paymentMap=new FsStorePaymentScrm();
-                paymentMap.setPaymentId(41868L);
-                paymentMap.setStatus(-1);
-                paymentMap.setRefundTime(DateUtils.getNowDate());
-                paymentMap.setRefundMoney(BigDecimal.valueOf(0.1));
-                fsStorePaymentScrmMapper.updateFsStorePayment(paymentMap);
-                log.error("成功");
-            }
-            else {
-                log.error("失败");
-            }
-        } catch (WxPayException e) {
-            log.error("失败");
-        }
-    }
 
 
     /**

+ 2 - 2
fs-user-app/src/main/java/com/fs/app/controller/store/CourseCommentScrmController.java

@@ -91,7 +91,7 @@ public class CourseCommentScrmController extends AppBaseController
         PageInfo<FsUserCourseComment> defaultPageInfo= new PageInfo<>(fsUserCourseComments);
         try {
             PageHelper.startPage(param.getPageNum(), param.getPageSize());
-            fsUserCourseComments = fsUserCourseCommentService.selectFsUserCourseCommentListByTypeAndCourseId(3, param.getCourseId());
+            fsUserCourseComments = fsUserCourseCommentService.selectFsUserCourseCommentListByTypeAndCourseId(3, param.getCourseId(),param.getVideoId());
             defaultPageInfo = new PageInfo<>(fsUserCourseComments);
         } catch (Exception ignore) {}
 
@@ -114,7 +114,7 @@ public class CourseCommentScrmController extends AppBaseController
         PageInfo<FsUserCourseComment> defaultPageInfo= new PageInfo<>(fsUserCourseComments);
         try {
             PageHelper.startPage(param.getPageNum(), param.getPageSize());
-            fsUserCourseComments = fsUserCourseCommentService.selectFsUserCourseCommentListByTypeAndCourseId(3, param.getCourseId());
+            fsUserCourseComments = fsUserCourseCommentService.selectFsUserCourseCommentListByTypeAndCourseId(3, param.getCourseId(),param.getVideoId());
             defaultPageInfo = new PageInfo<>(fsUserCourseComments);
         } catch (Exception ignore) {}
         return R.ok().put("data",listPageInfo).put("defaultPageInfo",defaultPageInfo);

+ 111 - 0
fs-user-app/src/main/java/com/fs/app/controller/store/StoreProductController.java

@@ -0,0 +1,111 @@
+package com.fs.app.controller.store;
+
+import com.fs.app.annotation.Login;
+import com.fs.app.controller.AppBaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.StringUtils;
+import com.fs.hisStore.domain.FsStoreProductAttrScrm;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.domain.FsStoreProductScrm;
+import com.fs.hisStore.service.IFsStoreProductAttrScrmService;
+import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
+import com.fs.hisStore.service.IFsStoreProductScrmService;
+import com.fs.hisStore.vo.FsStoreProductListVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@Api("商城产品")
+@RestController
+@RequestMapping("/app/storeProduct")
+public class StoreProductController extends AppBaseController {
+
+    @Autowired
+    private IFsStoreProductScrmService fsStoreProductService;
+
+    @Autowired
+    private IFsStoreProductAttrValueScrmService attrValueService;
+
+    @Autowired
+    private IFsStoreProductAttrScrmService attrService;
+
+    /**
+     * 查询本公司下的商城产品列表
+     */
+    @ApiOperation("查询本公司下的商城产品列表")
+    @GetMapping("/list")
+    public R list(Integer page, Integer pageSize, String productName,
+                  @RequestParam("companyId") Long companyId,
+                  @RequestParam("companyUserId") Long companyUserId) {
+        if (page == null || page < 1) {
+            page = 1;
+        }
+        if (pageSize == null || pageSize < 1) {
+            pageSize = 10;
+        }
+        if (companyId == null) {
+            return R.error("companyId不能为空");
+        }
+        PageHelper.startPage(page, pageSize);
+        FsStoreProductScrm query = new FsStoreProductScrm();
+        query.setIsDel(0);
+        query.setIsShow(1);
+        query.setIsAudit("1");
+        query.setCompanyIds(String.valueOf(companyId));
+        if (StringUtils.isNotEmpty(productName)) {
+            query.setProductName(productName);
+        }
+        List<FsStoreProductListVO> list = fsStoreProductService.selectFsStoreProductListVO(query);
+        PageInfo<FsStoreProductListVO> pageInfo = new PageInfo<>(list);
+        return R.ok().put("data", pageInfo);
+    }
+
+    /**
+     * 查看商品详情
+     */
+    @ApiOperation("查看商品详情")
+    @GetMapping("/{productId}")
+    public R getInfo(@PathVariable("productId") Long productId,
+                     @RequestParam("companyId") Long companyId,
+                     @RequestParam("companyUserId") Long companyUserId) {
+        FsStoreProductScrm product = fsStoreProductService.selectFsStoreProductById(productId);
+        if (product == null) {
+            return R.error("商品不存在");
+        }
+        // 校验该商品是否属于指定公司
+        String companyIds = product.getCompanyIds();
+        if (StringUtils.isEmpty(companyIds) || !containsCompanyId(companyIds, companyId)) {
+            return R.error("无权查看该商品");
+        }
+        // 查询商品规格属性值
+        List<FsStoreProductAttrScrm> productAttr=attrService.selectFsStoreProductAttrByProductId(product.getProductId());
+        List<FsStoreProductAttrValueScrm> productValues=attrValueService.selectFsStoreProductAttrValueByProductId(product.getProductId());
+
+        return R.ok().put("product", product)
+                .put("productAttr",productAttr)
+                .put("productValues",productValues);
+    }
+
+    /**
+     * 判断 companyIds 字符串中是否包含指定 companyId
+     * companyIds 格式可能是 "123" 或 "123,456" 等
+     */
+    private boolean containsCompanyId(String companyIds, Long companyId) {
+        if (StringUtils.isEmpty(companyIds)) {
+            return false;
+        }
+        String[] ids = companyIds.split(",");
+        for (String id : ids) {
+            if (id.trim().equals(String.valueOf(companyId))) {
+                return true;
+            }
+        }
+        return false;
+    }
+}