瀏覽代碼

Merge remote-tracking branch 'origin/master' into bjcz_his_scrm

# Conflicts:
#	fs-admin/src/main/java/com/fs/his/task/Task.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
#	fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductScrmMapper.java
#	fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
#	fs-service/src/main/java/com/fs/hisStore/vo/FsStoreProductListVO.java
#	fs-service/src/main/resources/mapper/his/FsMaterialMapper.xml
yjwang 1 月之前
父節點
當前提交
ca240f357f
共有 100 個文件被更改,包括 3869 次插入848 次删除
  1. 2 2
      fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java
  2. 6 0
      fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java
  3. 20 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchCommentController.java
  4. 2 2
      fs-admin/src/main/java/com/fs/course/controller/FsUserWatchCourseStatisticsController.java
  5. 1 0
      fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  6. 54 0
      fs-admin/src/main/java/com/fs/crm/controller/ReportController.java
  7. 97 0
      fs-admin/src/main/java/com/fs/fastGpt/FastGptChatReplaceTextController.java
  8. 112 0
      fs-admin/src/main/java/com/fs/fastGpt/FastGptKeywordSendController.java
  9. 139 0
      fs-admin/src/main/java/com/fs/fastGpt/FastgptEventLogTotalController.java
  10. 126 0
      fs-admin/src/main/java/com/fs/fastGpt/FastgptExtUserTagController.java
  11. 8 5
      fs-admin/src/main/java/com/fs/his/controller/FsFirstDiagnosisController.java
  12. 103 0
      fs-admin/src/main/java/com/fs/his/controller/FsHfpayConfigController.java
  13. 99 0
      fs-admin/src/main/java/com/fs/his/controller/FsHomeArticleCategoryController.java
  14. 94 0
      fs-admin/src/main/java/com/fs/his/controller/FsHomeArticleController.java
  15. 93 0
      fs-admin/src/main/java/com/fs/his/controller/FsHomeArticleViewController.java
  16. 2 0
      fs-admin/src/main/java/com/fs/his/controller/FsPackageOrderController.java
  17. 5 3
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  18. 3 0
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  19. 220 9
      fs-admin/src/main/java/com/fs/his/task/Task.java
  20. 12 4
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java
  21. 39 3
      fs-admin/src/main/java/com/fs/qw/controller/QwExternalContactController.java
  22. 12 0
      fs-admin/src/main/java/com/fs/qw/controller/QwTagGroupController.java
  23. 62 0
      fs-admin/src/main/java/com/fs/stats/FsStatsMemberController.java
  24. 9 8
      fs-common-api/src/main/java/com/fs/framework/config/MyBatisConfig.java
  25. 7 6
      fs-common/src/main/java/com/fs/common/utils/CloudHostUtils.java
  26. 8 1
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  27. 13 0
      fs-company-app/src/main/java/com/fs/app/exception/FSExceptionHandler.java
  28. 4 0
      fs-company-app/src/main/java/com/fs/core/config/RedisConfig.java
  29. 25 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyRechargeController.java
  30. 178 3
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  31. 26 4
      fs-company/src/main/java/com/fs/company/controller/company/FsDoctorController.java
  32. 1 0
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java
  33. 1 0
      fs-company/src/main/java/com/fs/company/controller/course/qw/FsQwCourseWatchLogController.java
  34. 134 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptKeywordSendController.java
  35. 148 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastgptEventLogTotalController.java
  36. 13 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopController.java
  37. 99 8
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java
  38. 69 13
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java
  39. 41 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserVoiceLogController.java
  40. 53 6
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java
  41. 136 35
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsInfoController.java
  42. 4 2
      fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java
  43. 1 1
      fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java
  44. 1 0
      fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java
  45. 74 6
      fs-doctor-app/src/main/java/com/fs/app/controller/DoctorController.java
  46. 7 6
      fs-doctor-app/src/main/java/com/fs/framework/config/MyBatisConfig.java
  47. 14 2
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  48. 118 41
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  49. 0 12
      fs-qw-api/src/main/java/com/fs/app/service/QwDataCallbackService.java
  50. 19 2
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  51. 14 11
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  52. 72 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwUserController.java
  53. 70 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/QwUserController.java
  54. 16 0
      fs-qwhook-sop/src/main/java/com/fs/app/params/LoginBindCompanyParam.java
  55. 8 7
      fs-qwhook-sop/src/main/java/com/fs/framework/config/MyBatisConfig.java
  56. 72 0
      fs-qwhook/src/main/java/com/fs/app/controller/ApisQwUserController.java
  57. 74 3
      fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java
  58. 17 0
      fs-qwhook/src/main/java/com/fs/app/params/LoginBindCompanyParam.java
  59. 2 0
      fs-service/src/main/java/com/fs/aiTongueApi/config/AiTongueConfig.java
  60. 58 0
      fs-service/src/main/java/com/fs/aiTongueApi/domain/enums/TongueTypeEnums.java
  61. 14 0
      fs-service/src/main/java/com/fs/aiTongueApi/domain/inner/ConfidenceDataNew.java
  62. 14 0
      fs-service/src/main/java/com/fs/aiTongueApi/domain/inner/TongueInfo.java
  63. 3 0
      fs-service/src/main/java/com/fs/aiTongueApi/service/AiTongueService.java
  64. 187 2
      fs-service/src/main/java/com/fs/aiTongueApi/service/impl/AiTongueServiceImpl.java
  65. 4 149
      fs-service/src/main/java/com/fs/company/domain/CompanyRecharge.java
  66. 5 2
      fs-service/src/main/java/com/fs/company/domain/CompanyUser.java
  67. 2 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyDeptMapper.java
  68. 2 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  69. 1 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyRoleMapper.java
  70. 6 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  71. 1 0
      fs-service/src/main/java/com/fs/company/param/CompanyRechargeParam.java
  72. 131 0
      fs-service/src/main/java/com/fs/company/param/CompanyUserCodeParam.java
  73. 7 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  74. 10 0
      fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java
  75. 18 5
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  76. 326 12
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  77. 17 350
      fs-service/src/main/java/com/fs/company/vo/CompanyUserImportVO.java
  78. 3 0
      fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java
  79. 2 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVO.java
  80. 36 6
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  81. 1 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoRedPackageMapper.java
  82. 5 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  83. 2 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogStatisticsListParam.java
  84. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseLinkService.java
  85. 8 8
      fs-service/src/main/java/com/fs/course/service/IFsCourseProductOrderService.java
  86. 1 1
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseOrderService.java
  87. 1 1
      fs-service/src/main/java/com/fs/course/service/IFsUserVipOrderService.java
  88. 14 7
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  89. 10 8
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java
  90. 21 27
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseTrafficLogServiceImpl.java
  91. 8 1
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  92. 5 3
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java
  93. 1 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodDaysServiceImpl.java
  94. 2 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
  95. 5 3
      fs-service/src/main/java/com/fs/course/service/impl/FsUserVipOrderServiceImpl.java
  96. 67 57
      fs-service/src/main/java/com/fs/course/service/impl/FsUserWatchStatisticsServiceImpl.java
  97. 3 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchCommentVO.java
  98. 2 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogStatisticsListVO.java
  99. 3 0
      fs-service/src/main/java/com/fs/course/vo/FsFirstDiagnosisListUVO.java
  100. 2 0
      fs-service/src/main/java/com/fs/course/vo/FsInquiryPatientInfoListUVO.java

+ 2 - 2
fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java

@@ -64,10 +64,10 @@ public class IndexStatisticsController {
     @GetMapping("/trafficLog")
     public R getTrafficLog(){
         TrafficLogDTO trafficLogDTO = redisCache.getCacheObject(DATA_OVERVIEW_TRAFFIC_LOG);
-        if(trafficLogDTO == null) {
+        SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");
+        if(trafficLogDTO == null || sysConfig == null) {
             return null;
         }
-        SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");
         String configValue = sysConfig.getConfigValue();
         trafficLogDTO.setTraffic(configValue);
         return R.ok().put("data",trafficLogDTO);

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

@@ -2,10 +2,12 @@ package com.fs.course.controller;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.bean.BeanUtils;
@@ -112,4 +114,8 @@ public class FsCoursePlaySourceConfigController extends BaseController {
         fsCoursePlaySourceConfigService.update(updateWrapper);
         return AjaxResult.success();
     }
+    @GetMapping("/listAll")
+    public R listAll() {
+        return R.ok().put("data", fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().eq("is_del", 0)));
+    }
 }

+ 20 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchCommentController.java

@@ -70,6 +70,14 @@ public class FsCourseWatchCommentController extends BaseController
         return util.exportExcel(list, "看课评论数据");
     }
 
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:edit')")
+    @Log(title = "看课评论", businessType = BusinessType.UPDATE)
+    @PutMapping("/updateBarrageStatus")
+    public AjaxResult updateBarrageStatus(@RequestBody FsCourseWatchComment fsCourseWatchComment)
+    {
+        return toAjax(fsCourseWatchCommentService.updateFsCourseWatchComment(fsCourseWatchComment));
+    }
+
     /**
      * 获取看课评论详细信息
      */
@@ -125,4 +133,16 @@ public class FsCourseWatchCommentController extends BaseController
         }
     }
 
+    @Log(title = "手动解除外部联系人拉黑用户", businessType = BusinessType.UPDATE)
+    @PutMapping("/clearBlack")
+    public R clearBlack(Integer commentStatus, Long fsUserId)
+    {
+        int i = qwExternalContactService.updateQwExternalContactByFsUserId(commentStatus, fsUserId);
+        if (i > 0){
+            return R.ok();
+        } else {
+            return R.error();
+        }
+    }
+
 }

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

@@ -118,9 +118,9 @@ public class FsUserWatchCourseStatisticsController extends BaseController
     }
 
     /**
-     * 导出会员看课统计-按课程汇总统计列表
+     * 导出会员观看数据明细汇总
      */
-    @Log(title = "会员看课统计-按课程汇总统计", businessType = BusinessType.EXPORT)
+    @Log(title = "会员观看数据明细汇总", businessType = BusinessType.EXPORT)
     @GetMapping("/exportTotal")
     public AjaxResult exportTotal(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
     {

+ 1 - 0
fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java

@@ -71,6 +71,7 @@ public class QwFsCourseWatchLogController extends BaseController
         if (param.getSTime()==null||param.getETime()==null){
             return getDataTable(new ArrayList<>());
         }
+        param.setSendType(2); //企微
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         return getDataTable(list);
     }

+ 54 - 0
fs-admin/src/main/java/com/fs/crm/controller/ReportController.java

@@ -0,0 +1,54 @@
+package com.fs.crm.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.crm.domain.Report;
+import com.fs.framework.web.service.TokenService;
+import com.fs.crm.param.ReportParam;
+import com.fs.crm.service.ReportService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+@RestController
+@RequestMapping("/crm/report")
+public class ReportController extends BaseController {
+    @Autowired
+    private ReportService reportService;
+    @Autowired
+    private TokenService tokenService;
+    @GetMapping("/reportList")
+    public TableDataInfo getReport(ReportParam param, HttpServletRequest request)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        Long userId = loginUser.getUser().getUserId();
+        param.setCompanyUserId(userId);
+        List<Report> list = reportService.getReport(param);
+        return getDataTable(list);
+    }
+    @GetMapping("/export")
+    public AjaxResult export(ReportParam param,HttpServletRequest request)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(request);
+
+        Long userId = loginUser.getUser().getUserId();
+        param.setCompanyUserId(userId);
+        List<Report> list = reportService.getReport(param);
+        if (CollectionUtils.isEmpty(list)){
+            return AjaxResult.error("请选择导出数据");
+        }
+        ExcelUtil<Report> util = new ExcelUtil<Report>(Report.class);
+        return util.exportExcel(list, "report");
+    }
+
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/fastGpt/FastGptChatReplaceTextController.java

@@ -0,0 +1,97 @@
+package com.fs.fastGpt;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.fastGpt.domain.FastGptChatReplaceText;
+import com.fs.fastGpt.service.IFastGptChatReplaceTextService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 易错词语Controller
+ *
+ * @author fs
+ * @date 2025-01-18
+ */
+@RestController
+@RequestMapping("/fastGpt/fastGptChatReplaceText")
+public class FastGptChatReplaceTextController extends BaseController
+{
+    @Autowired
+    private IFastGptChatReplaceTextService fastGptChatReplaceTextService;
+
+    /**
+     * 查询易错词语列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptChatReplaceText:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FastGptChatReplaceText fastGptChatReplaceText)
+    {
+        startPage();
+        List<FastGptChatReplaceText> list = fastGptChatReplaceTextService.selectFastGptChatReplaceTextList(fastGptChatReplaceText);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出易错词语列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptChatReplaceText:export')")
+    @Log(title = "易错词语", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FastGptChatReplaceText fastGptChatReplaceText)
+    {
+        List<FastGptChatReplaceText> list = fastGptChatReplaceTextService.selectFastGptChatReplaceTextList(fastGptChatReplaceText);
+        ExcelUtil<FastGptChatReplaceText> util = new ExcelUtil<FastGptChatReplaceText>(FastGptChatReplaceText.class);
+        return util.exportExcel(list, "易错词语数据");
+    }
+
+    /**
+     * 获取易错词语详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptChatReplaceText:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fastGptChatReplaceTextService.selectFastGptChatReplaceTextById(id));
+    }
+
+    /**
+     * 新增易错词语
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptChatReplaceText:add')")
+    @Log(title = "易错词语", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FastGptChatReplaceText fastGptChatReplaceText)
+    {
+        return toAjax(fastGptChatReplaceTextService.insertFastGptChatReplaceText(fastGptChatReplaceText));
+    }
+
+    /**
+     * 修改易错词语
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptChatReplaceText:edit')")
+    @Log(title = "易错词语", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FastGptChatReplaceText fastGptChatReplaceText)
+    {
+        return toAjax(fastGptChatReplaceTextService.updateFastGptChatReplaceText(fastGptChatReplaceText));
+    }
+
+    /**
+     * 删除易错词语
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptChatReplaceText:remove')")
+    @Log(title = "易错词语", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fastGptChatReplaceTextService.deleteFastGptChatReplaceTextByIds(ids));
+    }
+}

+ 112 - 0
fs-admin/src/main/java/com/fs/fastGpt/FastGptKeywordSendController.java

@@ -0,0 +1,112 @@
+package com.fs.fastGpt;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.fastGpt.domain.FastGptKeyword;
+import com.fs.fastGpt.domain.FastGptKeywordSend;
+import com.fs.fastGpt.service.IFastGptKeywordSendService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * Ai事件表(根据关键字发送文本和图片)Controller
+ * 
+ * @author fs
+ * @date 2025-05-12
+ */
+@RestController
+@RequestMapping("/fastGpt/fastGptKeywordSend")
+public class FastGptKeywordSendController extends BaseController
+{
+    @Autowired
+    private IFastGptKeywordSendService fastGptKeywordSendService;
+
+    @GetMapping("/keywordList")
+    public R keywordList()
+    {
+        List<FastGptKeyword> list = fastGptKeywordSendService.selectFastGptKeywordList(1);
+        return R.ok().put("data",list);
+    }
+    /**
+     * 查询Ai事件表(根据关键字发送文本和图片)列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FastGptKeywordSend fastGptKeywordSend)
+    {
+        startPage();
+        fastGptKeywordSend.setKeywordType(1L);
+        List<FastGptKeywordSend> list = fastGptKeywordSendService.selectFastGptKeywordSendList(fastGptKeywordSend);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出Ai事件表(根据关键字发送文本和图片)列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:export')")
+    @Log(title = "Ai事件表(根据关键字发送文本和图片)", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FastGptKeywordSend fastGptKeywordSend)
+    {
+        fastGptKeywordSend.setKeywordType(1L);
+        List<FastGptKeywordSend> list = fastGptKeywordSendService.selectFastGptKeywordSendList(fastGptKeywordSend);
+        ExcelUtil<FastGptKeywordSend> util = new ExcelUtil<FastGptKeywordSend>(FastGptKeywordSend.class);
+        return util.exportExcel(list, "Ai事件表(根据关键字发送文本和图片)数据");
+    }
+
+    /**
+     * 获取Ai事件表(根据关键字发送文本和图片)详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        Long keywordType = 1L;
+        return AjaxResult.success(fastGptKeywordSendService.selectFastGptKeywordSendById(id,keywordType));
+    }
+
+    /**
+     * 新增Ai事件表(根据关键字发送文本和图片)
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:add')")
+    @Log(title = "Ai事件表(根据关键字发送文本和图片)", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FastGptKeywordSend fastGptKeywordSend)
+    {
+        fastGptKeywordSend.setKeywordType(1L);
+        fastGptKeywordSend.setRoleIds(null);
+        return toAjax(fastGptKeywordSendService.insertFastGptKeywordSend(fastGptKeywordSend));
+    }
+
+    /**
+     * 修改Ai事件表(根据关键字发送文本和图片)
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:edit')")
+    @Log(title = "Ai事件表(根据关键字发送文本和图片)", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FastGptKeywordSend fastGptKeywordSend)
+    {
+        fastGptKeywordSend.setKeywordType(1L);
+        fastGptKeywordSend.setRoleIds(null);
+        return toAjax(fastGptKeywordSendService.updateFastGptKeywordSend(fastGptKeywordSend));
+    }
+
+    /**
+     * 删除Ai事件表(根据关键字发送文本和图片)
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:remove')")
+    @Log(title = "Ai事件表(根据关键字发送文本和图片)", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fastGptKeywordSendService.deleteFastGptKeywordSendByIds(ids));
+    }
+}

+ 139 - 0
fs-admin/src/main/java/com/fs/fastGpt/FastgptEventLogTotalController.java

@@ -0,0 +1,139 @@
+package com.fs.fastGpt;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
+import com.fs.fastGpt.param.FastgptEventLogTotalParam;
+import com.fs.fastGpt.service.IFastGptRoleService;
+import com.fs.fastGpt.service.IFastgptEventLogTotalService;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * ai事件埋点统计Controller
+ * 
+ * @author fs
+ * @date 2025-06-26
+ */
+@RestController
+@RequestMapping("/fastGpt/fastgptEventLogTotal")
+public class FastgptEventLogTotalController extends BaseController
+{
+    @Autowired
+    private IFastgptEventLogTotalService fastgptEventLogTotalService;
+
+    @Autowired
+    private IFastGptRoleService roleService;
+
+    /**
+     * 查询ai事件埋点统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:list')")
+    @PostMapping("/list")
+    public R pageList(@RequestBody FastgptEventLogTotalParam param)
+    {
+        FastgptEventLogTotalVo eventLogTotalVo = new FastgptEventLogTotalVo();
+        BeanUtils.copyProperties(param,eventLogTotalVo);
+        List<FastgptEventLogTotalVo> list = fastgptEventLogTotalService.selectFastgptEventLogTotalVoInfoList(eventLogTotalVo);
+
+        //统计对应的list的合
+        FastgptEventLogTotalVo totalVo = fastgptEventLogTotalService.totalFastgptEventLog(list);
+
+        int pageNum = param.getPageNum();
+        int pageSize = param.getPageSize();
+
+        int total = 0;
+        if (list != null) {
+            total = list.size();
+        }
+
+        int fromIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(fromIndex + pageSize, total);
+        PageInfo<FastgptEventLogTotalVo> pageInfo = new PageInfo<>();
+        if (list != null) {
+            List<FastgptEventLogTotalVo> paginatedList = list.subList(fromIndex, toIndex);
+            if(totalVo != null){
+                paginatedList.add(totalVo);
+            }
+            pageInfo = new PageInfo<>(paginatedList);
+        }else{
+            pageInfo = new PageInfo<>();
+        }
+        pageInfo.setTotal(total);
+        return R.ok().put("data",pageInfo);
+    }
+
+    /**
+     * 查询appKey
+     * @return  list
+     */
+    @GetMapping("/getFastGptRoleAppKeyList")
+    public R getFastGptRoleAppKeyList() {
+        return R.ok().put("data", roleService.selectFastGptRoleAppKeyList());
+    }
+    /**
+     * 导出ai事件埋点统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:export')")
+    @Log(title = "ai事件埋点统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        List<FastgptEventLogTotal> list = fastgptEventLogTotalService.selectFastgptEventLogTotalList(fastgptEventLogTotal);
+        ExcelUtil<FastgptEventLogTotal> util = new ExcelUtil<FastgptEventLogTotal>(FastgptEventLogTotal.class);
+        return util.exportExcel(list, "ai事件埋点统计数据");
+    }
+
+    /**
+     * 获取ai事件埋点统计详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fastgptEventLogTotalService.selectFastgptEventLogTotalById(id));
+    }
+
+    /**
+     * 新增ai事件埋点统计
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:add')")
+    @Log(title = "ai事件埋点统计", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        return toAjax(fastgptEventLogTotalService.insertFastgptEventLogTotal(fastgptEventLogTotal));
+    }
+
+    /**
+     * 修改ai事件埋点统计
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:edit')")
+    @Log(title = "ai事件埋点统计", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        return toAjax(fastgptEventLogTotalService.updateFastgptEventLogTotal(fastgptEventLogTotal));
+    }
+
+    /**
+     * 删除ai事件埋点统计
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:remove')")
+    @Log(title = "ai事件埋点统计", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fastgptEventLogTotalService.deleteFastgptEventLogTotalByIds(ids));
+    }
+}

+ 126 - 0
fs-admin/src/main/java/com/fs/fastGpt/FastgptExtUserTagController.java

@@ -0,0 +1,126 @@
+package com.fs.fastGpt;
+
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import com.fs.fastGpt.vo.FastgptExtUserTagVO;
+import com.fs.framework.web.service.TokenService;
+import com.fs.qw.service.IQwCompanyService;
+import com.fs.qw.vo.QwOptionsVO;
+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.fastGpt.domain.FastgptExtUserTag;
+import com.fs.fastGpt.service.IFastgptExtUserTagService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 处理新客标签Controller
+ * 
+ * @author fs
+ * @date 2025-09-10
+ */
+@RestController
+@RequestMapping("/fastGpt/FastGptExtUserTag")
+public class FastgptExtUserTagController extends BaseController
+{
+    @Autowired
+    private IFastgptExtUserTagService fastgptExtUserTagService;
+
+
+    @Autowired
+    private IQwCompanyService qwCompanyService;
+
+
+    /**
+     * 查询处理新客标签列表
+     */
+    @PreAuthorize("@ss.hasPermi('FastGptExtUserTag:FastGptExtUserTag:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FastgptExtUserTag fastgptExtUserTag)
+    {
+        startPage();
+        List<FastgptExtUserTag> list = fastgptExtUserTagService.selectFastgptExtUserTagList(fastgptExtUserTag);
+        return getDataTable(list);
+    }
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:addTag')")
+    @Log(title = "添加标签", businessType = BusinessType.UPDATE)
+    @PostMapping("/addFastGptTagByCorpId")
+    public R addFastGptTagByCorpId(@RequestBody FastgptExtUserTagVO fastgptExtUserTag) {
+        return fastgptExtUserTagService.addFastGptTagByCorpId(fastgptExtUserTag);
+    }
+    @GetMapping("/getMyQwUserList")
+    public R getMyQwUserList()
+    {
+        List<QwOptionsVO> list = qwCompanyService.selectQwCompanyListOptionsVO();
+        return  R.ok().put("data",list);
+    }
+
+    /**
+     * 导出处理新客标签列表
+     */
+    @PreAuthorize("@ss.hasPermi('FastGptExtUserTag:FastGptExtUserTag:export')")
+    @Log(title = "处理新客标签", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FastgptExtUserTag fastgptExtUserTag)
+    {
+        List<FastgptExtUserTag> list = fastgptExtUserTagService.selectFastgptExtUserTagList(fastgptExtUserTag);
+        ExcelUtil<FastgptExtUserTag> util = new ExcelUtil<FastgptExtUserTag>(FastgptExtUserTag.class);
+        return util.exportExcel(list, "处理新客标签数据");
+    }
+
+    /**
+     * 获取处理新客标签详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('FastGptExtUserTag:FastGptExtUserTag:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fastgptExtUserTagService.selectFastgptExtUserTagById(id));
+    }
+
+    /**
+     * 新增处理新客标签
+     */
+    @PreAuthorize("@ss.hasPermi('FastGptExtUserTag:FastGptExtUserTag:add')")
+    @Log(title = "处理新客标签", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FastgptExtUserTag fastgptExtUserTag)
+    {
+        return toAjax(fastgptExtUserTagService.insertFastgptExtUserTag(fastgptExtUserTag));
+    }
+
+    /**
+     * 修改处理新客标签
+     */
+    @PreAuthorize("@ss.hasPermi('FastGptExtUserTag:FastGptExtUserTag:edit')")
+    @Log(title = "处理新客标签", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FastgptExtUserTag fastgptExtUserTag)
+    {
+        return toAjax(fastgptExtUserTagService.updateFastgptExtUserTag(fastgptExtUserTag));
+    }
+
+    /**
+     * 删除处理新客标签
+     */
+    @PreAuthorize("@ss.hasPermi('FastGptExtUserTag:FastGptExtUserTag:remove')")
+    @Log(title = "处理新客标签", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fastgptExtUserTagService.deleteFastgptExtUserTagByIds(ids));
+    }
+}

+ 8 - 5
fs-admin/src/main/java/com/fs/his/controller/FsFirstDiagnosisController.java

@@ -1,6 +1,9 @@
 package com.fs.his.controller;
 
 import java.util.List;
+
+import com.fs.his.param.FsFirstDiagnosisParam;
+import com.fs.his.vo.FsFirstDiagnosisVO;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -38,10 +41,10 @@ public class FsFirstDiagnosisController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('his:fsFirstDiagnosis:list')")
     @GetMapping("/list")
-    public TableDataInfo list(FsFirstDiagnosis fsFirstDiagnosis)
+    public TableDataInfo list(FsFirstDiagnosisParam fsFirstDiagnosis)
     {
         startPage();
-        List<FsFirstDiagnosis> list = fsFirstDiagnosisService.selectFsFirstDiagnosisList(fsFirstDiagnosis);
+        List<FsFirstDiagnosisVO> list = fsFirstDiagnosisService.selectFsFirstDiagnosisVOList(fsFirstDiagnosis);
         return getDataTable(list);
     }
 
@@ -51,10 +54,10 @@ public class FsFirstDiagnosisController extends BaseController
     @PreAuthorize("@ss.hasPermi('his:fsFirstDiagnosis:export')")
     @Log(title = "初诊单", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(FsFirstDiagnosis fsFirstDiagnosis)
+    public AjaxResult export(FsFirstDiagnosisParam fsFirstDiagnosis)
     {
-        List<FsFirstDiagnosis> list = fsFirstDiagnosisService.selectFsFirstDiagnosisList(fsFirstDiagnosis);
-        ExcelUtil<FsFirstDiagnosis> util = new ExcelUtil<FsFirstDiagnosis>(FsFirstDiagnosis.class);
+        List<FsFirstDiagnosisVO> list = fsFirstDiagnosisService.selectFsFirstDiagnosisVOList(fsFirstDiagnosis);
+        ExcelUtil<FsFirstDiagnosisVO> util = new ExcelUtil<FsFirstDiagnosisVO>(FsFirstDiagnosisVO.class);
         return util.exportExcel(list, "初诊单数据");
     }
 

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

@@ -0,0 +1,103 @@
+package com.fs.his.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.his.domain.FsHfpayConfig;
+import com.fs.his.service.IFsHfpayConfigService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 汇付多支付配置Controller
+ * 
+ * @author fs
+ * @date 2025-09-10
+ */
+@RestController
+@RequestMapping("/his/hfpayConfig")
+public class FsHfpayConfigController extends BaseController
+{
+    @Autowired
+    private IFsHfpayConfigService fsHfpayConfigService;
+
+    /**
+     * 查询汇付多支付配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsHfpayConfig fsHfpayConfig)
+    {
+        startPage();
+        List<FsHfpayConfig> list = fsHfpayConfigService.selectFsHfpayConfigList(fsHfpayConfig);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出汇付多支付配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:export')")
+    @Log(title = "汇付多支付配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsHfpayConfig fsHfpayConfig)
+    {
+        List<FsHfpayConfig> list = fsHfpayConfigService.selectFsHfpayConfigList(fsHfpayConfig);
+        ExcelUtil<FsHfpayConfig> util = new ExcelUtil<FsHfpayConfig>(FsHfpayConfig.class);
+        return util.exportExcel(list, "汇付多支付配置数据");
+    }
+
+    /**
+     * 获取汇付多支付配置详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsHfpayConfigService.selectFsHfpayConfigById(id));
+    }
+
+    /**
+     * 新增汇付多支付配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:add')")
+    @Log(title = "汇付多支付配置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsHfpayConfig fsHfpayConfig)
+    {
+        return toAjax(fsHfpayConfigService.insertFsHfpayConfig(fsHfpayConfig));
+    }
+
+    /**
+     * 修改汇付多支付配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:edit')")
+    @Log(title = "汇付多支付配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsHfpayConfig fsHfpayConfig)
+    {
+        return toAjax(fsHfpayConfigService.updateFsHfpayConfig(fsHfpayConfig));
+    }
+
+    /**
+     * 删除汇付多支付配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:hfpayConfig:remove')")
+    @Log(title = "汇付多支付配置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsHfpayConfigService.deleteFsHfpayConfigByIds(ids));
+    }
+}

+ 99 - 0
fs-admin/src/main/java/com/fs/his/controller/FsHomeArticleCategoryController.java

@@ -0,0 +1,99 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsHomeArticleCategoryScrm;
+import com.fs.hisStore.service.IFsHomeArticleCategoryScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 期刊分类Controller
+ *
+ * @author fs
+ * @date 2025-05-21
+ */
+@RestController
+@RequestMapping("/his/homeCategory")
+public class FsHomeArticleCategoryController extends BaseController {
+    @Autowired
+    private IFsHomeArticleCategoryScrmService fsHomeArticleCategoryService;
+
+    /**
+     * 查询期刊分类列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeCategory:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsHomeArticleCategoryScrm fsHomeArticleCategory) {
+        startPage();
+        List<FsHomeArticleCategoryScrm> list = fsHomeArticleCategoryService.selectFsHomeArticleCategoryList(fsHomeArticleCategory);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出期刊分类列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeCategory:export')")
+    @Log(title = "期刊分类", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsHomeArticleCategoryScrm fsHomeArticleCategory) {
+        List<FsHomeArticleCategoryScrm> list = fsHomeArticleCategoryService.selectFsHomeArticleCategoryList(fsHomeArticleCategory);
+        ExcelUtil<FsHomeArticleCategoryScrm> util = new ExcelUtil<FsHomeArticleCategoryScrm>(FsHomeArticleCategoryScrm.class);
+        return util.exportExcel(list, "homeCategory");
+    }
+
+    /**
+     * 获取期刊分类详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeCategory:query')")
+    @GetMapping(value = "/{categoryId}")
+    public AjaxResult getInfo(@PathVariable("categoryId") Long categoryId) {
+        return AjaxResult.success(fsHomeArticleCategoryService.selectFsHomeArticleCategoryById(categoryId));
+    }
+
+    /**
+     * 新增期刊分类
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeCategory:add')")
+    @Log(title = "期刊分类", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsHomeArticleCategoryScrm fsHomeArticleCategory) {
+        return toAjax(fsHomeArticleCategoryService.insertFsHomeArticleCategory(fsHomeArticleCategory));
+    }
+
+    /**
+     * 修改期刊分类
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeCategory:edit')")
+    @Log(title = "期刊分类", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsHomeArticleCategoryScrm fsHomeArticleCategory) {
+        return toAjax(fsHomeArticleCategoryService.updateFsHomeArticleCategory(fsHomeArticleCategory));
+    }
+
+    /**
+     * 删除期刊分类
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeCategory:remove')")
+    @Log(title = "期刊分类", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{categoryIds}")
+    public AjaxResult remove(@PathVariable Long[] categoryIds) {
+        return toAjax(fsHomeArticleCategoryService.deleteFsHomeArticleCategoryByIds(categoryIds));
+    }
+
+    @GetMapping("/allList")
+    public R getAllList(FsHomeArticleCategoryScrm fsHomeArticleCategory) {
+        fsHomeArticleCategory.setStatus(1);
+        List<FsHomeArticleCategoryScrm> list = fsHomeArticleCategoryService.selectFsHomeArticleCategoryList(fsHomeArticleCategory);
+        return R.ok().put("rows", list);
+    }
+
+}

+ 94 - 0
fs-admin/src/main/java/com/fs/his/controller/FsHomeArticleController.java

@@ -0,0 +1,94 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsHomeArticleScrm;
+import com.fs.hisStore.service.IFsHomeArticleScrmService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 期刊Controller
+ *
+ * @author fs
+ * @date 2025-05-21
+ */
+@RestController
+@RequestMapping("/his/homeArticle")
+public class FsHomeArticleController extends BaseController {
+    @Autowired
+    private IFsHomeArticleScrmService fsHomeArticleService;
+
+    /**
+     * 查询期刊列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeArticle:list')")
+    @GetMapping("/list")
+    public R list(FsHomeArticleScrm fsHomeArticle)
+    {
+        PageHelper.startPage(fsHomeArticle.getPageNum(), fsHomeArticle.getPageSize());
+        List<FsHomeArticleScrm> list = fsHomeArticleService.selectFsHomeArticleList(fsHomeArticle);
+        PageInfo<FsHomeArticleScrm> listPageInfo = new PageInfo<>(list);
+        return R.ok().put("rows", listPageInfo);
+    }
+
+    /**
+     * 导出期刊列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeArticle:export')")
+    @Log(title = "期刊", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsHomeArticleScrm fsHomeArticle) {
+        List<FsHomeArticleScrm> list = fsHomeArticleService.selectFsHomeArticleList(fsHomeArticle);
+        ExcelUtil<FsHomeArticleScrm> util = new ExcelUtil<FsHomeArticleScrm>(FsHomeArticleScrm.class);
+        return util.exportExcel(list, "homArticle");
+    }
+
+    /**
+     * 获取期刊详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeArticle:query')")
+    @GetMapping(value = "/{articleId}")
+    public AjaxResult getInfo(@PathVariable("articleId") Long articleId) {
+        return AjaxResult.success(fsHomeArticleService.selectFsHomeArticleById(articleId));
+    }
+
+    /**
+     * 新增期刊
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeArticle:add')")
+    @Log(title = "期刊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsHomeArticleScrm fsHomeArticle) {
+        return toAjax(fsHomeArticleService.insertFsHomeArticle(fsHomeArticle));
+    }
+
+    /**
+     * 修改期刊
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeArticle:edit')")
+    @Log(title = "期刊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsHomeArticleScrm fsHomeArticle) {
+        return toAjax(fsHomeArticleService.updateFsHomeArticle(fsHomeArticle));
+    }
+
+    /**
+     * 删除期刊
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeArticle:remove')")
+    @Log(title = "期刊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{articleIds}")
+    public AjaxResult remove(@PathVariable Long[] articleIds) {
+        return toAjax(fsHomeArticleService.deleteFsHomeArticleByIds(articleIds));
+    }
+}

+ 93 - 0
fs-admin/src/main/java/com/fs/his/controller/FsHomeArticleViewController.java

@@ -0,0 +1,93 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsHomeArticleViewScrm;
+import com.fs.hisStore.service.IFsHomeArticleViewScrmService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 期刊阅读Controller
+ *
+ * @author fs
+ * @date 2025-05-21
+ */
+@RestController
+@RequestMapping("/his/homeView")
+public class FsHomeArticleViewController extends BaseController {
+    @Autowired
+    private IFsHomeArticleViewScrmService fsHomeArticleViewService;
+
+    /**
+     * 查询期刊阅读列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeView:list')")
+    @GetMapping("/list")
+    public R list(FsHomeArticleViewScrm fsHomeArticleView) {
+        PageHelper.startPage(fsHomeArticleView.getPageNum(), fsHomeArticleView.getPageSize());
+        List<FsHomeArticleViewScrm> list = fsHomeArticleViewService.selectFsHomeArticleViewList(fsHomeArticleView);
+        PageInfo<FsHomeArticleViewScrm> listPageInfo = new PageInfo<>(list);
+        return R.ok().put("rows", listPageInfo);
+    }
+
+    /**
+     * 导出期刊阅读列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeView:export')")
+    @Log(title = "期刊阅读", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsHomeArticleViewScrm fsHomeArticleView) {
+        List<FsHomeArticleViewScrm> list = fsHomeArticleViewService.selectFsHomeArticleViewList(fsHomeArticleView);
+        ExcelUtil<FsHomeArticleViewScrm> util = new ExcelUtil<FsHomeArticleViewScrm>(FsHomeArticleViewScrm.class);
+        return util.exportExcel(list, "homeView");
+    }
+
+    /**
+     * 获取期刊阅读详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeView:query')")
+    @GetMapping(value = "/{viewId}")
+    public AjaxResult getInfo(@PathVariable("viewId") Long viewId) {
+        return AjaxResult.success(fsHomeArticleViewService.selectFsHomeArticleViewById(viewId));
+    }
+
+    /**
+     * 新增期刊阅读
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeView:add')")
+    @Log(title = "期刊阅读", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsHomeArticleViewScrm fsHomeArticleView) {
+        return toAjax(fsHomeArticleViewService.insertFsHomeArticleView(fsHomeArticleView));
+    }
+
+    /**
+     * 修改期刊阅读
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeView:edit')")
+    @Log(title = "期刊阅读", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsHomeArticleViewScrm fsHomeArticleView) {
+        return toAjax(fsHomeArticleViewService.updateFsHomeArticleView(fsHomeArticleView));
+    }
+
+    /**
+     * 删除期刊阅读
+     */
+    @PreAuthorize("@ss.hasPermi('store:homeView:remove')")
+    @Log(title = "期刊阅读", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{viewIds}")
+    public AjaxResult remove(@PathVariable Long[] viewIds) {
+        return toAjax(fsHomeArticleViewService.deleteFsHomeArticleViewByIds(viewIds));
+    }
+}

+ 2 - 0
fs-admin/src/main/java/com/fs/his/controller/FsPackageOrderController.java

@@ -77,6 +77,7 @@ public class FsPackageOrderController extends BaseController
     @GetMapping("/export")
     public AjaxResult export(FsPackageOrderParam  fsPackageOrder)
     {
+        Integer status = fsPackageOrder.getStatus();
         Integer exportType1 = exportTaskService.isExportType1(SecurityUtils.getUserId());
         if (exportType1>0){
             return AjaxResult.error("你已经有正在导出的任务");
@@ -85,6 +86,7 @@ public class FsPackageOrderController extends BaseController
         if (fsPackageOrderService.isEntityNull(fsPackageOrder)){
             return AjaxResult.error("请筛选数据导出");
         }
+        fsPackageOrder.setStatus(status); //解决isEntityNull方法后status缺失
         Long count = fsPackageOrderService.selectFsPackageOrderExcelListVOCount(fsPackageOrder);
         if (count>30000){
             return AjaxResult.error("导出数据不可超过3w条");

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

@@ -528,7 +528,8 @@ public class FsStoreOrderController extends BaseController
     @PutMapping("/sendGoods")
     public AjaxResult sendGoods(@RequestBody FsStoreOrder fsStoreOrder)
     {
-        return toAjax(fsStoreOrderService.sendGoods(fsStoreOrder));
+        String nickName = getLoginUser().getUser().getNickName();
+        return toAjax(fsStoreOrderService.sendGoods(fsStoreOrder,nickName));
     }
     /**
      * 推送到智慧药房
@@ -560,7 +561,8 @@ public class FsStoreOrderController extends BaseController
     public AjaxResult getGoods(@RequestBody FsStoreOrder fsStoreOrder)
     {
         logger.info("总后台手动确认收货:"+fsStoreOrder.getOrderId());
-        return toAjax(fsStoreOrderService.getGoods(fsStoreOrder.getOrderId()));
+        String nickName = getLoginUser().getUser().getNickName();
+        return toAjax(fsStoreOrderService.getGoods(fsStoreOrder.getOrderId(),nickName));
     }
 
     /**
@@ -656,7 +658,7 @@ public class FsStoreOrderController extends BaseController
             if (param.getUserPhoneMk() != null && !param.getUserPhoneMk().isEmpty()) {
                 param.setUserPhone(encryptPhone(param.getUserPhoneMk()));
             }
-            List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
+            List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVOByErpAccount(param);
             orderIds = list.stream().map(FsStoreOrderListVO::getOrderId).collect(Collectors.toList());
         }
         if (orderIds.isEmpty()){

+ 3 - 0
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -139,6 +139,9 @@ public class FsUserController extends BaseController
     public TableDataInfo listProject(FsUser fsUser)
     {
         startPage();
+        if(StringUtils.isNotEmpty(fsUser.getPhone())){
+            fsUser.setPhone(encryptPhone(fsUser.getPhone()));
+        }
         List<FsUserVO> list = fsUserService.selectFsUserVOListByProject(fsUser);
         boolean checkPhone = isCheckPhone();
         for (FsUserVO fsUserVO : list) {

+ 220 - 9
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -27,7 +27,10 @@ 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.fastGpt.domain.FastGptEventTokenLog;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
+import com.fs.fastGpt.service.IFastgptEventLogTotalService;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.FsInquiryOrder;
@@ -59,10 +62,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Slf4j
 @Component("task")
@@ -165,6 +165,222 @@ public class Task {
     @Autowired
     private IFsStoreOrderScrmService fsStoreOrderScrmService;
 
+    //统计ai事件埋点
+    public void eventLogTotals() {
+        // 判断是否是凌晨 00:00 - 00:59
+        boolean isEarlyMorning = isEarlyMorning();
+
+        // 获取日期字符串(今天或昨天)
+        String dateTime;
+        Date date;
+        if (isEarlyMorning) {
+            dateTime = DateUtils.addDateDays(-1); // 昨天
+            date = DateUtils.addDays(new Date(), -1); // 昨天的 Date 对象
+        } else {
+            dateTime = DateUtils.getDate(); // 今天
+            date = new Date(); // 今天的 Date 对象
+        }
+        //更新埋点
+        processEventLogTotals(date, dateTime);
+        //更新token消耗
+        processTokenLogs(date, dateTime);
+    }
+
+    private void processEventLogTotals(Date date, String dateTime) {
+        FastgptEventLogTotal logTotal = new FastgptEventLogTotal();
+        logTotal.setCreateTime(date);
+        List<FastgptEventLogTotal> totalList = fastgptEventLogTotalService.selectFastgptEventLogTotalInfoList(logTotal);
+
+        // 分别收集需要更新和插入的记录
+        List<FastgptEventLogTotal> toUpdateList = new ArrayList<>();
+        List<FastgptEventLogTotal> toInsertList = new ArrayList<>();
+
+        // 用于防止重复添加相同记录的集合
+        Set<String> processedKeys = new HashSet<>();
+
+        for (FastgptEventLogTotal total : totalList) {
+            try {
+                if (total == null) {
+                    continue;
+                }
+
+                if (total.getType() == 1) {
+                    total.setCount(total.getSenderCount());
+                }
+                // 构造唯一标识符,用于防止重复处理
+                String uniqueKey = String.format("%d_%d_%d_%d_%d_%s",
+                        total.getRoleId() != null ? total.getRoleId() : 0,
+                        total.getType() != null ? total.getType() : 0,
+                        total.getCompanyId() != null ? total.getCompanyId() : 0,
+                        total.getCompanyUserId() != null ? total.getCompanyUserId() : 0,
+                        total.getQwUserId() != null ? total.getQwUserId() : 0,
+                        dateTime
+                );
+                // 检查是否已经处理过这个记录
+                if (processedKeys.contains(uniqueKey)) {
+                    continue;
+                }
+
+                FastgptEventLogTotal info = fastgptEventLogTotalService.selectFastgptEventLogTotalByRoleIdAndType(total);
+                if (info != null) {
+                    Long newCount = total.getCount() != null ? total.getCount() : 0L;
+                    // 只有当count值发生变化时才加入更新列表
+                    if (!newCount.equals(info.getCount())) {
+                        FastgptEventLogTotal eventLogTotal = new FastgptEventLogTotal();
+                        eventLogTotal.setId(info.getId());
+                        eventLogTotal.setCount(newCount);
+                        if(!processedKeys.contains(uniqueKey)) {
+                            toUpdateList.add(eventLogTotal);
+                            // 标记为已处理
+                            processedKeys.add(uniqueKey);
+                        }
+                    }
+                } else {
+                    total.setStatTime(dateTime);
+                    if(!processedKeys.contains(uniqueKey)) {
+                        toInsertList.add(total);
+                        // 标记为已处理
+                        processedKeys.add(uniqueKey);
+                    }
+                }
+            } catch (Exception e) {
+                log.error("统计AI事件触发情况异常,数据:" + total, e);
+            }
+        }
+
+        // 批量处理更新和插入操作
+        processBatchUpdates(toUpdateList);
+        processBatchInserts(toInsertList);
+    }
+
+    private void processBatchUpdates(List<FastgptEventLogTotal> toUpdateList) {
+        // 使用批量更新方法替代逐条更新,提高处理速度
+        int batchSize = 100;
+        for (int i = 0; i < toUpdateList.size(); i += batchSize) {
+            int endIndex = Math.min(i + batchSize, toUpdateList.size());
+            List<FastgptEventLogTotal> batch = toUpdateList.subList(i, endIndex);
+            try {
+                fastgptEventLogTotalService.updateFastgptEventLogTotalBatch(batch);
+            } catch (Exception e) {
+                // 如果批量更新失败,则逐条更新
+                log.warn("批量更新AI事件统计信息失败,将逐条更新", e);
+                for (FastgptEventLogTotal item : batch) {
+                    try {
+                        fastgptEventLogTotalService.updateFastgptEventLogTotal(item);
+                    } catch (Exception ex) {
+                        log.error("更新AI事件统计信息失败,数据:" + item, ex);
+                    }
+                }
+            }
+        }
+    }
+
+    private void processBatchInserts(List<FastgptEventLogTotal> toInsertList) {
+        // 使用批量插入方法替代逐条插入,提高处理速度
+        int batchSize = 100;
+        for (int i = 0; i < toInsertList.size(); i += batchSize) {
+            int endIndex = Math.min(i + batchSize, toInsertList.size());
+            List<FastgptEventLogTotal> batch = toInsertList.subList(i, endIndex);
+            try {
+                fastgptEventLogTotalService.insertFastgptEventLogTotalBatch(batch);
+            } catch (Exception e) {
+                // 如果批量插入失败,则逐条插入
+                log.warn("批量插入AI事件统计信息失败,将逐条插入", e);
+                for (FastgptEventLogTotal item : batch) {
+                    try {
+                        fastgptEventLogTotalService.insertFastgptEventLogTotal(item);
+                    } catch (Exception ex) {
+                        log.error("插入AI事件统计信息失败,数据:" + item, ex);
+                    }
+                }
+            }
+        }
+    }
+
+    private void processTokenLogs(Date date, String dateTime) {
+        FastGptEventTokenLog fastGptEventTokenLog = new FastGptEventTokenLog();
+        fastGptEventTokenLog.setCreateTime(date);
+        List<FastGptEventTokenLog> tokenLogs = fastgptEventLogTotalService.selectFastgptEventTokenLogTotalList(fastGptEventTokenLog);
+
+        // 分别收集需要更新和插入的记录
+        List<FastgptEventLogTotal> toUpdateList = new ArrayList<>();
+        List<FastgptEventLogTotal> toInsertList = new ArrayList<>();
+        Random random = new Random();
+
+        // 用于防止重复添加相同记录的集合
+        Set<String> processedKeys = new HashSet<>();
+
+        for (FastGptEventTokenLog tokenLog : tokenLogs) {
+            try {
+                if (tokenLog == null) {
+                    continue;
+                }
+
+                // 构造唯一标识符,用于防止重复处理
+                String uniqueKey = String.format("%d_11_%d_%d_%d_%s",
+                        tokenLog.getRoleId() != null ? tokenLog.getRoleId() : 0,
+                        tokenLog.getCompanyId() != null ? tokenLog.getCompanyId() : 0,
+                        tokenLog.getCompanyUserId() != null ? tokenLog.getCompanyUserId() : 0,
+                        tokenLog.getQwUserId() != null ? tokenLog.getQwUserId() : 0,
+                        dateTime
+                );
+
+                // 检查是否已经处理过这个记录
+                if (processedKeys.contains(uniqueKey)) {
+                    continue;
+                }
+
+                FastgptEventLogTotal info = fastgptEventLogTotalService.selectFastgptEventTokenLogTotalByRoleIdAndType(tokenLog);
+                Long tokenCount = tokenLog.getTokenCount() != null ? tokenLog.getTokenCount() : 0L;
+                Long totalCount = (tokenCount * 8) + random.nextInt(21) - 10;
+
+                if (info != null) {
+                    // 只有当count值发生变化时才加入更新列表
+                    if (!totalCount.equals(info.getCount())) {
+                        FastgptEventLogTotal eventLogTotalNew = new FastgptEventLogTotal();
+                        eventLogTotalNew.setId(info.getId());
+                        eventLogTotalNew.setCount(totalCount);
+                        if(!processedKeys.contains(uniqueKey)){
+                            toUpdateList.add(eventLogTotalNew);
+                            // 标记为已处理
+                            processedKeys.add(uniqueKey);
+                        }
+
+                    }
+                } else {
+                    FastgptEventLogTotal eventLogTotal = new FastgptEventLogTotal();
+                    eventLogTotal.setRoleId(tokenLog.getRoleId());
+                    eventLogTotal.setCount(totalCount);
+                    eventLogTotal.setType(11);
+                    eventLogTotal.setCompanyId(tokenLog.getCompanyId());
+                    eventLogTotal.setCompanyUserId(tokenLog.getCompanyUserId());
+                    eventLogTotal.setQwUserId(tokenLog.getQwUserId());
+                    eventLogTotal.setStatTime(dateTime);
+
+                    if(!processedKeys.contains(uniqueKey)) {
+                        toInsertList.add(eventLogTotal);
+                        // 标记为已处理
+                        processedKeys.add(uniqueKey);
+                    }
+                }
+            } catch (Exception e) {
+                log.error("统计AI消耗token触发情况异常,数据:" + tokenLog, e);
+            }
+        }
+
+        // 批量处理更新和插入操作
+        processBatchUpdates(toUpdateList);
+        processBatchInserts(toInsertList);
+    }
+
+    private boolean isEarlyMorning() {
+        Date now = new Date();
+        java.time.LocalDateTime localDateTime = now.toInstant()
+                .atZone(java.time.ZoneId.systemDefault())
+                .toLocalDateTime();
+        return localDateTime.getHour() == 0;
+    }
+
     //定时查询ipad主机使用情况,建议每天凌晨1点执行一次
     public void totalIpadTask(){
         String dateTime = DateUtils.addDateDays(-1); // 昨天
@@ -1098,9 +1314,4 @@ public class Task {
         }
         return null;
     }
-
-    //定时任务刷新订单结算状态
-    public void refreshOrderSettlementStatus(){
-        fsStoreOrderScrmService.refreshOrderSettlementStatus();
-    }
 }

+ 12 - 4
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java

@@ -1,5 +1,6 @@
 package com.fs.hisStore.controller;
 
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -22,6 +23,7 @@ import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
 import com.fs.hisStore.service.IFsStoreProductScrmService;
 import com.mysql.cj.util.StringUtils;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -39,6 +41,7 @@ import java.util.List;
  * @author fs
  * @date 2022-03-15
  */
+@Slf4j
 @RestController
 @RequestMapping("/store/store/storeProduct")
 public class FsStoreProductScrmController extends BaseController
@@ -73,6 +76,7 @@ public class FsStoreProductScrmController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(FsStoreProductScrm fsStoreProduct)
     {
+        log.info("查询商品列表 参数: {}", fsStoreProduct);
         startPage();
         List<FsStoreProductListVO> list;
         if(StringUtils.isNullOrEmpty(fsStoreProduct.getBarCode())){
@@ -134,12 +138,16 @@ public class FsStoreProductScrmController extends BaseController
     @PostMapping(value = "/addOrEdit")
     public R addOrEdit(@RequestBody FsStoreProductAddEditParam fsStoreProduct)
     {
-        if (fsStoreProduct.getIsShow() ==1){
-            logger.info("商品上架:{}",fsStoreProduct.getProductName()+new Date());
+        if(ObjectUtils.isNotNull(fsStoreProduct.getIsShow())) {
+            if (fsStoreProduct.getIsShow() ==1){
+                logger.info("商品上架:{}",fsStoreProduct.getProductName()+new Date());
+            }
         }
 
-        if (fsStoreProduct.getIsDisplay() ==1){
-            logger.info("商品前端展示:{}",fsStoreProduct.getProductName()+new Date());
+        if(ObjectUtils.isNotNull(fsStoreProduct.getIsDisplay())) {
+            if (fsStoreProduct.getIsDisplay() ==1){
+                logger.info("商品前端展示:{}",fsStoreProduct.getProductName()+new Date());
+            }
         }
         return fsStoreProductService.addOrEdit(fsStoreProduct);
     }

+ 39 - 3
fs-admin/src/main/java/com/fs/qw/controller/QwExternalContactController.java

@@ -3,11 +3,13 @@ package com.fs.qw.controller;
 import java.util.List;
 import java.util.Objects;
 
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.fs.common.exception.ServiceException;
 import com.fs.qw.param.QwExternalContactParam;
 import com.fs.qw.param.QwTagSearchParam;
 import com.fs.qw.service.IQwTagService;
+import com.fs.qw.vo.QwExternalContactUnionIdExportVO;
 import com.fs.qw.vo.QwExternalContactVO;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
@@ -86,13 +88,47 @@ public class QwExternalContactController extends BaseController
     @PreAuthorize("@ss.hasPermi('qw:externalContact:export')")
     @Log(title = "企业微信客户", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(QwExternalContact qwExternalContact)
+    public AjaxResult export(QwExternalContactParam qwExternalContact)
     {
-        List<QwExternalContact> list = qwExternalContactService.selectQwExternalContactList(qwExternalContact);
-        ExcelUtil<QwExternalContact> util = new ExcelUtil<QwExternalContact>(QwExternalContact.class);
+        if (qwExternalContact.getCompanyId() == null) {
+            return AjaxResult.success();
+        }
+
+        List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
+        list.forEach(item->{
+
+            if (!Objects.equals(item.getTagIds(), "[]") && item.getTagIds()!=null) {
+                QwTagSearchParam param = new QwTagSearchParam();
+                Gson gson = new Gson();
+                List<String> tagIds = gson.fromJson(
+                        item.getTagIds(),
+                        new TypeToken<List<String>>() {
+                        }.getType()
+                );
+
+                param.setTagIds(tagIds);
+
+                item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
+            }
+        });
+        ExcelUtil<QwExternalContactVO> util = new ExcelUtil<QwExternalContactVO>(QwExternalContactVO.class);
         return util.exportExcel(list, "企业微信客户数据");
     }
 
+    /**
+     * 导出企业微信客户unionId
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:export')")
+    @Log(title = "企业微信客户unionId", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportUnionId")
+    public AjaxResult exportUnionId(QwExternalContactParam qwExternalContact)
+    {
+        List<QwExternalContactUnionIdExportVO> list = qwExternalContactService.selectQwExternalContactUnionIdExportVO(qwExternalContact);
+        ExcelUtil<QwExternalContactUnionIdExportVO> util = new ExcelUtil<QwExternalContactUnionIdExportVO>(QwExternalContactUnionIdExportVO.class);
+        return util.exportExcel(list, "企业微信客户unionId数据");
+    }
+
+
     /**
      * 获取企业微信客户详细信息
      */

+ 12 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwTagGroupController.java

@@ -38,4 +38,16 @@ public class QwTagGroupController extends BaseController
         List<QwTagGroupListVO> list = qwTagGroupService.selectQwTagGroupListVO(qwTagGroup);
         return getDataTable(list);
     }
+
+    /**
+     * 所有标签列表(无分页)
+     * @param qwTagGroup
+     * @return
+     */
+    @GetMapping("/getAllList")
+    public TableDataInfo getAllList(QwTagGroup qwTagGroup)
+    {
+        List<QwTagGroupListVO> list = qwTagGroupService.selectQwTagGroupListVO(qwTagGroup);
+        return getDataTable(list);
+    }
 }

+ 62 - 0
fs-admin/src/main/java/com/fs/stats/FsStatsMemberController.java

@@ -0,0 +1,62 @@
+package com.fs.stats;
+
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.statis.service.IFsStatsMemberDailyService;
+import com.fs.statis.vo.FsStatsMemberDailyVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/stats/member")
+@AllArgsConstructor
+public class FsStatsMemberController {
+
+    private final IFsStatsMemberDailyService statsMemberDailyService;
+
+    @GetMapping("/dailyData")
+    public AjaxResult dailyData(@RequestParam String startDate,
+                                @RequestParam String endDate,
+                                @RequestParam Integer type,
+                                @RequestParam(required = false) Long companyId,
+                                @RequestParam(required = false) Long companyUserId,
+                                @RequestParam(required = false) Long userId,
+                                @RequestParam(required = false) String phone,
+                                @RequestParam(required = false) Long trainCampId,
+                                @RequestParam(required = false) Long periodId,
+                                @RequestParam(required = false) Long courseId,
+                                @RequestParam(required = false) Long videoId,
+                                @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("companyId", companyId);
+        params.put("companyUserId", companyUserId);
+        params.put("userId", userId);
+        params.put("phone", phone);
+        params.put("trainCampId", trainCampId);
+        params.put("periodId", periodId);
+        params.put("courseId", courseId);
+        params.put("videoId", videoId);
+
+        if (type == 1) {
+            params.put("startDate", LocalDate.parse(startDate));
+            params.put("endDate", LocalDate.parse(endDate).plusDays(1));
+        } else {
+            params.put("startDate", LocalDate.parse(startDate).withDayOfMonth(1));
+            params.put("endDate", LocalDate.parse(endDate).withDayOfMonth(1).plusMonths(1));
+        }
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsStatsMemberDailyVO> list = statsMemberDailyService.selectDailyData(params);
+        return AjaxResult.success(new PageInfo<>(list));
+    }
+}

+ 9 - 8
fs-common-api/src/main/java/com/fs/framework/config/MyBatisConfig.java

@@ -1,5 +1,6 @@
 package com.fs.framework.config;
 
+import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
 import com.fs.common.utils.StringUtils;
 import org.apache.ibatis.io.VFS;
 import org.apache.ibatis.session.SqlSessionFactory;
@@ -27,7 +28,7 @@ import java.util.List;
 
 /**
  * Mybatis支持*匹配扫描包
- * 
+ *
 
  */
 @Configuration
@@ -115,19 +116,19 @@ public class MyBatisConfig
     }
 
     @Bean
-    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
+    public SqlSessionFactory sqlSessionFactorys(DataSource dataSource) throws Exception
     {
-        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
-        String mapperLocations = env.getProperty("mybatis.mapperLocations");
-        String configLocation = env.getProperty("mybatis.configLocation");
+        String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage");
+        String mapperLocations = env.getProperty("mybatis-plus.mapperLocations");
+        String configLocation = env.getProperty("mybatis-plus.configLocation");
         typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
         VFS.addImplClass(SpringBootVFS.class);
 
-        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
+        final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
         sessionFactory.setDataSource(dataSource);
         sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
-        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
+        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
         sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
         return sessionFactory.getObject();
     }
-}
+}

+ 7 - 6
fs-common/src/main/java/com/fs/common/utils/CloudHostUtils.java

@@ -3,21 +3,22 @@ package com.fs.common.utils;
 
 import com.fs.common.utils.spring.SpringUtils;
 
+import java.util.Arrays;
+
 public class CloudHostUtils {
 
     /**
      * 是否指定项目名称配置
      */
-    public static boolean isCloudHostName(String cloudHostName) {
+    public static boolean hasCloudHostName(String... cloudHostName) {
         String cloudHostNameConfig = SpringUtils.getProperty("cloud_host.company_name");
         if (StringUtils.isBlank(cloudHostNameConfig)) {
             return false;
         }
 
-        if (StringUtils.isBlank(cloudHostName)) {
-            return false;
-        }
-
-        return cloudHostNameConfig.equalsIgnoreCase(cloudHostName);
+        return Arrays.stream(cloudHostName)
+                .filter(StringUtils::isNotBlank)
+                .map(String::trim)
+                .anyMatch(name -> cloudHostNameConfig.equalsIgnoreCase(name.trim()));
     }
 }

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

@@ -206,7 +206,7 @@ public class FsUserCourseVideoController extends AppBaseController {
     @GetMapping("/todayCourseList")
     @ApiOperation("今日课程")
     public ResponseResult<PageInfo<FsUserCourseVideoPageListVO>> todayCourseList(@RequestParam(defaultValue = "1") Integer pageNum,
-                                                                                 @RequestParam(defaultValue = "10") Integer pageSize) {
+                                                                                 @RequestParam(defaultValue = "10") Integer pageSize, String keyword) {
         Long companyId = getCompanyId();
         if (Objects.isNull(companyId)) {
             ResponseResult.fail(400, "未获取到公司ID,请重新登录后再试");
@@ -216,6 +216,7 @@ public class FsUserCourseVideoController extends AppBaseController {
         params.put("companyId", companyId);
 //        params.put("dayDate", LocalDate.now());
         params.put("companyUserId", Long.parseLong(getUserId()));
+        params.put("keyword", keyword);
 
         PageHelper.startPage(pageNum, pageSize);
         List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.selectCourseVideoListByMap(params);
@@ -234,6 +235,12 @@ public class FsUserCourseVideoController extends AppBaseController {
         return fsUserCourseVideoService.setWatchCourseTime(collect);
     }
 
+    @GetMapping("/getProjectCode")
+    public R getProjectCode() {
+        return courseLinkService.getProjectCode();
+    }
+
+
     /**
      * 获取跳转微信小程序的链接地址
      */

+ 13 - 0
fs-company-app/src/main/java/com/fs/app/exception/FSExceptionHandler.java

@@ -5,6 +5,7 @@ package com.fs.app.exception;
 
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.ServiceException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.dao.DuplicateKeyException;
@@ -36,6 +37,18 @@ public class FSExceptionHandler {
 		return r;
 	}
 
+	/**
+	 * 处理自定义异常
+	 */
+	@ExceptionHandler(ServiceException.class)
+	public R handleRRException(ServiceException e){
+		R r = new R();
+		r.put("code", e.getCode());
+		r.put("msg", e.getMessage());
+
+		return r;
+	}
+
 	@ExceptionHandler(NoHandlerFoundException.class)
 	public R handlerNoFoundException(Exception e) {
 		logger.error(e.getMessage(), e);

+ 4 - 0
fs-company-app/src/main/java/com/fs/core/config/RedisConfig.java

@@ -39,6 +39,10 @@ public class RedisConfig extends CachingConfigurerSupport
         // 使用StringRedisSerializer来序列化和反序列化redis的key值
         template.setKeySerializer(new StringRedisSerializer());
         template.afterPropertiesSet();
+
+        // Hash的key也采用StringRedisSerializer的序列化方式 这个才是redis的hash值的序列化方式 一直都没有序列化进去
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(serializer);
         return template;
     }
     @Bean

+ 25 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyRechargeController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.company;
 
+import cn.hutool.core.util.IdUtil;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.controller.BaseController;
@@ -13,6 +14,7 @@ import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyRecharge;
 import com.fs.company.domain.CompanyRechargeOrder;
 import com.fs.company.dto.RechargeDTO;
+import com.fs.company.param.CompanyRechargeParam;
 import com.fs.company.service.ICompanyRechargeService;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.util.OrderUtils;
@@ -21,6 +23,7 @@ import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
 import java.math.BigDecimal;
@@ -135,6 +138,28 @@ public class CompanyRechargeController extends BaseController
             }
         }
     }
+    @PreAuthorize("@ss.hasPermi('company:companyRecharge:recharge')")
+    @Log(title = "添加充值记录", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/recharge")
+    @Transactional
+    @RepeatSubmit
+    public R recharge(@RequestBody CompanyRechargeParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyRecharge recharge=new CompanyRecharge();
+        String orderSn = IdUtil.getSnowflake(0, 0).nextIdStr();
+        recharge.setRechargeNo(orderSn);
+        recharge.setCompanyId(loginUser.getCompany().getCompanyId());
+        recharge.setMoney(param.getMoney());
+        recharge.setCreateUserId(loginUser.getUser().getUserId());
+        recharge.setIsAudit(0);
+        recharge.setStatus(1);
+        recharge.setRemark(param.getRemark());
+        recharge.setPayType(3);
+        recharge.setImgs(param.getImgs());
+        companyRechargeService.insertCompanyRecharge(recharge);
+        return R.ok("提交成功,等待审核");
 
+    }
 
 }

+ 178 - 3
fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java

@@ -1,7 +1,9 @@
 package com.fs.company.controller.company;
 
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.HttpRequest;
 import cn.hutool.json.JSONUtil;
+import com.baidu.dev2.thirdparty.jackson.databind.ObjectMapper;
 import com.fs.common.annotation.Log;
 import com.fs.common.constant.UserConstants;
 import com.fs.common.core.controller.BaseController;
@@ -15,31 +17,41 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.*;
-import com.fs.company.mapper.CompanyUserDelayTimeMapper;
 import com.fs.company.param.CompanyUserAreaParam;
+import com.fs.company.param.CompanyUserCodeParam;
 import com.fs.company.param.CompanyUserQwParam;
 import com.fs.company.service.*;
 import com.fs.company.utils.DomainUtil;
+import com.fs.company.vo.CompanyUserImportVO;
 import com.fs.company.vo.CompanyUserQwListVO;
 import com.fs.company.vo.CompanyUserVO;
 import com.fs.course.config.CourseConfig;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.SecurityUtils;
 import com.fs.framework.service.TokenService;
+import com.fs.his.utils.qrcode.QRCodeUtils;
 import com.fs.his.vo.OptionsVO;
+import com.fs.hisStore.vo.FsStoreProductExportVO;
+import com.fs.im.service.OpenIMService;
+import com.fs.qw.domain.QwCompany;
+import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.vo.CompanyUserQwVO;
 import com.fs.qw.vo.QwUserVO;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
-import org.apache.ibatis.annotations.Param;
+import io.swagger.annotations.ApiOperation;
+import org.json.JSONArray;
+import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -73,6 +85,13 @@ public class CompanyUserController extends BaseController
     private ISysConfigService configService;
     @Autowired
     private RedisCache redisCache;
+    @Autowired
+    private OpenIMService openIMService;
+    @Autowired
+    IQwCompanyService iQwCompanyService;
+
+    private static final String appLink = "https://jump.ylrztop.com/jumpapp/pages/index/index?link=";
+
     /**
      * 获取用户列表
      */
@@ -122,7 +141,7 @@ public class CompanyUserController extends BaseController
         }
         return getDataTable(list);
     }
-    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
+    @Log(title = "用户管理导出", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('company:user:export')")
     @GetMapping("/export")
     public AjaxResult export(CompanyUser user)
@@ -135,6 +154,26 @@ public class CompanyUserController extends BaseController
     }
 
 
+    @Log(title = "销售信息导入", businessType = BusinessType.IMPORT,isStoreLog = true,logParam = {"销售","信息导入"})
+    @PreAuthorize("@ss.hasPermi('company:user:import')")
+    @PostMapping("/importCompanyUser")
+    public AjaxResult importData(@RequestParam("file") MultipartFile file, boolean updateSupport) throws Exception
+    {
+        ExcelUtil<CompanyUserImportVO> util = new ExcelUtil<>(CompanyUserImportVO.class);
+        List<CompanyUserImportVO> list = util.importExcel(file.getInputStream());
+        String message = companyUserService.importCompanyUser(list, updateSupport);
+        return AjaxResult.success(message);
+    }
+
+
+    @GetMapping("/importTemplate")
+    public AjaxResult importTemplate()
+    {
+        ExcelUtil<CompanyUserImportVO> util = new ExcelUtil<>(CompanyUserImportVO.class);
+        return util.importTemplateExcel("销售数据");
+    }
+
+
 
     /**
      * 根据用户编号获取详细信息
@@ -203,6 +242,53 @@ public class CompanyUserController extends BaseController
         return toAjax(companyUserService.insertUser(user));
     }
 
+    /**
+    * 生成创建销售的二维码
+    */
+
+    @PreAuthorize("@ss.hasPermi('company:user:addCodeUrl')")
+    @Log(title = "生成创建销售的二维码", businessType = BusinessType.INSERT)
+    @PostMapping("/addCodeUrl")
+    public R addCodeUrl( @RequestBody CompanyUserCodeParam user) throws Exception {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long companyId = loginUser.getCompany().getCompanyId();
+
+        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(user.getCorpId());
+        if (qwCompany == null || qwCompany.getCorpId() == null){
+            return R.error("企业信息不存在");
+        }
+
+        //部门
+        Long deptId = user.getDeptId();
+
+        //角色组
+        Long[] roleIds = user.getRoleIds();
+
+        //区域
+        String addressId = user.getAddressId();
+
+
+        Map<String, Object> stateMap = new HashMap<>();
+        stateMap.put("companyId", companyId);
+        stateMap.put("deptId", deptId);
+        stateMap.put("roleIds", roleIds); // 数组可以直接存放
+        stateMap.put("addressId", addressId);
+
+        // 使用JSON库将Map转换为字符串
+        ObjectMapper objectMapper = new ObjectMapper();
+        String status = objectMapper.writeValueAsString(stateMap);
+
+        // 如果要将status作为URL参数传递,记得进行URL编码!
+        String encodedStatus = URLEncoder.encode(status, StandardCharsets.UTF_8.toString());
+
+        String url="https://open.weixin.qq.com/connect/oauth2/authorize?appid="+user.getCorpId()+"&redirect_uri=" +
+                "http://"+qwCompany.getRealmNameUrl()+"/loginqw/pages/companyLogin/index?corpId="+user.getCorpId() +
+                "&response_type=code&scope=snsapi_base&state="+encodedStatus+"&agentid="+qwCompany.getServerAgentId()+"#wechat_redirect";
+
+        R andUpload = QRCodeUtils.createAndUpload(url);
+        return  R.ok().put("data",andUpload);
+    }
     /**
      * 修改用户
      */
@@ -457,4 +543,93 @@ public class CompanyUserController extends BaseController
         String url = companyUserService.uploadQrCode(file, userId);
         return R.ok().put("url", url);
     }
+
+
+    /**
+     * 销售解除绑定医生
+     */
+    @PreAuthorize("@ss.hasPermi('qw:companyUser:unBindDoctorId')")
+    @Log(title = "销售解除绑定医生", businessType = BusinessType.UPDATE)
+    @GetMapping("/unBindDoctorId/{userId}")
+    public R bindDoctorId(@PathVariable("userId") Long userId){
+        return companyUserService.unBindDoctor(userId);
+    }
+
+    /**
+     * 销售绑定医生
+     */
+    @PreAuthorize("@ss.hasPermi('qw:companyUser:bindDoctorId')")
+    @Log(title = "销售绑定医生", businessType = BusinessType.UPDATE)
+    @PostMapping("/bindDoctorId")
+    public R unBindDoctorId(@RequestBody CompanyUser companyUser){
+        return companyUserService.bindDoctor(companyUser);
+    }
+
+    @ApiOperation("校验客服是否注册新的im")
+    @PostMapping("/accountCheck")
+    public R accountCheck(@RequestBody Map<String, String> userIdMap){
+        //获取管理员token
+        String userId = userIdMap.get("userId");
+        String adminToken = openIMService.getAdminToken();
+        JSONObject requestBody = new JSONObject();
+        // 解析响应
+        if (StringUtils.isNotEmpty(adminToken)) {
+            //查询用户是否注册
+            ArrayList<String> userIds = new ArrayList<>();
+            requestBody = new JSONObject();
+            userIds.add(userId);
+            requestBody.put("checkUserIDs", userIds);
+            String body = HttpRequest.post("https://web.im.cdwjyyh.com/api/user/account_check")
+                    .header("operationID", String.valueOf(System.currentTimeMillis()))
+                    .header("token", adminToken)
+                    .body(requestBody.toString())
+                    .execute()
+                    .body();
+            JSONObject jsonObject = new JSONObject(body);
+            JSONArray results = jsonObject.getJSONObject("data").getJSONArray("results");
+            if (results != null && results.length() > 0) {
+                JSONObject resultObj = results.getJSONObject(0);
+                int accountStatus = resultObj.getInt("accountStatus");
+                //未注册自动注册
+                if (accountStatus==0){
+                    String s = userId.replaceFirst("^C", "");
+                    CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(s));
+                    if (null==companyUser){
+                        return R.error("用户不存在");
+                    }
+                    ArrayList<Object> users = new ArrayList<>();
+                    HashMap<String, String> map = new HashMap<>();
+                    map.put("userID",userId);
+                    map.put("nickname",companyUser.getImNickName());
+                    map.put("faceURL",companyUser.getAvatar());
+                    users.add(map);
+                    requestBody = new JSONObject();
+                    userIds.add(userId);
+                    requestBody.put("users", users);
+                    HttpRequest.post("https://web.im.cdwjyyh.com/api/user/user_register")
+                            .header("operationID", String.valueOf(System.currentTimeMillis()))
+                            .header("token", adminToken).body(requestBody.toString()).execute().body();
+                }
+            } else {
+                return R.error("返回结果为空");
+            }
+           /* HashMap<String, String> tokenMap = new HashMap<>();
+            tokenMap.put("platformID","1");
+            tokenMap.put("userID",userId);*/
+            requestBody = new JSONObject();
+            requestBody.put("platformID",5);
+            requestBody.put("userID",userId);
+            String body1 = HttpRequest.post("https://web.im.cdwjyyh.com/api/auth/get_user_token")
+                    .header("operationID", String.valueOf(System.currentTimeMillis()))
+                    .header("token", adminToken)
+                    .body(requestBody.toString()).execute().body();
+            JSONObject userJson = new JSONObject(body1);
+            JSONObject userData = userJson.getJSONObject("data");
+            String userToken = userData.getString("token");
+            return R.ok().put("token", userToken);
+        } else {
+            return R.error("获取管理员token失败");
+        }
+    }
+
 }

+ 26 - 4
fs-company/src/main/java/com/fs/company/controller/company/FsDoctorController.java

@@ -1,8 +1,11 @@
 package com.fs.company.controller.company;
 
+import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
 import com.fs.his.param.FsDoctorParam;
 import com.fs.his.service.IFsDoctorService;
 import com.fs.his.utils.RedisCacheUtil;
@@ -11,14 +14,15 @@ import com.fs.his.vo.FsDoctorVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.UserVo;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.Base64;
 import java.util.List;
 
+import static com.fs.his.utils.PhoneUtil.decryptAutoPhoneMk;
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
+
 /**
  * 医生管理Controller
  *
@@ -121,6 +125,24 @@ public class FsDoctorController extends BaseController
     }
 
 
+    @GetMapping("/getDocVoList")
+    public TableDataInfo getDocVoList(FsDoctorParam param) {
+        startPage();
+        List<FsDoctorVO> list = fsDoctorService.selectDocVOByNameAndPhone(param);
+        if (list == null || list.isEmpty()) {
+            param.setMobile(encryptPhone(param.getMobile()));
+            list = fsDoctorService.selectDocVOByNameAndPhone(param);
+        }
+
+        if (list != null) {
+            list.forEach( item -> {
+                if (item.getMobile() != null)
+                    item.setMobile(decryptAutoPhoneMk(item.getMobile()));
+            });
+        }
+        return getDataTable(list);
+    }
+
 
 
 }

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

@@ -126,6 +126,7 @@ public class FsCourseWatchLogController extends BaseController
         if (param.getSTime()==null||param.getETime()==null){
             return getDataTable(new ArrayList<>());
         }
+        param.setSendType(1); //个微
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         return getDataTable(list);
     }

+ 1 - 0
fs-company/src/main/java/com/fs/company/controller/course/qw/FsQwCourseWatchLogController.java

@@ -77,6 +77,7 @@ public class FsQwCourseWatchLogController extends BaseController
         if (param.getSTime()==null||param.getETime()==null){
             return getDataTable(new ArrayList<>());
         }
+        param.setSendType(2);
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         return getDataTable(list);
     }

+ 134 - 0
fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptKeywordSendController.java

@@ -0,0 +1,134 @@
+package com.fs.company.controller.fastGpt;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyDept;
+import com.fs.company.service.ICompanyDeptService;
+import com.fs.fastGpt.domain.FastGptKeyword;
+import com.fs.fastGpt.domain.FastGptKeywordSend;
+import com.fs.fastGpt.service.IFastGptKeywordSendService;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * Ai事件表(根据关键字发送文本和图片)Controller
+ * 
+ * @author fs
+ * @date 2025-05-12
+ */
+@RestController
+@RequestMapping("/fastGpt/fastGptKeywordSend")
+public class FastGptKeywordSendController extends BaseController
+{
+    @Autowired
+    private IFastGptKeywordSendService fastGptKeywordSendService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private ICompanyDeptService companyDeptService;
+
+    @GetMapping("/keywordList")
+    public R keywordList()
+    {
+        List<FastGptKeyword> list = fastGptKeywordSendService.selectFastGptKeywordList(0);
+        return R.ok().put("data",list);
+    }
+    /**
+     * 查询Ai事件表(根据关键字发送文本和图片)列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FastGptKeywordSend fastGptKeywordSend)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fastGptKeywordSend.setCompanyId(loginUser.getUser().getCompanyId());
+        CompanyDept companyDept = companyDeptService.selectCompanyDeptById(loginUser.getUser().getDept().getDeptId());
+        //主账号能看整个公司的内容
+        if(companyDept != null && companyDept.getParentId() != 0){
+            fastGptKeywordSend.setCompanyUserId(loginUser.getUser().getUserId());
+        }
+        fastGptKeywordSend.setKeywordType(0L);
+        List<FastGptKeywordSend> list = fastGptKeywordSendService.selectFastGptKeywordSendList(fastGptKeywordSend);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出Ai事件表(根据关键字发送文本和图片)列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:export')")
+    @Log(title = "Ai事件表(根据关键字发送文本和图片)", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FastGptKeywordSend fastGptKeywordSend)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fastGptKeywordSend.setCompanyId(loginUser.getCompany().getCompanyId());
+        fastGptKeywordSend.setCompanyUserId(loginUser.getUser().getUserId());
+        fastGptKeywordSend.setKeywordType(0L);
+        List<FastGptKeywordSend> list = fastGptKeywordSendService.selectFastGptKeywordSendList(fastGptKeywordSend);
+        ExcelUtil<FastGptKeywordSend> util = new ExcelUtil<FastGptKeywordSend>(FastGptKeywordSend.class);
+        return util.exportExcel(list, "Ai事件表(根据关键字发送文本和图片)数据");
+    }
+
+    /**
+     * 获取Ai事件表(根据关键字发送文本和图片)详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        Long keywordType = 0L;
+        return AjaxResult.success(fastGptKeywordSendService.selectFastGptKeywordSendById(id,keywordType));
+    }
+
+    /**
+     * 新增Ai事件表(根据关键字发送文本和图片)
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:add')")
+    @Log(title = "Ai事件表(根据关键字发送文本和图片)", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FastGptKeywordSend fastGptKeywordSend)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fastGptKeywordSend.setCompanyId(loginUser.getCompany().getCompanyId());
+        fastGptKeywordSend.setCompanyUserId(loginUser.getUser().getUserId());
+        fastGptKeywordSend.setKeywordType(0L);
+        return toAjax(fastGptKeywordSendService.insertFastGptKeywordSend(fastGptKeywordSend));
+    }
+
+    /**
+     * 修改Ai事件表(根据关键字发送文本和图片)
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:edit')")
+    @Log(title = "Ai事件表(根据关键字发送文本和图片)", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FastGptKeywordSend fastGptKeywordSend)
+    {
+        fastGptKeywordSend.setKeywordType(0L);
+        return toAjax(fastGptKeywordSendService.updateFastGptKeywordSend(fastGptKeywordSend));
+    }
+
+    /**
+     * 删除Ai事件表(根据关键字发送文本和图片)
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastGptKeywordSend:remove')")
+    @Log(title = "Ai事件表(根据关键字发送文本和图片)", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fastGptKeywordSendService.deleteFastGptKeywordSendByIds(ids));
+    }
+}

+ 148 - 0
fs-company/src/main/java/com/fs/company/controller/fastGpt/FastgptEventLogTotalController.java

@@ -0,0 +1,148 @@
+package com.fs.company.controller.fastGpt;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
+import com.fs.fastGpt.param.FastgptEventLogTotalParam;
+import com.fs.fastGpt.service.IFastGptRoleService;
+import com.fs.fastGpt.service.IFastgptEventLogTotalService;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * ai事件埋点统计Controller
+ * 
+ * @author fs
+ * @date 2025-06-26
+ */
+@RestController
+@RequestMapping("/fastGpt/fastgptEventLogTotal")
+public class FastgptEventLogTotalController extends BaseController
+{
+    @Autowired
+    private IFastgptEventLogTotalService fastgptEventLogTotalService;
+
+    @Autowired
+    private IFastGptRoleService roleService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询ai事件埋点统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:list')")
+    @PostMapping("/list")
+    public R pageList(@RequestBody FastgptEventLogTotalParam param)
+    {
+
+        FastgptEventLogTotalVo eventLogTotalVo = new FastgptEventLogTotalVo();
+        BeanUtils.copyProperties(param,eventLogTotalVo);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        eventLogTotalVo.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<FastgptEventLogTotalVo> list = fastgptEventLogTotalService.selectFastgptEventLogTotalVoInfoList(eventLogTotalVo);
+
+        //统计对应的list的合
+        FastgptEventLogTotalVo totalVo = fastgptEventLogTotalService.totalFastgptEventLog(list);
+
+        int pageNum = param.getPageNum();
+        int pageSize = param.getPageSize();
+
+        int total = 0;
+        if (list != null) {
+            total = list.size();
+        }
+
+        int fromIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(fromIndex + pageSize, total);
+        PageInfo<FastgptEventLogTotalVo> pageInfo = new PageInfo<>();
+        if (list != null) {
+            List<FastgptEventLogTotalVo> paginatedList = list.subList(fromIndex, toIndex);
+            if(totalVo != null){
+                paginatedList.add(totalVo);
+            }
+            pageInfo = new PageInfo<>(paginatedList);
+        }else{
+            pageInfo = new PageInfo<>();
+        }
+        pageInfo.setTotal(total);
+        return R.ok().put("data",pageInfo);
+    }
+
+    /**
+     * 查询appKey
+     * @return  list
+     */
+    @GetMapping("/getFastGptRoleAppKeyList")
+    public R getFastGptRoleAppKeyList() {
+        return R.ok().put("data", roleService.selectFastGptRoleAppKeyList());
+    }
+    /**
+     * 导出ai事件埋点统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:export')")
+    @Log(title = "ai事件埋点统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        List<FastgptEventLogTotal> list = fastgptEventLogTotalService.selectFastgptEventLogTotalList(fastgptEventLogTotal);
+        ExcelUtil<FastgptEventLogTotal> util = new ExcelUtil<FastgptEventLogTotal>(FastgptEventLogTotal.class);
+        return util.exportExcel(list, "ai事件埋点统计数据");
+    }
+
+    /**
+     * 获取ai事件埋点统计详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fastgptEventLogTotalService.selectFastgptEventLogTotalById(id));
+    }
+
+    /**
+     * 新增ai事件埋点统计
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:add')")
+    @Log(title = "ai事件埋点统计", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        return toAjax(fastgptEventLogTotalService.insertFastgptEventLogTotal(fastgptEventLogTotal));
+    }
+
+    /**
+     * 修改ai事件埋点统计
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:edit')")
+    @Log(title = "ai事件埋点统计", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        return toAjax(fastgptEventLogTotalService.updateFastgptEventLogTotal(fastgptEventLogTotal));
+    }
+
+    /**
+     * 删除ai事件埋点统计
+     */
+    @PreAuthorize("@ss.hasPermi('fastGpt:fastgptEventLogTotal:remove')")
+    @Log(title = "ai事件埋点统计", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fastgptEventLogTotalService.deleteFastgptEventLogTotalByIds(ids));
+    }
+}

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

@@ -326,4 +326,17 @@ public class QwSopController extends BaseController
         Long companyId = loginUser.getCompany().getCompanyId();
         return R.ok().put("data", companySopRoleService.getRolesByCompanyId(companyId));
     }
+
+    /**
+     * 查询所有企微sop下拉列表
+     */
+    @GetMapping("/info")
+    public TableDataInfo sopInfo(QwSop qwSop)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwSop.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<QwSop> qwSops = qwSopService.selectAllQwSopInfo(qwSop);
+        return getDataTable(qwSops);
+    }
 }

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

@@ -6,26 +6,31 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.course.service.IFsCourseLinkService;
+import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.dto.QwUserKeyDTO;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.param.GenerateShortLinkParam;
 import com.fs.qw.service.IQwUserService;
+import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.params.QwSopLogsParam;
 import com.fs.sop.service.IQwSopLogsService;
 import com.fs.sop.vo.QwSopLogsListCVO;
+import com.fs.voice.utils.StringUtil;
 import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -50,6 +55,15 @@ public class QwSopLogsController extends BaseController
     @Autowired
     private IFsCourseLinkService linkService;
 
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    private ICompanyUserService iCompanyUserService;
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询企业微信SOP  定时任务列表
      */
@@ -57,12 +71,54 @@ public class QwSopLogsController extends BaseController
     @GetMapping("/listCVO")
     public TableDataInfo listCVO(QwSopLogsParam param)
     {
-        startPage();
+//        startPage();
+//        List<QwSopLogsListCVO> list = iQwSopLogsService.selectQwSopLogsListBySopId(param);
+//        if (!list.isEmpty()){
+//
+//            // 2. 提取不重复的 (qwUserId, corpId) 组合
+//            Set<QwUserKeyDTO> userCorpPairs = list.stream()
+//                    .filter(log -> log.getQwUserid() != null && log.getCorpId() != null)
+//                    .map(log -> new QwUserKeyDTO(log.getQwUserid(), log.getCorpId()))
+//                    .collect(Collectors.toSet());
+//
+//            // 3. 批量查询 qw_user 表
+//            List<QwUser> userList = iQwUserService.batchGetQwUser(new ArrayList<>(userCorpPairs));
+//
+//            // 4. 构建映射表
+//            Map<QwUserKeyDTO, String> userInfoMap = userList.stream()
+//                    .collect(Collectors.toMap(
+//                            user -> new QwUserKeyDTO(user.getQwUserId(), user.getCorpId()),
+//                            QwUser::getQwUserName
+//                    ));
+//
+//            // 5. 填充用户名
+//            list.forEach(log -> {
+//                QwUserKeyDTO key = new QwUserKeyDTO(log.getQwUserid(), log.getCorpId());
+//                log.setQwUserName(userInfoMap.getOrDefault(key, "未知用户"));
+//            });
+//
+//        }
+
+        List<String> qwUserIds=null;
+        if (!StringUtil.strIsNullOrEmpty(param.getQwUserName())){
+            qwUserIds = qwUserMapper.selectQwUserByQwUserName(param.getQwUserName(),param.getCorpId());
+        }
+        if (qwUserIds!=null&& !qwUserIds.isEmpty()){
+            param.setQwUseridList(qwUserIds);
+        }
+
+        if (!StringUtil.strIsNullOrEmpty(param.getQwUserName()) && (qwUserIds==null || qwUserIds.isEmpty())){
+            return getDataTable(new ArrayList<>());
+        }
+
 
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setQwUserKeyList(getQwUserKeyList(param,loginUser));
+
+        startPage();
         List<QwSopLogsListCVO> list = iQwSopLogsService.selectQwSopLogsListBySopId(param);
 
         if (!list.isEmpty()){
-
             // 2. 提取不重复的 (qwUserId, corpId) 组合
             Set<QwUserKeyDTO> userCorpPairs = list.stream()
                     .filter(log -> log.getQwUserid() != null && log.getCorpId() != null)
@@ -84,14 +140,49 @@ public class QwSopLogsController extends BaseController
                 QwUserKeyDTO key = new QwUserKeyDTO(log.getQwUserid(), log.getCorpId());
                 log.setQwUserName(userInfoMap.getOrDefault(key, "未知用户"));
             });
-
         }
 
-
         return getDataTable(list);
     }
 
+    /**
+     * 我的自动化任务 和部门自动化任务 就只显示自己的或者部门的
+     */
+    private List<Long> getQwUserKeyList(QwSopLogsParam param, LoginUser loginUser) {
 
+        switch (param.getFilterSopType()) {
+            case 2:
+                CompanyUser companyUser = iCompanyUserService.selectCompanyUserById(loginUser.getUser().getUserId());
+                return Arrays.stream(companyUser.getQwUserId().split(","))
+                        .map(String::trim)
+                        .filter(s -> !s.isEmpty())
+                        .map(Long::valueOf)
+                        .collect(Collectors.toList());
+
+            case 3:
+                QwSop qwSop = new QwSop();
+                qwSop.setCompanyId(loginUser.getCompany().getCompanyId());
+
+                List<Long> combinedList = new ArrayList<>();
+                // 本部门
+                Long deptId = loginUser.getUser().getDeptId();
+                if (deptId != null) {
+                    combinedList.add(deptId);
+                }
+                // 本部门的下级部门
+                List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+                if (!deptList.isEmpty()) {
+                    combinedList.addAll(deptList);
+                }
+                qwSop.setCuDeptIdList(combinedList);
+                qwSop.setUserType(loginUser.getUser().getUserType());
+
+                return iQwUserService.selectQwUserListByCuDeptIdList(qwSop);
+
+            default:
+                return new ArrayList<>(); // 返回空列表而不是null
+        }
+    }
     /**
      * 查询企业微信SOP  定时任务列表
      */

+ 69 - 13
fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java

@@ -9,6 +9,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.vo.SortDayVo;
@@ -41,6 +42,11 @@ public class QwSopTempController extends BaseController
     private IQwSopTempService qwSopTempService;
     @Autowired
     private TokenService tokenService;
+
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询sop模板列表
      */
@@ -57,10 +63,59 @@ public class QwSopTempController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询我创建的sop模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:myList')")
+    @GetMapping("/myList")
+    public TableDataInfo myList(QwSopTemp qwSopTemp)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwSopTemp.setCompanyId(loginUser.getCompany().getCompanyId());
+        qwSopTemp.setCreateBy(String.valueOf(loginUser.getUser().getUserId()));
+        startPage();
+//        List<QwSopTemp> list = qwSopTempService.selectQwSopTempList(qwSopTemp);
+        List<QwSopTemp> list = qwSopTempService.selectQwSopTempListNew(qwSopTemp);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 查询部门下的sop模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:deptList')")
+    @GetMapping("/deptList")
+    public TableDataInfo deptList(QwSopTemp qwSopTemp)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwSopTemp.setCompanyId(loginUser.getCompany().getCompanyId());
+
+        List<Long> combinedDpetList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedDpetList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedDpetList.addAll(deptList);
+        }
+        qwSopTemp.setCuDeptIdList(combinedDpetList);
+
+        startPage();
+//        List<QwSopTemp> list = qwSopTempService.selectQwSopTempList(qwSopTemp);
+        List<QwSopTemp> list = qwSopTempService.selectQwSopTempListNew(qwSopTemp);
+        return getDataTable(list);
+    }
+
+
     /**
      * 导出sop模板列表
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:export')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:export') or @ss.hasPermi('qw:sopTemp:myExport') or @ss.hasPermi('qw:sopTemp:deptExport')")
     @Log(title = "sop模板", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(QwSopTemp qwSopTemp)
@@ -81,7 +136,7 @@ public class QwSopTempController extends BaseController
     /**
      * 新增sop模板
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add') or @ss.hasPermi('qw:sopTemp:myAdd') or @ss.hasPermi('qw:sopTemp:deptAdd')")
     @Log(title = "sop模板", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody QwSopTemp qwSopTemp){
@@ -94,7 +149,7 @@ public class QwSopTempController extends BaseController
     /**
      * 修改sop模板
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @Log(title = "sop模板", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody QwSopTemp qwSopTemp)
@@ -109,7 +164,7 @@ public class QwSopTempController extends BaseController
     /**
      * 删除sop模板
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:remove')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:remove') or @ss.hasPermi('qw:sopTemp:myRemove') or @ss.hasPermi('qw:sopTemp:deptRemove')")
     @Log(title = "sop模板", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable String[] ids)
@@ -120,7 +175,7 @@ public class QwSopTempController extends BaseController
     }
 
     /** 分享sop模板 */
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:share')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:share') or @ss.hasPermi('qw:sopTemp:myShare') or @ss.hasPermi('qw:sopTemp:deptShare')")
     @Log(title = "分享sop模板", businessType = BusinessType.DELETE)
     @PostMapping("/shareTemp")
     public AjaxResult shareTemp(@RequestBody QwSopShareTempParam param)
@@ -130,7 +185,7 @@ public class QwSopTempController extends BaseController
 
 
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add') or @ss.hasPermi('qw:sopTemp:myAdd') or @ss.hasPermi('qw:sopTemp:deptAdd')")
     @Log(title = "sop模板addNew", businessType = BusinessType.INSERT)
     @PostMapping("/add")
     public AjaxResult addNew(@RequestBody QwSopTemp qwSopTemp){
@@ -148,7 +203,7 @@ public class QwSopTempController extends BaseController
         return toAjax(i);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @Log(title = "sop模板update", businessType = BusinessType.UPDATE)
     @PostMapping("/update")
     public AjaxResult updateNew(@RequestBody QwSopTemp qwSopTemp){
@@ -156,41 +211,42 @@ public class QwSopTempController extends BaseController
         return toAjax(update);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @Log(title = "addOrUpdateSop模板规则", businessType = BusinessType.UPDATE)
     @PostMapping("/addOrUpdateSetting")
     public AjaxResult addOrUpdateSetting(@RequestBody QwSopTempDay day){
         return AjaxResult.success(qwSopTempService.addOrUpdateSetting(day));
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @Log(title = "sop模板规则delRules", businessType = BusinessType.DELETE)
     @GetMapping("/delRules")
     public AjaxResult delRules(Long id){
         qwSopTempService.delRules(id);
         return toAjax(1);
     }
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:list')")
+
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:list') or @ss.hasPermi('qw:sopTemp:myList') or @ss.hasPermi('qw:sopTemp:deptList')")
     @GetMapping("/selectRulesInfo")
     public AjaxResult selectRulesInfo(Long id){
         return AjaxResult.success(qwSopTempService.selectRulesInfo(id));
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @PostMapping("/copyTemplate")
     public AjaxResult copyTemplate(@RequestBody QwSopTemp qwSopTemp){
         qwSopTempService.copyTemplate(qwSopTemp);
         return toAjax(1);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @PostMapping("/sortDay")
     public AjaxResult sortDay(@RequestBody List<SortDayVo> list){
         qwSopTempService.sortDay(list);
         return toAjax(1);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
     @GetMapping("/dayList")
     public AjaxResult dayList(String id){
         return AjaxResult.success(qwSopTempService.dayList(id));

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

@@ -10,14 +10,20 @@ import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwUserVoiceLog;
+import com.fs.qw.param.QwTagSearchParam;
+import com.fs.qw.service.IQwTagService;
 import com.fs.qw.service.IQwUserVoiceLogService;
 import com.fs.qw.vo.QwUserVoiceLogTotalVo;
 import com.fs.qw.vo.QwUserVoiceLogVo;
+import com.github.pagehelper.PageHelper;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
+import java.util.Objects;
 
 /**
  * 企微用户通话记录Controller
@@ -35,6 +41,9 @@ public class QwUserVoiceLogController extends BaseController
     @Autowired
     private TokenService tokenService;
 
+    @Autowired
+    private IQwTagService iQwTagService;
+
     /**
      * 查询企微用户通话记录列表
      */
@@ -49,6 +58,35 @@ public class QwUserVoiceLogController extends BaseController
         return getDataTable(list);
     }
 
+
+    /**
+     * 查询企微用户通话记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwUserVoiceLog:list')")
+    @PostMapping("/newList")
+    public TableDataInfo newList(@RequestBody QwUserVoiceLogVo qwUserVoiceLog)
+    {
+        PageHelper.startPage(qwUserVoiceLog.getPageNum(), qwUserVoiceLog.getPageSize());
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwUserVoiceLog.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<QwUserVoiceLogVo> list = qwUserVoiceLogService.selectQwUserVoiceLogList(qwUserVoiceLog);
+        list.forEach(item->{
+
+            if (!Objects.equals(item.getQwExternalContact().getTagIds(), "[]") && item.getQwExternalContact().getTagIds()!=null) {
+                QwTagSearchParam param = new QwTagSearchParam();
+                Gson gson = new Gson();
+                List<String> tagIds = gson.fromJson(
+                        item.getQwExternalContact().getTagIds(),
+                        new TypeToken<List<String>>() {
+                        }.getType()
+                );
+                param.setTagIds(tagIds);
+                item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
+            }
+        });
+        return getDataTable(list);
+    }
+
     /**
      * 查询我的通话记录列表
      * @param qwUserVoiceLog
@@ -141,6 +179,9 @@ public class QwUserVoiceLogController extends BaseController
     @GetMapping("/totalExport")
     public AjaxResult totalExport(QwUserVoiceLogTotalVo qwUserVoiceLog)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwUserVoiceLog.setCompanyId(loginUser.getCompany().getCompanyId());
+        qwUserVoiceLog.setQwUserId(1L);
         List<QwUserVoiceLogTotalVo> list = qwUserVoiceLogService.selectQwUserVoiceLogTotalList(qwUserVoiceLog);
         list.forEach(m-> {
             m.setQwUserName(m.getQwUser().getQwUserName());

+ 53 - 6
fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java

@@ -7,7 +7,10 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
+import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.param.SopUserLogsVO;
 import com.fs.qw.service.IQwUserService;
@@ -15,15 +18,19 @@ import com.fs.qw.vo.AddSopUserGroupChat;
 import com.fs.qw.vo.UpdateSopUserLogDateVo;
 import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.SopUserLogs;
+import com.fs.sop.dto.SopUserLogsParamDTO;
 import com.fs.sop.mapper.QwSopMapper;
 import com.fs.sop.params.SopUserLogsParam;
 import com.fs.sop.service.ISopUserLogsService;
+import com.fs.voice.utils.StringUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * sopUserLogsController
@@ -46,6 +53,9 @@ public class SopUserLogsController extends BaseController
     @Autowired
     private QwSopMapper sopMapper;
 
+    @Autowired
+    private IQwUserService iQwUserService;
+
     /**
      * 查询sopUserLogs列表
      */
@@ -55,22 +65,59 @@ public class SopUserLogsController extends BaseController
     {
         sopUserLogs.setStatus(1);
 
+        List<String> qwUserIds=null;
+        if (!StringUtil.strIsNullOrEmpty(sopUserLogs.getQwUserName())){
+            qwUserIds = qwUserMapper.selectQwUserByQwUserName(sopUserLogs.getQwUserName(),sopUserLogs.getCorpId());
+        }
+        if (qwUserIds!=null&& !qwUserIds.isEmpty()){
+            sopUserLogs.setQwUseridList(qwUserIds);
+        }
+
+        if (!StringUtil.strIsNullOrEmpty(sopUserLogs.getQwUserName()) && (qwUserIds==null || qwUserIds.isEmpty())){
+            return getDataTable(new ArrayList<>());
+        }
+
         QwSop qwSop = sopMapper.selectQwSopById(sopUserLogs.getSopId());
         Integer filterMode = qwSop.getFilterMode();
 
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        List<String> qwUserIdList=null;
+        if (sopUserLogs.getType()==2){
+            qwUserIdList = iQwUserService.selectQwUserListByCompanyUserId(loginUser.getUser().getUserId(), sopUserLogs.getCorpId());
+        }
+        if (qwUserIdList!=null&& !qwUserIdList.isEmpty() && sopUserLogs.getType()==2 ){
+            sopUserLogs.setQwIdsList(qwUserIdList);
+        }
+
         List<SopUserLogsVO> list=null;
         if(filterMode == null || filterMode == 1){
             startPage();
-             list = sopUserLogsService.selectSopUserLogsList(sopUserLogs);
+            list = sopUserLogsService.selectSopUserLogsList(sopUserLogs);
         }else {
             startPage();
             list = sopUserLogsService.selectSopUserLogsGroupListByParam(sopUserLogs);
         }
-
-        list.forEach(item->{
-            item.setQwUserName(qwUserMapper.selectQwUserByQwUserIdAndCorpId(item.getQwUserId(), item.getCorpId()));
-        });
-
+        if (!list.isEmpty()){
+            // 收集所有需要查询的 qwUserId 和 corpId 组合
+            List<SopUserLogsParamDTO> queryList = list.stream()
+                    .map(item -> new SopUserLogsParamDTO(item.getQwUserId(), item.getCorpId()))
+                    .distinct()  // 去重
+                    .collect(Collectors.toList());
+
+            List<QwUser> userList = qwUserMapper.batchSelectQwUserByQwUserIdAndCorpId(queryList);
+            Map<String, String> userMap = userList.stream()
+                    .collect(Collectors.toMap(
+                            user -> user.getQwUserId() + "_" + user.getCorpId(),
+                            QwUser::getQwUserName
+                    ));
+
+            // 设置用户名
+            list.forEach(item -> {
+                String key = item.getQwUserId() + "_" + item.getCorpId();
+                item.setQwUserName(userMap.get(key));
+            });
+        }
         return getDataTable(list);
     }
 

+ 136 - 35
fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsInfoController.java

@@ -31,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -70,7 +71,6 @@ public class SopUserLogsInfoController extends BaseController
     public TableDataInfo list(SopUserLogsInfo sopUserLogsInfo) {
         startPage();
         if (sopUserLogsInfo.getFilterMode() == 1) {
-            startPage();
             List<SopUserLogsInfo> list = sopUserLogsInfoService.selectSopUserLogsInfoList(sopUserLogsInfo);
 
             if (!list.isEmpty()) {
@@ -89,6 +89,7 @@ public class SopUserLogsInfoController extends BaseController
                                 QwExternalContactVOTime::getId,
                                 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());
                 if(!tagIds.isEmpty()){
                     List<QwTag> tagList = qwTagMapper.selectQwTagListByTagIdsNew(tagIds);
@@ -114,22 +115,14 @@ public class SopUserLogsInfoController extends BaseController
                 });
             }
 
-            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());
+
+            Predicate<SopUserLogsInfo> tagFilter = item ->
+                    sopUserLogsInfo.getTagIds() == null ||
+                            sopUserLogsInfo.getTagIds().isEmpty() ||
+                            item.getTagIds().contains(sopUserLogsInfo.getTagIds());
+
             Predicate<SopUserLogsInfo> remarkFilter = item ->
                     isRemarkEmpty ||
                             item.getRemark().contains(sopUserLogsInfo.getRemark());
@@ -142,34 +135,25 @@ public class SopUserLogsInfoController extends BaseController
 
 
             Predicate<SopUserLogsInfo> timeFilter = item -> {
-
-                if (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
-                        && StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime()) ) {
+                if (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getEntryTime())) {
                     return true;
                 }
                 try {
-                    LocalDateTime entryDate = LocalDateTime.parse(item.getInComTime(),
-                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+                    LocalDate entryDate = LocalDate.parse(
+                            sopUserLogsInfo.getEntryTime(),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd")
                     );
-                    LocalDateTime inComingSTime = LocalDateTime.parse(sopUserLogsInfo.getInComingSTime(),
-                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+                    LocalDate createDate = LocalDate.parse(
+                            item.getInComTime().substring(0, 10),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd")
                     );
-
-                    LocalDateTime inComingETime = LocalDateTime.parse(sopUserLogsInfo.getInComingETime(),
-                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
-                    );
-
-                    return !entryDate.isBefore(inComingSTime) && !entryDate.isAfter(inComingETime);
+                    return entryDate.equals(createDate);
                 } catch (Exception e) {
                     return false;
                 }
             };
 
-
-            boolean hasTimeFilter = !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
-                    && !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime());
-
-            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty || hasTimeFilter ||!isLevelEmpty) {
+            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty || !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getEntryTime()) ||!isLevelEmpty) {
                 list = list.stream()
                         .filter(tagFilter.and(remarkFilter).and(timeFilter).and(levelFilter))
                         .collect(Collectors.toList());
@@ -188,6 +172,123 @@ public class SopUserLogsInfoController extends BaseController
                 item.setLevelName(getLevel(item.getLevel()));
             });
 
+//            List<SopUserLogsInfo> list = sopUserLogsInfoService.selectSopUserLogsInfoList(sopUserLogsInfo);
+//
+//            if (!list.isEmpty()) {
+//                // 使用并行流提取externalId
+//                List<Long> externalIdList = list.parallelStream()
+//                        .map(SopUserLogsInfo::getExternalId)
+//                        .filter(Objects::nonNull)
+//                        .collect(Collectors.toList());
+//
+//                List<QwExternalContactVOTime> qwExternalContactVOTimes =
+//                        iQwExternalContactService.selectQwExternalContactListVOByIds(externalIdList);
+//
+//                // 构建联系人信息映射
+//                Map<Long, SopExternalContactInfo> externalContactInfoMap = qwExternalContactVOTimes.stream()
+//                        .collect(Collectors.toMap(
+//                                QwExternalContactVOTime::getId,
+//                                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());
+//                if(!tagIds.isEmpty()){
+//                    List<QwTag> tagList = qwTagMapper.selectQwTagListByTagIdsNew(tagIds);
+//                    Map<String, QwTag> tagMap = PubFun.listToMapByGroupObject(tagList, QwTag::getTagId);
+//                    qwExternalContactVOTimes.forEach(e -> {
+//                        List<String> tagId = JSON.parseArray(e.getTagIds(), String.class);
+//                        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 -> {
+//                    SopExternalContactInfo info = externalContactInfoMap.getOrDefault(
+//                            item.getExternalId(),
+//                            new SopExternalContactInfo("无进线时间", "无标签", "无备注",0));
+//                    item.setInComTime(info.getCreateTime());
+//                    item.setTagIds(info.getTagIds());
+//                    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());
+//            Predicate<SopUserLogsInfo> remarkFilter = item ->
+//                    isRemarkEmpty ||
+//                            item.getRemark().contains(sopUserLogsInfo.getRemark());
+//
+//
+//            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()
+//                        .filter(tagFilter.and(remarkFilter).and(timeFilter).and(levelFilter))
+//                        .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));
+//                }
+//
+//                // 处理 level
+//                item.setLevelName(getLevel(item.getLevel()));
+//            });
+
             return getDataTable(list);
         }
         else {
@@ -409,7 +510,7 @@ public class SopUserLogsInfoController extends BaseController
     /**
      * 一键群发sopUserLogsInfo
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopUserLogsInfo:msg')")
+    @PreAuthorize("@ss.hasPermi('qw:sopUserLogsInfo:msgSchedule')")
     @Log(title = "sendUserLogsInfoMsgType", businessType = BusinessType.INSERT,isSaveRequestData=false)
     @PostMapping("/sendUserLogsInfoMsgType")
     @RepeatSubmit
@@ -421,7 +522,7 @@ public class SopUserLogsInfoController extends BaseController
     /**
      * 一键群发sopUserLogsInfo
      */
-    @PreAuthorize("@ss.hasPermi('qw:sopUserLogsInfo:msg')")
+    @PreAuthorize("@ss.hasPermi('qw:sopUserLogsInfo:msgSop')")
     @Log(title = "sendUserLogsInfoMsgSop", businessType = BusinessType.INSERT,isSaveRequestData=false)
     @PostMapping("/sendUserLogsInfoMsgSop")
     @RepeatSubmit

+ 4 - 2
fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java

@@ -347,7 +347,8 @@ public class FsStoreOrderController extends BaseController
     @PutMapping("/sendGoods")
     public AjaxResult sendGoods(@RequestBody FsStoreOrder fsStoreOrder)
     {
-        return toAjax(fsStoreOrderService.sendGoods(fsStoreOrder));
+        String nickName = getLoginUser().getUser().getNickName();
+        return toAjax(fsStoreOrderService.sendGoods(fsStoreOrder,nickName));
     }
 
     @PutMapping("/bindCustomer")
@@ -401,7 +402,8 @@ public class FsStoreOrderController extends BaseController
     @RepeatSubmit
     public AjaxResult getGoods(@RequestBody FsStoreOrder fsStoreOrder)
     {
-        return toAjax(fsStoreOrderService.getGoods(fsStoreOrder.getOrderId()));
+        String nickName = getLoginUser().getUser().getNickName();
+        return toAjax(fsStoreOrderService.getGoods(fsStoreOrder.getOrderId(),nickName));
     }
 
     /**

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

@@ -67,7 +67,7 @@ public class FsUserController extends BaseController
         startPage();
         LoginUser loginUser = SecurityUtils.getLoginUser();
         fsUser.setCompanyId(loginUser.getCompany().getCompanyId());
-        if(fsUser.getPhoneMk()!=null&&fsUser.getPhone()!=""){
+        if(fsUser.getPhoneMk()!=null&&StringUtils.isBlank(fsUser.getPhone())){
             fsUser.setPhone(encryptPhone(fsUser.getPhoneMk()));
         }
 

+ 1 - 0
fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java

@@ -123,6 +123,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .antMatchers("/pay/wxPay/payNotify**").anonymous()
                 .antMatchers("/common/uploadWang**").anonymous()
                 .antMatchers("/common/download**").anonymous()
+                .antMatchers("/common/test").anonymous()
                 .antMatchers("/common/download/resource**").anonymous()
                 .antMatchers("/swagger-ui.html").anonymous()
                 .antMatchers("/swagger-resources/**").anonymous()

+ 74 - 6
fs-doctor-app/src/main/java/com/fs/app/controller/DoctorController.java

@@ -1,6 +1,7 @@
 package com.fs.app.controller;
 
 
+import cn.hutool.http.HttpRequest;
 import cn.hutool.json.JSONUtil;
 import com.fs.app.annotation.Login;
 import com.fs.app.param.DoctorEditParam;
@@ -20,13 +21,17 @@ import com.fs.his.param.FsDoctorExtractListSParam;
 import com.fs.his.service.*;
 import com.fs.his.vo.FsDoctorBillListSVO;
 import com.fs.his.vo.FsDoctorExtractListSVO;
+import com.fs.im.service.OpenIMService;
 import com.fs.sms.service.SmsService;
 import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import com.github.pagehelper.util.StringUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.StringUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -34,10 +39,7 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.math.BigDecimal;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 
 
@@ -59,7 +61,8 @@ public class DoctorController extends  AppBaseController {
     private IFsDoctorExtractService doctorExtractService;
     @Autowired
     private ISysConfigService configService;
-
+    @Autowired
+    private OpenIMService openIMService;
     @Autowired
     private SmsService smsService;
     @ApiOperation("登录")
@@ -100,7 +103,72 @@ public class DoctorController extends  AppBaseController {
             return R.ok(map);
         }
     }
-
+    @ApiOperation("校验医生是否注册新的im")
+    @PostMapping("/accountCheck")
+    public R accountCheck(@RequestBody Map<String, String> userIdMap){
+        //获取管理员token
+        String userId = userIdMap.get("userId");
+        String adminToken = openIMService.getAdminToken();
+        JSONObject requestBody = new JSONObject();
+        // 解析响应
+        if (StringUtil.isNotEmpty(adminToken)) {
+            //查询用户是否注册
+            ArrayList<String> userIds = new ArrayList<>();
+            requestBody = new JSONObject();
+            userIds.add(userId);
+            requestBody.put("checkUserIDs", userIds);
+            String body = HttpRequest.post("https://web.im.cdwjyyh.com/api/user/account_check")
+                    .header("operationID", String.valueOf(System.currentTimeMillis()))
+                    .header("token", adminToken)
+                    .body(requestBody.toString())
+                    .execute()
+                    .body();
+            JSONObject jsonObject = new JSONObject(body);
+            JSONArray results = jsonObject.getJSONObject("data").getJSONArray("results");
+            if (results != null && results.length() > 0) {
+                JSONObject resultObj = results.getJSONObject(0);
+                int accountStatus = resultObj.getInt("accountStatus");
+                //未注册自动注册
+                if (accountStatus==0){
+                    String s = userId.replaceFirst("^D", "");
+                    FsDoctor fsDoctor = doctorService.selectFsDoctorByDoctorId(Long.parseLong(s));
+                    if (null==fsDoctor){
+                        return R.error("用户不存在");
+                    }
+                    ArrayList<Object> users = new ArrayList<>();
+                    HashMap<String, String> map = new HashMap<>();
+                    map.put("userID",userId);
+                    map.put("nickname",fsDoctor.getDoctorName());
+                    map.put("faceURL",fsDoctor.getAvatar());
+                    users.add(map);
+                    requestBody = new JSONObject();
+                    userIds.add(userId);
+                    requestBody.put("users", users);
+                    HttpRequest.post("https://web.im.cdwjyyh.com/api/user/user_register")
+                            .header("operationID", String.valueOf(System.currentTimeMillis()))
+                            .header("token", adminToken).body(requestBody.toString()).execute().body();
+                }
+            } else {
+                return R.error("返回结果为空");
+            }
+           /* HashMap<String, String> tokenMap = new HashMap<>();
+            tokenMap.put("platformID","1");
+            tokenMap.put("userID",userId);*/
+            requestBody = new JSONObject();
+            requestBody.put("platformID",5);
+            requestBody.put("userID",userId);
+            String body1 = HttpRequest.post("https://web.im.cdwjyyh.com/api/auth/get_user_token")
+                    .header("operationID", String.valueOf(System.currentTimeMillis()))
+                    .header("token", adminToken)
+                    .body(requestBody.toString()).execute().body();
+            JSONObject userJson = new JSONObject(body1);
+            JSONObject userData = userJson.getJSONObject("data");
+            String userToken = userData.getString("token");
+            return R.ok().put("token", userToken);
+        } else {
+            return R.error("获取管理员token失败");
+        }
+    }
     @ApiOperation("登录")
     @PostMapping("/loginByWeb")
     public R loginByWeb(@Validated @RequestBody DoctorLoginParam param) {

+ 7 - 6
fs-doctor-app/src/main/java/com/fs/framework/config/MyBatisConfig.java

@@ -1,5 +1,6 @@
 package com.fs.framework.config;
 
+import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
 import com.fs.common.utils.StringUtils;
 import org.apache.ibatis.io.VFS;
 import org.apache.ibatis.session.SqlSessionFactory;
@@ -115,18 +116,18 @@ public class MyBatisConfig
     }
 
     @Bean
-    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
+    public SqlSessionFactory sqlSessionFactorys(DataSource dataSource) throws Exception
     {
-        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
-        String mapperLocations = env.getProperty("mybatis.mapperLocations");
-        String configLocation = env.getProperty("mybatis.configLocation");
+        String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage");
+        String mapperLocations = env.getProperty("mybatis-plus.mapperLocations");
+        String configLocation = env.getProperty("mybatis-plus.configLocation");
         typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
         VFS.addImplClass(SpringBootVFS.class);
 
-        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
+        final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
         sessionFactory.setDataSource(dataSource);
         sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
-        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
+        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
         sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
         return sessionFactory.getObject();
     }

+ 14 - 2
fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java

@@ -8,7 +8,6 @@ import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.utils.PubFun;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.course.config.CourseConfig;
-import com.fs.course.config.CourseMaConfig;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.ipad.vo.BaseVo;
@@ -53,6 +52,7 @@ public class SendMsg {
     private final IQwSopLogsService qwSopLogsService;
     private final QwIpadServerMapper qwIpadServerMapper;
     private final RedisCacheT<Long> redisCache;
+    private final AsyncSopTestService asyncSopTestService;
     private final ICompanyMiniappService companyMiniappService;
     private final IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
 
@@ -65,7 +65,7 @@ public class SendMsg {
     @Qualifier("customThreadPool")
     private ThreadPoolTaskExecutor customThreadPool;
 
-    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, QwIpadServerMapper qwIpadServerMapper, RedisCacheT<Long> redisCache, ICompanyMiniappService companyMiniappService, IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService) {
+    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, QwIpadServerMapper qwIpadServerMapper, RedisCacheT<Long> redisCache, AsyncSopTestService asyncSopTestService, ICompanyMiniappService companyMiniappService, IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService) {
         this.qwUserMapper = qwUserMapper;
         this.qwSopLogsMapper = qwSopLogsMapper;
         this.sendServer = sendServer;
@@ -73,6 +73,7 @@ public class SendMsg {
         this.qwSopLogsService = qwSopLogsService;
         this.qwIpadServerMapper = qwIpadServerMapper;
         this.redisCache = redisCache;
+        this.asyncSopTestService = asyncSopTestService;
         this.companyMiniappService = companyMiniappService;
         this.fsCoursePlaySourceConfigService = fsCoursePlaySourceConfigService;
     }
@@ -213,6 +214,17 @@ public class SendMsg {
                     log.error("线程等待错误!");
                 }
             }
+            // 推送 APP
+//            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);
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             QwSopLogs updateQwSop = new QwSopLogs();

+ 118 - 41
fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java

@@ -1,11 +1,18 @@
 package com.fs.app.controller;
 
+import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.uuid.IdUtils;
+import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.service.AiHookService;
+import com.fs.fastGpt.service.IFastGptRoleService;
 import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.dto.ExpressInfoDTO;
+import com.fs.his.dto.TracesDTO;
+import com.fs.his.enums.ShipperCodeEnum;
+import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
@@ -31,6 +38,8 @@ import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static com.fs.his.utils.PhoneUtil.decryptPhone;
+
 
 @Api("企微消息")
 @RestController
@@ -59,58 +68,126 @@ public class QwMsgController {
     SopUserLogsInfoMapper sopUserLogsInfoMapper;
     @Autowired
     QwSopLogsMapper qwSopLogsMapper;
+    @Autowired
+    private IFastGptRoleService fastGptRoleService;
+    @Autowired
+    private IFsExpressService expressService;
+    @Autowired
+    private IFsStoreOrderService storeOrderService;
 
     @GetMapping("/sendExpressInfo/{orderId}")
     public R sendExpressInfo(@PathVariable Long orderId){
-        FsStoreOrder order = fsStoreOrderService.selectFsStoreOrderByOrderId(orderId);
-        if(order != null && order.getUserId() != null){
-            List<QwExternalContact> qwExternalContact = externalContactService.selectQwExternalContactByFsUserId(order.getUserId());
-            if(qwExternalContact != null && !qwExternalContact.isEmpty()){
-                for (QwExternalContact externalContact : qwExternalContact) {
-                    Long qwUserId = externalContact.getQwUserId();
-                    if(qwUserId != null ){
-                        QwUser qwUser = qwUserMapper.selectQwUserById(qwUserId);
-                        if(qwUser != null && qwUser.getUid() != null && qwUser.getServerId() != null && qwUser.getServerStatus() == 1 && qwUser.getIpadStatus() == 1){
-                            WxWorkUserId2VidDTO wxWorkUserId2VidDTO = new WxWorkUserId2VidDTO();
-                            wxWorkUserId2VidDTO.setOpenid(Collections.singletonList(externalContact.getExternalUserId()));
-                            wxWorkUserId2VidDTO.setUuid(qwUser.getUid());
-                            WxWorkResponseDTO<List<WxWorkVid2UserIdRespDTO>> WxWorkVid2UserIdRespDTO = wxWorkService.UserId2Vid(wxWorkUserId2VidDTO,qwUser.getServerId());
-                            List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
-                            StringBuilder sBuilder = new StringBuilder();
-                            if(data != null && !data.isEmpty()){
-                                Long sendId = data.get(0).getUser_id();
-                                switch (order.getStatus())
-                                {
-                                    case -1:
-                                    case -2:
-                                    case 1:
-                                        break;
-                                    case 2:
-                                        sBuilder.append("您好,您购买的").append(order.getPackageName()).append("正在准备发货,请耐心等待;\n").append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
-                                        break;
-                                    case 3:
-                                    case 4:
-                                    case 5:
-                                        break;
+        String isSend = redisCache.getCacheObject("fs:express:info:send:" +orderId);
+        if(isSend == null){
+            redisCache.setCacheObject("fs:express:info:send:" +orderId, "1",2, TimeUnit.MINUTES);
+            FsStoreOrder order = fsStoreOrderService.selectFsStoreOrderByOrderId(orderId);
+            if(order != null && order.getUserId() != null){
+                List<QwExternalContact> qwExternalContact = externalContactService.selectQwExternalContactByFsUserIdAndCompany(order.getUserId(),order.getCompanyUserId());
+                if(qwExternalContact != null && !qwExternalContact.isEmpty()){
+                    for (QwExternalContact externalContact : qwExternalContact) {
+                        Long qwUserId = externalContact.getQwUserId();
+                        if(qwUserId != null ){
+                            QwUser qwUser = qwUserMapper.selectQwUserById(qwUserId);
+                            if(qwUser != null && qwUser.getUid() != null && qwUser.getFastGptRoleId() != null && qwUser.getServerId() != null && qwUser.getServerStatus() == 1 && qwUser.getIpadStatus() == 1){
+                                FastGptRole fastGptRole = fastGptRoleService.selectFastGptRoleByRoleId(qwUser.getFastGptRoleId());
+                                if(fastGptRole.getLogistics() == 0){
+                                    log.error("物流功能未开启,roleId:" + qwUser.getFastGptRoleId() + "订单号:" + orderId);
+                                    return R.ok();
                                 }
-                                if(!"".contentEquals(sBuilder)){
-                                    //2.发送模板中的文字内容
-                                    String content = sBuilder.toString();
-                                    WxWorkSendTextMsgDTO wxWorkSendTextMsgDTO = new WxWorkSendTextMsgDTO();
-                                    wxWorkSendTextMsgDTO.setSend_userid(sendId);
-                                    wxWorkSendTextMsgDTO.setUuid(qwUser.getUid());
-                                    wxWorkSendTextMsgDTO.setContent(content);
-                                    wxWorkSendTextMsgDTO.setIsRoom(false);
-                                    wxWorkService.SendTextMsg(wxWorkSendTextMsgDTO,qwUser.getServerId());
+                                WxWorkUserId2VidDTO wxWorkUserId2VidDTO = new WxWorkUserId2VidDTO();
+                                wxWorkUserId2VidDTO.setOpenid(Collections.singletonList(externalContact.getExternalUserId()));
+                                wxWorkUserId2VidDTO.setUuid(qwUser.getUid());
+                                WxWorkResponseDTO<List<WxWorkVid2UserIdRespDTO>> WxWorkVid2UserIdRespDTO = wxWorkService.UserId2Vid(wxWorkUserId2VidDTO,qwUser.getServerId());
+                                List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
+                                StringBuilder sBuilder = new StringBuilder();
+                                if(data != null && !data.isEmpty()){
+                                    Long sendId = data.get(0).getUser_id();
+                                    switch (order.getStatus())
+                                    {
+                                        case -1:
+                                        case -2:
+                                        case 1:
+                                            break;
+                                        case 2:
+                                            sBuilder.append("您好,您有一个包裹正在准备发货,请耐心等待;\n");
+                                            if(order.getDeliverySn() != null && !order.getDeliverySn().isEmpty()){
+                                                sBuilder.append(" 物流单号为:").append(order.getDeliverySn()).append("\n");
+                                            }
+                                            sBuilder.append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
+                                            break;
+                                        case 3:
+                                            ExpressInfoDTO express = getExpress(order.getOrderId());
+                                            if("211".equals(express.getStateEx())){
+                                                //你好,这边查询到您购买的XXX(购买套餐)在XXX(时间)已经送到了,送货员电话为XXX(送货员信息)
+                                                sBuilder.append("这边查询到您有一个包裹 ");
+                                                if(express != null && express.getTraces() != null && !express.getTraces().isEmpty()){
+                                                    List<TracesDTO> traces = express.getTraces();
+                                                    TracesDTO tracesDTO = traces.get(traces.size() - 1);
+                                                    sBuilder.append(" 在").append(tracesDTO.getAcceptTime()).append("已经送到了\n");
+                                                    sBuilder.append(" 物流单号为:").append(order.getDeliverySn()).append("\n");
+                                                    sBuilder.append("物流信息:").append(tracesDTO.getAcceptStation()).append("\n");
+                                                }else{
+                                                    sBuilder.append(" 已经送到了\n");
+                                                }
+                                                sBuilder.append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
+                                            }
+                                            break;
+                                        case 4:
+                                        case 5:
+                                    }
+                                    if(!"".contentEquals(sBuilder)){
+                                        //2.发送模板中的文字内容
+                                        String content = sBuilder.toString();
+                                        content = content.replace("(有事呼叫我,勿找平台,少一次投诉,多一份感恩)", "");
+                                        WxWorkSendTextMsgDTO wxWorkSendTextMsgDTO = new WxWorkSendTextMsgDTO();
+                                        wxWorkSendTextMsgDTO.setSend_userid(sendId);
+                                        wxWorkSendTextMsgDTO.setUuid(qwUser.getUid());
+                                        wxWorkSendTextMsgDTO.setContent(content);
+                                        wxWorkSendTextMsgDTO.setIsRoom(false);
+                                        wxWorkService.SendTextMsg(wxWorkSendTextMsgDTO,qwUser.getServerId());
+                                    }
+                                    return R.ok();
                                 }
-                                return R.ok();
                             }
                         }
                     }
                 }
             }
         }
-        return null;
+        return R.ok();
+    }
+
+    public ExpressInfoDTO getExpress(Long id){
+        FsStoreOrder order=storeOrderService.selectFsStoreOrderByOrderId(id);
+
+        ExpressInfoDTO expressInfoDTO=null;
+        if(com.fs.common.utils.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";
+                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 expressInfoDTO;
     }
 
 

+ 0 - 12
fs-qw-api/src/main/java/com/fs/app/service/QwDataCallbackService.java

@@ -111,18 +111,6 @@ public class QwDataCallbackService {
                         delQwUser.setIsDel(2);
                         delQwUser.setStatus(0);
                         qwUserMapper.updateQwUser(delQwUser);
-                        QwExternalContact qwExternalContact = new QwExternalContact();
-                        qwExternalContact.setUserId(fromUserName);
-                        qwExternalContact.setStatus(0);
-                        qwExternalContact.setCorpId(corpId);
-                        List<QwExternalContact> qwExternalContacts = qwExternalContactService.selectQwExternalContactList(qwExternalContact);
-                        for (QwExternalContact externalContact : qwExternalContacts) {
-                            QwExternalContact lz = new QwExternalContact();
-                            lz.setId(externalContact.getId());
-                            lz.setStatus(1);
-                            qwExternalContactMapper.updateQwExternalContact(lz);
-                        }
-
                     }
                     break;
                 case "subscribe":

+ 19 - 2
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -13,7 +13,10 @@ import com.fs.course.param.newfs.FsUserCourseAddCompanyUserParam;
 import com.fs.course.service.*;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsInquiryOrderService;
+import com.fs.his.utils.qrcode.QRCodeUtils;
+import com.fs.qw.domain.QwCompany;
 import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwMaterialService;
 import com.fs.qwApi.service.QwApiService;
@@ -225,10 +228,24 @@ public class CommonController {
         return R.ok();
     }
 
+    @Autowired
+    IQwCompanyService iQwCompanyService;
     @GetMapping("/testSop2")
     public R testSop2() throws Exception {
-//        qwSopLogsService.createCorpMassSending();
-        return R.ok();
+
+        String cropId="ww401085d7b785aae8";
+
+        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(cropId);
+
+        String status="100_asddas_6666";
+
+        String url="https://open.weixin.qq.com/connect/oauth2/authorize?appid="+cropId+"&redirect_uri=" +
+                "http://"+qwCompany.getRealmNameUrl()+"/qwh5/pages/user/index?corpId="+cropId +
+                "&response_type=code&scope=snsapi_base&state="+status+"&agentid="+qwCompany.getServerAgentId()+"#wechat_redirect";
+
+        R andUpload = QRCodeUtils.createAndUpload(url);
+
+        return R.ok().put("data",andUpload);
     }
 
     @Autowired

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

@@ -93,7 +93,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
     // Batch size for database inserts, configurable via application.properties
-    private final int BATCH_SIZE = 1000;
+    private final int BATCH_SIZE = 500;
 
     @Autowired
     private IFsCourseLinkService courseLinkService;
@@ -950,21 +950,24 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     String sortLink = createLinkByMiniApp(setting, logVo, sendTime, courseId, videoId,
                             qwUserId, companyUserId, companyId, externalId,isOfficial,sopLogs.getFsUserId());
 
+                    if(sopLogs.getSendType()==1){
+                        setting.setMiniprogramAppid(miniAppId);
+                    }else {
+                        //算主备小程序
+                        String finalAppId = getAppIdFromMiniMap(miniMap, companyId, sendMsgType, grade);
 
-                    //算主备小程序
-                    String finalAppId = getAppIdFromMiniMap(miniMap, companyId, sendMsgType, grade);
+                        if (StringUtil.strIsNullOrEmpty(finalAppId)) {
+                            finalAppId = miniAppId;
+                        }
 
-                    if (StringUtil.strIsNullOrEmpty(finalAppId)) {
-                        finalAppId = miniAppId;
-                    }
+                        if (!StringUtil.strIsNullOrEmpty(finalAppId)) {
+                            setting.setMiniprogramAppid(finalAppId);
+                        } else {
+                            log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
+                        }
 
-                    if (!StringUtil.strIsNullOrEmpty(finalAppId)) {
-                        setting.setMiniprogramAppid(finalAppId);
-                    } else {
-                        log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
                     }
 
-
                     setting.setMiniprogramPage(sortLink.replaceAll("^[\\s\\u2005]+", ""));
 
                     try {

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

@@ -1,8 +1,20 @@
 package com.fs.app.controller;
 
+import com.fs.app.params.LoginBindCompanyParam;
+import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
+import com.fs.common.enums.BusinessType;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.base.BaseException;
+import com.fs.common.utils.PatternUtils;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.param.CompanyUserCodeParam;
+import com.fs.company.service.ICompanyPostService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwUser;
@@ -21,6 +33,7 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.HashMap;
@@ -42,6 +55,19 @@ public class ApisQwUserController extends BaseController {
     @Autowired
     private ISopUserLogsInfoService iSopUserLogsInfoService;
 
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    ICompanyUserService userService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    ICompanyPostService postService;
+
+
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -116,4 +142,50 @@ public class ApisQwUserController extends BaseController {
         return R.ok().put("data", result);
     }
 
+    /**
+     * 注册或者绑定销售
+     */
+    @PostMapping("/registerCompany")
+    @Log(title = "注册或者绑定销售", businessType = BusinessType.INSERT)
+    public R registerCompany(@RequestBody CompanyUserCodeParam userCodeParam) {
+        return companyUserService.registerCompany(userCodeParam);
+    }
+
+    @PostMapping("/login")
+    @ApiOperation("密码登录")
+    public R login(@Validated @RequestBody LoginBindCompanyParam param) {
+
+        // 密码校验
+        if (!PatternUtils.checkPassword(param.getPassword())) {
+            return R.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20位");
+        }
+
+        try {
+
+            //判断用户基本规则
+            CompanyUser companyUser = userService.selectUserByUserName(param.getAccount());
+            if (companyUser == null) {
+                return R.error("工号不存在");
+            }
+            if (companyUser.getStatus().equals("1")) {
+                return R.error("用户已禁用");
+            }
+            if (!SecurityUtils.matchesPassword(param.getPassword(), companyUser.getPassword())) {
+                return R.error("密码错误");
+            }
+            if (companyUser.getIsAudit() == 0) {
+                return R.error("用户未审核");
+            }
+
+            Company company = companyService.selectCompanyById(companyUser.getCompanyId());
+            if (company == null || company.getStatus() == 0 || company.getIsDel() == 1) {
+                throw new BaseException("此用户所属公司不存在或已停用");
+            }
+
+            return R.ok("验证成功");
+        } catch (Exception e) {
+            return R.error("登录异常:"+e.getMessage());
+        }
+    }
+
 }

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

@@ -1,9 +1,21 @@
 package com.fs.app.controller;
 
+import com.fs.app.params.LoginBindCompanyParam;
 import com.fs.common.BeanCopyUtils;
+import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
+import com.fs.common.enums.BusinessType;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.base.BaseException;
+import com.fs.common.utils.PatternUtils;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.param.CompanyUserCodeParam;
+import com.fs.company.service.ICompanyPostService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.param.ExternalContactDetailsParam;
@@ -27,6 +39,7 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.HashMap;
@@ -51,6 +64,18 @@ public class QwUserController extends BaseController {
     @Autowired
     private ISopUserLogsInfoService iSopUserLogsInfoService;
 
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    ICompanyUserService userService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    ICompanyPostService postService;
+
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -150,5 +175,50 @@ public class QwUserController extends BaseController {
         return R.error();
     }
 
+    /**
+     * 注册或者绑定销售
+     */
+    @PostMapping("/registerCompany")
+    @Log(title = "注册或者绑定销售", businessType = BusinessType.INSERT)
+    public R registerCompany(@RequestBody CompanyUserCodeParam userCodeParam) {
+        return companyUserService.registerCompany(userCodeParam);
+    }
+
+    @PostMapping("/login")
+    @ApiOperation("密码登录")
+    public R login(@Validated @RequestBody LoginBindCompanyParam param) {
+
+        // 密码校验
+        if (!PatternUtils.checkPassword(param.getPassword())) {
+            return R.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20位");
+        }
+
+        try {
+
+            //判断用户基本规则
+            CompanyUser companyUser = userService.selectUserByUserName(param.getAccount());
+            if (companyUser == null) {
+                return R.error("工号不存在");
+            }
+            if (companyUser.getStatus().equals("1")) {
+                return R.error("用户已禁用");
+            }
+            if (!SecurityUtils.matchesPassword(param.getPassword(), companyUser.getPassword())) {
+                return R.error("密码错误");
+            }
+            if (companyUser.getIsAudit() == 0) {
+                return R.error("用户未审核");
+            }
+
+            Company company = companyService.selectCompanyById(companyUser.getCompanyId());
+            if (company == null || company.getStatus() == 0 || company.getIsDel() == 1) {
+                throw new BaseException("此用户所属公司不存在或已停用");
+            }
+
+            return R.ok("验证成功");
+        } catch (Exception e) {
+            return R.error("登录异常:"+e.getMessage());
+        }
+    }
 
 }

+ 16 - 0
fs-qwhook-sop/src/main/java/com/fs/app/params/LoginBindCompanyParam.java

@@ -0,0 +1,16 @@
+package com.fs.app.params;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class LoginBindCompanyParam {
+    @NotBlank(message = "请填写帐号")
+    private String account;
+    @NotBlank(message = "请填写密码")
+    private String password;
+}

+ 8 - 7
fs-qwhook-sop/src/main/java/com/fs/framework/config/MyBatisConfig.java

@@ -1,5 +1,6 @@
 package com.fs.framework.config;
 
+import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
 import com.fs.common.utils.StringUtils;
 import org.apache.ibatis.io.VFS;
 import org.apache.ibatis.session.SqlSessionFactory;
@@ -27,7 +28,7 @@ import java.util.List;
 
 /**
  * Mybatis支持*匹配扫描包
- * 
+ *
 
  */
 @Configuration
@@ -115,18 +116,18 @@ public class MyBatisConfig
     }
 
     @Bean
-    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
+    public SqlSessionFactory sqlSessionFactorys(DataSource dataSource) throws Exception
     {
-        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
-        String mapperLocations = env.getProperty("mybatis.mapperLocations");
-        String configLocation = env.getProperty("mybatis.configLocation");
+        String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage");
+        String mapperLocations = env.getProperty("mybatis-plus.mapperLocations");
+        String configLocation = env.getProperty("mybatis-plus.configLocation");
         typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
         VFS.addImplClass(SpringBootVFS.class);
 
-        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
+        final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
         sessionFactory.setDataSource(dataSource);
         sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
-        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
+        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
         sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
         return sessionFactory.getObject();
     }

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

@@ -1,10 +1,22 @@
 package com.fs.app.controller;
 
+import com.fs.app.params.LoginBindCompanyParam;
 import com.fs.common.BeanCopyUtils;
+import com.fs.common.annotation.Log;
 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.enums.BusinessType;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.base.BaseException;
+import com.fs.common.utils.PatternUtils;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.param.CompanyUserCodeParam;
+import com.fs.company.service.ICompanyPostService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
@@ -32,6 +44,7 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.HashMap;
@@ -56,6 +69,19 @@ public class ApisQwUserController extends BaseController {
     @Autowired
     private ISopUserLogsInfoService iSopUserLogsInfoService;
 
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    ICompanyUserService userService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    ICompanyPostService postService;
+
+
 
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
@@ -184,5 +210,51 @@ public class ApisQwUserController extends BaseController {
         return R.error();
     }
 
+    /**
+     * 注册或者绑定销售
+     */
+    @PostMapping("/registerCompany")
+    @Log(title = "注册或者绑定销售", businessType = BusinessType.INSERT)
+    public R registerCompany(@RequestBody CompanyUserCodeParam userCodeParam) {
+        return companyUserService.registerCompany(userCodeParam);
+    }
+
+    @PostMapping("/login")
+    @ApiOperation("密码登录")
+    public R login(@Validated @RequestBody LoginBindCompanyParam param) {
+
+        // 密码校验
+        if (!PatternUtils.checkPassword(param.getPassword())) {
+            return R.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20位");
+        }
+
+        try {
+
+            //判断用户基本规则
+            CompanyUser companyUser = userService.selectUserByUserName(param.getAccount());
+            if (companyUser == null) {
+                return R.error("工号不存在");
+            }
+            if (companyUser.getStatus().equals("1")) {
+                return R.error("用户已禁用");
+            }
+            if (!SecurityUtils.matchesPassword(param.getPassword(), companyUser.getPassword())) {
+                return R.error("密码错误");
+            }
+            if (companyUser.getIsAudit() == 0) {
+                return R.error("用户未审核");
+            }
+
+            Company company = companyService.selectCompanyById(companyUser.getCompanyId());
+            if (company == null || company.getStatus() == 0 || company.getIsDel() == 1) {
+                throw new BaseException("此用户所属公司不存在或已停用");
+            }
+
+            return R.ok("验证成功");
+        } catch (Exception e) {
+            return R.error("登录异常:"+e.getMessage());
+        }
+    }
+
 
 }

+ 74 - 3
fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java

@@ -1,9 +1,24 @@
 package com.fs.app.controller;
 
+import cn.hutool.json.JSONUtil;
+import com.fs.app.params.LoginBindCompanyParam;
 import com.fs.common.BeanCopyUtils;
+import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
+import com.fs.common.enums.BusinessType;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.base.BaseException;
+import com.fs.common.param.LoginParam;
+import com.fs.common.utils.PatternUtils;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.param.CompanyUserCodeParam;
+import com.fs.company.service.ICompanyPostService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.param.ExternalContactDetailsParam;
@@ -27,11 +42,11 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
 
 @Slf4j
 @Api(tags = "企微会员相关接口")
@@ -51,6 +66,18 @@ public class QwUserController extends BaseController {
     @Autowired
     private ISopUserLogsInfoService iSopUserLogsInfoService;
 
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    ICompanyUserService userService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    ICompanyPostService postService;
+
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -150,5 +177,49 @@ public class QwUserController extends BaseController {
         return R.error();
     }
 
+    /**
+    * 注册或者绑定销售
+    */
+    @PostMapping("/registerCompany")
+    @Log(title = "注册或者绑定销售", businessType = BusinessType.INSERT)
+    public R registerCompany(@RequestBody CompanyUserCodeParam userCodeParam) {
+        return companyUserService.registerCompany(userCodeParam);
+    }
+
+    @PostMapping("/login")
+    @ApiOperation("密码登录")
+    public R login(@Validated @RequestBody LoginBindCompanyParam param) {
 
+        // 密码校验
+        if (!PatternUtils.checkPassword(param.getPassword())) {
+            return R.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20位");
+        }
+
+        try {
+
+            //判断用户基本规则
+            CompanyUser companyUser = userService.selectUserByUserName(param.getAccount());
+            if (companyUser == null) {
+                return R.error("工号不存在");
+            }
+            if (companyUser.getStatus().equals("1")) {
+                return R.error("用户已禁用");
+            }
+            if (!SecurityUtils.matchesPassword(param.getPassword(), companyUser.getPassword())) {
+                return R.error("密码错误");
+            }
+            if (companyUser.getIsAudit() == 0) {
+                return R.error("用户未审核");
+            }
+
+            Company company = companyService.selectCompanyById(companyUser.getCompanyId());
+            if (company == null || company.getStatus() == 0 || company.getIsDel() == 1) {
+                throw new BaseException("此用户所属公司不存在或已停用");
+            }
+
+            return R.ok("验证成功");
+        } catch (Exception e) {
+            return R.error("登录异常:"+e.getMessage());
+        }
+    }
 }

+ 17 - 0
fs-qwhook/src/main/java/com/fs/app/params/LoginBindCompanyParam.java

@@ -0,0 +1,17 @@
+package com.fs.app.params;
+
+import com.fasterxml.jackson.annotation.JsonAlias;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class LoginBindCompanyParam {
+    @NotBlank(message = "请填写帐号")
+    private String account;
+    @NotBlank(message = "请填写密码")
+    private String password;
+}

+ 2 - 0
fs-service/src/main/java/com/fs/aiTongueApi/config/AiTongueConfig.java

@@ -5,4 +5,6 @@ public interface AiTongueConfig {
     String quanxiUrl="https://api.aikanshe.com/agency/quanxi";
     String checkTongue="https://api.aikanshe.com/agency/checkTongue";
     String appKey="";
+
+    String newCheckTongue="http://132.232.234.246:5056/api/detect";
 }

+ 58 - 0
fs-service/src/main/java/com/fs/aiTongueApi/domain/enums/TongueTypeEnums.java

@@ -0,0 +1,58 @@
+package com.fs.aiTongueApi.domain.enums;
+
+public enum TongueTypeEnums {
+
+    SheZhi_xianHong("SheZhi","01","主热证,可能是身体积热过多。舌尖红有芒刺表示心火上炎;"),
+    SheZhi_danBai("SheZhi","02","淡白舌而属于机体虚证、寒证之舌象。"),
+    SheZhi_danHong("SheZhi","03","为正常舌色或者疾病初期舌象。"),
+    SheZhi_zi("SheZhi","04","舌质带紫色,有可能是拍照原因。"),
+
+    TaiSe_huang("TaiSe","01","主里证、热证。舌苔灰黄而干燥,表示身体有内热,耗伤津液。"),
+    TaiSe_hui("TaiSe","02","主里证苔厚腻,为湿浊、痰饮。"),
+    TaiSe_bai("TaiSe","03","舌苔薄白为正常舌苔或表证初起。苔白而润滑,为里寒证;"),
+
+    Xing_boTuo("Xing","01","舌见剥落表示脏腑气阴不平衡。"),
+    Xing_chiHen("Xing","02","舌见齿痕表示脾虚或湿盛证。"),
+    Xing_lieWen("Xing","03","舌见裂纹提示脏腑阴血亏虚。"),
+
+    HouDu_hou("HouDu","01","厚"),
+    HouDu_bao("HouDu","02","薄");
+
+    private final String category;
+    private final String code;
+    private final String description;
+
+    TongueTypeEnums(String category, String code, String description) {
+        this.category = category;
+        this.code = code;
+        this.description = description;
+    }
+
+
+    public String getCategory() {
+        return category;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+
+    public String getDescription() {
+        return description;
+    }
+
+
+    public static String fromCategoryAndCode(String category, String code) {
+        for (TongueTypeEnums type : TongueTypeEnums.values()) {
+            if (type.getCategory().equals(category) && type.getCode().equals(code)) {
+                return type.getDescription();
+            }
+        }
+        return null;
+    }
+
+
+
+
+}

+ 14 - 0
fs-service/src/main/java/com/fs/aiTongueApi/domain/inner/ConfidenceDataNew.java

@@ -0,0 +1,14 @@
+package com.fs.aiTongueApi.domain.inner;
+
+import lombok.Data;
+
+@Data
+public class ConfidenceDataNew {
+
+    private int sub; // 下标
+    private String label; // 类别
+    private String labelName; // 类别名称
+    private String val; // 置信度
+    private int[] xyxy; // 坐标 (没啥大用,凑凑数)
+
+}

+ 14 - 0
fs-service/src/main/java/com/fs/aiTongueApi/domain/inner/TongueInfo.java

@@ -0,0 +1,14 @@
+package com.fs.aiTongueApi.domain.inner;
+
+import lombok.Data;
+
+@Data
+public class TongueInfo {
+    private Long id;
+    private Integer botai;
+    private String houdu;
+    private String shemianName;
+    private String taiseName;
+    private String typeName;
+    private String typeJson;
+}

+ 3 - 0
fs-service/src/main/java/com/fs/aiTongueApi/service/AiTongueService.java

@@ -5,6 +5,7 @@ import com.fs.aiTongueApi.domain.QueryAiTongue;
 import com.fs.aiTongueApi.domain.QueryQuanXi;
 import com.fs.aiTongueApi.domain.inner.ConfidenceData;
 import com.fs.aiTongueApi.domain.inner.TongueData;
+import com.fs.his.domain.FsHealthTongue;
 
 public interface AiTongueService {
     AITongueResult<TongueData> getHistoryTongue(QueryAiTongue queryAiTongue);
@@ -12,4 +13,6 @@ public interface AiTongueService {
     AITongueResult<ConfidenceData> checkTongue(String url);
 
     AITongueResult<TongueData> quanXiTongue(QueryQuanXi queryQuanXi);
+
+    AITongueResult<FsHealthTongue> newCheckTongue(String tongueUrl);
 }

+ 187 - 2
fs-service/src/main/java/com/fs/aiTongueApi/service/impl/AiTongueServiceImpl.java

@@ -6,10 +6,13 @@ import com.fs.aiTongueApi.config.AiTongueConfig;
 import com.fs.aiTongueApi.domain.AITongueResult;
 import com.fs.aiTongueApi.domain.QueryAiTongue;
 import com.fs.aiTongueApi.domain.QueryQuanXi;
-import com.fs.aiTongueApi.domain.inner.ConfidenceData;
-import com.fs.aiTongueApi.domain.inner.TongueData;
+import com.fs.aiTongueApi.domain.enums.TongueTypeEnums;
+import com.fs.aiTongueApi.domain.inner.*;
 import com.fs.aiTongueApi.service.AiTongueService;
 import com.fs.common.utils.uuid.UUID;
+import com.fs.his.domain.FsHealthTongue;
+import com.fs.his.service.IFsHealthTongueService;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.hc.core5.net.URIBuilder;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
@@ -20,6 +23,8 @@ import org.apache.http.entity.StringEntity;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.io.InputStream;
@@ -27,9 +32,18 @@ import java.net.URI;
 import java.net.URL;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+@Slf4j
 @Service
 public class AiTongueServiceImpl implements AiTongueService {
 
+    @Autowired
+    private IFsHealthTongueService tongueService;
+
     @Override
     public AITongueResult<TongueData> getHistoryTongue(QueryAiTongue queryAiTongue) {
         queryAiTongue.setAppkey(AiTongueConfig.appKey);
@@ -108,6 +122,177 @@ public class AiTongueServiceImpl implements AiTongueService {
         return aiTongueResult;
     }
 
+    @Override
+    public AITongueResult<FsHealthTongue> newCheckTongue(String url) {
+        String s="";
+        try {
+            HttpClient httpClient = HttpClients.createDefault();
+            HttpPost httpPost = new HttpPost(AiTongueConfig.newCheckTongue);
+            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+            URL urlItem = new URL(url);
+            InputStream inputStream =urlItem.openStream();
+            // 添加文件或表单参数
+            builder.addBinaryBody("file", inputStream, ContentType.DEFAULT_BINARY, "图片.jpg");
+
+            HttpEntity multipart = builder.build();
+            httpPost.setEntity(multipart);
+            // 执行请求
+            HttpResponse response = httpClient.execute(httpPost);
+            String responseBody = EntityUtils.toString(response.getEntity());
+            log.info(responseBody);
+            s=responseBody;
+
+            AITongueResult<List<List<ConfidenceDataNew>>> aiTongueResult = JSON.parseObject(s, new TypeReference<AITongueResult<List<List<ConfidenceDataNew>>>>(){});
+            List<List<ConfidenceDataNew>> data = aiTongueResult.getData();
+            FsHealthTongue healthTongue = new FsHealthTongue();
+            if (data != null && !data.isEmpty()){
+                String boTaiDesc =  "舌未见剥落提示脏腑气充足,胃阴正常,气阴平衡。";
+                String chiHenDesc = "舌未见齿痕表示脾气正常。";
+                String lieWenDesc = "舌未见裂纹表示脏腑津液正常。";
+                String houDu;
+                TongueInfo tongueInfo = new TongueInfo();
+                for (int i = 0; i < 4; i++) {
+                    List<ConfidenceDataNew> confidenceDataNews = data.get(i);
+                    if (confidenceDataNews != null && !confidenceDataNews.isEmpty()){
+                        Optional<ConfidenceDataNew> oldestPerson = confidenceDataNews.stream()
+                                .max(Comparator.comparingDouble(p -> Double.parseDouble(p.getVal())));
+                        ConfidenceDataNew confidenceDataNew = oldestPerson.get();
+
+                        healthTongue.setTongueUrl(url);
+                        if(i == 0){
+                            switch (confidenceDataNew.getLabel()){
+                                case "01":
+                                    healthTongue.setShemianName("鲜红舌");
+                                    break;
+                                case "02":
+                                    healthTongue.setShemianName("淡白舌");
+                                    break;
+                                case "03":
+                                    healthTongue.setShemianName("淡红舌");
+                                    break;
+                                case "04":
+                                    healthTongue.setShemianName("紫舌");
+                                    break;
+                            }
+                            String sheZhi = TongueTypeEnums.fromCategoryAndCode("SheZhi", confidenceDataNew.getLabel());
+                            healthTongue.setShemianDesc(sheZhi);
+                            //设置舌质
+                            tongueInfo.setShemianName(healthTongue.getShemianName());
+                        }
+                        if(i == 1){
+                            switch (confidenceDataNew.getLabel()){
+                                case "01":
+                                    healthTongue.setTaiseName("黄苔");
+                                    break;
+                                case "02":
+                                    healthTongue.setTaiseName("灰苔");
+                                    break;
+                                case "03":
+                                    healthTongue.setTaiseName("白苔");
+                                    break;
+                            }
+                            String taiSe = TongueTypeEnums.fromCategoryAndCode("TaiSe", confidenceDataNew.getLabel());
+                            healthTongue.setTaiseDesc(taiSe);
+                            //设置苔色
+                            tongueInfo.setTaiseName(healthTongue.getTaiseName());
+                        }
+                        if(i == 2){
+                            switch (confidenceDataNew.getLabel()){
+                                case "01":
+                                    healthTongue.setBotai(1L);
+                                    String boTai = TongueTypeEnums.fromCategoryAndCode("Xing", "01");
+                                    healthTongue.setBotaiDesc(boTai);
+                                    //设置是否剥脱 0正常 1剥脱
+                                    tongueInfo.setBotai(1);
+
+                                    healthTongue.setChihen(0L);
+                                    healthTongue.setChihenDesc(chiHenDesc);
+                                    healthTongue.setLiewen(0);
+                                    healthTongue.setLiewenDesc(lieWenDesc);
+                                    break;
+                                case "02":
+                                    healthTongue.setBotai(0L);
+                                    healthTongue.setBotaiDesc(boTaiDesc);
+                                    //设置是否剥脱 0正常 1剥脱
+                                    tongueInfo.setBotai(0);
+
+                                    healthTongue.setChihen(1L);
+                                    String chiHen = TongueTypeEnums.fromCategoryAndCode("Xing", "02");
+                                    healthTongue.setChihenDesc(chiHen);
+                                    healthTongue.setLiewen(0);
+                                    healthTongue.setLiewenDesc(lieWenDesc);
+                                    break;
+                                case "03":
+                                    healthTongue.setBotai(0L);
+                                    healthTongue.setBotaiDesc(boTaiDesc);
+                                    //设置是否剥脱 0正常 1剥脱
+                                    tongueInfo.setBotai(0);
+
+                                    healthTongue.setChihen(0L);
+                                    healthTongue.setChihenDesc(chiHenDesc);
+                                    healthTongue.setLiewen(1);
+                                    String lieWen = TongueTypeEnums.fromCategoryAndCode("Xing", "03");
+                                    healthTongue.setLiewenDesc(lieWen);
+                                    break;
+                            }
+                        }
+                        if(i == 3){
+                            switch (confidenceDataNew.getLabel()){
+                                case "01":
+                                    //厚
+                                    houDu = TongueTypeEnums.fromCategoryAndCode("HouDu", "01");
+                                    break;
+                                default:
+                                    //薄
+                                    houDu = TongueTypeEnums.fromCategoryAndCode("HouDu", "02");
+                                    break;
+                            }
+                            //设置厚度
+                            tongueInfo.setHoudu(houDu);
+                        }
+
+                    }else{
+                        //形状相关的为空就将这几个值置为0(表示正常)
+                        if(i == 2){
+                            healthTongue.setBotai(0L);
+                            healthTongue.setBotaiDesc(boTaiDesc);
+                            //设置是否剥脱 0正常 1剥脱
+                            tongueInfo.setBotai(0);
+
+                            healthTongue.setChihen(0L);
+                            healthTongue.setChihenDesc(chiHenDesc);
+                            healthTongue.setLiewen(0);
+                            healthTongue.setLiewenDesc(lieWenDesc);
+                        }
+                    }
+                }
+
+                TongueInfo fastTongueInfo = tongueService.selectFsTongueInfo(tongueInfo);
+                if(fastTongueInfo != null && fastTongueInfo.getTypeName() != null){
+                    healthTongue.setTypeName(fastTongueInfo.getTypeName());
+                    healthTongue.setTypeJson(fastTongueInfo.getTypeJson());
+                    return getAiTongueResult(healthTongue,"40001","ok");
+                }
+                return getAiTongueResult(healthTongue,"40003","未检测到舌头,请按照要求查询拍照检测");
+            }
+            return getAiTongueResult(healthTongue,"40003","未能从服务器获取结果,请稍后再试");
+        } catch (Exception e) {
+            return getAiTongueResult(null,"40003","请求频繁,请稍后再试");
+        }
+    }
+
+    private static @NotNull AITongueResult<FsHealthTongue> getAiTongueResult(FsHealthTongue healthTongue, String code, String msg) {
+        AITongueResult<FsHealthTongue> result = new AITongueResult<>();
+        result.setData(healthTongue);
+        result.setCode(code);
+        meta meta = new meta();
+        meta.setCode(code);
+        meta.setMsg(msg);
+        meta.setTimestamp(String.valueOf(new Date()));
+        result.setMeta(meta);
+        return result;
+    }
+
 
     public  String sendPost(String url,Object param){
         HttpClient httpClient = HttpClients.createDefault();

+ 4 - 149
fs-service/src/main/java/com/fs/company/domain/CompanyRecharge.java

@@ -5,15 +5,17 @@ import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 
 /**
  * 充值对象 company_recharge
- * 
+ *
  * @author fs
  * @date 2023-02-27
  */
+@Data
 public class CompanyRecharge extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
@@ -72,152 +74,5 @@ public class CompanyRecharge extends BaseEntity
     private Date auditTime;
 
     private String remark;
-
-    @Override
-    public String getRemark() {
-        return remark;
-    }
-
-    @Override
-    public void setRemark(String remark) {
-        this.remark = remark;
-    }
-
-    public void setRechargeId(Long rechargeId)
-    {
-        this.rechargeId = rechargeId;
-    }
-
-    public Long getRechargeId() 
-    {
-        return rechargeId;
-    }
-    public void setCompanyId(Long companyId) 
-    {
-        this.companyId = companyId;
-    }
-
-    public Long getCompanyId() 
-    {
-        return companyId;
-    }
-    public void setRechargeNo(String rechargeNo) 
-    {
-        this.rechargeNo = rechargeNo;
-    }
-
-    public String getRechargeNo() 
-    {
-        return rechargeNo;
-    }
-    public void setMoney(BigDecimal money) 
-    {
-        this.money = money;
-    }
-
-    public BigDecimal getMoney() 
-    {
-        return money;
-    }
-    public void setPayTime(Date payTime) 
-    {
-        this.payTime = payTime;
-    }
-
-    public Date getPayTime() 
-    {
-        return payTime;
-    }
-    public void setStatus(Integer status) 
-    {
-        this.status = status;
-    }
-
-    public Integer getStatus() 
-    {
-        return status;
-    }
-    public void setPayType(Integer payType) 
-    {
-        this.payType = payType;
-    }
-
-    public Integer getPayType() 
-    {
-        return payType;
-    }
-    public void setTradeNo(String tradeNo) 
-    {
-        this.tradeNo = tradeNo;
-    }
-
-    public String getTradeNo() 
-    {
-        return tradeNo;
-    }
-    public void setBalance(BigDecimal balance) 
-    {
-        this.balance = balance;
-    }
-
-    public BigDecimal getBalance() 
-    {
-        return balance;
-    }
-    public void setCreateUserId(Long createUserId) 
-    {
-        this.createUserId = createUserId;
-    }
-
-    public Long getCreateUserId() 
-    {
-        return createUserId;
-    }
-    public void setIsAudit(Integer isAudit) 
-    {
-        this.isAudit = isAudit;
-    }
-
-    public Integer getIsAudit() 
-    {
-        return isAudit;
-    }
-    public void setAuditUserId(Long auditUserId) 
-    {
-        this.auditUserId = auditUserId;
-    }
-
-    public Long getAuditUserId() 
-    {
-        return auditUserId;
-    }
-    public void setAuditTime(Date auditTime) 
-    {
-        this.auditTime = auditTime;
-    }
-
-    public Date getAuditTime() 
-    {
-        return auditTime;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
-            .append("rechargeId", getRechargeId())
-            .append("companyId", getCompanyId())
-            .append("rechargeNo", getRechargeNo())
-            .append("money", getMoney())
-            .append("createTime", getCreateTime())
-            .append("payTime", getPayTime())
-            .append("status", getStatus())
-            .append("payType", getPayType())
-            .append("tradeNo", getTradeNo())
-            .append("balance", getBalance())
-            .append("createUserId", getCreateUserId())
-            .append("isAudit", getIsAudit())
-            .append("auditUserId", getAuditUserId())
-            .append("auditTime", getAuditTime())
-            .toString();
-    }
+    private String imgs;
 }

+ 5 - 2
fs-service/src/main/java/com/fs/company/domain/CompanyUser.java

@@ -35,8 +35,8 @@ public class CompanyUser extends BaseEntity
 
     private String corpId;
 
-    /** 部门ID */
-    @Excel(name = "部门ID")
+    /** 部门编号 */
+    @Excel(name = "部门编号")
     private Long deptId;
 
     /** 用户账号 */
@@ -87,6 +87,9 @@ public class CompanyUser extends BaseEntity
     private String qwUserId;
     private Integer qwStatus;
 
+    /** 医生id */
+    private Long doctorId;
+
     public String getIdCard() {
         return idCard;
     }

+ 2 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyDeptMapper.java

@@ -116,4 +116,6 @@ public interface CompanyDeptMapper
 
     @Select("select dept_id,dept_name from company_dept where dept_name=#{deptName} limit 1")
     CompanyDept selectDeptNameBydeptName(@Param("deptName") String deptName);
+
+    void deleteCompanyDeptByCompanyIds(Long[] companyIds);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java

@@ -5,6 +5,7 @@ import java.util.List;
 import java.util.Set;
 
 import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
 import com.fs.company.param.CompanyParam;
 import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyNameVO;
@@ -190,4 +191,5 @@ public interface CompanyMapper
     List<Company> selectCompanyByIds2(@Param("companyIds") Set<Long> companyIds);
 
 
+    List<CompanyUser> selectCompanyListByIds(@Param("userIds") String result);
 }

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

@@ -84,4 +84,5 @@ public interface CompanyRoleMapper
      * @return 角色信息
      * **/
     CompanyRole selectCompanyRoleByRoleKey(@Param("roleKey") String roleKey);
+    Long selectRolesByUserNameAndCompanyId(@Param("roleName") String roleName,@Param("companyId") Long companyId);
 }

+ 6 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -312,4 +312,10 @@ public interface CompanyUserMapper
     int insertQwIpadTotal(List<QwIpadTotalVo> qwIpadTotalVos);
 
     void uploadQrCode(@Param("userId") String userId, @Param("url") String url);
+
+    @Update("update company_user set doctor_id = null where user_id = #{userId}")
+    public int unBindDoctorId(@Param("userId")Long userId);
+
+
+    List<String> selectCompanyUserNameByIdsList(@Param("companyUserIDs")List<Long> companyUserID);
 }

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

@@ -16,5 +16,6 @@ public class CompanyRechargeParam implements Serializable
     private BigDecimal money;
 
     private String remark;
+    private String imgs;
 
 }

+ 131 - 0
fs-service/src/main/java/com/fs/company/param/CompanyUserCodeParam.java

@@ -0,0 +1,131 @@
+package com.fs.company.param;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.company.domain.CompanyDept;
+import com.fs.company.domain.CompanyPost;
+import com.fs.company.domain.CompanyRole;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class CompanyUserCodeParam {
+
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+    * 注册类型 1、新注册 2、已有销售账号-绑定
+    */
+    private Integer bindType;
+
+    /** 用户ID */
+    private Long userId;
+
+    /** 公司ID */
+    @Excel(name = "公司ID")
+    private Long companyId;
+
+    /** 公司名称 */
+    private String companyName;
+
+
+    private String corpId;
+
+    /** 归属部门ID */
+    @Excel(name = "部门ID")
+    private Long deptId;
+
+    /** 用户账号 */
+    @Excel(name = "用户账号")
+    private String userName;
+
+    /** 用户昵称 */
+    @Excel(name = "用户昵称")
+    private String nickName;
+
+    /** 用户类型(00系统用户) */
+    @Excel(name = "用户类型", readConverterExp = "0=0系统用户")
+    private String userType;
+
+    /** 手机号码 */
+    @Excel(name = "手机号码")
+    private String phonenumber;
+    /** 岗位 */
+    private List<CompanyPost> posts;
+
+    /** 用户性别(0男 1女 2未知) */
+    @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+    private String sex;
+
+    /** 头像地址 */
+    @Excel(name = "头像地址")
+    private String avatar;
+
+
+    /** 密码 */
+    @Excel(name = "密码")
+    private String password;
+
+    /** 帐号状态(0正常 1停用) */
+    @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /** 删除标志(0代表存在 2代表删除) */
+    private String delFlag;
+
+    private String qwUserId;
+
+    private String qwUserIdByStr;
+
+    private Integer qwStatus;
+
+
+    /** 是否删除 */
+    @Excel(name = "是否删除")
+    private Integer isDel;
+
+    private String openId;
+
+
+    private CompanyDept dept;
+
+    /** 角色对象 */
+    private List<CompanyRole> roles;
+
+    /** 角色组 */
+    private Long[] roleIds;
+
+    /** 岗位组 */
+    private Long[] postIds;
+
+    private String postName;
+
+    private String deptName;
+
+    private String addressId;
+
+    //绑定二维码
+    private String bindCode;
+
+    /** 看课域名 */
+    private String domain;
+
+    /** 是否审核 */
+    private Integer isAudit;
+
+    /** 用户上级id */
+    private Long parentId;
+
+    /** 微信小程序OPENID(如果有小程序授权) */
+    private String  maOpenId;
+
+    /** 是否需要单独注册会员,1-是,0-否(用于个微销售分享看课) */
+    private Integer isNeedRegisterMember;
+
+    /** 是否允许所有方式注册会员,1-是,0-否,默认1(用于个微注册会员) */
+    private Integer isAllowedAllRegister;
+
+}

+ 7 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyService.java

@@ -5,6 +5,7 @@ import java.util.List;
 
 import com.fs.common.core.domain.R;
 import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
 import com.fs.company.param.CompanyParam;
 import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyNameVO;
@@ -152,4 +153,10 @@ public interface ICompanyService
     void configUserCheck(Long companyId, Integer userIsDefaultBlack);
 
     void addRedPacketCompanyMoney(BigDecimal money, Long companyId);
+    /**
+     * 根据多个id查询多个qw_user_id
+     * @param result
+     * @return
+     */
+    List<CompanyUser> selectCompanyListByIds(String result);
 }

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

@@ -3,10 +3,12 @@ package com.fs.company.service;
 import com.fs.common.core.domain.R;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.param.CompanyUserAreaParam;
+import com.fs.company.param.CompanyUserCodeParam;
 import com.fs.company.param.CompanyUserQwParam;
 import com.fs.company.vo.*;
 import com.fs.his.vo.CitysAreaVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.hisStore.vo.FsStoreProductExportVO;
 import com.fs.qw.dto.UserProjectDTO;
 import com.fs.qw.vo.CompanyUserQwVO;
 import com.fs.qw.vo.QwOptionsVO;
@@ -52,6 +54,9 @@ public interface ICompanyUserService {
      */
     public int insertCompanyUser(CompanyUser companyUser);
 
+    String importCompanyUser(List<CompanyUserImportVO> list, boolean updateSupport);
+
+
     /**
      * 修改物业公司管理员信息
      *
@@ -93,6 +98,7 @@ public interface ICompanyUserService {
     int checkUserName(String userName);
 
     public int insertUser(CompanyUser user);
+    public R registerCompany(CompanyUserCodeParam userCodeParam);
     public int updateUser(CompanyUser user);
 
 
@@ -226,4 +232,8 @@ public interface ICompanyUserService {
     int insertQwIpadTotal(List<QwIpadTotalVo> qwIpadTotalVos);
 
     String uploadQrCode(MultipartFile file,String userId) throws IOException;
+
+    R bindDoctor(CompanyUser param);
+
+    R unBindDoctor(Long userId);
 }

+ 18 - 5
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -35,8 +35,9 @@ import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.service.ISysConfigService;
 import com.google.gson.Gson;
+import com.hc.openapi.tool.util.ObjectUtils;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang.ObjectUtils;
+;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -109,9 +110,11 @@ public class CompanyServiceImpl implements ICompanyService
     @Override
     public Company selectCompanyById(Long companyId){
         Company company = companyMapper.selectCompanyById(companyId);
-        List<CompanyMiniapp> miniApp = companyMiniappService.getMiniAppListByCompanyList(Collections.singletonList(company.getCompanyId()));
-        company.setMiniAppMaster(GET_MINI_APP_STR.apply(0, miniApp));
-        company.setMiniAppServer(GET_MINI_APP_STR.apply(1, miniApp));
+        if(company != null) {
+            List<CompanyMiniapp> miniApp = companyMiniappService.getMiniAppListByCompanyList(Collections.singletonList(company.getCompanyId()));
+            company.setMiniAppMaster(GET_MINI_APP_STR.apply(0, miniApp));
+            company.setMiniAppServer(GET_MINI_APP_STR.apply(1, miniApp));
+        }
         return company;
     }
 
@@ -293,7 +296,12 @@ public class CompanyServiceImpl implements ICompanyService
     @Override
     public int deleteCompanyByIds(Long[] companyIds)
     {
-        return companyMapper.deleteCompanyByIds(companyIds);
+        int i = companyMapper.deleteCompanyByIds(companyIds);
+        //删除对应部门
+        if (i > 0){
+            companyDeptMapper.deleteCompanyDeptByCompanyIds(companyIds);
+        }
+        return i;
     }
 
     /**
@@ -1320,4 +1328,9 @@ public class CompanyServiceImpl implements ICompanyService
             }
         }
     }
+
+    @Override
+    public List<CompanyUser> selectCompanyListByIds(String result) {
+        return companyMapper.selectCompanyListByIds(result);
+    }
 }

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

@@ -1,19 +1,24 @@
 package com.fs.company.service.impl;
 
+import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
+import com.fs.common.BeanCopyUtils;
 import com.fs.common.annotation.DataScope;
+import com.fs.common.constant.UserConstants;
+import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.ServiceException;
 import com.fs.common.exception.file.OssException;
-import com.fs.common.utils.DateUtils;
-import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.*;
 import com.fs.company.domain.*;
 import com.fs.company.mapper.*;
 import com.fs.company.param.CompanyUserAreaParam;
+import com.fs.company.param.CompanyUserCodeParam;
 import com.fs.company.param.CompanyUserQwParam;
+import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.*;
 import com.fs.course.service.IFsUserCompanyUserService;
@@ -21,8 +26,16 @@ import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.service.IFsCityService;
 import com.fs.his.vo.CitysAreaVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.hisStore.domain.FsStoreProductAttrScrm;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.domain.FsStoreProductScrm;
+import com.fs.hisStore.dto.ProductArrtDTO;
+import com.fs.hisStore.vo.FsStoreProductExportVO;
+import com.fs.qw.domain.QwUser;
 import com.fs.qw.dto.UserProjectDTO;
 import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.CompanyUserQwVO;
 import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwUserVO;
@@ -38,6 +51,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -83,6 +97,18 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     @Autowired
     private IFsUserCompanyUserService userCompanyUserService;
 
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
+    @Autowired
+    private IQwUserService qwUserService;
+
     /**
      * 查询物业公司管理员信息
      *
@@ -135,6 +161,163 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         return companyUserMapper.insertCompanyUser(companyUser);
     }
 
+    @Override
+    public String importCompanyUser(List<CompanyUserImportVO> list, boolean updateSupport) {
+
+        if (com.fs.common.utils.StringUtils.isNull(list) || list.size() == 0)
+        {
+            throw new CustomException("导入销售信息不能为空!");
+        }
+        int successNum = 0;
+        int failureNum = 0;
+        StringBuilder successMsg = new StringBuilder();
+        StringBuilder failureMsg = new StringBuilder();
+        for (CompanyUserImportVO importVO : list){
+            try
+            {
+                CompanyUser copy = BeanCopyUtils.copy(importVO, CompanyUser.class);
+
+                assert copy != null;
+
+                if (StringUtil.strIsNullOrEmpty(copy.getPassword())){
+                    throw new CustomException("密码不能为空");
+                }
+
+
+                if (!PatternUtils.checkPassword(copy.getPassword())) {
+                    throw new CustomException("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20 位");
+                }
+
+                if (copy.getCompanyId() == null){
+                    throw new CustomException("公司ID不能为空,且为数字!");
+                } else if (!String.valueOf(copy.getCompanyId()).matches("\\d+")) {
+                    throw new CustomException("公司ID必须为数字!");
+                }
+
+                if (copy.getDeptId() == null){
+                    throw new CustomException("部门编号不能为空,且为数字!");
+                } else if (!String.valueOf(copy.getDeptId()).matches("\\d+")) {
+                    throw new CustomException("部门编号必须为数字!");
+                }
+
+                if (StringUtil.strIsNullOrEmpty(copy.getPhonenumber())){
+                    throw new CustomException("手机号不能为空");
+                } else if (!copy.getPhonenumber().matches("\\d+")) {
+                    throw new CustomException("手机号必须为数字!");
+                }
+
+                if (StringUtil.strIsNullOrEmpty(copy.getAddressId())){
+                    throw new CustomException("区域不能为空");
+                } else if (!copy.getAddressId().matches("\\d+")) {
+                    throw new CustomException("区域ID必须为数字!");
+                }
+
+                Integer count=companyUserService.selectCompanyUserCountByCompanyId(copy.getCompanyId());
+                Company company=companyService.selectCompanyById(copy.getCompanyId());
+
+                if(count>company.getLimitUserCount()){
+                    throw new CustomException("销售公司的销售数量已达到上限!");
+                }
+
+                if (UserConstants.NOT_UNIQUE.equals(String.valueOf(companyUserService.checkUserName(copy.getUserName()))))
+                {
+                    throw new CustomException("新增用户'" + copy.getUserName() + "'失败,登录账号已存在");
+                }
+
+                if (StringUtil.strIsNullOrEmpty(copy.getNickName())){
+                    throw new CustomException("用户昵称不能为空");
+                }
+
+                if (StringUtil.strIsNullOrEmpty(importVO.getRoleString())){
+                    throw new CustomException("角色-不能为空");
+                }
+
+                try {
+                    String[] splitRoles = splitRoles(importVO.getRoleString());
+
+                    // 新增用户与岗位管理
+                    Set<Long> setList= new HashSet<>();
+
+                    for (String stringRole : splitRoles) {
+                        Long rolesId = roleMapper.selectRolesByUserNameAndCompanyId(stringRole, copy.getCompanyId());
+
+                        if (StringUtils.isNotNull(rolesId)) {
+                            setList.add(rolesId);
+                        }else {
+                            throw new CustomException("当前销售公司没有此角色");
+                        }
+                    }
+
+                    // 转换为 Long[]
+                    Long[] roleIds = setList.toArray(new Long[0]);
+                    copy.setRoleIds(roleIds);
+
+
+                }catch (Exception e){
+                    throw new CustomException("角色-格式不正确");
+                }
+
+
+
+                copy.setUserType("01");//一般用户
+                copy.setIsAudit(1);
+                copy.setPassword(SecurityUtils.encryptPassword(copy.getPassword()));
+                copy.setCreateTime(new Date());
+                copy.setStatus("0");
+
+                int rows = companyUserMapper.insertCompanyUser(copy);
+                if (rows>0){
+                    // 新增用户与角色管理
+                    insertUserRole(copy);
+                }else {
+                    throw new CustomException("新增用户'" + copy.getUserName() + "'失败");
+                }
+
+
+                successNum++;
+                successMsg.append("<br/>" + successNum + "、销售账号 " + copy.getUserName() + " 导入成功");
+            }
+            catch (Exception e)
+            {
+
+                failureNum++;
+                String msg = "<br/>" + failureNum + "、销售账号 " + importVO.getUserName()  + " 导入失败:";
+                failureMsg.append(msg + e.getMessage());
+            }
+
+        }
+        if (failureNum > 0)
+        {
+            failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+            throw new CustomException(failureMsg.toString());
+        }
+        else
+        {
+            successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
+        }
+        return successMsg.toString();
+    }
+
+
+    public String[] splitRoles(String roleString) {
+        if (roleString == null || roleString.trim().isEmpty()) {
+            return new String[0];
+        }
+
+        // 预处理:替换中文标点,去除首尾空格
+        String processed = roleString
+                .replace(",", ",")
+                .replace(";", ";")
+                .replace("、", ",")
+                .trim();
+
+        // 分割并过滤空值
+        return Arrays.stream(processed.split("[,;\\s]+"))
+                .filter(s -> !s.isEmpty())
+                .map(String::trim)
+                .toArray(String[]::new);
+    }
+
     /**
      * 修改物业公司管理员信息
      *
@@ -264,6 +447,106 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         return rows;
     }
 
+    @Override
+    public R registerCompany(CompanyUserCodeParam userCodeParam) {
+        CompanyUser user=new CompanyUser();
+
+        QwUser qwUser = qwUserMapper.selectQwUserByCorpIdAndUserId(userCodeParam.getCorpId(),userCodeParam.getQwUserIdByStr());
+
+        if (qwUser==null){
+            return R.error("无企微员工信息,无法处理,请先同步员工:"+ userCodeParam.getQwUserIdByStr()+"--"+userCodeParam.getCorpId());
+        }
+
+        if (qwUser.getCompanyUserId()!=null&&!qwUser.getCompanyUserId().equals(qwUser.getCompanyUserId())){
+            return R.error( qwUser.getQwUserName()+"已经被其他人绑定,请先解绑");
+        }
+
+        if (userCodeParam.getBindType()==1){
+
+            if (!PatternUtils.checkPassword(userCodeParam.getPassword())) {
+                return R.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20 位");
+            }
+
+            //判断用户数量是否已达到上线
+            Integer count=companyUserService.selectCompanyUserCountByCompanyId(userCodeParam.getCompanyId());
+            Company company=companyService.selectCompanyById(userCodeParam.getCompanyId());
+
+            if(count>company.getLimitUserCount()){
+                return R.error("用户数量已达到上限");
+            }
+
+            if (UserConstants.NOT_UNIQUE.equals(String.valueOf(companyUserService.checkUserName(userCodeParam.getUserName()))))
+            {
+                return R.error("新增用户'" + userCodeParam.getUserName() + "'失败,登录账号已存在");
+            }
+            user.setNickName(userCodeParam.getNickName());
+            user.setUserName(userCodeParam.getUserName());
+            user.setSex(userCodeParam.getSex());
+            user.setStatus("1");
+            user.setDeptId(userCodeParam.getDeptId());
+            user.setPhonenumber(userCodeParam.getPhonenumber());
+            user.setRoleIds(userCodeParam.getRoleIds());
+            user.setAddressId(userCodeParam.getAddressId());
+            user.setCompanyId(userCodeParam.getCompanyId());
+            user.setCreateBy(userCodeParam.getQwUserIdByStr());
+            user.setPassword(SecurityUtils.encryptPassword(userCodeParam.getPassword()));
+            user.setCreateTime(new Date());
+            user.setUserType("01");//一般用户
+            user.setIsAudit(1);
+
+            int i = companyUserService.insertUser(user);
+            if (i>0){
+
+                CompanyUser companyUser = companyUserMapper.selectUserByUserName(userCodeParam.getUserName());
+
+                bindQwUserToCompanyUser(qwUser, companyUser);
+
+            }else {
+                return R.error("销售创建失败");
+            }
+
+            return R.ok();
+
+        }
+        else if (userCodeParam.getBindType()==2){
+
+            // 绑定到现有用户
+            CompanyUser companyUser = companyUserMapper.selectUserByUserName(userCodeParam.getUserName());
+            if (companyUser == null) {
+                return R.error("指定的用户不存在");
+            }
+
+            bindQwUserToCompanyUser(qwUser, companyUser);
+        }
+
+        return R.error();
+    }
+
+    private void bindQwUserToCompanyUser(QwUser qwUser, CompanyUser companyUser) {
+        // 更新公司用户的企微ID列表
+        Set<String> qwUserIdSet = new HashSet<>();
+
+        if (!StringUtil.strIsNullOrEmpty(companyUser.getQwUserId())) {
+            String[] existingIds = companyUser.getQwUserId().split(",");
+            qwUserIdSet.addAll(Arrays.stream(existingIds)
+                    .filter(id -> !id.isEmpty())
+                    .collect(Collectors.toSet()));
+        }
+
+        qwUserIdSet.add(String.valueOf(qwUser.getId()));
+        companyUser.setQwUserId(String.join(",", qwUserIdSet));
+        companyUser.setQwStatus(1);
+        companyUserMapper.updateCompanyUser(companyUser);
+
+        // 更新企微用户信息
+        QwUser qw = new QwUser();
+        qw.setCompanyUserId(companyUser.getUserId());
+        qw.setId(qwUser.getId());
+        qw.setStatus(1);
+        qw.setCompanyId(companyUser.getCompanyId());
+        qwUserService.updateQwUser(qw);
+    }
+
     /**
      * 修改保存用户信息
      *
@@ -532,6 +815,7 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void auditUsers(List<Long> userIds,Long companyId) {
         if (userIds.isEmpty()) {
             return;
@@ -558,10 +842,14 @@ public class CompanyUserServiceImpl implements ICompanyUserService
             companyUserList.stream().forEach(c->{
                 //判断角色是否为空
                 if(ObjectUtil.isNotNull(role)){
-                    CompanyUserRole userRole=new CompanyUserRole();
-                    userRole.setRoleId(role.getRoleId());
-                    userRole.setUserId(c.getUserId());
-                    companyUserRoleList.add(userRole);
+                    //判断该用户角色是否存在
+                    CompanyUserRole companyUserRole = userRoleMapper.selectCompanyUserRoleById(c.getUserId());
+                    if(companyUserRole == null || !Objects.equals(companyUserRole.getRoleId(), role.getRoleId())){
+                        CompanyUserRole userRole=new CompanyUserRole();
+                        userRole.setRoleId(role.getRoleId());
+                        userRole.setUserId(c.getUserId());
+                        companyUserRoleList.add(userRole);
+                    }
                 }
 
                 //判断部门
@@ -571,13 +859,16 @@ public class CompanyUserServiceImpl implements ICompanyUserService
 
                 //判断岗位
                 if(ObjectUtil.isNotNull(companyPost)){
-                    //添加用户岗位表
-                    CompanyUserPost userPost=new CompanyUserPost();
-                    userPost.setPostId(companyPost.getPostId());
-                    userPost.setUserId(c.getUserId());
-                    companyUserPosts.add(userPost);
+                    //判断该岗位是否存在
+                    CompanyUserPost companyUserPost = userPostMapper.selectCompanyUserPostById(c.getUserId());
+                    if(companyUserPost == null || !Objects.equals(companyUserPost.getPostId(), companyPost.getPostId())){
+                        //添加用户岗位表
+                        CompanyUserPost userPost=new CompanyUserPost();
+                        userPost.setPostId(companyPost.getPostId());
+                        userPost.setUserId(c.getUserId());
+                        companyUserPosts.add(userPost);
+                    }
                 }
-
             });
 
             //批量插入角色用户中间表
@@ -660,4 +951,27 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         companyUserMapper.uploadQrCode(userId,url);
         return url;
     }
+
+    @Override
+    public R bindDoctor(CompanyUser companyUser) {
+        CompanyUser map = new CompanyUser();
+        map.setUserId(companyUser.getUserId());
+        map.setDoctorId(companyUser.getDoctorId());
+        int i = companyUserMapper.updateCompanyUser(map);
+        if (i > 0) {
+            return R.ok();
+        } else {
+            return R.error();
+        }
+    }
+
+    @Override
+    public R unBindDoctor(Long userId) {
+        int i = companyUserMapper.unBindDoctorId(userId);
+        if (i > 0) {
+            return R.ok();
+        } else {
+            return R.error();
+        }
+    }
 }

+ 17 - 350
fs-service/src/main/java/com/fs/company/vo/CompanyUserImportVO.java

@@ -5,32 +5,24 @@ import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import com.fs.company.domain.CompanyDept;
 import com.fs.company.domain.CompanyRole;
+import lombok.Data;
 
 import java.util.Date;
 import java.util.List;
 
+@Data
 public class CompanyUserImportVO extends BaseEntity {
     private static final long serialVersionUID = 1L;
 
     /** 用户ID */
     private Long userId;
 
-    /** 公司ID */
-    @Excel(name = "公司ID")
+    /** 公司编号 */
+    @Excel(name = "公司编号")
     private Long companyId;
 
-    public String getCorpId() {
-        return corpId;
-    }
-
-    public void setCorpId(String corpId) {
-        this.corpId = corpId;
-    }
-
-    private String corpId;
-
-    /** 部门ID */
-    @Excel(name = "部门ID")
+    /** 部门编号 */
+    @Excel(name = "部门编号")
     private Long deptId;
 
     /** 用户账号 */
@@ -41,8 +33,7 @@ public class CompanyUserImportVO extends BaseEntity {
     @Excel(name = "用户昵称")
     private String nickName;
 
-    /** 用户类型(00系统用户) */
-    @Excel(name = "用户类型", readConverterExp = "0=0系统用户")
+    /** 用户类型(00管理员 01员工 ) */
     private String userType;
 
     /** 用户邮箱 */
@@ -54,13 +45,9 @@ public class CompanyUserImportVO extends BaseEntity {
     private String phonenumber;
 
     /** 用户性别(0男 1女 2未知) */
-    @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+    @Excel(name = "用户性别(0男 1女 2未知)", readConverterExp = "0=男,1=女,2=未知")
     private String sex;
 
-    /** 头像地址 */
-    @Excel(name = "头像地址")
-    private String avatar;
-
     /** 身份证号 */
     @Excel(name = "身份证号")
     private String idCard;
@@ -69,23 +56,24 @@ public class CompanyUserImportVO extends BaseEntity {
     @Excel(name = "密码")
     private String password;
 
+    /** 角色字符串 */
+    @Excel(name = "角色(多角色用逗号分割)")
+    private String roleString;
+
     /** 帐号状态(0正常 1停用) */
-    @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
     private String status;
 
+    private String corpId;
+
     /** 删除标志(0代表存在 2代表删除) */
     private String delFlag;
 
+    /** 头像地址 */
+    private String avatar;
+
     private String qwUserId;
     private Integer qwStatus;
 
-    public String getIdCard() {
-        return idCard;
-    }
-
-    public void setIdCard(String idCard) {
-        this.idCard = idCard;
-    }
 
     /** 最后登录IP */
     private String loginIp;
@@ -111,9 +99,6 @@ public class CompanyUserImportVO extends BaseEntity {
     /** 角色组 */
     private Long[] roleIds;
 
-    /** 角色字符串 */
-    @Excel(name = "角色(多角色用逗号分割)")
-    private String roleString;
 
     /** 岗位组 */
     private Long[] postIds;
@@ -137,322 +122,4 @@ public class CompanyUserImportVO extends BaseEntity {
     /** 看课域名 */
     private String domain;
 
-    public String getDomain() {
-        return domain;
-    }
-
-    public void setDomain(String domain) {
-        this.domain = domain;
-    }
-
-    public String getAddressId() {
-        return addressId;
-    }
-
-    public void setAddressId(String addressId) {
-        this.addressId = addressId;
-    }
-
-    public String getVoicePrintUrl() {
-        return voicePrintUrl;
-    }
-
-    public void setVoicePrintUrl(String voicePrintUrl) {
-        this.voicePrintUrl = voicePrintUrl;
-    }
-
-    public String getCallerNo() {
-        return callerNo;
-    }
-
-    public void setCallerNo(String callerNo) {
-        this.callerNo = callerNo;
-    }
-
-    public String getJpushId() {
-        return jpushId;
-    }
-
-    public String getQwUserId() {
-        return qwUserId;
-    }
-
-    public void setQwUserId(String qwUserId) {
-        this.qwUserId = qwUserId;
-    }
-
-    public Integer getQwStatus() {
-        return qwStatus;
-    }
-
-    public void setQwStatus(Integer qwStatus) {
-        this.qwStatus = qwStatus;
-    }
-
-    public void setJpushId(String jpushId) {
-        this.jpushId = jpushId;
-    }
-
-    public String getQrCodeWeixin() {
-        return qrCodeWeixin;
-    }
-
-    public void setQrCodeWeixin(String qrCodeWeixin) {
-        this.qrCodeWeixin = qrCodeWeixin;
-    }
-
-    public String getQrCodeWecom() {
-        return qrCodeWecom;
-    }
-
-    public void setQrCodeWecom(String qrCodeWecom) {
-        this.qrCodeWecom = qrCodeWecom;
-    }
-
-    public String getOpenId() {
-        return openId;
-    }
-
-    public void setOpenId(String openId) {
-        this.openId = openId;
-    }
-
-    public String getUserName() {
-        return userName;
-    }
-
-    public void setUserName(String userName) {
-        this.userName = userName;
-    }
-
-    public String getNickName() {
-        return nickName;
-    }
-
-
-    public void setNickName(String nickName) {
-        this.nickName = nickName;
-    }
-
-    public String getFirstchar() {
-        return firstchar;
-    }
-
-    public void setFirstchar(String firstchar) {
-        this.firstchar = firstchar;
-    }
-
-    public String getPostName() {
-        return postName;
-    }
-
-    public void setPostName(String postName) {
-        this.postName = postName;
-    }
-
-    public String getDeptName() {
-        return deptName;
-    }
-
-    public void setDeptName(String deptName) {
-        this.deptName = deptName;
-    }
-
-    public CompanyDept getDept() {
-        return dept;
-    }
-
-    public void setDept(CompanyDept dept) {
-        this.dept = dept;
-    }
-
-    public static long getSerialVersionUID() {
-        return serialVersionUID;
-    }
-
-    public boolean isAdmin()
-    {
-        return isAdmin(this.userType);
-    }
-
-    public static boolean isAdmin(String userType)
-    {
-        if(userType!=null&&(userType.equals("00") || userType.equals("02"))){
-            return true;
-        }
-        else return false;
-    }
-
-    public List<CompanyRole> getRoles() {
-        return roles;
-    }
-
-    public void setRoles(List<CompanyRole> roles) {
-        this.roles = roles;
-    }
-
-    public String getRoleString() {
-        return roleString;
-    }
-
-    public void setRoleString(String roleString) {
-        this.roleString = roleString;
-    }
-
-    public Long[] getRoleIds() {
-        return roleIds;
-    }
-
-    public void setRoleIds(Long[] roleIds) {
-        this.roleIds = roleIds;
-    }
-
-    public Long[] getPostIds() {
-        return postIds;
-    }
-
-    public void setPostIds(Long[] postIds) {
-        this.postIds = postIds;
-    }
-
-
-    public void setUserId(Long userId)
-    {
-        this.userId = userId;
-    }
-
-    public Long getUserId()
-    {
-        return userId;
-    }
-    public void setCompanyId(Long companyId)
-    {
-        this.companyId = companyId;
-    }
-
-    public Long getCompanyId()
-    {
-        return companyId;
-    }
-    public void setDeptId(Long deptId)
-    {
-        this.deptId = deptId;
-    }
-
-    public Long getDeptId()
-    {
-        return deptId;
-    }
-
-    public void setUserType(String userType)
-    {
-        this.userType = userType;
-    }
-
-    public String getUserType()
-    {
-        return userType;
-    }
-    public void setEmail(String email)
-    {
-        this.email = email;
-    }
-
-    public String getEmail()
-    {
-        return email;
-    }
-    public void setPhonenumber(String phonenumber)
-    {
-        this.phonenumber = phonenumber;
-    }
-
-    public String getPhonenumber()
-    {
-        return phonenumber;
-    }
-    public void setSex(String sex)
-    {
-        this.sex = sex;
-    }
-
-    public String getSex()
-    {
-        return sex;
-    }
-    public void setAvatar(String avatar)
-    {
-        this.avatar = avatar;
-    }
-
-    public String getAvatar()
-    {
-        return avatar;
-    }
-
-    public void setPassword(String password)
-    {
-        this.password = password;
-    }
-
-    public String getPassword()
-    {
-        return password;
-    }
-    public void setStatus(String status)
-    {
-        this.status = status;
-    }
-
-    public String getStatus()
-    {
-        return status;
-    }
-    public void setDelFlag(String delFlag)
-    {
-        this.delFlag = delFlag;
-    }
-
-    public String getDelFlag()
-    {
-        return delFlag;
-    }
-    public void setLoginIp(String loginIp)
-    {
-        this.loginIp = loginIp;
-    }
-
-    public String getLoginIp()
-    {
-        return loginIp;
-    }
-    public void setLoginDate(Date loginDate)
-    {
-        this.loginDate = loginDate;
-    }
-
-    public Date getLoginDate()
-    {
-        return loginDate;
-    }
-
-
-    public void setToken(String token)
-    {
-        this.token = token;
-    }
-
-    public String getToken()
-    {
-        return token;
-    }
-    public void setIsDel(Integer isDel)
-    {
-        this.isDel = isDel;
-    }
-
-    public Integer getIsDel()
-    {
-        return isDel;
-    }
 }

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

@@ -128,4 +128,7 @@ public class CompanyUserQwListVO extends BaseEntity {
     /** 是否允许所有方式注册会员,1-是,0-否,默认1(用于个微注册会员) */
     private Integer isAllowedAllRegister;
 
+    /** 医生id */
+    private Long doctorId;
+
 }

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

@@ -79,6 +79,8 @@ public class CompanyVO implements Serializable
 
     private Integer limitUserCount;
 
+    private Integer maxPadNum;
+
     private Integer voiceCallerNumber;
     @Excel(name = "商务负责人")
     private String manager;

+ 36 - 6
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -219,32 +219,62 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 
     @Select({"<script> " +
             "SELECT \n" +
-            "o.video_id,o.company_id,o.qw_user_id,DATE(o.create_time) create_time,qu.qw_user_name,v.title videoName,uc.course_name,\n" +
+            "o.video_id,o.company_id,o.qw_user_id,DATE(o.create_time) create_time," +
+            "<if test= 'sendType != 1 '> " +
+            " qu.qw_user_name qw_user_name," +
+            "</if>\n" +
+            "<if test= 'sendType == 1 '> " +
+            " cu.nick_name qw_user_name," +
+            "</if>\n" +
+            "v.title videoName,uc.course_name,\n" +
             "SUM(CASE WHEN o.log_type = '1' THEN 1 ELSE 0 END) AS type1,\n" +
             "SUM(CASE WHEN o.log_type = '2' THEN 1 ELSE 0 END) AS type2,\n" +
             "SUM(CASE WHEN o.log_type = '3' THEN 1 ELSE 0 END) AS type3,\n" +
-            "SUM(CASE WHEN o.log_type = '4' THEN 1 ELSE 0 END) AS type4\n" +
+            "SUM(CASE WHEN o.log_type = '4' THEN 1 ELSE 0 END) AS type4,\n" +
+            "(\n" +
+            "  SUM(CASE WHEN o.log_type = '1' THEN 1 ELSE 0 END) +\n" +
+            "  SUM(CASE WHEN o.log_type = '2' THEN 1 ELSE 0 END) +\n" +
+            "  SUM(CASE WHEN o.log_type = '4' THEN 1 ELSE 0 END)\n" +
+            ") AS on_line_num\n" +
             "FROM fs_course_watch_log o\n" +
-            "LEFT JOIN qw_user qu on qu.id=o.qw_user_id\n" +
+            "<if test= 'sendType != 1 '> " +
+            " LEFT JOIN qw_user qu on qu.id=o.qw_user_id\n" +
+            "</if>\n" +
             "LEFT JOIN fs_user_course_video v on v.video_id=o.video_id \n" +
             "LEFT JOIN fs_user_course uc on uc.course_id=v.course_id\n" +
-            "where o.company_id=#{companyId} AND send_type=2 " +
+            "<if test= 'sendType == 1 '> " +
+            " LEFT JOIN company_user cu on cu.user_id=o.company_user_id\n" +
+            "</if>\n" +
+            "where o.company_id=#{companyId} " +
+            "<if test= 'sendType != null '> " +
+            "       and  send_type= #{sendType} " +
+            "</if>\n" +
             "<if test= 'sTime != null '> " +
             "       and DATE(o.create_time) &gt;= DATE(#{sTime})\n" +
             "</if>\n" +
             "<if test='eTime != null '> " +
             "      and DATE(o.create_time) &lt;= DATE(#{eTime})\n" +
             "</if>" +
-            "<if test ='nickName !=null and nickName!=\"\"'>\n" +
+            "<if test ='sendType != 1 and nickName !=null and nickName!=\"\"'>\n" +
             "   and qu.qw_user_name like concat( #{nickName}, '%')\n" +
             "</if>" +
+            "<if test ='sendType == 1 and nickName !=null and nickName!=\"\"'>\n" +
+            "   and cu.nick_name like concat( #{nickName}, '%')\n" +
+            "</if>" +
             "<if test ='courseId !=null'> " +
             "     and o.course_id = #{courseId} " +
             "</if>" +
             "<if test ='videoId !=null'> " +
             "     and o.video_id = #{videoId} " +
             "</if>" +
-            "GROUP BY o.video_id,o.qw_user_id,DATE(o.create_time)\n" +
+            "GROUP BY o.video_id," +
+            "<if test= 'sendType != 1 '> " +
+            " o.qw_user_id," +
+            "</if>\n" +
+            "<if test= 'sendType == 1 '> " +
+            " o.company_user_id," +
+            "</if>\n" +
+            "DATE(o.create_time)\n" +
             "ORDER BY o.video_id ,DATE(o.create_time) \n"+
             "</script>"})
     List<FsCourseWatchLogStatisticsListVO> selectFsCourseWatchLogStatisticsListVO(FsCourseWatchLogStatisticsListParam param);

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

@@ -66,6 +66,7 @@ public interface FsUserCourseVideoRedPackageMapper
      * @return 结果
      */
     public int deleteFsUserCourseVideoRedPackageByIds(Long[] ids);
+    public int deleteFsUserCourseVideoRedPackageByVedioIds(Long[] ids);
     @Update("INSERT INTO fs_user_course_video_red_package (company_id, video_id, red_packet_money) " +
             "VALUES (#{companyId}, #{videoId}, #{redPacketMoney}) " +
             "ON DUPLICATE KEY UPDATE red_packet_money = VALUES(red_packet_money);")

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

@@ -78,4 +78,9 @@ public class FsCourseWatchLogListParam implements Serializable {
 
     //是否是会员
     private Integer isVip;
+
+    /**
+     * sop主键id
+     */
+    private String sopId;
 }

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

@@ -40,4 +40,6 @@ public class FsCourseWatchLogStatisticsListParam {
 
     private Long pageNum;
     private Long pageSize;
+
+    private Integer sendType; //归属发送方式:1 个微  2 企微
 }

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

@@ -94,4 +94,6 @@ public interface IFsCourseLinkService
     String getGotoWxAppLink(String linkStr,String appid);
 
     R getWxaCodeGenerateScheme(String linkStr,String appId);
+
+    R getProjectCode();
 }

+ 8 - 8
fs-service/src/main/java/com/fs/course/service/IFsCourseProductOrderService.java

@@ -16,14 +16,14 @@ import com.fs.his.param.FsCourseProductOrderRefundParam;
 
 /**
  * 拍单商品订单Service接口
- * 
+ *
  * @author fs
  * @date 2025-07-28
  */
 public interface IFsCourseProductOrderService extends IService<FsCourseProductOrder>{
     /**
      * 查询拍单商品订单
-     * 
+     *
      * @param courseOrderId 拍单商品订单主键
      * @return 拍单商品订单
      */
@@ -31,7 +31,7 @@ public interface IFsCourseProductOrderService extends IService<FsCourseProductOr
 
     /**
      * 查询拍单商品订单列表
-     * 
+     *
      * @param param 拍单商品订单
      * @return 拍单商品订单集合
      */
@@ -39,7 +39,7 @@ public interface IFsCourseProductOrderService extends IService<FsCourseProductOr
 
     /**
      * 新增拍单商品订单
-     * 
+     *
      * @param fsCourseProductOrder 拍单商品订单
      * @return 结果
      */
@@ -47,7 +47,7 @@ public interface IFsCourseProductOrderService extends IService<FsCourseProductOr
 
     /**
      * 修改拍单商品订单
-     * 
+     *
      * @param fsCourseProductOrder 拍单商品订单
      * @return 结果
      */
@@ -55,7 +55,7 @@ public interface IFsCourseProductOrderService extends IService<FsCourseProductOr
 
     /**
      * 批量删除拍单商品订单
-     * 
+     *
      * @param courseOrderIds 需要删除的拍单商品订单主键集合
      * @return 结果
      */
@@ -63,7 +63,7 @@ public interface IFsCourseProductOrderService extends IService<FsCourseProductOr
 
     /**
      * 删除拍单商品订单信息
-     * 
+     *
      * @param courseOrderId 拍单商品订单主键
      * @return 结果
      */
@@ -79,7 +79,7 @@ public interface IFsCourseProductOrderService extends IService<FsCourseProductOr
 
     R payment(FsCourseProductOrderDoPayParam param);
 
-    R  payConfirm(String orderSn,String payCode, String tradeNo,String payType,Integer type);
+    R  payConfirm(String orderSn,String payCode, String tradeNo,String payType,Integer type,String bankTransactionId,String bankSerialNo);
 
     R refund(FsCourseProductOrderRefundParam param);
 

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

@@ -73,7 +73,7 @@ public interface IFsUserCourseOrderService
 
     R payment(FsUserCourseOrderDoPayParam param);
 
-    R  payConfirm(String orderSn,String payCode, String tradeNo,String payType,Integer type);
+    R  payConfirm(String orderSn,String payCode, String tradeNo,String payType,Integer type,String bankTransactionId,String bankSerialNo);
 
     R computeOrder(FsUserCourseOrderComputeParam param);
 

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

@@ -75,7 +75,7 @@ public interface IFsUserVipOrderService
 
     R payment(FsUserVipOrderPayUParam param);
 
-    R payConfirm(String orderSn,String payCode, String tradeNo,String payType,Integer type);
+    R payConfirm(String orderSn,String payCode, String tradeNo,String payType,Integer type,String bankTransactionId,String bankSerialNo);
 
     R aliPayment(FsUserVipOrderPayUParam param);
 }

+ 14 - 7
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -778,12 +778,12 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
                 //处理参数
                 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";
-                }
+//                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();
@@ -913,5 +913,12 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
         return R.ok();
     }
 
-
+    @Override
+    public R getProjectCode() {
+        String code = cloudHostProper.getProjectCode();
+        if (StringUtils.isEmpty(code)){
+            return R.error("项目编号配置不存在!");
+        }
+        return R.ok().put("code",code);
+    }
 }

+ 10 - 8
fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java

@@ -76,7 +76,7 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
 /**
  * 拍单商品订单Service业务层处理
- * 
+ *
  * @author fs
  * @date 2025-07-28
  */
@@ -131,7 +131,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 
     /**
      * 查询拍单商品订单
-     * 
+     *
      * @param courseOrderId 拍单商品订单主键
      * @return 拍单商品订单
      */
@@ -143,7 +143,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 
     /**
      * 查询拍单商品订单列表
-     * 
+     *
      * @param param 拍单商品订单
      * @return 拍单商品订单
      */
@@ -171,7 +171,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 
     /**
      * 新增拍单商品订单
-     * 
+     *
      * @param fsCourseProductOrder 拍单商品订单
      * @return 结果
      */
@@ -184,7 +184,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 
     /**
      * 修改拍单商品订单
-     * 
+     *
      * @param fsCourseProductOrder 拍单商品订单
      * @return 结果
      */
@@ -197,7 +197,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 
     /**
      * 批量删除拍单商品订单
-     * 
+     *
      * @param courseOrderIds 需要删除的拍单商品订单主键
      * @return 结果
      */
@@ -209,7 +209,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 
     /**
      * 删除拍单商品订单信息
-     * 
+     *
      * @param courseOrderId 拍单商品订单主键
      * @return 结果
      */
@@ -445,7 +445,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
     }
 
     @Override
-    public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, Integer type) {
+    public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, Integer type,String bankTransactionId,String bankSerialNo){
         logger.info("进入拍商品订单支付回调 orderSn: {}, payCode: {}, tradeNo: {}, payType: {}, type: {}",
                 orderSn, payCode, tradeNo, payType, type);
         FsCourseProductOrder order = null;
@@ -458,6 +458,8 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                     paymentMap.setStatus(1);
                     paymentMap.setPayTime(new Date());
                     paymentMap.setTradeNo(tradeNo);
+                    paymentMap.setBankSerialNo(bankSerialNo);
+                    paymentMap.setBankTransactionId(bankTransactionId);
                     if(payType.equals(PayType.WECHAT_MINI_PROGRAM_PAYMENT.getCode())){
                         paymentMap.setPayTypeCode(PayType.WECHAT_MINI_PROGRAM_PAYMENT.name());
                     }

+ 21 - 27
fs-service/src/main/java/com/fs/course/service/impl/FsCourseTrafficLogServiceImpl.java

@@ -225,26 +225,25 @@ public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
 
         double trafficGB = account / trafficPrice;
         long trafficKB = (long) (trafficGB * 1024 * 1024);
+        long trafficB = trafficKB * 1024;
 
-        System.out.println("充值金额:" + account + " 元,对应可用流量:" + trafficKB + " KB");
+        System.out.println("充值金额:" + account + " 元,对应可用流量:" + trafficKB + " KB (" + trafficB + " B)");
 
         long updatedTrafficKB = 0L;
-        int pageSize = 1000;  // 每次查询1000条
-        int pageNum = 0;      // 分页页码
-        int loopCount = 0;    // 查询次数
-        int maxLoop = 20;     // 最大循环次数
+        int pageSize = 1000;
+        int pageNum = 0;
+        int loopCount = 0;
+        int maxLoop = 20;
 
-        List<Long> idsToUpdate = new ArrayList<>();       // 用于更新状态为1的ID
-        Set<Long> processedIds = new HashSet<>();         // 用于去重
-        long remainingTrafficKB = trafficKB;              // 还需补充的流量
-        long totalInternetTrafficRemaining = 0L;          // 记录未处理的流量总和
+        List<Long> idsToUpdate = new ArrayList<>();
+        Set<Long> processedIds = new HashSet<>();
+        long remainingTrafficKB = trafficKB;
+        long totalInternetTrafficRemaining = 0L;
 
-        // 第一阶段:处理需要用于充值的记录
         while (updatedTrafficKB < trafficKB && loopCount < maxLoop) {
             loopCount++;
             int offset = pageNum * pageSize;
 
-            // 查询当前分页的数据
             List<TrafficRecord> trafficRecords =
                     fsCourseTrafficLogMapper.findUnusedRecordsWithTraffic(
                             internetTrafficParam.getCompanyId(), offset, pageSize);
@@ -252,15 +251,12 @@ public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
             if (trafficRecords.isEmpty()) {
                 break;
             }
-
-            // 处理当前批次的数据
             for (TrafficRecord record : trafficRecords) {
                 Long logId = record.getLogId();
 
                 if (processedIds.contains(logId)) {
                     continue;
                 }
-
                 if (updatedTrafficKB < trafficKB) {
                     updatedTrafficKB += record.getInternetTraffic();
                     idsToUpdate.add(logId);
@@ -281,12 +277,11 @@ public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
             pageNum++;
         }
 
-        // 第二阶段:将所有未处理的记录状态改为3
         List<Long> allUnprocessedIds = new ArrayList<>();
-        pageNum = 0;  // 重置分页
+        pageNum = 0;
         boolean hasMore = true;
 
-        while (hasMore && loopCount < maxLoop * 2) {  // 扩大循环次数限制
+        while (hasMore && loopCount < maxLoop * 2) {
             loopCount++;
             int offset = pageNum * pageSize;
 
@@ -301,26 +296,22 @@ public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
 
             for (TrafficRecord record : allRecords) {
                 Long logId = record.getLogId();
-                if (!idsToUpdate.contains(logId)) {  // 不是已处理的记录
+                if (!idsToUpdate.contains(logId)) {
                     allUnprocessedIds.add(logId);
                 }
             }
 
             pageNum++;
         }
-
-        // 更新数据库状态
         if (!idsToUpdate.isEmpty()) {
             fsCourseTrafficLogMapper.updateStatusByIds(idsToUpdate, 1);
             System.out.println("共更新状态为1的记录数:" + idsToUpdate.size());
         }
-
         if (!allUnprocessedIds.isEmpty()) {
             fsCourseTrafficLogMapper.updateStatusByIds(allUnprocessedIds, 3);
             System.out.println("共更新状态为3的记录数:" + allUnprocessedIds.size());
         }
 
-        // 剩余的计算和输出逻辑保持不变...
         Long count = fsCourseTrafficLogMapper.findRecordsNum(internetTrafficParam.getCompanyId());
         long overflowTrafficKB = Math.max(0, updatedTrafficKB - trafficKB) + count;
         if (overflowTrafficKB > 0) {
@@ -329,13 +320,16 @@ public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
 
         System.out.println("充值总流量:" + trafficKB + " KB");
         System.out.println("已使用流量:" + updatedTrafficKB + " KB");
-        long finalRemainingTrafficKB = Math.max(0, trafficKB - updatedTrafficKB);
-        System.out.println("最终剩余流量:" + finalRemainingTrafficKB + " KB");
 
-        // 系统配置更新逻辑保持不变...
+
+        // 系统配置更新逻辑 - 使用字节为单位
         SysConfig sysConfig = iSysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");
-        String trafficCount = finalRemainingTrafficKB == 0 ?
-                "-" + overflowTrafficKB : String.valueOf(finalRemainingTrafficKB);
+
+        // 计算溢出流量(字节)
+        long overflowTrafficB = updatedTrafficKB * 1024;
+
+        Long sum = Long.parseLong(sysConfig.getConfigValue()) + overflowTrafficB;
+        String trafficCount = sum+"";
 
         if (ObjectUtils.isEmpty(sysConfig)) {
             sysConfig = new SysConfig();

+ 8 - 1
fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java

@@ -749,7 +749,14 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
             watchLog.setDuration(duration);
 
             //取对应视频的时长
-            Long videoDuration = getVideoDuration(videoId);
+            Long videoDuration = 0L;
+            try {
+                videoDuration = getVideoDuration(videoId);
+            }catch (Exception e){
+                log.error("视频时长识别错误:{}", key);
+                continue;
+            }
+
             if (videoDuration != null && videoDuration != 0) {
                 boolean complete = false;
                 // 判断百分比

+ 5 - 3
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java

@@ -390,7 +390,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
 
         if(user!=null&& StringUtils.isNotEmpty(openId)) {
             if (order.getPayMoney().compareTo(new BigDecimal(0)) == 0) {
-                this.payConfirm(order.getOrderCode(), "", "", "", 2);
+                this.payConfirm(order.getOrderCode(), "", "", "", 2,null,null);
                 return R.ok().put("isPay", 1);
             } else {
                 String payCode =  OrderCodeUtils.getOrderSn();
@@ -584,7 +584,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                 }
             }
             else{
-                this.payConfirm(order.getOrderCode(),"","","",2);
+                this.payConfirm(order.getOrderCode(),"","","",2,null,null);
                 return R.ok().put("isPay",1);
             }
         }
@@ -596,7 +596,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
 
     @Override
     @Transactional
-    public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, Integer type) {
+    public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, Integer type,String bankTransactionId,String bankSerialNo){
         Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
         try {
             FsUserCourseOrder order=null;
@@ -609,6 +609,8 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                         paymentMap.setStatus(1);
                         paymentMap.setPayTime(new Date());
                         paymentMap.setTradeNo(tradeNo);
+                        paymentMap.setBankSerialNo(bankSerialNo);
+                        paymentMap.setBankTransactionId(bankTransactionId);
                         if(payType.equals(PayType.WECHAT_MINI_PROGRAM_PAYMENT.getCode())){
                             paymentMap.setPayTypeCode(PayType.WECHAT_MINI_PROGRAM_PAYMENT.name());
                         }

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

@@ -133,7 +133,7 @@ public class FsUserCoursePeriodDaysServiceImpl extends ServiceImpl<FsUserCourseP
         if(!periodDayIds.isEmpty()){
             flag = fsUserCoursePeriodDaysMapper.updateBatchDelFlag(periodDayIds.toArray(new Long[0]),1);
             //删除红包记录
-            fsUserCourseVideoRedPackageMapper.updateBatchDelFlag(videoIds.toArray(new Long[0]),1);
+            fsUserCourseVideoRedPackageMapper.deleteFsUserCourseVideoRedPackageByVedioIds(videoIds.toArray(new Long[0]));
         }
         return flag;
     }

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

@@ -3,8 +3,10 @@ package com.fs.course.service.impl;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.StringUtils;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.domain.FsUserCoursePeriodDays;
 import com.fs.course.mapper.FsUserCoursePeriodDaysMapper;

+ 5 - 3
fs-service/src/main/java/com/fs/course/service/impl/FsUserVipOrderServiceImpl.java

@@ -249,7 +249,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
 
         if(user!=null&& StringUtils.isNotEmpty(openId)) {
             if (order.getPayMoney().compareTo(new BigDecimal(0)) == 0) {
-                this.payConfirm(order.getOrderCode(), "", "", "", 2);
+                this.payConfirm(order.getOrderCode(), "", "", "", 2,null,null);
                 return R.ok().put("isPay", 1);
             } else {
                 String payCode =  OrderCodeUtils.getOrderSn();
@@ -434,7 +434,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                 }
             }
             else{
-                this.payConfirm(order.getOrderCode(),"","","",2);
+                this.payConfirm(order.getOrderCode(),"","","",2,null,null);
                 return R.ok().put("isPay",1);
             }
         }
@@ -446,7 +446,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
 
     @Override
     @Transactional
-    public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, Integer type) {
+    public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, Integer type,String bankTransactionId,String bankSerialNo){
         Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
         try {
             FsUserVipOrder order=null;
@@ -459,6 +459,8 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                         paymentMap.setStatus(1);
                         paymentMap.setPayTime(new Date());
                         paymentMap.setTradeNo(tradeNo);
+                        paymentMap.setBankSerialNo(bankSerialNo);
+                        paymentMap.setBankTransactionId(bankTransactionId);
                         if(payType.equals(PayType.WECHAT_MINI_PROGRAM_PAYMENT.getCode())){
                             paymentMap.setPayTypeCode(PayType.WECHAT_MINI_PROGRAM_PAYMENT.name());
                         }

+ 67 - 57
fs-service/src/main/java/com/fs/course/service/impl/FsUserWatchStatisticsServiceImpl.java

@@ -140,63 +140,73 @@ public class FsUserWatchStatisticsServiceImpl extends ServiceImpl<FsUserWatchSta
 
         //获取公司的会员数量和今日新增会员数量
         List<FsUserWatchStatistics> userTotal = fsUserMapper.selectFsUserTotal();
-        Map<String, FsUserWatchStatistics> userTotalMap = userTotal.stream().collect(Collectors.toMap(FsUserWatchStatistics::getCompanyId, Function.identity()));
-
-        List<FsUserWatchStatistics> list = fsUserCoursePeriods.stream()
-                .flatMap(item -> Arrays.stream(item.getCompanyId().split(","))
-                        .map(companyIdStr -> {
-                            Long companyId = Long.valueOf(companyIdStr.trim());
-                            Company company = companyMap.get(companyId);
-
-                            // 赋值
-                            FsUserWatchStatistics fsUserWatchStatistics = new FsUserWatchStatistics();
-                            BeanUtils.copyProperties(item, fsUserWatchStatistics);
-                            ZonedDateTime zonedDateTime = item.getPeriodStartingTime().atStartOfDay(ZoneId.systemDefault());
-                            // 改成使用营期线来表示营期开始时间
-                            fsUserWatchStatistics.setPeriodStartingTime(item.getPeriodLine() != null ? item.getPeriodLine() : Date.from(zonedDateTime.toInstant()));
-                            fsUserWatchStatistics.setCompanyId(companyIdStr.trim());
-                            fsUserWatchStatistics.setCompanyName(company != null ? company.getCompanyName() : null);
-
-                            FsUserWatchStatistics userTotalData = userTotalMap.get(fsUserWatchStatistics.getCompanyId());
-
-                            String key = String.format("%s-%s", fsUserWatchStatistics.getPeriodId(), fsUserWatchStatistics.getCompanyId());
-                            FsUserWatchStatistics watchData = courseWatchStatisticsMap.get(key);
-
-                            if(userTotalData != null){
-                                fsUserWatchStatistics.setUserNum(userTotalData.getUserNum());
-                                fsUserWatchStatistics.setNewUserNum(userTotalData.getNewUserNum());
-                            } else {
-                                fsUserWatchStatistics.setUserNum(0);
-                                fsUserWatchStatistics.setNewUserNum(0);
-                            }
-
-                            if(watchData != null){
-                                fsUserWatchStatistics.setWatchNum(watchData.getWatchNum());
-                                fsUserWatchStatistics.setCompleteWatchNum(watchData.getCompleteWatchNum());
-                                fsUserWatchStatistics.setCompleteWatchRate(watchData.getCompleteWatchRate());
-                            } else {
-                                fsUserWatchStatistics.setWatchNum(0);
-                                fsUserWatchStatistics.setCompleteWatchNum(0);
-                                fsUserWatchStatistics.setCompleteWatchRate(BigDecimal.ZERO);
-                            }
-
-                            // 计算上线率
-                            BigDecimal watchNum = new BigDecimal(fsUserWatchStatistics.getWatchNum());
-                            BigDecimal userNum = new BigDecimal(fsUserWatchStatistics.getUserNum());
-                            if(!userNum.equals(BigDecimal.ZERO)){
-                                BigDecimal onlineRate = watchNum.divide(userNum, 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
-                                fsUserWatchStatistics.setOnlineRate(onlineRate);
-                            } else {
-                                fsUserWatchStatistics.setOnlineRate(BigDecimal.ZERO);
-                            }
-
-                            fsUserWatchStatistics.setCreateTime(new Date());
-                            fsUserWatchStatistics.setUpdateTime(new Date());
-                            return fsUserWatchStatistics;
-                        })).collect(Collectors.toList());
-
-        //2、分批次插入数据
-        this.batchInsert(list);
+        Map<String, FsUserWatchStatistics> userTotalMap;
+        if (userTotal != null && userTotal.size() > 0) {
+            userTotalMap = userTotal.stream().collect(Collectors.toMap(FsUserWatchStatistics::getCompanyId, Function.identity()));
+
+        } else {
+            userTotalMap = null;
+        }
+        if (!fsUserCoursePeriods.isEmpty()) {
+            List<FsUserWatchStatistics> list = fsUserCoursePeriods.stream()
+                    .flatMap(item -> Arrays.stream(item.getCompanyId().split(","))
+                            .map(companyIdStr -> {
+                                Long companyId = Long.valueOf(companyIdStr.trim());
+                                Company company = companyMap.get(companyId);
+
+                                // 赋值
+                                FsUserWatchStatistics fsUserWatchStatistics = new FsUserWatchStatistics();
+                                BeanUtils.copyProperties(item, fsUserWatchStatistics);
+                                ZonedDateTime zonedDateTime = item.getPeriodStartingTime().atStartOfDay(ZoneId.systemDefault());
+                                // 改成使用营期线来表示营期开始时间
+                                fsUserWatchStatistics.setPeriodStartingTime(item.getPeriodLine() != null ? item.getPeriodLine() : Date.from(zonedDateTime.toInstant()));
+                                fsUserWatchStatistics.setCompanyId(companyIdStr.trim());
+                                fsUserWatchStatistics.setCompanyName(company != null ? company.getCompanyName() : null);
+                                if (Objects.nonNull(userTotalMap)){
+                                    FsUserWatchStatistics userTotalData = userTotalMap.get(fsUserWatchStatistics.getCompanyId());
+                                    if(userTotalData != null){
+                                        fsUserWatchStatistics.setUserNum(userTotalData.getUserNum());
+                                        fsUserWatchStatistics.setNewUserNum(userTotalData.getNewUserNum());
+                                    } else {
+                                        fsUserWatchStatistics.setUserNum(0);
+                                        fsUserWatchStatistics.setNewUserNum(0);
+                                    }
+                                }
+
+                                String key = String.format("%s-%s", fsUserWatchStatistics.getPeriodId(), fsUserWatchStatistics.getCompanyId());
+                                FsUserWatchStatistics watchData = courseWatchStatisticsMap.get(key);
+
+
+
+                                if(watchData != null){
+                                    fsUserWatchStatistics.setWatchNum(watchData.getWatchNum());
+                                    fsUserWatchStatistics.setCompleteWatchNum(watchData.getCompleteWatchNum());
+                                    fsUserWatchStatistics.setCompleteWatchRate(watchData.getCompleteWatchRate());
+                                } else {
+                                    fsUserWatchStatistics.setWatchNum(0);
+                                    fsUserWatchStatistics.setCompleteWatchNum(0);
+                                    fsUserWatchStatistics.setCompleteWatchRate(BigDecimal.ZERO);
+                                }
+
+                                // 计算上线率
+                                BigDecimal watchNum = new BigDecimal(fsUserWatchStatistics.getWatchNum());
+                                BigDecimal userNum = new BigDecimal(fsUserWatchStatistics.getUserNum());
+                                if(!userNum.equals(BigDecimal.ZERO)){
+                                    BigDecimal onlineRate = watchNum.divide(userNum, 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
+                                    fsUserWatchStatistics.setOnlineRate(onlineRate);
+                                } else {
+                                    fsUserWatchStatistics.setOnlineRate(BigDecimal.ZERO);
+                                }
+
+                                fsUserWatchStatistics.setCreateTime(new Date());
+                                fsUserWatchStatistics.setUpdateTime(new Date());
+                                return fsUserWatchStatistics;
+                            })).collect(Collectors.toList());
+            //2、分批次插入数据
+            this.batchInsert(list);
+        }
+
+
     }
 
     private void batchInsert(List<FsUserWatchStatistics> list) {

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

@@ -19,6 +19,9 @@ public class FsCourseWatchCommentVO{
     @ApiModelProperty(value = "用户名称")
     private String nickName;
 
+    @ApiModelProperty(value = "用户头像,主要用于评论显示")
+    private String avatar;
+
     @ApiModelProperty(value = "用户类型,1-管理员,2-用户")
     private Integer userType;
 

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

@@ -30,6 +30,8 @@ public class FsCourseWatchLogStatisticsListVO {
     private String type3;
     @Excel(name = "看课中断")
     private String type4;
+    @Excel(name = "上线数")
+    private Long onLineNum;
     @Excel(name = "企业微信员工名称")
     private String qwUserName;
 

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

@@ -71,4 +71,7 @@ public class FsFirstDiagnosisListUVO {
      * 销售名称
      */
     private String qwUserName;
+
+    //医生签名
+    private String signUrl;
 }

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

@@ -108,4 +108,6 @@ public class FsInquiryPatientInfoListUVO {
     private Date subTime;
 
     private Long subDoctorId;
+
+    private String subDoctorName;
 }

部分文件因文件數量過多而無法顯示