Browse Source

Merge branch 'refs/heads/master' into master_yzt_20250707

# Conflicts:
#	fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
#	fs-admin/src/main/java/com/fs/his/controller/HzOMSErpApiController.java
#	fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java
#	fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
#	fs-qw-task/src/main/resources/application.yml
#	fs-service/src/main/java/com/fs/common/param/LoginParam.java
#	fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java
#	fs-service/src/main/java/com/fs/his/mapper/FsStoreProductMapper.java
#	fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
#	fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java
#	fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
#	fs-store/src/main/java/com/fs/store/controller/store/FsStoreOrderController.java
#	fs-user-app/src/main/java/com/fs/app/controller/WxUserController.java
#	fs-user-app/src/main/resources/application.yml
xdd 1 month ago
parent
commit
25985b1172
100 changed files with 3502 additions and 302 deletions
  1. 2 2
      .gitignore
  2. 2 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java
  3. 12 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserVideoController.java
  4. 38 0
      fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java
  5. 1 1
      fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderController.java
  6. 12 1
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java
  7. 114 0
      fs-admin/src/main/java/com/fs/his/controller/FsPhysicalReportTemplateController.java
  8. 140 0
      fs-admin/src/main/java/com/fs/his/controller/FsPhysicalReportTemplateFieldController.java
  9. 187 47
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  10. 6 9
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  11. 7 0
      fs-admin/src/main/java/com/fs/his/controller/FsUserOperationLogController.java
  12. 57 5
      fs-admin/src/main/java/com/fs/his/controller/HzOMSErpApiController.java
  13. 59 18
      fs-admin/src/main/java/com/fs/his/task/Task.java
  14. 103 0
      fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerController.java
  15. 118 0
      fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerLogController.java
  16. 118 0
      fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerUserController.java
  17. 1 1
      fs-admin/src/main/resources/application.yml
  18. 13 4
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  19. 3 18
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  20. 1 3
      fs-company-app/src/main/java/com/fs/app/controller/FsUserOperationLogController.java
  21. 2 1
      fs-company-app/src/main/resources/application.yml
  22. 11 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  23. 3 1
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java
  24. 4 1
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java
  25. 8 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserOperationLogController.java
  26. 0 1
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptRoleController.java
  27. 4 2
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  28. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactInfoController.java
  29. 20 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopController.java
  30. 1 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserVoiceLogController.java
  31. 164 30
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsInfoController.java
  32. 1 1
      fs-company/src/main/java/com/fs/company/controller/stats/SalesWatchStatisController.java
  33. 30 4
      fs-company/src/main/java/com/fs/company/controller/store/FsInquiryOrderController.java
  34. 7 0
      fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java
  35. 4 3
      fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java
  36. 2 1
      fs-company/src/main/resources/application.yml
  37. 34 0
      fs-ipad-task/src/main/java/com/fs/app/service/CustomThreadPoolConfig.java
  38. 7 3
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  39. 45 44
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  40. 1 0
      fs-ipad-task/src/main/java/com/fs/framework/config/DataSourceConfig.java
  41. 18 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  42. 13 0
      fs-qw-task/src/main/java/com/fs/app/task/qwTask.java
  43. 25 22
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  44. 18 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwUserController.java
  45. 18 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/QwUserController.java
  46. 1 1
      fs-qwhook-sop/src/main/resources/application.yml
  47. 20 0
      fs-qwhook/src/main/java/com/fs/app/controller/ApisQwUserController.java
  48. 16 0
      fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java
  49. 6 0
      fs-service/src/main/java/com/fs/common/param/LoginMaWxParam.java
  50. 1 0
      fs-service/src/main/java/com/fs/common/param/LoginParam.java
  51. 0 1
      fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java
  52. 4 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  53. 1 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  54. 3 0
      fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java
  55. 4 1
      fs-service/src/main/java/com/fs/config/ai/AiHostProper.java
  56. 1 0
      fs-service/src/main/java/com/fs/course/config/CourseConfig.java
  57. 17 2
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseComplaintRecord.java
  58. 4 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  59. 8 4
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java
  60. 19 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  61. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsVideoResourceMapper.java
  62. 2 0
      fs-service/src/main/java/com/fs/course/param/FsCourseSendRewardUParam.java
  63. 5 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  64. 4 0
      fs-service/src/main/java/com/fs/course/param/FsUserCourseVideoParam.java
  65. 13 0
      fs-service/src/main/java/com/fs/course/param/SendXfkParam.java
  66. 4 0
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseAddCompanyUserParam.java
  67. 4 0
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseBeMemberParam.java
  68. 9 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseLinkService.java
  69. 6 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java
  70. 55 0
      fs-service/src/main/java/com/fs/course/service/impl/AsyncIsAddKfXfkService.java
  71. 156 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  72. 4 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseComplaintRecordServiceImpl.java
  73. 86 35
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  74. 52 12
      fs-service/src/main/java/com/fs/course/service/impl/TencentCloudCosService.java
  75. 5 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseOverVO.java
  76. 26 16
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogListVO.java
  77. 118 0
      fs-service/src/main/java/com/fs/erp/constant/AfterSalesOrderStatusEnum.java
  78. 111 0
      fs-service/src/main/java/com/fs/erp/constant/ErpQueryOrderStatusEnum.java
  79. 90 0
      fs-service/src/main/java/com/fs/erp/constant/OrderStatusEnum.java
  80. 87 0
      fs-service/src/main/java/com/fs/erp/constant/TaskStatusEnum.java
  81. 2 1
      fs-service/src/main/java/com/fs/erp/domain/ErpDeliverys.java
  82. 3 0
      fs-service/src/main/java/com/fs/erp/domain/ErpGoods.java
  83. 2 0
      fs-service/src/main/java/com/fs/erp/domain/ErpOrder.java
  84. 85 0
      fs-service/src/main/java/com/fs/erp/domain/FsJstAftersalePush.java
  85. 77 0
      fs-service/src/main/java/com/fs/erp/domain/FsJstCodPush.java
  86. 40 0
      fs-service/src/main/java/com/fs/erp/dto/AfterSaleConfirmRequestDTO.java
  87. 69 0
      fs-service/src/main/java/com/fs/erp/dto/AfterSaleResponseDTO.java
  88. 45 0
      fs-service/src/main/java/com/fs/erp/dto/AssetProcessDetailDTO.java
  89. 42 0
      fs-service/src/main/java/com/fs/erp/dto/AssetProcessResultDTO.java
  90. 35 0
      fs-service/src/main/java/com/fs/erp/dto/CommonResponse.java
  91. 56 0
      fs-service/src/main/java/com/fs/erp/dto/ErpOrderResponseDTO.java
  92. 22 0
      fs-service/src/main/java/com/fs/erp/dto/ExtDataDTO.java
  93. 62 0
      fs-service/src/main/java/com/fs/erp/dto/FinanceDataDTO.java
  94. 51 0
      fs-service/src/main/java/com/fs/erp/dto/GetInitTokenRequestDTO.java
  95. 41 0
      fs-service/src/main/java/com/fs/erp/dto/GetInitTokenResponseDTO.java
  96. 297 0
      fs-service/src/main/java/com/fs/erp/dto/GoodsInfoDTO.java
  97. 38 0
      fs-service/src/main/java/com/fs/erp/dto/OrderCancelRequestDTO.java
  98. 33 0
      fs-service/src/main/java/com/fs/erp/dto/OrderExtDTO.java
  99. 52 0
      fs-service/src/main/java/com/fs/erp/dto/OrderExtDataDTO.java
  100. 68 0
      fs-service/src/main/java/com/fs/erp/dto/OrderItemDTO.java

+ 2 - 2
.gitignore

@@ -6,8 +6,8 @@ target/
 !**/src/main/**/target/
 !**/src/main/**/target/
 !**/src/test/**/target/
 !**/src/test/**/target/
 #logback.xml
 #logback.xml
-application-druid-rt.yml
-application-druid-yjf.yml
+application.yml
+
 
 
 ### STS ###
 ### STS ###
 .apt_generated
 .apt_generated

+ 2 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java

@@ -189,6 +189,7 @@ public class FsUserCoursePeriodController extends BaseController {
         return R.ok().put("data", periodRedPacketList);
         return R.ok().put("data", periodRedPacketList);
     }
     }
 
 
+    @Log(title = "按课程批量保存设置红包金额", businessType = BusinessType.UPDATE)
     @PreAuthorize("@ss.hasPermi('course:period:setCourseRedPacket')")
     @PreAuthorize("@ss.hasPermi('course:period:setCourseRedPacket')")
     @ApiOperation("按课程批量保存设置红包金额")
     @ApiOperation("按课程批量保存设置红包金额")
     @PostMapping("/batchRedPacket")
     @PostMapping("/batchRedPacket")
@@ -202,6 +203,7 @@ public class FsUserCoursePeriodController extends BaseController {
         return R.ok();
         return R.ok();
     }
     }
 
 
+    @Log(title = "按营期批量保存设置红包金额", businessType = BusinessType.UPDATE)
     @PreAuthorize("@ss.hasPermi('course:period:setRedPacket')")
     @PreAuthorize("@ss.hasPermi('course:period:setRedPacket')")
     @ApiOperation("按营期批量保存设置红包金额")
     @ApiOperation("按营期批量保存设置红包金额")
     @PostMapping("/batchRedPacket/byPeriod")
     @PostMapping("/batchRedPacket/byPeriod")

+ 12 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserVideoController.java

@@ -9,9 +9,11 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.domain.FsUserVideo;
 import com.fs.course.domain.FsUserVideo;
 import com.fs.course.domain.FsVideoResource;
 import com.fs.course.domain.FsVideoResource;
 import com.fs.course.param.*;
 import com.fs.course.param.*;
+import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.service.IFsUserVideoService;
 import com.fs.course.service.IFsUserVideoService;
 import com.fs.course.service.IFsVideoResourceService;
 import com.fs.course.service.IFsVideoResourceService;
 import com.fs.course.service.impl.TencentCloudCosService;
 import com.fs.course.service.impl.TencentCloudCosService;
@@ -55,6 +57,9 @@ public class FsUserVideoController extends BaseController
     @Autowired
     @Autowired
     private IFsVideoResourceService iFsVideoResourceService;
     private IFsVideoResourceService iFsVideoResourceService;
 
 
+    @Autowired
+    private IFsUserCourseVideoService fsUserCourseVideoService;
+
     /**
     /**
      * 查询课堂视频列表
      * 查询课堂视频列表
      */
      */
@@ -354,6 +359,13 @@ public class FsUserVideoController extends BaseController
             iFsVideoResourceService.updateById(videoMap);
             iFsVideoResourceService.updateById(videoMap);
             log.info("成功更新视频转码状态,视频ID: {}", video.getId());
             log.info("成功更新视频转码状态,视频ID: {}", video.getId());
 
 
+
+            FsUserCourseVideo fsUserCourseVideo = fsUserCourseVideoService.selectByFileKey(video.getFileKey());
+            fsUserCourseVideo.setLineOne(video.getLine1().replace(inputPath,transcodeFileKey));
+            fsUserCourseVideo.setTranscodeFileKey(transcodeFileKey);
+            fsUserCourseVideo.setIsTranscode(1);
+            fsUserCourseVideoService.updateFsUserCourseVideo(fsUserCourseVideo);
+
             return R.ok();
             return R.ok();
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("处理视频转码请求时发生异常", e);
             log.error("处理视频转码请求时发生异常", e);

+ 38 - 0
fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java

@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.*;
 
 
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.*;
+import java.util.stream.Collectors;
 
 
 /**
 /**
  * 资源库管理
  * 资源库管理
@@ -102,6 +103,43 @@ public class FsVideoResourceController extends BaseController {
         return AjaxResult.success();
         return AjaxResult.success();
     }
     }
 
 
+    /**
+     * 批量修改视频分类
+     * @param typeId
+     * @param typeSubId
+     * @param ids
+     * @return
+     */
+    @PreAuthorize("@ss.hasPermi('course:videoResource:batchUpdateClass')")
+    @Log(title = "视频素材库", businessType = BusinessType.UPDATE)
+    @PostMapping("/batchUpdateClass")
+    public AjaxResult batchUpdateClass(@RequestParam("typeId") Long typeId,
+                                       @RequestParam("typeSubId") Long typeSubId,
+                                       @RequestParam("ids") String ids) {
+        if(typeId == null || typeId <= 0){
+            return AjaxResult.error("请选择分类");
+        }
+        if(typeSubId == null || typeSubId <= 0){
+            return AjaxResult.error("请选择子分类");
+        }
+        if(ids == null || ids.isEmpty()){
+            return AjaxResult.error("请选择要修改的分类");
+        }
+
+        // 将ids字符串分割为ID列表
+        List<String> idList = Arrays.asList(ids.split(","));
+
+        // 创建更新条件
+        Wrapper<FsVideoResource> updateWrapper = Wrappers.<FsVideoResource>lambdaUpdate()
+                .set(FsVideoResource::getTypeId, typeId)
+                .set(FsVideoResource::getTypeSubId, typeSubId)
+                .in(FsVideoResource::getId, idList.stream().map(Long::valueOf).collect(Collectors.toList()));
+
+        // 执行批量更新
+        fsVideoResourceService.update(updateWrapper);
+        return AjaxResult.success();
+    }
+
     @PreAuthorize("@ss.hasPermi('course:videoResource:batchAdd')")
     @PreAuthorize("@ss.hasPermi('course:videoResource:batchAdd')")
     @Log(title = "视频素材库", businessType = BusinessType.INSERT)
     @Log(title = "视频素材库", businessType = BusinessType.INSERT)
     @PostMapping("/batchAddVideoResource")
     @PostMapping("/batchAddVideoResource")

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

@@ -157,7 +157,7 @@ public class FsInquiryOrderController extends BaseController
     @GetMapping(value = "/sendMsg/{orderId}")
     @GetMapping(value = "/sendMsg/{orderId}")
     public AjaxResult sendMsg(@PathVariable("orderId") Long orderId)
     public AjaxResult sendMsg(@PathVariable("orderId") Long orderId)
     {
     {
-        ;
+
         return AjaxResult.success(fsInquiryOrderService.sendStartMsg(orderId));
         return AjaxResult.success(fsInquiryOrderService.sendStartMsg(orderId));
     }
     }
     /**
     /**

+ 12 - 1
fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java

@@ -1,6 +1,7 @@
 package com.fs.his.controller;
 package com.fs.his.controller;
 
 
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
@@ -16,6 +17,7 @@ import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.param.FsIntegralOrderParam;
 import com.fs.his.param.FsIntegralOrderParam;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsIntegralOrderService;
 import com.fs.his.service.IFsIntegralOrderService;
+import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.*;
 import com.fs.his.vo.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -66,8 +68,17 @@ public class FsIntegralOrderController extends BaseController
     {
     {
         List<FsIntegralOrder> list = fsIntegralOrderService.selectFsIntegralOrderList(fsIntegralOrder);
         List<FsIntegralOrder> list = fsIntegralOrderService.selectFsIntegralOrderList(fsIntegralOrder);
         for (FsIntegralOrder vo : list) {
         for (FsIntegralOrder vo : list) {
+            //商品名称以及原价赋值
+            String itemJson = vo.getItemJson();
+            if(StringUtils.isNotBlank(itemJson)){
+                JSONObject jsonObject = JSONObject.parseObject(itemJson);
+                vo.setGoodsName(jsonObject.getString("goodsName"));
+                vo.setOtPrice(jsonObject.getBigDecimal("otPrice"));
+            }
             if (vo.getUserPhone()!=null&&!vo.getUserPhone().equals("")){
             if (vo.getUserPhone()!=null&&!vo.getUserPhone().equals("")){
-                vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                if(vo.getUserPhone().chars().allMatch(Character::isDigit)){continue;}
+//                vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                vo.setUserPhone(PhoneUtil.decryptPhone(vo.getUserPhone()));
             }
             }
         }
         }
         ExcelUtil<FsIntegralOrder> util = new ExcelUtil<FsIntegralOrder>(FsIntegralOrder.class);
         ExcelUtil<FsIntegralOrder> util = new ExcelUtil<FsIntegralOrder>(FsIntegralOrder.class);

+ 114 - 0
fs-admin/src/main/java/com/fs/his/controller/FsPhysicalReportTemplateController.java

@@ -0,0 +1,114 @@
+package com.fs.his.controller;
+
+import java.util.List;
+
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.utils.ServletUtils;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.his.domain.FsPhysicalReportTemplate;
+import com.fs.his.service.IFsPhysicalReportTemplateService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 体检报告模板Controller
+ * 
+ * @author fs
+ * @date 2025-07-23
+ */
+@RestController
+@RequestMapping("/his/physicalReportTemplate")
+public class FsPhysicalReportTemplateController extends BaseController
+{
+    @Autowired
+    private IFsPhysicalReportTemplateService fsPhysicalReportTemplateService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询体检报告模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplate:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsPhysicalReportTemplate fsPhysicalReportTemplate)
+    {
+        startPage();
+        List<FsPhysicalReportTemplate> list = fsPhysicalReportTemplateService.selectFsPhysicalReportTemplateList(fsPhysicalReportTemplate);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出体检报告模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplate:export')")
+    @Log(title = "体检报告模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsPhysicalReportTemplate fsPhysicalReportTemplate)
+    {
+        List<FsPhysicalReportTemplate> list = fsPhysicalReportTemplateService.selectFsPhysicalReportTemplateList(fsPhysicalReportTemplate);
+        ExcelUtil<FsPhysicalReportTemplate> util = new ExcelUtil<FsPhysicalReportTemplate>(FsPhysicalReportTemplate.class);
+        return util.exportExcel(list, "体检报告模板数据");
+    }
+
+    /**
+     * 获取体检报告模板详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplate:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id)
+    {
+        return AjaxResult.success(fsPhysicalReportTemplateService.selectFsPhysicalReportTemplateById(id));
+    }
+
+    /**
+     * 新增体检报告模板
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplate:add')")
+    @Log(title = "体检报告模板", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsPhysicalReportTemplate fsPhysicalReportTemplate)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsPhysicalReportTemplate.setCreateBy(String.valueOf(loginUser.getUserId()));
+        return toAjax(fsPhysicalReportTemplateService.insertFsPhysicalReportTemplate(fsPhysicalReportTemplate));
+    }
+
+    /**
+     * 修改体检报告模板
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplate:edit')")
+    @Log(title = "体检报告模板", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsPhysicalReportTemplate fsPhysicalReportTemplate)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsPhysicalReportTemplate.setUpdateBy(String.valueOf(loginUser.getUserId()));
+        return toAjax(fsPhysicalReportTemplateService.updateFsPhysicalReportTemplate(fsPhysicalReportTemplate));
+    }
+
+    /**
+     * 删除体检报告模板
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplate:remove')")
+    @Log(title = "体检报告模板", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable String[] ids)
+    {
+        return toAjax(fsPhysicalReportTemplateService.deleteFsPhysicalReportTemplateByIds(ids));
+    }
+}

+ 140 - 0
fs-admin/src/main/java/com/fs/his/controller/FsPhysicalReportTemplateFieldController.java

@@ -0,0 +1,140 @@
+package com.fs.his.controller;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.extension.api.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.framework.web.service.TokenService;
+import com.fs.his.dto.FsPhysicalReportTemplateFieldDTO;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.his.domain.FsPhysicalReportTemplateField;
+import com.fs.his.service.IFsPhysicalReportTemplateFieldService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 体检报告模板字段Controller
+ *
+ * @author fs
+ * @date 2025-07-24
+ */
+@RestController
+@RequestMapping("/his/physicalReportTemplateField")
+public class FsPhysicalReportTemplateFieldController extends BaseController {
+    @Autowired
+    private IFsPhysicalReportTemplateFieldService fsPhysicalReportTemplateFieldService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询体检报告模板字段列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplateField:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsPhysicalReportTemplateField fsPhysicalReportTemplateField) {
+        startPage();
+        List<FsPhysicalReportTemplateField> list = fsPhysicalReportTemplateFieldService.selectFsPhysicalReportTemplateFieldList(fsPhysicalReportTemplateField);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出体检报告模板字段列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplateField:export')")
+    @Log(title = "体检报告模板字段", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsPhysicalReportTemplateField fsPhysicalReportTemplateField) {
+        List<FsPhysicalReportTemplateField> list = fsPhysicalReportTemplateFieldService.selectFsPhysicalReportTemplateFieldList(fsPhysicalReportTemplateField);
+        ExcelUtil<FsPhysicalReportTemplateField> util = new ExcelUtil<FsPhysicalReportTemplateField>(FsPhysicalReportTemplateField.class);
+        return util.exportExcel(list, "体检报告模板字段数据");
+    }
+
+    /**
+     * 获取体检报告模板字段详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplateField:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id) {
+        return AjaxResult.success(fsPhysicalReportTemplateFieldService.selectFsPhysicalReportTemplateFieldById(id));
+    }
+
+    /**
+     * 新增体检报告模板字段
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplateField:add')")
+    @Log(title = "体检报告模板字段", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsPhysicalReportTemplateField fsPhysicalReportTemplateField) {
+        return toAjax(fsPhysicalReportTemplateFieldService.insertFsPhysicalReportTemplateField(fsPhysicalReportTemplateField));
+    }
+
+    /**
+     * 修改体检报告模板字段
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplateField:edit')")
+    @Log(title = "体检报告模板字段", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsPhysicalReportTemplateField fsPhysicalReportTemplateField) {
+        return toAjax(fsPhysicalReportTemplateFieldService.updateFsPhysicalReportTemplateField(fsPhysicalReportTemplateField));
+    }
+
+    /**
+     * 删除体检报告模板字段
+     */
+    @PreAuthorize("@ss.hasPermi('his:physicalReportTemplateField:remove')")
+    @Log(title = "体检报告模板字段", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable String[] ids) {
+        return toAjax(fsPhysicalReportTemplateFieldService.deleteFsPhysicalReportTemplateFieldByIds(ids));
+    }
+
+    /**
+     * 获取模板自定义字段
+     *
+     * @param templateId 模板ID
+     * @return R
+     **/
+    @PostMapping("/getTemplateField/{templateId}")
+    public R getTemplateField(@PathVariable String templateId) {
+        if (StringUtils.isNull(templateId)) {
+            return R.failed("操作失败,模板ID不能为空!");
+        }
+        return fsPhysicalReportTemplateFieldService.getTemplateField(templateId);
+    }
+
+    /**
+     * 新增模板
+     *
+     * @param fieldDTO
+     * @return AjaxResult
+     **/
+    @Log(title = "体检报告模板字段", businessType = BusinessType.INSERT)
+    @PostMapping("/saveTemplate")
+    public AjaxResult saveTemplate(@RequestBody FsPhysicalReportTemplateFieldDTO fieldDTO) {
+        if (StringUtils.isNull(fieldDTO.getTemplateId())) {
+            throw new ServiceException("操作失败,模板ID不能为空!");
+        } else if (fieldDTO.getTemplateFieldList().isEmpty()) {
+            throw new ServiceException("操作失败,字段列表不能为空!");
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fieldDTO.setCreateBy(String.valueOf(loginUser.getUserId()));
+        return toAjax(fsPhysicalReportTemplateFieldService.saveFsPhysicalReportTemplateField(fieldDTO));
+    }
+}

+ 187 - 47
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -17,28 +17,33 @@ import com.fs.common.utils.StringUtils;
 import com.fs.company.param.CompanyStoreOrderMoneyLogsListParam;
 import com.fs.company.param.CompanyStoreOrderMoneyLogsListParam;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.company.vo.CompanyStoreOrderMoneyLogsVO;
 import com.fs.company.vo.CompanyStoreOrderMoneyLogsVO;
+import com.fs.config.cloud.CloudHostProper;
 import com.fs.erp.domain.ErpDeliverys;
 import com.fs.erp.domain.ErpDeliverys;
 import com.fs.erp.domain.ErpOrderQuery;
 import com.fs.erp.domain.ErpOrderQuery;
+import com.fs.erp.dto.ErpDeliverysRequest;
+import com.fs.erp.dto.ErpDeliverysResponse;
 import com.fs.erp.dto.ErpOrderQueryRequert;
 import com.fs.erp.dto.ErpOrderQueryRequert;
 import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.dto.ErpOrderQueryResponse;
+import com.fs.erp.dto.df.BspOrderResponse;
+import com.fs.erp.dto.df.DFConfigVo;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.framework.web.service.TokenService;
 import com.fs.framework.web.service.TokenService;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.domain.*;
 import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.dto.StoreOrderExpressExportDTO;
 import com.fs.his.dto.StoreOrderExpressExportDTO;
+import com.fs.his.dto.TracesDTO;
 import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.param.FsFollowMsgParam;
 import com.fs.his.param.FsFollowMsgParam;
 import com.fs.his.param.FsStoreOrderParam;
 import com.fs.his.param.FsStoreOrderParam;
 import com.fs.his.param.FsStoreOrderSalesParam;
 import com.fs.his.param.FsStoreOrderSalesParam;
 import com.fs.his.param.FsStoreOrderSetErpPhoneParam;
 import com.fs.his.param.FsStoreOrderSetErpPhoneParam;
-import com.fs.his.service.IFsExportTaskService;
-import com.fs.his.service.IFsExpressService;
-import com.fs.his.service.IFsStoreService;
+import com.fs.his.service.*;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.*;
 import com.fs.his.vo.*;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.mapper.SysConfigMapper;
+import com.github.pagehelper.PageHelper;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -49,7 +54,6 @@ import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
-import com.fs.his.service.IFsStoreOrderService;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartFile;
@@ -95,20 +99,58 @@ public class FsStoreOrderController extends BaseController
     @Qualifier("hzOMSErpOrderServiceImpl")
     @Qualifier("hzOMSErpOrderServiceImpl")
     private IErpOrderService hdtOrderService;
     private IErpOrderService hdtOrderService;
 
 
+    @Autowired
+    @Qualifier("hzOMSErpOrderServiceImpl")
+    private IErpOrderService hzOMSErpOrderService;
+
+    @Autowired
+    @Qualifier("dfOrderServiceImpl")
+    private IErpOrderService dfOrderService;
+
+    @Autowired
+    @Qualifier("JSTErpOrderServiceImpl")
+    private IErpOrderService jSTOrderService;
+
     @Autowired
     @Autowired
     SysConfigMapper sysConfigMapper;
     SysConfigMapper sysConfigMapper;
+
+    @Autowired
+    private IFsStoreOrderDfService fsStoreOrderDfService;
+
+    @Autowired
+    private CloudHostProper cloudHostProper;
     /**
     /**
      * 查询订单列表
      * 查询订单列表
      */
      */
-    @GetMapping("/list")
-    public TableDataInfo list(FsStoreOrderParam fsStoreOrder)
+    @PostMapping("/list")
+    public TableDataInfo list(@RequestBody FsStoreOrderParam fsStoreOrder)
     {
     {
-        startPage();
-        if (fsStoreOrder.getUserPhoneMk()!=null&&fsStoreOrder.getUserPhoneMk()!=""){
+        PageHelper.startPage(fsStoreOrder);
+        if (fsStoreOrder.getUserPhoneMk()!=null&& !fsStoreOrder.getUserPhoneMk().isEmpty()){
             fsStoreOrder.setUserPhone(encryptPhone(fsStoreOrder.getUserPhoneMk()));
             fsStoreOrder.setUserPhone(encryptPhone(fsStoreOrder.getUserPhoneMk()));
         }
         }
-        List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVO(fsStoreOrder);
-        return getDataTable(list);
+        List<FsStoreOrderListVO> list;
+        if (StringUtils.isNotBlank(fsStoreOrder.getErpAccount())){
+            //金牛erp查询
+            list = fsStoreOrderService.selectFsStoreOrderListVOByErpAccount(fsStoreOrder);
+        } else {
+            list = fsStoreOrderService.selectFsStoreOrderListVO(fsStoreOrder);
+        }
+        //金牛需求 区别其他项目 status = 6 (金牛代服管家) ,其他项目请避免使用订单状态status = 6
+        TableDataInfo dataTable = getDataTable(list);
+        if ("金牛明医".equals(cloudHostProper.getCompanyName())){
+            if (fsStoreOrder.getStatus() !=null && fsStoreOrder.getStatus() != 1){
+                list.forEach(vo->{
+                    //查询顺丰代服账号
+                    FsStoreOrderDf df = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(vo.getOrderId());
+                    if (df != null){
+                        vo.setErpAccount(df.getLoginAccount());
+                    }
+                });
+            }
+            dataTable.setMsg("jnmy");
+        }
+        return dataTable;
     }
     }
 
 
     /**
     /**
@@ -375,8 +417,13 @@ public class FsStoreOrderController extends BaseController
                     //旺店通
                     //旺店通
                     erpOrderService =  wdtOrderService;
                     erpOrderService =  wdtOrderService;
                 } else if (erpType == 3){
                 } else if (erpType == 3){
-                    //旺店通
-                    erpOrderService =  hdtOrderService;
+                    //
+                    erpOrderService =  hzOMSErpOrderService;
+                } else if (erpType == 4){
+                    //代服
+                    erpOrderService =  dfOrderService;
+                }else if(erpType == 5){
+                    erpOrderService=jSTOrderService;
                 }
                 }
                 return erpOrderService;
                 return erpOrderService;
 
 
@@ -491,20 +538,95 @@ public class FsStoreOrderController extends BaseController
     @ApiOperation("批量创建ERP订单")
     @ApiOperation("批量创建ERP订单")
     @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
     @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
     @PostMapping(value = "/batchCreateErpOrder")
     @PostMapping(value = "/batchCreateErpOrder")
-    public R batchCreateErpOrder(@RequestBody List<Long> orderIds)
+    public R batchCreateErpOrder(@RequestBody FsStoreOrderSetErpPhoneParam param)
     {
     {
-        if (orderIds != null && !orderIds.isEmpty()) {
-            orderIds.forEach(orderId->{
-                try {
-                    fsStoreOrderService.createOmsOrder(orderId);
-                } catch (ParseException e) {
-                    throw new RuntimeException(e);
-                }
-
-            });
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)){
+            return R.error("未选择推送erp账户");
+        }
+        FsStoreOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null){
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds  == null || orderIds.isEmpty()) {
+            if (param.getUserPhoneMk() != null && !param.getUserPhoneMk().isEmpty()) {
+                param.setUserPhone(encryptPhone(param.getUserPhoneMk()));
+            }
+            List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
+            orderIds = list.stream().map(FsStoreOrderListVO::getOrderId).collect(Collectors.toList());
         }
         }
+        if (orderIds.isEmpty()){
+            return R.ok();
+        }
+        orderIds.forEach(orderId->{
+            try {
+                df.setOrderId(orderId);
+                FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
+                if (temp == null){
+                    fsStoreOrderDfService.insertFsStoreOrderDf(df);
+                }
+                fsStoreOrderService.createOmsOrder(orderId);
+            } catch (ParseException e) {
+                throw new RuntimeException(e);
+            }
 
 
+        });
         return R.ok();
         return R.ok();
+}
+    @ApiOperation("批量设置订单账户")
+    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @PostMapping(value = "/batchSetErpOrder")
+    public R batchSetErpOrder(@RequestBody FsStoreOrderSetErpPhoneParam param)
+    {
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)){
+            return R.error("未选择erp账户");
+        }
+        FsStoreOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null){
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds  == null || orderIds.isEmpty()) {
+            if (param.getUserPhoneMk() != null && !param.getUserPhoneMk().isEmpty()) {
+                param.setUserPhone(encryptPhone(param.getUserPhoneMk()));
+            }
+            List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
+            orderIds = list.stream().map(FsStoreOrderListVO::getOrderId).collect(Collectors.toList());
+        }
+        if (orderIds.isEmpty()){
+            return R.ok();
+        }
+        orderIds.forEach(orderId->{
+            df.setOrderId(orderId);
+            FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
+            if (temp != null){
+                df.setUpdateTime(new Date());
+                fsStoreOrderDfService.updateFsStoreOrderDf(df);
+            } else {
+                fsStoreOrderDfService.insertFsStoreOrderDf(df);
+            }
+        });
+    }
+
+    private FsStoreOrderDf getDFInfo(String loginAccount) {
+        //查询订单账户 判断是否存在该订单账户
+        List<DFConfigVo> erpAccounts = fsStoreOrderService.getErpAccount();
+        FsStoreOrderDf df = new FsStoreOrderDf();
+        for (DFConfigVo erpAccount : erpAccounts) {
+            if (loginAccount.equals(erpAccount.getLoginAccount())){
+                //添加df记录
+                df.setAppKey(erpAccount.getDfAppKey());
+                df.setAppSecret(erpAccount.getDfAppsecret());
+                df.setLoginAccount(loginAccount);
+                df.setMonthlyCard(erpAccount.getMonthlyCard());
+                df.setExpressProductCode(erpAccount.getExpressProductCode());
+                df.setStatus(0);
+                break;
+            }
+        }
+        return df;
     }
     }
 
 
     @Log(title = "冻结/解冻", businessType = BusinessType.UPDATE)
     @Log(title = "冻结/解冻", businessType = BusinessType.UPDATE)
@@ -543,7 +665,12 @@ public class FsStoreOrderController extends BaseController
     @PreAuthorize("@ss.hasPermi('his:storeOrder:syncExpress')")
     @PreAuthorize("@ss.hasPermi('his:storeOrder:syncExpress')")
     @GetMapping(value = "/syncExpress/{id}")
     @GetMapping(value = "/syncExpress/{id}")
     public R syncExpress(@PathVariable("id") Long id) {
     public R syncExpress(@PathVariable("id") Long id) {
-        return fsStoreOrderService.syncExpress(id);
+        IErpOrderService erpService = getErpService();
+        if (erpService!=null && erpService == dfOrderService){
+            return fsStoreOrderService.syncDfExpress(id);
+        } else {
+            return fsStoreOrderService.syncExpress(id);
+        }
     }
     }
 
 
     @PreAuthorize("@ss.hasPermi('his:storeOrder:sendMsg')")
     @PreAuthorize("@ss.hasPermi('his:storeOrder:sendMsg')")
@@ -564,34 +691,41 @@ public class FsStoreOrderController extends BaseController
     @GetMapping(value = "/getExpress/{id}")
     @GetMapping(value = "/getExpress/{id}")
     public R getExpress(@PathVariable("id") Long id)
     public R getExpress(@PathVariable("id") Long id)
     {
     {
-        FsStoreOrder order=fsStoreOrderService.selectFsStoreOrderByOrderId(id);
         ExpressInfoDTO expressInfoDTO=null;
         ExpressInfoDTO expressInfoDTO=null;
-        if(StringUtils.isNotEmpty(order.getDeliverySn())){
-            String lastFourNumber = "";
-            if (order.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
-
-                lastFourNumber = order.getUserPhone();
-                if (lastFourNumber.length() == 11) {
-                    lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
-                }else if (lastFourNumber.length()>11){
-                    String jm = decryptPhone(lastFourNumber);
-                    lastFourNumber = StrUtil.sub(jm, jm.length(), -4);
-                }
-            }
-            expressInfoDTO=expressService.getExpressInfo(order.getOrderCode(),order.getDeliveryCode(),order.getDeliverySn(),lastFourNumber);
-
-            if((expressInfoDTO.getStateEx()!=null&&expressInfoDTO.getStateEx().equals("0"))&&(expressInfoDTO.getState()!=null&&expressInfoDTO.getState().equals("0"))){
-                lastFourNumber = "19923690275";
+        FsStoreOrder order=fsStoreOrderService.selectFsStoreOrderByOrderId(id);
+        //代服管家 查询自己的物流
+        IErpOrderService erpService = getErpService();
+        if (erpService == dfOrderService){
+            expressInfoDTO = fsStoreOrderService.getDfExpressInfoDTO(order);
+        } else {
+            if(StringUtils.isNotEmpty(order.getDeliverySn())){
+                String lastFourNumber = "";
                 if (order.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
                 if (order.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
+
+                    lastFourNumber = order.getUserPhone();
                     if (lastFourNumber.length() == 11) {
                     if (lastFourNumber.length() == 11) {
                         lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
                         lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+                    }else if (lastFourNumber.length()>11){
+                        String jm = decryptPhone(lastFourNumber);
+                        lastFourNumber = StrUtil.sub(jm, jm.length(), -4);
                     }
                     }
                 }
                 }
-
                 expressInfoDTO=expressService.getExpressInfo(order.getOrderCode(),order.getDeliveryCode(),order.getDeliverySn(),lastFourNumber);
                 expressInfoDTO=expressService.getExpressInfo(order.getOrderCode(),order.getDeliveryCode(),order.getDeliverySn(),lastFourNumber);
 
 
+                if((expressInfoDTO.getStateEx()!=null&&expressInfoDTO.getStateEx().equals("0"))&&(expressInfoDTO.getState()!=null&&expressInfoDTO.getState().equals("0"))){
+                    lastFourNumber = "19923690275";
+                    if (order.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
+                        if (lastFourNumber.length() == 11) {
+                            lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+                        }
+                    }
+
+                    expressInfoDTO=expressService.getExpressInfo(order.getOrderCode(),order.getDeliveryCode(),order.getDeliverySn(),lastFourNumber);
+
+                }
             }
             }
         }
         }
+
         return R.ok().put("data",expressInfoDTO);
         return R.ok().put("data",expressInfoDTO);
     }
     }
     @PreAuthorize("@ss.hasPermi('his:storeOrder:msgList')")
     @PreAuthorize("@ss.hasPermi('his:storeOrder:msgList')")
@@ -654,15 +788,21 @@ public class FsStoreOrderController extends BaseController
     @PostMapping("/editErpPhone")
     @PostMapping("/editErpPhone")
     public AjaxResult editErpPhone(@RequestBody FsStoreOrderSetErpPhoneParam param)
     public AjaxResult editErpPhone(@RequestBody FsStoreOrderSetErpPhoneParam param)
     {
     {
-        String erpPhone = param.getErpPhone();
-        if (StringUtils.isBlank(erpPhone)) {
+        List<String> erpPhone = param.getErpPhone();
+        if (erpPhone == null || erpPhone.isEmpty()) {
             return AjaxResult.error("请选择手机号");
             return AjaxResult.error("请选择手机号");
         }
         }
-        List<Long> orderIds = param.getOrderIds();
-        if (orderIds  == null || orderIds.isEmpty()){
-            return AjaxResult.success();
-        }
         return toAjax(fsStoreOrderService.batchUpdateErpByOrderIds(param));
         return toAjax(fsStoreOrderService.batchUpdateErpByOrderIds(param));
     }
     }
 
 
+    /**
+     * 获取erp账户
+     */
+    @GetMapping("/getErpAccount")
+    public R getErpAccount()
+    {
+        List<DFConfigVo> erpAccounts = fsStoreOrderService.getErpAccount();
+        List<String> list = erpAccounts.stream().map(DFConfigVo::getLoginAccount).collect(Collectors.toList());
+        return R.ok().put("data", list);
+    }
 }
 }

+ 6 - 9
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -199,16 +199,13 @@ public class FsUserController extends BaseController
 //        startPage();
 //        startPage();
 //        PageHelper.startPage(param.getPageNum(), param.getPageSize());
 //        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
-        if(ObjectUtils.isNotNull(fsUserPageListVOPageInfo)){
-            for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOPageInfo.getList()) {
-                fsUserPageListVO.setPhone(ParseUtils.parsePhone(fsUserPageListVO.getPhone()));
-            }
-            Map<String, Object> map = new HashMap<String, Object>();
-            map.put("rows", fsUserPageListVOPageInfo.getList());
-            map.put("total", fsUserPageListVOPageInfo.getList().size());
-            return R.ok(map);
+        for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOPageInfo.getList()) {
+            fsUserPageListVO.setPhone(ParseUtils.parsePhone(fsUserPageListVO.getPhone()));
         }
         }
-        return R.ok();
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("rows", fsUserPageListVOPageInfo.getList());
+        map.put("total", fsUserPageListVOPageInfo.getTotal());
+        return R.ok(map);
     }
     }
 
 
     @PreAuthorize("@ss.hasPermi('his:user:enabledUsers')")
     @PreAuthorize("@ss.hasPermi('his:user:enabledUsers')")

+ 7 - 0
fs-admin/src/main/java/com/fs/his/controller/FsUserOperationLogController.java

@@ -1,6 +1,7 @@
 package com.fs.his.controller;
 package com.fs.his.controller;
 
 
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.his.domain.FsUserOperationLog;
 import com.fs.his.domain.FsUserOperationLog;
 import com.fs.his.service.IFsUserOperationLogService;
 import com.fs.his.service.IFsUserOperationLogService;
@@ -36,4 +37,10 @@ public class FsUserOperationLogController extends BaseController {
 
 
         return getDataTable(list);
         return getDataTable(list);
     }
     }
+
+    @GetMapping("/getOperationType")
+    public R getOperationType()
+    {
+        return R.ok().put("data",fsUserOperationLogService.getOperationType());
+    }
 }
 }

+ 57 - 5
fs-admin/src/main/java/com/fs/his/controller/HzOMSErpApiController.java

@@ -1,21 +1,24 @@
 package com.fs.his.controller;
 package com.fs.his.controller;
 
 
 
 
-import com.fs.erp.domain.ErpOrder;
-import com.fs.erp.dto.ErpOrderResponse;
-import com.fs.erp.dto.sdk.HzOMS.utils.HzOMSUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.StringUtils;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.erp.service.IErpOrderService;
-import com.fs.his.domain.FsVessel;
 import com.fs.his.param.HzOMSErpApiParam;
 import com.fs.his.param.HzOMSErpApiParam;
 import com.fs.his.service.ErpApiService;
 import com.fs.his.service.ErpApiService;
+import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.vo.HzOMSErpResponseVO;
 import com.fs.his.vo.HzOMSErpResponseVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.RestController;
 
 
-import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 
 /**
 /**
  * 瀚智OMS Erp系统推送平数据接口
  * 瀚智OMS Erp系统推送平数据接口
@@ -23,6 +26,7 @@ import java.util.List;
 
 
 @RestController
 @RestController
 @RequestMapping("/erp/call")
 @RequestMapping("/erp/call")
+@Slf4j
 public class HzOMSErpApiController {
 public class HzOMSErpApiController {
 
 
     @Autowired
     @Autowired
@@ -33,6 +37,9 @@ public class HzOMSErpApiController {
     @Qualifier("hzOMSErpOrderServiceImpl")
     @Qualifier("hzOMSErpOrderServiceImpl")
     IErpOrderService HzOMSErpOrderService;
     IErpOrderService HzOMSErpOrderService;
 
 
+    @Autowired
+    private IFsStoreOrderService fsStoreOrderService;
+
     /**
     /**
      * 用于将瀚智商品库存同步到第三方
      * 用于将瀚智商品库存同步到第三方
      *
      *
@@ -118,6 +125,51 @@ public class HzOMSErpApiController {
 //        return hzOMSErpResponseVO;
 //        return hzOMSErpResponseVO;
 //    }
 //    }
 
 
+
+    /**
+     * 代服管家订单回调
+     */
+    @PostMapping("/dfNotifyUrl")
+    public R dfOrderResult(HttpServletRequest request){
+        String body = null;
+        try {
+            // 1. 先设置编码
+            request.setCharacterEncoding("UTF-8");
+            // 3. 按 UTF-8 解码
+            body = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            log.error("读取 body 失败", e);
+            return null;
+        }
+        log.info("Body UTF-8: {}", body);
+
+        return StringUtils.isNotBlank(body)
+                ? fsStoreOrderService.dfOrderResult(body)
+                : R.ok();
+    }
+
+    /**
+     * 代服管家订单状态回调
+     */
+    @PostMapping("/receiveWaybillPush")
+    public R receiveWaybillPush(HttpServletRequest request) {
+        String body = null;
+        try {
+            // 1. 先设置编码
+            request.setCharacterEncoding("UTF-8");
+            // 3. 按 UTF-8 解码
+            body = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            log.error("读取 body 失败", e);
+            return null;
+        }
+        log.info("Body UTF-8: {}", body);
+
+        return StringUtils.isNotBlank(body)
+                ? fsStoreOrderService.receiveWaybillPush(body)
+                : R.ok();
+    }
+
     /**
     /**
      * 推送商品到瀚智OMS
      * 推送商品到瀚智OMS
      * @return
      * @return

+ 59 - 18
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -16,9 +16,13 @@ import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.ITencentCloudCosService;
 import com.fs.course.service.ITencentCloudCosService;
 import com.fs.erp.domain.ErpDeliverys;
 import com.fs.erp.domain.ErpDeliverys;
+import com.fs.erp.domain.ErpOrder;
 import com.fs.erp.domain.ErpOrderQuery;
 import com.fs.erp.domain.ErpOrderQuery;
+import com.fs.erp.domain.FsErpFinishPush;
 import com.fs.erp.dto.ErpOrderQueryRequert;
 import com.fs.erp.dto.ErpOrderQueryRequert;
 import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.dto.ErpOrderQueryResponse;
+import com.fs.erp.dto.ErpOrderResponse;
+import com.fs.erp.mapper.FsErpFinishPushMapper;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.FsSysConfig;
@@ -262,10 +266,11 @@ public class Task {
         List<FsStoreOrder> orders = null;
         List<FsStoreOrder> orders = null;
         if (erpOrderService == gyOrderService){
         if (erpOrderService == gyOrderService){
             orders = fsStoreOrderMapper.selectOmsOrderdeliveryOp();
             orders = fsStoreOrderMapper.selectOmsOrderdeliveryOp();
-        } else if (erpOrderService == wdtOrderService){
+        } else if (erpOrderService == wdtOrderService || erpOrderService == dfOrderService || erpOrderService == jSTOrderService){
             orders = fsStoreOrderMapper.selectWdtOmsOrderdeliveryOp();
             orders = fsStoreOrderMapper.selectWdtOmsOrderdeliveryOp();
         }
         }
 
 
+
         for(FsStoreOrder order:orders){
         for(FsStoreOrder order:orders){
 
 
             ErpOrderQueryRequert request=new ErpOrderQueryRequert();
             ErpOrderQueryRequert request=new ErpOrderQueryRequert();
@@ -273,17 +278,19 @@ public class Task {
             request.setCode(order.getExtendOrderId());
             request.setCode(order.getExtendOrderId());
             if (erpOrderService != null){
             if (erpOrderService != null){
                 ErpOrderQueryResponse response=erpOrderService.getOrder(request);
                 ErpOrderQueryResponse response=erpOrderService.getOrder(request);
-                if(response.getOrders()!=null&&response.getOrders().size()>0){
-                    for(ErpOrderQuery orderQuery : response.getOrders()){
-                        if(orderQuery.getDeliverys()!=null&&orderQuery.getDeliverys().size()>0){
-                            for(ErpDeliverys delivery:orderQuery.getDeliverys()){
-                                if(delivery.getDelivery()&& StringUtils.isNotEmpty(delivery.getMail_no())){
-                                    //更新商订单状态 删除REDIS
-                                    fsStoreOrderService.deliveryOrder(order.getOrderCode(),delivery.getMail_no(),delivery.getExpress_code(),delivery.getExpress_name());
-                                    redisCache.deleteObject("delivery"+":"+order.getExtendOrderId());
+                if (erpOrderService != dfOrderService){
+                    if(response.getOrders()!=null&&response.getOrders().size()>0){
+                        for(ErpOrderQuery orderQuery : response.getOrders()){
+                            if(orderQuery.getDeliverys()!=null&&orderQuery.getDeliverys().size()>0){
+                                for(ErpDeliverys delivery:orderQuery.getDeliverys()){
+                                    if(delivery.getDelivery()&& StringUtils.isNotEmpty(delivery.getMail_no())){
+                                        //更新商订单状态 删除REDIS
+                                        fsStoreOrderService.deliveryOrder(order.getOrderCode(),delivery.getMail_no(),delivery.getExpress_code(),delivery.getExpress_name());
+                                        redisCache.deleteObject("delivery"+":"+order.getExtendOrderId());
+                                    }
                                 }
                                 }
-                            }
 
 
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
@@ -295,6 +302,21 @@ public class Task {
 
 
     }
     }
 
 
+
+    public void getOrderDeliveryStatus()
+    {
+        IErpOrderService erpOrderService = getErpService();
+        List<FsStoreOrder> orders = null;
+        if (erpOrderService !=null && erpOrderService == dfOrderService){
+            orders = fsStoreOrderMapper.selectShippedOrder();
+            if(orders!=null&& !orders.isEmpty()){
+                for(FsStoreOrder order:orders){
+                    erpOrderService.getOrderDeliveryStatus(order);
+                }
+            }
+        }
+    }
+
     public void CreateOmsAndHis()
     public void CreateOmsAndHis()
     {
     {
         List<Long> omsList = fsStoreOrderMapper.selectFsStoreOrderNoCreateOms();
         List<Long> omsList = fsStoreOrderMapper.selectFsStoreOrderNoCreateOms();
@@ -304,14 +326,14 @@ public class Task {
             } catch (Exception e) {
             } catch (Exception e) {
             }
             }
         }
         }
-        List<Long> tuiOrderList = fsStoreOrderMapper.selectFsStoreOrderNoTuiOrder();
-        for (Long l : tuiOrderList) {
-            try {
-                fsStoreOrderService.tuiOrder(l);
-            } catch (Exception e) {
-            }
-
-        }
+//        List<Long> tuiOrderList = fsStoreOrderMapper.selectFsStoreOrderNoTuiOrder();
+//        for (Long l : tuiOrderList) {
+//            try {
+//                fsStoreOrderService.tuiOrder(l);
+//            } catch (Exception e) {
+//            }
+//
+//        }
     }
     }
 
 
     public void createFollow()
     public void createFollow()
@@ -1001,6 +1023,17 @@ public class Task {
     @Autowired
     @Autowired
     @Qualifier("wdtErpOrderServiceImpl")
     @Qualifier("wdtErpOrderServiceImpl")
     private IErpOrderService wdtOrderService;
     private IErpOrderService wdtOrderService;
+    @Autowired
+    @Qualifier("hzOMSErpOrderServiceImpl")
+    private IErpOrderService hzOMSErpOrderService;
+    @Autowired
+    @Qualifier("dfOrderServiceImpl")
+    private IErpOrderService dfOrderService;
+
+    @Autowired
+    @Qualifier("JSTErpOrderServiceImpl")
+    private IErpOrderService jSTOrderService;
+
     private IErpOrderService getErpService() {
     private IErpOrderService getErpService() {
         FsSysConfig sysConfig = configUtil.getSysConfig();
         FsSysConfig sysConfig = configUtil.getSysConfig();
         Integer erpOpen = sysConfig.getErpOpen();
         Integer erpOpen = sysConfig.getErpOpen();
@@ -1015,6 +1048,14 @@ public class Task {
                 } else if (erpType == 2){
                 } else if (erpType == 2){
                     //旺店通
                     //旺店通
                     erpOrderService =  wdtOrderService;
                     erpOrderService =  wdtOrderService;
+                } else if (erpType == 3){
+                    //
+                    erpOrderService =  hzOMSErpOrderService;
+                } else if (erpType == 4){
+                    //代服
+                    erpOrderService =  dfOrderService;
+                }else if(erpType == 5){
+                    erpOrderService=jSTOrderService;
                 }
                 }
                 return erpOrderService;
                 return erpOrderService;
 
 

+ 103 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerController.java

@@ -0,0 +1,103 @@
+package com.fs.qw.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.qw.domain.QwIpadServer;
+import com.fs.qw.service.IQwIpadServerService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * ipad服务器Controller
+ *
+ * @author fs
+ * @date 2025-07-23
+ */
+@RestController
+@RequestMapping("/qw/qwIpadServer")
+public class QwIpadServerController extends BaseController
+{
+    @Autowired
+    private IQwIpadServerService qwIpadServerService;
+
+    /**
+     * 查询ipad服务器列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwIpadServer qwIpadServer)
+    {
+        startPage();
+        List<QwIpadServer> list = qwIpadServerService.selectQwIpadServerList(qwIpadServer);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出ipad服务器列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:export')")
+    @Log(title = "ipad服务器", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwIpadServer qwIpadServer)
+    {
+        List<QwIpadServer> list = qwIpadServerService.selectQwIpadServerList(qwIpadServer);
+        ExcelUtil<QwIpadServer> util = new ExcelUtil<QwIpadServer>(QwIpadServer.class);
+        return util.exportExcel(list, "ipad服务器数据");
+    }
+
+    /**
+     * 获取ipad服务器详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwIpadServerService.selectQwIpadServerById(id));
+    }
+
+    /**
+     * 新增ipad服务器
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:add')")
+    @Log(title = "ipad服务器", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwIpadServer qwIpadServer)
+    {
+        return toAjax(qwIpadServerService.insertQwIpadServer(qwIpadServer));
+    }
+
+    /**
+     * 修改ipad服务器
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:edit')")
+    @Log(title = "ipad服务器", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwIpadServer qwIpadServer)
+    {
+        return toAjax(qwIpadServerService.updateQwIpadServer(qwIpadServer));
+    }
+
+    /**
+     * 删除ipad服务器
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:remove')")
+    @Log(title = "ipad服务器", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwIpadServerService.deleteQwIpadServerByIds(ids));
+    }
+}

+ 118 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerLogController.java

@@ -0,0 +1,118 @@
+package com.fs.qw.controller;
+
+import java.util.List;
+
+import com.fs.qw.param.IPadServerLogParam;
+import com.fs.qw.vo.QwIPadServerLogVO;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.qw.domain.QwIpadServerLog;
+import com.fs.qw.service.IQwIpadServerLogService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * ipad服务器日志Controller
+ *
+ * @author fs
+ * @date 2025-07-23
+ */
+@RestController
+@RequestMapping("/qw/qwIpadServerLog")
+public class QwIpadServerLogController extends BaseController
+{
+    @Autowired
+    private IQwIpadServerLogService qwIpadServerLogService;
+
+    /**
+     * 查询ipad服务器日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwIpadServerLog qwIpadServerLog)
+    {
+        startPage();
+        List<QwIpadServerLog> list = qwIpadServerLogService.selectQwIpadServerLogList(qwIpadServerLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询ipad服务器日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:list')")
+    @GetMapping("/ipadServerLogList")
+    public TableDataInfo ipadServerLogList(IPadServerLogParam iPadServerLogParam)
+    {
+        startPage();
+        List<QwIPadServerLogVO> list = qwIpadServerLogService.selectIpadServerLogList(iPadServerLogParam);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出ipad服务器日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:export')")
+    @Log(title = "ipad服务器日志", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(IPadServerLogParam qwIpadServerLog)
+    {
+        List<QwIPadServerLogVO> list = qwIpadServerLogService.selectIpadServerLogList(qwIpadServerLog);
+        ExcelUtil<QwIPadServerLogVO> util = new ExcelUtil<QwIPadServerLogVO>(QwIPadServerLogVO.class);
+        return util.exportExcel(list, "ipad服务器日志数据");
+    }
+
+    /**
+     * 获取ipad服务器日志详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwIpadServerLogService.selectQwIpadServerLogById(id));
+    }
+
+    /**
+     * 新增ipad服务器日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:add')")
+    @Log(title = "ipad服务器日志", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwIpadServerLog qwIpadServerLog)
+    {
+        return toAjax(qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog));
+    }
+
+    /**
+     * 修改ipad服务器日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:edit')")
+    @Log(title = "ipad服务器日志", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwIpadServerLog qwIpadServerLog)
+    {
+        return toAjax(qwIpadServerLogService.updateQwIpadServerLog(qwIpadServerLog));
+    }
+
+    /**
+     * 删除ipad服务器日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:remove')")
+    @Log(title = "ipad服务器日志", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwIpadServerLogService.deleteQwIpadServerLogByIds(ids));
+    }
+}

+ 118 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerUserController.java

@@ -0,0 +1,118 @@
+package com.fs.qw.controller;
+
+import java.util.List;
+
+import com.fs.qw.param.IPadServerUserParam;
+import com.fs.qw.vo.QwIPadServerUserVO;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.qw.domain.QwIpadServerUser;
+import com.fs.qw.service.IQwIpadServerUserService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * ipad用户Controller
+ *
+ * @author fs
+ * @date 2025-07-23
+ */
+@RestController
+@RequestMapping("/qw/qwIpadServerUser")
+public class QwIpadServerUserController extends BaseController
+{
+    @Autowired
+    private IQwIpadServerUserService qwIpadServerUserService;
+
+    /**
+     * 查询ipad用户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwIpadServerUser qwIpadServerUser)
+    {
+        startPage();
+        List<QwIpadServerUser> list = qwIpadServerUserService.selectQwIpadServerUserList(qwIpadServerUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询ipad用户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:list')")
+    @GetMapping("/ipadServerUserList")
+    public TableDataInfo list(IPadServerUserParam iPadServerUserParam)
+    {
+        startPage();
+        List<QwIPadServerUserVO> list = qwIpadServerUserService.selectIpadServerUserList(iPadServerUserParam);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出ipad用户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:export')")
+    @Log(title = "ipad用户", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(IPadServerUserParam iPadServerUserParam)
+    {
+        List<QwIPadServerUserVO> list = qwIpadServerUserService.selectIpadServerUserList(iPadServerUserParam);
+        ExcelUtil<QwIPadServerUserVO> util = new ExcelUtil<QwIPadServerUserVO>(QwIPadServerUserVO.class);
+        return util.exportExcel(list, "ipad用户数据");
+    }
+
+    /**
+     * 获取ipad用户详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwIpadServerUserService.selectQwIpadServerUserById(id));
+    }
+
+    /**
+     * 新增ipad用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:add')")
+    @Log(title = "ipad用户", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwIpadServerUser qwIpadServerUser)
+    {
+        return toAjax(qwIpadServerUserService.insertQwIpadServerUser(qwIpadServerUser));
+    }
+
+    /**
+     * 修改ipad用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:edit')")
+    @Log(title = "ipad用户", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwIpadServerUser qwIpadServerUser)
+    {
+        return toAjax(qwIpadServerUserService.updateQwIpadServerUser(qwIpadServerUser));
+    }
+
+    /**
+     * 删除ipad用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:remove')")
+    @Log(title = "ipad用户", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwIpadServerUserService.deleteQwIpadServerUserByIds(ids));
+    }
+}

+ 1 - 1
fs-admin/src/main/resources/application.yml

@@ -4,7 +4,7 @@ server:
 # Spring配置
 # Spring配置
 spring:
 spring:
   profiles:
   profiles:
-    active: dev
+    active: druid-myhk-test
 #    active: druid-hdt
 #    active: druid-hdt
 #    active: druid-yzt
 #    active: druid-yzt
 #    active: druid-sxjz
 #    active: druid-sxjz

+ 13 - 4
fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java

@@ -5,7 +5,6 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.app.annotation.Login;
 import com.fs.app.annotation.Login;
 import com.fs.app.config.ImageStorageConfig;
 import com.fs.app.config.ImageStorageConfig;
-
 import com.fs.app.param.FsUserTagUpdateParam;
 import com.fs.app.param.FsUserTagUpdateParam;
 import com.fs.app.param.FsUserUpdateParam;
 import com.fs.app.param.FsUserUpdateParam;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
@@ -42,7 +41,10 @@ import java.io.InputStream;
 import java.time.LocalDate;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 
 @Slf4j
 @Slf4j
 @Api(tags = "用户会员相关接口")
 @Api(tags = "用户会员相关接口")
@@ -78,6 +80,7 @@ public class FsUserController extends AppBaseController {
         param.setUserId(Long.parseLong(getUserId()));
         param.setUserId(Long.parseLong(getUserId()));
 //        PageHelper.startPage(param.getPageNum(), param.getPageSize());
 //        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
+//        PageInfo<FsUserPageListVO> pageInfo = new PageInfo<>(list);
         return ResponseResult.ok(fsUserPageListVOPageInfo);
         return ResponseResult.ok(fsUserPageListVOPageInfo);
     }
     }
 
 
@@ -299,7 +302,7 @@ public class FsUserController extends AppBaseController {
         return ResponseResult.ok(fsUserService.companyUserSummaryCount(userId, companyUserId));
         return ResponseResult.ok(fsUserService.companyUserSummaryCount(userId, companyUserId));
     }
     }
 
 
-    @Login
+//    @Login
     @ApiOperation("会员关联绑定销售")
     @ApiOperation("会员关联绑定销售")
     @PostMapping("/beMember")
     @PostMapping("/beMember")
     public ResponseResult<Boolean> becomeMember(@Valid @RequestBody FsUserCourseBeMemberParam param) {
     public ResponseResult<Boolean> becomeMember(@Valid @RequestBody FsUserCourseBeMemberParam param) {
@@ -326,7 +329,7 @@ public class FsUserController extends AppBaseController {
             String userPosterImage = jsonObject.getString("userPosterImage");
             String userPosterImage = jsonObject.getString("userPosterImage");
             String backgroundImagePath;
             String backgroundImagePath;
             if(StringUtils.isEmpty(userPosterImage)){
             if(StringUtils.isEmpty(userPosterImage)){
-                backgroundImagePath = "https://drk-1363981074.cos.ap-chongqing.myqcloud.com/fs/logo/30d7a0d1ec31e5ac16c6e96d5ca76ad.png";
+                backgroundImagePath = "https://fbylive.obs.cn-southwest-2.myhuaweicloud.com/fs/20250430/1745980979886.png";
             } else {
             } else {
                 backgroundImagePath = userPosterImage;
                 backgroundImagePath = userPosterImage;
             }
             }
@@ -341,4 +344,10 @@ public class FsUserController extends AppBaseController {
         }
         }
     }
     }
 
 
+    @PostMapping("/test")
+    @ApiOperation("测试定时任务")
+    public void userCourseCountTask() {
+        userCourseCountService.insertFsUserCourseCountTask();
+    }
+
 }
 }

+ 3 - 18
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -1,7 +1,5 @@
 package com.fs.app.controller;
 package com.fs.app.controller;
 
 
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.json.JSONUtil;
 import com.fs.app.annotation.Login;
 import com.fs.app.annotation.Login;
 import com.fs.app.config.ImageStorageConfig;
 import com.fs.app.config.ImageStorageConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
@@ -9,7 +7,6 @@ import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.service.ICompanyUserService;
-import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsWatchCourseTimeParam;
 import com.fs.course.param.FsWatchCourseTimeParam;
@@ -20,13 +17,11 @@ import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsUserCoursePeriodService;
 import com.fs.course.service.IFsUserCoursePeriodService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.service.IFsUserCourseVideoService;
-import com.fs.course.service.impl.FsUserCourseServiceImpl;
 import com.fs.course.vo.FsUserCourseParticipationRecordVO;
 import com.fs.course.vo.FsUserCourseParticipationRecordVO;
 import com.fs.course.vo.newfs.FsUserCourseListVO;
 import com.fs.course.vo.newfs.FsUserCourseListVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.course.vo.newfs.FsUserVideoListVO;
 import com.fs.course.vo.newfs.FsUserVideoListVO;
-import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
@@ -37,7 +32,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
 import java.io.InputStream;
 import java.io.InputStream;
-import java.time.LocalDate;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
@@ -56,8 +50,6 @@ public class FsUserCourseVideoController extends AppBaseController {
 
 
     @Autowired
     @Autowired
     private IFsUserCourseService fsUserCourseService;
     private IFsUserCourseService fsUserCourseService;
-    @Autowired
-    private ISysConfigService configService;
 
 
     @Autowired
     @Autowired
     private IFsCourseLinkService courseLinkService;
     private IFsCourseLinkService courseLinkService;
@@ -165,15 +157,8 @@ public class FsUserCourseVideoController extends AppBaseController {
 
 
         R courseSortLink = fsUserCourseService.createCourseSortLink(fsCourseLinkCreateParam);
         R courseSortLink = fsUserCourseService.createCourseSortLink(fsCourseLinkCreateParam);
         String link = courseSortLink.get("link").toString();
         String link = courseSortLink.get("link").toString();
-//        R r = courseLinkService.getRealLink(link);
-//        String realLink = r.get("realLink").toString();
-        String json = configService.selectConfigByKey("course.config");
-        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        //验证是否有分配二级域名
-        CompanyUser companyUser=companyUserService.selectCompanyUserById(param.getCompanyUserId());
-        String realLink = (ObjectUtil.isNotNull(companyUser) && ObjectUtil.isNotNull(companyUser.getDomain())?companyUser.getDomain():config.getRealLinkDomainName()) + FsUserCourseServiceImpl.shortLink + link;
-
-        log.info("二维码生成地址:{}", realLink);
+        R r = courseLinkService.getRealLink(link);
+        String realLink = r.get("realLink").toString();
         try {
         try {
             String path = imageConfig.getServerPath();
             String path = imageConfig.getServerPath();
             log.info("获取的logo图片路径,fileUrl:{}", path);
             log.info("获取的logo图片路径,fileUrl:{}", path);
@@ -229,7 +214,7 @@ public class FsUserCourseVideoController extends AppBaseController {
 
 
         Map<String, Object> params = new HashMap<>();
         Map<String, Object> params = new HashMap<>();
         params.put("companyId", companyId);
         params.put("companyId", companyId);
-        params.put("dayDate", LocalDate.now());
+//        params.put("dayDate", LocalDate.now());
         params.put("companyUserId", Long.parseLong(getUserId()));
         params.put("companyUserId", Long.parseLong(getUserId()));
 
 
         PageHelper.startPage(pageNum, pageSize);
         PageHelper.startPage(pageNum, pageSize);

+ 1 - 3
fs-company-app/src/main/java/com/fs/app/controller/FsUserOperationLogController.java

@@ -53,9 +53,7 @@ public class FsUserOperationLogController extends AppBaseController
             return ResponseResult.fail(500,"未选择会员");
             return ResponseResult.fail(500,"未选择会员");
         }
         }
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        List<FsUserOperationLogPageVo> list = fsUserOperationLogService.selectFsUserOperationLogList(param);
-        PageInfo<FsUserOperationLogPageVo> pageInfo = new PageInfo<>(list);
-        return ResponseResult.ok(pageInfo);
+        return ResponseResult.ok(fsUserOperationLogService.selectFsUserOperationLogList(param));
     }
     }
 
 
 
 

+ 2 - 1
fs-company-app/src/main/resources/application.yml

@@ -5,4 +5,5 @@ server:
 # Spring配置
 # Spring配置
 spring:
 spring:
   profiles:
   profiles:
-    active: druid-fcky-test
+#    active: druid-fcky-test
+    active: dev

+ 11 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java

@@ -405,4 +405,15 @@ public class CompanyUserController extends BaseController
         String subDomain = "http://" + DomainUtil.generateSubDomain(config.getCourseDomainName(), 6, String.valueOf(SecurityUtils.getLoginUser().getUser().getUserId()));
         String subDomain = "http://" + DomainUtil.generateSubDomain(config.getCourseDomainName(), 6, String.valueOf(SecurityUtils.getLoginUser().getUser().getUserId()));
         return  R.ok().put("data",subDomain);
         return  R.ok().put("data",subDomain);
     }
     }
+
+    @Log(title = "设置是否需要单独注册会员", businessType = BusinessType.UPDATE)
+    @PutMapping("/setRegister")
+    public AjaxResult setIsRegisterMember(@RequestParam Boolean status, @RequestBody List<Long> userIds) {
+        Boolean r = companyUserService.setIsRegisterMember(status, userIds);
+        if (r) {
+            return AjaxResult.success();
+        } else {
+            return AjaxResult.error("操作失败");
+        }
+    }
 }
 }

+ 3 - 1
fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java

@@ -213,7 +213,9 @@ public class FsCourseRedPacketLogController extends BaseController
     @GetMapping("/courseList")
     @GetMapping("/courseList")
     public R courseList()
     public R courseList()
     {
     {
-        List<OptionsVO> optionsVOS = fsUserCourseMapper.selectFsUserCourseAllList();
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        List<OptionsVO> optionsVOS = fsUserCourseMapper.selectFsUserCourseByCompany(loginUser.getCompany().getCompanyId());
         return R.ok().put("list", optionsVOS);
         return R.ok().put("list", optionsVOS);
     }
     }
 
 

+ 4 - 1
fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java

@@ -61,6 +61,7 @@ public class FsCourseWatchLogController extends BaseController
     @GetMapping("/list")
     @GetMapping("/list")
     public TableDataInfo list(FsCourseWatchLogListParam param)
     public TableDataInfo list(FsCourseWatchLogListParam param)
     {
     {
+
         startPage();
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
@@ -225,6 +226,7 @@ public class FsCourseWatchLogController extends BaseController
     {
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
+        param.setCompanyUserId( loginUser.getUser().getUserId());
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
         ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);
         ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);
         return util.exportExcel(list, "短链课程看课记录数据");
         return util.exportExcel(list, "短链课程看课记录数据");
@@ -239,7 +241,8 @@ public class FsCourseWatchLogController extends BaseController
     public AjaxResult myExport(FsCourseWatchLogListParam param)
     public AjaxResult myExport(FsCourseWatchLogListParam param)
     {
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        param.setCompanyId( loginUser.getCompany().getCompanyId());
+//        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        param.setCompanyUserId( loginUser.getUser().getUserId());
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
         ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);
         ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);
         return util.exportExcel(list, "短链课程看课记录数据");
         return util.exportExcel(list, "短链课程看课记录数据");

+ 8 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsUserOperationLogController.java

@@ -1,6 +1,7 @@
 package com.fs.company.controller.course;
 package com.fs.company.controller.course;
 
 
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.his.domain.FsUserOperationLog;
 import com.fs.his.domain.FsUserOperationLog;
 import com.fs.his.service.IFsUserOperationLogService;
 import com.fs.his.service.IFsUserOperationLogService;
@@ -9,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.RestController;
 
 
 import java.util.List;
 import java.util.List;
@@ -32,4 +34,10 @@ public class FsUserOperationLogController extends BaseController {
 
 
         return getDataTable(list);
         return getDataTable(list);
     }
     }
+
+    @GetMapping("/getOperationType")
+    public R getOperationType()
+    {
+        return R.ok().put("data",fsUserOperationLogService.getOperationType());
+    }
 }
 }

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

@@ -61,7 +61,6 @@ public class FastGptRoleController extends BaseController
     @GetMapping("/getAllRoleType")
     @GetMapping("/getAllRoleType")
     public R list()
     public R list()
     {
     {
-
         List<OptionsVO> list = fastGptRoleService.selectFastGptRoleType();
         List<OptionsVO> list = fastGptRoleService.selectFastGptRoleType();
         return R.ok().put("data",list);
         return R.ok().put("data",list);
     }
     }

+ 4 - 2
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java

@@ -207,12 +207,14 @@ public class QwExternalContactController extends BaseController
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
+
     @Log(title = "同步我的企业微信客户", businessType = BusinessType.INSERT)
     @Log(title = "同步我的企业微信客户", businessType = BusinessType.INSERT)
     @GetMapping("/syncMyExternalContact/{id}")
     @GetMapping("/syncMyExternalContact/{id}")
     public R  syncMyExternalContact(@PathVariable("id") Long id ) throws IOException {
     public R  syncMyExternalContact(@PathVariable("id") Long id ) throws IOException {
         return qwExternalContactService.syncMyQwExternalContact(id);
         return qwExternalContactService.syncMyQwExternalContact(id);
     }
     }
 
 
+
     @Log(title = "新客同步", businessType = BusinessType.INSERT)
     @Log(title = "新客同步", businessType = BusinessType.INSERT)
     @GetMapping("/syncAddMyExternalContact/{id}")
     @GetMapping("/syncAddMyExternalContact/{id}")
     public R  syncAddMyExternalContact(@PathVariable("id") Long id ) throws IOException {
     public R  syncAddMyExternalContact(@PathVariable("id") Long id ) throws IOException {
@@ -322,7 +324,7 @@ public class QwExternalContactController extends BaseController
         return qwExternalContactService.syncQwExternalContactUnassigned(qwExternalContact.getCorpId());
         return qwExternalContactService.syncQwExternalContactUnassigned(qwExternalContact.getCorpId());
     }
     }
 
 
-    @PreAuthorize("@ss.hasPermi('qw:externalContact:addTag')")
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:addTag') or @ss.hasPermi('qw:externalContact:myAddTag') or @ss.hasPermi('qw:externalContact:deptAddTag')")
     @Log(title = "添加标签", businessType = BusinessType.UPDATE)
     @Log(title = "添加标签", businessType = BusinessType.UPDATE)
     @PostMapping("/addTag")
     @PostMapping("/addTag")
     public R addTag(@RequestBody QwExternalContactAddTagParam Param) throws JSONException {
     public R addTag(@RequestBody QwExternalContactAddTagParam Param) throws JSONException {
@@ -339,7 +341,7 @@ public class QwExternalContactController extends BaseController
 
 
     }
     }
 
 
-    @PreAuthorize("@ss.hasPermi('qw:externalContact:delTag')")
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:delTag') or @ss.hasPermi('qw:externalContact:myDelTag') or @ss.hasPermi('qw:externalContact:deptDelTag')")
     @Log(title = "移除标签", businessType = BusinessType.UPDATE)
     @Log(title = "移除标签", businessType = BusinessType.UPDATE)
     @PostMapping("/delTag")
     @PostMapping("/delTag")
     public R delTag(@RequestBody QwExternalContactAddTagParam Param)
     public R delTag(@RequestBody QwExternalContactAddTagParam Param)

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

@@ -76,7 +76,7 @@ public class QwExternalContactInfoController extends BaseController
     /**
     /**
      * 修改外部联系人信息表
      * 修改外部联系人信息表
      */
      */
-    @PreAuthorize("@ss.hasPermi('qw:externalContactInfo:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:externalContactInfo:edit') or @ss.hasPermi('qw:externalContactInfo:myEdit') or @ss.hasPermi('qw:externalContactInfo:deptEdit')")
     @Log(title = "外部联系人信息表", businessType = BusinessType.UPDATE)
     @Log(title = "外部联系人信息表", businessType = BusinessType.UPDATE)
     @PutMapping
     @PutMapping
     public AjaxResult edit(@RequestBody QwExternalContactInfo qwExternalContactInfo)
     public AjaxResult edit(@RequestBody QwExternalContactInfo qwExternalContactInfo)
@@ -98,6 +98,7 @@ public class QwExternalContactInfoController extends BaseController
 
 
 
 
 
 
+    @PreAuthorize("@ss.hasPermi('qw:externalContactInfo:updateTalk') or @ss.hasPermi('qw:externalContactInfo:myUpdateTalk') or @ss.hasPermi('qw:externalContactInfo:deptUpdateTalk')")
     @Log(title = "更改外部联系人信息表", businessType = BusinessType.UPDATE)
     @Log(title = "更改外部联系人信息表", businessType = BusinessType.UPDATE)
     @PutMapping("/editTalk/{ids}")
     @PutMapping("/editTalk/{ids}")
     public AjaxResult editTalk(@PathVariable Long[] ids)
     public AjaxResult editTalk(@PathVariable Long[] ids)
@@ -105,6 +106,7 @@ public class QwExternalContactInfoController extends BaseController
         return toAjax(qwExternalContactInfoService.updateQwExternalContactInfoByIds(ids));
         return toAjax(qwExternalContactInfoService.updateQwExternalContactInfoByIds(ids));
     }
     }
 
 
+    @PreAuthorize("@ss.hasPermi('qw:externalContactInfo:updateAllTalk') or @ss.hasPermi('qw:externalContactInfo:myUpdateAllTalk') or @ss.hasPermi('qw:externalContactInfo:deptUpdateAllTalk')")
     @Log(title = "更改外部联系人信息表", businessType = BusinessType.UPDATE)
     @Log(title = "更改外部联系人信息表", businessType = BusinessType.UPDATE)
     @PutMapping("/editAllTalk/{id}")
     @PutMapping("/editAllTalk/{id}")
     public AjaxResult editAllTalk(@PathVariable Long id)
     public AjaxResult editAllTalk(@PathVariable Long id)

+ 20 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwSopController.java

@@ -184,6 +184,26 @@ public class QwSopController extends BaseController
         return util.exportExcel(list, "企微sop数据");
         return util.exportExcel(list, "企微sop数据");
     }
     }
 
 
+    /**
+     * 我的企微导出sop
+     * @param qwSop
+     * @return
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sop:myExport')")
+    @Log(title = "我的企微sop", businessType = BusinessType.EXPORT)
+    @GetMapping("/myExport")
+    public AjaxResult myExport(QwSop qwSop)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long companyId = loginUser.getCompany().getCompanyId();
+        Long userId = loginUser.getUser().getUserId();
+        qwSop.setCompanyId(companyId);
+        qwSop.setUserId(userId);
+        List<QwSop> list = qwSopService.selectQwSopList(qwSop);
+        ExcelUtil<QwSop> util = new ExcelUtil<QwSop>(QwSop.class);
+        return util.exportExcel(list, "企微sop数据");
+    }
+
     /**
     /**
      * 获取企微sop详细信息
      * 获取企微sop详细信息
      */
      */

+ 1 - 1
fs-company/src/main/java/com/fs/company/controller/qw/QwUserVoiceLogController.java

@@ -107,7 +107,7 @@ public class QwUserVoiceLogController extends BaseController
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
-    @PreAuthorize("@ss.hasPermi('qw:qwUserVoiceLog:sellTotalList')")
+
     @GetMapping("/sellTotalList")
     @GetMapping("/sellTotalList")
     public TableDataInfo sellTotalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     public TableDataInfo sellTotalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     {
     {

+ 164 - 30
fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsInfoController.java

@@ -26,16 +26,14 @@ import com.fs.sop.params.SendUserLogsInfoMsgParam;
 import com.fs.sop.service.ISopUserLogsInfoService;
 import com.fs.sop.service.ISopUserLogsInfoService;
 import com.fs.voice.utils.StringUtil;
 import com.fs.voice.utils.StringUtil;
 import com.google.gson.Gson;
 import com.google.gson.Gson;
-import com.google.gson.JsonSyntaxException;
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
 import java.util.function.Predicate;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
@@ -89,7 +87,7 @@ public class SopUserLogsInfoController extends BaseController
                 Map<Long, SopExternalContactInfo> externalContactInfoMap = qwExternalContactVOTimes.stream()
                 Map<Long, SopExternalContactInfo> externalContactInfoMap = qwExternalContactVOTimes.stream()
                         .collect(Collectors.toMap(
                         .collect(Collectors.toMap(
                                 QwExternalContactVOTime::getId,
                                 QwExternalContactVOTime::getId,
-                                item -> new SopExternalContactInfo(item.getCreateTime(), item.getTagIds(), item.getRemark())
+                                item -> new SopExternalContactInfo(item.getCreateTime(), item.getTagIds(), item.getRemark(),item.getLevel())
                         ));
                         ));
                 List<String> tagIds = qwExternalContactVOTimes.stream().map(QwExternalContactVOTime::getTagIds).filter(StringUtils::isNotEmpty).flatMap(e -> JSON.parseArray(e, String.class).stream()).collect(Collectors.toList());
                 List<String> tagIds = qwExternalContactVOTimes.stream().map(QwExternalContactVOTime::getTagIds).filter(StringUtils::isNotEmpty).flatMap(e -> JSON.parseArray(e, String.class).stream()).collect(Collectors.toList());
                 if(!tagIds.isEmpty()){
                 if(!tagIds.isEmpty()){
@@ -97,35 +95,83 @@ public class SopUserLogsInfoController extends BaseController
                     Map<String, QwTag> tagMap = PubFun.listToMapByGroupObject(tagList, QwTag::getTagId);
                     Map<String, QwTag> tagMap = PubFun.listToMapByGroupObject(tagList, QwTag::getTagId);
                     qwExternalContactVOTimes.forEach(e -> {
                     qwExternalContactVOTimes.forEach(e -> {
                         List<String> tagId = JSON.parseArray(e.getTagIds(), String.class);
                         List<String> tagId = JSON.parseArray(e.getTagIds(), String.class);
-                        List<String> tagNameList = tagId.stream().filter(tagMap::containsKey).map(t -> tagMap.get(t).getName()).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
-                        e.setTagIdsName(tagNameList);
+                        if(StringUtils.isNotEmpty(tagId)){
+                            List<String> tagNameList = tagId.stream().filter(tagMap::containsKey).map(t -> tagMap.get(t).getName()).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+                            e.setTagIdsName(tagNameList);
+                        }
                     });
                     });
                 }
                 }
                 // 设置联系信息
                 // 设置联系信息
                 list.forEach(item -> {
                 list.forEach(item -> {
                     SopExternalContactInfo info = externalContactInfoMap.getOrDefault(
                     SopExternalContactInfo info = externalContactInfoMap.getOrDefault(
                             item.getExternalId(),
                             item.getExternalId(),
-                            new SopExternalContactInfo("无进线时间", "无标签", "无备注"));
+                            new SopExternalContactInfo("无进线时间", "无标签", "无备注",0));
                     item.setInComTime(info.getCreateTime());
                     item.setInComTime(info.getCreateTime());
                     item.setTagIds(info.getTagIds());
                     item.setTagIds(info.getTagIds());
                     item.setRemark(info.getRemark());
                     item.setRemark(info.getRemark());
+                    item.setLevel(info.getLevel());
+
                 });
                 });
             }
             }
 
 
+            Predicate<SopUserLogsInfo> tagFilter = item -> {
+                String queryTagIds = sopUserLogsInfo.getTagIds();
+                String itemTagIds = item.getTagIds();
+
+                if (queryTagIds == null || queryTagIds.trim().equals("[]")) {
+                    return true;
+                }
+                List<String> queryTags = parseTagIds(queryTagIds);
+                List<String> itemTags = parseTagIds(itemTagIds);
+
+                // 检查 itemTags 是否包含所有 queryTags(AND 关系)
+                return itemTags.containsAll(queryTags);
+            };
+
             // 优化过滤条件
             // 优化过滤条件
             boolean isRemarkEmpty = StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getRemark());
             boolean isRemarkEmpty = StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getRemark());
-            Predicate<SopUserLogsInfo> tagFilter = item ->
-                    sopUserLogsInfo.getTagIds() == null ||
-                            sopUserLogsInfo.getTagIds().isEmpty() ||
-                            item.getTagIds().contains(sopUserLogsInfo.getTagIds());
-
             Predicate<SopUserLogsInfo> remarkFilter = item ->
             Predicate<SopUserLogsInfo> remarkFilter = item ->
                     isRemarkEmpty ||
                     isRemarkEmpty ||
                             item.getRemark().contains(sopUserLogsInfo.getRemark());
                             item.getRemark().contains(sopUserLogsInfo.getRemark());
 
 
-            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty) {
+
+            boolean isLevelEmpty = sopUserLogsInfo.getLevel() == null;
+            Predicate<SopUserLogsInfo> levelFilter = item ->
+                    isLevelEmpty ||
+                            (item.getLevel() != null && Objects.equals(item.getLevel(), sopUserLogsInfo.getLevel()) );
+
+
+            Predicate<SopUserLogsInfo> timeFilter = item -> {
+
+                if (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
+                        && StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime()) ) {
+                    return true;
+                }
+                try {
+                    LocalDateTime entryDate = LocalDateTime.parse(item.getInComTime(),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+                    );
+                    LocalDateTime inComingSTime = LocalDateTime.parse(sopUserLogsInfo.getInComingSTime(),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+                    );
+
+                    LocalDateTime inComingETime = LocalDateTime.parse(sopUserLogsInfo.getInComingETime(),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+                    );
+
+                    return !entryDate.isBefore(inComingSTime) && !entryDate.isAfter(inComingETime);
+                } catch (Exception e) {
+                    return false;
+                }
+            };
+
+
+            boolean hasTimeFilter = !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
+                    && !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime());
+
+            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty || hasTimeFilter ||!isLevelEmpty) {
                 list = list.stream()
                 list = list.stream()
-                        .filter(tagFilter.and(remarkFilter))
+                        .filter(tagFilter.and(remarkFilter).and(timeFilter).and(levelFilter))
                         .collect(Collectors.toList());
                         .collect(Collectors.toList());
             }
             }
 
 
@@ -137,9 +183,15 @@ public class SopUserLogsInfoController extends BaseController
                     param.setTagIds(tagIds);
                     param.setTagIds(tagIds);
                     item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
                     item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
                 }
                 }
+
+                // 处理 level
+                item.setLevelName(getLevel(item.getLevel()));
             });
             });
+
             return getDataTable(list);
             return getDataTable(list);
-        } else {
+        }
+        else {
+
             List<QwGroupChatUser> list = qwGroupChatUserService.selectByChatId(sopUserLogsInfo);
             List<QwGroupChatUser> list = qwGroupChatUserService.selectByChatId(sopUserLogsInfo);
 
 
 
 
@@ -158,15 +210,14 @@ public class SopUserLogsInfoController extends BaseController
                 Map<String, SopExternalContactInfo> externalContactInfoMap = qwExternalContactVOTimes.stream()
                 Map<String, SopExternalContactInfo> externalContactInfoMap = qwExternalContactVOTimes.stream()
                         .collect(Collectors.toMap(
                         .collect(Collectors.toMap(
                                 QwExternalContactVOTime::getExternalUserId,
                                 QwExternalContactVOTime::getExternalUserId,
-                                item -> new SopExternalContactInfo(item.getCreateTime(), item.getTagIdsName(), item.getTagIds(), item.getRemark())
+                                item -> new SopExternalContactInfo(item.getCreateTime(), item.getTagIds(), item.getRemark(),item.getLevel())
                         ));
                         ));
 
 
                 // 遍历 list,赋值 inComTime 和 tagIds
                 // 遍历 list,赋值 inComTime 和 tagIds
                 list.forEach(item -> {
                 list.forEach(item -> {
-                    SopExternalContactInfo info = externalContactInfoMap.getOrDefault(item.getUserId(), new SopExternalContactInfo("无进线时间", "无标签", "无备注"));
+                    SopExternalContactInfo info = externalContactInfoMap.getOrDefault(item.getUserId(), new SopExternalContactInfo("无进线时间", "无标签", "无备注",0));
                     item.setInComTime(info.getCreateTime());
                     item.setInComTime(info.getCreateTime());
                     item.setTagIds(info.getTagIds());
                     item.setTagIds(info.getTagIds());
-                    item.setTagNames(info.getTagNames());
                     item.setRemark(info.getRemark());
                     item.setRemark(info.getRemark());
                 });
                 });
 
 
@@ -181,22 +232,105 @@ public class SopUserLogsInfoController extends BaseController
                         )
                         )
                         .collect(Collectors.toList());
                         .collect(Collectors.toList());
             }
             }
+
+            // 处理标签名称
+            list.parallelStream().forEach(item -> {
+                if (item.getTagIds() != null && !item.getTagIds().equals("[]") && !item.getTagIds().equals("无标签")) {
+                    List<String> tagIds = GSON.fromJson(item.getTagIds(), new TypeToken<List<String>>() {}.getType());
+                    QwTagSearchParam param = new QwTagSearchParam();
+                    param.setTagIds(tagIds);
+                    item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
+                }
+            });
             return getDataTable(list);
             return getDataTable(list);
+//            List<QwGroupChatUser> list = qwGroupChatUserService.selectByChatId(sopUserLogsInfo);
+//
+//
+//            if (!list.isEmpty()) {
+//
+//                List<String> externalIdList = list.stream()
+//                        .map(QwGroupChatUser::getUserId) // 提取 externalId
+//                        .filter(StringUtils::isNotEmpty) // 过滤掉 null 值,防止 NullPointerException
+//                        .distinct()
+//                        .collect(Collectors.toList()); // 收集到 List
+//
+//                List<QwExternalContactVOTime> qwExternalContactVOTimes = iQwExternalContactService.selectQwExternalContactListVOByUserIds(externalIdList);
+//
+//
+//                // 先将 qwExternalContactVOTimes 转换为 Map,key 为 id,value 为 ExternalContactInfo(包含 createTime 和 tagIds)
+//                Map<String, SopExternalContactInfo> externalContactInfoMap = qwExternalContactVOTimes.stream()
+//                        .collect(Collectors.toMap(
+//                                QwExternalContactVOTime::getExternalUserId,
+//                                item -> new SopExternalContactInfo(item.getCreateTime(), item.getTagIdsName(), item.getTagIds(), item.getRemark())
+//                        ));
+//
+//                // 遍历 list,赋值 inComTime 和 tagIds
+//                list.forEach(item -> {
+//                    SopExternalContactInfo info = externalContactInfoMap.getOrDefault(item.getUserId(), new SopExternalContactInfo("无进线时间", "无标签", "无备注"));
+//                    item.setInComTime(info.getCreateTime());
+//                    item.setTagIds(info.getTagIds());
+//                    item.setTagNames(info.getTagNames());
+//                    item.setRemark(info.getRemark());
+//                });
+//
+//            }
+//
+//            if ((sopUserLogsInfo.getTagIds() != null && !sopUserLogsInfo.getTagIds().isEmpty())
+//                    || !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getRemark())) {
+//                list = list.stream()
+//                        .filter(item ->
+//                                (sopUserLogsInfo.getTagIds() == null || sopUserLogsInfo.getTagIds().isEmpty() || item.getTagIds().contains(sopUserLogsInfo.getTagIds()))
+//                                        && (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getRemark()) || item.getRemark().contains(sopUserLogsInfo.getRemark()))
+//                        )
+//                        .collect(Collectors.toList());
+//            }
+//            return getDataTable(list);
         }
         }
 
 
-//        if (sopUserLogsInfo.getTagIds() != null && !sopUserLogsInfo.getTagIds().isEmpty()) {
-//            list = list.stream()
-//                    .filter(item -> item.getTagIds().contains(sopUserLogsInfo.getTagIds()))
-//                    .collect(Collectors.toList());
-//        }
-//        if (!StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getRemark())) {
-//            list = list.stream()
-//                    .filter(item -> item.getRemark().contains(sopUserLogsInfo.getRemark()))
-//                    .collect(Collectors.toList());
-//        }
     }
     }
 
 
 
 
+    private String getLevel(Integer level){
+
+        String levelName = "无";
+
+        if (level != null) {
+
+            switch (level) {
+                case 0:
+                    levelName = "无";
+                    break;
+                case 1:
+                    levelName = "A";
+                    break;
+                case 2:
+                    levelName = "B";
+                    break;
+                case 3:
+                    levelName = "C";
+                    break;
+                case 4:
+                    levelName = "D";
+                    break;
+                case 5:
+                    levelName = "E";
+                    break;
+                default:
+                    levelName = "无";
+            }
+        }
+        return  levelName;
+    }
+    private List<String> parseTagIds(String jsonTagIds) {
+        if (jsonTagIds == null || jsonTagIds.trim().isEmpty() || jsonTagIds.equals("[]")) {
+            return Collections.emptyList();
+        }
+        // 去掉开头和结尾的 [ ],然后按 "," 分割
+        return Arrays.stream(jsonTagIds.replaceAll("[\\[\\]\"]", "").split(","))
+                .map(String::trim)
+                .filter(s -> !s.isEmpty())
+                .collect(Collectors.toList());
+    }
 //    /**
 //    /**
 //     * 导出sopUserLogsInfo列表
 //     * 导出sopUserLogsInfo列表
 //     */
 //     */

+ 1 - 1
fs-company/src/main/java/com/fs/company/controller/stats/SalesWatchStatisController.java

@@ -100,7 +100,7 @@ public class SalesWatchStatisController {
         param.setPageSize(null);
         param.setPageSize(null);
         List<FsStatisQwWatch> list = fsStatisQwWatchService.exportQueryList(param);
         List<FsStatisQwWatch> list = fsStatisQwWatchService.exportQueryList(param);
         ExcelUtil<FsStatisQwWatch> util = new ExcelUtil<>(FsStatisQwWatch.class);
         ExcelUtil<FsStatisQwWatch> util = new ExcelUtil<>(FsStatisQwWatch.class);
-        return util.exportExcel(list, "销售完播统计");
+        return util.exportExcel(list, "进线转化统计");
     }
     }
 
 
 
 

+ 30 - 4
fs-company/src/main/java/com/fs/company/controller/store/FsInquiryOrderController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.store;
 package com.fs.company.controller.store;
 
 
+import cn.hutool.core.util.IdUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.annotation.RepeatSubmit;
@@ -7,6 +8,7 @@ import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.core.redis.RedisCache;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.LoginUser;
@@ -16,6 +18,7 @@ import com.fs.his.domain.FsInquiryOrder;
 import com.fs.his.domain.FsInquiryOrderMsg;
 import com.fs.his.domain.FsInquiryOrderMsg;
 import com.fs.his.domain.FsStoreOrderLogs;
 import com.fs.his.domain.FsStoreOrderLogs;
 import com.fs.his.param.FsInquiryOrderCancelParam;
 import com.fs.his.param.FsInquiryOrderCancelParam;
+import com.fs.his.param.FsInquiryOrderCreateParam;
 import com.fs.his.param.FsInquiryOrderParam;
 import com.fs.his.param.FsInquiryOrderParam;
 import com.fs.his.param.FsInquiryOrderRefundParam;
 import com.fs.his.param.FsInquiryOrderRefundParam;
 import com.fs.his.service.IFsDoctorService;
 import com.fs.his.service.IFsDoctorService;
@@ -32,9 +35,11 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
+import java.util.Base64;
 import java.util.Date;
 import java.util.Date;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 
 /**
 /**
  * 问诊订单Controller
  * 问诊订单Controller
@@ -59,7 +64,7 @@ public class FsInquiryOrderController extends BaseController
     /**
     /**
      * 查询问诊订单列表
      * 查询问诊订单列表
      */
      */
-    @PreAuthorize("@ss.hasPermi('store:inquiryOrder:list')")
+//    @PreAuthorize("@ss.hasPermi('store:inquiryOrder:list')")
     @GetMapping("/list")
     @GetMapping("/list")
    public TableDataInfo list(FsInquiryOrderParam fsInquiryOrder)
    public TableDataInfo list(FsInquiryOrderParam fsInquiryOrder)
     {
     {
@@ -247,16 +252,24 @@ public class FsInquiryOrderController extends BaseController
         }
         }
         return AjaxResult.success(fsInquiryOrderVO);
         return AjaxResult.success(fsInquiryOrderVO);
     }
     }
-
+    @Autowired
+    RedisCache redisCache;
     /**
     /**
      * 新增问诊订单
      * 新增问诊订单
      */
      */
     @PreAuthorize("@ss.hasPermi('store:inquiryOrder:add')")
     @PreAuthorize("@ss.hasPermi('store:inquiryOrder:add')")
     @Log(title = "问诊订单", businessType = BusinessType.INSERT)
     @Log(title = "问诊订单", businessType = BusinessType.INSERT)
     @PostMapping
     @PostMapping
-    public AjaxResult add(@RequestBody FsInquiryOrder fsInquiryOrder)
+    public R add(@RequestBody FsInquiryOrderCreateParam param)
     {
     {
-        return toAjax(fsInquiryOrderService.insertFsInquiryOrder(fsInquiryOrder));
+        String uuid = IdUtil.randomUUID();
+        redisCache.setCacheObject("orderKey:"+uuid,uuid,200, TimeUnit.MINUTES);
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setOrderKey(uuid);
+        param.setCompanyId(loginUser.getCompany().getCompanyId());
+        param.setCompanyUserId(loginUser.getUser().getUserId());
+        param.setIsVisit("就诊过");
+        return fsInquiryOrderService.createOrder(param);
     }
     }
 
 
     /**
     /**
@@ -350,4 +363,17 @@ public class FsInquiryOrderController extends BaseController
     }
     }
 
 
 
 
+    /**
+    * 生成订单二维码
+    */
+    @PreAuthorize("@ss.hasPermi('store:inquiryOrder:wxaCodeInquiryOrder')")
+    @GetMapping("/getWxaCodeInquiryOrderUnLimit/{orderId}")
+    public AjaxResult getWxaCodeInquiryOrderUnLimit(@PathVariable("orderId") Long orderId)
+    {
+
+        byte[] bytes = fsInquiryOrderService.getWxaCodeInquiryOrderUnLimit(orderId);
+        String base64 = Base64.getEncoder().encodeToString(bytes);
+        return AjaxResult.success("成功",base64);
+
+    }
 }
 }

+ 7 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java

@@ -531,6 +531,11 @@ public class FsStoreOrderController extends BaseController
     @Autowired
     @Autowired
     @Qualifier("hzOMSErpOrderServiceImpl")
     @Qualifier("hzOMSErpOrderServiceImpl")
     private IErpOrderService hzOMSErpOrderService;
     private IErpOrderService hzOMSErpOrderService;
+
+    @Autowired
+    @Qualifier("JSTErpOrderServiceImpl")
+    private IErpOrderService jSTOrderService;
+
     private IErpOrderService getErpService() {
     private IErpOrderService getErpService() {
         FsSysConfig sysConfig = configUtil.getSysConfig();
         FsSysConfig sysConfig = configUtil.getSysConfig();
         Integer erpOpen = sysConfig.getErpOpen();
         Integer erpOpen = sysConfig.getErpOpen();
@@ -548,6 +553,8 @@ public class FsStoreOrderController extends BaseController
                 }  else if (erpType == 3){
                 }  else if (erpType == 3){
                     //hzOMs
                     //hzOMs
                     erpOrderService =  hzOMSErpOrderService;
                     erpOrderService =  hzOMSErpOrderService;
+                }else if(erpType == 5){
+                    erpOrderService = jSTOrderService;
                 }
                 }
                 return erpOrderService;
                 return erpOrderService;
 
 

+ 4 - 3
fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java

@@ -76,9 +76,10 @@ public class FsUserController extends BaseController
     public TableDataInfo userList(FsUserParam fsUser)
     public TableDataInfo userList(FsUserParam fsUser)
     {
     {
         startPage();
         startPage();
-        if(fsUser.getPhoneMk()!=null&&fsUser.getPhone()!=""){
-            fsUser.setPhone(encryptPhone(fsUser.getPhoneMk()));
-        }
+
+
+        fsUser.setPhone(encryptPhone(fsUser.getPhone()));
+
         List<FsUserVO> list = fsUserService.selectFsUserListVOByComponent(fsUser);
         List<FsUserVO> list = fsUserService.selectFsUserListVOByComponent(fsUser);
         for (FsUserVO fsUserVO : list) {
         for (FsUserVO fsUserVO : list) {
             fsUserVO.setPhone(decryptAutoPhoneMk(fsUserVO.getPhone()));
             fsUserVO.setPhone(decryptAutoPhoneMk(fsUserVO.getPhone()));

+ 2 - 1
fs-company/src/main/resources/application.yml

@@ -3,7 +3,8 @@ server:
 # Spring配置
 # Spring配置
 spring:
 spring:
   profiles:
   profiles:
-    active: druid-fcky-test
+#    active: druid-fcky-test
+    active: dev
 #    active: druid-jzzx
 #    active: druid-jzzx
 #    active: druid-hdt
 #    active: druid-hdt
 #    active: druid-sxjz
 #    active: druid-sxjz

+ 34 - 0
fs-ipad-task/src/main/java/com/fs/app/service/CustomThreadPoolConfig.java

@@ -0,0 +1,34 @@
+package com.fs.app.service;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author MixLiu
+ * @date 2025/7/11 上午11:04)
+ */
+@Configuration
+public class CustomThreadPoolConfig {
+    @Bean(name = "customThreadPool", destroyMethod = "shutdown")
+    public ThreadPoolTaskExecutor customThreadPool() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        // 核心线程数
+        executor.setCorePoolSize(300);
+        // 最大线程数
+        executor.setMaxPoolSize(300);
+        // 线程名前缀
+        executor.setThreadNamePrefix("custom-pool-");
+        // 拒绝策略:直接丢弃新任务
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
+        // 非核心线程空闲存活时间(秒)
+        executor.setKeepAliveSeconds(60);
+        // 等待所有任务完成后关闭线程池
+        executor.setWaitForTasksToCompleteOnShutdown(true);
+        // 初始化
+        executor.initialize();
+        return executor;
+    }
+}

+ 7 - 3
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -141,10 +141,10 @@ public class IpadSendServer {
         }
         }
     }
     }
 
 
-    public boolean isSend(QwUser qwUser) {
+    public boolean isSend(QwUser qwUser, BaseVo parentVo) {
         // 判断企微发送方式是否是ipad
         // 判断企微发送方式是否是ipad
         if (qwUser.getSendMsgType() == 0) {
         if (qwUser.getSendMsgType() == 0) {
-            log.debug("企微用户:ID:{} 名称:{} 发送方式:{}", qwUser.getId(), qwUser.getQwUserName(), qwUser.getSendMsgType().toString());
+            log.debug("发送方式是侧边栏企微用户:ID:{} 名称:{}", qwUser.getId(), qwUser.getQwUserName());
             return false;
             return false;
         }
         }
         // 判断是否信息准确
         // 判断是否信息准确
@@ -188,6 +188,7 @@ public class IpadSendServer {
                 qwUserMapper.updateById(updateQwUser);
                 qwUserMapper.updateById(updateQwUser);
                 return false;
                 return false;
             }
             }
+            parentVo.setCorpId(login.getUser_info().getObject().getCorp_id());
             log.debug("QwUserID:{}, AI主机信息:{}", qwUser.getId(), login);
             log.debug("QwUserID:{}, AI主机信息:{}", qwUser.getId(), login);
         } catch (Exception e) {
         } catch (Exception e) {
             updateQwUser.setId(qwUser.getId());
             updateQwUser.setId(qwUser.getId());
@@ -196,6 +197,7 @@ public class IpadSendServer {
             qwUserMapper.updateById(updateQwUser);
             qwUserMapper.updateById(updateQwUser);
             return false;
             return false;
         }
         }
+
         return true;
         return true;
     }
     }
 
 
@@ -277,13 +279,15 @@ public class IpadSendServer {
         return true;
         return true;
     }
     }
 
 
-    public void send(QwSopCourseFinishTempSetting.Setting content, QwUser qwUser, QwSopLogs qwSopLogs, Map<String, CourseMaConfig> miniMap) {
+    public void send(QwSopCourseFinishTempSetting.Setting content, QwUser qwUser, QwSopLogs qwSopLogs, Map<String, CourseMaConfig> miniMap, BaseVo parentVo) {
         BaseVo vo = new BaseVo();
         BaseVo vo = new BaseVo();
         vo.setId(Long.parseLong(qwSopLogs.getId()));
         vo.setId(Long.parseLong(qwSopLogs.getId()));
         vo.setRoom(qwSopLogs.getSendType() == 12);
         vo.setRoom(qwSopLogs.getSendType() == 12);
         vo.setUuid(qwUser.getUid());
         vo.setUuid(qwUser.getUid());
         vo.setExId(qwSopLogs.getExternalUserId());
         vo.setExId(qwSopLogs.getExternalUserId());
         vo.setServerId(qwUser.getServerId());
         vo.setServerId(qwUser.getServerId());
+        vo.setCorpCode(parentVo.getCorpCode());
+        vo.setCorpId(parentVo.getCorpId());
         try {
         try {
             content.setSendStatus(1);
             content.setSendStatus(1);
             switch (content.getContentType()) {
             switch (content.getContentType()) {

+ 45 - 44
fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java

@@ -8,6 +8,7 @@ import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.PubFun;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseMaConfig;
 import com.fs.course.config.CourseMaConfig;
+import com.fs.ipad.vo.BaseVo;
 import com.fs.qw.domain.QwIpadServer;
 import com.fs.qw.domain.QwIpadServer;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwIpadServerMapper;
 import com.fs.qw.mapper.QwIpadServerMapper;
@@ -20,18 +21,21 @@ import com.fs.sop.service.IQwSopLogsService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.mapper.SysConfigMapper;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
 import org.springframework.util.StringUtils;
 
 
 import java.text.SimpleDateFormat;
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 
 
 @Component
 @Component
 @Slf4j
 @Slf4j
@@ -43,30 +47,32 @@ public class SendMsg {
     private final SysConfigMapper sysConfigMapper;
     private final SysConfigMapper sysConfigMapper;
     private final IQwSopLogsService qwSopLogsService;
     private final IQwSopLogsService qwSopLogsService;
     private final AsyncSopTestService asyncSopTestService;
     private final AsyncSopTestService asyncSopTestService;
-    private final RedisCacheT<Long> redisCache;
     private final QwIpadServerMapper qwIpadServerMapper;
     private final QwIpadServerMapper qwIpadServerMapper;
+    private final RedisCacheT<Long> redisCache;
 
 
     @Value("${group-no}")
     @Value("${group-no}")
     private String groupNo;
     private String groupNo;
     private final List<QwUser> qwUserList = Collections.synchronizedList(new ArrayList<>());
     private final List<QwUser> qwUserList = Collections.synchronizedList(new ArrayList<>());
     private final Map<Long, Long> qwMap = new ConcurrentHashMap<>();
     private final Map<Long, Long> qwMap = new ConcurrentHashMap<>();
 
 
+    @Autowired
+    @Qualifier("customThreadPool")
+    private ThreadPoolTaskExecutor customThreadPool;
 
 
-    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, AsyncSopTestService asyncSopTestService, RedisCacheT<Long> redisCache, QwIpadServerMapper qwIpadServerMapper) {
+    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, AsyncSopTestService asyncSopTestService, QwIpadServerMapper qwIpadServerMapper, RedisCacheT<Long> redisCache) {
         this.qwUserMapper = qwUserMapper;
         this.qwUserMapper = qwUserMapper;
         this.qwSopLogsMapper = qwSopLogsMapper;
         this.qwSopLogsMapper = qwSopLogsMapper;
         this.sendServer = sendServer;
         this.sendServer = sendServer;
         this.sysConfigMapper = sysConfigMapper;
         this.sysConfigMapper = sysConfigMapper;
         this.qwSopLogsService = qwSopLogsService;
         this.qwSopLogsService = qwSopLogsService;
         this.asyncSopTestService = asyncSopTestService;
         this.asyncSopTestService = asyncSopTestService;
-        this.redisCache = redisCache;
         this.qwIpadServerMapper = qwIpadServerMapper;
         this.qwIpadServerMapper = qwIpadServerMapper;
+        this.redisCache = redisCache;
     }
     }
     private List<QwUser> getQwUserList() {
     private List<QwUser> getQwUserList() {
         if (qwUserList.isEmpty()) {
         if (qwUserList.isEmpty()) {
-//            List<QwUser> qwUsers = qwUserMapper.selectList(new QueryWrapper<QwUser>().eq("send_msg_type", 1).eq("server_status", 1).eq("ipad_status", 1).isNotNull("server_id").eq("corp_id", corpId));
             List<QwIpadServer> serverList = qwIpadServerMapper.selectList(new QueryWrapper<QwIpadServer>().eq("group_no", groupNo));
             List<QwIpadServer> serverList = qwIpadServerMapper.selectList(new QueryWrapper<QwIpadServer>().eq("group_no", groupNo));
-            if(serverList.isEmpty()){
+            if (serverList.isEmpty()) {
                 return new ArrayList<>();
                 return new ArrayList<>();
             }
             }
             List<Long> serverIds = PubFun.listToNewList(serverList, QwIpadServer::getId);
             List<Long> serverIds = PubFun.listToNewList(serverList, QwIpadServer::getId);
@@ -83,12 +89,11 @@ public class SendMsg {
     }
     }
 
 
 
 
-    @Scheduled(fixedRate = 50000) // 每10秒执行一次
+    @Scheduled(fixedRate = 50000) // 每50秒执行一次
     public void refulsQwUserList() {
     public void refulsQwUserList() {
         qwUserList.clear();
         qwUserList.clear();
     }
     }
-
-    @Scheduled(fixedRate = 20000) // 每10秒执行一次
+    @Scheduled(fixedDelay = 20000) // 每20秒执行一次
     public void sendMsg2() {
     public void sendMsg2() {
         log.info("执行日志:{}", LocalDateTime.now());
         log.info("执行日志:{}", LocalDateTime.now());
         if (StringUtils.isEmpty(groupNo)) {
         if (StringUtils.isEmpty(groupNo)) {
@@ -109,45 +114,41 @@ public class SendMsg {
             delayEnd = config.getDelayEnd();
             delayEnd = config.getDelayEnd();
         }
         }
         Map<String, CourseMaConfig> miniMap = getMiniMap();
         Map<String, CourseMaConfig> miniMap = getMiniMap();
-
-        List<QwUser> qwUsers = getQwUserList().stream().parallel().filter(e -> !qwMap.containsKey(e.getId())).collect(Collectors.toList());
-        qwUsers.parallelStream().forEach(e -> {
-            if (qwMap.putIfAbsent(e.getId(), System.currentTimeMillis()) == null) {
-                // 判断企微是否发送消息,是否为ipad发送并且判断是否真实在线
-                new Thread(() -> {
+        getQwUserList().forEach(e -> {
+            qwMap.computeIfAbsent(e.getId(), k -> {
+                CompletableFuture.runAsync(() -> {
                     try {
                     try {
+                        log.info("开始任务:{}", e.getQwUserName());
                         processUser(e, delayStart, delayEnd, miniMap);
                         processUser(e, delayStart, delayEnd, miniMap);
-                    } catch (Exception exception){
+                    } catch (Exception exception) {
                         log.error("发送错误:", exception);
                         log.error("发送错误:", exception);
+                    } finally {
+                        log.info("删除任务:{}", e.getQwUserName());
+                        qwMap.remove(e.getId());
+//                        removeQwMap.putIfAbsent(e.getId(), System.currentTimeMillis());
                     }
                     }
-                    log.info("销售删除线程:{}", e.getQwUserName());
-                    qwMap.remove(e.getId());
-                }).start();
-            }
+                }, customThreadPool);
+                return System.currentTimeMillis(); // 占位值
+            });
         });
         });
     }
     }
 
 
     private void processUser(QwUser qwUser, int delayStart, int delayEnd, Map<String, CourseMaConfig> miniMap) {
     private void processUser(QwUser qwUser, int delayStart, int delayEnd, Map<String, CourseMaConfig> miniMap) {
-        if (!qwMap.containsKey(qwUser.getId())) {
-            log.warn("用户:{}已在处理中,跳过重复执行", qwUser.getQwUserName());
-            return;
-        }
-        qwMap.put(qwUser.getId(), System.currentTimeMillis());
         long start1 = System.currentTimeMillis();
         long start1 = System.currentTimeMillis();
         List<QwSopLogs> qwSopLogList = qwSopLogsMapper.selectByQwUserId(qwUser.getId());
         List<QwSopLogs> qwSopLogList = qwSopLogsMapper.selectByQwUserId(qwUser.getId());
-        if(qwSopLogList.isEmpty()){
+        if (qwSopLogList.isEmpty()) {
             return;
             return;
         }
         }
         QwUser user = qwUserMapper.selectById(qwUser.getId());
         QwUser user = qwUserMapper.selectById(qwUser.getId());
+        BaseVo parentVo = new BaseVo();
+        parentVo.setCorpCode(qwUser.getCorpId());
         long end1 = System.currentTimeMillis();
         long end1 = System.currentTimeMillis();
-        if (!sendServer.isSend(user)) {
-            qwMap.remove(user.getId());
+        if (!sendServer.isSend(user, parentVo)) {
             return;
             return;
         }
         }
         log.info("销售:{}, 消息:{}, 耗时: {}, 时间:{}", user.getQwUserName(), qwSopLogList.size(), end1 - start1, qwMap.get(qwUser.getId()));
         log.info("销售:{}, 消息:{}, 耗时: {}, 时间:{}", user.getQwUserName(), qwSopLogList.size(), end1 - start1, qwMap.get(qwUser.getId()));
         long start3 = System.currentTimeMillis();
         long start3 = System.currentTimeMillis();
         for (QwSopLogs qwSopLogs : qwSopLogList) {
         for (QwSopLogs qwSopLogs : qwSopLogList) {
-
             long start2 = System.currentTimeMillis();
             long start2 = System.currentTimeMillis();
             QwSopCourseFinishTempSetting setting = JSON.parseObject(qwSopLogs.getContentJson(), QwSopCourseFinishTempSetting.class);
             QwSopCourseFinishTempSetting setting = JSON.parseObject(qwSopLogs.getContentJson(), QwSopCourseFinishTempSetting.class);
             // 判断消息状态是否满足发送条件
             // 判断消息状态是否满足发送条件
@@ -155,8 +156,19 @@ public class SendMsg {
                 log.info("销售:{}, 消息发送条件未满足:{}", user.getQwUserName(), qwSopLogs.getId());
                 log.info("销售:{}, 消息发送条件未满足:{}", user.getQwUserName(), qwSopLogs.getId());
                 continue;
                 continue;
             }
             }
+            log.info("进入发送消息状态:{}", qwSopLogs.getId());
+            String key = "qw:logs:pad:send:id:" + qwSopLogs.getId();
+            Long time = redisCache.getCacheObject(key);
+            if (redisCache.getCacheObject(key) != null) {
+                log.error("{}已有发送:{}, :{}", qwUser.getQwUserName(), qwSopLogs.getId(), time);
+                return;
+            }
+            redisCache.setCacheObject(key, System.currentTimeMillis(), 10, TimeUnit.MINUTES);
             for (QwSopCourseFinishTempSetting.Setting content : setting.getSetting()) {
             for (QwSopCourseFinishTempSetting.Setting content : setting.getSetting()) {
-                sendServer.send(content, user, qwSopLogs, miniMap);
+                long start4 = System.currentTimeMillis();
+                sendServer.send(content, user, qwSopLogs, miniMap, parentVo);
+                long end4 = System.currentTimeMillis();
+                log.info("请求pad发送完成:{}, {}, 时长4:{}", user.getQwUserName(), qwSopLogs.getId(), end4 - start4);
                 if(content.getSendStatus() == 2 && "请求失败:消息发送过于频繁,请稍后再试".equals(content.getSendRemarks())){
                 if(content.getSendStatus() == 2 && "请求失败:消息发送过于频繁,请稍后再试".equals(content.getSendRemarks())){
                     QwUser update = new QwUser();
                     QwUser update = new QwUser();
                     update.setRemark("请求频率异常,暂停发送,三小时后恢复继续发送");
                     update.setRemark("请求频率异常,暂停发送,三小时后恢复继续发送");
@@ -167,22 +179,12 @@ public class SendMsg {
                 }
                 }
                 try {
                 try {
                     int delay = ThreadLocalRandom.current().nextInt(300, 1000);
                     int delay = ThreadLocalRandom.current().nextInt(300, 1000);
-                    log.debug("等待:{}ms", delay);
+                    log.debug("pad发送消息等待:{}ms", delay);
                     Thread.sleep(delay);
                     Thread.sleep(delay);
                 } catch (InterruptedException e) {
                 } catch (InterruptedException e) {
                     log.error("线程等待错误!");
                     log.error("线程等待错误!");
                 }
                 }
             }
             }
-//            if (!setting.getSetting().isEmpty()) {
-//                new Thread(() -> {
-//                    try {
-//                        List<QwSopTempSetting.Content.Setting> settings = JSON.parseArray(JSON.toJSONString(setting.getSetting()), QwSopTempSetting.Content.Setting.class).stream().filter(e -> "9".equals(e.getContentType())).collect(Collectors.toList());
-//                        asyncSopTestService.asyncSendMsgBySopAppLinkNormalIM(settings, qwSopLogs.getCorpId(), user.getCompanyUserId(), qwSopLogs.getFsUserId());
-//                    } catch (Exception e) {
-//                        log.error("推送APP失败", e);
-//                    }
-//                }).start();
-//            }
             qwSopLogs.setSend(true);
             qwSopLogs.setSend(true);
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             QwSopLogs updateQwSop = new QwSopLogs();
             QwSopLogs updateQwSop = new QwSopLogs();
@@ -204,13 +206,12 @@ public class SendMsg {
                 updateQwSop.setRealSendTime(sdf.format(new Date()));
                 updateQwSop.setRealSendTime(sdf.format(new Date()));
             }
             }
             updateQwSop.setContentJson(JSON.toJSONString(setting));
             updateQwSop.setContentJson(JSON.toJSONString(setting));
-
             long end2 = System.currentTimeMillis();
             long end2 = System.currentTimeMillis();
             int i = qwSopLogsService.updateQwSopLogsSendType(updateQwSop);
             int i = qwSopLogsService.updateQwSopLogsSendType(updateQwSop);
-            log.info("销售:{}, 修改条数{}, 发送方消息完成:{}, 耗时: {}", user.getQwUserName(), i, qwSopLogs.getId(),end2 - start2);
+            log.info("销售:{}, 修改条数{}, 发送方消息完成:{}, 耗时: {}", user.getQwUserName(), i, qwSopLogs.getId(), end2 - start2);
             try {
             try {
                 int delay = ThreadLocalRandom.current().nextInt(delayStart, delayEnd);
                 int delay = ThreadLocalRandom.current().nextInt(delayStart, delayEnd);
-                log.debug("等待:{}ms", delay);
+                log.debug("企微发送消息等待:{}ms", delay);
                 Thread.sleep(delay);
                 Thread.sleep(delay);
             } catch (InterruptedException e) {
             } catch (InterruptedException e) {
                 log.error("线程等待错误!");
                 log.error("线程等待错误!");

+ 1 - 0
fs-ipad-task/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -66,6 +66,7 @@ public class DataSourceConfig {
 
 
         targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
         targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
+        targetDataSources.put(DataSourceType.SopREAD.name(), sopReadDataSource);
         targetDataSources.put(DataSourceType.CLICKHOUSE.name(), clickhouseDataSource); // Ensure matching key
         targetDataSources.put(DataSourceType.CLICKHOUSE.name(), clickhouseDataSource); // Ensure matching key
         return new DynamicDataSource(masterDataSource, targetDataSources);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }
     }

+ 18 - 0
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -12,6 +12,8 @@ import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsUserVideoService;
 import com.fs.course.service.IFsUserVideoService;
 import com.fs.course.service.IHuaweiObsService;
 import com.fs.course.service.IHuaweiObsService;
+import com.fs.his.service.IFsInquiryOrderService;
+import com.fs.his.service.IFsPackageOrderService;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.qwApi.service.QwApiService;
@@ -19,6 +21,7 @@ import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.QwSopMapper;
 import com.fs.sop.mapper.QwSopMapper;
 import com.fs.sop.mapper.SopUserLogsMapper;
 import com.fs.sop.mapper.SopUserLogsMapper;
 import com.fs.sop.service.*;
 import com.fs.sop.service.*;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.fs.sop.vo.QwSopLogsDoSendListTVO;
 import com.fs.sop.vo.QwSopLogsDoSendListTVO;
 import com.fs.store.service.IFsUserCourseCountService;
 import com.fs.store.service.IFsUserCourseCountService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
@@ -33,6 +36,7 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.List;
 import java.util.List;
 
 
 @Api("公共接口")
 @Api("公共接口")
@@ -92,6 +96,12 @@ public class CommonController {
     @Autowired
     @Autowired
     private ISopUserLogsInfoService iSopUserLogsInfoService;
     private ISopUserLogsInfoService iSopUserLogsInfoService;
 
 
+    @Autowired
+    private IFsInquiryOrderService inquiryOrderService;
+
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
 
 
     /**
     /**
     * 发官方通连
     * 发官方通连
@@ -129,6 +139,14 @@ public class CommonController {
         return R.ok();
         return R.ok();
     }
     }
 
 
+    @GetMapping("/testSop")
+    public R testSop() throws Exception {
+
+        byte[] bytes = inquiryOrderService.getWxaCodeInquiryOrderUnLimit(2582616L);
+        String base64 = Base64.getEncoder().encodeToString(bytes);
+        return R.ok().put("data",base64);
+    }
+
     @GetMapping("/testRatingSop")
     @GetMapping("/testRatingSop")
     public R testRatingSop(String sopId) throws Exception {
     public R testRatingSop(String sopId) throws Exception {
 
 

+ 13 - 0
fs-qw-task/src/main/java/com/fs/app/task/qwTask.java

@@ -326,4 +326,17 @@ public class qwTask {
         long endTimeMillis = System.currentTimeMillis();
         long endTimeMillis = System.currentTimeMillis();
         log.info("====== sop营期-用户分级处理完成,耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
         log.info("====== sop营期-用户分级处理完成,耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
     }
     }
+
+    /**
+     * 更新掉所有前一天的所有待发送
+     */
+    @Scheduled(cron = "0 3 0 * * ?")
+    public void updateQwSopLogsDayBefore() {
+        long startTimeMillis = System.currentTimeMillis();
+        log.info("====== 更新掉所有前一天的所有待发送 ======");
+        qwSopLogsMapper.updateQwSopLogsByDayBefore();
+
+        long endTimeMillis = System.currentTimeMillis();
+        log.info("====== 更新掉所有前一天的所有待发送,耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
+    }
 }
 }

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

@@ -635,7 +635,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
                         insertSopUserLogs(sopUserLogsInfos, logVo, sendTime, ruleTimeVO, content, qwUserId,
                         insertSopUserLogs(sopUserLogsInfos, logVo, sendTime, ruleTimeVO, content, qwUserId,
                                 companyUserId, companyId, qwUserByRedis.getWelcomeText(),qwUserByRedis.getQwUserName(),
                                 companyUserId, companyId, qwUserByRedis.getWelcomeText(),qwUserByRedis.getQwUserName(),
-                                groupChatMap, miniAppId);
+                                groupChatMap, miniAppId,config);
 
 
                     }
                     }
                 } catch (Exception e) {
                 } catch (Exception e) {
@@ -678,7 +678,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private void insertSopUserLogs(List<SopUserLogsInfo> sopUserLogsInfos, SopUserLogsVo logVo, Date sendTime,
     private void insertSopUserLogs(List<SopUserLogsInfo> sopUserLogsInfos, SopUserLogsVo logVo, Date sendTime,
                                    QwSopRuleTimeVO ruleTimeVO, QwSopTempSetting.Content content,
                                    QwSopRuleTimeVO ruleTimeVO, QwSopTempSetting.Content content,
                                    String qwUserId,String companyUserId,String companyId,String welcomeText,String qwUserName,
                                    String qwUserId,String companyUserId,String companyId,String welcomeText,String qwUserName,
-                                   Map<String, QwGroupChat> groupChatMap,String miniAppId) {
+                                   Map<String, QwGroupChat> groupChatMap,String miniAppId,CourseConfig config) {
         String formattedSendTime = sendTime.toInstant()
         String formattedSendTime = sendTime.toInstant()
                 .atZone(ZoneId.systemDefault())
                 .atZone(ZoneId.systemDefault())
                 .format(DATE_TIME_FORMATTER);
                 .format(DATE_TIME_FORMATTER);
@@ -704,7 +704,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             if (content.getIndex() == 0) {
             if (content.getIndex() == 0) {
                 QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null);
                 QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null);
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
-                        type, qwUserId, companyUserId, companyId, groupChat.getChatId(), welcomeText, qwUserName, null, true, miniAppId, groupChat);
+                        type, qwUserId, companyUserId, companyId, groupChat.getChatId(), welcomeText, qwUserName,
+                        null, true, miniAppId, groupChat,config);
             } else {
             } else {
                 if(groupChat.getChatUserList() != null && !groupChat.getChatUserList().isEmpty()){
                 if(groupChat.getChatUserList() != null && !groupChat.getChatUserList().isEmpty()){
                     groupChat.getChatUserList().forEach(user -> {
                     groupChat.getChatUserList().forEach(user -> {
@@ -712,7 +713,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                         ruleTimeVO.setRemark("客户群催课");
                         ruleTimeVO.setRemark("客户群催课");
                         QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, user.getUserId(), user.getName(), null, isOfficial, null);
                         QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, user.getUserId(), user.getName(), null, isOfficial, null);
                         handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                         handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
-                                type, qwUserId, companyUserId, companyId, user.getId().toString(), welcomeText, qwUserName, null, false, miniAppId, groupChat);
+                                type, qwUserId, companyUserId, companyId, user.getId().toString(), welcomeText, qwUserName,
+                                null, false, miniAppId, groupChat,config);
                     });
                     });
                 }
                 }
             }
             }
@@ -725,7 +727,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     Long fsUserId = contactId.getFsUserId();
                     Long fsUserId = contactId.getFsUserId();
                     QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId, isOfficial, contactId.getExternalId());
                     QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId, isOfficial, contactId.getExternalId());
                     handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                     handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
-                            type, qwUserId, companyUserId, companyId, externalId, welcomeText, qwUserName, fsUserId, false, miniAppId, null);
+                            type, qwUserId, companyUserId, companyId, externalId, welcomeText, qwUserName, fsUserId, false, miniAppId, null,config);
                 } catch (Exception e) {
                 } catch (Exception e) {
                     log.error("处理 externalContactId {} 时发生异常: {}", contactId, e.getMessage(), e);
                     log.error("处理 externalContactId {} 时发生异常: {}", contactId, e.getMessage(), e);
                 }
                 }
@@ -775,14 +777,6 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         sopLogs.setCorpId(logVo.getCorpId());
         sopLogs.setCorpId(logVo.getCorpId());
         sopLogs.setLogType(ruleTimeVO.getType());
         sopLogs.setLogType(ruleTimeVO.getType());
         sopLogs.setTakeRecords(0);
         sopLogs.setTakeRecords(0);
-        try {
-            if(StringUtils.isNotEmpty(logVo.getUserId())){
-                String[] split = logVo.getUserId().split("\\|");
-                sopLogs.setQwUserKey(Long.parseLong(split[0]));
-            }
-        }catch (Exception e){
-            log.error("设置qwUserId异常", e);
-        }
 
 
         if (isOfficial == 1) {
         if (isOfficial == 1) {
 
 
@@ -817,7 +811,14 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         sopLogs.setReceivingStatus(0L);
         sopLogs.setReceivingStatus(0L);
 
 
         String[] userKey = logVo.getUserId().split("\\|");
         String[] userKey = logVo.getUserId().split("\\|");
+        log.info("sopLogVo:{}", JSON.toJSONString(logVo));
+        log.info("sop_logs -》 userId:{}", logVo.getUserId());
+        log.info("sop_logs -》 userId -》 split:{}", Arrays.asList(userKey));
         sopLogs.setCompanyId(Long.valueOf(userKey[2].trim()));
         sopLogs.setCompanyId(Long.valueOf(userKey[2].trim()));
+        if (StringUtils.isNotEmpty(userKey[0].trim())){
+            sopLogs.setQwUserKey(Long.valueOf(userKey[0].trim()));
+            log.info("qw_sop数据:{}", JSON.toJSONString(sopLogs));
+        }
         sopLogs.setSopId(logVo.getSopId());
         sopLogs.setSopId(logVo.getSopId());
         sopLogs.setSort(Integer.valueOf(logVo.getStartTime().replaceAll("-","")));
         sopLogs.setSort(Integer.valueOf(logVo.getStartTime().replaceAll("-","")));
         sopLogs.setExternalUserId(externalContactId);
         sopLogs.setExternalUserId(externalContactId);
@@ -833,14 +834,16 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                                       SopUserLogsVo logVo, Date sendTime, Long courseId,
                                       SopUserLogsVo logVo, Date sendTime, Long courseId,
                                       Long videoId, int type, String qwUserId,
                                       Long videoId, int type, String qwUserId,
                                       String companyUserId, String companyId, String externalId, String welcomeText,
                                       String companyUserId, String companyId, String externalId, String welcomeText,
-                                      String qwUserName, Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat) {
+                                      String qwUserName, Long fsUserId, boolean isGroupChat, String miniAppId,
+                                      QwGroupChat groupChat,CourseConfig config) {
         switch (type) {
         switch (type) {
             case 1:
             case 1:
                 handleNormalMessage(sopLogs, content,companyUserId);
                 handleNormalMessage(sopLogs, content,companyUserId);
                 break;
                 break;
             case 2:
             case 2:
                 handleCourseMessage(sopLogs, content, logVo, sendTime, courseId, videoId,
                 handleCourseMessage(sopLogs, content, logVo, sendTime, courseId, videoId,
-                        qwUserId, companyUserId, companyId, externalId, welcomeText,qwUserName, fsUserId, isGroupChat, miniAppId, groupChat);
+                        qwUserId, companyUserId, companyId, externalId, welcomeText,qwUserName, fsUserId,
+                        isGroupChat, miniAppId, groupChat,config);
                 break;
                 break;
             case 3:
             case 3:
                 handleOrderMessage(sopLogs, content);
                 handleOrderMessage(sopLogs, content);
@@ -873,7 +876,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                                      SopUserLogsVo logVo, Date sendTime, Long courseId,
                                      SopUserLogsVo logVo, Date sendTime, Long courseId,
                                      Long videoId, String qwUserId, String companyUserId,
                                      Long videoId, String qwUserId, String companyUserId,
                                      String companyId, String externalId, String welcomeText, String qwUserName,
                                      String companyId, String externalId, String welcomeText, String qwUserName,
-                                     Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat) {
+                                     Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat,CourseConfig config) {
         // 深拷贝 Content 对象,避免使用 JSON
         // 深拷贝 Content 对象,避免使用 JSON
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         if (clonedContent == null) {
         if (clonedContent == null) {
@@ -974,7 +977,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     setting.setMiniprogramPage(sortLink.replaceAll("^[\\s\\u2005]+", ""));
                     setting.setMiniprogramPage(sortLink.replaceAll("^[\\s\\u2005]+", ""));
 
 
                     try {
                     try {
-                        setting.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(setting.getMiniprogramPicUrl())?"https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png":setting.getMiniprogramPicUrl());
+                        setting.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(setting.getMiniprogramPicUrl())? config.getSidebarImageUrl():setting.getMiniprogramPicUrl());
                     } catch (Exception e) {
                     } catch (Exception e) {
                         log.error("赋值-小程序封面地址失败-" + e);
                         log.error("赋值-小程序封面地址失败-" + e);
                     }
                     }
@@ -1241,6 +1244,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             log.error("CourseConfig is not loaded.");
             log.error("CourseConfig is not loaded.");
             return "";
             return "";
         }
         }
+
+
 //        if (StringUtils.isEmpty(config.getMiniprogramPage())){
 //        if (StringUtils.isEmpty(config.getMiniprogramPage())){
 //            log.error("miniprogramPage is not loaded.");
 //            log.error("miniprogramPage is not loaded.");
 //            return "";
 //            return "";
@@ -1848,11 +1853,9 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         sopLogs.setExternalUserName(externalContact.getName());
         sopLogs.setExternalUserName(externalContact.getName());
         sopLogs.setFsUserId(finishLog.getUserId() != null ? finishLog.getUserId() : null );
         sopLogs.setFsUserId(finishLog.getUserId() != null ? finishLog.getUserId() : null );
         sopLogs.setUserLogsId("-");
         sopLogs.setUserLogsId("-");
-        try {
-            sopLogs.setQwUserKey(finishLog.getQwUserId());
-        }catch (Exception e){
-            log.error("设置qwUserId异常", e);
-        }
+
+        sopLogs.setQwUserKey(finishLog.getQwUserId() != null ? finishLog.getQwUserId() : null);
+
         // 解析模板设置
         // 解析模板设置
         List<QwSopCourseFinishTempSetting.Setting> settings = parseSettings(finishTemp.getSetting());
         List<QwSopCourseFinishTempSetting.Setting> settings = parseSettings(finishTemp.getSetting());
         if (settings == null) {
         if (settings == null) {

+ 18 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwUserController.java

@@ -7,10 +7,13 @@ import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.param.ExternalContactDetailsParam;
 import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.service.IQwExternalContactInfoService;
 import com.fs.qw.service.IQwExternalContactInfoService;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.vo.ExternalContactDetailsVO;
 import com.fs.qw.vo.ExternalContactDetailsVO;
 import com.fs.qw.vo.QwExternalListByHeavyVO;
 import com.fs.qw.vo.QwExternalListByHeavyVO;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
@@ -36,6 +39,9 @@ public class ApisQwUserController extends BaseController {
     @Autowired
     @Autowired
     private IQwExternalContactInfoService qwExternalContactInfoService;
     private IQwExternalContactInfoService qwExternalContactInfoService;
 
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
     @GetMapping("/details")
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -98,4 +104,16 @@ public class ApisQwUserController extends BaseController {
         PageInfo<QwExternalListByHeavyVO> result = new PageInfo<>(qwExternalListByHeavy);
         PageInfo<QwExternalListByHeavyVO> result = new PageInfo<>(qwExternalListByHeavy);
         return R.ok().put("data", result);
         return R.ok().put("data", result);
     }
     }
+
+    @PostMapping("/extCourseSopWatchLog")
+    @ApiOperation("获取外部联系人按照 营期天数 获取到的今天该看的课")
+    public R getExtCourseSopWatchLog(@RequestBody QwExtCourseSopWatchLog param) {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExtCourseSopWatchLogVO> list = iSopUserLogsInfoService.getExtCourseSopWatchLog(param);
+        PageInfo<ExtCourseSopWatchLogVO> result = new PageInfo<>(list);
+
+        return R.ok().put("data", result);
+    }
+
 }
 }

+ 18 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/QwUserController.java

@@ -7,6 +7,7 @@ import com.fs.common.exception.CustomException;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.param.ExternalContactDetailsParam;
 import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
@@ -17,6 +18,8 @@ import com.fs.qw.vo.ExternalContactDetailsVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
@@ -45,6 +48,9 @@ public class QwUserController extends BaseController {
     @Autowired
     @Autowired
     private IQwTagGroupService qwTagGroupService;
     private IQwTagGroupService qwTagGroupService;
 
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
     @GetMapping("/details")
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -81,6 +87,18 @@ public class QwUserController extends BaseController {
         return R.ok();
         return R.ok();
     }
     }
 
 
+    @PostMapping("/extCourseSopWatchLog")
+    @ApiOperation("获取外部联系人按照 营期天数 获取到的今天该看的课")
+    public R getExtCourseSopWatchLog(@RequestBody QwExtCourseSopWatchLog param) {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExtCourseSopWatchLogVO> list = iSopUserLogsInfoService.getExtCourseSopWatchLog(param);
+        PageInfo<ExtCourseSopWatchLogVO> result = new PageInfo<>(list);
+
+        return R.ok().put("data", result);
+    }
+
+
     @GetMapping("/externalContact")
     @GetMapping("/externalContact")
     @ApiOperation("获取侧边栏外部联系人信息")
     @ApiOperation("获取侧边栏外部联系人信息")
     public R getExternalContactInfo(@RequestParam(value = "qwExternalContactId") Long qwExternalContactId) {
     public R getExternalContactInfo(@RequestParam(value = "qwExternalContactId") Long qwExternalContactId) {

+ 1 - 1
fs-qwhook-sop/src/main/resources/application.yml

@@ -10,4 +10,4 @@ spring:
 #    active: druid-yzt
 #    active: druid-yzt
 #    active: druid-hdt
 #    active: druid-hdt
 #    active: druid-sxjz
 #    active: druid-sxjz
-    active: druid-sft
+    active: druid-myhk-test

+ 20 - 0
fs-qwhook/src/main/java/com/fs/app/controller/ApisQwUserController.java

@@ -3,12 +3,14 @@ package com.fs.app.controller;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.CustomException;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.param.ExternalContactDetailsParam;
 import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
@@ -21,6 +23,8 @@ import com.fs.qw.vo.QwExternalListByHeavyVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
@@ -49,6 +53,10 @@ public class ApisQwUserController extends BaseController {
     @Autowired
     @Autowired
     private IQwTagGroupService qwTagGroupService;
     private IQwTagGroupService qwTagGroupService;
 
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
+
     @GetMapping("/details")
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -112,6 +120,18 @@ public class ApisQwUserController extends BaseController {
         return R.ok().put("data", result);
         return R.ok().put("data", result);
     }
     }
 
 
+
+    @PostMapping("/extCourseSopWatchLog")
+    @ApiOperation("获取外部联系人按照 营期天数 获取到的今天该看的课")
+    public R getExtCourseSopWatchLog(@RequestBody QwExtCourseSopWatchLog param) {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExtCourseSopWatchLogVO> list = iSopUserLogsInfoService.getExtCourseSopWatchLog(param);
+        PageInfo<ExtCourseSopWatchLogVO> result = new PageInfo<>(list);
+
+        return R.ok().put("data", result);
+    }
+
     @GetMapping("/externalContact")
     @GetMapping("/externalContact")
     @ApiOperation("获取侧边栏外部联系人信息")
     @ApiOperation("获取侧边栏外部联系人信息")
     public R getExternalContactInfo(@RequestParam(value = "qwExternalContactId") Long qwExternalContactId) {
     public R getExternalContactInfo(@RequestParam(value = "qwExternalContactId") Long qwExternalContactId) {

+ 16 - 0
fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java

@@ -7,6 +7,7 @@ import com.fs.common.exception.CustomException;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.param.ExternalContactDetailsParam;
 import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
@@ -17,6 +18,8 @@ import com.fs.qw.vo.ExternalContactDetailsVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
@@ -45,6 +48,9 @@ public class QwUserController extends BaseController {
     @Autowired
     @Autowired
     private IQwTagGroupService qwTagGroupService;
     private IQwTagGroupService qwTagGroupService;
 
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
     @GetMapping("/details")
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -81,6 +87,16 @@ public class QwUserController extends BaseController {
         return R.ok();
         return R.ok();
     }
     }
 
 
+    @PostMapping("/extCourseSopWatchLog")
+    @ApiOperation("获取外部联系人按照 营期天数 获取到的今天该看的课")
+    public R getExtCourseSopWatchLog(@RequestBody QwExtCourseSopWatchLog param) {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExtCourseSopWatchLogVO> list = iSopUserLogsInfoService.getExtCourseSopWatchLog(param);
+        PageInfo<ExtCourseSopWatchLogVO> result = new PageInfo<>(list);
+
+        return R.ok().put("data", result);
+    }
 
 
     @GetMapping("/externalContact")
     @GetMapping("/externalContact")
     @ApiOperation("获取侧边栏外部联系人信息")
     @ApiOperation("获取侧边栏外部联系人信息")

+ 6 - 0
fs-service/src/main/java/com/fs/common/param/LoginMaWxParam.java

@@ -34,6 +34,10 @@ public class LoginMaWxParam implements Serializable {
     @ApiModelProperty(value = "用户头像")
     @ApiModelProperty(value = "用户头像")
     private String avatar;
     private String avatar;
 
 
+//    @NotNull(message = "项目id不能为空")
+    @ApiModelProperty(value = "课程归属项目id")
+    private Long projectId;
+
 //    @ApiModelProperty(value = "公司id,如果不是第一位销售,都需要传")
 //    @ApiModelProperty(value = "公司id,如果不是第一位销售,都需要传")
 //    private Long companyId;
 //    private Long companyId;
 
 
@@ -53,4 +57,6 @@ public class LoginMaWxParam implements Serializable {
     @ApiModelProperty(value = "小程序授权类型")
     @ApiModelProperty(value = "小程序授权类型")
     private Integer authType;
     private Integer authType;
 
 
+    private String appId;
+
 }
 }

+ 1 - 0
fs-service/src/main/java/com/fs/common/param/LoginParam.java

@@ -14,4 +14,5 @@ public class LoginParam implements Serializable {
     private String rawData;
     private String rawData;
     private String signature;
     private String signature;
     private String appId;
     private String appId;
+    private Integer authType;
 }
 }

+ 0 - 1
fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java

@@ -209,5 +209,4 @@ public interface ICompanyUserService {
     List<CompanyUser> getCompanyUserList(CompanyUser companyUser);
     List<CompanyUser> getCompanyUserList(CompanyUser companyUser);
 
 
     List<QwOptionsVO> selectQwUserListLikeName(Map<String, Object> params);
     List<QwOptionsVO> selectQwUserListLikeName(Map<String, Object> params);
-
 }
 }

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

@@ -510,7 +510,10 @@ public class CompanyServiceImpl implements ICompanyService
                 SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
                 SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
                 StoreConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), StoreConfig.class);
                 StoreConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), StoreConfig.class);
                 Integer DeductMoneyRate = fsPayConfig.getDeductMoneyRate();
                 Integer DeductMoneyRate = fsPayConfig.getDeductMoneyRate();
