Procházet zdrojové kódy

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

# Conflicts:
#	fs-service/src/main/resources/application-common.yml
yzx před 1 dnem
rodič
revize
8588000551
100 změnil soubory, kde provedl 3184 přidání a 572 odebrání
  1. 41 0
      fs-admin/src/main/java/com/fs/course/business/FsVideoResourceBusinessService.java
  2. 43 31
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCompanyStatisticsController.java
  3. 27 23
      fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java
  4. 24 7
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java
  5. 109 0
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderLogsController.java
  6. 27 3
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  7. 5 1
      fs-admin/src/main/java/com/fs/his/controller/FsUserCouponController.java
  8. 61 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  9. 2 1
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreAfterSalesScrmController.java
  10. 41 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java
  11. 43 3
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java
  12. 23 5
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java
  13. 61 9
      fs-admin/src/main/java/com/fs/hisStore/task/LiveTask.java
  14. 6 0
      fs-admin/src/main/java/com/fs/hisStore/task/MallStoreTask.java
  15. 29 6
      fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesController.java
  16. 1 1
      fs-admin/src/main/java/com/fs/live/controller/LiveAutoTaskController.java
  17. 1 1
      fs-admin/src/main/java/com/fs/live/controller/LiveController.java
  18. 66 0
      fs-admin/src/main/java/com/fs/live/controller/LiveDataController.java
  19. 73 18
      fs-admin/src/main/java/com/fs/live/controller/LiveOrderController.java
  20. 326 0
      fs-admin/src/main/java/com/fs/qw/controller/IpadAllocationRecordsController.java
  21. 93 6
      fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java
  22. 30 39
      fs-admin/src/main/java/com/fs/web/controller/system/SysConfigController.java
  23. 284 0
      fs-common/src/main/java/com/fs/common/utils/RedwoodCryptoUtil.java
  24. 21 1
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  25. 5 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserLoginByMpParam.java
  26. 12 6
      fs-company/src/main/java/com/fs/company/controller/live/LiveAfterSalesController.java
  27. 1 1
      fs-company/src/main/java/com/fs/company/controller/live/LiveAutoTaskController.java
  28. 8 1
      fs-company/src/main/java/com/fs/company/controller/live/LiveController.java
  29. 3 3
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferLogController.java
  30. 8 8
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java
  31. 5 0
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java
  32. 8 0
      fs-company/src/main/java/com/fs/company/controller/store/FsPackageOrderController.java
  33. 1 1
      fs-company/src/main/java/com/fs/user/FsUserAdminController.java
  34. 1 6
      fs-doctor-app/src/main/java/com/fs/app/controller/FsUserInformationCollectionController.java
  35. 73 1
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  36. 12 0
      fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java
  37. 2 1
      fs-quartz/src/main/java/com/fs/quartz/config/ScheduleConfig.java
  38. 94 5
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  39. 3 3
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  40. 5 5
      fs-service/pom.xml
  41. 13 13
      fs-service/src/main/java/com/cloud/host/CloudHostConfig.java
  42. 4 1
      fs-service/src/main/java/com/fs/company/domain/CompanyUser.java
  43. 4 1
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  44. 5 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVO.java
  45. 10 10
      fs-service/src/main/java/com/fs/core/utils/OrderCodeUtils.java
  46. 19 0
      fs-service/src/main/java/com/fs/course/config/RandomRedPacketConfig.java
  47. 28 0
      fs-service/src/main/java/com/fs/course/config/RandomRedPacketRule.java
  48. 5 0
      fs-service/src/main/java/com/fs/course/domain/FsCoursePlaySourceConfig.java
  49. 11 23
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseCompanyStatistics.java
  50. 8 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  51. 19 14
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  52. 3 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigCreateParam.java
  53. 3 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java
  54. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsCoursePlaySourceConfigService.java
  55. 16 6
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java
  56. 0 5
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  57. 6 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCoursePlaySourceConfigServiceImpl.java
  58. 2 1
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java
  59. 9 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  60. 357 171
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  61. 3 0
      fs-service/src/main/java/com/fs/course/vo/FsCoursePlaySourceConfigVO.java
  62. 4 4
      fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderVO.java
  63. 6 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java
  64. 4 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/df/DfClient.java
  65. 86 23
      fs-service/src/main/java/com/fs/erp/service/impl/DfOrderServiceImpl.java
  66. 6 4
      fs-service/src/main/java/com/fs/erp/service/impl/JSTErpOrderServiceImpl.java
  67. 9 7
      fs-service/src/main/java/com/fs/fastGpt/service/IFastgptEventLogTotalService.java
  68. 237 7
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptEventLogTotalServiceImpl.java
  69. 1 1
      fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java
  70. 2 0
      fs-service/src/main/java/com/fs/his/config/FsSmsConfig.java
  71. 3 0
      fs-service/src/main/java/com/fs/his/domain/FsAdv.java
  72. 47 0
      fs-service/src/main/java/com/fs/his/domain/FsIntegralOrderLogs.java
  73. 5 0
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  74. 6 0
      fs-service/src/main/java/com/fs/his/domain/FsUserInformationCollection.java
  75. 0 1
      fs-service/src/main/java/com/fs/his/mapper/FsAdvMapper.java
  76. 62 0
      fs-service/src/main/java/com/fs/his/mapper/FsIntegralOrderLogsMapper.java
  77. 3 4
      fs-service/src/main/java/com/fs/his/mapper/FsPackageOrderMapper.java
  78. 1 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserInformationCollectionMapper.java
  79. 4 0
      fs-service/src/main/java/com/fs/his/param/FsUserInformationCollectionParam.java
  80. 62 0
      fs-service/src/main/java/com/fs/his/service/IFsIntegralOrderLogsService.java
  81. 5 4
      fs-service/src/main/java/com/fs/his/service/IFsPackageOrderService.java
  82. 2 0
      fs-service/src/main/java/com/fs/his/service/IFsUserInformationCollectionService.java
  83. 92 0
      fs-service/src/main/java/com/fs/his/service/impl/FsIntegralOrderLogsServiceImpl.java
  84. 51 9
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java
  85. 6 4
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java
  86. 8 2
      fs-service/src/main/java/com/fs/his/service/impl/FsPrescribeServiceImpl.java
  87. 50 6
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  88. 100 31
      fs-service/src/main/java/com/fs/his/service/impl/FsUserInformationCollectionServiceImpl.java
  89. 20 0
      fs-service/src/main/java/com/fs/his/utils/IdCardUtil.java
  90. 12 0
      fs-service/src/main/java/com/fs/his/vo/FsUserInfoCollectionAndStoreOrderVo.java
  91. 4 0
      fs-service/src/main/java/com/fs/his/vo/FsUserInformationCollectionAndPatientVO.java
  92. 13 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsUserScrm.java
  93. 11 11
      fs-service/src/main/java/com/fs/hisStore/mapper/FsShippingTemplatesScrmMapper.java
  94. 5 2
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java
  95. 14 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStorePaymentScrmMapper.java
  96. 8 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsUserScrmMapper.java
  97. 6 0
      fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderParam.java
  98. 11 11
      fs-service/src/main/java/com/fs/hisStore/service/IFsShippingTemplatesScrmService.java
  99. 5 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStorePaymentScrmService.java
  100. 8 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsUserScrmService.java

+ 41 - 0
fs-admin/src/main/java/com/fs/course/business/FsVideoResourceBusinessService.java