-                BigDecimal money = order.getPrescribePrice().multiply(new BigDecimal(DeductMoneyRate).multiply(new BigDecimal("0.01")));
+                BigDecimal money = BigDecimal.ZERO;
+                if (DeductMoneyRate != null && DeductMoneyRate > 0) {
+                    money = order.getPrescribePrice().multiply(new BigDecimal(DeductMoneyRate).multiply(new BigDecimal("0.01")));
+                }
                 logger.info("扣除成本:"+order.getOrderCode()+":"+money);
                 logger.info("扣除成本:"+order.getOrderCode()+":"+money);
                 company.setMoney(company.getMoney().subtract(money));
                 company.setMoney(company.getMoney().subtract(money));
                 companyMapper.updateCompany(company);
                 companyMapper.updateCompany(company);

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

@@ -416,7 +416,7 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         if (StringUtils.isNotNull(roles))
         if (StringUtils.isNotNull(roles))
         {
         {
             // 新增用户与角色管理
             // 新增用户与角色管理
-            List<CompanyUserRole> list = new ArrayList<CompanyUserRole>();
+            List<CompanyUserRole> list = new ArrayList<>();
             for (Long roleId : roles)
             for (Long roleId : roles)
             {
             {
                 CompanyUserRole ur = new CompanyUserRole();
                 CompanyUserRole ur = new CompanyUserRole();

+ 3 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java

@@ -121,4 +121,7 @@ public class CompanyUserQwListVO extends BaseEntity {
      * 发送延时时间
      * 发送延时时间
      */
      */
     private Long sendDelayTime;
     private Long sendDelayTime;
+
+    /** 是否需要单独注册会员,1-是,0-否*/
+    private Integer isNeedRegisterMember;
 }
 }

+ 4 - 1
fs-service/src/main/java/com/fs/config/ai/AiHostProper.java

@@ -9,5 +9,8 @@ import org.springframework.stereotype.Component;
 public class AiHostProper {
 public class AiHostProper {
     @Value("${ipad.ipadUrl}")
     @Value("${ipad.ipadUrl}")
     private String ipadUrl;
     private String ipadUrl;
-    
+
+    @Value("${ipad.aiApi}")
+    private String aiApi;
+
 }
 }

+ 1 - 0
fs-service/src/main/java/com/fs/course/config/CourseConfig.java

@@ -36,6 +36,7 @@ public class CourseConfig implements Serializable {
 
 
     private String companyUserQRCode;// 默认客服二维码图片
     private String companyUserQRCode;// 默认客服二维码图片
     private String courseLogo;//课程Logo
     private String courseLogo;//课程Logo
+    private String sidebarImageUrl;//侧边栏公共图
     private Integer delayStart;
     private Integer delayStart;
     private Integer delayEnd;
     private Integer delayEnd;
 
 

+ 17 - 2
fs-service/src/main/java/com/fs/course/domain/FsUserCourseComplaintRecord.java

@@ -1,12 +1,15 @@
 package com.fs.course.domain;
 package com.fs.course.domain;
 
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import com.fs.common.annotation.Excel;
 import io.swagger.annotations.ApiModelProperty;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.Data;
 import com.fs.common.core.domain.BaseEntity;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.EqualsAndHashCode;
 import lombok.EqualsAndHashCode;
 
 
+import java.util.Date;
+
 /**
 /**
  * 看课投诉记录对象 fs_user_course_complaint_record
  * 看课投诉记录对象 fs_user_course_complaint_record
  *
  *
@@ -25,9 +28,21 @@ public class FsUserCourseComplaintRecord extends BaseEntity{
     @TableField(exist = false)
     @TableField(exist = false)
     private Integer pageSize = 10;
     private Integer pageSize = 10;
 
 
-    @ApiModelProperty(value = "用户昵称")
+    //    @ApiModelProperty(value = "用户昵称")
+//    @TableField(exist = false)
+//    private String nickName;
+
+    @ApiModelProperty(value = "投诉类型")
+    @TableField(exist = false)
+    private String complaintTypeName;
+
+    @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date startCreateTime;
+
     @TableField(exist = false)
     @TableField(exist = false)
-    private String nickName;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date endCreateTime;
 
 
     /** 投诉记录id */
     /** 投诉记录id */
     private Long recordId;
     private Long recordId;

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

@@ -229,7 +229,10 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
     List<FsCourseUserStatisticsListVO> selectFsCourseUserStatisticsListVO(FsCourseUserStatisticsListParam param);
     List<FsCourseUserStatisticsListVO> selectFsCourseUserStatisticsListVO(FsCourseUserStatisticsListParam param);
 
 
     @Select({"<script> " +
     @Select({"<script> " +
-            "select MIN(o.create_time) createTime,ANY_VALUE(qu.qw_user_name) qwUserName ,ext.name externalUserName,ext.create_time userCreateTime from fs_course_watch_log o LEFT JOIN qw_user qu on qu.id=o.qw_user_id LEFT JOIN qw_external_contact ext ON ext.id =  o.qw_external_contact_id where log_type=2 and o.company_id=#{companyId} " +
+            "select MIN(o.create_time) createTime,ANY_VALUE(qu.qw_user_name) qwUserName ,ext.name externalUserName,ext.avatar," +
+            "   ext.create_time userCreateTime from fs_course_watch_log o " +
+            "LEFT JOIN qw_user qu on qu.id=o.qw_user_id " +
+            "LEFT JOIN qw_external_contact ext ON ext.id =  o.qw_external_contact_id where log_type=2 and o.company_id=#{companyId} " +
             "<if test= 'sTime != null '> " +
             "<if test= 'sTime != null '> " +
             "       and DATE(o.create_time) &gt;= DATE(#{sTime})\n" +
             "       and DATE(o.create_time) &gt;= DATE(#{sTime})\n" +
             "</if>\n" +
             "</if>\n" +

+ 8 - 4
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java

@@ -128,9 +128,6 @@ public interface FsUserCourseMapper
             "</script>"})
             "</script>"})
     List<FsUserCourseListUVO> selectFsUserCourseListUVO(@Param("maps") FsUserCourseListUParam param);
     List<FsUserCourseListUVO> selectFsUserCourseListUVO(@Param("maps") FsUserCourseListUParam param);
 
 
-    @Select("select course_id dict_value, course_name dict_label,img_url dict_imgUrl  from fs_user_course where is_del = 0 and is_private = 1 ")
-    List<OptionsVO> selectFsUserCourseAllList();
-
 
 
     @Select({"<script> " +
     @Select({"<script> " +
             "select c.*,cc.cate_name,ucc.cate_name as sub_cate_name from fs_user_course  c " +
             "select c.*,cc.cate_name,ucc.cate_name as sub_cate_name from fs_user_course  c " +
@@ -227,9 +224,16 @@ public interface FsUserCourseMapper
             "</script>"})
             "</script>"})
     List<FsUserCourseListPVO> selectFsUserCourseListCompanyPVO(@Param("maps")FsUserCourseParam fsUserCourse);
     List<FsUserCourseListPVO> selectFsUserCourseListCompanyPVO(@Param("maps")FsUserCourseParam fsUserCourse);
 
 
+
+
+    @Select("select course_id dict_value, course_name dict_label,img_url dict_imgUrl  from fs_user_course where is_del = 0 and is_private = 1 ")
+    List<OptionsVO> selectFsUserCourseAllList();
+
+
     @Select("select course_id dict_value, course_name dict_label,img_url dict_imgUrl  from fs_user_course where is_del = 0 and is_private = 1" +
     @Select("select course_id dict_value, course_name dict_label,img_url dict_imgUrl  from fs_user_course where is_del = 0 and is_private = 1" +
             " and find_in_set(#{companyId},company_ids) ")
             " and find_in_set(#{companyId},company_ids) ")
     List<OptionsVO> selectFsUserCourseByCompany(@Param("companyId") Long companyId);
     List<OptionsVO> selectFsUserCourseByCompany(@Param("companyId") Long companyId);
+
     @Select("select course_id ,project   from fs_user_course where is_del = 0 and is_private = 1")
     @Select("select course_id ,project   from fs_user_course where is_del = 0 and is_private = 1")
     List<FsUserCourse> selectFsUserCourseAllCourse();
     List<FsUserCourse> selectFsUserCourseAllCourse();
 
 
@@ -242,7 +246,7 @@ public interface FsUserCourseMapper
             "        LEFT JOIN fs_user_course_period_days fcpd ON fcpd.period_id = fcp.period_id\n" +
             "        LEFT JOIN fs_user_course_period_days fcpd ON fcpd.period_id = fcp.period_id\n" +
             "        LEFT JOIN fs_user_course c ON c.course_id = fcpd.course_id\n" +
             "        LEFT JOIN fs_user_course c ON c.course_id = fcpd.course_id\n" +
             "        WHERE\n" +
             "        WHERE\n" +
-            "        c.is_del = 0\n" +
+            "        c.is_del = 0 and fcp.del_flag = '0'\n" +
             "        AND FIND_IN_SET(#{companyId}, fcp.company_id)\n" +
             "        AND FIND_IN_SET(#{companyId}, fcp.company_id)\n" +
             "        <if test=\"keyword != null and keyword !='' \">\n" +
             "        <if test=\"keyword != null and keyword !='' \">\n" +
             "            AND fcp.period_name LIKE concat('%',#{keyword},'%'\n" +
             "            AND fcp.period_name LIKE concat('%',#{keyword},'%'\n" +

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

@@ -14,6 +14,7 @@ import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 
 
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.util.List;
 import java.util.List;
@@ -140,7 +141,8 @@ public interface FsUserCourseVideoMapper
     List<OptionsVO> selectFsUserCourseVodeAllList(Long id);
     List<OptionsVO> selectFsUserCourseVodeAllList(Long id);
 
 
     @Select({"<script> " +
     @Select({"<script> " +
-            "select v.*,p.red_packet_money company_red_packet_money from fs_user_course_video v LEFT JOIN fs_user_course_video_red_package p on p.video_id= v.video_id and p.company_id =#{maps.companyId} " +
+            "select v.*,p.red_packet_money company_red_packet_money from fs_user_course_video v " +
+            "LEFT JOIN fs_user_course_video_red_package p on p.video_id= v.video_id and p.company_id =#{maps.companyId} and p.data_type = 1 " +
             "where v.is_del = 0 and  v.course_id = #{maps.courseId}   " +
             "where v.is_del = 0 and  v.course_id = #{maps.courseId}   " +
             "<if test = ' maps.title!=null and maps.title != \"\" '> " +
             "<if test = ' maps.title!=null and maps.title != \"\" '> " +
             "and v.title = #{maps.title} " +
             "and v.title = #{maps.title} " +
@@ -198,4 +200,20 @@ public interface FsUserCourseVideoMapper
     List<FsCourseVideoListBySidebarVO> getFsCourseVideoListBySidebar(@Param("data") FsCourseListBySidebarParam param);
     List<FsCourseVideoListBySidebarVO> getFsCourseVideoListBySidebar(@Param("data") FsCourseListBySidebarParam param);
 
 
     List<FsUserCourseVideoPageListVO> selectFsUserCourseVideoListByMap(@Param("params") Map<String, Object> params);
     List<FsUserCourseVideoPageListVO> selectFsUserCourseVideoListByMap(@Param("params") Map<String, Object> params);
+
+    FsUserCourseVideo selectByFileKey(@Param("params")String fileKey);
+
+    @Select("select * from fs_user_course_video where file_key = #{fileKey} ")
+    List<FsUserCourseVideo> selectVideoByFileKey(@Param("fileKey") String fileKey);
+
+    @Update("UPDATE fs_user_course_video " +
+            "SET line_one = #{lineOne}, " +
+            "    transcode_file_key = #{transcodeFileKey}, " +
+            "    is_transcode = 1, " +
+            "    update_time = NOW() " +  // 添加更新时间
+            "WHERE file_key = #{fileKey}")
+    void updateFsUserCourseVideoByFileKey(FsUserCourseVideo courseVideo);
+
+    @Select("select title from fs_user_course_video WHERE video_id=#{videoId}")
+    String selectFsUserCourseVideoByVideoForTitle(@Param("videoId") Long videoId);
 }
 }

+ 3 - 0
fs-service/src/main/java/com/fs/course/mapper/FsVideoResourceMapper.java

@@ -24,4 +24,7 @@ public interface FsVideoResourceMapper extends BaseMapper<FsVideoResource> {
 
 
     @Select("select * from fs_video_resource where is_transcode = 1 and is_del = 0 and transcode_file_key is null")
     @Select("select * from fs_video_resource where is_transcode = 1 and is_del = 0 and transcode_file_key is null")
     List<FsVideoResource> selectVideoIsTranscode();
     List<FsVideoResource> selectVideoIsTranscode();
+
+    @Select("select * from fs_video_resource where file_key = #{fileKey} limit 1")
+    FsVideoResource selectByFileKey(String fileKey);
 }
 }

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

@@ -27,4 +27,6 @@ public class FsCourseSendRewardUParam implements Serializable
     private Integer sendType;
     private Integer sendType;
     private Long periodId;
     private Long periodId;
 
 
+    private String appId;
+
 }
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java

@@ -52,6 +52,11 @@ public class FsCourseWatchLogListParam implements Serializable {
     @JsonFormat(pattern = "yyyy-MM-dd")
     @JsonFormat(pattern = "yyyy-MM-dd")
     private String scheduleEndTime;
     private String scheduleEndTime;
 
 
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private String qecSTime;
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private String qecETime;
+
     private List<String> sopIds;
     private List<String> sopIds;
 
 
 
 

+ 4 - 0
fs-service/src/main/java/com/fs/course/param/FsUserCourseVideoParam.java

@@ -16,8 +16,12 @@ public class FsUserCourseVideoParam {
     private String title;
     private String title;
     private String redPacketMoney;
     private String redPacketMoney;
     private Long companyId;
     private Long companyId;
+
+    private Integer dataType;
+
     @ApiModelProperty(value = "页码,默认为1")
     @ApiModelProperty(value = "页码,默认为1")
     private Integer pageNum =1;
     private Integer pageNum =1;
+
     @ApiModelProperty(value = "页大小,默认为10")
     @ApiModelProperty(value = "页大小,默认为10")
     private Integer pageSize = 10;
     private Integer pageSize = 10;
 }
 }

+ 13 - 0
fs-service/src/main/java/com/fs/course/param/SendXfkParam.java

@@ -0,0 +1,13 @@
+package com.fs.course.param;
+
+import lombok.Data;
+
+@Data
+public class SendXfkParam {
+    private String corpId;
+    private String userId;
+    private String name;
+    private Integer addWay;
+    private String state;
+    private String createTime;
+}

+ 4 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseAddCompanyUserParam.java

@@ -33,4 +33,8 @@ public class FsUserCourseAddCompanyUserParam implements Serializable {
     @ApiModelProperty(value = "营期id")
     @ApiModelProperty(value = "营期id")
     private Long periodId;
     private Long periodId;
 
 
+//    @NotNull(message = "项目id不能为空")
+    @ApiModelProperty(value = "项目ID")
+    private Long projectId;
+
 }
 }

+ 4 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseBeMemberParam.java

@@ -24,5 +24,9 @@ public class FsUserCourseBeMemberParam implements Serializable {
     @ApiModelProperty(value = "标签ids,数组格式")
     @ApiModelProperty(value = "标签ids,数组格式")
     private String[] tagIds;
     private String[] tagIds;
 
 
+//    @NotNull(message = "项目id不能为空")
+    @ApiModelProperty(value = "课程归属项目id")
+    private Long projectId;
+
 
 
 }
 }

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

@@ -83,4 +83,13 @@ public interface IFsCourseLinkService
     R getRealLinkH5(String link);
     R getRealLinkH5(String link);
 
 
     R createRoomLink(FsCourseLinkRoomParam param, QwUser qwUser);
     R createRoomLink(FsCourseLinkRoomParam param, QwUser qwUser);
+
+    String testGetAppLink();
+
+    /**
+     * 获取跳转微信小程序的链接地址
+     * @param linkStr
+     * @return
+     */
+    String getGotoWxAppLink(String linkStr,String appid);
 }
 }

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

@@ -176,4 +176,10 @@ public interface IFsUserCourseVideoService
     ResponseResult<Boolean> setWatchCourseTime(List<FsWatchCourseTimeParam> collect);
     ResponseResult<Boolean> setWatchCourseTime(List<FsWatchCourseTimeParam> collect);
 
 
     R createRoomMiniLink(FsCourseLinkMiniParam param);
     R createRoomMiniLink(FsCourseLinkMiniParam param);
+
+    FsUserCourseVideo selectByFileKey(String fileKey);
+
+    String selectFsUserCourseVideoByVideoForTitle(Long videoId);
+
+    R updateVideo();
 }
 }

+ 55 - 0
fs-service/src/main/java/com/fs/course/service/impl/AsyncIsAddKfXfkService.java

@@ -0,0 +1,55 @@
+package com.fs.course.service.impl;
+
+import cn.hutool.http.HttpRequest;
+import com.alibaba.fastjson.JSON;
+import com.fs.common.utils.PubFun;
+import com.fs.course.param.SendXfkParam;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.qw.result.QwFilterSopCustomersResult;
+import com.fs.qw.vo.QwSopRuleTimeVO;
+import com.fs.sop.domain.*;
+import com.fs.sop.mapper.QwSopLogsMapper;
+import com.fs.sop.mapper.QwSopMapper;
+import com.fs.sop.mapper.QwSopTempMapper;
+import com.fs.sop.mapper.SopUserLogsInfoMapper;
+import com.fs.sop.params.DeleteQwSopParam;
+import com.fs.sop.params.QwSopTagsParam;
+import com.fs.sop.params.SopUserLogsArray;
+import com.fs.sop.params.SopUserLogsList;
+import com.fs.sop.service.IQwSopTempVoiceService;
+import com.fs.sop.service.ISopUserLogsService;
+import com.fs.voice.utils.StringUtil;
+import com.fs.wxUser.domain.CompanyWxUser;
+import com.fs.wxUser.mapper.CompanyWxUserMapper;
+import com.fs.wxUser.param.CompanyWxUserSopParam;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@AllArgsConstructor
+public class AsyncIsAddKfXfkService {
+
+    private static final String domainXFKName = "https://workapi.dazhengnet.cn/api.php/Home/XfkWork/bindMember";
+
+    /**
+     * 异步推送
+     */
+    @Async("scheduledExecutorService")
+    public void executeSopByIds(SendXfkParam xfkParam) {
+
+        HttpRequest.post(domainXFKName)
+                .body(JSON.toJSONString(xfkParam),"application/json;charset=UTF-8")
+                .execute().body();
+
+
+    }
+
+}

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

@@ -1,8 +1,10 @@
 package com.fs.course.service.impl;
 package com.fs.course.service.impl;
 
 
+import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.PubFun;
@@ -10,6 +12,7 @@ import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.config.cloud.CloudHostProper;
+import com.fs.core.config.WxMaConfiguration;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.domain.*;
 import com.fs.course.mapper.FsCourseDomainNameMapper;
 import com.fs.course.mapper.FsCourseDomainNameMapper;
@@ -20,6 +23,8 @@ import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsCourseLinkRoomParam;
 import com.fs.course.param.FsCourseLinkRoomParam;
 import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseService;
+import com.fs.his.config.FsSysConfig;
+import com.fs.his.utils.ConfigUtil;
 import com.fs.qw.domain.QwGroupChat;
 import com.fs.qw.domain.QwGroupChat;
 import com.fs.qw.domain.QwGroupChatUser;
 import com.fs.qw.domain.QwGroupChatUser;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
@@ -32,13 +37,26 @@ import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.fs.voice.utils.StringUtil;
 import lombok.Synchronized;
 import lombok.Synchronized;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 
 
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.ZoneId;
@@ -89,6 +107,11 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
     @Autowired
     @Autowired
     CloudHostProper cloudHostProper;
     CloudHostProper cloudHostProper;
 
 
+    private static String TOKEN_VALID_CODE = "40001";
+
+    private volatile Integer version = 0;
+
+
     /**
     /**
      * 查询短链
      * 查询短链
      *
      *
@@ -661,4 +684,137 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
     }
     }
 
 
 
 
+    /**
+     *
+     * 生成跳转微信小程序的链接 base
+     *
+     * @param appid 微信appid
+     * @param path  跳转页面路径
+     * @param query 需要传参的String
+     * @return
+     */
+    public String getWxAppLink(String appid, String path, String query) {
+
+        StringBuilder wxAppLink = new StringBuilder("weixin://dl/business/?");
+        try {
+            wxAppLink.append("appid=").append(appid);
+            wxAppLink.append("&path=").append(path);
+            String encodedQuery =  URLEncoder.encode(URLEncoder.encode(query, StandardCharsets.UTF_8.toString()));
+            wxAppLink.append("&query=").append(encodedQuery);
+//            wxAppLink.append("&env_version=trial");
+//            if(StringUtils.isNotBlank(envVersion)){
+//                wxAppLink.append("&env_version=").append(envVersion);
+//            }
+
+        } catch (UnsupportedEncodingException e) {
+            log.error("生成跳转微信小程序的链接失败" + e.getMessage());
+            return "生成失败";
+        }
+        return wxAppLink.toString();
+
+    }
+
+    @Override
+    public String testGetAppLink() {
+        String pageLink = "/pages_course/video.html?course\\u003d{\\\"companyId\\\":100,\\\"companyUserId\\\":2020,\\\"corpId\\\":\\\"ww51717e2b71d5e2d3\\\",\\\"courseId\\\":63,\\\"link\\\":\\\"1943203055923101696\\\",\\\"linkType\\\":3,\\\"qwExternalId\\\":20812637,\\\"qwUserId\\\":\\\"9112\\\",\\\"videoId\\\":400}";
+        String miniprogramAppid = "wx76cb55db092a41ae";
+        if (StringUtils.isNotBlank(pageLink)) {
+
+            //解析pageLink
+            String[] split = pageLink.split("\\?");
+            if (split.length == 2 && split[0].length() > 0 && split[1].length() > 0) {
+                //处理页面路径
+                String pageUrl =split[0];
+                if(pageUrl.startsWith("/")){
+                    pageUrl = pageUrl.substring(1);
+                }
+                if(pageUrl.contains(".html")){
+                    pageUrl = pageUrl.replace(".html", "");
+                }
+                //处理参数
+                String query = split[1];
+                query = query.replace("\\u003d", "=");
+                String wxAppLink = getWxAppLink(miniprogramAppid, pageUrl, query);
+                return wxAppLink;
+            } else {
+                return "页面链接错误,获取失败";
+            }
+        }
+        return pageLink;
+
+    }
+
+    /**
+     * 获取跳转微信小程序的链接地址
+     * @param linkStr
+     * @return
+     */
+    @Override
+    public String getGotoWxAppLink(String linkStr,String appId) {
+        CloseableHttpClient client = null;
+        try {
+            client = HttpClients.createDefault();
+            String[] split = linkStr.split("\\?");
+            if (split.length == 2 && split[0].length() > 0 && split[1].length() > 0) {
+                //处理页面路径
+                String pageUrl = split[0];
+                if (pageUrl.startsWith("/")) {
+                    pageUrl = pageUrl.substring(1);
+                }
+                //处理参数
+                String query = split[1];
+                query = URLEncoder.encode(query, StandardCharsets.UTF_8.toString());
+                String json = configService.selectConfigByKey("course.config");
+                CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+                String miniprogramAppid = config.getMiniprogramAppid();
+                if (StringUtils.isBlank(miniprogramAppid)) {
+                    return "未配置点播小程序id";
+                }
+                //获取微信token
+                final WxMaService wxService = WxMaConfiguration.getMaService(appId);
+                String token = wxService.getAccessToken();
+                log.info("小程序TOKEN值-------->刷新前TOKEN:{}", token);
+                HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/wxa/generate_urllink?access_token=" + token);
+                JSONObject bodyObj = new JSONObject();
+                bodyObj.put("path", pageUrl);
+                bodyObj.put("query", query);
+                log.info("微信小程序请求参数打印:{}", bodyObj.toJSONString());
+                StringEntity entity = new StringEntity(bodyObj.toJSONString(),"UTF-8");
+                httpPost.setEntity(entity);
+                httpPost.setHeader("Content-type", "application/json");
+                httpPost.setHeader("cache-control","max-age=0");
+                HttpEntity response = client.execute(httpPost).getEntity();
+                String responseString = EntityUtils.toString(response);
+                log.info("微信小程序接口响应数据:{}", responseString);
+                JSONObject jsonObject = JSONObject.parseObject(responseString);
+
+                if(TOKEN_VALID_CODE.equals(jsonObject.getString("errcode"))){
+                    Integer curVersion =  Integer.valueOf(version);
+                    synchronized (TOKEN_VALID_CODE){
+                        if(curVersion.equals(version)){
+                            log.info("小程序TOKEN:40001进入强制刷新-------->刷新前TOKEN:{}", token);
+                            wxService.getAccessToken(true);
+                            version = version.equals(Integer.MAX_VALUE) ? 0 : curVersion + 1;
+                            log.info("小程序TOKEN:40001进入强制刷新-------->刷新后TOKEN:{}", wxService.getAccessToken());
+                        }
+                        return getGotoWxAppLink(linkStr,appId);
+                    }
+                }
+
+                if(null != jsonObject && !jsonObject.isEmpty() && jsonObject.containsKey("url_link")){
+                    return jsonObject.getString("url_link");
+                }
+            } else {
+                return "页面链接错误,获取失败";
+            }
+
+        } catch (WxErrorException e) {
+            throw new RuntimeException(e);
+        } catch (ClientProtocolException e) {
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return "";
+    }
 }
 }

+ 4 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseComplaintRecordServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fs.course.service.impl;
 package com.fs.course.service.impl;
 
 
+import java.util.Collections;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.function.Function;
 import java.util.function.Function;
@@ -55,6 +56,9 @@ public class FsUserCourseComplaintRecordServiceImpl extends ServiceImpl<FsUserCo
 
 
         // 获取外部联系人看课状态
         // 获取外部联系人看课状态
         List<Long> userIds = list.stream().map(FsUserCourseComplaintRecordPageListVO::getUserId).collect(Collectors.toList());
         List<Long> userIds = list.stream().map(FsUserCourseComplaintRecordPageListVO::getUserId).collect(Collectors.toList());
+        if(userIds.isEmpty()){
+            return Collections.emptyList();
+        }
         List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectExternalByFsUserIds(userIds);
         List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectExternalByFsUserIds(userIds);
         Map<Long, QwExternalContact> qwExternalContactMap = qwExternalContacts.stream().collect(Collectors.toMap(QwExternalContact::getFsUserId, Function.identity(), (v1, v2) -> v1));
         Map<Long, QwExternalContact> qwExternalContactMap = qwExternalContacts.stream().collect(Collectors.toMap(QwExternalContact::getFsUserId, Function.identity(), (v1, v2) -> v1));
 
 

+ 86 - 35
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fs.course.service.impl;
 package com.fs.course.service.impl;
 
 
+import cn.hutool.http.HttpRequest;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
@@ -77,6 +78,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.math.RoundingMode;
 import java.net.SocketTimeoutException;
 import java.net.SocketTimeoutException;
+import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.ZoneId;
@@ -103,6 +105,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private static final String miniappRealLink = "/pages_course/video.html?course=";
     private static final String miniappRealLink = "/pages_course/video.html?course=";
     private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
     private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
     private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
     private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
+
     @Autowired
     @Autowired
     private CompanyMoneyLogsMapper moneyLogsMapper;
     private CompanyMoneyLogsMapper moneyLogsMapper;
     @Autowired
     @Autowired
@@ -128,6 +131,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     @Autowired
     private FsCourseLinkMapper fsCourseLinkMapper;
     private FsCourseLinkMapper fsCourseLinkMapper;
 
 
+    @Autowired
+    private AsyncIsAddKfXfkService xfkService;
+
 
 
     @Autowired
     @Autowired
     private QwExternalContactMapper qwExternalContactMapper;
     private QwExternalContactMapper qwExternalContactMapper;
@@ -408,17 +414,17 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
 
         String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为会员独享<br>请长按二维码</div>\n" +
         String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为会员独享<br>请长按二维码</div>\n" +
                 "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
                 "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
-        try {
-            new Thread(() -> {
-                try {
-                    rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(1).fsUserId(param.getUserId()).build()));
-                }catch (Exception e){
-                    logger.error("看课重粉提交mq失败", e);
-                }
-            }).start();
-        }catch (Exception e){
-            logger.error("看课重粉提交mq失败", e);
-        }
+//        try {
+//            new Thread(() -> {
+//                try {
+//                    rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(1).fsUserId(param.getUserId()).build()));
+//                }catch (Exception e){
+//                    logger.error("看课重粉提交mq失败", e);
+//                }
+//            }).start();
+//        }catch (Exception e){
+//            logger.error("看课重粉提交mq失败", e);
+//        }
 
 
         Integer isRoom = param.getIsRoom();
         Integer isRoom = param.getIsRoom();
 
 
@@ -649,6 +655,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             QwExternalContact contact = new QwExternalContact();
             QwExternalContact contact = new QwExternalContact();
             contact.setId(param.getQwExternalId());
             contact.setId(param.getQwExternalId());
             contact.setFsUserId(param.getUserId());
             contact.setFsUserId(param.getUserId());
+            contact.setRegisterTime(new Date());
             qwExternalContactMapper.updateQwExternalContact(contact);
             qwExternalContactMapper.updateQwExternalContact(contact);
 
 
             iSopUserLogsInfoService.updateSopUserInfoByExternalId(qwExternalId,param.getUserId());
             iSopUserLogsInfoService.updateSopUserInfoByExternalId(qwExternalId,param.getUserId());
@@ -659,6 +666,25 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             user.setQwExtId(param.getQwExternalId());
             user.setQwExtId(param.getQwExternalId());
             fsUserMapper.updateFsUser(user);
             fsUserMapper.updateFsUser(user);
 
 
+
+//            //小访客特有
+//            SendXfkParam xfkParam=new SendXfkParam();
+//            xfkParam.setCorpId(externalContact.getCorpId());
+//            xfkParam.setUserId(externalContact.getUserId());
+//            xfkParam.setName(externalContact.getName());
+//            xfkParam.setAddWay(externalContact.getAddWay());
+//            xfkParam.setState(externalContact.getState());
+//            if (externalContact.getCreateTime()!=null){
+//                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//                String formattedTime = sdf.format(externalContact.getCreateTime());
+//                xfkParam.setCreateTime(formattedTime);
+//            }else {
+//                xfkParam.setCreateTime("");
+//            }
+//
+//
+//            xfkService.executeSopByIds(xfkParam);
+
             iSopUserLogsInfoService.updateSopUserInfoByExternalId(qwExternalId,param.getUserId());
             iSopUserLogsInfoService.updateSopUserInfoByExternalId(qwExternalId,param.getUserId());
 
 
             //绑定上之后 更新观看记录
             //绑定上之后 更新观看记录
@@ -934,23 +960,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
      * @return 处理结果
      * @return 处理结果
      */
      */
     private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
     private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
-        // 判断是否属于领取红包时间(会员看课发放红包)
-        if (param.getPeriodId()!=null && param.getPeriodId()>0) {
-            FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
-            periodDays.setVideoId(param.getVideoId());
-            periodDays.setPeriodId(param.getPeriodId());
-            //正常情况是只能查询到一条,之前可能存在重复的脏数据,暂使用查询list的方式
-            List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
-            if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
-                periodDays = fsUserCoursePeriodDays.get(0);
-            }
-            if(periodDays != null && periodDays.getLastJoinTime() !=null && LocalDateTime.now().isAfter(periodDays.getLastJoinTime())) {
-                return R.error(403,"已超过领取红包时间");
-            }
-        }
-
-
-
 
 
         // 确定红包金额
         // 确定红包金额
         BigDecimal amount = BigDecimal.ZERO;
         BigDecimal amount = BigDecimal.ZERO;
@@ -964,12 +973,18 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
 
         // 准备发送红包参数
         // 准备发送红包参数
         WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
         WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
-//        packetParam.setOpenId(getOpenId(user.getUserId(), param.getCompanyId(), param.getSource()));
         packetParam.setOpenId(user.getMpOpenId());
         packetParam.setOpenId(user.getMpOpenId());
         // 来源是小程序切换openId
         // 来源是小程序切换openId
         if (param.getSource() == 2) {
         if (param.getSource() == 2) {
-            System.out.println("小程序id"+user.getCourseMaOpenId());
-            packetParam.setOpenId(user.getCourseMaOpenId());
+            //处理多小程序问题
+            FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
+            if (fsUserWx ==null || fsUserWx.getOpenId()==null){
+                packetParam.setOpenId(user.getCourseMaOpenId());
+            }else {
+                packetParam.setOpenId(fsUserWx.getOpenId());
+            }
+            //查出公司绑定openid并赋值
+
         }
         }
         packetParam.setAmount(amount);
         packetParam.setAmount(amount);
         packetParam.setSource(param.getSource());
         packetParam.setSource(param.getSource());
@@ -1405,7 +1420,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }
         }
 
 
         // 逻辑调整:如果会员已经绑定了销售,直接提示,不添加重粉数据了-2025年6月16日14点53分
         // 逻辑调整:如果会员已经绑定了销售,直接提示,不添加重粉数据了-2025年6月16日14点53分
-        if (fsUser.getCompanyUserId() != null && !param.getCompanyUserId().equals(fsUser.getCompanyUserId())){
+        if (!param.getCompanyUserId().equals(fsUser.getCompanyUserId())){
             return ResponseResult.fail(406,"该用户已成为其他销售会员");
             return ResponseResult.fail(406,"该用户已成为其他销售会员");
         }
         }
 
 
@@ -1720,6 +1735,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Override
     @Override
     public R createMiniLink(FsCourseLinkMiniParam param) {
     public R createMiniLink(FsCourseLinkMiniParam param) {
 
 
+
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
         QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
         QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
 
 
         if (qwUser==null||qwUser.getCompanyId()==null||qwUser.getCompanyUserId()==null){
         if (qwUser==null||qwUser.getCompanyId()==null||qwUser.getCompanyUserId()==null){
@@ -1741,7 +1760,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         JSONObject news = new JSONObject(true);
         JSONObject news = new JSONObject(true);
         news.put("miniprogramAppid", qwCompany.getMiniAppId());
         news.put("miniprogramAppid", qwCompany.getMiniAppId());
         news.put("miniprogramTitle", param.getTitle());
         news.put("miniprogramTitle", param.getTitle());
-        news.put("miniprogramPicUrl", "https://cos.his.cdwjyyh.com/fs/20250523/9c8af5735d784847818cada7fa776a7b.jpg");
+        news.put("miniprogramPicUrl", config.getSidebarImageUrl());
         news.put("miniprogramPage", linkByMiniApp);
         news.put("miniprogramPage", linkByMiniApp);
 
 
         return R.ok().put("data",news);
         return R.ok().put("data",news);
@@ -1785,7 +1804,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         JSONObject news = new JSONObject(true); // true 表示保持字段顺序
         JSONObject news = new JSONObject(true); // true 表示保持字段顺序
         news.put("linkTitle", param.getTitle());
         news.put("linkTitle", param.getTitle());
         news.put("linkDescribe", param.getTitle());
         news.put("linkDescribe", param.getTitle());
-        news.put("linkImageUrl", "https://cos.his.cdwjyyh.com/fs/20250523/9c8af5735d784847818cada7fa776a7b.jpg");
+        news.put("linkImageUrl", config.getSidebarImageUrl());
         news.put("linkUrl", linkByCartLink);
         news.put("linkUrl", linkByCartLink);
 
 
         return R.ok().put("data",news);
         return R.ok().put("data",news);
@@ -1820,6 +1839,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
 
             //存看课记录
             //存看课记录
             courseWatchLogMapper.insertOrUpdateFsCourseWatchLog(watchLog);
             courseWatchLogMapper.insertOrUpdateFsCourseWatchLog(watchLog);
+
         }catch (Exception e){
         }catch (Exception e){
             logger.error("一键群发失败-插入观看记录失败:"+e.getMessage());
             logger.error("一键群发失败-插入观看记录失败:"+e.getMessage());
         }
         }
@@ -1995,6 +2015,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
 
     @Override
     @Override
     public R createRoomMiniLink(FsCourseLinkMiniParam param) {
     public R createRoomMiniLink(FsCourseLinkMiniParam param) {
+
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
         QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
         QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
 
 
         if (qwUser==null||qwUser.getCompanyId()==null||qwUser.getCompanyUserId()==null){
         if (qwUser==null||qwUser.getCompanyId()==null||qwUser.getCompanyUserId()==null){
@@ -2013,12 +2037,23 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         JSONObject news = new JSONObject(true);
         JSONObject news = new JSONObject(true);
         news.put("miniprogramAppid", qwCompany.getMiniAppId());
         news.put("miniprogramAppid", qwCompany.getMiniAppId());
         news.put("miniprogramTitle", param.getTitle());
         news.put("miniprogramTitle", param.getTitle());
-        news.put("miniprogramPicUrl", "https://cos.his.cdwjyyh.com/fs/20250523/9c8af5735d784847818cada7fa776a7b.jpg");
+        news.put("miniprogramPicUrl", config.getSidebarImageUrl());
         news.put("miniprogramPage", linkByMiniApp);
         news.put("miniprogramPage", linkByMiniApp);
 
 
         return R.ok().put("data",news);
         return R.ok().put("data",news);
     }
     }
 
 
+    @Override
+    public FsUserCourseVideo selectByFileKey(String fileKey) {
+        FsUserCourseVideo fsUserCourseVideo = fsUserCourseVideoMapper.selectByFileKey(fileKey);
+        return fsUserCourseVideo;
+    }
+
+    @Override
+    public String selectFsUserCourseVideoByVideoForTitle(Long videoId) {
+        return fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoForTitle(videoId);
+    }
+
     /**
     /**
      * 获取视频时长(优先从Redis获取,不存在则查数据库)
      * 获取视频时长(优先从Redis获取,不存在则查数据库)
      */
      */
@@ -2119,4 +2154,20 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 videoDuration/60, config.getMinutesNum()));
                 videoDuration/60, config.getMinutesNum()));
     }
     }
 
 
+
+    @Override
+    public R updateVideo() {
+        FsUserCourseVideo param = new FsUserCourseVideo();
+        param.setCourseId(144L);
+        List<FsUserCourseVideo> videos = selectFsUserCourseVideoListByCourseId(param);
+        for (FsUserCourseVideo courseVideo :  videos){
+            FsVideoResource resource = fsVideoResourceMapper.selectByFileKey(courseVideo.getFileKey());
+            if (resource==null){
+                continue;
+            }
+            courseVideo.setLineOne(resource.getLine1());
+            fsUserCourseVideoMapper.updateFsUserCourseVideo(courseVideo);
+        }
+        return R.ok();
+    }
 }
 }

+ 52 - 12
fs-service/src/main/java/com/fs/course/service/impl/TencentCloudCosService.java

@@ -26,6 +26,7 @@ import com.tencentcloudapi.mps.v20190612.models.*;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 
 
 import java.io.IOException;
 import java.io.IOException;
@@ -159,25 +160,64 @@ public class TencentCloudCosService implements ITencentCloudCosService {
         return config;
         return config;
     }
     }
 
 
+//    @Override
+//    @Transactional
+//    public R updateUrl() {
+//        try {
+//            //查出已转码的视频并且没有文件key的
+//            List<FsVideoResource> videos =  videoResourceMapper.selectVideoIsTranscode();
+//            for (FsVideoResource video : videos ){
+//                String newUrl = replaceCourse(video.getLine1());
+//                FsVideoResource videoMap = new FsVideoResource();
+//                videoMap.setId(video.getId());
+//                videoMap.setLine1(newUrl);
+//                videoMap.setTranscodeFileKey(replaceCourse(video.getFileKey()));
+//                videoResourceMapper.updateById(videoMap);
+//                //更新课程管理目录的视频
+//                FsUserCourseVideo courseVideo = new FsUserCourseVideo();
+//                courseVideo.setFileKey(video.getFileKey());
+//                courseVideo.setLineOne(newUrl);
+//                courseVideo.setTranscodeFileKey(videoMap.getTranscodeFileKey());
+//                courseVideoMapper.updateFsUserCourseVideoByFileKey(courseVideo);
+//
+//            }
+//            return R.ok();
+//        }catch (Exception e){
+//            return R.error();
+//        }
+//
+//    }
+
     @Override
     @Override
-    @Transactional
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
     public R updateUrl() {
     public R updateUrl() {
         try {
         try {
-            //查出已转码的视频并且没有文件key的
-            List<FsVideoResource> videos =  videoResourceMapper.selectVideoIsTranscode();
-            for (FsVideoResource video : videos ){
-                String newUrl = replaceCourse(video.getLine1());
-                FsVideoResource videoMap = new FsVideoResource();
-                videoMap.setId(video.getId());
-                videoMap.setLine1(newUrl);
-                videoMap.setTranscodeFileKey(replaceCourse(video.getFileKey()));
-                videoResourceMapper.updateById(videoMap);
+            List<FsVideoResource> videos = videoResourceMapper.selectVideoIsTranscode();
+            for (FsVideoResource video : videos) {
+                updateSingleVideo(video); // 将单个视频更新逻辑提取到方法
             }
             }
             return R.ok();
             return R.ok();
-        }catch (Exception e){
-            return R.error();
+        } catch (Exception e) {
+            return R.error(e.getMessage());
         }
         }
+    }
 
 
+    // 为每个视频更新使用独立事务
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    public void updateSingleVideo(FsVideoResource video) {
+        String newUrl = replaceCourse(video.getLine1());
+
+        FsVideoResource videoMap = new FsVideoResource();
+        videoMap.setId(video.getId());
+        videoMap.setLine1(newUrl);
+        videoMap.setTranscodeFileKey(replaceCourse(video.getFileKey()));
+        videoResourceMapper.updateById(videoMap);
+
+        FsUserCourseVideo courseVideo = new FsUserCourseVideo();
+        courseVideo.setFileKey(video.getFileKey());
+        courseVideo.setLineOne(newUrl);
+        courseVideo.setTranscodeFileKey(videoMap.getTranscodeFileKey());
+        courseVideoMapper.updateFsUserCourseVideoByFileKey(courseVideo);
     }
     }
 
 
     private byte[] getObjectInputStream() throws IOException {
     private byte[] getObjectInputStream() throws IOException {

+ 5 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseOverVO.java

@@ -12,6 +12,11 @@ public class FsCourseOverVO {
 
 
     @Excel(name = "企微客户")
     @Excel(name = "企微客户")
     private String qwUserName;
     private String qwUserName;
+
+    @Excel(name = "客户头像")
+    private String avatar;
+
+
     @Excel(name = "企业微信员工名称")
     @Excel(name = "企业微信员工名称")
     private String externalUserName;
     private String externalUserName;
 
 

+ 26 - 16
fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogListVO.java

@@ -21,13 +21,23 @@ public class FsCourseWatchLogListVO extends BaseEntity
     @Excel(name = "记录编号")
     @Excel(name = "记录编号")
     private Long logId;
     private Long logId;
 
 
-    @Excel(name = "会员id")
+    /** 会员id */
+//    @Excel(name = "会员id")
     private Long userId;
     private Long userId;
 
 
-    @Excel(name = "小程序昵称")
+    /** 小程序昵称 */
+//    @Excel(name = "小程序昵称")
     private String fsNickName;
     private String fsNickName;
 
 
-    @Excel(name = "小程序头像")
+    @Excel(name = "客户昵称")
+    private String externalUserName;
+
+    /** 外部联系人头像 */
+    @Excel(name = "客户头像")
+    private String externalUserAvatar;
+
+    /** 客户头像 */
+//    @Excel(name = "客户头像")
     private String fsAvatar;
     private String fsAvatar;
 
 
     @Excel(name = "课程名称")
     @Excel(name = "课程名称")
@@ -39,7 +49,7 @@ public class FsCourseWatchLogListVO extends BaseEntity
     @Excel(name = "记录类型" ,dictType = "sys_course_watch_log_type")
     @Excel(name = "记录类型" ,dictType = "sys_course_watch_log_type")
     private Integer logType;
     private Integer logType;
 
 
-    @Excel(name = "企微外部联系人id")
+//    @Excel(name = "企微外部联系人id")
     private String qwExternalContactId;
     private String qwExternalContactId;
 
 
 
 
@@ -47,26 +57,27 @@ public class FsCourseWatchLogListVO extends BaseEntity
     private String duration;
     private String duration;
 
 
 
 
-    @Excel(name = "分享人企微userId")
+//    @Excel(name = "分享人企微userId")
     private String qwUserId;
     private String qwUserId;
     /**
     /**
      * 企业微信员工名称
      * 企业微信员工名称
      */
      */
-    @Excel(name = "企信员工名称")
+    @Excel(name = "所属企微")
     private String qwUserName;
     private String qwUserName;
 
 
-
     @Excel(name = "所属销售")
     @Excel(name = "所属销售")
     private String companyUserName;
     private String companyUserName;
 
 
-    @Excel(name = "所属团队")
+    /** 所属团队 */
+//    @Excel(name = "所属团队")
     private String companyName;
     private String companyName;
 
 
-    @Excel(name = "所属团队编号")
+    /** 所属团队编号 */
+//    @Excel(name = "所属团队编号")
     private String companyId;
     private String companyId;
 
 
-
-    @Excel(name = "发送方式")
+    /** 发送方式 */
+//    @Excel(name = "发送方式")
     private Integer sendType; //归属发送方式:1 个微  2 企微
     private Integer sendType; //归属发送方式:1 个微  2 企微
 
 
 
 
@@ -79,7 +90,7 @@ public class FsCourseWatchLogListVO extends BaseEntity
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
     private Date updateTime;
 
 
-    @Excel(name = "最后心跳时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
+//    @Excel(name = "最后心跳时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date lastHeartbeatTime;
     private Date lastHeartbeatTime;
 
 
@@ -91,9 +102,8 @@ public class FsCourseWatchLogListVO extends BaseEntity
     @JsonFormat(pattern = "yyyy-MM-dd")
     @JsonFormat(pattern = "yyyy-MM-dd")
     private Date campPeriodTime;
     private Date campPeriodTime;
 
 
-    @Excel(name = "外部联系人名称")
-    private String externalUserName; //外部联系人名称
-
-    private String externalUserAvatar;//外部联系人头像
+    @Excel(name = "进线时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date qecCreateTime;
 
 
 }
 }

+ 118 - 0
fs-service/src/main/java/com/fs/erp/constant/AfterSalesOrderStatusEnum.java

@@ -0,0 +1,118 @@
+package com.fs.erp.constant;
+
+/**
+ * 平台单据状态枚举
+ *
+ * 定义售后单据在不同阶段的状态常量
+ */
+public enum AfterSalesOrderStatusEnum {
+
+    /**
+     * 买家已经申请,等待卖家同意
+     */
+    WAIT_SELLER_AGREE(0, "WAIT_SELLER_AGREE", "买家已经申请,等待卖家同意"),
+
+    /**
+     * 卖家已经同意,等待买家退货
+     */
+    WAIT_BUYER_RETURN_GOODS(1, "WAIT_BUYER_RETURN_GOODS", "卖家已经同意,等待买家退货"),
+
+    /**
+     * 买家已经退货,等待卖家确认收货
+     */
+    WAIT_SELLER_CONFIRM_GOODS(2, "WAIT_SELLER_CONFIRM_GOODS", "买家已经退货,等待卖家确认收货"),
+
+    /**
+     * 卖家拒绝售后
+     */
+    SELLER_REFUSE_BUYER(3, "SELLER_REFUSE_BUYER", "卖家拒绝售后"),
+
+    /**
+     * 等待卖家发货
+     */
+    WAIT_SELLER_DELIVER_GOODS(4, "WAIT_SELLER_DELIVER_GOODS", "等待卖家发货"),
+
+    /**
+     * 补发卖家发货
+     */
+    REISSUE_SELLER_DELIVERY(5, "REISSUE_SELLER_DELIVERY", "补发卖家发货"),
+
+    /**
+     * 售后关闭(售后单未确认前填写该状态erp的售后单自动作废)
+     */
+    CLOSED(6, "CLOSED", "售后关闭"),
+
+    /**
+     * 退款成功
+     * 补发、换货售后单确认时需在系统中手动确认
+     * 注意:抖音、拼多多、淘系等线上平台换货单据,通过接口修改状态为SUCCESS且发出的快递单号是空,
+     * 平台会判定为换货单超时未处理,会被平台强制退款,线上售后类型会变为普通退货
+     */
+    SUCCESS(7, "SUCCESS", "退款成功"),
+    CONFIRM(10, "CONFIRM", "确认");
+
+    private final Integer index;
+    private final String code;
+    private final String description;
+
+    AfterSalesOrderStatusEnum(Integer index, String code, String description) {
+        this.index = index;
+        this.code = code;
+        this.description = description;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public Integer getIndex() {
+        return index;
+    }
+
+    /**
+     * 根据状态码获取枚举实例
+     *
+     * @param code 状态码
+     * @return 对应的枚举实例,如果未找到则返回null
+     */
+    public static AfterSalesOrderStatusEnum getByCode(String code) {
+        if (code == null) {
+            return null;
+        }
+
+        for (AfterSalesOrderStatusEnum status : AfterSalesOrderStatusEnum.values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 根据状态码获取枚举实例
+     *
+     * @param index 状态码
+     * @return 对应的枚举实例,如果未找到则返回null
+     */
+    public static AfterSalesOrderStatusEnum getByIndex(Integer index) {
+        if (index == null) {
+            return null;
+        }
+
+        for (AfterSalesOrderStatusEnum status : AfterSalesOrderStatusEnum.values()) {
+            if (status.getIndex().equals(index)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return this.code;
+    }
+}

+ 111 - 0
fs-service/src/main/java/com/fs/erp/constant/ErpQueryOrderStatusEnum.java

@@ -0,0 +1,111 @@
+package com.fs.erp.constant;
+
+import lombok.Getter;
+
+/**
+ * 订单状态枚举类
+ */
+@Getter
+public enum ErpQueryOrderStatusEnum {
+
+    /**
+     * 待付款
+     */
+    WAIT_PAY("WaitPay", "待付款"),
+
+    /**
+     * 发货中
+     */
+    DELIVERING("Delivering", "发货中"),
+
+    /**
+     * 被合并
+     */
+    MERGED("Merged", "被合并"),
+
+    /**
+     * 异常
+     */
+    QUESTION("Question", "异常"),
+
+    /**
+     * 被拆分
+     */
+    SPLIT("Split", "被拆分"),
+
+    /**
+     * 等供销商|外仓发货
+     */
+    WAIT_OUTER_SENT("WaitOuterSent", "等供销商|外仓发货"),
+
+    /**
+     * 已付款待审核
+     */
+    WAIT_CONFIRM("WaitConfirm", "已付款待审核"),
+
+    /**
+     * 已客审待财审
+     */
+    WAIT_FCONFIRM("WaitFConfirm", "已客审待财审"),
+
+    /**
+     * 已发货
+     */
+    SENT("Sent", "已发货"),
+
+    /**
+     * 取消
+     */
+    CANCELLED("Cancelled", "取消");
+
+    /**
+     * 状态码
+     */
+    private final String code;
+
+    /**
+     * 状态描述
+     */
+    private final String description;
+
+    /**
+     * 构造方法
+     *
+     * @param code        状态码
+     * @param description 状态描述
+     */
+    ErpQueryOrderStatusEnum(String code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据状态码获取对应的枚举值
+     *
+     * @param code 状态码
+     * @return 对应的枚举值,若未找到则返回null
+     */
+    public static ErpQueryOrderStatusEnum getByCode(String code) {
+        for (ErpQueryOrderStatusEnum status : values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 判断给定的状态码是否有效
+     *
+     * @param code 状态码
+     * @return 若有效返回true,否则返回false
+     */
+    public static boolean isValidCode(String code) {
+        return getByCode(code) != null;
+    }
+
+    @Override
+    public String toString() {
+        return this.code + ":" + this.description;
+    }
+}

+ 90 - 0
fs-service/src/main/java/com/fs/erp/constant/OrderStatusEnum.java

@@ -0,0 +1,90 @@
+package com.fs.erp.constant;
+
+import lombok.Getter;
+
+/**
+ * 商城系统订单状态枚举
+ * 包含订单流转的各个状态及其说明
+ */
+@Getter
+public enum OrderStatusEnum {
+
+    /**
+     * 等待买家付款
+     */
+    WAIT_BUYER_PAY("等待买家付款"),
+
+    /**
+     * 等待卖家发货
+     * 传此状态时,实际支付金额(pay节点支付金额=应付金额)ERP才会显示已付款待审核
+     */
+    WAIT_SELLER_SEND_GOODS("等待卖家发货"),
+
+    /**
+     * 等待买家确认收货
+     */
+    WAIT_BUYER_CONFIRM_GOODS("等待买家确认收货"),
+
+    /**
+     * 交易成功
+     */
+    TRADE_FINISHED("交易成功"),
+
+    /**
+     * 付款后交易关闭
+     */
+    TRADE_CLOSED("付款后交易关闭"),
+
+    /**
+     * 付款前交易关闭
+     */
+    TRADE_CLOSED_BY_TAOBAO("付款前交易关闭");
+
+    /**
+     * 订单状态描述
+     */
+    private final String description;
+
+    /**
+     * 构造函数
+     * @param description 订单状态描述
+     */
+    OrderStatusEnum(String description) {
+        this.description = description;
+    }
+
+    /**
+     * 判断订单状态是否可以更新
+     * @return 所有状态均可更新,返回true
+     */
+    public boolean canUpdate() {
+        return true;
+    }
+
+    /**
+     * 根据状态码获取枚举实例
+     * @param code 状态码
+     * @return 对应的枚举实例,如果不存在则返回null
+     */
+    public static OrderStatusEnum getByCode(String code) {
+        try {
+            return OrderStatusEnum.valueOf(code);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 检查给定的状态码是否为有效的订单状态
+     * @param code 状态码
+     * @return 是否有效
+     */
+    public static boolean isValidCode(String code) {
+        return getByCode(code) != null;
+    }
+
+    @Override
+    public String toString() {
+        return this.name() + "(" + this.description + ")";
+    }
+}

+ 87 - 0
fs-service/src/main/java/com/fs/erp/constant/TaskStatusEnum.java

@@ -0,0 +1,87 @@
+package com.fs.erp.constant;
+
+/**
+ * 任务状态枚举
+ */
+public enum TaskStatusEnum {
+
+    /**
+     * 待处理
+     */
+    PENDING(0, "待处理"),
+
+    /**
+     * 成功
+     */
+    SUCCESS(1, "成功"),
+
+    /**
+     * 失败
+     */
+    FAILED(2, "失败"),
+
+    /**
+     * 正在处理
+     */
+    PROCESSING(3, "正在处理"),
+
+    /**
+     * 已取消
+     */
+    CANCELLED(4, "已取消");
+
+    private final Integer code; // 状态码
+    private final String description; // 状态描述
+
+    /**
+     * 构造方法
+     *
+     * @param code        状态码
+     * @param description 状态描述
+     */
+    TaskStatusEnum(Integer code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据状态码获取枚举值
+     *
+     * @param code 状态码
+     * @return 对应的枚举值,如果没有匹配的则返回 null
+     */
+    public static TaskStatusEnum getByCode(Integer code) {
+        for (TaskStatusEnum status : TaskStatusEnum.values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取状态码
+     *
+     * @return 状态码
+     */
+    public Integer getCode() {
+        return code;
+    }
+
+    /**
+     * 获取状态描述
+     *
+     * @return 状态描述
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public String toString() {
+        return "TaskStatusEnum{" +
+                "code=" + code +
+                ", description='" + description + '\'' +
+                '}';
+    }
+}

+ 2 - 1
fs-service/src/main/java/com/fs/erp/domain/ErpDeliverys.java

@@ -1,9 +1,10 @@
 package com.fs.erp.domain;
 package com.fs.erp.domain;
 
 
+import com.fs.erp.dto.df.DFDeliveryResponse;
 import lombok.Data;
 import lombok.Data;
 
 
 @Data
 @Data
-public class ErpDeliverys {
+public class ErpDeliverys extends DFDeliveryResponse {
 
 
     String mail_no;
     String mail_no;
     String express_code;
     String express_code;

+ 3 - 0
fs-service/src/main/java/com/fs/erp/domain/ErpGoods.java

@@ -21,4 +21,7 @@ public class ErpGoods {
     List<ErpCombineItem> combine_item;
     List<ErpCombineItem> combine_item;
     //hzOMSErp 使用 商品id
     //hzOMSErp 使用 商品id
     Long storeProductId;
     Long storeProductId;
+
+    //适用多商品批量上传
+    List<Long> productIdList;
 }
 }

+ 2 - 0
fs-service/src/main/java/com/fs/erp/domain/ErpOrder.java

@@ -32,4 +32,6 @@ public class ErpOrder {
 
 
     Integer isPackage;
     Integer isPackage;
     List<ErpOrderPayment> payments;
     List<ErpOrderPayment> payments;
+
+    String buyer_account;
 }
 }

+ 85 - 0
fs-service/src/main/java/com/fs/erp/domain/FsJstAftersalePush.java

@@ -0,0 +1,85 @@
+package com.fs.erp.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 订阅物流
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FsJstAftersalePush {
+
+    /**
+     * 主键,自增
+     */
+    private Long id;
+
+    /**
+     * 订单号
+     */
+    private String orderId;
+    /**
+     * 售后id
+     */
+    private String afterSaleId;
+
+    /**
+     * 平台单据状态:
+     * 0 WAIT_SELLER_AGREE:买家已经申请,等待卖家同意,
+     * 1 WAIT_BUYER_RETURN_GOODS:卖家已经同意,等待买家退货,
+     * 2 WAIT_SELLER_CONFIRM_GOODS:买家已经退货,等待卖家确认收货,
+     * 3 SELLER_REFUSE_BUYER:卖家拒绝售后,
+     * 4 WAIT_SELLER_DELIVER_GOODS:等待卖家发货,
+     * 5 REISSUE_SELLER_DELIVERY:补发卖家发货,
+     * 6 CLOSED:售后关闭(售后单未确认前填写该状态erp的售后单自动作废),
+     * 7 SUCCESS:退款成功;可更新,补发、换货售后单确认时需在系统中手动确认;抖音、拼多多、淘系等线上平台换货换货单据,通过接口修改状态为SUCCESS且发出的快递单号是空,平台会判定为换货单超时未处理,会被平台强制退款,线上售后类型会变为普通退货
+     */
+    private String type;
+
+    /**
+     * 任务状态:0-待处理,1-成功,2-失败,3-正在处理,4-已取消
+     */
+    private Integer taskStatus;
+
+    /**
+     * 重试次数,默认为 0
+     */
+    private Integer retryCount;
+
+    /**
+     * 上次执行时间,用于记录任务执行的最后时间
+     */
+    private LocalDateTime lastExecuteTime;
+
+    /**
+     * 记录创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 记录更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 调用接口时传入的参数(JSON 格式)
+     */
+    private String params;
+
+    /**
+     * 调用接口返回的结果(JSON 格式)
+     */
+    private String result;
+
+    /**
+     * 错误信息(记录失败原因)
+     */
+    private String errorMessage;
+}

+ 77 - 0
fs-service/src/main/java/com/fs/erp/domain/FsJstCodPush.java

@@ -0,0 +1,77 @@
+package com.fs.erp.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * jst货到付款推送
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FsJstCodPush {
+    /**
+     * 主键,自增
+     */
+    private Long id;
+
+    /**
+     * 订单id
+     */
+    private String orderId;
+
+    /**
+     * 售后id
+     */
+    private String afterSaleId;
+
+    /**
+     * 0创建订单 1后续金额
+     */
+    private String type;
+
+    /**
+     * 任务状态:0-待处理,1-成功,2-失败,3-正在处理,4-已取消
+     */
+    private Integer taskStatus;
+
+    /**
+     * 重试次数,默认为 0
+     */
+    private Integer retryCount;
+
+    /**
+     * 上次执行时间,用于记录任务执行的最后时间
+     */
+    private LocalDateTime lastExecuteTime;
+
+    /**
+     * 记录创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 记录更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 调用接口时传入的参数(JSON 格式)
+     */
+    private String params;
+
+    /**
+     * 调用接口返回的结果(JSON 格式)
+     */
+    private String result;
+
+    /**
+     * 错误信息(记录失败原因)
+     */
+    private String errorMessage;
+}

+ 40 - 0
fs-service/src/main/java/com/fs/erp/dto/AfterSaleConfirmRequestDTO.java

@@ -0,0 +1,40 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 售后确认请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AfterSaleConfirmRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 售后单id数组
+     */
+    private List<Long> asIds;
+
+    /**
+     * 换货售后单是否强制确认
+     */
+    private Boolean exchangeForce;
+
+    /**
+     * 是否同步确认退款单
+     */
+    private Boolean confirmRefund;
+}

+ 69 - 0
fs-service/src/main/java/com/fs/erp/dto/AfterSaleResponseDTO.java

@@ -0,0 +1,69 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 售后单响应DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AfterSaleResponseDTO implements Serializable {
+
+    private static final long serialVersionUID = -1L;
+
+    /**
+     * 响应消息
+     */
+    private String msg;
+
+    /**
+     * 售后单ID
+     */
+    private Long asId;
+
+    /**
+     * 是否成功
+     */
+    private Boolean issuccess;
+
+    /**
+     * 订单号
+     */
+    private String soId;
+
+    /**
+     * 外部售后单号
+     */
+    private String outerAsId;
+
+    /**
+     * 订单ID
+     */
+    private Long oId;
+
+    /**
+     * ID
+     */
+    private Long id;
+
+    /**
+     * 订单类型
+     */
+    private String orderType;
+
+    /**
+     * 订单授权ID
+     */
+    private String oaid;
+}

+ 45 - 0
fs-service/src/main/java/com/fs/erp/dto/AssetProcessDetailDTO.java

@@ -0,0 +1,45 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 资产处理详情对象
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AssetProcessDetailDTO {
+
+    /**
+     * 资产ID
+     */
+    private Long asId;
+
+    /**
+     * 外部资产ID
+     */
+    private String outerAsId;
+
+    /**
+     * 处理详情
+     */
+    private String details;
+
+    /**
+     * 处理消息
+     */
+    private String message;
+
+    /**
+     * 是否处理成功
+     */
+    private Boolean isSuccess;
+}

+ 42 - 0
fs-service/src/main/java/com/fs/erp/dto/AssetProcessResultDTO.java

@@ -0,0 +1,42 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 资产处理结果响应对象
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AssetProcessResultDTO {
+
+    /**
+     * 处理失败的资产列表
+     */
+    private List<AssetProcessDetailDTO> fail;
+
+    /**
+     * 处理成功的资产列表
+     */
+    private List<AssetProcessDetailDTO> success;
+
+    /**
+     * 成功处理的资产数量
+     */
+    private Integer successCount;
+
+    /**
+     * 处理失败的资产数量
+     */
+    private Integer failCount;
+}

+ 35 - 0
fs-service/src/main/java/com/fs/erp/dto/CommonResponse.java

@@ -0,0 +1,35 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 通用响应DTO
+ *
+ * @author xdd
+ * @since 2025-02-27
+ * @version 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class CommonResponse<T> implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 错误码
+     */
+    private Integer code;
+
+    /**
+     * 错误描述
+     */
+    private String msg;
+
+    /**
+     * 响应数据
+     */
+    private T data;
+}

+ 56 - 0
fs-service/src/main/java/com/fs/erp/dto/ErpOrderResponseDTO.java

@@ -0,0 +1,56 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * ERP订单返回结果DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Accessors(chain = true)
+public class ErpOrderResponseDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 订单数据列表
+     */
+    private List<OrderData> datas;
+
+    /**
+     * 订单数据实体
+     */
+    @Data
+    @Accessors(chain = true)
+    public static class OrderData implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * ERP订单界面-内部单号
+         */
+        private Integer oId;
+
+        /**
+         * ERP订单界面-线上单号
+         */
+        private String soId;
+
+        /**
+         * 是否成功
+         */
+        private Boolean issuccess;
+
+        /**
+         * 返回结果描述
+         */
+        private String msg;
+    }
+}

+ 22 - 0
fs-service/src/main/java/com/fs/erp/dto/ExtDataDTO.java

@@ -0,0 +1,22 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 扩展数据DTO
+ */
+@Data
+class ExtDataDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 公司名称
+     */
+    private String companyName;
+
+    /**
+     * 门牌号
+     */
+    private String doorPlate;
+}

+ 62 - 0
fs-service/src/main/java/com/fs/erp/dto/FinanceDataDTO.java

@@ -0,0 +1,62 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 财务数据DTO
+ */
+@Data
+class FinanceDataDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 返点费用
+     */
+    private Double rebateFee;
+
+    /**
+     * 商品税
+     */
+    private Double productTax;
+
+    /**
+     * 运输税
+     */
+    private Double shippingTax;
+
+    /**
+     * 其他收入
+     */
+    private Double otherIncome;
+
+    /**
+     * 卖家代金券
+     */
+    private Double voucherFromSeller;
+
+    /**
+     * 平台佣金
+     */
+    private Double platformCommission;
+
+    /**
+     * 过渡费
+     */
+    private Double transitionFee;
+
+    /**
+     * 交易费
+     */
+    private Double transactionFee;
+
+    /**
+     * 不透明包装费
+     */
+    private Double opaqueBaggingFee;
+
+    /**
+     * 其他支出
+     */
+    private Double otherExpense;
+}

+ 51 - 0
fs-service/src/main/java/com/fs/erp/dto/GetInitTokenRequestDTO.java

@@ -0,0 +1,51 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 获取初始化Token请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @date 2025-02-27
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class GetInitTokenRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 开发者应用Key
+     */
+    private String app_key;
+
+    /**
+     * 当前请求的时间戳(单位:秒)
+     */
+    private String timestamp;
+
+    /**
+     * 授权类型(固定值:authorization_code)
+     */
+    private String grant_type;
+
+    /**
+     * 交互数据编码(固定值:utf-8)
+     */
+    private String charset;
+
+    /**
+     * 随机码(六位随机字符串)
+     */
+    private String code;
+
+    /**
+     * 数字签名
+     */
+    private String sign;
+}

+ 41 - 0
fs-service/src/main/java/com/fs/erp/dto/GetInitTokenResponseDTO.java

@@ -0,0 +1,41 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 获取初始化Token响应DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @date 2025-02-27
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class GetInitTokenResponseDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 访问令牌
+     */
+    private String access_token;
+
+    /**
+     * access_token访问过期时间(单位:秒)
+     */
+    private Integer expires_in;
+
+    /**
+     * 更新令牌
+     */
+    private String refresh_token;
+
+    /**
+     * 权限范围(固定值:all)
+     */
+    private String scope;
+}

+ 297 - 0
fs-service/src/main/java/com/fs/erp/dto/GoodsInfoDTO.java

@@ -0,0 +1,297 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 商品信息DTO
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0.0
+ */
+@Data
+public class GoodsInfoDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 商品列表
+     */
+    private List<GoodsItem> items;
+
+    @Data
+    public static class GoodsItem implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 商品编码
+         */
+        private String skuId;
+
+        /**
+         * 款式编码
+         */
+        private String iId;
+
+        /**
+         * 品牌
+         */
+        private String brand;
+
+        /**
+         * 虚拟分类
+         */
+        private String vcName;
+
+        /**
+         * 商品分类
+         */
+        private String cName;
+
+        /**
+         * 基本售价
+         */
+        private BigDecimal sPrice;
+
+        /**
+         * 商品属性
+         */
+        private String itemType;
+
+        /**
+         * 长度
+         */
+        private BigDecimal l;
+
+        /**
+         * 宽度
+         */
+        private BigDecimal w;
+
+        /**
+         * 高度
+         */
+        private BigDecimal h;
+
+        /**
+         * 图片地址(款图片)
+         */
+        private String pic;
+
+        /**
+         * 大图地址
+         */
+        private String picBig;
+
+        /**
+         * 商品图片(SKU图片)
+         */
+        private String skuPic;
+
+        /**
+         * 商品名称
+         */
+        private String name;
+
+        /**
+         * 备注
+         */
+        private String remark;
+
+        /**
+         * 颜色及规格
+         */
+        private String propertiesValue;
+
+        /**
+         * 简称
+         */
+        private String shortName;
+
+        /**
+         * 重量
+         */
+        private BigDecimal weight;
+
+        /**
+         * 是否启用 -1=禁用,0=备用,1=启用
+         */
+        private Integer enabled;
+
+        /**
+         * 供应商名称
+         */
+        private String supplierName;
+
+        /**
+         * 国标码
+         */
+        private String skuCode;
+
+        /**
+         * 供应商商品编码
+         */
+        private String supplierSkuId;
+
+        /**
+         * 供应商款式编码
+         */
+        private String supplierIId;
+
+        /**
+         * 其它价格1
+         */
+        private BigDecimal otherPrice1;
+
+        /**
+         * 其它价格2
+         */
+        private BigDecimal otherPrice2;
+
+        /**
+         * 其它价格3
+         */
+        private BigDecimal otherPrice3;
+
+        /**
+         * 其它价格4
+         */
+        private BigDecimal otherPrice4;
+
+        /**
+         * 其它价格5
+         */
+        private BigDecimal otherPrice5;
+
+        /**
+         * 其它属性1
+         */
+        private String other1;
+
+        /**
+         * 其它属性2
+         */
+        private String other2;
+
+        /**
+         * 其它属性3
+         */
+        private String other3;
+
+        /**
+         * 其它属性4
+         */
+        private String other4;
+
+        /**
+         * 其它属性5
+         */
+        private String other5;
+
+        /**
+         * 禁止同步
+         */
+        private Boolean stockDisabled;
+
+        /**
+         * 成本价
+         */
+        private BigDecimal cPrice;
+
+        /**
+         * 市场价/吊牌价
+         */
+        private BigDecimal marketPrice;
+
+        /**
+         * 单位
+         */
+        private String unit;
+
+        /**
+         * 标签列表
+         */
+        private List<String> labels;
+
+        /**
+         * 是否启用生产批次
+         */
+        private Boolean batchEnabled;
+
+        /**
+         * 是否启用序列号
+         */
+        private Boolean isSeriesNumber;
+
+        /**
+         * 辅助码
+         */
+        private String otherCode;
+
+        /**
+         * 保质期天数
+         */
+        private Integer shelfLife;
+
+        /**
+         * 临期天数
+         */
+        private Integer handDay;
+
+        /**
+         * 保质期禁收天数
+         */
+        private Integer rejectLifecycle;
+
+        /**
+         * 保质期禁售天数
+         */
+        private Integer lockupLifecycle;
+
+        /**
+         * 保质期临期预警天数
+         */
+        private Integer adventLifecycle;
+
+        /**
+         * 商品类目属性
+         */
+        private CategoryProperty categoryPropertys;
+
+        /**
+         * 移除标签列表
+         */
+        private List<String> deletedlabels;
+
+        /**
+         * 生产许可证
+         */
+        private String productionLicence;
+
+        /**
+         * 采购价
+         */
+        private BigDecimal purchasePrice;
+
+        /**
+         * 是否校验组合装商品编码
+         */
+        private Boolean isNormal;
+    }
+
+    @Data
+    public static class CategoryProperty implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 年份
+         */
+        private String year;
+    }
+}

+ 38 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderCancelRequestDTO.java

@@ -0,0 +1,38 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 订单取消请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Accessors(chain = true)
+public class OrderCancelRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 内部订单号列表
+     * 一次最大支持50条
+     */
+    private List<Integer> oIds;
+
+    /**
+     * 取消类型
+     * 示例值:不需要了
+     */
+    private String cancelType;
+
+    /**
+     * 备注信息
+     */
+    private String remark;
+}

+ 33 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderExtDTO.java

@@ -0,0 +1,33 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 订单扩展信息DTO
+ */
+@Data
+class OrderExtDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 跟踪号
+     */
+    private String trackingNo;
+
+    /**
+     * 跟踪类型
+     */
+    private String trackingType;
+
+    /**
+     * PDF URL
+     */
+    private String pdfUrl;
+
+    /**
+     * 扩展数据列表
+     */
+    private List<OrderExtDataDTO> datas;
+}

+ 52 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderExtDataDTO.java

@@ -0,0 +1,52 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 订单扩展数据DTO
+ */
+@Data
+class OrderExtDataDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private String autoId;
+    private String iid;
+    private String skuId;
+    private String skuCode;
+    private String name;
+    private String declareNameZN;
+    private String declareNameEN;
+    private String declareAmount;
+    private String declareWeight;
+    private String hsCode;
+    private String postTaxNum;
+    private Boolean isBattery;
+    private Boolean isLiquid;
+    private Boolean isDisable;
+    private String creator;
+    private String created;
+    private String modifier;
+    private String modified;
+    private String unit;
+    private Boolean isSetSkubin;
+    private Boolean isJoinSkuid;
+    private Boolean isPaste;
+    private Boolean isMagnetic;
+    private Boolean isFluid;
+    private Boolean isGetPrice;
+    private Boolean isGetWeight;
+    private String specialAttr;
+    private String country;
+    private String tempName;
+    private String tempId;
+    private Boolean isDefault;
+    private String shopId;
+    private Boolean isOAmount;
+    private String cid;
+    private Boolean isPowder;
+    private Boolean isSpecialCargo;
+    private Boolean isJoinSkubin;
+    private String saveType;
+    private Integer declareType;
+}

+ 68 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderItemDTO.java

@@ -0,0 +1,68 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 订单商品项DTO
+ */
+@Data
+public class OrderItemDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * SKU ID
+     */
+    private String skuId;
+
+    /**
+     * 店铺SKU ID
+     */
+    private String shopSkuId;
+
+    /**
+     * 金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 基础价格
+     */
+    private Double basePrice;
+
+    /**
+     * 数量
+     */
+    private Integer qty;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 外部订单项ID
+     */
+    private String outerOiId;
+
+    /**
+     * 批次ID
+     */
+    private String batchId;
+
+    /**
+     * 生产日期
+     */
+    private String producedDate;
+
+    /**
+     * 商品属性
+     * **/
+    private String propertiesValue;
+
+    /**
+     * 款式编码
+     * **/
+    private String shopIId;
+}

Some files were not shown because too many files changed in this diff