@@ -0,0 +1,41 @@
+package com.fs.course.business;
+
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.domain.FsVideoResource;
+import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.course.service.IFsVideoResourceService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+public class FsVideoResourceBusinessService {
+
+    private final IFsVideoResourceService fsVideoResourceService;
+
+    private final IFsUserCourseVideoService fsUserCourseVideoService;
+
+    public FsVideoResourceBusinessService(IFsVideoResourceService fsVideoResourceService,
+                                          IFsUserCourseVideoService fsUserCourseVideoService) {
+        this.fsVideoResourceService = fsVideoResourceService;
+        this.fsUserCourseVideoService = fsUserCourseVideoService;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void edit(FsVideoResource fsVideoResource) {
+        FsVideoResource oldResource = fsVideoResourceService.getById(fsVideoResource.getId());
+        fsVideoResourceService.updateById(fsVideoResource);
+        fsUserCourseVideoService.update(new UpdateWrapper<FsUserCourseVideo>()
+                .eq("video_url", oldResource.getVideoUrl())
+                .set("video_url", fsVideoResource.getVideoUrl())
+                .set("line_one", fsVideoResource.getLine1())
+                .set("line_two", fsVideoResource.getLine2())
+                .set("line_three", fsVideoResource.getLine3())
+                .set("duration", fsVideoResource.getDuration())
+                .set("file_size", fsVideoResource.getFileSize())
+                .set("file_key", fsVideoResource.getFileKey())
+                .set("file_name", fsVideoResource.getFileName())
+                .set("thumbnail", fsVideoResource.getThumbnail())
+        );
+    }
+}

+ 43 - 31
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCompanyStatisticsController.java

@@ -89,44 +89,56 @@ public class FsUserCourseCompanyStatisticsController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:statistics:export')")
     @Log(title = "会员每日看课统计", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(FsUserCourseCompanyStatistics fsUserCourseCompanyStatistics)
-    {
+    public AjaxResult export(FsUserCourseCompanyStatistics fsUserCourseCompanyStatistics) {
+
         List<FsUserCourseCompanyStatistics> list =
                 fsUserCourseCompanyStatisticsService.selectFsUserCourseCompanyStatisticsTotal(fsUserCourseCompanyStatistics);
 
-        Optional.ofNullable(list).orElse(Collections.emptyList())
-                .forEach(item -> {
-                    // 计算完播率 (完播次数 / 观看次数 * 100)
-                    item.setCompleteRate(
-                            Optional.ofNullable(item.getWatchCount())
-                                    .filter(watchCount -> watchCount > 0)
-                                    .map(watchCount -> BigDecimal.valueOf(
-                                                    Optional.ofNullable(item.getCompleteWatchCount()).orElse(0L))
-                                            .multiply(BigDecimal.valueOf(100))
-                                            .divide(BigDecimal.valueOf(watchCount), 2, RoundingMode.HALF_UP)
-                                            .longValue()
-                                    )
-                                    .orElse(0L)
-                    );
-
-                    // 计算正确率 (正确人次 / 答题人次 * 100)
-                    item.setCorrectRate(
-                            Optional.ofNullable(item.getAnswerCount())
-                                    .filter(answerCount -> answerCount > 0)
-                                    .map(answerCount -> BigDecimal.valueOf(
-                                                    Optional.ofNullable(item.getCorrectCount()).orElse(0L))
-                                            .multiply(BigDecimal.valueOf(100))
-                                            .divide(BigDecimal.valueOf(answerCount), 2, RoundingMode.HALF_UP)
-                                            .longValue()
-                                    )
-                                    .orElse(0L)
-                    );
-                });
+        if (list == null) {
+            list = Collections.emptyList();
+        }
+
+        for (FsUserCourseCompanyStatistics item : list) {
 
-        ExcelUtil<FsUserCourseCompanyStatistics> util = new ExcelUtil<FsUserCourseCompanyStatistics>(FsUserCourseCompanyStatistics.class);
+            Long watchCount = item.getWatchCount();
+            Long completeWatchCount = Optional.ofNullable(item.getCompleteWatchCount()).orElse(0L);
+
+            // 完播率 = 完播次数 / 观看次数 * 100  (放大100倍存入long,再格式化两位小数)
+            if (watchCount != null && watchCount > 0) {
+                Long rateValue = BigDecimal.valueOf(completeWatchCount)
+                        .multiply(BigDecimal.valueOf(10000)) // 100*100
+                        .divide(BigDecimal.valueOf(watchCount), 0, RoundingMode.HALF_UP)
+                        .longValue();
+                item.setCompleteRate(rateValue);
+                item.setCompleteRateStr(String.format("%.2f%%", rateValue / 100.0));  // Excel 格式化
+            } else {
+                item.setCompleteRate(0L);
+                item.setCompleteRateStr("0.00%");
+            }
+
+            Long answerCount = item.getAnswerCount();
+            Long correctCount = Optional.ofNullable(item.getCorrectCount()).orElse(0L);
+
+            // 正确率 = 正确人次 / 答题人次 * 100
+            if (answerCount != null && answerCount > 0) {
+                Long rateValue = BigDecimal.valueOf(correctCount)
+                        .multiply(BigDecimal.valueOf(10000))
+                        .divide(BigDecimal.valueOf(answerCount), 0, RoundingMode.HALF_UP)
+                        .longValue();
+                item.setCorrectRate(rateValue);
+                item.setCorrectRateStr(String.format("%.2f%%", rateValue / 100.0));
+            } else {
+                item.setCorrectRate(0L);
+                item.setCorrectRateStr("0.00%");
+            }
+        }
+
+        ExcelUtil<FsUserCourseCompanyStatistics> util = new ExcelUtil<>(FsUserCourseCompanyStatistics.class);
         return util.exportExcel(list, "会员每日看课统计数据");
     }
 
+
+
     /**
      * 获取会员每日看课统计详细信息
      */

+ 27 - 23
fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java

@@ -11,6 +11,8 @@ import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
+import com.fs.config.cloud.CloudHostProper;
+import com.fs.course.business.FsVideoResourceBusinessService;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsVideoResource;
 import com.fs.course.service.IFsVideoResourceService;
@@ -19,7 +21,6 @@ import com.fs.framework.web.service.TokenService;
 import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
@@ -37,11 +38,13 @@ public class FsVideoResourceController extends BaseController {
 
     private final IFsVideoResourceService fsVideoResourceService;
 
-    @Autowired
-    private TokenService tokenService;
+    private final TokenService tokenService;
 
-    @Autowired
-    private ISysConfigService configService;
+    private final ISysConfigService configService;
+
+    private final CloudHostProper cloudHostProper;
+
+    private final FsVideoResourceBusinessService videoResourceBusinessService;
 
     /**
      * 查询视频素材库列表
@@ -53,8 +56,7 @@ public class FsVideoResourceController extends BaseController {
                               @RequestParam(required = false) Integer typeId,
                               @RequestParam(required = false) Integer typeSubId,
                               @RequestParam(required = false, defaultValue = "1") Integer pageNum,
-                              @RequestParam(required = false, defaultValue = "10") Integer pageSize)
-    {
+                              @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
         Map<String, Object> params = new HashMap<>();
         params.put("resourceName", resourceName);
         params.put("fileName", fileName);
@@ -63,7 +65,7 @@ public class FsVideoResourceController extends BaseController {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             params.put("userId", loginUser.getUser().getUserId());
         }
         PageHelper.startPage(pageNum, pageSize);
@@ -77,8 +79,7 @@ public class FsVideoResourceController extends BaseController {
      */
     @PreAuthorize("@ss.hasPermi('course:videoResource:query')")
     @GetMapping(value = "/{id}")
-    public AjaxResult getInfo(@PathVariable("id") Long id)
-    {
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
         return AjaxResult.success(fsVideoResourceService.getById(id));
     }
 
@@ -88,13 +89,12 @@ public class FsVideoResourceController extends BaseController {
     @PreAuthorize("@ss.hasPermi('course:videoResource:add')")
     @Log(title = "视频素材库", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody FsVideoResource fsVideoResource)
-    {
+    public AjaxResult add(@RequestBody FsVideoResource fsVideoResource) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsVideoResource.setUserId(userId);
         }
         fsVideoResource.setCreateTime(LocalDateTime.now());
@@ -108,8 +108,12 @@ public class FsVideoResourceController extends BaseController {
     @PreAuthorize("@ss.hasPermi('course:videoResource:edit')")
     @Log(title = "视频素材库", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody FsVideoResource fsVideoResource)
-    {
+    public AjaxResult edit(@RequestBody FsVideoResource fsVideoResource) {
+        if (("今正科技".equals(cloudHostProper.getCompanyName()))) {
+            // 同步资源到课程
+            videoResourceBusinessService.edit(fsVideoResource);
+            return AjaxResult.success();
+        }
         fsVideoResourceService.updateById(fsVideoResource);
         return AjaxResult.success();
     }
@@ -120,8 +124,7 @@ public class FsVideoResourceController extends BaseController {
     @PreAuthorize("@ss.hasPermi('course:videoResource:remove')")
     @Log(title = "视频素材库", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
-    public AjaxResult remove(@PathVariable Long[] ids)
-    {
+    public AjaxResult remove(@PathVariable Long[] ids) {
         Wrapper<FsVideoResource> updateWrapper = Wrappers.<FsVideoResource>lambdaUpdate()
                 .set(FsVideoResource::getIsDel, 1)
                 .in(FsVideoResource::getId, Arrays.asList(ids));
@@ -131,6 +134,7 @@ public class FsVideoResourceController extends BaseController {
 
     /**
      * 批量修改视频分类
+     *
      * @param typeId
      * @param typeSubId
      * @param ids
@@ -142,13 +146,13 @@ public class FsVideoResourceController extends BaseController {
     public AjaxResult batchUpdateClass(@RequestParam("typeId") Long typeId,
                                        @RequestParam("typeSubId") Long typeSubId,
                                        @RequestParam("ids") String ids) {
-        if(typeId == null || typeId <= 0){
+        if (typeId == null || typeId <= 0) {
             return AjaxResult.error("请选择分类");
         }
-        if(typeSubId == null || typeSubId <= 0){
+        if (typeSubId == null || typeSubId <= 0) {
             return AjaxResult.error("请选择子分类");
         }
-        if(ids == null || ids.isEmpty()){
+        if (ids == null || ids.isEmpty()) {
             return AjaxResult.error("请选择要修改的分类");
         }
 
@@ -178,12 +182,12 @@ public class FsVideoResourceController extends BaseController {
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
 
-        list.forEach(v ->{
+        list.forEach(v -> {
             v.setCreateTime(LocalDateTime.now());
-            if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+            if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
                 v.setUserId(userId);
             }
-        } );
+        });
         fsVideoResourceService.saveBatch(list);
         return AjaxResult.success();
     }

+ 24 - 7
fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java

@@ -12,10 +12,8 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.his.domain.FsDfAccount;
-import com.fs.his.domain.FsIntegralOrder;
-import com.fs.his.domain.FsIntegralOrderDf;
-import com.fs.his.domain.FsStoreOrder;
+import com.fs.common.utils.uuid.IdUtils;
+import com.fs.his.domain.*;
 import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.mapper.FsIntegralOrderMapper;
@@ -59,6 +57,8 @@ public class FsIntegralOrderController extends BaseController
     @Autowired
     private IFsStoreOrderService fsStoreOrderService;
 
+    @Autowired
+    private IFsIntegralOrderLogsService integralOrderLogsService;
 
     @Autowired
     private IFsIntegralOrderDfService integralOrderDfService;
@@ -314,12 +314,20 @@ public class FsIntegralOrderController extends BaseController
             } else {
                 integralOrderDfService.insertFsIntegralOrderDf(df);
             }
-            //积分订单操作日志暂定
+            // 添加积分订单操作记录
+            FsIntegralOrderLogs logs = new FsIntegralOrderLogs();
+            logs.setLogsId(IdUtils.fastUUID());
+            logs.setOrderId(item.getOrderId());
+            logs.setChangeType("set_erp_account");
+            logs.setChangeMessage(nickName+"设置ERP账户为:" + loginAccount);
+            logs.setChangeTime(LocalDateTime.now());
+            logs.setOperator(nickName);
+            integralOrderLogsService.insertFsIntegralOrderLogs(logs);
         });
         return R.ok();
     }
 
-//    @Log(title = "手动推管易", businessType = BusinessType.INSERT)
+    //    @Log(title = "手动推管易", businessType = BusinessType.INSERT)
     @ApiOperation("批量创建ERP订单")
 //    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
     @Log(title = "积分商品订单", businessType = BusinessType.UPDATE)
@@ -354,9 +362,18 @@ public class FsIntegralOrderController extends BaseController
                     integralOrderDfService.getBaseMapper().insert(df);
                     order.setLoginAccount(df.getLoginAccount());
                     integralOrderMapper.updateById(order);
-                    //日志表,待定
                 }
                 fsIntegralOrderService.createErpOrder(order.getOrderId());
+
+                // 添加积分订单操作记录
+                FsIntegralOrderLogs logs = new FsIntegralOrderLogs();
+                logs.setLogsId(IdUtils.fastUUID());
+                logs.setOrderId(order.getOrderId());
+                logs.setChangeType("create_erp_order");
+                logs.setChangeMessage(getLoginUser().getUser().getNickName()+"创建ERP订单,账户:" + loginAccount);
+                logs.setChangeTime(LocalDateTime.now());
+                logs.setOperator(getLoginUser().getUser().getNickName());
+                integralOrderLogsService.insertFsIntegralOrderLogs(logs);
             }
         }
         return R.ok("推送成功");

+ 109 - 0
fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderLogsController.java

@@ -0,0 +1,109 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsIntegralOrderLogs;
+import com.fs.his.service.IFsIntegralOrderLogsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 订单操作记录Controller
+ *
+ * @author fs
+ * @date 2025-11-25
+ */
+@RestController
+@RequestMapping("/his/logs")
+public class FsIntegralOrderLogsController extends BaseController
+{
+    @Autowired
+    private IFsIntegralOrderLogsService fsIntegralOrderLogsService;
+
+    /**
+     * 查询订单操作记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        startPage();
+        List<FsIntegralOrderLogs> list = fsIntegralOrderLogsService.selectFsIntegralOrderLogsList(fsIntegralOrderLogs);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出订单操作记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:export')")
+    @Log(title = "订单操作记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        List<FsIntegralOrderLogs> list = fsIntegralOrderLogsService.selectFsIntegralOrderLogsList(fsIntegralOrderLogs);
+        ExcelUtil<FsIntegralOrderLogs> util = new ExcelUtil<FsIntegralOrderLogs>(FsIntegralOrderLogs.class);
+        return util.exportExcel(list, "订单操作记录数据");
+    }
+
+    /**
+     * 获取订单操作记录详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:query')")
+    @GetMapping(value = "/{logsId}")
+    public AjaxResult getInfo(@PathVariable("logsId") String logsId)
+    {
+        return AjaxResult.success(fsIntegralOrderLogsService.selectFsIntegralOrderLogsByLogsId(logsId));
+    }
+
+    /**
+     * 新增订单操作记录
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:add')")
+    @Log(title = "订单操作记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        return toAjax(fsIntegralOrderLogsService.insertFsIntegralOrderLogs(fsIntegralOrderLogs));
+    }
+
+    /**
+     * 修改订单操作记录
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:edit')")
+    @Log(title = "订单操作记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        return toAjax(fsIntegralOrderLogsService.updateFsIntegralOrderLogs(fsIntegralOrderLogs));
+    }
+
+    /**
+     * 根据订单ID查询操作记录
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:query')")
+    @GetMapping("/order/{orderId}")
+    public AjaxResult getLogsByOrderId(@PathVariable("orderId") Long orderId)
+    {
+        FsIntegralOrderLogs queryParam = new FsIntegralOrderLogs();
+        queryParam.setOrderId(orderId);
+        List<FsIntegralOrderLogs> list = fsIntegralOrderLogsService.selectFsIntegralOrderLogsList(queryParam);
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 删除订单操作记录
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:remove')")
+    @Log(title = "订单操作记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{logsIds}")
+    public AjaxResult remove(@PathVariable String[] logsIds)
+    {
+        return toAjax(fsIntegralOrderLogsService.deleteFsIntegralOrderLogsByLogsIds(logsIds));
+    }
+}

+ 27 - 3
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -34,6 +34,7 @@ import com.fs.his.dto.TracesDTO;
 import com.fs.his.enums.FsStoreOrderLogEnum;
 import com.fs.his.enums.FsStoreOrderStatusEnum;
 import com.fs.his.enums.ShipperCodeEnum;
+import com.fs.his.mapper.FsUserInformationCollectionMapper;
 import com.fs.his.param.FsFollowMsgParam;
 import com.fs.his.param.FsStoreOrderParam;
 import com.fs.his.param.FsStoreOrderSalesParam;
@@ -125,6 +126,11 @@ public class FsStoreOrderController extends BaseController
 
     @Autowired
     private IFsDfAccountService fsDfAccountService;
+    @Autowired
+    private FsUserInformationCollectionMapper userInformationCollectionMapper;
+    @Autowired
+    private IFsPackageOrderService fsPackageOrderService;
+
     /**
      * 查询订单列表
      */
@@ -648,6 +654,12 @@ public class FsStoreOrderController extends BaseController
     public AjaxResult sendGoods(@RequestBody FsStoreOrder fsStoreOrder)
     {
         String nickName = getLoginUser().getUser().getNickName();
+        if(CloudHostUtils.hasCloudHostName("金牛明医")){
+            FsUserInfoCollectionAndStoreOrderVo info = fsPackageOrderService.selectInformationCollectionByStoreOrderId(fsStoreOrder.getOrderId());
+            if (info != null&&info.getDoctorType2Confirm()!=1) {
+                return AjaxResult.error("药师未确认");
+            }
+        }
         return toAjax(fsStoreOrderService.sendGoods(fsStoreOrder,nickName));
     }
     /**
@@ -751,8 +763,16 @@ public class FsStoreOrderController extends BaseController
         if (orderIds.isEmpty()){
             return R.ok();
         }
-        orderIds.forEach(orderId->{
+        //失败的订单
+        StringBuilder msg = new StringBuilder();
+        for (Long orderId : orderIds) {
             try {
+                //判断是否是信息采集订单 且 药师已经确认
+                FsUserInfoCollectionAndStoreOrderVo info = fsPackageOrderService.selectInformationCollectionByStoreOrderId(orderId);
+                if (info != null&&info.getDoctorType2Confirm()!=1) {
+                    msg.append("订单编号:").append(info.getStoreOrderCode()).append(",推送erp失败,失败原因-信息采集订单,药师暂未确认!\n");
+                    continue;
+                }
                 df.setOrderId(orderId);
                 FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
                 if (temp == null){
@@ -768,8 +788,12 @@ public class FsStoreOrderController extends BaseController
                 throw new RuntimeException(e);
             }
 
-        });
-        return R.ok();
+        }
+        if (msg.toString().isEmpty()){
+            return R.ok();
+        } else {
+            return R.error(msg.toString());
+        }
     }
 
 

+ 5 - 1
fs-admin/src/main/java/com/fs/his/controller/FsUserCouponController.java

@@ -3,6 +3,7 @@ package com.fs.his.controller;
 import java.util.List;
 
 import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.utils.StringUtils;
 import com.fs.his.param.FsUserCouponParam;
 import com.fs.his.param.FsUserCouponSendParam;
 import com.fs.his.vo.FsFollowExcelListVO;
@@ -62,7 +63,10 @@ public class FsUserCouponController extends BaseController
         startPage();
         List<FsUserCouponListVO> list = fsUserCouponService.selectFsUserCouponListVO(fsUserCoupon);
         for (FsUserCouponListVO vo : list) {
-            vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+            String phone = vo.getPhone();
+            if (StringUtils.isNotBlank(phone)) {
+                vo.setPhone(phone.replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+            }
         }
         return getDataTable(list);
     }

+ 61 - 0
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -57,6 +57,12 @@ import com.fs.his.service.impl.FsPackageOrderServiceImpl;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.FsSubOrderResultVO;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
+import com.fs.hisStore.domain.FsStorePaymentScrm;
+import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
+import com.fs.hisStore.service.IFsStorePaymentScrmService;
+import com.fs.huifuPay.domain.HuiFuQueryOrderResult;
+import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayQueryRequest;
+import com.fs.huifuPay.service.HuiFuService;
 import com.fs.im.dto.*;
 import com.fs.im.service.IImService;
 import com.fs.im.service.OpenIMService;
@@ -81,6 +87,8 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.*;
@@ -1069,6 +1077,59 @@ public class Task {
         System.out.println(msgResponseDTO);
     }
 
+    @Autowired
+    FsStorePaymentScrmMapper fsStorePaymentScrmMapper;
+
+    @Autowired
+    HuiFuService huiFuService;
+
+    /**
+     * 查询同步商城订单的支付转台
+     */
+    public void syncOrderPayStatus(){
+        //查询支付状态是待支付的数据
+        FsStorePaymentScrm paymentScrm = new FsStorePaymentScrm();
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
+        paymentScrm.setStatus(0);
+        List<FsStorePaymentScrm> fsStorePaymentScrms = fsStorePaymentScrmMapper.selectFsStorePaymentList(paymentScrm);
+        if(null != fsStorePaymentScrms && !fsStorePaymentScrms.isEmpty()){
+            for (FsStorePaymentScrm payment : fsStorePaymentScrms) {
+                if(StringUtils.isBlank(payment.getTradeNo())){
+                    continue;
+                }
+                V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
+                request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
+                request.setOrgHfSeqId(payment.getTradeNo());
+                HuiFuQueryOrderResult o = null;
+                try {
+                    o = huiFuService.queryOrder(request);
+                } catch (Exception e) {
+                    log.error("查询失败:"+e.getMessage());
+                    continue;
+                }
+                log.info("汇付返回" + o);
+                if ("00000000".equals(o.getResp_code()) && "S".equals(o.getTrans_stat())) {
+                    try {
+                        Date payTime = formatter.parse(o.getEnd_time());
+                        FsStorePaymentScrm payUpdate = new FsStorePaymentScrm();
+                        payUpdate.setPaymentId(payment.getPaymentId());
+                        payUpdate.setPayTime(payTime);
+                        payUpdate.setStatus(1);
+                        payUpdate.setTradeNo(o.getOrg_hf_seq_id());
+                        payUpdate.setBankSerialNo(o.getParty_order_id());
+                        payUpdate.setBankTransactionId(o.getOut_trans_id());
+                        fsStorePaymentScrmMapper.updateFsStorePayment(payUpdate);
+                    } catch (ParseException e) {
+                        log.error("更新失败 payment:{}",payment ,e);
+//                        throw new RuntimeException(e);
+                    }
+
+
+                }
+            }
+        }
+    }
+
 //    @Autowired
 //    private FsStoreMapper fsStoreMapper;
 //    @Autowired

+ 2 - 1
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreAfterSalesScrmController.java

@@ -9,6 +9,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.framework.web.service.TokenService;
 import com.fs.his.domain.FsUser;
@@ -79,7 +80,7 @@ public class FsStoreAfterSalesScrmController extends BaseController
     @GetMapping("/export")
     public AjaxResult export(FsStoreAfterSalesScrm fsStoreAfterSales)
     {
-        if (fsStoreAfterSales.getBeginTime().equals("") && fsStoreAfterSales.getEndTime().equals("")){
+        if (StringUtils.isNotEmpty(fsStoreAfterSales.getBeginTime()) && StringUtils.isNotEmpty(fsStoreAfterSales.getEndTime())){
             fsStoreAfterSales.setBeginTime(null);
             fsStoreAfterSales.setEndTime(null);
         }

+ 41 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java

@@ -7,14 +7,17 @@ import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.CloudHostUtils;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.erp.service.IErpOrderService;
+import com.fs.framework.web.service.TokenService;
 import com.fs.his.domain.FsStoreOrderDf;
 import com.fs.his.service.IFsStoreOrderDfService;
 import com.fs.his.service.IFsUserService;
@@ -48,6 +51,8 @@ public class FsStoreHealthOrderScrmController extends BaseController {
 
     @Autowired
     private IFsStoreOrderStatusScrmService orderStatusService;
+    @Autowired
+    private TokenService tokenService;
 
     @Autowired
     IErpOrderService erpOrderService;
@@ -93,6 +98,7 @@ public class FsStoreHealthOrderScrmController extends BaseController {
             dataTable.setMsg("knt");
         }
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderVO vo : list) {
                 if(vo.getPhone()!=null){
                     vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
@@ -105,6 +111,18 @@ public class FsStoreHealthOrderScrmController extends BaseController {
                         vo.setErpAccount(df.getLoginAccount());
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setPayDelivery(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
 
             }
         }
@@ -269,6 +287,7 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
         //对手机号脱敏
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderItemExportVO vo : list) {
                 if (vo.getUserPhone() != null) {
                     String phone = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2");
@@ -281,6 +300,17 @@ public class FsStoreHealthOrderScrmController extends BaseController {
                     } catch (Exception e) {
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
@@ -314,6 +344,7 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
         //对手机号脱敏
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderItemExportVO vo : list) {
                 if (!StringUtils.isEmpty(vo.getJsonInfo())) {
                     try {
@@ -322,6 +353,16 @@ public class FsStoreHealthOrderScrmController extends BaseController {
                     } catch (Exception e) {
                     }
                 }
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);

+ 43 - 3
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java

@@ -53,6 +53,7 @@ import com.fs.hisStore.service.*;
 import com.fs.hisStore.vo.*;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
+import com.github.pagehelper.PageHelper;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -173,7 +174,7 @@ public class FsStoreOrderScrmController extends BaseController {
     @PreAuthorize("@ss.hasPermi('store:storeOrder:list')")
     @PostMapping("/list")
     public TableDataInfo list(@RequestBody FsStoreOrderParam param) {
-        startPage();
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         if(!StringUtils.isEmpty(param.getCreateTimeRange())){
             param.setCreateTimeList(param.getCreateTimeRange().split("--"));
         }
@@ -194,6 +195,7 @@ public class FsStoreOrderScrmController extends BaseController {
             dataTable.setMsg("knt");
         }
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderVO vo : list) {
                 if(vo.getPhone()!=null){
                     vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
@@ -206,6 +208,18 @@ public class FsStoreOrderScrmController extends BaseController {
                         vo.setErpAccount(df.getLoginAccount());
                     }
                 }
+                //
+                if ((loginUser.getPermissions().contains("his:storeAfterSales:finance")) || loginUser.getPermissions().contains("*:*:*") && (vo.getCost() != null && vo.getTotalNum() != null)) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setPayDelivery(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
             }
         }
         FsStoreOrderListAndStatisticsVo vo = new FsStoreOrderListAndStatisticsVo();
@@ -236,7 +250,7 @@ public class FsStoreOrderScrmController extends BaseController {
     @PreAuthorize("@ss.hasPermi('store:storeOrder:payRemainList')")
     @GetMapping("/payRemainList")
     public TableDataInfo payRemainList(FsStoreOrderParam param) {
-        startPage();
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         if(!StringUtils.isEmpty(param.getCreateTimeRange())){
             param.setCreateTimeList(param.getCreateTimeRange().split("--"));
         }
@@ -435,6 +449,8 @@ public class FsStoreOrderScrmController extends BaseController {
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
         //对手机号脱敏
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
             for (FsStoreOrderItemExportVO vo : list) {
                 if (vo.getUserPhone() != null) {
                     String phone = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2");
@@ -450,6 +466,17 @@ public class FsStoreOrderScrmController extends BaseController {
                     } catch (Exception e) {
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
@@ -486,6 +513,7 @@ public class FsStoreOrderScrmController extends BaseController {
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
         //对手机号脱敏
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderItemExportVO vo : list) {
                 if (!StringUtils.isEmpty(vo.getJsonInfo())) {
                     try {
@@ -494,6 +522,17 @@ public class FsStoreOrderScrmController extends BaseController {
                     } catch (Exception e) {
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
@@ -755,7 +794,8 @@ public class FsStoreOrderScrmController extends BaseController {
 
     @GetMapping("/getCustomerOrderList")
     public TableDataInfo getCustomerOrderList(FsStoreOrderParam param) {
-        startPage();
+//        startPage();
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         List<FsStoreOrderVO> list = fsStoreOrderService.selectFsCustomerStoreOrderListVO(param);
         if (list != null) {
             for (FsStoreOrderVO vo : list) {

+ 23 - 5
fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java

@@ -194,11 +194,11 @@ public class FsStorePaymentScrmController extends BaseController
 
         if(payment.getPayTypeCode().equals("weixin")){
             String json;
-            if (CloudHostUtils.hasCloudHostName("康年堂")){
+//            if (CloudHostUtils.hasCloudHostName("康年堂")){
                 json = configService.selectConfigByKey("his.pay");
-            } else {
-                json = configService.selectConfigByKey("store.pay");
-            }
+//            } else {
+//                json = configService.selectConfigByKey("store.pay");
+//            }
             if (StringUtils.isBlank(json)) {
                 return R.error("缺少支付相关配置");
             }
@@ -226,6 +226,7 @@ public class FsStorePaymentScrmController extends BaseController
                 Map<String, Object> extendInfoMap = new HashMap<>();
                 extendInfoMap.put("org_party_order_id", payment.getBankSerialNo());
                 request.setExtendInfo(extendInfoMap);
+                logger.info("请求参数:"+request);
                 HuiFuRefundResult refund = huiFuService.refund(request);
                 logger.info("退款:"+refund);
                 if((refund.getResp_code().equals("00000000")||refund.getResp_code().equals("00000100"))&&(refund.getTrans_stat().equals("S")||refund.getTrans_stat().equals("P"))){
@@ -243,7 +244,8 @@ public class FsStorePaymentScrmController extends BaseController
                     return R.error(refund.getResp_desc());
                 }
 
-            }else if (payment.getPayMode()!=null&&payment.getPayMode().equals("wx")){
+            }
+            else if (payment.getPayMode()!=null&&payment.getPayMode().equals("wx")){
 
             }
 
@@ -332,4 +334,20 @@ public class FsStorePaymentScrmController extends BaseController
     {
         return toAjax(fsStorePaymentService.deleteFsStorePaymentByIds(paymentIds));
     }
+
+    /**
+     * 一键发货
+     * @return R
+     * **/
+    @Log(title = "发货同步导入", businessType = BusinessType.IMPORT)
+    @PostMapping("/oneClickShipping")
+    public R oneClickShipping() {
+
+        try {
+            return fsStorePaymentService.oneClickShipping();
+        }catch (Exception e){
+            e.getStackTrace();
+        }
+        return R.ok();
+    }
 }

+ 61 - 9
fs-admin/src/main/java/com/fs/hisStore/task/LiveTask.java

@@ -2,7 +2,9 @@ package com.fs.hisStore.task;
 
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.DateUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
@@ -21,7 +23,11 @@ import com.fs.hisStore.dto.DateComparisonConfigDTO;
 import com.fs.hisStore.enums.ShipperCodeEnum;
 import com.fs.hisStore.mapper.FsStoreProductAttrValueScrmMapper;
 import com.fs.hisStore.param.FsStoreOrderAddTuiMoneyParam;
+import com.fs.hisStore.service.IFsStoreOrderScrmService;
 import com.fs.hisStore.service.IFsStoreProductScrmService;
+import com.fs.huifuPay.domain.HuiFuQueryOrderResult;
+import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayQueryRequest;
+import com.fs.huifuPay.service.HuiFuService;
 import com.fs.live.domain.LiveAfterSales;
 import com.fs.live.domain.LiveOrder;
 import com.fs.live.domain.LiveOrderItem;
@@ -49,8 +55,10 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.time.LocalTime;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
@@ -89,9 +97,6 @@ public class LiveTask {
     @Autowired
     private ILiveOrderPaymentService liveOrderPaymentService;
 
-    @Autowired
-    private IFsUserService userService;
-
     @Autowired
     private ICompanyService companyService;
 
@@ -149,8 +154,50 @@ public class LiveTask {
     @Autowired
     private JdbcTemplate jdbcTemplate;
 
+    @Autowired
+    private HuiFuService huiFuService;
+
+    @Autowired
+    private IFsStoreOrderScrmService orderService;
+
+
+    // 订单银行回调数据丢失补偿
+    public void recoveryBankOrder() {
+        // 查询出来最近三十分钟的订单 待支付 未退款
+        List<LiveOrder> list = liveOrderService.selectBankOrder();
+        if(list == null || list.isEmpty()) return;
+        for (LiveOrder liveOrder : list) {
+            List<LiveOrderPayment> liveOrderPayments = liveOrderPaymentMapper.selectLiveOrderPaymentByOrderId(liveOrder.getOrderId());
+            if(liveOrderPayments == null || liveOrderPayments.isEmpty()) continue;
+            for (LiveOrderPayment payment : liveOrderPayments) {
+                V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
+                request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
+                request.setOrgHfSeqId(payment.getTradeNo());
+                HuiFuQueryOrderResult o = null;
+                try {
+                    o = huiFuService.queryOrder(request);
+                } catch (Exception e) {
+                    log.error("查询失败:"+e.getMessage());
+                    continue;
+                }
+                log.info("汇付返回"+o);
+                if ("00000000".equals(o.getResp_code()) && "S".equals(o.getTrans_stat())) {
+                    String[] order=o.getOrg_req_seq_id().split("-");
+                    if ("live".equals(order[0])) {
+                        liveOrderService.payConfirm(1, null, order[1], o.getOrg_hf_seq_id(), o.getOut_trans_id(), o.getParty_order_id());
+                    }
+                }
+            }
+        }
+    }
+
+
     public void PushErp() throws ParseException {
         List<Long> ids = liveOrderMapper.selectOrderIdByNoErp();
+        if(ids == null) return;
+        if (ids.size() > 50) {
+            ids = ids.subList(0, 50);
+        }
         for (Long id : ids) {
             liveOrderService.createOmsOrder(id);
         }
@@ -182,9 +229,14 @@ public class LiveTask {
     public void deliveryOp() {
         List<LiveOrder> list = liveOrderService.selectUpdateExpress();
         if(list == null || list.isEmpty()) return;
-        if (list.size() > 100) {
-            list = list.subList(0, 100);
+        if (list.size() > 50) {
+            list = list.subList(0, 50);
         }
+        Date nowDate = DateUtils.getNowDate();
+        for (LiveOrder order : list) {
+            order.setUpdateTime(nowDate);
+        }
+        liveOrderService.batchUpdateTime(list);
         for (LiveOrder order : list) {
             ErpOrderQueryRequert request = new ErpOrderQueryRequert();
             request.setCode(order.getExtendOrderId());
@@ -317,10 +369,10 @@ public class LiveTask {
     }
 
     public void updateOrderItem() throws ParseException {
-        List<Long> ids = liveOrderService.selectOrderIdByNoErp();
-        for (Long id : ids) {
-            liveOrderService.createOmsOrder(id);
-        }
+//        List<Long> ids = liveOrderService.selectOrderIdByNoErp();
+//        for (Long id : ids) {
+//            liveOrderService.createOmsOrder(id);
+//        }
     }
 
     //每天执行一次

+ 6 - 0
fs-admin/src/main/java/com/fs/hisStore/task/MallStoreTask.java

@@ -165,6 +165,9 @@ public class MallStoreTask
         } else {
             ids = fsStoreOrderMapper.selectFsStoreOrderNoCreateOms();
         }
+        if (!ids.isEmpty() && ids.size() > 50) {
+            ids = ids.subList(0, 50);
+        }
         for (Long id : ids) {
             fsStoreOrderService.createOmsOrder(id);
         }
@@ -204,6 +207,9 @@ public class MallStoreTask
     public void deliveryOp()
     {
         List<FsStoreOrderScrm> list = fsStoreOrderMapper.selectUpdateExpress();
+        if (list != null && list.size() > 50) {
+            list = list.subList(0, 50);
+        }
         for (FsStoreOrderScrm order : list){
             ErpOrderQueryRequert request = new ErpOrderQueryRequert();
             request.setCode(order.getExtendOrderId());

+ 29 - 6
fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesController.java

@@ -1,5 +1,6 @@
 package com.fs.live.controller;
 
+import cn.hutool.core.date.DateTime;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -11,7 +12,9 @@ import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.framework.web.service.TokenService;
+import com.fs.his.domain.FsStoreAfterSalesLogs;
 import com.fs.his.domain.FsUser;
+import com.fs.his.enums.FsStoreAfterSalesStatusEnum;
 import com.fs.his.service.IFsUserService;
 import com.fs.live.domain.LiveAfterSales;
 import com.fs.live.domain.LiveAfterSalesItem;
@@ -61,7 +64,7 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 获取售后记录详细信息
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:query')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:query')")
     @GetMapping(value = "/{id}")
     public R getInfo(@PathVariable("id") Long id)
     {
@@ -79,7 +82,7 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 查询售后记录列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:list')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:list')")
     @GetMapping("/list")
     public TableDataInfo list(LiveAfterSalesVo liveAfterSales)
     {
@@ -94,7 +97,7 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 导出售后记录列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:export')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:export')")
     @Log(title = "售后记录", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(LiveAfterSalesVo liveAfterSales)
@@ -114,7 +117,7 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 新增售后记录
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:add')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:add')")
     @Log(title = "售后记录", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody LiveAfterSales liveAfterSales)
@@ -125,18 +128,28 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 修改售后记录
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:edit')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:edit')")
     @Log(title = "售后记录", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody LiveAfterSales liveAfterSales)
     {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        //操作记录
+        LiveAfterSalesLogs logs = new LiveAfterSalesLogs();
+        logs.setChangeTime(new DateTime());
+        logs.setChangeType(2);
+        logs.setOperator(loginUser.getUser().getNickName());
+        logs.setStoreAfterSalesId(liveAfterSales.getId());
+        logs.setChangeMessage(FsStoreAfterSalesStatusEnum.STATUS_2.getDesc());
+        liveAfterSalesLogsService.insertLiveAfterSalesLogs(logs);
         return toAjax(liveAfterSalesService.updateLiveAfterSales(liveAfterSales));
     }
 
     /**
      * 删除售后记录
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:remove')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:remove')")
     @Log(title = "售后记录", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable Long[] ids)
@@ -180,4 +193,14 @@ public class LiveAfterSalesController extends BaseController
         param.setOperator(loginUser.getUser().getNickName());
         return liveAfterSalesService.cancel(param);
     }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:refund')")
+    @PostMapping("/handleImmediatelyRefund")
+    public R handleImmediatelyRefund(@RequestBody LiveAfterSalesRefundParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setOperator(loginUser.getUser().getNickName());
+        return liveAfterSalesService.handleImmediatelyRefund(param.getOrderId());
+    }
+
 }

+ 1 - 1
fs-admin/src/main/java/com/fs/live/controller/LiveAutoTaskController.java

@@ -66,7 +66,7 @@ public class LiveAutoTaskController extends BaseController
         return getDataTable(list);
     }
 
-    @PreAuthorize("@ss.hasPermi('live:task:list')")
+//    @PreAuthorize("@ss.hasPermi('live:task:list')")
     @GetMapping("/consoleList")
     public TableDataInfo consoleList(LiveAutoTask liveAutoTask)
     {

+ 1 - 1
fs-admin/src/main/java/com/fs/live/controller/LiveController.java

@@ -93,7 +93,7 @@ public class LiveController extends BaseController {
     @Log(title = "直播", businessType = BusinessType.DELETE)
     @DeleteMapping("/{liveIds}")
     public AjaxResult remove(@PathVariable Long[] liveIds) {
-        return toAjax(liveService.deleteLiveByLiveIds(liveIds));
+        return toAjax(liveService.deleteLiveByLiveIds(liveIds, new Live()));
     }
 
     @PreAuthorize("@ss.hasPermi('live:live:query')")

+ 66 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveDataController.java

@@ -1,13 +1,18 @@
 package com.fs.live.controller;
 
+import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.live.domain.LiveData;
 import com.fs.live.param.LiveDataParam;
 import com.fs.live.service.ILiveDataService;
 import com.fs.live.vo.LiveUserFirstVo;
+import com.fs.live.vo.LiveUserDetailExportVO;
 import com.github.pagehelper.PageHelper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -109,5 +114,66 @@ public class LiveDataController extends BaseController {
         return R.ok(liveViewData);
     }
 
+    /**
+     * 查询直播间详情数据(SQL方式)
+     * @param liveId 直播间ID
+     * @return 详情数据
+     */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:query')")
+    @GetMapping("/getLiveDataDetailBySql")
+    public R getLiveDataDetailBySql(@RequestParam Long liveId) {
+        return liveDataService.getLiveDataDetailBySql(liveId);
+    }
+
+    /**
+     * 查询直播间用户详情列表(SQL方式)
+     * @param liveId 直播间ID
+     * @return 用户详情列表
+     */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:query')")
+    @GetMapping("/getLiveUserDetailListBySql")
+    public R getLiveUserDetailListBySql(@RequestParam Long liveId) {
+        return liveDataService.getLiveUserDetailListBySql(liveId);
+    }
+
+    /**
+     * 查询直播间详情数据(查询数据服务器处理方式)
+     * @param liveId 直播间ID
+     * @return 详情数据
+     */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:query')")
+    @GetMapping("/getLiveDataDetailByServer")
+    public R getLiveDataDetailByServer(@RequestParam Long liveId) {
+        return liveDataService.getLiveDataDetailByServer(liveId);
+    }
+
+    /**
+     * 查询直播间用户详情列表(查询数据服务器处理方式)
+     * @param liveId 直播间ID
+     * @return 用户详情列表
+     */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:query')")
+    @GetMapping("/getLiveUserDetailListByServer")
+    public R getLiveUserDetailListByServer(@RequestParam Long liveId) {
+        return liveDataService.getLiveUserDetailListByServer(liveId);
+    }
+
+    /**
+     * 导出直播间用户详情数据
+     * @param liveId 直播间ID
+     * @return Excel文件
+     */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:export')")
+    @Log(title = "直播间用户详情", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportLiveUserDetail")
+    public AjaxResult exportLiveUserDetail(@RequestParam Long liveId) {
+        List<LiveUserDetailExportVO> list = liveDataService.exportLiveUserDetail(liveId);
+        if (list == null || list.isEmpty()) {
+            return AjaxResult.error("未找到用户详情数据");
+        }
+        
+        ExcelUtil<LiveUserDetailExportVO> util = new ExcelUtil<>(LiveUserDetailExportVO.class);
+        return util.exportExcel(list, "直播间用户详情数据");
+    }
 
 }

+ 73 - 18
fs-admin/src/main/java/com/fs/live/controller/LiveOrderController.java

@@ -31,6 +31,8 @@ import com.fs.his.enums.FsStoreOrderLogEnum;
 import com.fs.his.service.IFsDfAccountService;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.hisStore.config.FsErpConfig;
 import com.fs.hisStore.dto.StoreOrderExpressExportDTO;
 import com.fs.hisStore.param.*;
 import com.fs.hisStore.service.IFsExpressScrmService;
@@ -116,6 +118,27 @@ public class LiveOrderController extends BaseController
 
     @Autowired
     private LiveTask liveTask;
+    @Autowired
+    @Qualifier("erpOrderServiceImpl")
+    private IErpOrderService gyOrderService;
+
+    @Autowired
+    @Qualifier("wdtErpOrderServiceImpl")
+    private IErpOrderService wdtOrderService;
+    @Autowired
+    @Qualifier("hzOMSErpOrderServiceImpl")
+    private IErpOrderService hzOMSErpOrderService;
+    @Autowired
+    @Qualifier("dfOrderServiceImpl")
+    private IErpOrderService dfOrderService;
+    @Autowired
+    @Qualifier("k9OrderScrmServiceImpl")
+    private IErpOrderService k9OrderService;
+    @Autowired
+    @Qualifier("JSTErpOrderServiceImpl")
+    private IErpOrderService jSTOrderService;
+    @Autowired
+    private ConfigUtil configUtil;
 
 
 
@@ -178,6 +201,10 @@ public class LiveOrderController extends BaseController
             } else {
                 vo.setCostPrice(BigDecimal.ZERO);
                 vo.setFPrice(BigDecimal.ZERO);
+                vo.setPayDelivery(BigDecimal.ZERO);
+                vo.setBarCode("");
+                vo.setCateName("");
+                vo.setBankTransactionId("");
             }
             vo.setCost(vo.getCostPrice());
 
@@ -202,11 +229,12 @@ public class LiveOrderController extends BaseController
             vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
             // 财务独特字段
             if (loginUser.getPermissions().contains("live:liveOrder:finance") || loginUser.getPermissions().contains("*:*:*")) {
-                vo.setCostPrice(vo.getCostPrice());
+                vo.setCostPrice(vo.getCost());
                 vo.setFPrice(vo.getCostPrice().multiply(BigDecimal.valueOf(Long.parseLong(vo.getTotalNum()))));
             } else {
                 vo.setCostPrice(BigDecimal.ZERO);
                 vo.setFPrice(BigDecimal.ZERO);
+                vo.setBankTransactionId("");
             }
             vo.setCost(vo.getCostPrice());
         }
@@ -432,20 +460,41 @@ public class LiveOrderController extends BaseController
     @PreAuthorize("@ss.hasPermi('live:liveOrder:getEroOrder')")
     @GetMapping("/getEroOrder")
     public R getEroOrder(@RequestParam("extendOrderId") String extendOrderId) {
+        IErpOrderService erpOrderService = getErpService();
         ErpOrderQueryRequert request = new ErpOrderQueryRequert();
         request.setCode(extendOrderId);
-        if(StringUtils.isEmpty(extendOrderId)) return R.error("物流订单ID为空!");
-
-        LiveOrder order = liveOrderService.selectLiveOrderByExtendId(extendOrderId);
-
-        // 根据仓库code找erp
-//        if(com.fs.common.utils.StringUtils.isNotBlank(order.getStoreHouseCode())){
-//            String erp = fsWarehousesMapper.selectErpByCode(order.getStoreHouseCode());
-//            ErpContextHolder.setErpType(erp);
-//        }
-
-//        ErpOrderQueryResponse response = erpOrderService.getOrderLive(request);
-        return R.ok().put("data","123");
+        ErpOrderQueryResponse response = erpOrderService.getLiveOrder(request);
+        return R.ok().put("data",response);
+    }
+    private IErpOrderService getErpService(){
+        //判断是否开启erp
+        IErpOrderService erpOrderService = null;
+        FsErpConfig erpConfig = configUtil.getErpConfig();
+        Integer erpOpen = erpConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1) {
+            //判断erp类型
+            Integer erpType = erpConfig.getErpType();
+            if (erpType != null) {
+                if (erpType == 1){
+                    //管易
+                    erpOrderService =  gyOrderService;
+                } else if (erpType == 2){
+                    //旺店通
+                    erpOrderService =  wdtOrderService;
+                } else if (erpType == 3){
+                    //
+                    erpOrderService =  hzOMSErpOrderService;
+                } else if (erpType == 4){
+                    //代服
+                    erpOrderService =  dfOrderService;
+                }else if(erpType == 5){
+                    erpOrderService=jSTOrderService;
+                }else if(erpType == 6){
+                    erpOrderService=k9OrderService;
+                }
+            }
+        }
+        return erpOrderService;
     }
 
     @Log(title = "冻结、解冻佣金", businessType = BusinessType.UPDATE)
@@ -484,8 +533,12 @@ public class LiveOrderController extends BaseController
     {
         logger.info("手动推管易 订单号: {}",orderCode);
         LiveOrder order=liveOrderService.selectOrderIdByOrderCode(orderCode);
-        liveOrderService.createOmsOrder(order.getOrderId());
-        return R.ok();
+        if (orderPaymentService.selectByBussinessId(order.getOrderId()) != null) {
+            liveOrderService.createOmsOrder(order.getOrderId());
+            return R.ok();
+        }
+        return R.error("订单未支付!");
+
     }
 
     @Log(title = "同步管易物流单号", businessType = BusinessType.UPDATE)
@@ -636,9 +689,11 @@ public class LiveOrderController extends BaseController
                     orderLogsService.create(orderId, FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getValue(),
                             nickName + " " +FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getDesc() + ":" + df.getLoginAccount());
                 }
-                liveOrderService.createOmsOrder(orderId);
-                orderLogsService.create(orderId, FsStoreOrderLogEnum.PUSH_ORDER_ERP.getValue(),
-                        nickName + " " +FsStoreOrderLogEnum.PUSH_ORDER_ERP.getDesc() + ":" + df.getLoginAccount());
+                if (orderPaymentService.selectByBussinessId(orderId) != null) {
+                    liveOrderService.createOmsOrder(orderId);
+                    orderLogsService.create(orderId, FsStoreOrderLogEnum.PUSH_ORDER_ERP.getValue(),
+                            nickName + " " +FsStoreOrderLogEnum.PUSH_ORDER_ERP.getDesc() + ":" + df.getLoginAccount());
+                }
             } catch (ParseException e) {
                 throw new RuntimeException(e);
             }

+ 326 - 0
fs-admin/src/main/java/com/fs/qw/controller/IpadAllocationRecordsController.java

@@ -0,0 +1,326 @@
+package com.fs.qw.controller;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.IpadAllocationDetails;
+import com.fs.qw.domain.IpadAllocationRecords;
+import com.fs.qw.domain.QwIpadServer;
+import com.fs.qw.mapper.IpadAllocationRecordsMapper;
+import com.fs.qw.param.ServerParam;
+import com.fs.qw.service.IIpadAllocationRecordsService;
+import com.fs.qw.service.IQwIpadServerService;
+import com.fs.qw.utils.HMACAuth;
+import com.fs.qw.vo.IpadAllocationRecordsVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 分配记录Controller
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+@RestController
+@RequestMapping("/qw/records")
+@Slf4j
+public class IpadAllocationRecordsController extends BaseController {
+    @Autowired
+    private IIpadAllocationRecordsService ipadAllocationRecordsService;
+    @Autowired
+    private IQwIpadServerService serverService;
+
+
+    @Autowired
+    private IpadAllocationRecordsMapper ipadAllocationRecordsMapper;
+    @Value("${ipad.watchUrl:https://manwatch.ylrzcloud.com/prod-api}")
+    private String ipadServerUrl;
+
+    /**
+     * 查询分配记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(IpadAllocationRecords ipadAllocationRecords) {
+        startPage();
+        List<IpadAllocationRecords> list = ipadAllocationRecordsService.selectIpadAllocationRecordsList(ipadAllocationRecords);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出分配记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:export')")
+    @Log(title = "分配记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(IpadAllocationRecords ipadAllocationRecords) {
+        List<IpadAllocationRecords> list = ipadAllocationRecordsService.selectIpadAllocationRecordsList(ipadAllocationRecords);
+        ExcelUtil<IpadAllocationRecords> util = new ExcelUtil<IpadAllocationRecords>(IpadAllocationRecords.class);
+        return util.exportExcel(list, "分配记录数据");
+    }
+
+    /**
+     * 获取分配记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return AjaxResult.success(ipadAllocationRecordsService.selectIpadAllocationRecordsById(id));
+    }
+
+    /**
+     * 新增分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:add')")
+    @Log(title = "分配记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody IpadAllocationRecords ipadAllocationRecords) {
+        return toAjax(ipadAllocationRecordsService.insertIpadAllocationRecords(ipadAllocationRecords));
+    }
+
+    /**
+     * 修改分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:edit')")
+    @Log(title = "分配记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody IpadAllocationRecords ipadAllocationRecords) {
+        return toAjax(ipadAllocationRecordsService.updateIpadAllocationRecords(ipadAllocationRecords));
+    }
+
+    /**
+     * 删除分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:remove')")
+    @Log(title = "分配记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(ipadAllocationRecordsService.deleteIpadAllocationRecordsByIds(ids));
+    }
+
+    //根据记录id查询他的服务器详情
+    @GetMapping("/server/{id}")
+    public AjaxResult getServerInfo(@PathVariable("id") Long id) {
+        IpadAllocationRecords ipadAllocationRecords = ipadAllocationRecordsService.selectIpadAllocationRecordsById(id);
+        if (ipadAllocationRecords == null) {
+            return AjaxResult.error("记录不存在");
+        }
+        List<IpadAllocationDetails> detailsList = JSON.parseArray(ipadAllocationRecords.getServerJson(), IpadAllocationDetails.class);
+        return AjaxResult.success(detailsList);
+    }
+
+    @Value("${ipad.fsCompanyId:13}")
+    private Long companyId;
+    //发起申请ipad服务器
+    @GetMapping("/apply")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult apply(Integer applyCount,String area) throws Exception {
+        //校验count是否为正整数
+        if (applyCount == null || applyCount <= 0) {
+            return AjaxResult.error("申请数量必须为正整数");
+        }
+        //校验area是否为空
+        if (area == null || area.isEmpty()) {
+            return AjaxResult.error("区域不能为空");
+        }
+
+        //插入数据库申请表
+        IpadAllocationRecords ipadAllocationRecords = new IpadAllocationRecords();
+        ipadAllocationRecords.setCompanyId(13L);
+        ipadAllocationRecords.setApplyQuantity(applyCount);
+        ipadAllocationRecords.setSubmitTime(LocalDateTime.now());
+        ipadAllocationRecords.setRegion(area);
+        ipadAllocationRecordsMapper.insert(ipadAllocationRecords);
+        //发起http请求
+        //调用ipad服务器申请接口
+        HashMap<Object, Object> param = new HashMap<>();
+        param.put("allocationId", ipadAllocationRecords.getId());//携带id过去,以后查询结果
+        param.put("companyId", companyId);//公司id自己去配置文件改自己公司的id去腕表找
+        param.put("region", area);//区域
+        param.put("applyQuantity", applyCount);
+        String paramJson = JSON.toJSONString(param);
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/addRecords");
+        log.info("发起请求,申请参数:{},url:{}", paramJson, ipadServerUrl + "/ipad/records/addRecords");
+        post.body(paramJson);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+        log.info("发起ipad服务器申请,申请数量:{},申请id:{},申请结果:{}", applyCount, ipadAllocationRecords.getId(), result);
+        //code不为200,回滚数据库
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+        if (response == null || (Integer) response.get("code") != 200) {
+            ipadAllocationRecordsMapper.deleteById(ipadAllocationRecords.getId());
+            throw new Exception("申请失败");
+        }
+        return AjaxResult.success("申请成功");
+    }
+
+    //批量更新分配记录状态
+    @PostMapping("/batchUpdate")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult batchUpdate(@RequestBody Long[] ids) throws Exception {
+        //校验ids是否为空
+        if (ids == null || ids.length == 0) {
+            return AjaxResult.error("ids不能为空");
+        }
+        //发起http请求
+        //调用ipad服务器更新接口
+        HashMap<Object, Object> param = new HashMap<>();
+        param.put("ids", ids);
+        String paramJson = JSON.toJSONString(param);
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/updateRecords");
+        post.body(paramJson);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+
+        log.info("发起ipad服务器更新状态,更新数量:{},拉取结果:{}", ids.length, result);
+
+        //解析返回的JSON结果
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+
+        //首先判断code是否为200
+        if (response != null && (Integer) response.get("code") == 200) {
+            //获取data字段
+            Object data = response.get("data");
+
+            //将data转换为List<IpadAllocationRecordsVO>
+            List<IpadAllocationRecordsVO> recordsList = JSON.parseArray(JSON.toJSONString(data), IpadAllocationRecordsVO.class);
+
+            for (IpadAllocationRecordsVO vo : recordsList) {
+                IpadAllocationRecords ipadAllocationRecords = ipadAllocationRecordsMapper.selectById(vo.getId());
+                if (!ipadAllocationRecords.getAuditStatus().equals(0)) {
+                    ipadAllocationRecords.setServerJson(JSON.toJSONString(vo.getDetailsList()));
+                    ipadAllocationRecordsMapper.updateById(ipadAllocationRecords);
+                    log.info("分配记录id:{},状态已更新,无需重复更新", vo.getId());
+                    continue;
+                }
+                log.info("更新分配记录,记录id:{},更新状态:{},分配数量:{},审核时间:{},拒绝原因:{},公司名称:{}",
+                        vo.getId(), vo.getAuditStatus(), vo.getAllocatedQuantity(), vo.getReviewTime(), vo.getRejectionReason(), vo.getCompanyName());
+                if (ipadAllocationRecords != null) {
+                    ipadAllocationRecords.setAuditStatus(vo.getAuditStatus());
+                    ipadAllocationRecords.setUpdatedTime(LocalDateTime.now());
+                    ipadAllocationRecords.setAllocatedQuantity(vo.getAllocatedQuantity());
+                    ipadAllocationRecords.setReviewTime(vo.getReviewTime());
+                    ipadAllocationRecords.setRejectionReason(vo.getRejectionReason());
+                    ipadAllocationRecords.setCompanyName(vo.getCompanyName());
+                    ipadAllocationRecords.setServerJson(JSON.toJSONString(vo.getDetailsList()));
+                    ipadAllocationRecords.setRegion(vo.getRegion());
+                    ipadAllocationRecordsMapper.updateById(ipadAllocationRecords);
+                }
+                List<IpadAllocationDetails> detailsList = vo.getDetailsList();
+                for (IpadAllocationDetails details : detailsList) {
+                    //去查询是否有相同端口和ip的服务器,有则去更新total_count和count都加上allocatedSeats,没有则添加一条服务器记录。
+                    Integer allocatedSeats = details.getAllocatedSeats();
+                    QwIpadServer server = serverService.selectIpAndPort(details.getIpAddress(), details.getPort());
+                    if (server != null) {
+                        server.setTotalCount(server.getTotalCount() + allocatedSeats);
+                        server.setCount(server.getCount() + allocatedSeats);
+                        server.setUpdateTime(DateUtils.getNowDate());
+//                        server.setRecordId(details.getAllocationId());//后面的审核记录会覆盖之前的审核记录id,这里存的是最新的审核记录id
+                        serverService.updateById(server);
+                    } else {
+                        //添加一条服务器记录
+                        QwIpadServer newServer = new QwIpadServer();
+//                        newServer.setRecordId(details.getAllocationId());
+                        newServer.setIp(details.getIpAddress());
+                        newServer.setPort(String.valueOf(details.getPort()));
+                        newServer.setTotalCount(Long.valueOf(allocatedSeats));
+                        newServer.setCount(Long.valueOf(allocatedSeats));
+                        newServer.setAddressId("520000000000");
+                        newServer.setUrl(details.getAccessUrl());
+                        newServer.setCreateTime(DateUtils.getNowDate());
+                        serverService.getBaseMapper().insert(newServer);
+                    }
+                }
+            }
+
+            //返回成功结果
+            return AjaxResult.success("更新成功", recordsList);
+        } else {
+            //返回错误结果
+            String errorMsg = response != null ? (String) response.get("msg") : "更新失败";
+            return AjaxResult.error(errorMsg);
+        }
+    }
+
+    //释放已申请的ipad服务器
+    //释放哪条记录的那台服务器多少台
+    @PostMapping("/release")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult release(@RequestBody ServerParam serverParam) throws Exception {
+        //校验参数是否为空
+        if (serverParam == null) {
+            return AjaxResult.error("serverParam不能为空");
+        }
+
+        QwIpadServer server = serverService.selectIpAndPort(serverParam.getIpAddress(), Long.valueOf(serverParam.getPort()));
+        if (server == null) {
+            log.info("服务器地址:{},端口:{},未查询到服务器记录,无法释放", serverParam.getIpAddress(), serverParam.getPort());
+            return AjaxResult.error("未查询到服务器记录,无法释放");
+        }
+        if (serverParam.getReleaseCount() > server.getCount()) {
+            log.info("服务器id:{},释放数量:{},剩余数量:{},释放数量大于剩余数量,无法释放", server.getId(), serverParam.getReleaseCount(), server.getCount());
+            return AjaxResult.error("释放数量大于剩余数量,无法释放");
+        }
+        IpadAllocationRecords record = ipadAllocationRecordsMapper.selectById(serverParam.getRecordId());
+        if (record == null) {
+            log.info("服务器id:{},释放数量:{},申请记录为空,无法释放", server.getId(), serverParam.getReleaseCount());
+            return AjaxResult.error("申请记录为空,无法释放");
+        }
+        record.setAllocatedQuantity(record.getAllocatedQuantity() - serverParam.getReleaseCount());
+//        record.setApplyQuantity(record.getApplyQuantity() - serverParam.getReleaseCount());
+
+        server.setCount(server.getCount() - serverParam.getReleaseCount());
+        server.setTotalCount(server.getTotalCount() - serverParam.getReleaseCount());
+        ipadAllocationRecordsMapper.updateById(record);
+        serverService.updateById(server);
+
+        ServerParam build = ServerParam.builder()
+                .ipadServerId(serverParam.getIpadServerId())
+                .recordId(serverParam.getRecordId())
+                .releaseCount(serverParam.getReleaseCount())
+                .ipAddress(serverParam.getIpAddress())
+                .port(serverParam.getPort())
+                .build();
+
+        //发起http请求
+        String body = JSON.toJSONString(build);
+
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/release");
+        post.body(body);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+        log.info("发起ipad服务器释放状态,释放数量:{},拉取结果:{}", body, result);
+
+        //解析返回的JSON结果
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+
+        //首先判断code是否为200,不是回滚事务
+        if (!response.get("code").equals(200)) {
+            String errorMsg = response != null ? (String) response.get("msg") : "释放失败";
+            throw new Exception(errorMsg);
+        }
+        return AjaxResult.success("释放成功");
+    }
+}

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

@@ -1,21 +1,24 @@
 package com.fs.qw.qwTask;
 
 import com.fs.course.service.IFsUserCourseService;
-import com.fs.qw.service.IQwExternalContactService;
-import com.fs.qw.service.IQwGroupMsgService;
-import com.fs.qw.service.IQwMaterialService;
-import com.fs.qw.service.IQwUserService;
+import com.fs.qw.domain.QwIpadServerLog;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.service.*;
 import com.fs.sop.service.impl.QwSopLogsServiceImpl;
 import com.fs.sop.service.impl.QwSopServiceImpl;
 import com.fs.sop.service.ISopUserLogsService;
 import com.fs.statis.IFsStatisQwWatchService;
 import com.fs.statis.service.FsStatisSalerWatchService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.fs.wxwork.dto.WxWorkGetQrCodeDTO;
+import com.fs.wxwork.service.WxWorkService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.List;
 
 @Component("qwTask")
 public class qwTask {
@@ -51,6 +54,25 @@ public class qwTask {
     private IQwMaterialService iQwMaterialService;
 
 
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    private IQwIpadServerService ipadServerService;
+
+    @Autowired
+    private IQwIpadServerLogService qwIpadServerLogService;
+
+    @Autowired
+    private IQwIpadServerUserService qwIpadServerUserService;
+
+    @Autowired
+    private IQwExternalContactService externalContactService;
+
+    @Autowired
+    private WxWorkService wxWorkService;
+
+
     //正在使用
     public void qwExternalContact()
     {
@@ -199,4 +221,69 @@ public class qwTask {
     public void updateMaterialByTwoDays(){
         iQwMaterialService.updateQwMaterialByQw();
     }
+
+    /**
+     * 统计 每天的官方群发统计
+     */
+    public void countQwApiAopLogToken(){
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        // 获取当前日期(只包含年月日)
+        LocalDate currentDate = LocalDate.now();
+
+        String todayStr = currentDate.format(dateFormatter);
+         qwSopLogsService.countQwApiAopLogToken(todayStr);
+
+
+    }
+
+    /**
+     * 定时清除 占着茅坑不拉屎的ipad 账号
+     */
+    public void selectQwUserByUnbindIpad(){
+        List<QwUser> list = qwUserMapper.selectQwUserByTest();
+        for (QwUser qwUser : list) {
+            try {
+                Integer serverStatus = qwUser.getServerStatus();
+                Long serverId = qwUser.getServerId();
+                if (serverStatus==0){
+                    System.out.println("不需要解绑");
+                }
+                if (serverId==null){
+                    System.out.println("serverId不存在");
+                }
+                QwUser u = new QwUser();
+                u.setId(qwUser.getId());
+                u.setServerId(null);
+                u.setServerStatus(0);
+                qwUserMapper.updateQwUser(u);
+                ipadServerService.addServer(serverId);
+                QwIpadServerLog qwIpadServerLog = new QwIpadServerLog();
+                qwIpadServerLog.setType(2);
+                qwIpadServerLog.setTilie("解绑");
+                qwIpadServerLog.setServerId(serverId);
+                qwIpadServerLog.setQwUserId(qwUser.getId());
+                qwIpadServerLog.setCompanyUserId(qwUser.getCompanyUserId());
+                qwIpadServerLog.setCompanyId(qwUser.getCompanyId());
+                qwIpadServerLog.setCreateTime(new Date());
+                qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog);
+                qwIpadServerUserService.deleteQwIpadServerUserByQwUserId(qwUser.getId());
+                WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
+                wxWorkGetQrCodeDTO.setUuid(qwUser.getUid());
+                wxWorkService.LoginOut(wxWorkGetQrCodeDTO,qwUser.getServerId());
+                updateIpadStatus(qwUser.getId(),0);
+            } catch (Exception e) {
+                System.out.println("解绑ipad报错"+e);
+
+            }
+        }
+    }
+
+
+    void updateIpadStatus(Long id ,Integer status){
+        QwUser u = new QwUser();
+        u.setId(id);
+        u.setIpadStatus(status);
+        qwUserMapper.updateQwUser(u);
+    }
+
 }

+ 30 - 39
fs-admin/src/main/java/com/fs/web/controller/system/SysConfigController.java

@@ -30,13 +30,10 @@ import com.fs.system.service.ISysConfigService;
 
 /**
  * 参数配置 信息操作处理
- *
-
  */
 @RestController
 @RequestMapping("/system/config")
-public class SysConfigController extends BaseController
-{
+public class SysConfigController extends BaseController {
     @Autowired
     private ISysConfigService configService;
     @Autowired
@@ -47,8 +44,7 @@ public class SysConfigController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:config:list')")
     @GetMapping("/list")
-    public TableDataInfo list(SysConfig config)
-    {
+    public TableDataInfo list(SysConfig config) {
         startPage();
         List<SysConfig> list = configService.selectConfigList(config);
         return getDataTable(list);
@@ -57,8 +53,7 @@ public class SysConfigController extends BaseController
     @Log(title = "参数管理", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:config:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysConfig config)
-    {
+    public AjaxResult export(SysConfig config) {
         List<SysConfig> list = configService.selectConfigList(config);
         ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
         return util.exportExcel(list, "参数数据");
@@ -69,8 +64,7 @@ public class SysConfigController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:config:query')")
     @GetMapping(value = "/{configId}")
-    public AjaxResult getInfo(@PathVariable Long configId)
-    {
+    public AjaxResult getInfo(@PathVariable Long configId) {
         return AjaxResult.success(configService.selectConfigById(configId));
     }
 
@@ -78,8 +72,7 @@ public class SysConfigController extends BaseController
      * 根据参数键名查询参数值
      */
     @GetMapping(value = "/configKey/{configKey}")
-    public AjaxResult getConfigKey(@PathVariable String configKey)
-    {
+    public AjaxResult getConfigKey(@PathVariable String configKey) {
         return AjaxResult.success(configService.selectConfigByKey(configKey));
     }
 
@@ -90,10 +83,8 @@ public class SysConfigController extends BaseController
     @Log(title = "参数管理", businessType = BusinessType.INSERT)
     @PostMapping
     @RepeatSubmit
-    public AjaxResult add(@Validated @RequestBody SysConfig config)
-    {
-        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
-        {
+    public AjaxResult add(@Validated @RequestBody SysConfig config) {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
             return AjaxResult.error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
         }
         config.setCreateBy(getUsername());
@@ -106,10 +97,8 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:edit')")
     @Log(title = "参数管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysConfig config)
-    {
-        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
-        {
+    public AjaxResult edit(@Validated @RequestBody SysConfig config) {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
             return AjaxResult.error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
         }
         config.setUpdateBy(getUsername());
@@ -122,8 +111,7 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:remove')")
     @Log(title = "参数管理", businessType = BusinessType.DELETE)
     @DeleteMapping("/{configIds}")
-    public AjaxResult remove(@PathVariable Long[] configIds)
-    {
+    public AjaxResult remove(@PathVariable Long[] configIds) {
         configService.deleteConfigByIds(configIds);
         return success();
     }
@@ -134,50 +122,53 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:remove')")
     @Log(title = "参数管理", businessType = BusinessType.CLEAN)
     @DeleteMapping("/refreshCache")
-    public AjaxResult refreshCache()
-    {
+    public AjaxResult refreshCache() {
         configService.resetConfigCache();
         return AjaxResult.success();
     }
 
     @GetMapping(value = "/getConfigByKey/{configKey}")
-    public AjaxResult getConfigByKey(@PathVariable String configKey)
-    {
-        SysConfig config=configService.selectConfigByConfigKey(configKey);
+    public AjaxResult getConfigByKey(@PathVariable String configKey) {
+        SysConfig config = configService.selectConfigByConfigKey(configKey);
         return AjaxResult.success(config);
     }
 
     @PostMapping(value = "/updateConfigByKey")
     @Log(title = "更改参数", businessType = BusinessType.UPDATE)
     @RepeatSubmit
-    public AjaxResult updateConfigByKey(@Validated @RequestBody SysConfig config)
-    {
+    public AjaxResult updateConfigByKey(@Validated @RequestBody SysConfig config) {
         config.setCreateBy(SecurityUtils.getUsername());
-        return toAjax(configService.updateConfig(config));
+        //修复只能更新的BUG
+        if (null != config.getConfigId()) {
+            return toAjax(configService.updateConfig(config));
+        } else {
+            return toAjax(configService.insertConfig(config));
+        }
+
     }
 
 
     /**
      * 启用-关闭小程序销售管理
+     *
      * @param bock
      * @return
      */
     @GetMapping("/updateIsTownOn")
-    public R queryIsTownOn(String bock, String appId)
-    {
-        String key = appId+"start_status_001";
+    public R queryIsTownOn(String bock, String appId) {
+        String key = appId + "start_status_001";
         String start = redisCache.getCacheObject(key);
-        if (ObjectUtil.isNotEmpty(bock)){
-            if (bock.equals("001")){
-                redisCache.setCacheObject(key,bock);
+        if (ObjectUtil.isNotEmpty(bock)) {
+            if (bock.equals("001")) {
+                redisCache.setCacheObject(key, bock);
                 return R.ok("调整成功");
-            }else if (bock.equals("002")){
-                redisCache.setCacheObject(key,bock);
+            } else if (bock.equals("002")) {
+                redisCache.setCacheObject(key, bock);
                 return R.ok("调整成功");
             }
 
         }
-        return R.ok().put("date",start);
+        return R.ok().put("date", start);
     }
 
 }

+ 284 - 0
fs-common/src/main/java/com/fs/common/utils/RedwoodCryptoUtil.java

@@ -0,0 +1,284 @@
+package com.fs.common.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.*;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeMap;
+
+/**
+ * 红杉健康开放平台加解密工具类
+ * 遵循文档规则:AES-256-CBC加密内容 + RSA加密AES密钥 + MD5签名
+ */
+public class RedwoodCryptoUtil {
+
+    // 加密算法配置(与文档一致)
+    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
+    private static final String AES_KEY_ALGORITHM = "AES";
+    private static final int AES_KEY_LENGTH = 256;
+    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
+    private static final String RSA_KEY_ALGORITHM = "RSA";
+    private static final String SIGN_ALGORITHM = "MD5";
+
+    // 配置参数(需根据实际环境替换)
+    private final String appSecret; // 平台提供的应用秘钥(作为AES初始化向量IV)
+    private final String platformPublicKey; // 红杉平台RSA公钥(加密AES密钥用)
+    private final String thirdPrivateKey; // 三方平台RSA私钥(解密响应密钥用)
+
+    /**
+     * 构造函数:初始化配置参数
+     *
+     * @param appSecret         平台应用秘钥(文档中appsecret)
+     * @param platformPublicKey 红杉平台RSA公钥(Base64编码)
+     * @param thirdPrivateKey   三方平台RSA私钥(Base64编码)
+     */
+    public RedwoodCryptoUtil(String appSecret, String platformPublicKey, String thirdPrivateKey) {
+        this.appSecret = appSecret;
+        this.platformPublicKey = platformPublicKey;
+        this.thirdPrivateKey = thirdPrivateKey;
+    }
+
+    /**
+     * 加密请求参数:生成接口所需的content、key、sign
+     *
+     * @param plainParam 明文请求参数(Map格式)
+     * @return 加密后的请求参数Map(包含content、key、sign)
+     * @throws Exception 加密异常
+     */
+    public Map<String, String> encryptRequest(Map<String, Object> plainParam) throws Exception {
+        // 1. 参数按ASCII码排序并转为JSON字符串(不转义Unicode)
+        Map<String, Object> sortedMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        sortedMap.putAll(plainParam);
+        String contentStr = new String(
+                JSON.toJSONBytes(sortedMap, SerializerFeature.BrowserCompatible)
+        );
+
+        // 2. 生成32位随机AES密钥(randStr)
+        String aesKey = generateRandomAesKey();
+
+        // 3. AES-256-CBC加密contentStr(IV为appSecret)
+        String encryptedContent = aesEncrypt(contentStr, aesKey, appSecret);
+
+        // 4. MD5生成签名(对原始contentStr)
+        String sign = generateSign(contentStr);
+
+        // 5. 用平台公钥加密AES密钥(RSA-PKCS1-SHA256)
+        String encryptedAesKey = rsaEncrypt(aesKey, platformPublicKey);
+
+        // 6. 返回加密结果(Base64编码后)
+        Map<String, String> encryptedParam = new HashMap<>();
+        encryptedParam.put("content", Base64.encodeBase64String(encryptedContent.getBytes()));
+        encryptedParam.put("key", Base64.encodeBase64String(encryptedAesKey.getBytes()));
+        encryptedParam.put("sign", sign);
+        return encryptedParam;
+    }
+
+    /**
+     * 解密响应参数:从content、key、sign中还原明文
+     *
+     * @param encryptedResponse 加密响应参数(包含content、key、sign)
+     * @return 明文响应结果(Map格式)
+     * @throws Exception 解密异常
+     */
+    public Map<String, Object> decryptResponse(Map<String, String> encryptedResponse) throws Exception {
+        // 1. 提取加密字段并Base64解码
+        String encryptedContent = new String(Base64.decodeBase64(encryptedResponse.get("content")));
+        String encryptedAesKey = new String(Base64.decodeBase64(encryptedResponse.get("key")));
+        String sign = encryptedResponse.get("sign");
+
+        // 2. 用三方私钥解密AES密钥
+        String aesKey = rsaDecrypt(encryptedAesKey, thirdPrivateKey);
+
+        // 3. AES-256-CBC解密content(IV为appSecret)
+        String contentStr = aesDecrypt(encryptedContent, aesKey, appSecret);
+
+        // 4. 验证签名(防止数据篡改)
+        if (!verifySign(contentStr, sign)) {
+            throw new SecurityException("签名验证失败,数据可能被篡改");
+        }
+
+        // 5. 解析JSON为Map返回
+        return JSON.parseObject(contentStr, Map.class);
+    }
+
+    /**
+     * AES加密(AES-256-CBC)
+     */
+    private String aesEncrypt(String content, String key, String iv) throws Exception {
+        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), AES_KEY_ALGORITHM);
+        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
+        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
+        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
+        byte[] encryptedBytes = cipher.doFinal(content.getBytes("UTF-8"));
+        return Base64.encodeBase64String(encryptedBytes);
+    }
+
+    /**
+     * AES解密(AES-256-CBC)
+     */
+    private String aesDecrypt(String encryptedContent, String key, String iv) throws Exception {
+        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), AES_KEY_ALGORITHM);
+        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
+        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
+        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
+        byte[] decryptedBytes = cipher.doFinal(Base64.decodeBase64(encryptedContent));
+        return new String(decryptedBytes, "UTF-8");
+    }
+
+    /**
+     * RSA加密(用公钥加密AES密钥)
+     */
+    private String rsaEncrypt(String content, String publicKeyStr) throws Exception {
+        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
+        PublicKey publicKey = KeyFactory.getInstance(RSA_KEY_ALGORITHM).generatePublic(keySpec);
+        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+        byte[] encryptedBytes = cipher.doFinal(content.getBytes("UTF-8"));
+        return Base64.encodeBase64String(encryptedBytes);
+    }
+
+    /**
+     * RSA解密(用私钥解密AES密钥)
+     */
+    private String rsaDecrypt(String encryptedContent, String privateKeyStr) throws Exception {
+        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
+        PrivateKey privateKey = KeyFactory.getInstance(RSA_KEY_ALGORITHM).generatePrivate(keySpec);
+        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+        cipher.init(Cipher.DECRYPT_MODE, privateKey);
+        byte[] decryptedBytes = cipher.doFinal(Base64.decodeBase64(encryptedContent));
+        return new String(decryptedBytes, "UTF-8");
+    }
+
+    /**
+     * 生成MD5签名
+     */
+    private String generateSign(String content) throws Exception {
+        MessageDigest md5 = MessageDigest.getInstance(SIGN_ALGORITHM);
+        byte[] signBytes = md5.digest(content.getBytes("UTF-8"));
+        return bytesToHex(signBytes);
+    }
+
+    /**
+     * 验证MD5签名
+     */
+    private boolean verifySign(String content, String sign) throws Exception {
+        String generatedSign = generateSign(content);
+        return generatedSign.equalsIgnoreCase(sign);
+    }
+
+    /**
+     * 生成32位随机AES密钥(字母+数字)
+     */
+    private String generateRandomAesKey() {
+        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+        StringBuilder sb = new StringBuilder(32);
+        Random random = new SecureRandom();
+        for (int i = 0; i < 32; i++) {
+            sb.append(chars.charAt(random.nextInt(chars.length())));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 字节数组转16进制字符串
+     */
+    private String bytesToHex(byte[] bytes) {
+        StringBuilder hex = new StringBuilder();
+        for (byte b : bytes) {
+            String hexStr = Integer.toHexString(b & 0xFF);
+            if (hexStr.length() == 1) {
+                hex.append("0");
+            }
+            hex.append(hexStr);
+        }
+        return hex.toString();
+    }
+
+    /**
+     * 生成RSA密钥对,用于platformPublicKey和thirdPrivateKey
+     */
+    public static void generateRSAKeyPair() throws Exception {
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+        keyPairGenerator.initialize(2048); // 使用2048位密钥长度
+        KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+        PublicKey publicKey = keyPair.getPublic();
+        PrivateKey privateKey = keyPair.getPrivate();
+
+        // 获取Base64编码的公钥和私钥
+        String publicKeyStr = Base64.encodeBase64String(publicKey.getEncoded());
+        String privateKeyStr = Base64.encodeBase64String(privateKey.getEncoded());
+
+        System.out.println("公钥 (platformPublicKey):");
+        System.out.println(wrapPublicKey(publicKeyStr));
+        System.out.println();
+        System.out.println("私钥 (thirdPrivateKey):");
+        System.out.println(privateKeyStr);
+    }
+
+    /**
+     * 将公钥包装成PEM格式
+     */
+    private static String wrapPublicKey(String publicKey) {
+        return "-----BEGIN PUBLIC KEY-----\n" +
+                splitLines(publicKey) +
+                "\n-----END PUBLIC KEY-----";
+    }
+
+    /**
+     * 将长Base64字符串按64字符分行
+     */
+    private static String splitLines(String base64Str) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < base64Str.length(); i += 64) {
+            if (sb.length() > 0) sb.append("\n");
+            sb.append(base64Str.substring(i, Math.min(i + 64, base64Str.length())));
+        }
+        return sb.toString();
+    }
+
+    // ------------------------------ 测试示例 ------------------------------
+    public static void main(String[] args) throws Exception {
+        // 1. 配置参数(替换为文档中的测试参数或实际环境参数)
+        String appSecret = "uuRKVwbfSutCpFTv"; // 文档中测试appsecret
+        String platformPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk2oCpi9eSMqcmqO3rrMN\n" +
+                "b9fqEFMckcRkU520PXyxFalzA2mfLNgNPe8TB9mBSqn7xPxLBBBOSaFwEAeAAs4E\n" +
+                "AojMVilbfrTXJh3ucyKlGvTpX3lMKgJaYG7asEzKVbw5V4j8oTBtNh3s20jP7zBm\n" +
+                "Y61opsLTIW0qiuvMxezJS8wHc6ajY99RHWBASd3AGozsc3cFLSgIUyh2BhcbB2l7\n" +
+                "V8UyDQj7+QI1BwNpkvGxYhP0DF4Yu7buaaf61gygkeeOZ/8JOjcDWBfVB6Q6wEja\n" +
+                "os0E9U+rYXN6v90va1wrRp+zRev4sMBWesvwc6uzcuYO/RfSJ19FDMUreCScm8tk\n" +
+                "PQIDAQAB"; // 文档中测试红杉密钥-公钥
+        String thirdPrivateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCTagKmL15Iypyao7eusw1v1+oQUxyRxGRTnbQ9fLEVqXMDaZ8s2A097xMH2YFKqfvE/EsEEE5JoXAQB4ACzgQCiMxWKVt+tNcmHe5zIqUa9OlfeUwqAlpgbtqwTMpVvDlXiPyhMG02HezbSM/vMGZjrWimwtMhbSqK68zF7MlLzAdzpqNj31EdYEBJ3cAajOxzdwUtKAhTKHYGFxsHaXtXxTINCPv5AjUHA2mS8bFiE/QMXhi7tu5pp/rWDKCR545n/wk6NwNYF9UHpDrASNqizQT1T6thc3q/3S9rXCtGn7NF6/iwwFZ6y/Bzq7Ny5g79F9InX0UMxSt4JJyby2Q9AgMBAAECggEAEqfp6eo4vnGV3CQ4DM3wN2VV4/cAuJnoMITW2Kk9KAan3ZiyYlR9aIcnG2k1aaOVj1p2i+8cWUkrC3xHgRNdgoyZf5YAVErCp7pGASAzUPQJzOFm+DIQCgA9gO5W9P67Kw7VGfks+RpUbXQLjLPNYXQCuIgTfDl6ltY8the/ae4Y/a4dyhBhQ+Q/sygACk/Woiq7B78pc/qCaeMyZyik42aVuC7ZMuIgzERSOBFDrerI/upBWmLE4faeUk4h/PE1Hrj+H2RJ9aM5j4Idn/AJ4H4r8TjzT5m+ldQBfErs37HAVbyP1lQJjmO+VBBvqFchGNDtU1yGIRpxfU5mJI5dQQKBgQDRFPe+IKsheKNF2z0EUke/hU+XIDNc3Qwvp+2ok78G3LiKLRM61II/k+N0PLmJii0JEjqF0figj83Cyr4nnbhymOKIIplftgv085E1ed6QH0m54AwJBCLLA6gHiHin1t21Xh7o38FF6pHQ6EnQjfnVCODkTKxQEihvV3oAv/UBeQKBgQC0fnDPZ29YcIdI2W6xteDFaBfWLTw9usHDu2NnZBPEa+E5Whvcnw6xCgYEI+yasGEt9wOG6tnMEaxIMHRtn7LXaa7nrYxvqE5yTCLpjle3NM3KJRoCxZvOzJwlGWKFRPVpxBe1Sm0DB/IfTbBqzYCVkKQgpnqcpyI91TvxBL/r5QKBgA/bETaf75poNamUiLoNK1fA2lpRnNOMB+KNT56bJb91eaEw7eZmO0JrCrLD8CYYDnZDpaCEXeB/R1FgYq9KbLR0F6nPReZWPe3jkr2FcnVnigXIkeEVKTZQHqwDk3LW/pVEf/+VCGku8sPu+boRKkMXm0Z08hRYbCyVa7Em3YOxAoGAOomzfqC2TQGZ7reOHha1wnBjIrRjEEYsp5VzxMmBW7f9QMOHu8LeWe69SsR37Sd9LRIq06wBXRzyOit050TfFNwSvNLddC0q3AjzXbormqCGiaQEzpdWU/iqP6H/AOf/jADsC4EK3+vIy/w/VjQ2GsvhXzF/HKVcBp/Mo/t9Xz0CgYACKTI8f7z43g6MHy0+QOYBJ4BBDS8SzhLdNIXoUnc4O8kySTospxNVRzZGUMKJ4R8T7bpfR+50H6nCxBZo125eD4lcMHL3Dd/JwabKSer7Nzjt7+UMbgncQIs3m9FjtP1rvYuHvHI7RbxFH+hrYVWMKysWpbS9xtMThF9BosmufA=="; // 文档中测试三方密钥-私钥
+
+        // 2. 创建工具类实例
+        RedwoodCryptoUtil cryptoUtil = new RedwoodCryptoUtil(appSecret, platformPublicKey, thirdPrivateKey);
+
+        // 3. 加密请求参数示例(模拟购药问诊申请参数)
+        Map<String, Object> plainParam = new HashMap<>();
+        plainParam.put("prescription_type", 1);
+        plainParam.put("register_type", "picture");
+        plainParam.put("union_code", "TEST20250819001");
+        // 其他参数按接口要求补充...
+
+        Map<String, String> encryptedParam = cryptoUtil.encryptRequest(plainParam);
+        System.out.println("加密后的请求参数:" + encryptedParam);
+
+        // 4. 解密响应参数示例(模拟接口返回的加密数据)
+        Map<String, String> mockEncryptedResponse = new HashMap<>();
+        mockEncryptedResponse.put("content", "加密后的content");
+        mockEncryptedResponse.put("key", "加密后的key");
+        mockEncryptedResponse.put("sign", "加密后的sign");
+
+        Map<String, Object> plainResponse = cryptoUtil.decryptResponse(mockEncryptedResponse);
+        System.out.println("解密后的响应结果:" + plainResponse);
+    }
+}

+ 21 - 1
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -9,9 +9,11 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyMiniapp;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyMiniappService;
+import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.dto.BatchSendCourseDTO;
@@ -39,6 +41,7 @@ import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -57,6 +60,9 @@ public class FsUserCourseVideoController extends AppBaseController {
     @Autowired
     private IFsUserCourseVideoService fsUserCourseVideoService;
 
+    @Autowired
+    private ICompanyService iCompanyService;
+
     @Autowired
     private IFsUserCourseService fsUserCourseService;
 
@@ -290,6 +296,20 @@ public class FsUserCourseVideoController extends AppBaseController {
         return ResponseResult.ok(courseLinkService.getGotoWxAppLink(linkStr,appid));
     }
 
+    @GetMapping("/getGotoAppLink")
+    @ApiOperation("获取跳转微信小程序的链接地址")
+    public ResponseResult<String> getGotoWxAppLink(String linkStr, Long companyId) {
+        Company company = iCompanyService.selectCompanyById(companyId);
+        String appid = null;
+        if (CollectionUtils.isNotEmpty(company.getMiniAppMaster())){
+            appid = company.getMiniAppMaster().get(0);
+        }else if (CollectionUtils.isNotEmpty(company.getMiniAppServer())){
+            appid = company.getMiniAppServer().get(0);
+        }else {
+            return ResponseResult.fail(500,"请在后台配置主备小程序!");
+        }
+        return ResponseResult.ok(courseLinkService.getGotoWxAppLink(linkStr,appid));
+    }
     /**
      * 获取跳转微信小程序的链接地址
      */
@@ -309,7 +329,7 @@ public class FsUserCourseVideoController extends AppBaseController {
         R courseSortLink = fsUserCourseService.createAppCourseSortLink(fsCourseLinkCreateParam);
         String url = courseSortLink.get("url").toString();
         batchSendCourseDTO.setUrl(url);
-
+        batchSendCourseDTO.setIsUrgeCourse(false);
         return openIMService.batchSendCourse(batchSendCourseDTO);
     }
 

+ 5 - 0
fs-company-app/src/main/java/com/fs/app/param/FsUserLoginByMpParam.java

@@ -9,4 +9,9 @@ import java.io.Serializable;
 public class FsUserLoginByMpParam implements Serializable {
     @NotBlank(message = "code参数缺失")
     private String code;
+    
+    /**
+     * 小程序appId
+     */
+    private String appId;
 }

+ 12 - 6
fs-company/src/main/java/com/fs/company/controller/live/LiveAfterSalesController.java

@@ -8,6 +8,8 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyUser;
+import com.fs.framework.security.SecurityUtils;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import com.fs.live.domain.LiveAfterSales;
@@ -50,11 +52,13 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 查询售后记录列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:list')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:list')")
     @GetMapping("/list")
     public TableDataInfo list(LiveAfterSalesVo liveAfterSales)
     {
         startPage();
+        CompanyUser user = SecurityUtils.getLoginUser().getUser();
+        liveAfterSales.setCompanyId(user.getCompanyId());
         List<LiveAfterSalesVo> list = liveAfterSalesService.selectLiveAfterSalesVoList(liveAfterSales);
         for (LiveAfterSalesVo liveAfterSalesVo : list) {
             liveAfterSalesVo.setUserPhone(ParseUtils.parsePhone(liveAfterSalesVo.getUserPhone()));
@@ -65,12 +69,14 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 导出售后记录列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:export')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:export')")
     @Log(title = "售后记录", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(LiveAfterSalesVo liveAfterSales)
     {
         PageHelper.startPage(1, 10000, "");
+        CompanyUser user = SecurityUtils.getLoginUser().getUser();
+        liveAfterSales.setCompanyId(user.getCompanyId());
         List<LiveAfterSalesVo> list = liveAfterSalesService.selectLiveAfterSalesVoList(liveAfterSales);
         for (LiveAfterSalesVo liveAfterSalesVo : list) {
             liveAfterSalesVo.setUserPhone(liveAfterSalesVo.getUserPhone() == null ? "" : liveAfterSalesVo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
@@ -83,7 +89,7 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 获取售后记录详细信息
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:query')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:query')")
     @GetMapping(value = "/{id}")
     public R getInfo(@PathVariable("id") Long id)
     {
@@ -101,7 +107,7 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 新增售后记录
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:add')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:add')")
     @Log(title = "售后记录", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody LiveAfterSales liveAfterSales)
@@ -112,7 +118,7 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 修改售后记录
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:edit')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:edit')")
     @Log(title = "售后记录", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody LiveAfterSales liveAfterSales)
@@ -123,7 +129,7 @@ public class LiveAfterSalesController extends BaseController
     /**
      * 删除售后记录
      */
-    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:remove')")
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSales:remove')")
     @Log(title = "售后记录", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable Long[] ids)

+ 1 - 1
fs-company/src/main/java/com/fs/company/controller/live/LiveAutoTaskController.java

@@ -55,7 +55,7 @@ public class LiveAutoTaskController extends BaseController
         return getDataTable(list);
     }
 
-    @PreAuthorize("@ss.hasPermi('live:task:list')")
+//    @PreAuthorize("@ss.hasPermi('live:task:list')")
     @GetMapping("/consoleList")
     public TableDataInfo consoleList(LiveAutoTask liveAutoTask)
     {

+ 8 - 1
fs-company/src/main/java/com/fs/company/controller/live/LiveController.java

@@ -181,6 +181,9 @@ public class LiveController extends BaseController
     @PutMapping
     public AjaxResult edit(@RequestBody Live live)
     {
+        CompanyUser user = SecurityUtils.getLoginUser().getUser();
+        live.setCompanyUserId(user.getUserId());
+        live.setCompanyId(user.getCompanyId());
         return toAjax(liveService.updateLive(live));
     }
 
@@ -192,7 +195,11 @@ public class LiveController extends BaseController
 	@DeleteMapping("/{liveIds}")
     public AjaxResult remove(@PathVariable Long[] liveIds)
     {
-        return toAjax(liveService.deleteLiveByLiveIds(liveIds));
+        Live live = new Live();
+        CompanyUser user = SecurityUtils.getLoginUser().getUser();
+        live.setCompanyUserId(user.getUserId());
+        live.setCompanyId(user.getCompanyId());
+        return toAjax(liveService.deleteLiveByLiveIds(liveIds, live));
     }
 
     @PreAuthorize("@ss.hasPermi('live:live:query')")

+ 3 - 3
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferLogController.java

@@ -104,10 +104,10 @@ public class QwExternalContactTransferLogController extends BaseController
     @PreAuthorize("@ss.hasPermi('qw:externalContactTransferLog:export')")
     @Log(title = "转接记录", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(QwExternalContactTransferLog qwExternalContactTransferLog)
+    public AjaxResult export(QwExternalContactTransferLogParam qwExternalContactTransferLog)
     {
-        List<QwExternalContactTransferLog> list = qwExternalContactTransferLogService.selectQwExternalContactTransferLogList(qwExternalContactTransferLog);
-        ExcelUtil<QwExternalContactTransferLog> util = new ExcelUtil<QwExternalContactTransferLog>(QwExternalContactTransferLog.class);
+        List<QwExternalContactTransferLogListVO> list = qwExternalContactTransferLogService.selectQwExternalContactTransferLogListVO(qwExternalContactTransferLog);
+        ExcelUtil<QwExternalContactTransferLogListVO> util = new ExcelUtil<QwExternalContactTransferLogListVO>(QwExternalContactTransferLogListVO.class);
         return util.exportExcel(list, "转接记录数据");
     }
 

+ 8 - 8
fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java

@@ -924,14 +924,14 @@ public class QwUserController extends BaseController
         return R.ok();
     }
 
-    /**
-     * 重启云主机
-     * @return
-     */
-    @PutMapping("/restartHost")
-    public R restartCloudHost(@RequestParam String serverIp) {
-        return qwUserService.restartCloudHost(serverIp);
-    }
+//    /**
+//     * 重启云主机
+//     * @return
+//     */
+//    @PutMapping("/restartHost")
+//    public R restartCloudHost(@RequestParam String serverIp) {
+//        return qwUserService.restartCloudHost(serverIp);
+//    }
     @PostMapping("/updateSendType")
     public R updateSendType(@RequestBody UpdateSendTypeVo vo) {
         return qwUserService.updateSendType(vo);

+ 5 - 0
fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java

@@ -195,4 +195,9 @@ public class SopUserLogsController extends BaseController
         sopUserLogsService.replaceUser(vo);
         return R.ok();
     }
+
+    @GetMapping("/getShortLink")
+    public R getShortLink(String id, String sopId, String appId){
+        return sopUserLogsService.getShortLink(id, sopId, appId);
+    }
 }

+ 8 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsPackageOrderController.java

@@ -20,6 +20,7 @@ import com.fs.his.service.IFsPackageOrderService;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsPackageOrderListVO;
 import com.fs.his.vo.FsPackageOrderVO;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -260,4 +261,11 @@ public class FsPackageOrderController extends BaseController
         return fsPackageOrderService.getWxaCodePackageOrderUnLimit(orderId);
 
     }
+
+    @ApiOperation("修改或者添加患者首诊图片")
+    @PostMapping("/editPatientImages")
+    public R editPatientImages(@RequestParam("orderId")Long orderId,
+                               @RequestParam("imagesList")String imagesList){
+        return fsPackageOrderService.editPatientImages(orderId,imagesList);
+    }
 }

+ 1 - 1
fs-company/src/main/java/com/fs/user/FsUserAdminController.java

@@ -167,7 +167,7 @@ public class FsUserAdminController extends BaseController {
         R courseSortLink = fsUserCourseService.createAppCourseSortLink(fsCourseLinkCreateParam);
         String url = courseSortLink.get("url").toString();
         batchSendCourseDTO.setUrl(url);
-
+        batchSendCourseDTO.setIsUrgeCourse(false);
         return openIMService.batchSendCourse(batchSendCourseDTO);
     }
 

+ 1 - 6
fs-doctor-app/src/main/java/com/fs/app/controller/FsUserInformationCollectionController.java

@@ -2,11 +2,8 @@ package com.fs.app.controller;
 
 import com.fs.common.core.domain.R;
 import com.fs.his.domain.FsUserInformationCollection;
-import com.fs.his.dto.FsUserInformationCollectionDTO;
-import com.fs.his.param.CollectionInfoConfirmParam;
 import com.fs.his.param.UserInformationDoctorType2Param;
 import com.fs.his.service.IFsUserInformationCollectionService;
-import com.fs.his.vo.FsInquiryOrderListPDVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -21,10 +18,8 @@ public class FsUserInformationCollectionController extends  AppBaseController {
     private IFsUserInformationCollectionService fsUserInformationCollectionService;
     @GetMapping("/getUserInformation")
     public R getUserInformation(@RequestParam("id") Long id) {
-        FsUserInformationCollectionDTO fsUserInformationCollection = fsUserInformationCollectionService.selectFsUserInformationCollectionDTOById(id);
 
-
-        return R.ok().put("data", fsUserInformationCollection);
+        return R.ok().put("data", fsUserInformationCollectionService.selectFsUserInformationCollectionVoById(id));
     }
     //医生确认
     @PostMapping("/doctorConfirm")

+ 73 - 1
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -1,18 +1,25 @@
 package com.fs.app.service;
 
 import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.domain.CompanyMiniapp;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
+import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.his.domain.FsUser;
+import com.fs.his.mapper.FsUserMapper;
 import com.fs.ipad.IpadSendUtils;
 import com.fs.ipad.vo.*;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUserVideo;
 import com.fs.qw.mapper.QwExternalContactMapper;
@@ -27,11 +34,15 @@ import com.fs.sop.service.impl.QwSopLogsServiceImpl;
 import com.fs.wxwork.dto.*;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Service
@@ -47,14 +58,74 @@ public class IpadSendServer {
     private final IQwUserVideoService qwUserVideoService;
     private final RedisCache redisCache;
     private final ICompanyMiniappService companyMiniappService;
-
+    private final IFsCoursePlaySourceConfigService playSourceConfigService;
+    private final FsUserMapper fsUserMapper;
+    private static final List<String> PROJECT_NAMES = Arrays.asList("济南联志健康", "北京存在文化","宽益堂");
     private void sendMiniProgram(BaseVo vo, QwSopCourseFinishTempSetting.Setting content, Map<String, FsCoursePlaySourceConfig> miniMap, Long companyId) {
+        // 发送参数原本的appid
         String appid = content.getMiniprogramAppid();
+        // 判断销售工时ID不为空并且有小程序类型
         if(companyId != null && content.getMiniType() != null){
+            // 获取销售公司下面绑定的主备小程序,并且根据当前应该发送的主备类型查询出数据
             List<CompanyMiniapp> list = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().eq("company_id", companyId).eq("type", content.getMiniType()));
+            // 判断当前绑定的最新的小程序,并且覆盖以前的值(可以达到实时替换小程序的功能)
             if(!list.isEmpty() && list.get(0) != null && StringUtils.isNotEmpty(list.get(0).getAppId())){
                 appid = list.get(0).getAppId();
             }
+            // 获取配置文件里面的项目名称
+            String signProjectName = SpringUtils.getProperty("cloud_host.company_name");
+            //区分新老用户,新用户发送备用小程序,老用户发送主小程序,TODO 需要使用的项目在参数里面加上
+            if(PROJECT_NAMES.contains(signProjectName)){
+                log.info("ID:{}, qwUserId:{},externalId:{},进入区分发小程序逻辑", vo.getId(), vo.getQwUserId(), vo.getExId());
+                // 判断消息是否是群聊,不是群聊再进去,TODO 当权无法判断群聊是否可以发送对应的小程序
+                if(!vo.isRoom()){
+                    log.info("qwUserId:{},externalId:{},不是群聊", vo.getQwUserId(), vo.getExId());
+                    try {
+                        // 获取当前外部联系人
+                        QwExternalContact qwExternalContact = qwExternalContactMapper.selectOne(new LambdaQueryWrapper<QwExternalContact>().eq(QwExternalContact::getQwUserId,vo.getQwUserId()).eq(QwExternalContact::getExternalUserId,vo.getExId()).last(" limit 1"));
+                        // 当前外部联系是否绑定用户数据,如果数据为空则是没看过小程序的新用户,不用去判断小程序,跳过判断
+                        if(qwExternalContact.getFsUserId() != null){
+                            // 根据用户绑定信息去查询用户信息
+                            FsUser fsUser = fsUserMapper.selectFsUserByUserId(qwExternalContact.getFsUserId());
+                            // 判断用户是否有看过其他的小程序多个
+                            if(StringUtils.isNotEmpty(fsUser.getAppId())){
+                                // 获取用户看过的小程序ID集合
+                                List<String> miniAppList = Arrays.asList(fsUser.getAppId().split(","));
+                                // 根据小程序ID查询小程序列表
+                                List<FsCoursePlaySourceConfig> configList = playSourceConfigService.selectByAppIds(miniAppList);
+                                // 筛选出半封禁的小程序数据,得到这个数据然后优先发这个小程序
+                                Optional<FsCoursePlaySourceConfig> optional = configList.stream().filter(e -> e.getStatus() != null && e.getStatus() == 1).findFirst();
+                                // 判断是否找到
+                                if(optional.isPresent()){
+                                    // 找到半封禁并且在appid里面存在证明这个客户是打开过小程序,优先发送这个
+                                    appid = optional.get().getAppid();
+                                }
+                            }else{
+                                // 获取用户的创建时间
+                                LocalDateTime createTime = DateUtil.dateToLocalDateTime(fsUser.getCreateTime());
+                                log.info("ID:{}, qwUserId:{},externalId:{},已绑定小程序,判断时间:{}", vo.getId(), vo.getQwUserId(), vo.getExId(), createTime);
+                                // 这个时间是写死的,目前判断的芳华封禁的时间,可以更具项目调整
+                                LocalDateTime lastTime = LocalDateTime.of(2025, 11, 6, 23, 59, 59);
+                                // 判断客户创建时间是在这个之前还是之后
+                                int listIndex = createTime.isAfter(lastTime) ? 1 : 0 ;
+                                // 获取公司里面的主备小程序,根据用户创建时间来发送主备,如果创建时间大于上看的时间就发送备用小程序,如果小于就发送主要小程序
+                                List<CompanyMiniapp> collect2 = list.stream().filter(e -> e.getType().equals(listIndex)).collect(Collectors.toList());
+                                // 判断是否获取到了配置
+                                if(!collect2.isEmpty() && collect2.get(0) != null && StringUtils.isNotEmpty(collect2.get(0).getAppId())){
+                                    appid = collect2.get(0).getAppId();
+                                    log.info("ID:{}, qwUserId:{},externalId:{},发送小程序:{}", vo.getId(), vo.getQwUserId(), vo.getExId(), appid);
+                                }
+                            }
+                        }else{
+                            log.info("ID:{}, qwUserId:{},externalId:{},未绑定小程序用户", vo.getId(), vo.getQwUserId(), vo.getExId());
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        log.error("6.输出外部联系人ID-------------->{}",vo.getExId());
+                        log.error("7.数据异常----------------------》{}",e.getMessage());
+                    }
+                }
+            }
         }
         FsCoursePlaySourceConfig courseMaConfig = miniMap.get(appid);
         if(courseMaConfig == null){
@@ -341,6 +412,7 @@ public class IpadSendServer {
         vo.setServerId(qwUser.getServerId());
         vo.setCorpCode(parentVo.getCorpCode());
         vo.setCorpId(parentVo.getCorpId());
+        vo.setQwUserId(qwUser.getId());
         try {
             content.setSendStatus(1);
             switch (content.getContentType()) {

+ 12 - 0
fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java

@@ -365,6 +365,9 @@ public class WebSocketServer {
                 case "goods":
                     sendGoodsMessage(msg);
                     break;
+                case "deleteMsg":
+                    deleteMsg(liveId,msg);
+                    break;
                 case "red":
                     processRed(liveId, msg);
                     break;
@@ -385,6 +388,15 @@ public class WebSocketServer {
         }
     }
 
+    private void deleteMsg(long liveId,SendMsgVo msg) {
+        SendMsgVo sendMsgVo = new SendMsgVo();
+        sendMsgVo.setLiveId(liveId);
+        sendMsgVo.setUserType(0L);
+        sendMsgVo.setCmd("deleteMsg");
+        sendMsgVo.setMsg(msg.getMsg());
+        broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+    }
+
     private void processCoupon(long liveId, SendMsgVo msg) {
         JSONObject jsonObject = JSON.parseObject(msg.getData());
         Integer status = jsonObject.getInteger("status");

+ 2 - 1
fs-quartz/src/main/java/com/fs/quartz/config/ScheduleConfig.java

@@ -8,7 +8,7 @@ import java.util.Properties;
 
 /**
  * 定时任务配置
- * 
+ *
 
  */
 @Configuration
@@ -51,6 +51,7 @@ public class ScheduleConfig
         factory.setOverwriteExistingJobs(true);
         // 设置自动启动,默认为true
         factory.setAutoStartup(true);
+//        factory.setAutoStartup(false);
 
         return factory;
     }

+ 94 - 5
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -21,10 +21,11 @@ import com.fs.his.service.IFsInquiryOrderService;
 import com.fs.his.utils.qrcode.QRCodeUtils;
 import com.fs.qw.domain.QwCompany;
 import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.domain.QwIpadServerLog;
+import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
-import com.fs.qw.service.IQwCompanyService;
-import com.fs.qw.service.IQwExternalContactService;
-import com.fs.qw.service.IQwMaterialService;
+import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.service.*;
 import com.fs.qwApi.domain.QwExternalContactResult;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.mapper.QwSopLogsMapper;
@@ -33,6 +34,8 @@ import com.fs.sop.mapper.SopUserLogsMapper;
 import com.fs.sop.service.*;
 import com.fs.sop.vo.QwSopLogsDoSendListTVO;
 import com.fs.store.service.IFsUserCourseCountService;
+import com.fs.wxwork.dto.WxWorkGetQrCodeDTO;
+import com.fs.wxwork.service.WxWorkService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
@@ -48,6 +51,7 @@ import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.List;
 
 @Api("公共接口")
@@ -134,11 +138,96 @@ public class CommonController {
     @Autowired
     public RedisCache redisCache;
 
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+
+    @Autowired
+    IQwIpadServerService ipadServerService;
+
+    @Autowired
+    IQwIpadServerLogService qwIpadServerLogService;
+    @Autowired
+    IQwIpadServerUserService qwIpadServerUserService;
+
+    @Autowired
+    IQwExternalContactService externalContactService;
+    @Autowired
+    WxWorkService wxWorkService;
+
     /**
-     * 获取跳转微信小程序的链接地址
+     *
+     */
+    @GetMapping("/selectQwUserByTest")
+    public void selectQwUserByTest() {
+        try {
+            List<QwUser> list = qwUserMapper.selectQwUserByTest();
+            for (QwUser qwUser : list) {
+                try {
+                    Integer serverStatus = qwUser.getServerStatus();
+                    Long serverId = qwUser.getServerId();
+                    if (serverStatus==0){
+                        log.error("不需要解绑");
+                    }
+                    if (serverId==null){
+                        log.error("serverId不存在");
+                    }
+                    QwUser u = new QwUser();
+                    u.setId(qwUser.getId());
+                    u.setServerId(null);
+                    u.setServerStatus(0);
+                    qwUserMapper.updateQwUser(u);
+                    ipadServerService.addServer(serverId);
+                    QwIpadServerLog qwIpadServerLog = new QwIpadServerLog();
+                    qwIpadServerLog.setType(2);
+                    qwIpadServerLog.setTilie("解绑");
+                    qwIpadServerLog.setServerId(serverId);
+                    qwIpadServerLog.setQwUserId(qwUser.getId());
+                    qwIpadServerLog.setCompanyUserId(qwUser.getCompanyUserId());
+                    qwIpadServerLog.setCompanyId(qwUser.getCompanyId());
+                    qwIpadServerLog.setCreateTime(new Date());
+                    qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog);
+                    qwIpadServerUserService.deleteQwIpadServerUserByQwUserId(qwUser.getId());
+                    WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
+                    wxWorkGetQrCodeDTO.setUuid(qwUser.getUid());
+                    wxWorkService.LoginOut(wxWorkGetQrCodeDTO,qwUser.getServerId());
+                    updateIpadStatus(qwUser.getId(),0);
+                } catch (Exception e) {
+                    log.error("解绑ipad报错",e);
+                }
+            }
+        } catch (Exception e) {
+            log.error("定时处理未绑定员工企微异常",e);
+        }
+
+    }
+
+
+    void updateIpadStatus(Long id ,Integer status){
+        QwUser u = new QwUser();
+        u.setId(id);
+        u.setIpadStatus(status);
+        qwUserMapper.updateQwUser(u);
+    }
+    /**
+     *
+     */
+    @GetMapping("/countQwApiAopLogToken")
+    public void countQwApiAopLogToken() {
+
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        // 获取当前日期(只包含年月日)
+        LocalDate currentDate = LocalDate.now();
+
+        String todayStr = currentDate.format(dateFormatter);
+        qwSopLogsService.countQwApiAopLogToken(todayStr);
+
+    }
+
+    /**
+     * 查询视频时长
      */
     @GetMapping("/getVideoDuration")
-    @ApiOperation("获取跳转微信小程序的链接地址")
     public Long getVideoDuration(Long videoId) {
 
             String redisKey = "h5user:video:duration:" + videoId;

+ 3 - 3
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -1074,7 +1074,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     setting.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
                     setting.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));
                     setting.setCourseUrl(setting.getLinkImageUrl());
-                    setting.setTitle(setting.getLinkTitle());
+                    setting.setTitle(setting.getLinkDescribe()); //小节名称
 
                     break;
                 //自定义小程序
@@ -1127,9 +1127,9 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         }
         clonedContent.getSetting().stream().filter(e -> "1".equals(e.getIsBindUrl())).forEach(e -> {
             e.setIsBindUrl("0");
-            e.setLinkDescribe(null);
+//            e.setLinkDescribe(null);
             e.setLinkUrl(null);
-            e.setLinkImageUrl(null);
+//            e.setLinkImageUrl(null);
         });
         sopLogs.setContentJson(JSON.toJSONString(clonedContent));
         enqueueQwSopLogs(sopLogs);

+ 5 - 5
fs-service/pom.xml

@@ -285,11 +285,11 @@
         </dependency>
 
         <!-- 移动云ECS SDK -->
-        <dependency>
-            <groupId>com.ecloud.sdk</groupId>
-            <artifactId>ecloud-sdk-ecs</artifactId>
-            <version>1.1.26</version>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>com.ecloud.sdk</groupId>-->
+<!--            <artifactId>ecloud-sdk-ecs</artifactId>-->
+<!--            <version>1.1.26</version>-->
+<!--        </dependency>-->
 
     </dependencies>
 

+ 13 - 13
fs-service/src/main/java/com/cloud/host/CloudHostConfig.java

@@ -1,7 +1,7 @@
 package com.cloud.host;
 
-import com.ecloud.sdk.config.Config;
-import com.ecloud.sdk.ecs.v1.Client;
+//import com.ecloud.sdk.config.Config;
+//import com.ecloud.sdk.ecs.v1.Client;
 import org.springframework.context.annotation.Configuration;
 
 @Configuration
@@ -14,16 +14,16 @@ public class CloudHostConfig {
      * @param poolId
      * @return Client
      */
-    public static Client createClient(String accessKey, String secretKey, String poolId) {
-        Config config = new Config();
-        config.setAccessKey(accessKey);
-        config.setSecretKey(secretKey);
-        config.setPoolId(poolId);
-        // 默认连接超时时间为60秒
-        config.setConnectTimeout(60);
-        // 默认响应超时时间为120秒
-        config.setReadTimeout(120);
-        return new Client(config);
-    }
+//    public static Client createClient(String accessKey, String secretKey, String poolId) {
+//        Config config = new Config();
+//        config.setAccessKey(accessKey);
+//        config.setSecretKey(secretKey);
+//        config.setPoolId(poolId);
+//        // 默认连接超时时间为60秒
+//        config.setConnectTimeout(60);
+//        // 默认响应超时时间为120秒
+//        config.setReadTimeout(120);
+//        return new Client(config);
+//    }
 
 }

+ 4 - 1
fs-service/src/main/java/com/fs/company/domain/CompanyUser.java

@@ -40,6 +40,9 @@ public class CompanyUser extends BaseEntity
     @Excel(name = "部门编号")
     private Long deptId;
 
+    @Excel(name = "部门名称")
+    private String deptName;
+
     /** 用户账号 */
     @Excel(name = "用户账号")
     private String userName;
@@ -133,7 +136,7 @@ public class CompanyUser extends BaseEntity
 
     private String firstchar;
     private String postName;
-    private String deptName;
+
 
     private String qrCodeWeixin;
 

+ 4 - 1
fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java

@@ -155,7 +155,10 @@ public interface CompanyMapper
 
 
     @Select({"<script> " +
-            "select c.*,cu.user_name,qu.used_num FROM company c LEFT JOIN company_user cu ON c.user_id =cu.user_id  " +
+            "select c.*,cu.user_name,qu.used_num," +
+            "CASE WHEN JSON_VALID(t1.config_value) THEN t1.config_value->>'$.mchId' ELSE NULL END as mchId" +
+            " FROM company c LEFT JOIN company_user cu ON c.user_id =cu.user_id  " +
+            " left join company_config t1 on t1.config_key = 'redPacket:config' and t1.company_id = c.company_id " +
             "LEFT JOIN (select company_id, count(id) as used_num from qw_user where server_id is not null and server_status = 1 group by company_id) qu ON qu.company_id = c.company_id " +
             "where c.is_del=0 " +
             "            <if test=\"companyName != null  and companyName != ''\"> and c.company_name like concat('%', #{companyName}, '%')</if>\n" +

+ 5 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyVO.java

@@ -99,4 +99,9 @@ public class CompanyVO implements Serializable
     private BigDecimal redPackageMoney;
 
     private Integer liveShow;
+
+    /**
+     * 新增展示商户号(分公司配置时有值)
+     */
+    private String mchId;
 }

+ 10 - 10
fs-service/src/main/java/com/fs/core/utils/OrderCodeUtils.java

@@ -44,16 +44,16 @@ public class OrderCodeUtils {
 
     }
     public static String getOrderSn(){
-//        String url= FSConfig.getCommonApi()+ "/app/common/genOrderCode";
-////        String url= "42.194.245.189:8010/app/common/genOrderCode";
-//        String json = HttpRequest.get(url)
-//                .execute().body();
-//        OrderCodeVO vo= JSONUtil.toBean(json, OrderCodeVO.class);
-//        if(vo.getCode()==200){
-//            return vo.getOrderCode();
-//        }
-//        else return null;
-        return OrderCodeUtils.genOrderSn();
+        String url= FSConfig.getCommonApi()+ "/app/common/genOrderCode";
+//        String url= "42.194.245.189:8010/app/common/genOrderCode";
+        String json = HttpRequest.get(url)
+                .execute().body();
+        OrderCodeVO vo= JSONUtil.toBean(json, OrderCodeVO.class);
+        if(vo.getCode()==200){
+            return vo.getOrderCode();
+        }
+        else return null;
+//        return OrderCodeUtils.genOrderSn();
 
     }
 

+ 19 - 0
fs-service/src/main/java/com/fs/course/config/RandomRedPacketConfig.java

@@ -0,0 +1,19 @@
+package com.fs.course.config;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author MixLiu
+ * @date 2025/11/27 下午2:07)
+ */
+@Data
+public class RandomRedPacketConfig {
+    /**
+     * 是否开启随机红包
+     */
+    private Boolean enableRandomRedpacket;
+
+    private List<RandomRedPacketRule> rules;
+}

+ 28 - 0
fs-service/src/main/java/com/fs/course/config/RandomRedPacketRule.java

@@ -0,0 +1,28 @@
+package com.fs.course.config;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author MixLiu
+ * @date 2025/11/27 下午2:08)
+ */
+
+@Data
+public class RandomRedPacketRule {
+    /**
+     * 最小金额
+     */
+    private BigDecimal minAmount;
+
+    /**
+     * 最大金额
+     */
+    private BigDecimal maxAmount;
+
+    /**
+     * 权重
+     */
+    private Integer weight;
+}

+ 5 - 0
fs-service/src/main/java/com/fs/course/domain/FsCoursePlaySourceConfig.java

@@ -99,4 +99,9 @@ public class FsCoursePlaySourceConfig {
      * 是否是互医/商城小程序
      */
     private Integer isMall;
+
+    /**
+     * 小程序状态:0正常,1半封禁,2封禁
+     */
+    private Integer status;
 }

+ 11 - 23
fs-service/src/main/java/com/fs/course/domain/FsUserCourseCompanyStatistics.java

@@ -17,67 +17,55 @@ import lombok.EqualsAndHashCode;
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class FsUserCourseCompanyStatistics extends BaseEntity{
+public class FsUserCourseCompanyStatistics extends BaseEntity {
 
-    /** 主键ID */
     private Long id;
 
-    /** 项目ID */
-//    @Excel(name = "项目ID")
     private Long projectId;
 
-    /** 完播次数(人次) */
-    @Excel(name = "完播次数", readConverterExp = "人=次")
+    @Excel(name = "完播次数")
     private Long completeWatchCount;
 
-    /** 观看次数(人次) */
-    @Excel(name = "观看次数", readConverterExp = "人=次")
+    @Excel(name = "观看次数")
     private Long watchCount;
 
-    /** 完播率(完播次数/观看次数) */
-    @Excel(name = "完播率", readConverterExp = "完=播次数/观看次数")
+    /** DB字段,存放放大100倍后的比例整数值,例 12.34% -> 1234 */
     private Long completeRate;
 
-    /** 答题人次 */
     @Excel(name = "答题人次")
     private Long answerCount;
 
-    /** 正确人次 */
     @Excel(name = "正确人次")
     private Long correctCount;
 
-    /** 正确率(正确人次/答题人次) */
-    @Excel(name = "正确率", readConverterExp = "正=确人次/答题人次")
+    /** DB字段,同样放大100倍后存储 */
     private Long correctRate;
 
-    /** 领取次数 */
     @Excel(name = "领取次数")
     private Long receiveCount;
 
-    /** 领取金额(元) */
-    @Excel(name = "领取金额", readConverterExp = "元=")
+    @Excel(name = "领取金额(元)")
     private BigDecimal receiveAmount;
 
-    /** 会员数量 */
     @Excel(name = "会员数量")
     private Long userCount;
 
-    /** 会员黑名单数量 */
     @Excel(name = "会员黑名单数量")
     private Long userBlacklistCount;
 
-    /** 公司ID */
-//    @Excel(name = "公司ID")
     private Long companyId;
 
-    /** 公司名称 */
     @Excel(name = "公司名称")
     private String companyName;
 
-    /** 统计日期 */
     @JsonFormat(pattern = "yyyy-MM-dd")
     @Excel(name = "统计日期", width = 30, dateFormat = "yyyy-MM-dd")
     private Date createDate;
 
+    /** 用于 Excel 导出显示的字符串,不入库 */
+    @Excel(name = "完播率(%)")
+    private String completeRateStr;
 
+    @Excel(name = "正确率(%)")
+    private String correctRateStr;
 }

+ 8 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java

@@ -1,5 +1,6 @@
 package com.fs.course.domain;
 
+import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
@@ -64,6 +65,7 @@ public class FsUserCourseVideo extends BaseEntity
 
     private String fileName;
 
+    @TableLogic(value = "0", delval = "1")
     private Integer isDel;
 
     /**
@@ -78,6 +80,12 @@ public class FsUserCourseVideo extends BaseEntity
     private Integer uploadType;
 
     private BigDecimal redPacketMoney;
+
+    /**
+     * 随机红包配置
+     */
+    private String randomRedPacketRules;
+
     private Long fileSize;//文件大小  字节
     private String fileKey;//文件key 对用存储桶
     private String round;//轮次

+ 19 - 14
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java

@@ -1,5 +1,6 @@
 package com.fs.course.mapper;
 
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.param.CourseVideoUpdates;
 import com.fs.course.param.FsCourseListBySidebarParam;
@@ -25,8 +26,7 @@ import java.util.Map;
  * @author fs
  * @date 2024-05-17
  */
-public interface FsUserCourseVideoMapper
-{
+public interface FsUserCourseVideoMapper extends BaseMapper<FsUserCourseVideo> {
     /**
      * 查询课堂视频
      *
@@ -62,7 +62,7 @@ public interface FsUserCourseVideoMapper
     public int updateFsUserCourseVideo(FsUserCourseVideo fsUserCourseVideo);
 
     @Update("<script> " +
-            "update fs_user_course_video set red_packet_money=#{data.redPacketMoney} where course_id=#{data.courseId} " +
+            "update fs_user_course_video set red_packet_money=#{data.redPacketMoney}, random_red_packet_rules = #{data.randomRedPacketRules} where course_id=#{data.courseId} " +
             "</script>")
     public int updateFsUserCourseRedPage(@Param("data") FsUserCourseRedPageParam courseRedPageParam);
 
@@ -94,7 +94,7 @@ public interface FsUserCourseVideoMapper
             "<if test = ' maps.userId!=null and maps.userId != \"\" '> " +
             "and v.user_id = #{maps.userId} " +
             "</if>" +
-            " order by v.course_sort  "+
+            " order by v.course_sort  " +
             "</script>"})
     List<FsUserCourseVideo> selectFsUserCourseVideoListByCourseId(@Param("maps") FsUserCourseVideo fsUserCourseVideo);
 
@@ -110,7 +110,7 @@ public interface FsUserCourseVideoMapper
             "<if test = ' maps.keyword!=null and maps.keyword != \"\" '> " +
             "and v.title like CONCAT('%',#{maps.keyword},'%') " +
             "</if>" +
-            " order by v.course_sort  "+
+            " order by v.course_sort  " +
             "</script>"})
     List<FsUserCourseVideoListUVO> selectFsUserCourseVideoListUVOByCourseId(@Param("maps") FsUserCourseVideoListUParam param);
 
@@ -121,7 +121,7 @@ public interface FsUserCourseVideoMapper
             "<if test = ' maps.keyword!=null and maps.keyword != \"\" '> " +
             "and v.title like CONCAT('%',#{maps.keyword},'%') " +
             "</if>" +
-            " order by v.course_sort  "+
+            " order by v.course_sort  " +
             "</script>"})
     List<FsUserCourseVideoListUVO> selectFsUserCourseVideoListByCourseIdAll(@Param("maps") FsUserCourseVideoListUParam param);
 
@@ -129,6 +129,7 @@ public interface FsUserCourseVideoMapper
     @Select("select v.*  from fs_user_course_video v  " +
             "where v.is_del = 0 and v.course_id = #{courseId}  order by v.course_sort  ")
     List<FsUserCourseVideo> selectFsUserCourseListByCourseId(Long courseId);
+
     @Select({"<script> " +
             "select v.video_id, v.title, v.video_url, v.thumbnail, SEC_TO_TIME(v.duration) as duration,v.create_time, v.talent_id, v.course_id, " +
             " v.status, v.course_sort  from fs_user_course_video v  " +
@@ -140,10 +141,10 @@ public interface FsUserCourseVideoMapper
     Long selectVideoCountByCourseId(@Param("courseId") Long courseId);
 
     @Select("select course_sort from fs_user_course_video where course_id = #{courseId} and is_del = 0 order by course_sort desc limit 1 ")
-    Long selectCourseVideoSort(@Param("courseId")Long courseId);
+    Long selectCourseVideoSort(@Param("courseId") Long courseId);
 
     @Select("select count(0) from fs_user_course_video where course_id = #{courseId} and course_sort = #{courseSort} and is_del = 0 ")
-    Long selectFsUserCourseVideoByCourseSort(@Param("courseId")Long courseId, @Param("courseSort")Long courseSort);
+    Long selectFsUserCourseVideoByCourseSort(@Param("courseId") Long courseId, @Param("courseSort") Long courseSort);
 
 
     @Select("select video_id dict_value, title dict_label  from fs_user_course_video where course_id=#{id} and is_del = 0 order by course_sort")
@@ -156,7 +157,7 @@ public interface FsUserCourseVideoMapper
             "<if test = ' maps.title!=null and maps.title != \"\" '> " +
             "and v.title = #{maps.title} " +
             "</if>" +
-            " order by v.course_sort  "+
+            " order by v.course_sort  " +
             "</script>"})
     List<FsUserCourseVideoVO> selectFsUserCourseVideoListByCourseIdAndCompany(@Param("maps") FsUserCourseVideoParam fsUserCourseVideo);
 
@@ -164,10 +165,13 @@ public interface FsUserCourseVideoMapper
             "left join fs_user_course c on c.course_id = v.course_id " +
             "where c.is_private = 1 and v.is_del = 0 ")
     List<FsUserCourseVideo> selectVideoIsPrivate();
+
     @Select("select * from fs_user_course_video WHERE video_id=#{videoId}")
     FsUserCourseVideo selectFsUserCourseVideoByVideoStringId(String videoId);
+
     @Select("select * from fs_user_course_video WHERE course_id=#{courseId} and is_del = 0 order by course_sort,video_id")
     List<FsUserCourseVideo> selectVideoByCourseId(Long courseId);
+
     @Select("select v.* from fs_user_course_video v " +
             "left join fs_user_course c on c.course_id = v.course_id " +
             "where c.is_private = 1 and v.is_del = 0 and v.is_transcode = #{isTranscode}")
@@ -192,8 +196,9 @@ public interface FsUserCourseVideoMapper
 
     /**
      * 获取选项列表
-     * @param params    参数
-     * @return  list
+     *
+     * @param params 参数
+     * @return list
      */
     List<OptionsVO> selectVideoListByMap(@Param("params") Map<String, Object> params);
 
@@ -227,7 +232,7 @@ public interface FsUserCourseVideoMapper
 
     List<FsUserCourseVideoPageListVO> selectFsUserCourseVideoListByMap(@Param("params") Map<String, Object> params);
 
-    FsUserCourseVideo selectByFileKey(@Param("params")String fileKey);
+    FsUserCourseVideo selectByFileKey(@Param("params") String fileKey);
 
     @Select("select * from fs_user_course_video where file_key = #{fileKey} ")
     List<FsUserCourseVideo> selectVideoByFileKey(@Param("fileKey") String fileKey);
@@ -243,7 +248,7 @@ public interface FsUserCourseVideoMapper
     @Select("select title from fs_user_course_video WHERE video_id=#{videoId}")
     String selectFsUserCourseVideoByVideoForTitle(@Param("videoId") Long videoId);
 
-    FsUserCourseVideo selectFsUserCourseVideoByVideoIdAndUserId(@Param("videoId") Long videoId,@Param("userId") Long userId);
+    FsUserCourseVideo selectFsUserCourseVideoByVideoIdAndUserId(@Param("videoId") Long videoId, @Param("userId") Long userId);
 
     /**
      * 查询选择使用的视频列表
@@ -255,7 +260,7 @@ public interface FsUserCourseVideoMapper
      */
     List<FsUserCourseVideoAppletVO> getFsUserCourseVideoAppletVOListByIds(@Param("videoIds") List<Long> videoIds);
 
-    FsUserCourseVO selectFsUserCourseVideoVoByVideoIdAndCourdeId(@Param("videoId") Long videoId,@Param("courseId") Long courseId);
+    FsUserCourseVO selectFsUserCourseVideoVoByVideoIdAndCourdeId(@Param("videoId") Long videoId, @Param("courseId") Long courseId);
 
     @Select("select video_id,is_first,course_sort,tg_id,watching_tg_id,watched_tg_id,watching_tag_id,watched_tag_id,tag_group_id from fs_user_course_video")
     @MapKey("videoId")

+ 3 - 0
fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigCreateParam.java

@@ -54,4 +54,7 @@ public class FsCoursePlaySourceConfigCreateParam {
     @ApiModelProperty("是否是互医/商城小程序")
     private Integer isMall;
     private Long createDeptId;
+
+    @ApiModelProperty("小程序状态:0正常,1半封禁,2封禁")
+    private Integer status;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java

@@ -52,4 +52,7 @@ public class FsCoursePlaySourceConfigEditParam {
     @ApiModelProperty("是否是互医/商城小程序")
     private Integer isMall;
     private Long createDeptId;
+
+    @ApiModelProperty("小程序状态:0正常,1半封禁,2封禁")
+    private Integer status;
 }

+ 2 - 0
fs-service/src/main/java/com/fs/course/service/IFsCoursePlaySourceConfigService.java

@@ -13,4 +13,6 @@ public interface IFsCoursePlaySourceConfigService extends IService<FsCoursePlayS
      * 查询点播配置列表
      */
     List<FsCoursePlaySourceConfigVO> selectCoursePlaySourceConfigVOListByMap(Map<String, Object> params);
+
+    List<FsCoursePlaySourceConfig> selectByAppIds(List<String> miniAppList);
 }

+ 16 - 6
fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java

@@ -17,7 +17,6 @@ import com.fs.course.vo.newfs.FsUserVideoListVO;
 import com.fs.his.domain.FsUser;
 import com.fs.his.vo.OptionsVO;
 import com.fs.qw.param.FsUserCourseRedPageParam;
-import com.fs.sop.domain.QwSopTempDay;
 
 import java.util.List;
 import java.util.Map;
@@ -28,8 +27,7 @@ import java.util.Map;
  * @author fs
  * @date 2024-05-17
  */
-public interface IFsUserCourseVideoService
-{
+public interface IFsUserCourseVideoService extends IService<FsUserCourseVideo> {
     /**
      * 查询课堂视频
      *
@@ -63,6 +61,7 @@ public interface IFsUserCourseVideoService
     public int updateFsUserCourseVideo(FsUserCourseVideo fsUserCourseVideo);
 
     public int updateFsUserCourseRedPage(FsUserCourseRedPageParam userCourseRedPageParam);
+
     public void sortCourseVideo(List<FsUserCourseVideo> list);
 
     /**
@@ -107,12 +106,14 @@ public interface IFsUserCourseVideoService
 
     /**
      * 获取课程视频分页列表
+     *
      * @return FsUserCourseVideoPageListVO
      */
     List<FsUserCourseVideoPageListVO> pageListCourseVideo(UserCourseVideoPageParam param);
 
     /**
      * 获取课程视频详情
+     *
      * @return FsUserCourseVideoDetailsVO
      */
     ResponseResult<FsUserCourseVideoDetailsVO> getVideoDetails(Long videoId);
@@ -121,6 +122,7 @@ public interface IFsUserCourseVideoService
 
     /**
      * 获取下拉视频列表(有分页,仅返回两个字段)
+     *
      * @param param 入参
      * @return list
      */
@@ -128,6 +130,7 @@ public interface IFsUserCourseVideoService
 
     /**
      * 判断是否添加销售
+     *
      * @param param 入参
      * @return 是/否 成功
      */
@@ -135,6 +138,7 @@ public interface IFsUserCourseVideoService
 
     /**
      * 获取链接用户课程详情
+     *
      * @param param 入参
      */
     ResponseResult<FsUserCourseVideoLinkDetailsVO> getLinkCourseVideoDetails(FsUserCourseVideoLinkParam param);
@@ -144,6 +148,7 @@ public interface IFsUserCourseVideoService
 
     /**
      * 更新看课时长
+     *
      * @param param 入参
      * @return
      */
@@ -157,8 +162,9 @@ public interface IFsUserCourseVideoService
 
     /**
      * 获取选项列表
-     * @param params    参数
-     * @return  list
+     *
+     * @param params 参数
+     * @return list
      */
     List<OptionsVO> selectVideoListByMap(Map<String, Object> params);
 
@@ -166,16 +172,19 @@ public interface IFsUserCourseVideoService
 
     /**
      * 只查询用户当天课程章节数据
+     *
      * @param param
      * @return
      */
     List<FsCourseVideoListBySidebarVO> getFsCourseVideoListBySidebarToday(FsCourseListBySidebarParam param);
 
     R createMiniLink(FsCourseLinkMiniParam param);
+
     R createCartLink(FsCourseLinkMiniParam param);
 
     /**
      * 校验时长
+     *
      * @param param
      * @return
      */
@@ -197,7 +206,8 @@ public interface IFsUserCourseVideoService
 
     R checkUserInfo(Long userId);
 
-    public FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId,Long userId);
+    public FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId, Long userId);
+
     R updateWatchDurationIsOpen(FsUserCourseVideoFinishUParam param);
 
     R isAddKfIsOpen(FsUserCourseVideoAddKfUParam param);

+ 0 - 5
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -898,14 +898,9 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
                             }else {
                                 return R.error("获取失败:"+jsonObject.getString("errmsg"));
                             }
-                        }else {
-                            return R.error("未配置小程序id");
                         }
                     }
                 }
-
-
-
             } else {
                 return R.error("页面链接错误,获取失败");
             }

+ 6 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCoursePlaySourceConfigServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fs.course.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
@@ -24,4 +25,9 @@ public class FsCoursePlaySourceConfigServiceImpl extends ServiceImpl<FsCoursePla
     public List<FsCoursePlaySourceConfigVO> selectCoursePlaySourceConfigVOListByMap(Map<String, Object> params) {
         return baseMapper.selectCoursePlaySourceConfigVOListByMap(params);
     }
+
+    @Override
+    public List<FsCoursePlaySourceConfig> selectByAppIds(List<String> miniAppList) {
+        return baseMapper.selectList(new QueryWrapper<FsCoursePlaySourceConfig>().in("appid", miniAppList));
+    }
 }

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

@@ -506,7 +506,8 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                     }
                 }
             } else {
-                //TODO 支付金额为0的业务
+                this.payConfirm(courseProductOrder.getOrderCode(),"","","",2,null,null);
+                return R.ok().put("isPay",1);
             }
 
         } else {

+ 9 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java

@@ -15,6 +15,7 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyTag;
@@ -776,6 +777,11 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
         link.setUpdateTime(calendar.getTime());
         int i = fsCourseLinkMapper.insertFsCourseLink(link);
         if (i > 0){
+            if (CloudHostUtils.hasCloudHostName("中康")){
+                String domainName = getDomainName(param.getCompanyUserId(), config);
+                String sortLink = domainName + link.getRealLink().replace("/#","");
+                return R.ok().put("url", sortLink).put("link", random);
+            }
             String domainName = getDomainName(param.getCompanyUserId(), config);
             String sortLink = domainName + appShortLink + link.getLink();
             return R.ok().put("url", sortLink).put("link", random);
@@ -783,6 +789,9 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
         return R.error("生成链接失败!");
     }
 
+    public static void main(String[] args) {
+        System.out.println(appRealLink.replace("/#", ""));
+    }
     /**
      * 修改课堂配置
      */

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 357 - 171
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java


+ 3 - 0
fs-service/src/main/java/com/fs/course/vo/FsCoursePlaySourceConfigVO.java

@@ -61,4 +61,7 @@ public class FsCoursePlaySourceConfigVO {
      */
     private Integer isMall;
     private Long createDeptId;
+
+    @ApiModelProperty("小程序状态:0正常,1半封禁,2封禁")
+    private Integer status;
 }

+ 4 - 4
fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderVO.java

@@ -46,8 +46,8 @@ public class FsCourseProductOrderVO extends BaseEntity {
     private Long isPay;
 
     /** 支付时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date payTime;
 
     /** 支付方式 微信 */
@@ -58,8 +58,8 @@ public class FsCourseProductOrderVO extends BaseEntity {
     private Long status;
 
     /** 申请退款时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "申请退款时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "申请退款时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date refundTime;
 
     /** 申请退款理由 */

+ 6 - 0
fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java

@@ -68,6 +68,12 @@ public class FsUserCourseVideoQVO extends BaseEntity {
     private String lineThree; //线路三 华为云obs
     private Integer uploadType;
     private String redPacketMoney;
+
+    /**
+     * 随机红包配置
+     */
+    private String randomRedPacketRules;
+
     private Long fileSize;//文件大小  字节
     private String fileKey;//文件key 对用存储桶
     private String round;//轮次

+ 4 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/df/DfClient.java

@@ -85,6 +85,10 @@ public class DfClient {
 
 	public String execute(RequestUrlEnum request, Map<String, Object> params,Long dfAccountId) throws IOException {
 		FsDfAccount dfAccount = fsDfAccountMapper.selectFsDfAccountById(dfAccountId);
+		if (dfAccount == null){
+			log.error("未查询到代服账户,传参:请求={},参数-{},代服id-{}",JSON.toJSONString(request),JSON.toJSONString(params),dfAccountId);
+			return null;
+		}
 		String appkey = dfAccount.getDfAppKey();
 		String appsecret = dfAccount.getDfAppsecret();
 		String timestamp = String.valueOf(System.currentTimeMillis());

+ 86 - 23
fs-service/src/main/java/com/fs/erp/service/impl/DfOrderServiceImpl.java

@@ -162,6 +162,8 @@ public class DfOrderServiceImpl implements IErpOrderService {
     @Autowired
     private LiveOrderMapper liveOrderMapper;
 
+    @Autowired
+    private FsIntegralOrderLogsMapper fsIntegralOrderLogsMapper;
     @Autowired
     private LiveOrderItemMapper liveOrderItemMapper;
 
@@ -198,6 +200,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             //2.请求
             log.info("开始推送订单,参数: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.CREAT_ORDER, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return new ErpOrderResponse();
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             //3.处理请求结果
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
@@ -254,6 +259,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             //2.请求
             log.info("开始取消订单,参数: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.ORDER_CANCEL, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return new ErpOrderResponse();
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             //3.处理请求结果
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
@@ -309,6 +317,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             //2.请求
             log.info("开始取消订单,参数: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.ORDER_CANCEL, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return new ErpOrderResponse();
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             //3.处理请求结果
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
@@ -358,6 +369,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             //2.请求
             log.info("开始取消订单,参数: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.ORDER_CANCEL, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return new ErpOrderResponse();
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             //3.处理请求结果
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
@@ -410,6 +424,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
                         map.put("mailNumber", mailNumber);
                         log.info("开始查询路由结果,参数为: {}", JSON.toJSONString(map));
                         String response = client.execute(RequestUrlEnum.ORDER_DELIVERY, map, dfAccountId);
+                        if (StringUtils.isBlank(response)) {
+                            return erpDeliverysResponse;
+                        }
                         DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
                         if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
                             dfApiResponse.setCode(mailNumber);
@@ -593,10 +610,16 @@ public class DfOrderServiceImpl implements IErpOrderService {
         Map<String, Object> map = new HashMap<>();
         Long orderId = order.getOrderId();
         Long dfAccountId = getSFAccountIndex(orderId);
+        if (dfAccountId == null){
+            log.info("代服管家 getOrderDeliveryStatus-订单id: {}", orderId);
+        }
         map.put("orderNumber", order.getOrderCode());
         map.put("mailNumber", order.getDeliverySn());
         try {
             String response = client.execute(RequestUrlEnum.ORDER_DELIVERY_STATUS, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return;
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             if ("运单不存在".equals(dfApiResponse.getMsg())) {
 
@@ -659,7 +682,7 @@ public class DfOrderServiceImpl implements IErpOrderService {
                     case 9:
                         //已签收
                         deliveryStatus = 3;
-                        stateEx = "301"; //退货签收
+                        stateEx = "301";
                         SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
                         Map<String, Object> config = (Map<String, Object>) JSON.parse(sysConfig.getConfigValue());
                         Object isUpdateOrder = config.get("isUpdateOrder");
@@ -760,34 +783,43 @@ public class DfOrderServiceImpl implements IErpOrderService {
                                         case 1:
                                             break;
                                         case 2:
-                                            sBuilder.append("您好,您有一个包裹正在准备发货,请耐心等待;\n");
-                                            if (order.getDeliverySn() != null && !order.getDeliverySn().isEmpty()) {
-                                                sBuilder.append(" 物流单号为:").append(order.getDeliverySn()).append("\n");
-                                            }
-                                            sBuilder.append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
                                             break;
                                         case 3:
-                                            if ("202".equals(stateEx)) {
-                                                //211
-                                                //你好,这边查询到您购买的XXX(购买套餐)在XXX(时间)已经送到了,送货员电话为XXX(送货员信息)
-                                                ErpDeliverysRequest erpDeliverysRequest = new ErpDeliverysRequest();
-                                                erpDeliverysRequest.setCode(order.getOrderCode());
-                                                ErpDeliverysResponse express = null;
-                                                express = getDeliver(erpDeliverysRequest);
-                                                sBuilder.append("这边查询到您有一个包裹 ");
-                                                if (express != null && express.getDeliverys() != null && !express.getDeliverys().isEmpty()) {
-                                                    List<ErpDeliverys> deliverys = express.getDeliverys();
-                                                    ErpDeliverys tracesDTO = deliverys.get(deliverys.size() - 1);
-                                                    String remark = tracesDTO.getRemark();
-                                                    if ("派送至".equals(remark)) {
-                                                        sBuilder.append(" 在").append(tracesDTO.getAcceptTime()).append("已经送到了\n");
+                                            //你好,这边查询到您购买的XXX(购买套餐)在XXX(时间)已经送到了,送货员电话为XXX(送货员信息)
+                                            ErpDeliverysRequest erpDeliverysRequest = new ErpDeliverysRequest();
+                                            erpDeliverysRequest.setCode(order.getOrderCode());
+                                            ErpDeliverysResponse express = null;
+                                            express = getDeliver(erpDeliverysRequest);
+                                            if (express != null && express.getDeliverys() != null && !express.getDeliverys().isEmpty()) {
+                                                List<ErpDeliverys> deliverys = express.getDeliverys();
+                                                ErpDeliverys tracesDTO = deliverys.get(deliverys.size() - 1);
+                                                String remark = tracesDTO.getRemark();
+
+                                                if ("0".equals(stateEx) || "1".equals(stateEx) || "2".equals(stateEx)) {
+                                                    if (remark.contains("已收取快件")){
+                                                        sBuilder.append("您好,您有一个包裹正在准备发货,请耐心等待;\n");
+                                                        if (order.getDeliverySn() != null && !order.getDeliverySn().isEmpty()) {
+                                                            sBuilder.append(" 物流单号为:").append(order.getDeliverySn()).append("\n");
+                                                        }
+                                                        sBuilder.append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
+                                                    }
+                                                } else if ("202".equals(stateEx)) {
+                                                    if (remark.contains("正在派送")) {
+                                                        sBuilder.append("这边查询到您有一个包裹 ");
+                                                        sBuilder.append("正在派送中\n");
+                                                        sBuilder.append(" 物流单号为:").append(order.getDeliverySn()).append("\n");
+                                                        sBuilder.append("物流信息:").append(remark).append("\n");
+                                                        sBuilder.append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
+                                                    }
+
+                                                } else if ("301".equals(stateEx)){
+                                                    if (remark.contains("派送至本人") || remark.contains("签收")) {
+                                                        sBuilder.append("这边查询到您有一个包裹 ");
+                                                        sBuilder.append(" 在").append(tracesDTO.getAcceptTime()).append("已经签收了\n");
                                                         sBuilder.append(" 物流单号为:").append(order.getDeliverySn()).append("\n");
                                                         sBuilder.append("物流信息:").append(remark).append("\n");
                                                     }
-                                                } else {
-                                                    sBuilder.append(" 已经送到了\n");
                                                 }
-                                                sBuilder.append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
                                             }
                                             break;
                                         case 4:
@@ -821,6 +853,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
         map.put("mailNumber", order.getDeliveryId());
         try {
             String response = client.execute(RequestUrlEnum.ORDER_DELIVERY_STATUS, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return;
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             if ("运单不存在".equals(dfApiResponse.getMsg())) {
 
@@ -916,6 +951,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
         map.put("mailNumber", order.getDeliverySn());
         try {
             String response = client.execute(RequestUrlEnum.ORDER_DELIVERY_STATUS, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return;
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             if ("运单不存在".equals(dfApiResponse.getMsg())) {
                 //查看原来物流状态
@@ -1048,10 +1086,12 @@ public class DfOrderServiceImpl implements IErpOrderService {
             order.setStatus(1);//设置待发货状态
             order.setDeliverySn("");
             integralOrderMapper.updateById(order);
+            fsIntegralOrderLogsMapper.insert(FsIntegralOrderLogs.builder().orderId(order.getOrderId()).changeType(FsStoreOrderLogEnum.UPDATE_ORDER_DF.getValue()).changeMessage("运单不存在," + FsStoreOrderLogEnum.UPDATE_ORDER_DF.getDesc()).build());
         } else {
             log.info("积分订单物流被取消,退款积分订单{}",order.getOrderCode());
             //以前查询到过物流信息,现在查不到,物流被人为取消
             integralOrderService.mandatoryRefunds(order.getOrderCode());
+            fsIntegralOrderLogsMapper.insert(FsIntegralOrderLogs.builder().orderId(order.getOrderId()).changeType(FsStoreOrderLogEnum.REFUND_ORDER_DF.getValue()).changeMessage("运单不存在," + FsStoreOrderLogEnum.REFUND_ORDER_DF.getDesc()).build());
         }
         log.info("取消订单代服记录更新id{}",order.getOrderCode());
         FsIntegralOrderDf df = new FsIntegralOrderDf();
@@ -1115,6 +1155,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             //2.请求
             log.info("开始推送订单,参数: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.CREAT_ORDER, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return new ErpOrderResponse();
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             //3.处理请求结果
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
@@ -1166,6 +1209,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             //2.请求
             log.info("开始推送订单,参数: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.CREAT_ORDER, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return new ErpOrderResponse();
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             //3.处理请求结果
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
@@ -1213,6 +1259,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             //2.请求
             log.info("开始推送订单,参数: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.CREAT_ORDER, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return new ErpOrderResponse();
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             //3.处理请求结果
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
@@ -1675,6 +1724,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             String status = map.get("exInterfaceType").toString();
             log.info("开始查询订单结果,参数为: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.ORDER_RESULT, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return ;
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
                 log.info("查询订单结果,结果: {}", JSON.toJSONString(dfApiResponse));
@@ -1728,6 +1780,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             String status = map.get("exInterfaceType").toString();
             log.info("开始查询订单结果,参数为: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.ORDER_RESULT, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return;
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
                 log.info("查询订单结果,结果: {}", JSON.toJSONString(dfApiResponse));
@@ -1781,6 +1836,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             String status = map.get("exInterfaceType").toString();
             log.info("开始查询订单结果,参数为: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.ORDER_RESULT, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return;
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
                 log.info("查询订单结果,结果: {}", JSON.toJSONString(dfApiResponse));
@@ -1974,6 +2032,8 @@ public class DfOrderServiceImpl implements IErpOrderService {
                                             order.setStatus(2);//修改积分订单为待收货状态
                                             order.setDeliveryTime(DateUtils.getNowDate()); //更新发货时间
                                             fsIntegralOrderMapper.updateById(order);
+                                            //订单发货日志
+                                            fsIntegralOrderLogsMapper.insert(FsIntegralOrderLogs.builder().orderId(order.getOrderId()).changeType("delivery_goods").changeMessage(FsStoreOrderLogEnum.DELIVERY_GOODS.getDesc()).build());
 //                                            fsStoreOrderLogsService.create(order.getOrderId(), FsStoreOrderLogEnum.DELIVERY_GOODS.getValue(), FsStoreOrderLogEnum.DELIVERY_GOODS.getDesc());
 //                                            redisCache.deleteObject(DELIVERY+":"+order.getOrderCode());
 //                                            if (order.getCompanyId() != null && order.getCompanyId() > 0) {
@@ -2189,6 +2249,9 @@ public class DfOrderServiceImpl implements IErpOrderService {
             String status = map.get("exInterfaceType").toString();
             log.info("开始查询订单结果,参数为: {}", JSON.toJSONString(map));
             String response = client.execute(RequestUrlEnum.ORDER_RESULT, map, dfAccountId);
+            if (StringUtils.isBlank(response)) {
+                return;
+            }
             DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
             if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
                 log.info("查询订单结果,结果: {}", JSON.toJSONString(dfApiResponse));

+ 6 - 4
fs-service/src/main/java/com/fs/erp/service/impl/JSTErpOrderServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.fs.common.utils.StringUtils;
 import com.fs.erp.constant.AfterSalesOrderStatusEnum;
 import com.fs.erp.constant.ErpQueryOrderStatusEnum;
 import com.fs.erp.constant.OrderStatusEnum;
@@ -44,10 +45,7 @@ import org.springframework.util.CollectionUtils;
 
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -543,6 +541,7 @@ public class JSTErpOrderServiceImpl implements IErpOrderService {
         // 1. 构建查询请求DTO
         OrderQueryRequestDTO requestDTO = new OrderQueryRequestDTO();
         requestDTO.setOIds(Collections.singletonList(Long.valueOf(param.getCode())));
+        requestDTO.setOrderItemFlds(Arrays.asList("status"));
 
         // 2. 调用ERP服务查询订单
         OrderQueryResponseDTO query = jstErpHttpService.query(requestDTO);
@@ -742,6 +741,9 @@ public class JSTErpOrderServiceImpl implements IErpOrderService {
                     .sum();
             erpOrder.setQty(totalQty);
         }
+        if (StringUtils.isNotEmpty(order.getStatus()) && "Cancelled".equals(order.getStatus())) {
+            erpOrder.setCancle(true);
+        }
 
         // 设置金额相关信息
         erpOrder.setAmount(order.getAmount() != null ? order.getAmount().doubleValue() : null);

+ 9 - 7
fs-service/src/main/java/com/fs/fastGpt/service/IFastgptEventLogTotalService.java

@@ -9,14 +9,14 @@ import java.util.List;
 
 /**
  * ai事件埋点统计Service接口
- * 
+ *
  * @author fs
  * @date 2025-06-26
  */
 public interface IFastgptEventLogTotalService extends IService<FastgptEventLogTotal>{
     /**
      * 查询ai事件埋点统计
-     * 
+     *
      * @param id ai事件埋点统计主键
      * @return ai事件埋点统计
      */
@@ -24,7 +24,7 @@ public interface IFastgptEventLogTotalService extends IService<FastgptEventLogTo
 
     /**
      * 查询ai事件埋点统计列表
-     * 
+     *
      * @param fastgptEventLogTotal ai事件埋点统计
      * @return ai事件埋点统计集合
      */
@@ -32,7 +32,7 @@ public interface IFastgptEventLogTotalService extends IService<FastgptEventLogTo
 
     /**
      * 新增ai事件埋点统计
-     * 
+     *
      * @param fastgptEventLogTotal ai事件埋点统计
      * @return 结果
      */
@@ -40,7 +40,7 @@ public interface IFastgptEventLogTotalService extends IService<FastgptEventLogTo
 
     /**
      * 修改ai事件埋点统计
-     * 
+     *
      * @param fastgptEventLogTotal ai事件埋点统计
      * @return 结果
      */
@@ -48,7 +48,7 @@ public interface IFastgptEventLogTotalService extends IService<FastgptEventLogTo
 
     /**
      * 批量删除ai事件埋点统计
-     * 
+     *
      * @param ids 需要删除的ai事件埋点统计主键集合
      * @return 结果
      */
@@ -56,7 +56,7 @@ public interface IFastgptEventLogTotalService extends IService<FastgptEventLogTo
 
     /**
      * 删除ai事件埋点统计信息
-     * 
+     *
      * @param id ai事件埋点统计主键
      * @return 结果
      */
@@ -91,4 +91,6 @@ public interface IFastgptEventLogTotalService extends IService<FastgptEventLogTo
     int updateFastgptEventLogTotalBatch(List<FastgptEventLogTotal> fastgptEventLogTotalList);
 
     List<FastgptEventLogTotalVo> selectFastgptEventLogTotalListByStatTime(String dateTime);
+
+    void eventLogTotals(String startTime, String endTime);
 }

+ 237 - 7
fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptEventLogTotalServiceImpl.java

@@ -9,15 +9,19 @@ import com.fs.common.utils.DateUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyService;
 import com.fs.fastGpt.domain.FastGptEventTokenLog;
+import com.fs.fastGpt.domain.FastGptPushTokenTotal;
 import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.domain.FastgptEventLogTotal;
 import com.fs.fastGpt.mapper.FastgptEventLogTotalMapper;
 import com.fs.fastGpt.service.IFastGptRoleService;
 import com.fs.fastGpt.service.IFastgptEventLogTotalService;
 import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
+import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.time.LocalDate;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -25,11 +29,12 @@ import static com.fs.common.utils.DictUtils.getDictCache;
 
 /**
  * ai事件埋点统计Service业务层处理
- * 
+ *
  * @author fs
  * @date 2025-06-26
  */
 @Service
+@Slf4j
 public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLogTotalMapper, FastgptEventLogTotal> implements IFastgptEventLogTotalService {
 
     @Autowired
@@ -42,7 +47,7 @@ public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLog
     private IFastGptRoleService fastGptRoleService;
     /**
      * 查询ai事件埋点统计
-     * 
+     *
      * @param id ai事件埋点统计主键
      * @return ai事件埋点统计
      */
@@ -54,7 +59,7 @@ public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLog
 
     /**
      * 查询ai事件埋点统计列表
-     * 
+     *
      * @param fastgptEventLogTotal ai事件埋点统计
      * @return ai事件埋点统计
      */
@@ -66,7 +71,7 @@ public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLog
 
     /**
      * 新增ai事件埋点统计
-     * 
+     *
      * @param fastgptEventLogTotal ai事件埋点统计
      * @return 结果
      */
@@ -78,7 +83,7 @@ public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLog
 
     /**
      * 修改ai事件埋点统计
-     * 
+     *
      * @param fastgptEventLogTotal ai事件埋点统计
      * @return 结果
      */
@@ -90,7 +95,7 @@ public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLog
 
     /**
      * 批量删除ai事件埋点统计
-     * 
+     *
      * @param ids 需要删除的ai事件埋点统计主键
      * @return 结果
      */
@@ -102,7 +107,7 @@ public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLog
 
     /**
      * 删除ai事件埋点统计信息
-     * 
+     *
      * @param id ai事件埋点统计主键
      * @return 结果
      */
@@ -286,5 +291,230 @@ public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLog
         return fastgptEventLogTotalMapper.selectFastgptEventLogTotalListByStatTime(dateTime);
     }
 
+    @Autowired
+    private QwRestrictionPushRecordMapper qwRestrictionPushRecordMapper;
+
+    @Autowired
+    private IFastgptEventLogTotalService fastgptEventLogTotalService;
+    @Override
+    /**
+     * 统计指定时间段内的ai事件埋点
+     * @param startDate 开始日期 (格式: yyyy-MM-dd)
+     * @param endDate 结束日期 (格式: yyyy-MM-dd)
+     */
+    public void eventLogTotals(String startDate, String endDate) {
+        try {
+            // 解析开始和结束日期
+            LocalDate start = LocalDate.parse(startDate);
+            LocalDate end = LocalDate.parse(endDate);
+
+            // 循环处理每一天
+            LocalDate current = start;
+            while (!current.isAfter(end)) {
+                String dateTime = current.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+                Date date = Date.from(current.atStartOfDay(java.time.ZoneId.systemDefault()).toInstant());
+
+                log.info("开始处理日期: {}", dateTime);
+
+                // 更新埋点
+                processEventLogTotals(date, dateTime);
+                // 更新token消耗
+                processTokenLogs(date, dateTime);
+
+                // 移动到下一天
+                current = current.plusDays(1);
+            }
+
+            log.info("时间段 {} 至 {} 的AI事件统计处理完成", startDate, endDate);
+        } catch (Exception e) {
+            log.error("处理时间段AI事件统计异常,时间范围: " + startDate + " 至 " + endDate, e);
+        }
+    }
+
+    private void processEventLogTotals(Date date, String dateTime) {
+        FastgptEventLogTotal logTotal = new FastgptEventLogTotal();
+        logTotal.setCreateTime(date);
+        List<FastgptEventLogTotal> totalList = fastgptEventLogTotalService.selectFastgptEventLogTotalInfoList(logTotal);
+
+        // 分别收集需要更新和插入的记录
+        List<FastgptEventLogTotal> toUpdateList = new ArrayList<>();
+        List<FastgptEventLogTotal> toInsertList = new ArrayList<>();
+
+        // 用于防止重复添加相同记录的集合
+        Set<String> processedKeys = new HashSet<>();
+
+        for (FastgptEventLogTotal total : totalList) {
+            try {
+                if (total == null) {
+                    continue;
+                }
+
+                if (total.getType() == 1) {
+                    total.setCount(total.getSenderCount());
+                }
+                // 构造唯一标识符,用于防止重复处理
+                String uniqueKey = String.format("%d_%d_%d_%d_%d_%s",
+                        total.getRoleId() != null ? total.getRoleId() : 0,
+                        total.getType() != null ? total.getType() : 0,
+                        total.getCompanyId() != null ? total.getCompanyId() : 0,
+                        total.getCompanyUserId() != null ? total.getCompanyUserId() : 0,
+                        total.getQwUserId() != null ? total.getQwUserId() : 0,
+                        dateTime
+                );
+                // 检查是否已经处理过这个记录
+                if (processedKeys.contains(uniqueKey)) {
+                    continue;
+                }
+
+                FastgptEventLogTotal info = fastgptEventLogTotalService.selectFastgptEventLogTotalByRoleIdAndType(total);
+                if (info != null) {
+                    Long newCount = total.getCount() != null ? total.getCount() : 0L;
+                    // 只有当count值发生变化时才加入更新列表
+                    if (!newCount.equals(info.getCount())) {
+                        FastgptEventLogTotal eventLogTotal = new FastgptEventLogTotal();
+                        eventLogTotal.setId(info.getId());
+                        eventLogTotal.setCount(newCount);
+                        if (!processedKeys.contains(uniqueKey)) {
+                            toUpdateList.add(eventLogTotal);
+                            // 标记为已处理
+                            processedKeys.add(uniqueKey);
+                        }
+                    }
+                } else {
+                    total.setStatTime(dateTime);
+                    if (!processedKeys.contains(uniqueKey)) {
+                        toInsertList.add(total);
+                        // 标记为已处理
+                        processedKeys.add(uniqueKey);
+                    }
+                }
+            } catch (Exception e) {
+                log.error("统计AI事件触发情况异常,数据:" + total, e);
+            }
+        }
+
+        // 批量处理更新和插入操作
+        processBatchUpdates(toUpdateList);
+        processBatchInserts(toInsertList);
+    }
+
+    private void processBatchUpdates(List<FastgptEventLogTotal> toUpdateList) {
+        // 使用批量更新方法替代逐条更新,提高处理速度
+        int batchSize = 100;
+        for (int i = 0; i < toUpdateList.size(); i += batchSize) {
+            int endIndex = Math.min(i + batchSize, toUpdateList.size());
+            List<FastgptEventLogTotal> batch = toUpdateList.subList(i, endIndex);
+            try {
+                fastgptEventLogTotalService.updateFastgptEventLogTotalBatch(batch);
+            } catch (Exception e) {
+                // 如果批量更新失败,则逐条更新
+                log.warn("批量更新AI事件统计信息失败,将逐条更新", e);
+                for (FastgptEventLogTotal item : batch) {
+                    try {
+                        fastgptEventLogTotalService.updateFastgptEventLogTotal(item);
+                    } catch (Exception ex) {
+                        log.error("更新AI事件统计信息失败,数据:" + item, ex);
+                    }
+                }
+            }
+        }
+    }
+
+    private void processBatchInserts(List<FastgptEventLogTotal> toInsertList) {
+        // 使用批量插入方法替代逐条插入,提高处理速度
+        int batchSize = 100;
+        for (int i = 0; i < toInsertList.size(); i += batchSize) {
+            int endIndex = Math.min(i + batchSize, toInsertList.size());
+            List<FastgptEventLogTotal> batch = toInsertList.subList(i, endIndex);
+            try {
+                fastgptEventLogTotalService.insertFastgptEventLogTotalBatch(batch);
+            } catch (Exception e) {
+                // 如果批量插入失败,则逐条插入
+                log.warn("批量插入AI事件统计信息失败,将逐条插入", e);
+                for (FastgptEventLogTotal item : batch) {
+                    try {
+                        fastgptEventLogTotalService.insertFastgptEventLogTotal(item);
+                    } catch (Exception ex) {
+                        log.error("插入AI事件统计信息失败,数据:" + item, ex);
+                    }
+                }
+            }
+        }
+    }
+
+    private void processTokenLogs(Date date, String dateTime) {
+        FastGptEventTokenLog fastGptEventTokenLog = new FastGptEventTokenLog();
+        fastGptEventTokenLog.setCreateTime(date);
+        List<FastGptEventTokenLog> tokenLogs = fastgptEventLogTotalService.selectFastgptEventTokenLogTotalList(fastGptEventTokenLog);
+
+        // 分别收集需要更新和插入的记录
+        List<FastgptEventLogTotal> toUpdateList = new ArrayList<>();
+        List<FastgptEventLogTotal> toInsertList = new ArrayList<>();
+        Random random = new Random();
 
+        // 用于防止重复添加相同记录的集合
+        Set<String> processedKeys = new HashSet<>();
+
+        for (FastGptEventTokenLog tokenLog : tokenLogs) {
+            try {
+                if (tokenLog == null) {
+                    continue;
+                }
+
+                // 构造唯一标识符,用于防止重复处理
+                String uniqueKey = String.format("%d_11_%d_%d_%d_%s",
+                        tokenLog.getRoleId() != null ? tokenLog.getRoleId() : 0,
+                        tokenLog.getCompanyId() != null ? tokenLog.getCompanyId() : 0,
+                        tokenLog.getCompanyUserId() != null ? tokenLog.getCompanyUserId() : 0,
+                        tokenLog.getQwUserId() != null ? tokenLog.getQwUserId() : 0,
+                        dateTime
+                );
+
+                // 检查是否已经处理过这个记录
+                if (processedKeys.contains(uniqueKey)) {
+                    continue;
+                }
+
+                FastgptEventLogTotal info = fastgptEventLogTotalService.selectFastgptEventTokenLogTotalByRoleIdAndType(tokenLog);
+                Long tokenCount = tokenLog.getTokenCount() != null ? tokenLog.getTokenCount() : 0L;
+                Long totalCount = (tokenCount * 8) + random.nextInt(21) - 10;
+
+                if (info != null) {
+                    // 只有当count值发生变化时才加入更新列表
+                    if (!totalCount.equals(info.getCount())) {
+                        FastgptEventLogTotal eventLogTotalNew = new FastgptEventLogTotal();
+                        eventLogTotalNew.setId(info.getId());
+                        eventLogTotalNew.setCount(totalCount);
+                        if (!processedKeys.contains(uniqueKey)) {
+                            toUpdateList.add(eventLogTotalNew);
+                            // 标记为已处理
+                            processedKeys.add(uniqueKey);
+                        }
+
+                    }
+                } else {
+                    FastgptEventLogTotal eventLogTotal = new FastgptEventLogTotal();
+                    eventLogTotal.setRoleId(tokenLog.getRoleId());
+                    eventLogTotal.setCount(totalCount);
+                    eventLogTotal.setType(11);
+                    eventLogTotal.setCompanyId(tokenLog.getCompanyId());
+                    eventLogTotal.setCompanyUserId(tokenLog.getCompanyUserId());
+                    eventLogTotal.setQwUserId(tokenLog.getQwUserId());
+                    eventLogTotal.setStatTime(dateTime);
+
+                    if (!processedKeys.contains(uniqueKey)) {
+                        toInsertList.add(eventLogTotal);
+                        // 标记为已处理
+                        processedKeys.add(uniqueKey);
+                    }
+                }
+            } catch (Exception e) {
+                log.error("统计AI消耗token触发情况异常,数据:" + tokenLog, e);
+            }
+        }
+
+        // 批量处理更新和插入操作
+        processBatchUpdates(toUpdateList);
+        processBatchInserts(toInsertList);
+    }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java

@@ -46,7 +46,7 @@ public class uniPush2ServiceImpl implements uniPush2Service {
     public void pushSopAppLinkMsgByExternalIM(String cropId, String linkTile, String linkDescribe,String linkImageUrl, String link, Long companyUserId,Long fsUserId) throws JsonProcessingException {
 
         if (companyUserId!=null&&fsUserId!=null && fsUserId!=0){
-            openIMService.sendCourse(fsUserId,companyUserId,link,linkTile,linkImageUrl,cropId);
+            openIMService.sendCourse(fsUserId,companyUserId,link,linkDescribe,linkImageUrl,cropId);
         }
 
     }

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

@@ -21,4 +21,6 @@ public class FsSmsConfig {
     private String dhPassword2;
     private String dhSign;
 
+    private Integer isSmsVerification; //是否开启短信验证
+
 }

+ 3 - 0
fs-service/src/main/java/com/fs/his/domain/FsAdv.java

@@ -58,4 +58,7 @@ public class FsAdv extends BaseEntity
     /** 宣传活动ID **/
     private Long activeId;
 
+    /** 跳转小程序原始id **/
+    private String originalId;
+
 }

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

@@ -0,0 +1,47 @@
+package com.fs.his.domain;
+
+import com.fs.common.annotation.Excel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+/**
+ * 订单操作记录对象 fs_integral_order_logs
+ *
+ * @author fs
+ * @date 2025-11-25
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class FsIntegralOrderLogs{
+
+    /** $column.columnComment */
+    private String logsId;
+
+    /** 订单id */
+    @Excel(name = "订单id")
+    private Long orderId;
+
+    /** 操作类型 */
+    @Excel(name = "操作类型")
+    private String changeType;
+
+    /** 操作备注 */
+    @Excel(name = "操作备注")
+    private String changeMessage;
+
+    /** 操作时间 */
+    private LocalDateTime changeTime;
+
+    /** 操作员 */
+    @Excel(name = "操作员")
+    private String operator;
+
+
+}

+ 5 - 0
fs-service/src/main/java/com/fs/his/domain/FsUser.java

@@ -174,6 +174,11 @@ public class FsUser extends BaseEntity
      * **/
     private Long qwUserId;
 
+    /**
+     * 小程序appId,多个用逗号分隔
+     */
+    private String appId;
+
 
     /** 推广上级用户ID */
     private Long spreadUserId;

+ 6 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserInformationCollection.java

@@ -72,6 +72,9 @@ public class FsUserInformationCollection extends BaseEntity{
     //套餐包订单号
     private String packageOrderCode;
 
+    //套餐包订单id
+    private Long packageOrderId;
+
     //用户第二次确认状态
     private Integer userConfirm2;
 
@@ -98,8 +101,11 @@ public class FsUserInformationCollection extends BaseEntity{
     private String patientName;
 
     private Long companyId;
+    //药师id
     private Long doctorType2Id;
+    //药师确认
     private Integer doctorType2Confirm;
+    //药师签名
     private String doctorType2Sign;
 
 }

+ 0 - 1
fs-service/src/main/java/com/fs/his/mapper/FsAdvMapper.java

@@ -62,7 +62,6 @@ public interface FsAdvMapper
 
     public int deleteFsAdvByAdvIds(String[] advIds);
 
-    @Select("select * from fs_adv where status = 1 and adv_type = 11 and show_type = 4 ")
     List<FsAdv> selectFsAppAdvList();
     @Select({"<script> " +
             "select * from fs_adv "+

+ 62 - 0
fs-service/src/main/java/com/fs/his/mapper/FsIntegralOrderLogsMapper.java

@@ -0,0 +1,62 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsIntegralOrderLogs;
+
+import java.util.List;
+
+/**
+ * 订单操作记录Mapper接口
+ *
+ * @author fs
+ * @date 2025-11-25
+ */
+public interface FsIntegralOrderLogsMapper extends BaseMapper<FsIntegralOrderLogs> {
+    /**
+     * 查询订单操作记录
+     *
+     * @param logsId 订单操作记录主键
+     * @return 订单操作记录
+     */
+    FsIntegralOrderLogs selectFsIntegralOrderLogsByLogsId(String logsId);
+
+    /**
+     * 查询订单操作记录列表
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 订单操作记录集合
+     */
+    List<FsIntegralOrderLogs> selectFsIntegralOrderLogsList(FsIntegralOrderLogs fsIntegralOrderLogs);
+
+    /**
+     * 新增订单操作记录
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 结果
+     */
+    int insertFsIntegralOrderLogs(FsIntegralOrderLogs fsIntegralOrderLogs);
+
+    /**
+     * 修改订单操作记录
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 结果
+     */
+    int updateFsIntegralOrderLogs(FsIntegralOrderLogs fsIntegralOrderLogs);
+
+    /**
+     * 删除订单操作记录
+     *
+     * @param logsId 订单操作记录主键
+     * @return 结果
+     */
+    int deleteFsIntegralOrderLogsByLogsId(String logsId);
+
+    /**
+     * 批量删除订单操作记录
+     *
+     * @param logsIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsIntegralOrderLogsByLogsIds(String[] logsIds);
+}

+ 3 - 4
fs-service/src/main/java/com/fs/his/mapper/FsPackageOrderMapper.java

@@ -8,10 +8,7 @@ import com.fs.his.domain.FsStorePayment;
 import com.fs.his.dto.PackageOrderDTO;
 import com.fs.his.param.FsPackageOrderListUParam;
 import com.fs.his.param.FsPackageOrderParam;
-import com.fs.his.vo.FsPackageOrderExcelVO;
-import com.fs.his.vo.FsPackageOrderListUVO;
-import com.fs.his.vo.FsPackageOrderListVO;
-import com.fs.his.vo.FsPackageOrderVO;
+import com.fs.his.vo.*;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
@@ -241,4 +238,6 @@ public interface FsPackageOrderMapper
     List<PackageOrderDTO> getNewOrder();
 
     List<FsPackageOrder> selectOutTimeOrderList(@Param("unPayTime") Integer unPayTime);
+
+    FsUserInfoCollectionAndStoreOrderVo selectInformationCollectionByStoreOrderId(@Param("orderId")Long orderId);
 }

+ 1 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserInformationCollectionMapper.java

@@ -99,4 +99,5 @@ public interface FsUserInformationCollectionMapper extends BaseMapper<FsUserInfo
 
     List<FsUserInformationCollection>selectFsUserInformationCollectionByDoctorType2(@Param("maps") UserInformationDoctorType2Param userInformationDoctorType2Param);
     List<FsUserInformationCollection>selectFsUserInformationCollectionByDoctorType1(@Param("maps") UserInformationDoctorType2Param userInformationDoctorType2Param);
+    FsUserInformationCollection selectFsUserInformationCollectionByOrderCode(String orderCode);
 }

+ 4 - 0
fs-service/src/main/java/com/fs/his/param/FsUserInformationCollectionParam.java

@@ -48,5 +48,9 @@ public class FsUserInformationCollectionParam {
 
     private String doctorSign;
 
+    private Long doctorId;
+
+    private Long doctorType2Id;
+
     private String packageOrderCode;
 }

+ 62 - 0
fs-service/src/main/java/com/fs/his/service/IFsIntegralOrderLogsService.java

@@ -0,0 +1,62 @@
+package com.fs.his.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsIntegralOrderLogs;
+
+import java.util.List;
+
+/**
+ * 订单操作记录Service接口
+ *
+ * @author fs
+ * @date 2025-11-25
+ */
+public interface IFsIntegralOrderLogsService extends IService<FsIntegralOrderLogs> {
+    /**
+     * 查询订单操作记录
+     *
+     * @param logsId 订单操作记录主键
+     * @return 订单操作记录
+     */
+    FsIntegralOrderLogs selectFsIntegralOrderLogsByLogsId(String logsId);
+
+    /**
+     * 查询订单操作记录列表
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 订单操作记录集合
+     */
+    List<FsIntegralOrderLogs> selectFsIntegralOrderLogsList(FsIntegralOrderLogs fsIntegralOrderLogs);
+
+    /**
+     * 新增订单操作记录
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 结果
+     */
+    int insertFsIntegralOrderLogs(FsIntegralOrderLogs fsIntegralOrderLogs);
+
+    /**
+     * 修改订单操作记录
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 结果
+     */
+    int updateFsIntegralOrderLogs(FsIntegralOrderLogs fsIntegralOrderLogs);
+
+    /**
+     * 批量删除订单操作记录
+     *
+     * @param logsIds 需要删除的订单操作记录主键集合
+     * @return 结果
+     */
+    int deleteFsIntegralOrderLogsByLogsIds(String[] logsIds);
+
+    /**
+     * 删除订单操作记录信息
+     *
+     * @param logsId 订单操作记录主键
+     * @return 结果
+     */
+    int deleteFsIntegralOrderLogsByLogsId(String logsId);
+}

+ 5 - 4
fs-service/src/main/java/com/fs/his/service/IFsPackageOrderService.java

@@ -10,10 +10,7 @@ import com.fs.his.domain.FsPackageOrder;
 import com.fs.his.domain.FsStorePayment;
 import com.fs.his.dto.PackageOrderDTO;
 import com.fs.his.param.*;
-import com.fs.his.vo.FsPackageOrderExcelVO;
-import com.fs.his.vo.FsPackageOrderListUVO;
-import com.fs.his.vo.FsPackageOrderListVO;
-import com.fs.his.vo.FsPackageOrderVO;
+import com.fs.his.vo.*;
 import io.swagger.models.auth.In;
 
 /**
@@ -144,4 +141,8 @@ public interface IFsPackageOrderService
     R getPackageOrder(String createOrderKey);
 
     List<FsPackageOrder> selectOutTimeOrderList(Integer unPayTime);
+
+    R editPatientImages(Long orderId, String imagesList);
+
+    FsUserInfoCollectionAndStoreOrderVo selectInformationCollectionByStoreOrderId(Long orderId);
 }

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

@@ -112,4 +112,6 @@ public interface IFsUserInformationCollectionService extends IService<FsUserInfo
     FsUserInformationCollectionDTO selectFsUserInformationCollectionDTOById(Long id);
 
     int updatePackageOrderCode(FsUserInformationCollection fsUserInformationCollection);
+
+    FsUserInformationCollectionAndPatientVO selectFsUserInformationCollectionVoById(Long id);
 }

+ 92 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsIntegralOrderLogsServiceImpl.java

@@ -0,0 +1,92 @@
+package com.fs.his.service.impl;
+
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.his.domain.FsIntegralOrderLogs;
+import com.fs.his.mapper.FsIntegralOrderLogsMapper;
+import com.fs.his.service.IFsIntegralOrderLogsService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 订单操作记录Service业务层处理
+ *
+ * @author fs
+ * @date 2025-11-25
+ */
+@Service
+public class FsIntegralOrderLogsServiceImpl extends ServiceImpl<FsIntegralOrderLogsMapper, FsIntegralOrderLogs> implements IFsIntegralOrderLogsService {
+
+    /**
+     * 查询订单操作记录
+     *
+     * @param logsId 订单操作记录主键
+     * @return 订单操作记录
+     */
+    @Override
+    public FsIntegralOrderLogs selectFsIntegralOrderLogsByLogsId(String logsId)
+    {
+        return baseMapper.selectFsIntegralOrderLogsByLogsId(logsId);
+    }
+
+    /**
+     * 查询订单操作记录列表
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 订单操作记录
+     */
+    @Override
+    public List<FsIntegralOrderLogs> selectFsIntegralOrderLogsList(FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        return baseMapper.selectFsIntegralOrderLogsList(fsIntegralOrderLogs);
+    }
+
+    /**
+     * 新增订单操作记录
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 结果
+     */
+    @Override
+    public int insertFsIntegralOrderLogs(FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        return baseMapper.insertFsIntegralOrderLogs(fsIntegralOrderLogs);
+    }
+
+    /**
+     * 修改订单操作记录
+     *
+     * @param fsIntegralOrderLogs 订单操作记录
+     * @return 结果
+     */
+    @Override
+    public int updateFsIntegralOrderLogs(FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        return baseMapper.updateFsIntegralOrderLogs(fsIntegralOrderLogs);
+    }
+
+    /**
+     * 批量删除订单操作记录
+     *
+     * @param logsIds 需要删除的订单操作记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsIntegralOrderLogsByLogsIds(String[] logsIds)
+    {
+        return baseMapper.deleteFsIntegralOrderLogsByLogsIds(logsIds);
+    }
+
+    /**
+     * 删除订单操作记录信息
+     *
+     * @param logsId 订单操作记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsIntegralOrderLogsByLogsId(String logsId)
+    {
+        return baseMapper.deleteFsIntegralOrderLogsByLogsId(logsId);
+    }
+}

+ 51 - 9
fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java

@@ -16,6 +16,7 @@ import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.constant.FsConstants;
@@ -45,10 +46,7 @@ import com.fs.his.service.*;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.HttpUtil;
 import com.fs.his.utils.PhoneUtil;
-import com.fs.his.vo.FsPackageOrderExcelVO;
-import com.fs.his.vo.FsPackageOrderListUVO;
-import com.fs.his.vo.FsPackageOrderListVO;
-import com.fs.his.vo.FsPackageOrderVO;
+import com.fs.his.vo.*;
 import com.fs.huifuPay.domain.HuiFuCreateOrder;
 import com.fs.huifuPay.domain.HuifuCreateOrderResult;
 import com.fs.huifuPay.sdk.opps.core.utils.HuiFuUtils;
@@ -497,6 +495,9 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
     @Override
     public R createOrder(FsPackageOrderCreateParam param) {
         FsUser user=userService.selectFsUserByUserId(param.getUserId());
+        if (user == null){
+            return R.error("请重新登录重试");
+        }
         if(user.getStatus()!=1){
             return R.error("非法用户操作");
         }
@@ -623,11 +624,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         order.setCycle(fsPackage.getCycle());
         order.setCostDiscountMoney(fsPackage.getTotalCostPrice().subtract(fsPackage.getTotalPrice()));
         if(fsPackageOrderMapper.insertFsPackageOrder(order)>0){
-            FsUserInformationCollection fsUserInformationCollection = fsUserInformationCollectionService.selectFsUserInformationCollectionById(param.getUserInformationId());
-            if (fsUserInformationCollection != null) {
-                fsUserInformationCollection.setPackageOrderCode(order.getOrderSn());
-                fsUserInformationCollectionService.updatePackageOrderCode(fsUserInformationCollection);
-            }
+            updateFsUserInformationCollectionByPackageOrder(param, order);
             String redisKey = String.valueOf(StrUtil.format("{}{}", FsConstants.REDIS_PACKAGE_ORDER_UNPAY, order.getOrderId()));
             redisCache.setCacheObject(redisKey,order.getOrderId(),30, TimeUnit.MINUTES);
             return R.ok().put("order",order);
@@ -637,6 +634,23 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         }
     }
 
+    private void updateFsUserInformationCollectionByPackageOrder(FsPackageOrderCreateParam param, FsPackageOrder order) {
+        if (param.getIsUserInformation()!=null && param.getIsUserInformation() == 1){
+            FsUserInformationCollection fsUserInformationCollection = fsUserInformationCollectionService.selectFsUserInformationCollectionById(param.getUserInformationId());
+            if (fsUserInformationCollection != null) {
+                fsUserInformationCollection.setPackageOrderCode(order.getOrderSn());
+                fsUserInformationCollection.setPackageOrderId(order.getOrderId());
+                fsUserInformationCollectionService.updatePackageOrderCode(fsUserInformationCollection);
+                //更新订单表
+                FsPackageOrder temp = new FsPackageOrder();
+                temp.setOrderId(order.getOrderId());
+                //添加前缀 区分信息采集订单
+                temp.setOrderSn("info"+ order.getOrderSn());
+                fsPackageOrderMapper.updateFsPackageOrder(temp);
+            }
+        }
+    }
+
     @Override
     @Transactional
     public R payOrder(FsPackageOrderPayParam param) {
@@ -1845,4 +1859,32 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
     public List<FsPackageOrder> selectOutTimeOrderList(Integer unPayTime) {
         return fsPackageOrderMapper.selectOutTimeOrderList(unPayTime);
     }
+
+    @Override
+    public R editPatientImages(Long orderId, String imagesList) {
+        FsPackageOrder fsPackageOrder = fsPackageOrderMapper.selectFsPackageOrderByOrderId(orderId);
+        if(fsPackageOrder==null){
+            return R.error("订单不存在");
+        }
+        String patientJson = fsPackageOrder.getPatientJson();
+        JSONObject jsonObject = JSONObject.parseObject(patientJson);
+        //后台编辑直接覆盖之前的图片
+        jsonObject.put("firstVisitImages",imagesList);
+        fsPackageOrder.setPatientJson(jsonObject.toJSONString());
+        int i = fsPackageOrderMapper.updateFsPackageOrder(fsPackageOrder);
+        if(i<=0){
+            return R.error("更新失败");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 根据storeOrderId 查询信息采集信息
+     * @param orderId
+     * @return FsUserInformationCollection
+     */
+    @Override
+    public FsUserInfoCollectionAndStoreOrderVo selectInformationCollectionByStoreOrderId(Long orderId) {
+        return fsPackageOrderMapper.selectInformationCollectionByStoreOrderId(orderId);
+    }
 }

+ 6 - 4
fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java

@@ -5,10 +5,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.net.URL;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONUtil;
@@ -336,6 +333,11 @@ public class FsPackageServiceImpl implements IFsPackageService {
         if(list != null && !list.isEmpty()){
             try {
                 for (FsPackage fsPackage : list) {
+                    //重命名
+                    fsPackage.setPackageName(fsPackage.getPackageName() + " - 副本");
+                    fsPackage.setSecondName(fsPackage.getSecondName() + " - 副本");
+                    fsPackage.setCreateTime(new Date());
+                    fsPackage.setUpdateTime(new Date());
                     fsPackageMapper.insertFsPackage(fsPackage);
                 }
             } catch (Exception e) {

+ 8 - 2
fs-service/src/main/java/com/fs/his/service/impl/FsPrescribeServiceImpl.java

@@ -21,6 +21,7 @@ import com.fs.his.service.IFsPrescribeDrugService;
 import com.fs.his.service.IFsPrescribeService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.utils.ConfigUtil;
+import com.fs.his.utils.IdCardUtil;
 import com.fs.his.utils.qrcode.QRCodeUtils;
 import com.fs.his.vo.*;
 import com.fs.im.dto.MsgCustomDTO;
@@ -517,7 +518,12 @@ public class FsPrescribeServiceImpl implements IFsPrescribeService
             return null;
         }
         long currentTimeMillis = System.currentTimeMillis();
-        long ageInMillis = currentTimeMillis - patJson.getBirthday();
+        Long birthday = patJson.getBirthday();
+        if (birthday == null) {
+            birthday = IdCardUtil.getBirthdayFromIdCard(patJson.getIdCard());
+            patJson.setBirthday(birthday);
+        }
+        long ageInMillis = currentTimeMillis - birthday;
         long ageInSeconds = ageInMillis / 1000;
         long ageInYears = ageInSeconds / (365 * 24 * 3600);
         fsPrescribe.setPatientAge(ageInYears+"");
@@ -525,7 +531,7 @@ public class FsPrescribeServiceImpl implements IFsPrescribeService
         fsPrescribe.setPatientName(patJson.getPatientName());
         fsPrescribe.setPatientTel(patJson.getMobile());
         fsPrescribe.setPatientGender(patJson.getSex().toString());
-        fsPrescribe.setPatientBirthday(new SimpleDateFormat("yyyy-MM-dd").format(new Date(patJson.getBirthday())));
+        fsPrescribe.setPatientBirthday(new SimpleDateFormat("yyyy-MM-dd").format(new Date(birthday)));
         fsPrescribe.setDoctorId(packageOrder.getDoctorId());
         FsDoctor fsDoctor = doctorMapper.selectFsDoctorByDoctorId(packageOrder.getDoctorId());
         if (fsDoctor==null){

+ 50 - 6
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -60,6 +60,7 @@ import com.fs.huifuPay.sdk.opps.core.utils.HuiFuUtils;
 import com.fs.huifuPay.service.HuiFuService;
 import com.fs.im.dto.*;
 import com.fs.im.service.IImService;
+import com.fs.im.service.OpenIMService;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
@@ -293,6 +294,11 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Autowired
     private com.fs.gtPush.service.uniPush2Service uniPush2Service;
 
+    @Autowired
+    private FsUserInformationCollectionMapper fsUserInformationCollectionMapper;
+    @Autowired
+    private OpenIMService openIMService;
+
     //ERP 类型到服务的映射
     private Map<Integer, IErpOrderService> erpServiceMap;
 
@@ -1036,6 +1042,10 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         }
 
         if (fsStoreOrderMapper.insertFsStoreOrder(order) > 0) {
+            if(CloudHostUtils.hasCloudHostName("金牛明医")){
+                //信息采集 发送药师im
+                doctorSendIm(packageOrder);
+            }
             if (packageOrder.getCycle() >= followRate) {
                 FsFollow fsFollow = new FsFollow();
                 fsFollow.setTempId(FollowTempId + 0L);
@@ -1120,6 +1130,24 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         return R.ok();
     }
 
+    private void doctorSendIm(FsPackageOrder packageOrder) {
+        try {
+            //信息采集 发送药师im
+            FsUserInformationCollection fsUserInformationCollectionParam = new FsUserInformationCollection();
+            fsUserInformationCollectionParam.setUserId(packageOrder.getUserId());
+            fsUserInformationCollectionParam.setPackageOrderId(packageOrder.getOrderId());
+            fsUserInformationCollectionParam.setPackageOrderCode(packageOrder.getOrderSn());
+            List<FsUserInformationCollection> fsUserInformationCollections = fsUserInformationCollectionMapper.selectFsUserInformationCollectionList(fsUserInformationCollectionParam);
+            if (!fsUserInformationCollections.isEmpty()) {
+                for (FsUserInformationCollection collection : fsUserInformationCollections) {
+                    openIMService.sendUserInformation(collection.getUserId(),collection.getDoctorType2Id(),collection.getId());
+                }
+            }
+        } catch (Exception e) {
+            log.error("信息采集 通知药师发送失败:{}",e.getMessage());
+        }
+    }
+
     @SuppressWarnings("all")
     @Override
     public String importSroreOrder(List<FsStoreProductDeliverExcelVO> list, Long storeId, Long companyId) {
@@ -1160,6 +1188,11 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 if (vo.getDeliverySn() == null || vo.getDeliverySn().isEmpty()) {
                     throw new CustomException("快递单号为空");
                 }
+                //判断是否是信息采集订单 且 药师已经确认
+                FsUserInfoCollectionAndStoreOrderVo info = fsPackageOrderMapper.selectInformationCollectionByStoreOrderId(o.getOrderId());
+                if (info != null&&info.getDoctorType2Confirm()!=1) {
+                    throw new CustomException("订单编号"+ info.getStoreOrderCode() +",手动发货导入发货失败,失败原因-信息采集订单,药师暂未确认!");
+                }
                 FsStoreOrder fsStoreOrder = new FsStoreOrder();
 
                 fsStoreOrder.setDeliverySn(vo.getDeliverySn());
@@ -3929,30 +3962,41 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 FsStoreOrder param = new FsStoreOrder(); //修改订单的参数
                 param.setOrderCode(vo.getOrderCode());
                 param.setOrderId(o.getOrderId());
-                if ("6".equals(vo.getStatus())) {
+                String inputStatus = vo.getStatus();
+                if ("6".equals(inputStatus)) {
                     failureNum++;
                     String msg = "<br/>" + failureNum + "、订单编号 " + vo.getOrderCode() + " 导入失败:";
                     failureMsg.append(msg).append("该状态不支持修改为待推送");
                     continue;
                 }
-                if ("-1".equals(vo.getStatus())) {
+                if ("-1".equals(inputStatus)) {
                     failureNum++;
                     String msg = "<br/>" + failureNum + "、订单编号 " + vo.getOrderCode() + " 导入失败:";
                     failureMsg.append(msg).append("该状态不支持修改为退款中,需要手动申请退款");
                     continue;
                 }
-                if ("-2".equals(vo.getStatus())) {
+                if ("-2".equals(inputStatus)) {
                     failureNum++;
                     String msg = "<br/>" + failureNum + "、订单编号 " + vo.getOrderCode() + " 导入失败:";
                     failureMsg.append(msg).append("该状态不支持修改为退款中,需要审核完成退款");
                     continue;
                 }
+                //发货
+                if ("2".equals(inputStatus)){
+                    //判断是否是信息采集订单 且 药师已经确认
+                    FsUserInfoCollectionAndStoreOrderVo info = fsPackageOrderMapper.selectInformationCollectionByStoreOrderId(o.getOrderId());
+                    if (info != null&&info.getDoctorType2Confirm()!=1) {
+                        String msg = "<br/>" + failureNum + "、订单编号 " + vo.getOrderCode() + " 导入失败:";
+                        failureMsg.append(msg).append("失败原因-信息采集订单,药师暂未确认!");
+                        continue;
+                    }
+                }
 
                 Integer status = o.getStatus();
 
-                if (StringUtils.isNotBlank(vo.getStatus())){
-                    param.setStatus(Integer.valueOf(vo.getStatus()));
-                    status = Integer.valueOf(vo.getStatus());
+                if (StringUtils.isNotBlank(inputStatus)){
+                    param.setStatus(Integer.valueOf(inputStatus));
+                    status = Integer.valueOf(inputStatus);
                 }
                 /**
                  * 地址和电话仅待付款和待推送可以修改

+ 100 - 31
fs-service/src/main/java/com/fs/his/service/impl/FsUserInformationCollectionServiceImpl.java

@@ -14,14 +14,18 @@ import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyUser;
+import com.fs.company.domain.CompanyUserUser;
 import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.company.mapper.CompanyUserUserMapper;
 import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.dto.FsUserInformationCollectionDTO;
+import com.fs.his.enums.FsPackageOrderStatusEnum;
 import com.fs.his.enums.FsStoreOrderStatusEnum;
 import com.fs.his.mapper.*;
 import com.fs.his.param.*;
@@ -56,6 +60,7 @@ import com.google.gson.Gson;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -128,6 +133,8 @@ public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserIn
 
     @Autowired
     private FsPackageOrderMapper packageOrderMapper;
+    @Autowired
+    private FsPatientMapper fsPatientMapper;
 
     @Autowired
     private FsPrescribeMapper fsPrescribeMapper;
@@ -149,6 +156,11 @@ public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserIn
     private IFsInquiryOrderService fsInquiryOrderService;
     @Autowired
     private OpenIMService openIMService;
+    @Autowired
+    private CompanyUserUserMapper companyUserUserMapper;
+    @Autowired
+    private FsPackageMapper fsPackageMapper;
+
     /**
      * 查询用户信息采集
      *
@@ -219,6 +231,9 @@ public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserIn
         if (collection.getUserConfirm() == 1 && collection.getUserConfirm2() == 0) {
             throw new CustomException("确认中,暂无法修改");
         }
+        param.setDoctorId(collection.getDoctorId());
+        param.setDoctorType2Id(collection.getDoctorType2Id());
+        param.setPackageId(collection.getPackageId());
         FsUserInformationCollection fsUserInformationCollection = getFsUserInformationCollection(param);
         fsUserInformationCollection.setUpdateTime(DateUtils.getNowDate());
         baseMapper.updateFsUserInformationCollection(fsUserInformationCollection);
@@ -246,6 +261,9 @@ public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserIn
         }
         //清空订单号
         fsUserInformationCollectionMapper.collectionOderCodeNULL(param.getId());
+        param.setDoctorId(collection.getDoctorId());
+        param.setDoctorType2Id(collection.getDoctorType2Id());
+        param.setPackageId(collection.getPackageId());
         FsUserInformationCollection fsUserInformationCollection = getFsUserInformationCollection(param);
         fsUserInformationCollection.setUserConfirm2(0);
         fsUserInformationCollection.setUserConfirm(0);
@@ -574,7 +592,7 @@ public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserIn
             map.setJsonInfo(JSON.toJSONString(answerVOS));
         }
 //
-
+        openIMService.doctorSendMsgToUser(collection.getUserId(),collection.getDoctorType2Id());
         if (fsUserInformationCollectionMapper.updateFsUserInformationCollection(map) > 0) {
             FsPackageOrder fsPackageOrder = packageOrderMapper.selectFsPackageOrderByOrderSn(collection.getPackageOrderCode());
             if(fsPackageOrder.getStoreOrderId()==null||fsPackageOrder.getStoreOrderId()==0){
@@ -674,6 +692,20 @@ public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserIn
         if (!Objects.equals(collection.getUserId(), param.getUserId())) {
             return R.error("用户信息不匹配,无法确认");
         }
+        //绑定用户
+        CompanyUserUser companyUserUserMap=new CompanyUserUser();
+        companyUserUserMap.setCompanyUserId(collection.getCompanyUserId());
+        companyUserUserMap.setUserId(collection.getUserId());
+        List<CompanyUserUser> list= companyUserUserMapper.selectCompanyUserUserList(companyUserUserMap);
+        if(list==null|| list.isEmpty()){
+            CompanyUser companyUser=companyUserMapper.selectCompanyUserById(collection.getCompanyUserId());
+            if(companyUser!=null&&companyUser.getStatus().equals("0")){
+                companyUserUserMap.setCompanyId(companyUser.getCompanyId());
+                companyUserUserMap.setCreateTime(new Date());
+                companyUserUserMapper.insertCompanyUserUser(companyUserUserMap);
+            }
+        }
+
         FsUserInformationCollection map = new FsUserInformationCollection();
         map.setId(param.getId());
         map.setUserConfirm(1);
@@ -943,6 +975,38 @@ public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserIn
         return fsUserInformationCollectionMapper.updateFsUserInformationCollection(fsUserInformationCollection);
     }
 
+    @Override
+    public FsUserInformationCollectionAndPatientVO selectFsUserInformationCollectionVoById(Long id) {
+        FsUserInformationCollection info = baseMapper.selectFsUserInformationCollectionById(id);
+        FsUserInformationCollectionAndPatientVO vo = new FsUserInformationCollectionAndPatientVO();
+        BeanUtils.copyProperties(info, vo);
+        Long patientId = info.getPatientId();
+        if(patientId != null){
+            FsPatient fsPatient = fsPatientMapper.selectFsPatientByPatientId(patientId);
+            if (fsPatient != null){
+
+                vo.setPatientInfo(fsPatient);
+                //查询是否支付
+                Integer isPay = 0;
+                Long packageOrderId = info.getPackageOrderId();
+                if (packageOrderId != null){
+                    FsPackageOrder order = packageOrderMapper.selectFsPackageOrderByOrderId(packageOrderId);
+                    if (order != null && order.getStatus() > 1){
+                        isPay = 1;
+                        vo.setStoreOrderId(order.getStoreOrderId());
+                        Integer status = order.getStatus();
+                        vo.setOrderStatus(FsPackageOrderStatusEnum.toType(status).getDesc()); //订单状态
+                        vo.setPackageJson(order.getPackageJson());
+                    }
+                }
+                vo.setIsPay(isPay);
+            }
+        }
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(info.getCompanyUserId());
+        vo.setCompanyId(companyUser.getCompanyId());
+        return vo;
+    }
+
     private List<AnswerVO> getAnswerVOs(List<AnswerVO> target,List<AnswerVO> source) {
         target.addAll(source);
         return target.stream()
@@ -982,38 +1046,43 @@ public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserIn
         if (companyUser == null) {
             throw new CustomException("销售不存在");
         }
-        Long doctorId = null;
-        if (companyUser.getDoctorId() != null) {
-            FsDoctor doctor = doctorMapper.selectFsDoctorByDoctorId(companyUser.getDoctorId());
-            if (doctor != null) {
-                doctorId = doctor.getDoctorId();
-            }
-        } else {
-            //随机获取医生id
-            doctorId = iFsDoctorService.selectFsDoctorDoctorByPackage();
-        }
-        doctorId = 324l;
-        fsUserInformationCollection.setDoctorId(doctorId);
-
+        //医生
+        Long doctorId = companyUser.getDoctorId();
+        fsUserInformationCollection.setDoctorId(getDoctorId(doctorId,1,param.getPackageId()));
+        //药师
+        Long doctorType2Id = param.getDoctorType2Id();
+        fsUserInformationCollection.setDoctorType2Id(getDoctorId(doctorType2Id,2,param.getPackageId()));
         return fsUserInformationCollection;
     }
 
-    public static void main(String[] args) {
-//        String str1 = "[{\"options\":[{\"flag\":false,\"name\":\"通天\",\"value\":0},{\"flag\":false,\"name\":\"哈哈\",\"value\":1}],\"title\":\"测试标题1\",\"value\":1},{\"options\":[{\"flag\":false,\"name\":\"呼呼\",\"value\":0},{\"flag\":false,\"name\":\"嘻嘻\",\"value\":1}],\"title\":\"测试标题2\",\"value\":1},{\"options\":[{\"flag\":false,\"name\":\"胸痛\",\"value\":0},{\"flag\":false,\"name\":\"胸闷\",\"value\":1},{\"flag\":false,\"name\":\"头晕\",\"value\":2},{\"flag\":false,\"name\":\"肢体麻木\",\"value\":3},{\"flag\":false,\"name\":\"无\",\"value\":4}],\"title\":\"您目前是否有心脑血管相关症状,如胸痛、胸闷、头晕、肢体麻木等?\",\"value\":1}]";
-//        String str2 = "[{\"options\":[{\"flag\":true,\"name\":\"胸痛\",\"value\":0},{\"flag\":true,\"name\":\"胸闷\",\"value\":1},{\"flag\":true,\"name\":\"头晕\",\"value\":2},{\"flag\":true,\"name\":\"肢体麻木\",\"value\":3},{\"flag\":true,\"name\":\"无\",\"value\":4}],\"title\":\"您目前是否有心脑血管相关症状,如胸痛、胸闷、头晕、肢体麻木等?\",\"value\":1},{\"options\":[{\"flag\":false,\"name\":\"胃疼\",\"value\":0},{\"flag\":false,\"name\":\"反酸\",\"value\":1},{\"flag\":false,\"name\":\"恶心\",\"value\":2},{\"flag\":false,\"name\":\"呕吐\",\"value\":3},{\"flag\":false,\"name\":\"黑便\",\"value\":4},{\"flag\":false,\"name\":\"无\",\"value\":5}],\"title\":\"您近期是否出现胃部不适症状,如胃痛、反酸、恶心、呕吐或黑便?\",\"value\":1}]";
-//        List<AnswerVO> vo1 = null;
-//        List<AnswerVO> vo2 = JSON.parseArray(str2, AnswerVO.class);
-//        System.out.println(vo1);
-//        System.out.println(vo2);
-//        vo2.addAll(vo1);
-//        Map<String, List<AnswerVO>> collect = vo2.stream()
-//                .collect(Collectors.groupingBy(AnswerVO::getTitle));
-//        List<AnswerVO> collect1 = vo2.stream()
-//                .collect(Collectors.groupingBy(AnswerVO::getTitle))
-//                .values().stream()
-//                .map(group -> group.stream().reduce((a, b) -> a).orElse(null)).collect(Collectors.toList());
-//        System.out.println(JSON.toJSONString(collect));
-//        System.out.println(JSON.toJSONString(collect1));
-        boolean contains = "是否有糖尿病相关疾病?".contains("糖尿病");
+    /**
+     *  如果是药师 需要根据套餐类型查询药师
+     * @param doctorId
+     * @param doctorType 1医生 2药师
+     * @return
+     */
+    private Long getDoctorId(Long doctorId,Integer doctorType,Long packageId) {
+        FsDoctor doctor = null;
+        if (doctorId != null) {
+            doctor = doctorMapper.selectFsDoctorByDoctorId(doctorId);
+        }
+        if (doctorId == null || doctor == null) {
+            if (doctorType == 1){
+                //随机获取医生id
+                doctorId = iFsDoctorService.selectFsDoctorDoctorByPackage();
+            } else if (doctorType == 2){
+                //随机获取药师id
+                FsPackage fsPackage = fsPackageMapper.selectFsPackageByPackageId(packageId);
+                if (fsPackage != null){
+                    doctor =doctorMapper.selectPackageFsDoctorType2Ids(fsPackage.getProductType());
+                }
+                if (doctor != null) {
+                    doctorId = doctor.getDoctorId();
+                }
+            }
+
+        }
+        return doctorId;
     }
+
 }

+ 20 - 0
fs-service/src/main/java/com/fs/his/utils/IdCardUtil.java

@@ -140,4 +140,24 @@ public class IdCardUtil {
             throw new RuntimeException("匹配请求异常", e);
         }
     }
+
+    /**
+     * 从身份证号码提取出生日期时间戳
+     * @param idCard 身份证号码
+     * @return 出生日期时间戳(毫秒)
+     */
+    public static Long getBirthdayFromIdCard(String idCard) {
+        if (idCard == null || idCard.length() != 18) {
+            throw new IllegalArgumentException("身份证号码格式不正确");
+        }
+
+        try {
+            String birthdayStr = idCard.substring(6, 14);
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+            Date birthday = sdf.parse(birthdayStr);
+            return birthday.getTime();
+        } catch (Exception e) {
+            throw new IllegalArgumentException("身份证出生日期解析失败", e);
+        }
+    }
 }

+ 12 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserInfoCollectionAndStoreOrderVo.java

@@ -0,0 +1,12 @@
+package com.fs.his.vo;
+
+import com.fs.his.domain.FsUserInformationCollection;
+import lombok.Data;
+
+
+@Data
+public class FsUserInfoCollectionAndStoreOrderVo extends FsUserInformationCollection {
+    private String storeOrderCode;
+
+
+}

+ 4 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserInformationCollectionAndPatientVO.java

@@ -13,6 +13,10 @@ import java.util.List;
 @Data
 public class FsUserInformationCollectionAndPatientVO extends FsUserInformationCollection {
     private FsPatient patientInfo; //病人信息
+    private Integer isPay;
+    private Long storeOrderId;
+    private String orderStatus;
+    private String packageJson;
 
 
 }

+ 13 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsUserScrm.java

@@ -178,6 +178,19 @@ public class FsUserScrm extends BaseEntity
      * **/
     private Long qwUserId;
 
+    /**
+     * 小程序appId,多个用逗号分隔
+     */
+    private String appId;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
     public void setNickName(String nickname)
     {
         if(StringUtils.isNotEmpty(nickname)){

+ 11 - 11
fs-service/src/main/java/com/fs/hisStore/mapper/FsShippingTemplatesScrmMapper.java

@@ -6,23 +6,23 @@ import org.apache.ibatis.annotations.Select;
 
 /**
  * 运费模板Mapper接口
- * 
+ *
  * @author fs
  * @date 2022-03-15
  */
-public interface FsShippingTemplatesScrmMapper 
+public interface FsShippingTemplatesScrmMapper
 {
     /**
      * 查询运费模板
-     * 
-     * @param shippingId 运费模板ID
+     *
+     * @param id 运费模板ID
      * @return 运费模板
      */
     public FsShippingTemplatesScrm selectFsShippingTemplatesById(Long id);
 
     /**
      * 查询运费模板列表
-     * 
+     *
      * @param fsShippingTemplates 运费模板
      * @return 运费模板集合
      */
@@ -30,7 +30,7 @@ public interface FsShippingTemplatesScrmMapper
 
     /**
      * 新增运费模板
-     * 
+     *
      * @param fsShippingTemplates 运费模板
      * @return 结果
      */
@@ -38,7 +38,7 @@ public interface FsShippingTemplatesScrmMapper
 
     /**
      * 修改运费模板
-     * 
+     *
      * @param fsShippingTemplates 运费模板
      * @return 结果
      */
@@ -46,16 +46,16 @@ public interface FsShippingTemplatesScrmMapper
 
     /**
      * 删除运费模板
-     * 
-     * @param shippingId 运费模板ID
+     *
+     * @param id 运费模板ID
      * @return 结果
      */
     public int deleteFsShippingTemplatesById(Long id);
 
     /**
      * 批量删除运费模板
-     * 
-     * @param shippingIds 需要删除的数据ID
+     *
+     * @param id 需要删除的数据ID
      * @return 结果
      */
     public int deleteFsShippingTemplatesByIds(Long[] id);

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

@@ -75,9 +75,12 @@ public interface FsStoreOrderItemScrmMapper
     List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long id);
 
     @Select({"<script> " +
-            "select i.*,o.user_id,o.status, o.real_name,o.user_phone,o.user_address,o.create_time,o.pay_time,o.delivery_sn,o.delivery_name,o.delivery_id, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,o.upload_time ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload   " +
-            " ,p.title as package_name,cts.name as scheduleName from fs_store_order_item_scrm i left join fs_store_order_scrm o on o.id=i.order_id left join fs_user u on o.user_id=u.user_id  " +
+            "select i.*,o.user_id,psps.cost,o.pay_postage,o.total_num,o.status,fspcs.cate_name, o.real_name,o.user_phone,o.user_address,o.create_time,o.pay_time,o.delivery_sn,o.delivery_name,o.delivery_id, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,o.upload_time ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload   " +
+            " ,p.title as package_name,cts.name as scheduleName, os.bank_transaction_id as bankTransactionId from fs_store_order_item_scrm i left join fs_store_order_scrm o on o.id=i.order_id" +
+            " left join fs_store_payment_scrm os on os.business_order_id = o.id " +
+            " left join fs_user u on o.user_id=u.user_id  " +
             " left join fs_store_product_package_scrm p on o.package_id=p.package_id left join company c on c.company_id=o.company_id left join company_user cu on cu.user_id=o.company_user_id left join company_tcm_schedule cts on cts.id = o.schedule_id " +
+            " left join fs_store_product_scrm psps on i.product_id=psps.product_id left join fs_store_product_category_scrm fspcs on fspcs.cate_id=psps.cate_id " +
             "where 1=1 " +
             "<if test = 'maps.orderCode != null and  maps.orderCode !=\"\"    '> " +
             "and o.order_code like CONCAT('%',#{maps.orderCode},'%') " +

+ 14 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStorePaymentScrmMapper.java

@@ -9,6 +9,7 @@ import com.fs.hisStore.domain.FsStorePaymentScrm;
 import com.fs.hisStore.param.FsStorePaymentParam;
 import com.fs.hisStore.param.FsStoreStatisticsParam;
 import com.fs.hisStore.vo.FsStorePaymentStatisticsVO;
+import com.fs.hisStore.vo.FsStorePaymentUsetVo;
 import com.fs.hisStore.vo.FsStorePaymentVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
@@ -371,4 +372,17 @@ public interface FsStorePaymentScrmMapper
 
     @Select("select * from fs_store_payment_scrm where pay_code=#{payCode}")
     FsStorePaymentScrm selectFsStorePaymentByPaymentCode(String payCode);
+
+    /**
+     * 获取查询用户支付信息
+     * @return list
+     **/
+    List<FsStorePaymentUsetVo> getPaymentUsetInfoList();
+
+    /**
+     * 批量更新发货状态
+     * **/
+    void batchUpadte(@Param("list") List<String> list);
+
+    void batchUpadteFailed(@Param("list") List<String> list);
 }

+ 8 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsUserScrmMapper.java

@@ -20,6 +20,7 @@ import com.fs.hisStore.domain.FsUserWatchStatisticsScrm;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
+import org.springframework.security.core.parameters.P;
 
 import java.math.BigDecimal;
 import java.util.List;
@@ -335,4 +336,11 @@ public interface FsUserScrmMapper
      */
     @Update("update fs_user set order_count = order_count + 1, total_amount = IFNULL(total_amount, 0) + #{amount} where user_id = #{userId}")
     void updateUserOrderCountAndAmount(@Param("userId") Long userId, @Param("amount") BigDecimal amount);
+
+    /**
+     * 累计成交总额
+     * @param payMoney 成交金额
+     */
+    @Update("update fs_user set total_amount = IFNULL(total_amount, 0) + #{payMoney} where user_id = #{userId}")
+    void incPayMoney(@Param("payMoney") BigDecimal payMoney, @Param("userId") Long userId);
 }

+ 6 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderParam.java

@@ -113,4 +113,10 @@ public class FsStoreOrderParam extends BaseEntity implements Serializable
 
     private String appId;
 
+    //银行交易流水号
+    private String bankTransactionId;
+
+    private Integer pageNum;
+    private Integer pageSize;
+
 }

+ 11 - 11
fs-service/src/main/java/com/fs/hisStore/service/IFsShippingTemplatesScrmService.java

@@ -8,23 +8,23 @@ import com.fs.hisStore.param.FsShippingTemplatesAddEditParam;
 
 /**
  * 运费模板Service接口
- * 
+ *
  * @author fs
  * @date 2022-03-15
  */
-public interface IFsShippingTemplatesScrmService 
+public interface IFsShippingTemplatesScrmService
 {
     /**
      * 查询运费模板
-     * 
-     * @param shippingId 运费模板ID
+     *
+     * @param id 运费模板ID
      * @return 运费模板
      */
     public FsShippingTemplatesScrm selectFsShippingTemplatesById(Long id);
 
     /**
      * 查询运费模板列表
-     * 
+     *
      * @param fsShippingTemplates 运费模板
      * @return 运费模板集合
      */
@@ -32,7 +32,7 @@ public interface IFsShippingTemplatesScrmService
 
     /**
      * 新增运费模板
-     * 
+     *
      * @param fsShippingTemplates 运费模板
      * @return 结果
      */
@@ -40,7 +40,7 @@ public interface IFsShippingTemplatesScrmService
 
     /**
      * 修改运费模板
-     * 
+     *
      * @param fsShippingTemplates 运费模板
      * @return 结果
      */
@@ -48,16 +48,16 @@ public interface IFsShippingTemplatesScrmService
 
     /**
      * 批量删除运费模板
-     * 
-     * @param shippingIds 需要删除的运费模板ID
+     *
+     * @param ids 需要删除的运费模板ID
      * @return 结果
      */
     public int deleteFsShippingTemplatesByIds(Long[] ids);
 
     /**
      * 删除运费模板信息
-     * 
-     * @param shippingId 运费模板ID
+     *
+     * @param id 运费模板ID
      * @return 结果
      */
     public int deleteFsShippingTemplatesById(Long id);

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

@@ -116,4 +116,9 @@ public interface IFsStorePaymentScrmService
     R getWxaCodeByPayment(FsStorePaymentGetWxaCodeParam param);
 
     R paymentByWxaCode(FsStorePaymentPayParam param);
+
+    /**
+     * 批量导入更新微信订单发货状态
+     * **/
+    R oneClickShipping();
 }

+ 8 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsUserScrmService.java

@@ -1,11 +1,14 @@
 package com.fs.hisStore.service;
 
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.param.LoginMaWxParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
 import com.fs.course.vo.newfs.FsCourseAnalysisVO;
 import com.fs.his.domain.FsStoreProductAttrValue;
+import com.fs.his.domain.FsUser;
 import com.fs.his.vo.OptionsVO;
 import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
 import com.fs.live.domain.LiveOrder;
@@ -25,6 +28,7 @@ import com.fs.hisStore.vo.FsUserTuiVO;
 import com.fs.hisStore.vo.h5.*;
 import com.github.pagehelper.PageInfo;
 
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
 
@@ -286,4 +290,8 @@ public interface IFsUserScrmService
     void addTuiLiveMoney(LiveOrder order, List<FsStoreProductAttrValueScrm> productAttrValues);
 
     void subLiveTuiMoney(LiveOrder liveOrder);
+
+    void handleFsUserWx(FsUserScrm user, LoginMaWxParam param, WxMaJscode2SessionResult session);
+
+    void incPayMoney(BigDecimal payMoney, Long userId);
 }

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů