Browse Source

Merge remote-tracking branch 'origin/ScrmStores' into ScrmStores

ct 1 day ago
parent
commit
f44e22877d
100 changed files with 4336 additions and 227 deletions
  1. 75 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyTrafficController.java
  2. 49 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyTrafficLogController.java
  3. 20 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchCommentController.java
  4. 1 0
      fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  5. 97 0
      fs-admin/src/main/java/com/fs/fastGpt/FastGptChatReplaceTextController.java
  6. 112 0
      fs-admin/src/main/java/com/fs/fastGpt/FastGptKeywordSendController.java
  7. 139 0
      fs-admin/src/main/java/com/fs/fastGpt/FastgptEventLogTotalController.java
  8. 8 5
      fs-admin/src/main/java/com/fs/his/controller/FsFirstDiagnosisController.java
  9. 224 4
      fs-admin/src/main/java/com/fs/his/task/Task.java
  10. 12 4
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java
  11. 9 5
      fs-common/src/main/java/com/fs/common/core/redis/RedisCache.java
  12. 24 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  13. 1 0
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java
  14. 1 0
      fs-company/src/main/java/com/fs/company/controller/course/qw/FsQwCourseWatchLogController.java
  15. 134 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptKeywordSendController.java
  16. 148 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastgptEventLogTotalController.java
  17. 1 0
      fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java
  18. 36 0
      fs-doctor-app/src/main/java/com/fs/app/controller/DiagnosisController.java
  19. 1 0
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  20. 1 1
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  21. 118 41
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  22. 52 16
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  23. 5 0
      fs-service/src/main/java/com/fs/company/constant/CompanyTrafficConstants.java
  24. 8 0
      fs-service/src/main/java/com/fs/company/domain/Company.java
  25. 41 0
      fs-service/src/main/java/com/fs/company/domain/CompanyTrafficRecord.java
  26. 45 0
      fs-service/src/main/java/com/fs/company/domain/CompanyTrafficRecordLog.java
  27. 6 2
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  28. 10 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyTrafficRecordLogMapper.java
  29. 14 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyTrafficRecordMapper.java
  30. 23 0
      fs-service/src/main/java/com/fs/company/param/CompanyTrafficRecordChargeParam.java
  31. 20 0
      fs-service/src/main/java/com/fs/company/param/CompanyTrafficRecordLogQueryParam.java
  32. 20 0
      fs-service/src/main/java/com/fs/company/param/CompanyTrafficRecordQueryParam.java
  33. 7 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  34. 16 0
      fs-service/src/main/java/com/fs/company/service/ICompanyTrafficRecordLogService.java
  35. 20 0
      fs-service/src/main/java/com/fs/company/service/ICompanyTrafficRecordService.java
  36. 10 5
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  37. 39 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTrafficRecordLogServiceImpl.java
  38. 220 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTrafficRecordServiceImpl.java
  39. 4 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVO.java
  40. 36 6
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  41. 2 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogStatisticsListParam.java
  42. 13 0
      fs-service/src/main/java/com/fs/course/param/FsFirstDiagnosisListUParam.java
  43. 11 0
      fs-service/src/main/java/com/fs/course/param/FsInquiryPatientInfoUParam.java
  44. 11 2
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  45. 69 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  46. 2 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogStatisticsListVO.java
  47. 77 0
      fs-service/src/main/java/com/fs/course/vo/FsFirstDiagnosisListUVO.java
  48. 113 0
      fs-service/src/main/java/com/fs/course/vo/FsInquiryPatientInfoListUVO.java
  49. 2 2
      fs-service/src/main/java/com/fs/erp/service/impl/DfOrderServiceImpl.java
  50. 96 0
      fs-service/src/main/java/com/fs/fastGpt/domain/FastGptChatReplaceText.java
  51. 2 0
      fs-service/src/main/java/com/fs/fastGpt/domain/FastGptRole.java
  52. 68 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptChatReplaceTextMapper.java
  53. 10 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptRoleMapper.java
  54. 93 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastgptEventLogTotalMapper.java
  55. 76 0
      fs-service/src/main/java/com/fs/fastGpt/param/FastgptEventLogTotalParam.java
  56. 62 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastGptChatReplaceTextService.java
  57. 8 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastGptRoleService.java
  58. 94 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastgptEventLogTotalService.java
  59. 101 30
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java
  60. 0 2
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptChatMsgServiceImpl.java
  61. 93 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptChatReplaceTextServiceImpl.java
  62. 77 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptRoleServiceImpl.java
  63. 290 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptEventLogTotalServiceImpl.java
  64. 19 0
      fs-service/src/main/java/com/fs/fastGpt/vo/FastGptRoleDataVO.java
  65. 70 0
      fs-service/src/main/java/com/fs/fastGpt/vo/FastgptEventLogTotalVo.java
  66. 110 8
      fs-service/src/main/java/com/fs/fastgptApi/util/AiImgUtil.java
  67. 2 2
      fs-service/src/main/java/com/fs/fastgptApi/util/EventLogUtils.java
  68. 20 1
      fs-service/src/main/java/com/fs/gtPush/domain/PushReqBean.java
  69. 93 0
      fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java
  70. 4 0
      fs-service/src/main/java/com/fs/gtPush/service/uniPush2Service.java
  71. 120 0
      fs-service/src/main/java/com/fs/gtPush/utils/PushUtils.java
  72. 6 0
      fs-service/src/main/java/com/fs/his/domain/FsFirstDiagnosis.java
  73. 12 0
      fs-service/src/main/java/com/fs/his/dto/FindUsersByDTO.java
  74. 35 0
      fs-service/src/main/java/com/fs/his/enums/PushLogDesTypeEnum.java
  75. 34 0
      fs-service/src/main/java/com/fs/his/enums/PushLogTypeEnum.java
  76. 53 0
      fs-service/src/main/java/com/fs/his/mapper/FsFirstDiagnosisMapper.java
  77. 25 0
      fs-service/src/main/java/com/fs/his/mapper/FsInquiryPatientInfoMapper.java
  78. 4 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  79. 12 0
      fs-service/src/main/java/com/fs/his/param/FindUserByParam.java
  80. 17 0
      fs-service/src/main/java/com/fs/his/param/FsDiagnosisFillDParam.java
  81. 13 0
      fs-service/src/main/java/com/fs/his/param/FsDiagnosisListDParam.java
  82. 25 0
      fs-service/src/main/java/com/fs/his/param/FsFirstDiagnosisParam.java
  83. 2 0
      fs-service/src/main/java/com/fs/his/param/FsInquiryOrderDoPayParam.java
  84. 2 0
      fs-service/src/main/java/com/fs/his/param/FsPackageOrderDoPayParam.java
  85. 2 0
      fs-service/src/main/java/com/fs/his/param/FsStoreOrderDoPayParam.java
  86. 26 5
      fs-service/src/main/java/com/fs/his/service/IFsFirstDiagnosisService.java
  87. 8 0
      fs-service/src/main/java/com/fs/his/service/IFsInquiryPatientInfoService.java
  88. 8 0
      fs-service/src/main/java/com/fs/his/service/IFsUserService.java
  89. 110 1
      fs-service/src/main/java/com/fs/his/service/impl/FsFirstDiagnosisServiceImpl.java
  90. 17 0
      fs-service/src/main/java/com/fs/his/service/impl/FsInquiryPatientInfoServiceImpl.java
  91. 52 32
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java
  92. 123 49
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  93. 7 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  94. 33 0
      fs-service/src/main/java/com/fs/his/vo/FsDiagnosisListDVO.java
  95. 2 0
      fs-service/src/main/java/com/fs/his/vo/FsDoctorArticleUVO.java
  96. 81 0
      fs-service/src/main/java/com/fs/his/vo/FsFirstDiagnosisVO.java
  97. 1 1
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  98. 4 2
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductScrmServiceImpl.java
  99. 3 0
      fs-service/src/main/java/com/fs/qw/domain/QwExternalContact.java
  100. 4 0
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java

+ 75 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyTrafficController.java

@@ -0,0 +1,75 @@
+package com.fs.company.controller;
+
+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.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.CompanyTrafficRecord;
+import com.fs.company.param.CompanyTrafficRecordChargeParam;
+import com.fs.company.param.CompanyTrafficRecordQueryParam;
+import com.fs.company.service.ICompanyTrafficRecordService;
+import com.fs.framework.web.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;
+
+@RestController
+@RequestMapping("/company/traffic")
+public class CompanyTrafficController extends BaseController {
+
+    @Autowired
+    private ICompanyTrafficRecordService companyTrafficRecordService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /** 充值流量 */
+    @PreAuthorize("@ss.hasPermi('company:traffic:charge')")
+    @Log(title = "公司流量充值", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/rechargeTraffic")
+    public R rechargeTraffic(@RequestBody CompanyTrafficRecordChargeParam companyTrafficRecord) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyTrafficRecord.setUserId(loginUser.getUser().getUserId());
+        companyTrafficRecord.setUserName(loginUser.getUser().getUserName());
+        companyTrafficRecordService.recharge(companyTrafficRecord);
+        return R.ok();
+    }
+
+    /** 流量充值记录查询 */
+    @PreAuthorize("@ss.hasPermi('company:traffic:list')")
+    @GetMapping(value = "/list")
+    public TableDataInfo list(CompanyTrafficRecordQueryParam param) {
+        startPage();
+        List<CompanyTrafficRecord> list = companyTrafficRecordService.selectList(param);
+        return getDataTable(list);
+    }
+
+    /** 流量充值详情 */
+    @PreAuthorize("@ss.hasPermi('company:traffic:detail')")
+    @GetMapping(value = "/detail/{logId}")
+    public R detail(@PathVariable("logId") Long logId) {
+        CompanyTrafficRecord record = companyTrafficRecordService.selectById(logId);
+        return R.ok().put("data", record);
+    }
+
+    /** 流量换算*/
+    @GetMapping(value = "/trafficConversion")
+    public R trafficConversion(@RequestParam("traffic") Long amount) {
+        Long trafficKB = companyTrafficRecordService.trafficConversion(amount);
+        return R.ok().put("data", trafficKB);
+    }
+
+    /** 刷新单价*/
+    @GetMapping(value = "/refreshPrice")
+    public R refreshPrice() {
+        companyTrafficRecordService.refreshPrice();
+        return R.ok();
+    }
+
+    /** 流量统计 TODO 待完善*/
+}

+ 49 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyTrafficLogController.java

@@ -0,0 +1,49 @@
+package com.fs.company.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.company.domain.CompanyTrafficRecordLog;
+import com.fs.company.param.CompanyTrafficRecordLogQueryParam;
+import com.fs.company.service.ICompanyTrafficRecordLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/company/trafficLog")
+public class CompanyTrafficLogController extends BaseController {
+
+    @Autowired
+    private ICompanyTrafficRecordLogService companyTrafficRecordLogService;
+
+
+    /** 流量充值记录查询 */
+    @PreAuthorize("@ss.hasPermi('company:trafficLog:list')")
+    @GetMapping(value = "/list")
+    public TableDataInfo list(CompanyTrafficRecordLogQueryParam param) {
+        startPage();
+        List<CompanyTrafficRecordLog> list = companyTrafficRecordLogService.selectList(param);
+        return getDataTable(list);
+    }
+
+
+    /** 导出 */
+    @PreAuthorize("@ss.hasPermi('company:trafficLog:export')")
+    @Log(title = "流量充值记录导出", businessType = BusinessType.EXPORT)
+    @GetMapping(value = "/export")
+    public AjaxResult export(CompanyTrafficRecordLogQueryParam param) {
+        List<CompanyTrafficRecordLog> list = companyTrafficRecordLogService.selectList(param);
+        ExcelUtil<CompanyTrafficRecordLog> util = new ExcelUtil<>(CompanyTrafficRecordLog.class);
+        return util.exportExcel(list, "流量充值记录");
+    }
+
+
+
+}

+ 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, "看课评论数据");
         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();
+        }
+    }
+
 }
 }

+ 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){
         if (param.getSTime()==null||param.getETime()==null){
             return getDataTable(new ArrayList<>());
             return getDataTable(new ArrayList<>());
         }
         }
+        param.setSendType(2); //企微
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         return getDataTable(list);
         return getDataTable(list);
     }
     }

+ 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));
+    }
+}

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

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

+ 224 - 4
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.dto.ErpOrderResponse;
 import com.fs.erp.mapper.FsErpFinishPushMapper;
 import com.fs.erp.mapper.FsErpFinishPushMapper;
 import com.fs.erp.service.IErpOrderService;
 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.mapper.FastGptChatSessionMapper;
+import com.fs.fastGpt.service.IFastgptEventLogTotalService;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.FsInquiryOrder;
 import com.fs.his.domain.FsInquiryOrder;
@@ -58,10 +61,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 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
 @Slf4j
 @Component("task")
 @Component("task")
@@ -161,6 +161,226 @@ public class Task {
     @Autowired
     @Autowired
     private ICompanyUserService userService;
     private ICompanyUserService userService;
 
 
+    @Autowired
+    private IFastgptEventLogTotalService fastgptEventLogTotalService;
+
+    //统计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点执行一次
     //定时查询ipad主机使用情况,建议每天凌晨1点执行一次
     public void totalIpadTask(){
     public void totalIpadTask(){
         String dateTime = DateUtils.addDateDays(-1); // 昨天
         String dateTime = DateUtils.addDateDays(-1); // 昨天

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

@@ -1,5 +1,6 @@
 package com.fs.hisStore.controller;
 package com.fs.hisStore.controller;
 
 
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
@@ -23,6 +24,7 @@ import com.fs.hisStore.service.IFsStoreProductScrmService;
 import com.fs.statis.dto.ProductAuditDTO;
 import com.fs.statis.dto.ProductAuditDTO;
 import com.mysql.cj.util.StringUtils;
 import com.mysql.cj.util.StringUtils;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.http.ResponseEntity;
@@ -40,6 +42,7 @@ import java.util.List;
  * @author fs
  * @author fs
  * @date 2022-03-15
  * @date 2022-03-15
  */
  */
+@Slf4j
 @RestController
 @RestController
 @RequestMapping("/store/store/storeProduct")
 @RequestMapping("/store/store/storeProduct")
 public class FsStoreProductScrmController extends BaseController
 public class FsStoreProductScrmController extends BaseController
@@ -85,6 +88,7 @@ public class FsStoreProductScrmController extends BaseController
     @GetMapping("/list")
     @GetMapping("/list")
     public TableDataInfo list(FsStoreProductScrm fsStoreProduct)
     public TableDataInfo list(FsStoreProductScrm fsStoreProduct)
     {
     {
+        log.info("查询商品列表 参数: {}", fsStoreProduct);
         startPage();
         startPage();
         List<FsStoreProductListVO> list;
         List<FsStoreProductListVO> list;
         if(StringUtils.isNullOrEmpty(fsStoreProduct.getBarCode())){
         if(StringUtils.isNullOrEmpty(fsStoreProduct.getBarCode())){
@@ -146,12 +150,16 @@ public class FsStoreProductScrmController extends BaseController
     @PostMapping(value = "/addOrEdit")
     @PostMapping(value = "/addOrEdit")
     public R addOrEdit(@RequestBody FsStoreProductAddEditParam fsStoreProduct)
     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);
         return fsStoreProductService.addOrEdit(fsStoreProduct);
     }
     }

+ 9 - 5
fs-common/src/main/java/com/fs/common/core/redis/RedisCache.java

@@ -1,10 +1,6 @@
 package com.fs.common.core.redis;
 package com.fs.common.core.redis;
 
 
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.BoundSetOperations;
 import org.springframework.data.redis.core.BoundSetOperations;
@@ -236,4 +232,12 @@ public class RedisCache
     public Boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) {
     public Boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) {
         return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
         return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
     }
     }
+
+    public Long decr(String key, Long delta) {
+        return redisTemplate.opsForValue().decrement(key, delta);
+    }
+
+    public Long incr(String key, Long delta) {
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
 }
 }

+ 24 - 1
fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java

@@ -8,6 +8,7 @@ import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.core.redis.RedisCache;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.PatternUtils;
 import com.fs.common.utils.PatternUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ServletUtils;
@@ -70,6 +71,8 @@ public class CompanyUserController extends BaseController
     private ICompanyUserDelayTimeService companyUserDelayTimeService;
     private ICompanyUserDelayTimeService companyUserDelayTimeService;
     @Autowired
     @Autowired
     private ISysConfigService configService;
     private ISysConfigService configService;
+    @Autowired
+    private RedisCache redisCache;
     /**
     /**
      * 获取用户列表
      * 获取用户列表
      */
      */
@@ -259,9 +262,29 @@ public class CompanyUserController extends BaseController
         if (!PatternUtils.checkPassword(user.getPassword())) {
         if (!PatternUtils.checkPassword(user.getPassword())) {
             return AjaxResult.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20 位");
             return AjaxResult.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20 位");
         }
         }
-        return toAjax(companyUserService.resetUserPwdByUserId(user.getUserId(), SecurityUtils.encryptPassword(user.getPassword())));
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        String newPassword = SecurityUtils.encryptPassword(user.getPassword());
+        int i = companyUserService.resetUserPwdByUserId(user.getUserId(), newPassword);
+
+        if (i > 0) {
+            // 更新缓存用户密码
+            loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
+            tokenService.setLoginUser(loginUser);
+            cleanFirstLogin(loginUser);
+        }
+
+        return toAjax(i);
     }
     }
 
 
+    /**
+     * 去除首次登录的标志
+     * @param loginUser
+     */
+    private void cleanFirstLogin(LoginUser loginUser) {
+        redisCache.deleteObject("newCompanyUser:" + loginUser.getUser().getCompanyId() + ":" + loginUser.getUser().getUserName());
+    }
     /**
     /**
      * 状态修改
      * 状态修改
      */
      */

+ 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){
         if (param.getSTime()==null||param.getETime()==null){
             return getDataTable(new ArrayList<>());
             return getDataTable(new ArrayList<>());
         }
         }
+        param.setSendType(1); //个微
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         return getDataTable(list);
         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){
         if (param.getSTime()==null||param.getETime()==null){
             return getDataTable(new ArrayList<>());
             return getDataTable(new ArrayList<>());
         }
         }
+        param.setSendType(2);
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         return getDataTable(list);
         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));
+    }
+}

+ 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("/pay/wxPay/payNotify**").anonymous()
                 .antMatchers("/common/uploadWang**").anonymous()
                 .antMatchers("/common/uploadWang**").anonymous()
                 .antMatchers("/common/download**").anonymous()
                 .antMatchers("/common/download**").anonymous()
+                .antMatchers("/common/test").anonymous()
                 .antMatchers("/common/download/resource**").anonymous()
                 .antMatchers("/common/download/resource**").anonymous()
                 .antMatchers("/swagger-ui.html").anonymous()
                 .antMatchers("/swagger-ui.html").anonymous()
                 .antMatchers("/swagger-resources/**").anonymous()
                 .antMatchers("/swagger-resources/**").anonymous()

+ 36 - 0
fs-doctor-app/src/main/java/com/fs/app/controller/DiagnosisController.java

@@ -0,0 +1,36 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.his.param.FsDiagnosisFillDParam;
+import com.fs.his.param.FsDiagnosisListDParam;
+import com.fs.his.service.IFsFirstDiagnosisService;
+import com.fs.his.vo.FsDiagnosisListDVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/app/diagnosis")
+public class DiagnosisController extends AppBaseController{
+
+    @Autowired
+    private IFsFirstDiagnosisService diagnosisService;
+
+    @GetMapping("/getDiagnosisList")
+    public R getDiagnosisList(FsDiagnosisListDParam param){
+        param.setDoctorId(Long.parseLong(getDoctorId()));
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsDiagnosisListDVO> diagnosisList = diagnosisService.getDiagnosisList(param);
+        PageInfo<FsDiagnosisListDVO> pageInfo = new PageInfo<>(diagnosisList);
+        return R.ok().put("data", pageInfo);
+    }
+
+    @PutMapping("/fill")
+    public R fill(@RequestBody FsDiagnosisFillDParam param){
+        param.setDoctorId(Long.parseLong(getDoctorId()));
+        return diagnosisService.fill(param);
+    }
+}

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

@@ -336,6 +336,7 @@ public class IpadSendServer {
                     sendLink(vo, content);
                     sendLink(vo, content);
                     break;
                     break;
                 case "4":
                 case "4":
+                case "10":
                     sendMiniProgram(vo, content, miniMap);
                     sendMiniProgram(vo, content, miniMap);
                     break;
                     break;
                 case "5":
                 case "5":

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

@@ -90,7 +90,7 @@ public class SendMsg {
     }
     }
 
 
     private Map<String, FsCoursePlaySourceConfig> getMiniMap() {
     private Map<String, FsCoursePlaySourceConfig> getMiniMap() {
-        List<FsCoursePlaySourceConfig> list = fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().eq("type", 1).eq("is_del", 0));
+        List<FsCoursePlaySourceConfig> list = fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().ne("type", 2).eq("is_del", 0));
 //        SysConfig maConfig = sysConfigMapper.selectConfigByConfigKey("courseMa.config");
 //        SysConfig maConfig = sysConfigMapper.selectConfigByConfigKey("courseMa.config");
 //        List<CourseMaConfig> courseMaConfigs = JSON.parseArray(maConfig.getConfigValue(), CourseMaConfig.class);
 //        List<CourseMaConfig> courseMaConfigs = JSON.parseArray(maConfig.getConfigValue(), CourseMaConfig.class);
         return PubFun.listToMapByGroupObject(list, FsCoursePlaySourceConfig::getAppid);
         return PubFun.listToMapByGroupObject(list, FsCoursePlaySourceConfig::getAppid);

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

@@ -1,11 +1,18 @@
 package com.fs.app.controller;
 package com.fs.app.controller;
 
 
+import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.uuid.IdUtils;
 import com.fs.common.utils.uuid.IdUtils;
+import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.service.AiHookService;
 import com.fs.fastGpt.service.AiHookService;
+import com.fs.fastGpt.service.IFastGptRoleService;
 import com.fs.his.domain.FsStoreOrder;
 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.his.service.IFsStoreOrderService;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
@@ -31,6 +38,8 @@ import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
 
 
+import static com.fs.his.utils.PhoneUtil.decryptPhone;
+
 
 
 @Api("企微消息")
 @Api("企微消息")
 @RestController
 @RestController
@@ -59,58 +68,126 @@ public class QwMsgController {
     SopUserLogsInfoMapper sopUserLogsInfoMapper;
     SopUserLogsInfoMapper sopUserLogsInfoMapper;
     @Autowired
     @Autowired
     QwSopLogsMapper qwSopLogsMapper;
     QwSopLogsMapper qwSopLogsMapper;
+    @Autowired
+    private IFastGptRoleService fastGptRoleService;
+    @Autowired
+    private IFsExpressService expressService;
+    @Autowired
+    private IFsStoreOrderService storeOrderService;
 
 
     @GetMapping("/sendExpressInfo/{orderId}")
     @GetMapping("/sendExpressInfo/{orderId}")
     public R sendExpressInfo(@PathVariable Long 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;
     }
     }
 
 
 
 

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

@@ -8,8 +8,10 @@ import com.fs.common.core.domain.R;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyMiniapp;
 import com.fs.company.domain.CompanyMiniapp;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.config.cloud.CloudHostProper;
@@ -168,6 +170,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     @Autowired
     @Autowired
     private IQwCompanyService iQwCompanyService;
     private IQwCompanyService iQwCompanyService;
 
 
+    @Autowired
+    private CompanyMapper companyMapper;
 
 
     @PostConstruct
     @PostConstruct
     public void init() {
     public void init() {
@@ -315,6 +319,9 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
         Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap = miniList.stream().collect(Collectors.groupingBy(CompanyMiniapp::getCompanyId, Collectors.groupingBy(CompanyMiniapp::getType)));
         Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap = miniList.stream().collect(Collectors.groupingBy(CompanyMiniapp::getCompanyId, Collectors.groupingBy(CompanyMiniapp::getType)));
 
 
+
+        List<Company> companies = companyMapper.selectCompanyAllList();
+
         log.info("共分组 {} 个 SOP ID 进行处理。", sopLogsGroupedById.size());
         log.info("共分组 {} 个 SOP ID 进行处理。", sopLogsGroupedById.size());
 
 
         CountDownLatch sopGroupLatch = new CountDownLatch(sopLogsGroupedById.size());
         CountDownLatch sopGroupLatch = new CountDownLatch(sopLogsGroupedById.size());
@@ -322,7 +329,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         for (Map.Entry<String, List<SopUserLogsVo>> entry : sopLogsGroupedById.entrySet()) {
         for (Map.Entry<String, List<SopUserLogsVo>> entry : sopLogsGroupedById.entrySet()) {
             String sopId = entry.getKey();
             String sopId = entry.getKey();
             List<SopUserLogsVo> userLogsVos = entry.getValue();
             List<SopUserLogsVo> userLogsVos = entry.getValue();
-            processSopGroupAsync(sopId, userLogsVos, sopGroupLatch,currentTime, groupChatMap,config,miniMap);
+            processSopGroupAsync(sopId, userLogsVos, sopGroupLatch,currentTime, groupChatMap,config,miniMap,companies);
         }
         }
 
 
         // 等待所有 SOP 分组处理完成
         // 等待所有 SOP 分组处理完成
@@ -343,9 +350,10 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             backoff = @Backoff(delay = 2000)
             backoff = @Backoff(delay = 2000)
     )
     )
     public void processSopGroupAsync(String sopId, List<SopUserLogsVo> userLogsVos, CountDownLatch latch ,LocalDateTime currentTime,
     public void processSopGroupAsync(String sopId, List<SopUserLogsVo> userLogsVos, CountDownLatch latch ,LocalDateTime currentTime,
-                                     Map<String, QwGroupChat> groupChatMap,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap) {
+                                     Map<String, QwGroupChat> groupChatMap,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
+                                     List<Company> companies) {
         try {
         try {
-            processSopGroup(sopId, userLogsVos,currentTime, groupChatMap, config,miniMap);
+            processSopGroup(sopId, userLogsVos,currentTime, groupChatMap, config,miniMap,companies);
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("处理 SOP ID {} 时发生异常: {}", sopId, e.getMessage(), e);
             log.error("处理 SOP ID {} 时发生异常: {}", sopId, e.getMessage(), e);
         } finally {
         } finally {
@@ -355,7 +363,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
 
 
     private void processSopGroup(String sopId, List<SopUserLogsVo> userLogsVos,LocalDateTime currentTime, Map<String,
     private void processSopGroup(String sopId, List<SopUserLogsVo> userLogsVos,LocalDateTime currentTime, Map<String,
-            QwGroupChat> groupChatMap,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap) throws Exception {
+            QwGroupChat> groupChatMap,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
+                                 List<Company> companies) throws Exception {
         QwSopRuleTimeVO ruleTimeVO = sopMapper.selectQwSopByClickHouseId(sopId);
         QwSopRuleTimeVO ruleTimeVO = sopMapper.selectQwSopByClickHouseId(sopId);
 
 
         if (ruleTimeVO == null) {
         if (ruleTimeVO == null) {
@@ -397,7 +406,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
         CountDownLatch userLogsLatch = new CountDownLatch(userLogsVos.size());
         CountDownLatch userLogsLatch = new CountDownLatch(userLogsVos.size());
         for (SopUserLogsVo logVo : userLogsVos) {
         for (SopUserLogsVo logVo : userLogsVos) {
-            processUserLogAsync(logVo, ruleTimeVO, rulesList, userLogsLatch, currentTime, groupChatMap,qwCompany.getMiniAppId(), config,miniMap);
+            processUserLogAsync(logVo, ruleTimeVO, rulesList, userLogsLatch, currentTime, groupChatMap,qwCompany.getMiniAppId(),
+                    config,miniMap,companies);
         }
         }
 
 
         // 等待所有用户日志处理完成
         // 等待所有用户日志处理完成
@@ -418,9 +428,10 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     )
     )
     public void processUserLogAsync(SopUserLogsVo logVo, QwSopRuleTimeVO ruleTimeVO, List<QwSopTempRules> tempSettings,
     public void processUserLogAsync(SopUserLogsVo logVo, QwSopRuleTimeVO ruleTimeVO, List<QwSopTempRules> tempSettings,
                                     CountDownLatch latch, LocalDateTime currentTime, Map<String, QwGroupChat> groupChatMap,
                                     CountDownLatch latch, LocalDateTime currentTime, Map<String, QwGroupChat> groupChatMap,
-                                    String miniAppId,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap) {
+                                    String miniAppId,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
+                                    List<Company> companies) {
         try {
         try {
-            processUserLog(logVo, ruleTimeVO, tempSettings,currentTime, groupChatMap, miniAppId, config,miniMap);
+            processUserLog(logVo, ruleTimeVO, tempSettings,currentTime, groupChatMap, miniAppId, config,miniMap,companies);
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("处理用户日志 {} 时发生异常: {}", logVo.getId(), e.getMessage(), e);
             log.error("处理用户日志 {} 时发生异常: {}", logVo.getId(), e.getMessage(), e);
         } finally {
         } finally {
@@ -431,7 +442,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
     private void processUserLog(SopUserLogsVo logVo, QwSopRuleTimeVO ruleTimeVO, List<QwSopTempRules> tempSettings,
     private void processUserLog(SopUserLogsVo logVo, QwSopRuleTimeVO ruleTimeVO, List<QwSopTempRules> tempSettings,
                                 LocalDateTime currentTime, Map<String, QwGroupChat> groupChatMap,String miniAppId,
                                 LocalDateTime currentTime, Map<String, QwGroupChat> groupChatMap,String miniAppId,
-                                CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap) {
+                                CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
+                                List<Company> companies) {
         try {
         try {
 
 
             LocalDate startDate = LocalDate.parse(logVo.getStartTime(), DATE_FORMATTER);
             LocalDate startDate = LocalDate.parse(logVo.getStartTime(), DATE_FORMATTER);
@@ -599,7 +611,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
                         insertSopUserLogs(sopUserLogsInfos, logVo, sendTime, ruleTimeVO, content, qwUserId,
                         insertSopUserLogs(sopUserLogsInfos, logVo, sendTime, ruleTimeVO, content, qwUserId,
                                 companyUserId, companyId, qwUserByRedis.getWelcomeText(),qwUserByRedis.getQwUserName(),
                                 companyUserId, companyId, qwUserByRedis.getWelcomeText(),qwUserByRedis.getQwUserName(),
-                                groupChatMap, miniAppId,config,miniMap, sendMsgType);
+                                groupChatMap, miniAppId,config,miniMap, sendMsgType,companies);
 
 
                     }
                     }
                 } catch (Exception e) {
                 } catch (Exception e) {
@@ -643,7 +655,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                                    QwSopRuleTimeVO ruleTimeVO, QwSopTempSetting.Content content,
                                    QwSopRuleTimeVO ruleTimeVO, QwSopTempSetting.Content content,
                                    String qwUserId,String companyUserId,String companyId,String welcomeText,String qwUserName,
                                    String qwUserId,String companyUserId,String companyId,String welcomeText,String qwUserName,
                                    Map<String, QwGroupChat> groupChatMap,String miniAppId,CourseConfig config,
                                    Map<String, QwGroupChat> groupChatMap,String miniAppId,CourseConfig config,
-                                   Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap, Integer sendMsgType) {
+                                   Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap, Integer sendMsgType,
+                                   List<Company> companies) {
         String formattedSendTime = sendTime.toInstant()
         String formattedSendTime = sendTime.toInstant()
                 .atZone(ZoneId.systemDefault())
                 .atZone(ZoneId.systemDefault())
                 .format(DATE_TIME_FORMATTER);
                 .format(DATE_TIME_FORMATTER);
@@ -670,7 +683,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                 QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null);
                 QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null);
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                         type, qwUserId, companyUserId, companyId, groupChat.getChatId(), welcomeText, qwUserName,
                         type, qwUserId, companyUserId, companyId, groupChat.getChatId(), welcomeText, qwUserName,
-                        null, true, miniAppId, groupChat,config, miniMap, null, sendMsgType);
+                        null, true, miniAppId, groupChat,config, miniMap, null, sendMsgType,companies);
             } else {
             } else {
                 if(groupChat.getChatUserList() != null && !groupChat.getChatUserList().isEmpty()){
                 if(groupChat.getChatUserList() != null && !groupChat.getChatUserList().isEmpty()){
                     groupChat.getChatUserList().forEach(user -> {
                     groupChat.getChatUserList().forEach(user -> {
@@ -679,7 +692,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                         QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, user.getUserId(), user.getName(), null, isOfficial, null);
                         QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, user.getUserId(), user.getName(), null, isOfficial, null);
                         handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                         handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                                 type, qwUserId, companyUserId, companyId, user.getId().toString(), welcomeText, qwUserName,
                                 type, qwUserId, companyUserId, companyId, user.getId().toString(), welcomeText, qwUserName,
-                                null, false, miniAppId, groupChat,config, miniMap, null, sendMsgType);
+                                null, false, miniAppId, groupChat,config, miniMap, null, sendMsgType,companies);
                     });
                     });
                 }
                 }
             }
             }
@@ -694,7 +707,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId, isOfficial, contactId.getExternalId());
                     QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId, isOfficial, contactId.getExternalId());
                     handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                     handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                             type, qwUserId, companyUserId, companyId, externalId, welcomeText, qwUserName, fsUserId, false, miniAppId,
                             type, qwUserId, companyUserId, companyId, externalId, welcomeText, qwUserName, fsUserId, false, miniAppId,
-                            null,config, miniMap, grade, sendMsgType);
+                            null,config, miniMap, grade, sendMsgType,companies);
                 } catch (Exception e) {
                 } catch (Exception e) {
                     log.error("处理 externalContactId {} 时发生异常: {}", contactId, e.getMessage(), e);
                     log.error("处理 externalContactId {} 时发生异常: {}", contactId, e.getMessage(), e);
                 }
                 }
@@ -803,7 +816,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                                       String qwUserName, Long fsUserId, boolean isGroupChat, String miniAppId,
                                       String qwUserName, Long fsUserId, boolean isGroupChat, String miniAppId,
                                       QwGroupChat groupChat,CourseConfig config,
                                       QwGroupChat groupChat,CourseConfig config,
                                       Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
                                       Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
-                                      Integer grade, Integer sendMsgType  ) {
+                                      Integer grade, Integer sendMsgType ,List<Company> companies ) {
         switch (type) {
         switch (type) {
             case 1:
             case 1:
                 handleNormalMessage(sopLogs, content,companyUserId);
                 handleNormalMessage(sopLogs, content,companyUserId);
@@ -811,7 +824,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             case 2:
             case 2:
                 handleCourseMessage(sopLogs, content, logVo, sendTime, courseId, videoId,
                 handleCourseMessage(sopLogs, content, logVo, sendTime, courseId, videoId,
                         qwUserId, companyUserId, companyId, externalId, welcomeText,qwUserName, fsUserId,
                         qwUserId, companyUserId, companyId, externalId, welcomeText,qwUserName, fsUserId,
-                        isGroupChat, miniAppId, groupChat,config,miniMap, grade, sendMsgType);
+                        isGroupChat, miniAppId, groupChat,config,miniMap, grade, sendMsgType,companies);
                 break;
                 break;
             case 3:
             case 3:
                 handleOrderMessage(sopLogs, content);
                 handleOrderMessage(sopLogs, content);
@@ -844,7 +857,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                                      SopUserLogsVo logVo, Date sendTime, Long courseId, Long videoId, String qwUserId, String companyUserId,
                                      SopUserLogsVo logVo, Date sendTime, Long courseId, Long videoId, String qwUserId, String companyUserId,
                                      String companyId, String externalId, String welcomeText, String qwUserName,
                                      String companyId, String externalId, String welcomeText, String qwUserName,
                                      Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat,CourseConfig config,Map<Long,
                                      Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat,CourseConfig config,Map<Long,
-                                     Map<Integer, List<CompanyMiniapp>>> miniMap,Integer grade, Integer sendMsgType) {
+                                     Map<Integer, List<CompanyMiniapp>>> miniMap,Integer grade, Integer sendMsgType,
+                                     List<Company> companies) {
         // 深拷贝 Content 对象,避免使用 JSON
         // 深拷贝 Content 对象,避免使用 JSON
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         if (clonedContent == null) {
         if (clonedContent == null) {
@@ -970,6 +984,28 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     setting.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
                     setting.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
                     setting.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));
                     setting.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));
 
 
+                    break;
+                //自定义小程序
+                case "10":
+                    addWatchLogIfNeeded(sopLogs, videoId, courseId, sendTime, qwUserId, companyUserId, companyId, externalId,logVo);
+
+                    Optional<Company> matchedCompany = companies.stream()
+                            .filter(company -> String.valueOf(company.getCompanyId()).equals(companyId))
+                            .findFirst();
+                    if (matchedCompany.isPresent()) {
+                        Company company = matchedCompany.get();
+
+                        String customMiniAppId = company.getCustomMiniAppId();
+
+                        if (customMiniAppId != null && !customMiniAppId.trim().isEmpty()) {
+                            setting.setMiniprogramAppid(customMiniAppId);
+                        } else {
+                            setting.setMiniprogramAppid("该公司未配置自定义小程序:"+companyId);
+                        }
+                    } else {
+                        setting.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
+                    }
+
                     break;
                     break;
                 default:
                 default:
                     break;
                     break;

+ 5 - 0
fs-service/src/main/java/com/fs/company/constant/CompanyTrafficConstants.java

@@ -0,0 +1,5 @@
+package com.fs.company.constant;
+
+public class CompanyTrafficConstants {
+    public static final String CACHE_KEY = "company:traffic:record:";
+}

+ 8 - 0
fs-service/src/main/java/com/fs/company/domain/Company.java

@@ -110,6 +110,11 @@ public class Company extends BaseEntity
      * 点播配置-小程序appId
      * 点播配置-小程序appId
      */
      */
     private String courseMiniAppId;
     private String courseMiniAppId;
+    /**
+    * 自定义小程序
+    */
+    private String customMiniAppId;
+
     /** 会员是否默认黑名单,1-是;0-否(用于销售分享成为会员的操作) */
     /** 会员是否默认黑名单,1-是;0-否(用于销售分享成为会员的操作) */
     private Integer fsUserIsDefaultBlack;
     private Integer fsUserIsDefaultBlack;
     private Integer repeat;
     private Integer repeat;
@@ -126,6 +131,9 @@ public class Company extends BaseEntity
 
 
     /** 后台制单是否需要付款 默认1 0-否 1-是*/
     /** 后台制单是否需要付款 默认1 0-否 1-是*/
     private Integer isPay;
     private Integer isPay;
+    /** 限制销售公司Pad数量 -1表示不做限制*/
     private Integer maxPadNum;
     private Integer maxPadNum;
+    /** 所属部门id */
+    private Long deptId;
 
 
 }
 }

+ 41 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyTrafficRecord.java

@@ -0,0 +1,41 @@
+package com.fs.company.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * 销售公司流量记录对象 company_traffic_record
+ *
+ * */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class CompanyTrafficRecord {
+
+    @Excel(name = "id")
+    @TableId
+    private Long id;
+    @Excel(name = "公司id")
+    private Long companyId;
+    @Excel(name = "部门id")
+    private Long deptId;
+    @Excel(name="公司名称")
+    private String companyName;
+    @Excel(name = "流量余额")
+    private Long balance;     // 单位: KB
+    @Excel(name = "创建时间")
+    private Date createTime;
+    @Excel(name = "更新时间")
+    private Date updateTime;
+    @Excel(name = "创建人")
+    private Long createBy;
+    @Excel(name = "更新人")
+    private Long updateBy;
+}

+ 45 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyTrafficRecordLog.java

@@ -0,0 +1,45 @@
+package com.fs.company.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * 销售公司流量记录对象 company_traffic_record_log
+ *
+ * */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class CompanyTrafficRecordLog {
+
+    @Excel(name = "id")
+    @TableId
+    private Long id;
+    @Excel(name = "公司id")
+    private Long companyId;
+    @Excel(name = "用户id")
+    private Long userId;
+    @Excel(name = "用户名称")
+    private String userName;
+    @Excel(name = "操作类型")
+    private Integer operationType; // 1-充值 2-扣费
+    @Excel(name = "流量变动数")
+    private Long trafficAmount;    // 单位: KB
+    @Excel(name = "充值金额")
+    private Long chargeAmount;    // 单位: 元
+    @Excel(name = "流量余额")
+    private Long balance;     // 单位: KB
+    @Excel(name = "备注")
+    private String remark;
+    @Excel(name = "创建时间" , width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.EXPORT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+}

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

@@ -5,6 +5,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.Set;
 
 
 import com.fs.company.domain.Company;
 import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
 import com.fs.company.param.CompanyParam;
 import com.fs.company.param.CompanyParam;
 import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyNameVO;
 import com.fs.company.vo.CompanyNameVO;
@@ -148,8 +149,9 @@ public interface CompanyMapper
 
 
 
 
     @Select({"<script> " +
     @Select({"<script> " +
-            "select c.*,cu.user_name FROM company c LEFT JOIN company_user cu ON c.user_id =cu.user_id  " +
-            "where is_del=0 " +
+            "select c.*,cu.user_name,qu.used_num FROM company c LEFT JOIN company_user cu ON c.user_id =cu.user_id  " +
+            "LEFT JOIN (select company_id, count(id) as used_num from qw_user where server_id is not null group by company_id) qu ON qu.company_id = c.company_id " +
+            "where c.is_del=0 " +
             "            <if test=\"companyName != null  and companyName != ''\"> and c.company_name like concat('%', #{companyName}, '%')</if>\n" +
             "            <if test=\"companyName != null  and companyName != ''\"> and c.company_name like concat('%', #{companyName}, '%')</if>\n" +
             "            <if test=\"companyMobile != null  and companyMobile != ''\"> and c.company_mobile = #{companyMobile}</if>\n" +
             "            <if test=\"companyMobile != null  and companyMobile != ''\"> and c.company_mobile = #{companyMobile}</if>\n" +
             "            <if test=\"companyAddress != null  and companyAddress != ''\"> and c.company_address = #{companyAddress}</if>\n" +
             "            <if test=\"companyAddress != null  and companyAddress != ''\"> and c.company_address = #{companyAddress}</if>\n" +
@@ -189,4 +191,6 @@ public interface CompanyMapper
 
 
     List<Company> selectCompanyByIds2(@Param("companyIds") Set<Long> companyIds);
     List<Company> selectCompanyByIds2(@Param("companyIds") Set<Long> companyIds);
 
 
+
+    List<CompanyUser> selectCompanyListByIds(@Param("userIds") String result);
 }
 }

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

@@ -0,0 +1,10 @@
+package com.fs.company.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.domain.CompanyTrafficRecordLog;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface CompanyTrafficRecordLogMapper extends BaseMapper<CompanyTrafficRecordLog> {
+
+}

+ 14 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyTrafficRecordMapper.java

@@ -0,0 +1,14 @@
+package com.fs.company.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.domain.CompanyTrafficRecord;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+@Mapper
+public interface CompanyTrafficRecordMapper extends BaseMapper<CompanyTrafficRecord> {
+
+    @Select("SELECT SUM(ctr.balance) FROM company_traffic_record ctr inner join company c on ctr.company_id = c.company_id and c.dept_id = #{deptId}")
+    Long calculateTotalTrafficByDeptId(@Param("deptId") Long deptId);
+}

+ 23 - 0
fs-service/src/main/java/com/fs/company/param/CompanyTrafficRecordChargeParam.java

@@ -0,0 +1,23 @@
+package com.fs.company.param;
+
+import com.fs.company.domain.Company;
+import lombok.Data;
+
+@Data
+public class CompanyTrafficRecordChargeParam {
+
+    private Long companyId;
+    private Integer operationType; // 1-充值 2-扣费
+    //充值金额
+    private Long chargeAmount;
+    //扣除流量
+    private Long changeTraffic;
+    private String remark;
+    private Long userId;
+    private String userName;
+
+    /**
+     *公司实例
+     * */
+    private Company company;
+}

+ 20 - 0
fs-service/src/main/java/com/fs/company/param/CompanyTrafficRecordLogQueryParam.java

@@ -0,0 +1,20 @@
+package com.fs.company.param;
+
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class CompanyTrafficRecordLogQueryParam {
+
+
+    private Long id;
+    private Long companyId;
+    private List<Long> companyIds;
+    private Long userId;
+    private Integer operationType; // 1-充值 2-扣费
+    private Date createTime;
+    private Date createTimeStart;
+    private Date createTimeEnd;
+}

+ 20 - 0
fs-service/src/main/java/com/fs/company/param/CompanyTrafficRecordQueryParam.java

@@ -0,0 +1,20 @@
+package com.fs.company.param;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class CompanyTrafficRecordQueryParam {
+
+
+    private Long id;
+    private Long companyId;
+    private List<Long> companyIds;
+    private Long createBy;
+    private Date createTime;
+    private Date createTimeStart;
+    private Date createTimeEnd;
+}

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

+ 16 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyTrafficRecordLogService.java

@@ -0,0 +1,16 @@
+package com.fs.company.service;
+
+import com.fs.company.domain.CompanyTrafficRecordLog;
+import com.fs.company.param.CompanyTrafficRecordLogQueryParam;
+
+import java.util.List;
+
+public interface ICompanyTrafficRecordLogService {
+    //查询流量记录列表
+    List<CompanyTrafficRecordLog> selectList(CompanyTrafficRecordLogQueryParam record);
+    //查询流量记录
+    CompanyTrafficRecordLog selectById(Long id);
+    //保存流量记录
+    boolean save(CompanyTrafficRecordLog entity);
+
+}

+ 20 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyTrafficRecordService.java

@@ -0,0 +1,20 @@
+package com.fs.company.service;
+
+import com.fs.company.domain.CompanyTrafficRecord;
+import com.fs.company.param.CompanyTrafficRecordChargeParam;
+import com.fs.company.param.CompanyTrafficRecordQueryParam;
+
+import java.util.List;
+
+public interface ICompanyTrafficRecordService {
+    //添加流量记录
+    boolean recharge(CompanyTrafficRecordChargeParam record);
+    //查询流量记录列表
+    List<CompanyTrafficRecord> selectList(CompanyTrafficRecordQueryParam record);
+    //查询流量记录
+    CompanyTrafficRecord selectById(Long id);
+
+    Long trafficConversion(Long amount);
+
+    void refreshPrice();
+}

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

@@ -109,11 +109,11 @@ public class CompanyServiceImpl implements ICompanyService
     @Override
     @Override
     public Company selectCompanyById(Long companyId){
     public Company selectCompanyById(Long companyId){
         Company company = companyMapper.selectCompanyById(companyId);
         Company company = companyMapper.selectCompanyById(companyId);
-        if(company == null)
-            return 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));
+        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;
         return company;
     }
     }
 
 
@@ -1322,4 +1322,9 @@ public class CompanyServiceImpl implements ICompanyService
             }
             }
         }
         }
     }
     }
+
+    @Override
+    public List<CompanyUser> selectCompanyListByIds(String result) {
+        return companyMapper.selectCompanyListByIds(result);
+    }
 }
 }

+ 39 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyTrafficRecordLogServiceImpl.java

@@ -0,0 +1,39 @@
+package com.fs.company.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.company.domain.CompanyTrafficRecordLog;
+import com.fs.company.mapper.CompanyTrafficRecordLogMapper;
+import com.fs.company.param.CompanyTrafficRecordLogQueryParam;
+import com.fs.company.service.ICompanyTrafficRecordLogService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+public class CompanyTrafficRecordLogServiceImpl extends ServiceImpl<CompanyTrafficRecordLogMapper, CompanyTrafficRecordLog> implements ICompanyTrafficRecordLogService {
+
+
+    @Override
+    public List<CompanyTrafficRecordLog> selectList(CompanyTrafficRecordLogQueryParam record) {
+        return baseMapper.selectList(new LambdaQueryWrapper<CompanyTrafficRecordLog>()
+                .eq(record.getCompanyId() != null ,CompanyTrafficRecordLog::getCompanyId, record.getCompanyId())
+                .in(record.getCompanyIds() != null,CompanyTrafficRecordLog::getCompanyId, record.getCompanyIds())
+                .eq(record.getUserId() != null ,CompanyTrafficRecordLog::getUserId, record.getUserId())
+                .eq(record.getOperationType() != null ,CompanyTrafficRecordLog::getOperationType, record.getOperationType())
+                .eq(record.getCreateTime() != null ,CompanyTrafficRecordLog::getCreateTime, record.getCreateTime())
+                .between(record.getCreateTimeStart() != null && record.getCreateTimeEnd() != null,CompanyTrafficRecordLog::getCreateTime, record.getCreateTimeStart(), record.getCreateTimeEnd()));
+    }
+
+    @Override
+    public CompanyTrafficRecordLog selectById(Long id) {
+        return baseMapper.selectById(id);
+    }
+
+    @Override
+    public boolean save(CompanyTrafficRecordLog entity) {
+        return baseMapper.insert(entity)==1;
+    }
+}

+ 220 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyTrafficRecordServiceImpl.java

@@ -0,0 +1,220 @@
+package com.fs.company.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.company.constant.CompanyTrafficConstants;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyTrafficRecord;
+import com.fs.company.domain.CompanyTrafficRecordLog;
+import com.fs.company.mapper.CompanyTrafficRecordMapper;
+import com.fs.company.param.CompanyTrafficRecordChargeParam;
+import com.fs.company.param.CompanyTrafficRecordQueryParam;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyTrafficRecordLogService;
+import com.fs.company.service.ICompanyTrafficRecordService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.util.Date;
+import java.util.List;
+
+@Service
+@Slf4j
+public class CompanyTrafficRecordServiceImpl extends ServiceImpl<CompanyTrafficRecordMapper, CompanyTrafficRecord> implements ICompanyTrafficRecordService {
+
+    @Autowired
+    RedisCache redisCache;
+
+    @Autowired
+    private ISysConfigService iSysConfigService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    private SysConfig config;
+
+    @Autowired
+    private ICompanyTrafficRecordLogService companyTrafficRecordLogService;
+
+    //启动时初始化流量
+    @PostConstruct
+    public void init() {
+        List<CompanyTrafficRecord> companyTrafficRecords = baseMapper.selectList(new LambdaQueryWrapper<>());
+        for (CompanyTrafficRecord companyTrafficRecord : companyTrafficRecords) {
+            // 获取公司流量
+            Long balance = companyTrafficRecord.getBalance();
+            // 获取部门ID
+            Long deptId = companyTrafficRecord.getDeptId();
+            // 获取公司ID
+            Long companyId = companyTrafficRecord.getCompanyId();
+            // 缓存 key=CACHE_KEY:deptId:companyId  value=剩余流量
+            redisCache.setCacheObject(CompanyTrafficConstants.CACHE_KEY + ":" + deptId + ":" + companyId, balance);
+            // 缓存 key=CACHE_KEY:deptId  value=部门ID
+            calculateTotalTrafficByDeptId(deptId);
+        }
+    }
+
+    @Scheduled(cron = "0 0 3 * * ?")
+    public void refreshTraffic() {
+        List<CompanyTrafficRecord> companyTrafficRecords = baseMapper.selectList(new LambdaQueryWrapper<>());
+        for (CompanyTrafficRecord companyTrafficRecord : companyTrafficRecords) {
+            updateRedisCache(companyTrafficRecord);
+        }
+    }
+
+    //通过redis更新表流量并添加扣除日志
+    private void updateRedisCache(CompanyTrafficRecord companyTrafficRecord){
+        Long balance = redisCache.getCacheObject(CompanyTrafficConstants.CACHE_KEY
+                + ":" + companyTrafficRecord.getDeptId()
+                + ":" + companyTrafficRecord.getCompanyId());
+        if(balance != null)
+            baseMapper.updateById(CompanyTrafficRecord.builder().id(companyTrafficRecord.getId()).balance(balance).build());
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean recharge(CompanyTrafficRecordChargeParam record) {
+        CompanyTrafficRecord companyTrafficRecord = new CompanyTrafficRecord();
+        //校验参数companyId
+        if (record.getCompanyId() == null || !validCompany(record))
+            throw new IllegalArgumentException("销售公司异常");
+
+        //查询公司流量记录
+        CompanyTrafficRecord companyRecord = baseMapper.selectOne(new LambdaQueryWrapper<CompanyTrafficRecord>()
+                .eq(CompanyTrafficRecord::getCompanyId, record.getCompanyId()));
+
+        switch (record.getOperationType()) {
+            //充值
+            case 1:
+                //获取转换后的流量
+                Long trafficAmount = trafficConversion(record.getChargeAmount());
+                record.setChangeTraffic(trafficAmount);//用于处理日志
+                if(companyRecord != null) {
+                    //不是第一次充值  增加流量
+                    companyTrafficRecord.setBalance(companyRecord.getBalance() + trafficAmount);
+                    companyTrafficRecord.setId(companyRecord.getId());
+                    companyTrafficRecord.setUpdateTime(new Date());
+                    companyTrafficRecord.setUpdateBy(record.getUserId());
+                    baseMapper.updateById(companyTrafficRecord);
+                }else{
+                    companyTrafficRecord.setBalance(trafficAmount);
+                    companyTrafficRecord.setCompanyId(record.getCompanyId());
+                    companyTrafficRecord.setDeptId(record.getCompany().getDeptId());
+                    companyTrafficRecord.setCompanyName(record.getCompany().getCompanyName());
+                    companyTrafficRecord.setCreateTime(new Date());
+                    companyTrafficRecord.setCreateBy(record.getUserId());
+                    baseMapper.insert(companyTrafficRecord);
+                }
+                break;
+            //扣除
+            case 2:
+                //扣除流量
+                /*if (companyRecord.getBalance() < record.getChangeTraffic())
+                    throw new IllegalArgumentException("公司流量余额不足");*/
+                companyTrafficRecord.setBalance(companyTrafficRecord.getBalance() - record.getChangeTraffic());
+                companyTrafficRecord.setId(companyRecord.getId());
+                companyTrafficRecord.setUpdateTime(new Date());
+                companyTrafficRecord.setUpdateBy(record.getUserId());
+                baseMapper.updateById(companyTrafficRecord);
+                break;
+            default:
+                throw new IllegalArgumentException("非法的操作类型");
+        }
+        // 更新Redis缓存
+        updateRedisCache(record, companyTrafficRecord);
+
+        return doLog(companyTrafficRecord,record);
+    }
+
+    private boolean validCompany(CompanyTrafficRecordChargeParam  record){
+        Company company = new Company();
+        company.setCompanyId(record.getCompanyId());
+        company.setIsDel(0);
+        List<Company> companies = companyService.selectCompanyList(company);
+        if(companies != null && companies.size() == 1){
+            record.setCompany(companies.get(0));
+            return true;
+        }else{
+            return false;
+        }
+    }
+    /**
+     * 更新Redis缓存
+     * @param record 充值参数
+     * @param companyTrafficRecord 公司流量记录
+     */
+    private void updateRedisCache(CompanyTrafficRecordChargeParam record, CompanyTrafficRecord companyTrafficRecord) {
+        if (record.getCompany() != null && record.getCompany().getDeptId() != null) {
+            // 更新缓存 key=CACHE_KEY:deptId:companyId  value=剩余流量
+            redisCache.setCacheObject(CompanyTrafficConstants.CACHE_KEY + ":" + record.getCompany().getDeptId() + ":" + record.getCompanyId(),
+                    companyTrafficRecord.getBalance());
+
+            // 计算该部门下所有公司流量总和
+            calculateTotalTrafficByDeptId(record.getCompany().getDeptId());
+        }else {
+            // 抛出异常
+            throw new IllegalArgumentException("缓存ID异常");
+        }
+    }
+
+    /**
+     * 部门下所有公司流量总和
+     * */
+    private void calculateTotalTrafficByDeptId(Long deptId) {
+        Long totalTraffic = baseMapper.calculateTotalTrafficByDeptId(deptId);
+        redisCache.setCacheObject(CompanyTrafficConstants.CACHE_KEY + ":" + deptId, totalTraffic);
+    }
+
+    private boolean doLog(CompanyTrafficRecord companyTrafficRecord,CompanyTrafficRecordChargeParam record){
+        return companyTrafficRecordLogService.save(CompanyTrafficRecordLog.builder()
+                        .balance(companyTrafficRecord.getBalance())
+                        .trafficAmount(record.getChangeTraffic())
+                        .chargeAmount(record.getChargeAmount())
+                        .companyId(record.getCompanyId())
+                        .createTime(new Date())
+                        .operationType(record.getOperationType())
+                        .userId(record.getUserId())
+                        .remark(record.getRemark())
+                        .userName(record.getUserName())
+                        .build());
+    }
+
+    @Override
+    public List<CompanyTrafficRecord> selectList(CompanyTrafficRecordQueryParam record) {
+        return baseMapper.selectList(new LambdaQueryWrapper<CompanyTrafficRecord>()
+                .eq(record.getCompanyId() != null,CompanyTrafficRecord::getCompanyId, record.getCompanyId())
+                .in(record.getCompanyIds() != null && !record.getCompanyIds().isEmpty(),CompanyTrafficRecord::getCompanyId, record.getCompanyIds())
+                .between(record.getCreateTimeStart() != null && record.getCreateTimeEnd() != null,CompanyTrafficRecord::getCreateTime, record.getCreateTimeStart(),record.getCreateTimeEnd()));
+    }
+
+    @Override
+    public CompanyTrafficRecord selectById(Long id) {
+        return baseMapper.selectById(id);
+    }
+
+
+    /** 充值金额转换流量KB*/
+    @Override
+    public Long trafficConversion(Long amount) {
+        if(this.config == null) {
+            this.config = iSysConfigService.selectConfigByConfigKey("statis.config");
+        }
+        JSONObject jsonObject = JSONObject.parseObject(this.config.getConfigValue());
+        float trafficPrice = jsonObject.getFloatValue("trafficPrice");
+        double trafficGB = amount / trafficPrice;
+        return (long) (trafficGB * 1024 * 1024);
+    }
+
+    @Override
+    public void refreshPrice() {
+        this.config = iSysConfigService.selectConfigByConfigKey("statis.config");
+    }
+}

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

@@ -90,4 +90,8 @@ public class CompanyVO implements Serializable
     private List<String> miniAppMaster;
     private List<String> miniAppMaster;
     private List<String> miniAppServer;
     private List<String> miniAppServer;
     private Integer maxPadNum;
     private Integer maxPadNum;
+    /** 已占用 */
+    private Integer usedNum;
+    /** 所属部门id */
+    private Long deptId;
 }
 }

+ 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({"<script> " +
             "SELECT \n" +
             "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 = '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 = '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 = '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" +
             "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_video v on v.video_id=o.video_id \n" +
             "LEFT JOIN fs_user_course uc on uc.course_id=v.course_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 '> " +
             "<if test= 'sTime != null '> " +
             "       and DATE(o.create_time) &gt;= DATE(#{sTime})\n" +
             "       and DATE(o.create_time) &gt;= DATE(#{sTime})\n" +
             "</if>\n" +
             "</if>\n" +
             "<if test='eTime != null '> " +
             "<if test='eTime != null '> " +
             "      and DATE(o.create_time) &lt;= DATE(#{eTime})\n" +
             "      and DATE(o.create_time) &lt;= DATE(#{eTime})\n" +
             "</if>" +
             "</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" +
             "   and qu.qw_user_name like concat( #{nickName}, '%')\n" +
             "</if>" +
             "</if>" +
+            "<if test ='sendType == 1 and nickName !=null and nickName!=\"\"'>\n" +
+            "   and cu.nick_name like concat( #{nickName}, '%')\n" +
+            "</if>" +
             "<if test ='courseId !=null'> " +
             "<if test ='courseId !=null'> " +
             "     and o.course_id = #{courseId} " +
             "     and o.course_id = #{courseId} " +
             "</if>" +
             "</if>" +
             "<if test ='videoId !=null'> " +
             "<if test ='videoId !=null'> " +
             "     and o.video_id = #{videoId} " +
             "     and o.video_id = #{videoId} " +
             "</if>" +
             "</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"+
             "ORDER BY o.video_id ,DATE(o.create_time) \n"+
             "</script>"})
             "</script>"})
     List<FsCourseWatchLogStatisticsListVO> selectFsCourseWatchLogStatisticsListVO(FsCourseWatchLogStatisticsListParam param);
     List<FsCourseWatchLogStatisticsListVO> selectFsCourseWatchLogStatisticsListVO(FsCourseWatchLogStatisticsListParam param);

+ 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 pageNum;
     private Long pageSize;
     private Long pageSize;
+
+    private Integer sendType; //归属发送方式:1 个微  2 企微
 }
 }

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

@@ -0,0 +1,13 @@
+package com.fs.course.param;
+
+import com.fs.his.param.BaseParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FsFirstDiagnosisListUParam extends BaseParam {
+    private Long userId;
+
+    private Integer doctorStatus;
+}

+ 11 - 0
fs-service/src/main/java/com/fs/course/param/FsInquiryPatientInfoUParam.java

@@ -0,0 +1,11 @@
+package com.fs.course.param;
+
+import com.fs.his.param.BaseParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FsInquiryPatientInfoUParam extends BaseParam {
+    private Long userId;
+}

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

@@ -414,7 +414,7 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
             log.error("key中id为S:{}", videoDuration);
             log.error("key中id为S:{}", videoDuration);
         }
         }
 
 
-        
+
         if (videoDuration==null){
         if (videoDuration==null){
             FsUserCourseVideo video = courseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
             FsUserCourseVideo video = courseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
             videoDuration=video.getDuration();
             videoDuration=video.getDuration();
@@ -957,7 +957,16 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
     public Long getVideoDuration(Long videoId){
     public Long getVideoDuration(Long videoId){
         //将视频时长也存到redis
         //将视频时长也存到redis
         String videoRedisKey = "h5user:video:duration:" + videoId;
         String videoRedisKey = "h5user:video:duration:" + videoId;
-        Long videoDuration = redisCache.getCacheObject(videoRedisKey);
+        Long videoDuration=0L;
+        try {
+            videoDuration = redisCache.getCacheObject(videoRedisKey);
+        }catch (Exception e){
+            String string = redisCache.getCacheObject(videoRedisKey);
+            videoDuration=Long.parseLong(string);
+            log.error("key中id为S:{}", videoDuration);
+        }
+
+
         if (videoDuration==null){
         if (videoDuration==null){
             FsUserCourseVideo video = courseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
             FsUserCourseVideo video = courseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
             videoDuration=video.getDuration();
             videoDuration=video.getDuration();

+ 69 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -16,6 +16,7 @@ import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.company.constant.CompanyTrafficConstants;
 import com.fs.company.domain.Company;
 import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyMoneyLogs;
 import com.fs.company.domain.CompanyMoneyLogs;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.domain.CompanyUser;
@@ -46,6 +47,7 @@ import com.fs.his.param.WxSendRedPacketParam;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.service.IFsUserWxService;
 import com.fs.his.service.IFsUserWxService;
+import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.qw.domain.QwCompany;
 import com.fs.qw.domain.QwCompany;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwExternalContact;
@@ -73,6 +75,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
@@ -214,6 +217,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     @Autowired
     private FsCourseAnswerLogsMapper courseAnswerLogsMapper;
     private FsCourseAnswerLogsMapper courseAnswerLogsMapper;
 
 
+    @Autowired
+    ConfigUtil configUtil;
+
 
 
     /**
     /**
      * 查询课堂视频
      * 查询课堂视频
@@ -779,6 +785,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 logger.error("zyp \n【缓冲值空】参数: {}",param);
                 logger.error("zyp \n【缓冲值空】参数: {}",param);
                 return R.error("缓冲值空");
                 return R.error("缓冲值空");
             }
             }
+
             FsCourseTrafficLog trafficLog = new FsCourseTrafficLog();
             FsCourseTrafficLog trafficLog = new FsCourseTrafficLog();
             trafficLog.setQwExternalContactId(param.getQwExternalId());
             trafficLog.setQwExternalContactId(param.getQwExternalId());
             trafficLog.setCreateTime(new Date());
             trafficLog.setCreateTime(new Date());
@@ -788,6 +795,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             if (video == null) {
             if (video == null) {
                 return R.error("视频不存在");
                 return R.error("视频不存在");
             }
             }
+            Company company = companyMapper.selectCompanyById(param.getCompanyId());
+            if (company==null){
+                return R.error("公司不存在");
+            }
 
 
             // 计算流量
             // 计算流量
             BigDecimal result = param.getBufferRate().divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
             BigDecimal result = param.getBufferRate().divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
@@ -801,6 +812,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 //                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
 //                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
                 fsCourseTrafficLogMapper.insertOrUpdateTrafficLog(trafficLog);
                 fsCourseTrafficLogMapper.insertOrUpdateTrafficLog(trafficLog);
             }
             }
+            //扣除流量
+            asyncDeductTraffic(company, roundedResult);
         } catch (Exception e) {
         } catch (Exception e) {
             e.printStackTrace();
             e.printStackTrace();
             // 打印参数param和异常信息
             // 打印参数param和异常信息
@@ -810,6 +823,52 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         return R.ok();
         return R.ok();
     }
     }
 
 
+    @Async
+    public void asyncDeductTraffic(Company company, Long traffic) {
+        try {
+            // 扣除流量
+            Long remainingTraffic = updateRedisCache(company, traffic);
+
+            if ("1".equals(configUtil.generateConfigByKey("watch.course.config").getString("doNotPlay")) && remainingTraffic <= 0) {
+                logger.warn("公司ID: {} 流量不足,当前剩余: {}", company.getCompanyId(), remainingTraffic);
+                throw new Exception("流量不足");
+            }
+
+            logger.info("异步扣除流量成功 - 公司ID: {}, 扣除流量: {}, 剩余流量: {}",
+                    company.getCompanyId(), traffic, remainingTraffic);
+        } catch (Exception e) {
+            logger.error("异步扣除流量失败 - 公司ID: {}, 扣除流量: {}, 错误信息: {}",
+                    company.getCompanyId(), traffic, e.getMessage(), e);
+        }
+    }
+
+    //
+    private Long updateRedisCache(Company company, Long traffic) throws Exception {
+        // 分布式扣除流量
+        String companyKey = CompanyTrafficConstants.CACHE_KEY + ":" + company.getDeptId() + ":" + company.getCompanyId();
+        String deptKey = CompanyTrafficConstants.CACHE_KEY + ":" + company.getCompanyId();
+        String lockKey = companyKey + ":lock";
+        //销售公司剩余流量
+        Long companyTraffic = redisCache.getCacheObject(companyKey);
+        if(companyTraffic == null || companyTraffic<0){
+            return companyTraffic == null?0:companyTraffic;
+        }
+        try {
+            if (redisCache.setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS)) {
+                try {
+                   companyTraffic = redisCache.decr(companyKey, traffic);
+                   redisCache.decr(deptKey, traffic);
+                } finally {
+                    redisCache.deleteObject(lockKey); // 释放锁
+                }
+            }
+        } catch (Exception e) {
+            logger.error("【更新Redis缓存失败】企业ID: {}, 流量: {}, 错误信息:{}", company.getCompanyId(), traffic, e.getMessage(), e);
+            throw e;
+        }
+        return companyTraffic;
+    }
+
 
 
     @Override
     @Override
     public R getIntegralByH5Video(FsUserCourseVideoFinishUParam param) {
     public R getIntegralByH5Video(FsUserCourseVideoFinishUParam param) {
@@ -2512,11 +2571,21 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoIdAndUserId(videoId,userId);
         FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoIdAndUserId(videoId,userId);
 
 
         BeanCopyUtils.copy(courseVideo,fsUserCourseVideoQVO);
         BeanCopyUtils.copy(courseVideo,fsUserCourseVideoQVO);
+        if(courseVideo != null && courseVideo.getRedPacketMoney() != null){
+            fsUserCourseVideoQVO.setRedPacketMoney(courseVideo.getRedPacketMoney().toString());
+        }
 
 
         if (StringUtils.isNotEmpty(courseVideo.getQuestionBankId())){
         if (StringUtils.isNotEmpty(courseVideo.getQuestionBankId())){
             List<FsCourseQuestionBank> fsCourseQuestionBanks = courseQuestionBankMapper.selectFsCourseQuestionBankByIdVO(courseVideo.getQuestionBankId().split(","));
             List<FsCourseQuestionBank> fsCourseQuestionBanks = courseQuestionBankMapper.selectFsCourseQuestionBankByIdVO(courseVideo.getQuestionBankId().split(","));
             fsUserCourseVideoQVO.setQuestionBankList(fsCourseQuestionBanks);
             fsUserCourseVideoQVO.setQuestionBankList(fsCourseQuestionBanks);
         }
         }
+
+        //返回课程关联的拍商品
+        if(courseVideo.getIsProduct() != null && courseVideo.getIsProduct() == 1 && courseVideo.getProductId() != null){
+            FsCourseProduct courseProduct = courseProductMapper.selectFsCourseProductById(courseVideo.getProductId());
+            List<FsCourseProduct> courseProducts = Arrays.asList(courseProduct);
+            fsUserCourseVideoQVO.setCourseProducts(courseProducts);
+        }
         return fsUserCourseVideoQVO;
         return fsUserCourseVideoQVO;
     }
     }
 
 

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

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

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

@@ -0,0 +1,77 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class FsFirstDiagnosisListUVO {
+    /** 主键 */
+    private Long id;
+    /** 患者姓名 */
+    @Excel(name = "患者姓名")
+    private String patientName;
+
+    /** 年龄 */
+    @Excel(name = "年龄")
+    private String age;
+
+    /** 0-未知 1-男性 2-女性 */
+    @Excel(name = "0-未知 1-男性 2-女性")
+    private Long gender;
+
+    /** 电话 */
+    @Excel(name = "电话")
+    private String phone;
+
+    /** 身体状况 */
+    @Excel(name = "身体状况")
+    private String physicalCondition;
+
+    /** 日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "日期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date dateTime;
+
+    /** 出版诊断 */
+    @Excel(name = "出版诊断")
+    private String firstDiagnosis;
+
+    /** 医生id */
+    @Excel(name = "医生id")
+    private Long doctorId;
+
+    /** 医生名称 */
+    @Excel(name = "医生名称")
+    private String doctorName;
+
+    /** 职称 */
+    @Excel(name = "职称")
+    private String doctorDep;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 医生证号 */
+    @Excel(name = "医生证号")
+    private String doctorCertificate;
+
+    /** 医生是否填写:0-未填写 1-已填写 */
+    private Integer doctorStatus;
+
+    /** 用户是否答复:0-未答复 1-已答复 */
+    private Integer userStatus;
+
+    private Long qwUserId;
+
+    /**
+     * 销售名称
+     */
+    private String qwUserName;
+
+    //医生签名
+    private String signUrl;
+}

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

@@ -0,0 +1,113 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class FsInquiryPatientInfoListUVO {
+
+    private Long id;
+
+    private String patientName;
+
+    /** 出生年月 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "出生年月", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date birthday;
+
+    /** 性别 */
+    @Excel(name = "性别")
+    private Integer sex;
+
+
+
+    /** 手机号 */
+    @Excel(name = "手机号")
+    private String mobile;
+
+    private String companyUserName;
+
+    /**
+     * 患者id
+     */
+    private Long patientId;
+
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+    /**
+     * 患者会员id
+     */
+    private Long userId;
+    /**
+     * 问诊订单id
+     */
+    private Long inquiryOrderId;
+    /**
+     * 课程id
+     */
+    private Long courseId;
+
+    /**
+     * 就诊状态 1-初诊 2-复诊
+     */
+    private Integer diagnosisStatus;
+
+    /**
+     * 客户标签
+     */
+    private String tag;
+
+    /**
+     * 课程/档期
+     */
+    private String courseName;
+
+    /**
+     * 患者病情主诉
+     */
+    private String patientCondition;
+
+    /**
+     * 部门负责人
+     */
+    private String deptManager;
+
+    /**
+     * 医生建议及处置
+     */
+    private String doctorAdviceJson;
+
+    /**
+     * 禁忌
+     */
+    private String taboo;
+    /**
+     * 客户需求
+     */
+    private String customerRequire;
+
+    /**
+     * 职业医生
+     */
+    private String professionalDoctor;
+
+    /**
+     * 助理医生
+     */
+    private String assistantDoctor;
+
+    /**
+     * 预约时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date subTime;
+
+    private Long subDoctorId;
+
+    private String subDoctorName;
+}

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

@@ -479,8 +479,8 @@ public class DfOrderServiceImpl implements IErpOrderService
             orderPayMethod = 1;
             orderPayMethod = 1;
         } else { // 如果是线上付款
         } else { // 如果是线上付款
             orderPayMethod = 2;
             orderPayMethod = 2;
-            // 货到付款金额 = 物流代收金额-优惠金额
-            vo.setCollectingMoney(fsStoreOrder.getPayDelivery().subtract(couponPrice).doubleValue());
+            // 货到付款金额 = 订单剩余支付金额
+            vo.setCollectingMoney(fsStoreOrder.getPayRemain().doubleValue());
             vo.setCollectionCardNumber(config.getMonthlyCard()); // 就是月结账号
             vo.setCollectionCardNumber(config.getMonthlyCard()); // 就是月结账号
         }
         }
         //订单付款方式 1:在线支付 2:货到付款
         //订单付款方式 1:在线支付 2:货到付款

+ 96 - 0
fs-service/src/main/java/com/fs/fastGpt/domain/FastGptChatReplaceText.java

@@ -0,0 +1,96 @@
+package com.fs.fastGpt.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 违规词语对象 fastgpt_chat_replace_words
+ *
+ * @author fs
+ * @date 2025-01-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FastGptChatReplaceText extends BaseEntity{
+
+    /** id */
+    private Long id;
+
+    /** 类型 */
+    @Excel(name = "类型")
+    private Integer type;
+
+    /** 原来的文本 */
+    @Excel(name = "原来的文本")
+    private String content;
+
+    /** 变更后的文本 */
+    @Excel(name = "变更后的文本")
+    private String changeCount;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Integer status;
+
+    /** 排序 */
+    @Excel(name = "排序")
+    private Long sort;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setType(Integer type)
+    {
+        this.type = type;
+    }
+
+    public Integer getType()
+    {
+        return type;
+    }
+    public void setContent(String content)
+    {
+        this.content = content;
+    }
+
+    public String getContent()
+    {
+        return content;
+    }
+    public void setChangeCount(String changeCount)
+    {
+        this.changeCount = changeCount;
+    }
+
+    public String getChangeCount()
+    {
+        return changeCount;
+    }
+    public void setStatus(Integer status)
+    {
+        this.status = status;
+    }
+
+    public Integer getStatus()
+    {
+        return status;
+    }
+    public void setSort(Long sort)
+    {
+        this.sort = sort;
+    }
+
+    public Long getSort()
+    {
+        return sort;
+    }
+
+}

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

@@ -63,4 +63,6 @@ public class FastGptRole extends BaseEntity
     private String contactInfo;
     private String contactInfo;
 
 
     private String channelType;
     private String channelType;
+
+    private Integer logistics;
 }
 }

+ 68 - 0
fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptChatReplaceTextMapper.java

@@ -0,0 +1,68 @@
+package com.fs.fastGpt.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.fastGpt.domain.FastGptChatReplaceText;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 易错词语Mapper接口
+ *
+ * @author fs
+ * @date 2025-01-18
+ */
+public interface FastGptChatReplaceTextMapper extends BaseMapper<FastGptChatReplaceText>{
+    /**
+     * 查询易错词语
+     *
+     * @param id 易错词语主键
+     * @return 易错词语
+     */
+    FastGptChatReplaceText selectFastGptChatReplaceTextById(Long id);
+
+    /**
+     * 查询易错词语列表
+     *
+     * @param fastGptChatReplaceText 易错词语
+     * @return 易错词语集合
+     */
+    List<FastGptChatReplaceText> selectFastGptChatReplaceTextList(FastGptChatReplaceText fastGptChatReplaceText);
+
+    /**
+     * 新增易错词语
+     *
+     * @param fastGptChatReplaceText 易错词语
+     * @return 结果
+     */
+    int insertFastGptChatReplaceText(FastGptChatReplaceText fastGptChatReplaceText);
+
+    /**
+     * 修改易错词语
+     *
+     * @param fastGptChatReplaceText 易错词语
+     * @return 结果
+     */
+    int updateFastGptChatReplaceText(FastGptChatReplaceText fastGptChatReplaceText);
+
+    /**
+     * 删除易错词语
+     *
+     * @param id 易错词语主键
+     * @return 结果
+     */
+    int deleteFastGptChatReplaceTextById(Long id);
+
+    /**
+     * 批量删除易错词语
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFastGptChatReplaceTextByIds(Long[] ids);
+
+
+    @Select("select * from fastgpt_chat_replace_words where `status`=1" )
+    List<FastGptChatReplaceText> selectAllFastGptChatReplaceText();
+
+}

+ 10 - 0
fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptRoleMapper.java

@@ -3,7 +3,9 @@ package com.fs.fastGpt.mapper;
 import java.util.List;
 import java.util.List;
 import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.vo.FastGptRoleVO;
 import com.fs.fastGpt.vo.FastGptRoleVO;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 import org.apache.ibatis.annotations.Update;
 
 
@@ -88,4 +90,12 @@ public interface FastGptRoleMapper
     List<OptionsVO> selectFastGptRoleType();
     List<OptionsVO> selectFastGptRoleType();
     @Select("select r.role_id, r.role_name,t.contact_info,r.company_id, r.create_time, r.update_time, r.role_type, r.mode_config_json, r.mode, r.kf_id, r.kf_url, r.avatar, r.kf_media_id,r.reminder_words, r.bind_corp_id,r.channel_type from fastgpt_role r LEFT JOIN fastgpt_role_type t on t.id =r.role_type where role_id = #{roleId}")
     @Select("select r.role_id, r.role_name,t.contact_info,r.company_id, r.create_time, r.update_time, r.role_type, r.mode_config_json, r.mode, r.kf_id, r.kf_url, r.avatar, r.kf_media_id,r.reminder_words, r.bind_corp_id,r.channel_type from fastgpt_role r LEFT JOIN fastgpt_role_type t on t.id =r.role_type where role_id = #{roleId}")
     FastGptRole selectFastGptRoleTypeByRoleId(Long roleId);
     FastGptRole selectFastGptRoleTypeByRoleId(Long roleId);
+
+    List<FastGptRole> selectFastGptRoleByRoleIds(@Param("roleIds") List<Long> roleIds);
+
+    List<String> selectFastGptRoleRoleIdsByAppKey(@Param("appKey") String appKey);
+
+    List<FastgptEventLogTotalVo> selectFastGptRoleAppKeyList();
+
+
 }
 }

+ 93 - 0
fs-service/src/main/java/com/fs/fastGpt/mapper/FastgptEventLogTotalMapper.java

@@ -0,0 +1,93 @@
+package com.fs.fastGpt.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.fastGpt.domain.FastGptEventTokenLog;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * ai事件埋点统计Mapper接口
+ * 
+ * @author fs
+ * @date 2025-06-26
+ */
+public interface FastgptEventLogTotalMapper extends BaseMapper<FastgptEventLogTotal>{
+    /**
+     * 查询ai事件埋点统计
+     * 
+     * @param id ai事件埋点统计主键
+     * @return ai事件埋点统计
+     */
+    FastgptEventLogTotal selectFastgptEventLogTotalById(Long id);
+
+    /**
+     * 查询ai事件埋点统计列表
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return ai事件埋点统计集合
+     */
+    List<FastgptEventLogTotal> selectFastgptEventLogTotalList(FastgptEventLogTotal fastgptEventLogTotal);
+
+    /**
+     * 新增ai事件埋点统计
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return 结果
+     */
+    int insertFastgptEventLogTotal(FastgptEventLogTotal fastgptEventLogTotal);
+
+    /**
+     * 修改ai事件埋点统计
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return 结果
+     */
+    int updateFastgptEventLogTotal(FastgptEventLogTotal fastgptEventLogTotal);
+
+    /**
+     * 删除ai事件埋点统计
+     * 
+     * @param id ai事件埋点统计主键
+     * @return 结果
+     */
+    int deleteFastgptEventLogTotalById(Long id);
+
+    /**
+     * 批量删除ai事件埋点统计
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFastgptEventLogTotalByIds(Long[] ids);
+
+    List<FastgptEventLogTotal> selectFastgptEventLogTotalInfoList(FastgptEventLogTotal logTotal);
+
+    FastgptEventLogTotal selectFastgptEventLogTotalByRoleIdAndType(FastgptEventLogTotal total);
+
+    List<FastgptEventLogTotal> selectFastgptEventLogTotalVoInfoList(FastgptEventLogTotalVo fastgptEventLogTotal);
+
+    List<FastGptEventTokenLog> selectFastgptEventTokenLogTotalList(FastGptEventTokenLog fastGptEventTokenLog);
+
+    FastgptEventLogTotal selectFastgptEventTokenLogTotalByRoleIdAndType(FastGptEventTokenLog tokenLog);
+
+    /**
+     * 批量插入ai事件埋点统计
+     *
+     * @param fastgptEventLogTotalList ai事件埋点统计列表
+     * @return 结果
+     */
+    int insertFastgptEventLogTotalBatch(@Param("list") List<FastgptEventLogTotal> fastgptEventLogTotalList);
+
+    /**
+     * 批量更新ai事件埋点统计
+     *
+     * @param fastgptEventLogTotalList ai事件埋点统计列表
+     * @return 结果
+     */
+    int updateFastgptEventLogTotalBatch(@Param("list") List<FastgptEventLogTotal> fastgptEventLogTotalList);
+
+    List<FastgptEventLogTotalVo> selectFastgptEventLogTotalListByStatTime(@Param("dateTime") String dateTime);
+}

+ 76 - 0
fs-service/src/main/java/com/fs/fastGpt/param/FastgptEventLogTotalParam.java

@@ -0,0 +1,76 @@
+package com.fs.fastGpt.param;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * ai事件埋点统计对象 fastgpt_event_log_total
+ *
+ * @author fs
+ * @date 2025-06-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FastgptEventLogTotalParam extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 角色id */
+    //@Excel(name = "角色id")
+    private Long roleId;
+
+    @Excel(name = "角色名称")
+    private Long roleName;
+
+    /** 数量 */
+    @Excel(name = "数量")
+    private Long count;
+
+    /** 日志类型 */
+    @Excel(name = "日志类型")
+    private Integer type;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 公司用户id */
+    @Excel(name = "公司用户id")
+    private Long companyUserId;
+
+    /** 企微用户id */
+    @Excel(name = "企微用户id")
+    private Long qwUserId;
+
+    @Excel(name = "日志生成时间")
+    private String statTime;
+
+    /**
+     * 员工列表
+     */
+    private List<String> userIds;
+
+    private String qwUserIds;
+
+    private Date createTime;
+
+    private Integer pageNum;
+    private Integer pageSize;
+
+
+    private String beginTime;
+
+
+    private String endTime;
+
+    private String appKey;
+
+
+
+}

+ 62 - 0
fs-service/src/main/java/com/fs/fastGpt/service/IFastGptChatReplaceTextService.java

@@ -0,0 +1,62 @@
+package com.fs.fastGpt.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.fastGpt.domain.FastGptChatReplaceText;
+
+import java.util.List;
+
+/**
+ * 易错词语Service接口
+ * 
+ * @author fs
+ * @date 2025-01-18
+ */
+public interface IFastGptChatReplaceTextService extends IService<FastGptChatReplaceText>{
+    /**
+     * 查询易错词语
+     * 
+     * @param id 易错词语主键
+     * @return 易错词语
+     */
+    FastGptChatReplaceText selectFastGptChatReplaceTextById(Long id);
+
+    /**
+     * 查询易错词语列表
+     * 
+     * @param fastGptChatReplaceText 易错词语
+     * @return 易错词语集合
+     */
+    List<FastGptChatReplaceText> selectFastGptChatReplaceTextList(FastGptChatReplaceText fastGptChatReplaceText);
+
+    /**
+     * 新增易错词语
+     * 
+     * @param fastGptChatReplaceText 易错词语
+     * @return 结果
+     */
+    int insertFastGptChatReplaceText(FastGptChatReplaceText fastGptChatReplaceText);
+
+    /**
+     * 修改易错词语
+     * 
+     * @param fastGptChatReplaceText 易错词语
+     * @return 结果
+     */
+    int updateFastGptChatReplaceText(FastGptChatReplaceText fastGptChatReplaceText);
+
+    /**
+     * 批量删除易错词语
+     * 
+     * @param ids 需要删除的易错词语主键集合
+     * @return 结果
+     */
+    int deleteFastGptChatReplaceTextByIds(Long[] ids);
+
+    /**
+     * 删除易错词语信息
+     * 
+     * @param id 易错词语主键
+     * @return 结果
+     */
+    int deleteFastGptChatReplaceTextById(Long id);
+}

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

@@ -4,6 +4,7 @@ import java.util.List;
 
 
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.domain.FastGptRole;
+import com.fs.fastGpt.vo.FastGptRoleDataVO;
 import com.fs.fastGpt.vo.FastGptRoleVO;
 import com.fs.fastGpt.vo.FastGptRoleVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
 
 
@@ -73,4 +74,11 @@ public interface IFastGptRoleService
     List<OptionsVO> selectFastGptRoleType();
     List<OptionsVO> selectFastGptRoleType();
 
 
     public FastGptRole selectFastGptRoleTypeByRoleId(Long roleId);
     public FastGptRole selectFastGptRoleTypeByRoleId(Long roleId);
+
+    List<String> selectFastGptRoleRoleIdsByAppKey(String appKey);
+
+    List<FastGptRole> selectFastGptRoleByRoleIds(List<Long> roleIds);
+
+    List<FastGptRoleDataVO> selectFastGptRoleAppKeyList();
+
 }
 }

+ 94 - 0
fs-service/src/main/java/com/fs/fastGpt/service/IFastgptEventLogTotalService.java

@@ -0,0 +1,94 @@
+package com.fs.fastGpt.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.fastGpt.domain.FastGptEventTokenLog;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
+
+import java.util.List;
+
+/**
+ * ai事件埋点统计Service接口
+ * 
+ * @author fs
+ * @date 2025-06-26
+ */
+public interface IFastgptEventLogTotalService extends IService<FastgptEventLogTotal>{
+    /**
+     * 查询ai事件埋点统计
+     * 
+     * @param id ai事件埋点统计主键
+     * @return ai事件埋点统计
+     */
+    FastgptEventLogTotal selectFastgptEventLogTotalById(Long id);
+
+    /**
+     * 查询ai事件埋点统计列表
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return ai事件埋点统计集合
+     */
+    List<FastgptEventLogTotal> selectFastgptEventLogTotalList(FastgptEventLogTotal fastgptEventLogTotal);
+
+    /**
+     * 新增ai事件埋点统计
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return 结果
+     */
+    int insertFastgptEventLogTotal(FastgptEventLogTotal fastgptEventLogTotal);
+
+    /**
+     * 修改ai事件埋点统计
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return 结果
+     */
+    int updateFastgptEventLogTotal(FastgptEventLogTotal fastgptEventLogTotal);
+
+    /**
+     * 批量删除ai事件埋点统计
+     * 
+     * @param ids 需要删除的ai事件埋点统计主键集合
+     * @return 结果
+     */
+    int deleteFastgptEventLogTotalByIds(Long[] ids);
+
+    /**
+     * 删除ai事件埋点统计信息
+     * 
+     * @param id ai事件埋点统计主键
+     * @return 结果
+     */
+    int deleteFastgptEventLogTotalById(Long id);
+
+    List<FastgptEventLogTotal> selectFastgptEventLogTotalInfoList(FastgptEventLogTotal logTotal);
+
+    FastgptEventLogTotal selectFastgptEventLogTotalByRoleIdAndType(FastgptEventLogTotal total);
+
+    List<FastgptEventLogTotalVo> selectFastgptEventLogTotalVoInfoList(FastgptEventLogTotalVo fastgptEventLogTotal);
+
+    List<FastGptEventTokenLog> selectFastgptEventTokenLogTotalList(FastGptEventTokenLog fastGptEventTokenLog);
+
+    FastgptEventLogTotal selectFastgptEventTokenLogTotalByRoleIdAndType(FastGptEventTokenLog tokenLog);
+
+    FastgptEventLogTotalVo totalFastgptEventLog(List<FastgptEventLogTotalVo> list);
+
+    /**
+     * 批量新增ai事件埋点统计
+     *
+     * @param fastgptEventLogTotalList ai事件埋点统计列表
+     * @return 结果
+     */
+    int insertFastgptEventLogTotalBatch(List<FastgptEventLogTotal> fastgptEventLogTotalList);
+
+    /**
+     * 批量修改ai事件埋点统计
+     *
+     * @param fastgptEventLogTotalList ai事件埋点统计列表
+     * @return 结果
+     */
+    int updateFastgptEventLogTotalBatch(List<FastgptEventLogTotal> fastgptEventLogTotalList);
+
+    List<FastgptEventLogTotalVo> selectFastgptEventLogTotalListByStatTime(String dateTime);
+}

+ 101 - 30
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -54,6 +54,7 @@ import com.fs.qwHookApi.vo.QwHookMsgVO;
 import com.fs.qwHookApi.vo.QwHookVO;
 import com.fs.qwHookApi.vo.QwHookVO;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.QwSopLogsMapper;
+import com.fs.utils.SensitiveDataUtils;
 import com.fs.voice.utils.StringUtil;
 import com.fs.voice.utils.StringUtil;
 import com.fs.wxwork.dto.*;
 import com.fs.wxwork.dto.*;
 import com.fs.wxwork.service.WxWorkService;
 import com.fs.wxwork.service.WxWorkService;
@@ -61,6 +62,7 @@ import com.vdurmont.emoji.EmojiParser;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.Nullable;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Async;
@@ -156,6 +158,8 @@ public class AiHookServiceImpl implements AiHookService {
     private IFsExpressService expressService;
     private IFsExpressService expressService;
     @Autowired
     @Autowired
     private CompanyConfigMapper companyConfigMapper;
     private CompanyConfigMapper companyConfigMapper;
+    @Autowired
+    private IFastGptChatReplaceTextService fastGptChatReplaceTextService;
 
 
     /** Ai半小时未回复提醒 **/
     /** Ai半小时未回复提醒 **/
     /**
     /**
@@ -363,38 +367,38 @@ public class AiHookServiceImpl implements AiHookService {
         if (qwContent.contains("我已经添加了你")){
         if (qwContent.contains("我已经添加了你")){
             return R.ok();
             return R.ok();
         }
         }
-        System.out.println(qwUserId);
+        log.info("数据:{}", qwUserId);
         QwUser user = qwUserMapper.selectQwUserById(qwUserId);
         QwUser user = qwUserMapper.selectQwUserById(qwUserId);
         //查询接收人
         //查询接收人
         if(user==null){
         if(user==null){
-            System.out.println("查询接收人为空");
+            log.error("查询接收人为空");
             return R.ok();
             return R.ok();
         }
         }
         if(user.getFastGptRoleId()==null){
         if(user.getFastGptRoleId()==null){
-            System.out.println("未绑定角色");
+            log.error("未绑定角色");
             return R.ok();
             return R.ok();
         }
         }
         Long serverId = user.getServerId();
         Long serverId = user.getServerId();
-        System.out.println("服务器id"+serverId);
+        log.info("服务器id"+serverId);
         if (serverId == null) {
         if (serverId == null) {
-            System.out.println("服务id为空");
+            log.error("服务id为空");
             return R.ok();
             return R.ok();
         }
         }
         FastGptRole role=roleService.selectFastGptRoleTypeByRoleId(user.getFastGptRoleId());
         FastGptRole role=roleService.selectFastGptRoleTypeByRoleId(user.getFastGptRoleId());
         //没用ai角色跳过
         //没用ai角色跳过
         if(role==null){
         if(role==null){
-            System.out.println("没用ai角色跳过");
+            log.error("没用ai角色跳过");
             return R.ok();
             return R.ok();
         }
         }
         String modeConfig=role.getModeConfigJson();
         String modeConfig=role.getModeConfigJson();
         //key不为空
         //key不为空
         if(StringUtils.isEmpty(modeConfig)){
         if(StringUtils.isEmpty(modeConfig)){
-            System.out.println("没有aiKey");
+            log.error("没有aiKey");
             return R.ok();
             return R.ok();
         }
         }
         ModeConfig config=JSONUtil.toBean(modeConfig,ModeConfig.class);
         ModeConfig config=JSONUtil.toBean(modeConfig,ModeConfig.class);
         if(StringUtils.isEmpty(config.getAPPKey())){
         if(StringUtils.isEmpty(config.getAPPKey())){
-            System.out.println("没有aiKey");
+            log.error("没有aiKey");
             return R.ok();
             return R.ok();
         }
         }
         WxWorkVid2UserIdDTO wxWorkVid2UserIdDTO = new WxWorkVid2UserIdDTO();
         WxWorkVid2UserIdDTO wxWorkVid2UserIdDTO = new WxWorkVid2UserIdDTO();
@@ -404,14 +408,14 @@ public class AiHookServiceImpl implements AiHookService {
         List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
         List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
         if (data==null|| data.isEmpty()){
         if (data==null|| data.isEmpty()){
 
 
-            System.out.println("未获取到extId"+wxWorkVid2UserIdDTO);
+            log.error("未获取到extId"+wxWorkVid2UserIdDTO);
             return R.ok();
             return R.ok();
         }
         }
         com.fs.wxwork.dto.WxWorkVid2UserIdRespDTO dto = data.get(0);
         com.fs.wxwork.dto.WxWorkVid2UserIdRespDTO dto = data.get(0);
 
 
         QwExternalContact qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByExternalUserIdAndQwUserId(dto.getOpenid(), user.getCorpId(),user.getQwUserId());
         QwExternalContact qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByExternalUserIdAndQwUserId(dto.getOpenid(), user.getCorpId(),user.getQwUserId());
         if (qwExternalContacts==null){
         if (qwExternalContacts==null){
-            System.out.println("没有外部联系人");
+            log.error("没有外部联系人" + "user:" + user);
             return R.ok();
             return R.ok();
         }
         }
         if(qwExternalContacts.getType()==2){
         if(qwExternalContacts.getType()==2){
@@ -437,13 +441,21 @@ public class AiHookServiceImpl implements AiHookService {
                     }
                     }
                 }
                 }
             }else {
             }else {
-                System.out.println("不是图片"+type);
+                log.info("不是图片"+type);
             }
             }
 
 
-            String contentEmj = replaceWxEmo(qwContent);
+            //对用户处理的内容做处理
+            String maskedContent = processContent(qwContent);
+            String contentEmj = replaceWxEmo(maskedContent);
             if(!contentEmj.contains("表情包")){
             if(!contentEmj.contains("表情包")){
                 if(!contentEmj.isEmpty()){
                 if(!contentEmj.isEmpty()){
                     addSaveAiMsg(1,1,contentEmj,user,fastGptChatSession.getSessionId(),role.getRoleId(),qwExternalContacts,fastGptChatSession.getUserId(),null,null,null);
                     addSaveAiMsg(1,1,contentEmj,user,fastGptChatSession.getSessionId(),role.getRoleId(),qwExternalContacts,fastGptChatSession.getUserId(),null,null,null);
+                    //通过用户发送的对话去查询用户是否为新客,是就删除sop,否就不做处理
+                    cleanNewUserDialogue(user, qwExternalContacts);
+                    //用户是未回复状态
+                    if(qwExternalContacts.getIsReply() == 0){
+                        qwExternalContactMapper.updateQwExternalContactIsRePlyById(qwExternalContacts.getId());
+                    }
                 }else {
                 }else {
                     contentEmj ="用户发送表情:"+qwContent;
                     contentEmj ="用户发送表情:"+qwContent;
                     if (type==16){
                     if (type==16){
@@ -455,7 +467,7 @@ public class AiHookServiceImpl implements AiHookService {
 
 
             //判断是否转人工
             //判断是否转人工
             if (fastGptChatSession.getIsArtificial()==1){
             if (fastGptChatSession.getIsArtificial()==1){
-                System.out.println("转人工了");
+                log.error("转人工了,sessionId:" + fastGptChatSession.getSessionId());
                 return R.ok();
                 return R.ok();
             }
             }
             //获取是用户是否发送消息
             //获取是用户是否发送消息
@@ -472,22 +484,32 @@ public class AiHookServiceImpl implements AiHookService {
                     redisCache.setCacheObject("msg:" + fastGptChatSession.getSessionId(),msg+","+contentEmj,5,TimeUnit.MINUTES);
                     redisCache.setCacheObject("msg:" + fastGptChatSession.getSessionId(),msg+","+contentEmj,5,TimeUnit.MINUTES);
                 }
                 }
                 //本次跳过
                 //本次跳过
-                System.out.println("正在对话");
+                log.info("正在对话");
                 return R.ok();
                 return R.ok();
             }
             }
             //用户首次发送消息
             //用户首次发送消息
             redisCache.setCacheObject("reply:" + fastGptChatSession.getSessionId(),1,5,TimeUnit.MINUTES);
             redisCache.setCacheObject("reply:" + fastGptChatSession.getSessionId(),1,5,TimeUnit.MINUTES);
             redisCache.setCacheObject("msg:" + fastGptChatSession.getSessionId(),contentEmj,5,TimeUnit.MINUTES);
             redisCache.setCacheObject("msg:" + fastGptChatSession.getSessionId(),contentEmj,5,TimeUnit.MINUTES);
-            System.out.println("等待");
+            log.info("等待");
             R r= sendAiMsg(replyI,fastGptChatSession,role,user,qwExternalContacts.getId(),config.getAPPKey(),qwExternalContacts,sender);
             R r= sendAiMsg(replyI,fastGptChatSession,role,user,qwExternalContacts.getId(),config.getAPPKey(),qwExternalContacts,sender);
             EventLogUtils.recordEventLog(sender,1L,1,user);
             EventLogUtils.recordEventLog(sender,1L,1,user);
             EventLogUtils.recordEventLog(sender,1L,2,user);
             EventLogUtils.recordEventLog(sender,1L,2,user);
-            System.out.println(r);
+            log.info("数据:{}", r);
             //完成对话 删除消息记录
             //完成对话 删除消息记录
             redisCache.deleteObject("reply:" + fastGptChatSession.getSessionId());
             redisCache.deleteObject("reply:" + fastGptChatSession.getSessionId());
             redisCache.deleteObject("msg:" + fastGptChatSession.getSessionId());
             redisCache.deleteObject("msg:" + fastGptChatSession.getSessionId());
             if(!r.get("code").equals(200)){
             if(!r.get("code").equals(200)){
-                log.info("ai报错转人工:"+role.getRoleId()+":"+qwExternalContacts.getName());
+                //判断消息是否需要重发的依据
+               /*redisCache.setCacheObject("retry:" + fastGptChatSession.getSessionId(),1,2,TimeUnit.MINUTES);
+                redisCache.setCacheObject("retryMsg:" + fastGptChatSession.getSessionId(),contentEmj,2,TimeUnit.MINUTES);
+                Integer retryCount = redisCache.getCacheObject("retry:" + fastGptChatSession.getSessionId());
+                if(retryCount < 3){
+                    r= retrySendAiMsg(retryCount,fastGptChatSession,role,user,qwExternalContacts.getId(),config.getAPPKey(),qwExternalContacts,sender);
+                }
+                redisCache.deleteObject("retry:" + fastGptChatSession.getSessionId());
+                redisCache.deleteObject("retryMsg:" + fastGptChatSession.getSessionId());*/
+
+                log.error("ai报错转人工:"+role.getRoleId()+":"+qwExternalContacts.getName());
                 notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," ai报错转人工",qwExternalContacts.getId(),sender);
                 notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," ai报错转人工",qwExternalContacts.getId(),sender);
                 return R.ok();
                 return R.ok();
             }
             }
@@ -507,13 +529,6 @@ public class AiHookServiceImpl implements AiHookService {
             }
             }
             //存聊天记录
             //存聊天记录
             addSaveAiMsg(2,2,contentKh,user,fastGptChatSession.getSessionId(),role.getRoleId(),qwExternalContacts,fastGptChatSession.getUserId(),result.getUsage().prompt_tokens,result.getUsage().completion_tokens,token);
             addSaveAiMsg(2,2,contentKh,user,fastGptChatSession.getSessionId(),role.getRoleId(),qwExternalContacts,fastGptChatSession.getUserId(),result.getUsage().prompt_tokens,result.getUsage().completion_tokens,token);
-            Integer replyOne = redisCache.getCacheObject("reply:" + fastGptChatSession.getSessionId());
-            if (replyOne!=null && replyOne == 1){
-                QwUser qwUser = qwUserService.selectQwUserById(fastGptChatSession.getQwUserId());
-                if (ObjectUtils.isNotEmpty(qwUser)&&ObjectUtils.isNotEmpty(qwUser.getIpadStatus())&&qwUser.getIpadStatus() == 1){
-                    addQwAutoTags(qwUser,qwExternalContacts.getUserId(),qwExternalContacts.getExternalUserId());
-                }
-            }
             if (!content.isEmpty()){
             if (!content.isEmpty()){
                 addSaveAiMsg(1,2,content,user,fastGptChatSession.getSessionId(),role.getRoleId(),qwExternalContacts,fastGptChatSession.getUserId(),null,null,null);
                 addSaveAiMsg(1,2,content,user,fastGptChatSession.getSessionId(),role.getRoleId(),qwExternalContacts,fastGptChatSession.getUserId(),null,null,null);
                 //从fastgpt_chat_artificial_words表中查询所有转人工文本
                 //从fastgpt_chat_artificial_words表中查询所有转人工文本
@@ -524,6 +539,12 @@ public class AiHookServiceImpl implements AiHookService {
                     notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," 触发关键词",qwExternalContacts.getId(),sender);
                     notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," 触发关键词",qwExternalContacts.getId(),sender);
                     return R.ok();
                     return R.ok();
                 }
                 }
+                //ai回复文字长度大于500就转人工
+                if(content.length() > 500){
+                    log.error("回复长度异常:"+role.getRoleId()+":"+qwExternalContacts.getName());
+                    notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," 回复长度异常",qwExternalContacts.getId(),sender);
+                    return R.ok();
+                }
                 if (result.isLongText()){
                 if (result.isLongText()){
                     //新增用户信息
                     //新增用户信息
                     addUserInfo(contentKh, qwExternalContacts.getId(),fastGptChatSession);
                     addUserInfo(contentKh, qwExternalContacts.getId(),fastGptChatSession);
@@ -569,7 +590,7 @@ public class AiHookServiceImpl implements AiHookService {
 
 
 
 
             if (result.isArtificial()){
             if (result.isArtificial()){
-                log.info("ai请求人工:"+role.getRoleId()+":"+qwExternalContacts.getName());
+                log.error("ai请求人工:"+role.getRoleId()+":"+qwExternalContacts.getName());
                 notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," ai请求人工协助",qwExternalContacts.getId(),sender);
                 notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," ai请求人工协助",qwExternalContacts.getId(),sender);
             }
             }
         }
         }
@@ -577,6 +598,34 @@ public class AiHookServiceImpl implements AiHookService {
         return R.ok();
         return R.ok();
     }
     }
 
 
+    /**
+     * 通过用户发送的对话去查询用户是否为新客,是就删除sop,否就不做处理
+     * @param user
+     * @param qwExternalContacts
+     */
+    private void cleanNewUserDialogue(QwUser user, QwExternalContact qwExternalContacts) {
+        String redisKey = "qwNewChat:" + user.getQwUserId() + ":" + user.getCorpId() + ":" + qwExternalContacts.getExternalUserId();
+        String key  = (String) redisCache.getCacheObject(redisKey);
+        if(!StringUtil.strIsNullOrEmpty(key)){
+            try {
+                QwSopLogs qwSopLogs = new QwSopLogs();
+                qwSopLogs.setQwUserid(user.getQwUserId());
+                qwSopLogs.setCorpId(user.getCorpId());
+                qwSopLogs.setExternalUserId(qwExternalContacts.getExternalUserId());
+                qwSopLogs.setSendStatus(3L);
+                qwSopLogs.setSendType(4);
+                List<QwSopLogs> qwSopLogsList = qwSopLogsMapper.selectQwSopLogsList(qwSopLogs);
+                if(qwSopLogsList != null && !qwSopLogsList.isEmpty()){
+                    qwSopLogsMapper.batchUpdateQwSopLogsNewUserById(qwSopLogsList);
+                }
+            } catch (Exception e) {
+                log.error("停用新客对话sop失败:" + redisKey + "原因:" + e);
+            }finally {
+                redisCache.deleteObject(redisKey);
+            }
+        }
+    }
+
 
 
 
 
     /**
     /**
@@ -636,7 +685,7 @@ public class AiHookServiceImpl implements AiHookService {
         Random random = new Random();
         Random random = new Random();
         FastGptKeywordSend fastGptKeywordSend = keywordSendList.get(random.nextInt(keywordSendList.size()));
         FastGptKeywordSend fastGptKeywordSend = keywordSendList.get(random.nextInt(keywordSendList.size()));
         if (fastGptKeywordSend == null){
         if (fastGptKeywordSend == null){
-            System.out.println("输出为空格");
+            log.info("输出为空格");
             return;
             return;
         }
         }
         if(fastGptKeywordSend.getKeywordType() == 1L && "物流".equals(fastGptKeywordSend.getKeyword())){
         if(fastGptKeywordSend.getKeywordType() == 1L && "物流".equals(fastGptKeywordSend.getKeyword())){
@@ -662,11 +711,11 @@ public class AiHookServiceImpl implements AiHookService {
                                 fastGptChatSessionMapper.updateFastGptChatSession(fastGptChatSession);
                                 fastGptChatSessionMapper.updateFastGptChatSession(fastGptChatSession);
                                 break;
                                 break;
                             case 2:
                             case 2:
-                                sBuilder.append("您购买的 ").append(fsStoreOrder.getPackageName()).append(" 正在准备发货,请耐心等待;\n");
-                                break;
+                                sBuilder.append("您好,您有一个包裹正在准备发货,请耐心等待;\n")
+                                        .append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
                             case 3:
                             case 3:
                                 ExpressInfoDTO expressInfo = getExpress(fsStoreOrder.getOrderId());
                                 ExpressInfoDTO expressInfo = getExpress(fsStoreOrder.getOrderId());
-                                sBuilder.append("您购买的 ").append(fsStoreOrder.getPackageName());
+                                sBuilder.append("您购买的有一个包裹 ");
                                 sBuilder.append(" 已经查询到了,正在配送中了。\n");
                                 sBuilder.append(" 已经查询到了,正在配送中了。\n");
                                 if(expressInfo != null && expressInfo.getTraces() != null && !expressInfo.getTraces().isEmpty()){
                                 if(expressInfo != null && expressInfo.getTraces() != null && !expressInfo.getTraces().isEmpty()){
                                     List<TracesDTO> traces = expressInfo.getTraces();
                                     List<TracesDTO> traces = expressInfo.getTraces();
@@ -679,7 +728,7 @@ public class AiHookServiceImpl implements AiHookService {
                             case 5:
                             case 5:
                                 ExpressInfoDTO express = getExpress(fsStoreOrder.getOrderId());
                                 ExpressInfoDTO express = getExpress(fsStoreOrder.getOrderId());
                                 //你好,这边查询到您购买的XXX(购买套餐)在XXX(时间)已经送到了,送货员电话为XXX(送货员信息)
                                 //你好,这边查询到您购买的XXX(购买套餐)在XXX(时间)已经送到了,送货员电话为XXX(送货员信息)
-                                sBuilder.append("这边查询到您购买的 ").append(fsStoreOrder.getPackageName());
+                                sBuilder.append("这边查询到您有一个包裹");
                                 if(express != null && express.getTraces() != null && !express.getTraces().isEmpty()){
                                 if(express != null && express.getTraces() != null && !express.getTraces().isEmpty()){
                                     List<TracesDTO> traces = express.getTraces();
                                     List<TracesDTO> traces = express.getTraces();
                                     TracesDTO tracesDTO = traces.get(traces.size() - 1);
                                     TracesDTO tracesDTO = traces.get(traces.size() - 1);
@@ -813,6 +862,28 @@ public class AiHookServiceImpl implements AiHookService {
         return null;
         return null;
     }
     }
 
 
+    /**
+     * 处理用户的输入问题
+     * @param qwContent
+     * @return
+     */
+    private @Nullable String processContent(String qwContent) {
+        String maskedContent = SensitiveDataUtils.maskMobileNumbers(qwContent);
+        if(maskedContent != null && !maskedContent.isEmpty()){
+            FastGptChatReplaceText fastGptChatReplaceText = new FastGptChatReplaceText();
+            fastGptChatReplaceText.setStatus(1);
+            List<FastGptChatReplaceText> chatReplaceTextList = fastGptChatReplaceTextService.selectFastGptChatReplaceTextList(fastGptChatReplaceText);
+            if(chatReplaceTextList != null && !chatReplaceTextList.isEmpty()){
+                for (FastGptChatReplaceText replaceText : chatReplaceTextList) {
+                    if(maskedContent.contains(replaceText.getContent())){
+                        maskedContent = maskedContent.replace(replaceText.getContent(), replaceText.getChangeCount());
+                    }
+                }
+            }
+        }
+        return maskedContent;
+    }
+
     private void sendAiVoiceMsg(String content, Long sendId , String uuid,Long serverId,QwUser user) {
     private void sendAiVoiceMsg(String content, Long sendId , String uuid,Long serverId,QwUser user) {
         if (content == null || content.trim().isEmpty()){
         if (content == null || content.trim().isEmpty()){
             System.out.println("输出为空格");
             System.out.println("输出为空格");

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

@@ -134,13 +134,11 @@ public class FastGptChatMsgServiceImpl implements IFastGptChatMsgService
     }
     }
 
 
     @Override
     @Override
-    @DataSource(DataSourceType.CLICKHOUSE)
     public void insertFastGptEventLog(FastGptEventLog fastGptEventLog) {
     public void insertFastGptEventLog(FastGptEventLog fastGptEventLog) {
         fastGptChatMsgMapper.insertFastGptEventLog(fastGptEventLog);
         fastGptChatMsgMapper.insertFastGptEventLog(fastGptEventLog);
     }
     }
 
 
     @Override
     @Override
-    @DataSource(DataSourceType.CLICKHOUSE)
     public void insertFastGptEventTokenLog(FastGptEventTokenLog fastGptEventTokenLog) {
     public void insertFastGptEventTokenLog(FastGptEventTokenLog fastGptEventTokenLog) {
         fastGptChatMsgMapper.insertFastGptEventTokenLog(fastGptEventTokenLog);
         fastGptChatMsgMapper.insertFastGptEventTokenLog(fastGptEventTokenLog);
     }
     }

+ 93 - 0
fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptChatReplaceTextServiceImpl.java

@@ -0,0 +1,93 @@
+package com.fs.fastGpt.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.fastGpt.domain.FastGptChatReplaceText;
+import com.fs.fastGpt.mapper.FastGptChatReplaceTextMapper;
+import com.fs.fastGpt.service.IFastGptChatReplaceTextService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 易错词语Service业务层处理
+ *
+ * @author fs
+ * @date 2025-01-18
+ */
+@Service
+public class FastGptChatReplaceTextServiceImpl extends ServiceImpl<FastGptChatReplaceTextMapper, FastGptChatReplaceText> implements IFastGptChatReplaceTextService {
+
+    /**
+     * 查询易错词语
+     *
+     * @param id 易错词语主键
+     * @return 易错词语
+     */
+    @Override
+    public FastGptChatReplaceText selectFastGptChatReplaceTextById(Long id)
+    {
+        return baseMapper.selectFastGptChatReplaceTextById(id);
+    }
+
+    /**
+     * 查询易错词语列表
+     *
+     * @param fastGptChatReplaceText 易错词语
+     * @return 易错词语
+     */
+    @Override
+    public List<FastGptChatReplaceText> selectFastGptChatReplaceTextList(FastGptChatReplaceText fastGptChatReplaceText)
+    {
+        return baseMapper.selectFastGptChatReplaceTextList(fastGptChatReplaceText);
+    }
+
+    /**
+     * 新增易错词语
+     *
+     * @param fastGptChatReplaceText 易错词语
+     * @return 结果
+     */
+    @Override
+    public int insertFastGptChatReplaceText(FastGptChatReplaceText fastGptChatReplaceText)
+    {
+        fastGptChatReplaceText.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFastGptChatReplaceText(fastGptChatReplaceText);
+    }
+
+    /**
+     * 修改易错词语
+     *
+     * @param fastGptChatReplaceText 易错词语
+     * @return 结果
+     */
+    @Override
+    public int updateFastGptChatReplaceText(FastGptChatReplaceText fastGptChatReplaceText)
+    {
+        return baseMapper.updateFastGptChatReplaceText(fastGptChatReplaceText);
+    }
+
+    /**
+     * 批量删除易错词语
+     *
+     * @param ids 需要删除的易错词语主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFastGptChatReplaceTextByIds(Long[] ids)
+    {
+        return baseMapper.deleteFastGptChatReplaceTextByIds(ids);
+    }
+
+    /**
+     * 删除易错词语信息
+     *
+     * @param id 易错词语主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFastGptChatReplaceTextById(Long id)
+    {
+        return baseMapper.deleteFastGptChatReplaceTextById(id);
+    }
+}

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

@@ -3,13 +3,18 @@ package com.fs.fastGpt.service.impl;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.fastGpt.domain.FastGptRoleTag;
 import com.fs.fastGpt.domain.FastGptRoleTag;
 import com.fs.fastGpt.mapper.FastGptRoleTagMapper;
 import com.fs.fastGpt.mapper.FastGptRoleTagMapper;
+import com.fs.fastGpt.vo.FastGptRoleDataVO;
 import com.fs.fastGpt.vo.FastGptRoleVO;
 import com.fs.fastGpt.vo.FastGptRoleVO;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -171,5 +176,77 @@ public class FastGptRoleServiceImpl implements IFastGptRoleService
         return fastGptRoleMapper.selectFastGptRoleTypeByRoleId(roleId);
         return fastGptRoleMapper.selectFastGptRoleTypeByRoleId(roleId);
     }
     }
 
 
+    @Override
+    public List<String> selectFastGptRoleRoleIdsByAppKey(String appKey) {
+        return fastGptRoleMapper.selectFastGptRoleRoleIdsByAppKey(appKey);
+    }
+
+    @Override
+    public List<FastGptRole> selectFastGptRoleByRoleIds(List<Long> roleIds) {
+        return fastGptRoleMapper.selectFastGptRoleByRoleIds(roleIds);
+    }
+
+    @Override
+    public List<FastGptRoleDataVO> selectFastGptRoleAppKeyList() {
+        List<FastgptEventLogTotalVo> eventLogTotalVos = fastGptRoleMapper.selectFastGptRoleAppKeyList();
+        Map<String, List<FastgptEventLogTotalVo>> appKeyLitMap = eventLogTotalVos.stream()
+                .filter(m -> {
+                    if (m.getAppKey() != null && !m.getAppKey().isEmpty()) {
+                        try {
+                            String appKey = m.getAppKey();
+                            if (appKey.startsWith("\"") && appKey.endsWith("\"")) {
+                                appKey = appKey.substring(1, appKey.length() - 1)
+                                        .replace("\\", "")
+                                        .replace(" ","");
+                            } else {
+                                appKey = appKey.replace("\\", "");
+                            }
+                            JSONObject jsonObject = JSONObject.parseObject(appKey);
+                            String key = jsonObject.getString("APPKey");
+                            if (key != null && !key.isEmpty() && !"null".equals(key)) {
+                                m.setAppKey(key);
+                            } else {
+                                return false;
+                            }
+                        } catch (Exception e) {
+                            return false;
+                        }
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }).collect(Collectors.groupingBy(FastgptEventLogTotalVo::getAppKey));
+
+        List<FastGptRoleDataVO> roleDataList = new ArrayList<>();
+        for (String appKey : appKeyLitMap.keySet()) {
+            List<FastgptEventLogTotalVo> eventLogTotalVos1 = appKeyLitMap.get(appKey);
+            FastGptRoleDataVO roleDataVO = new FastGptRoleDataVO();
+            List<FastGptRoleDataVO> roleInfoList = new ArrayList<>();
+            roleDataVO.setRoleName(appKey);
+            roleDataVO.setRoleId((long)roleDataList.size() + 1);
+            for (FastgptEventLogTotalVo eventLogTotalVo : eventLogTotalVos1) {
+                String roleName = eventLogTotalVo.getRoleName();
+                Long roleId = eventLogTotalVo.getRoleId();
+                if(roleDataVO.getRoleList() == null){
+                    FastGptRoleDataVO roleInfo = new FastGptRoleDataVO();
+                    roleInfo.setRoleName(roleName);
+                    roleInfo.setRoleId(roleId);
+                    roleInfoList.add(roleInfo);
+                    roleDataVO.setRoleList(roleInfoList);
+                }else{
+                    List<FastGptRoleDataVO> roleInfoList1 = roleDataVO.getRoleList();
+                    FastGptRoleDataVO roleInfo = new FastGptRoleDataVO();
+                    roleInfo.setRoleName(roleName);
+                    roleInfo.setRoleId(roleId);
+                    roleInfoList1.add(roleInfo);
+                    roleDataVO.setRoleList(roleInfoList1);
+                }
+            }
+            roleDataList.add(roleDataVO);
+        }
+
+        return roleDataList;
+    }
+
 
 
 }
 }

+ 290 - 0
fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptEventLogTotalServiceImpl.java

@@ -0,0 +1,290 @@
+package com.fs.fastGpt.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.annotation.DataSource;
+import com.fs.common.core.domain.entity.SysDictData;
+import com.fs.common.enums.DataSourceType;
+import com.fs.common.utils.DateUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyService;
+import com.fs.fastGpt.domain.FastGptEventTokenLog;
+import com.fs.fastGpt.domain.FastGptRole;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
+import com.fs.fastGpt.mapper.FastgptEventLogTotalMapper;
+import com.fs.fastGpt.service.IFastGptRoleService;
+import com.fs.fastGpt.service.IFastgptEventLogTotalService;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.fs.common.utils.DictUtils.getDictCache;
+
+/**
+ * ai事件埋点统计Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-06-26
+ */
+@Service
+public class FastgptEventLogTotalServiceImpl extends ServiceImpl<FastgptEventLogTotalMapper, FastgptEventLogTotal> implements IFastgptEventLogTotalService {
+
+    @Autowired
+    FastgptEventLogTotalMapper fastgptEventLogTotalMapper;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    private IFastGptRoleService fastGptRoleService;
+    /**
+     * 查询ai事件埋点统计
+     * 
+     * @param id ai事件埋点统计主键
+     * @return ai事件埋点统计
+     */
+    @Override
+    public FastgptEventLogTotal selectFastgptEventLogTotalById(Long id)
+    {
+        return baseMapper.selectFastgptEventLogTotalById(id);
+    }
+
+    /**
+     * 查询ai事件埋点统计列表
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return ai事件埋点统计
+     */
+    @Override
+    public List<FastgptEventLogTotal> selectFastgptEventLogTotalList(FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        return baseMapper.selectFastgptEventLogTotalList(fastgptEventLogTotal);
+    }
+
+    /**
+     * 新增ai事件埋点统计
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return 结果
+     */
+    @Override
+    public int insertFastgptEventLogTotal(FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        return baseMapper.insertFastgptEventLogTotal(fastgptEventLogTotal);
+    }
+
+    /**
+     * 修改ai事件埋点统计
+     * 
+     * @param fastgptEventLogTotal ai事件埋点统计
+     * @return 结果
+     */
+    @Override
+    public int updateFastgptEventLogTotal(FastgptEventLogTotal fastgptEventLogTotal)
+    {
+        return baseMapper.updateFastgptEventLogTotal(fastgptEventLogTotal);
+    }
+
+    /**
+     * 批量删除ai事件埋点统计
+     * 
+     * @param ids 需要删除的ai事件埋点统计主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFastgptEventLogTotalByIds(Long[] ids)
+    {
+        return baseMapper.deleteFastgptEventLogTotalByIds(ids);
+    }
+
+    /**
+     * 删除ai事件埋点统计信息
+     * 
+     * @param id ai事件埋点统计主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFastgptEventLogTotalById(Long id)
+    {
+        return baseMapper.deleteFastgptEventLogTotalById(id);
+    }
+
+    @Override
+    public List<FastgptEventLogTotal> selectFastgptEventLogTotalInfoList(FastgptEventLogTotal logTotal) {
+        return fastgptEventLogTotalMapper.selectFastgptEventLogTotalInfoList(logTotal);
+    }
+
+    @Override
+    public FastgptEventLogTotal selectFastgptEventLogTotalByRoleIdAndType(FastgptEventLogTotal total) {
+        return fastgptEventLogTotalMapper.selectFastgptEventLogTotalByRoleIdAndType(total);
+    }
+
+    @Override
+    public FastgptEventLogTotal selectFastgptEventTokenLogTotalByRoleIdAndType(FastGptEventTokenLog tokenLog) {
+        return fastgptEventLogTotalMapper.selectFastgptEventTokenLogTotalByRoleIdAndType(tokenLog);
+    }
+
+    @Override
+    public FastgptEventLogTotalVo totalFastgptEventLog(List<FastgptEventLogTotalVo> list) {
+        FastgptEventLogTotalVo totalVo = new FastgptEventLogTotalVo();
+        totalVo.setRoleName("总计");
+        Map<Integer, Long> totalMap = new HashMap<>();
+        if(list != null && !list.isEmpty()){
+            list.forEach(m -> {
+                m.getTypeCountMap().forEach((k,v) -> {
+                    if(totalMap.containsKey(k)){
+                        totalMap.put(k, totalMap.get(k) + v);
+                    }else{
+                        totalMap.put(k, v);
+                    }
+                });
+            });
+            totalVo.setTypeCountMap(totalMap);
+            return totalVo;
+        }else{
+            return null;
+        }
+    }
+
+    @Override
+    public List<FastgptEventLogTotalVo> selectFastgptEventLogTotalVoInfoList(FastgptEventLogTotalVo fastgptEventLogTotal) {
+        if(fastgptEventLogTotal.getBeginTime() == null || fastgptEventLogTotal.getEndTime() == null){
+            fastgptEventLogTotal.setBeginTime(DateUtil.offsetDay(DateUtil.parse(DateUtils.getDate()), -10).toDateStr());
+            fastgptEventLogTotal.setEndTime(DateUtils.getDate());
+        }
+        String appKey = fastgptEventLogTotal.getAppKey();
+        if(appKey != null){
+            List<String> roleIds = fastGptRoleService.selectFastGptRoleRoleIdsByAppKey(appKey);
+            if(roleIds != null && !roleIds.isEmpty()){
+                fastgptEventLogTotal.setRoleIds(roleIds);
+                fastgptEventLogTotal.setRoleId(null);
+            }else{
+                fastgptEventLogTotal.setRoleId(0L);
+            }
+        }
+
+        if(fastgptEventLogTotal.getUserIds() != null && !fastgptEventLogTotal.getUserIds().isEmpty()){
+            List<String> userIds = fastgptEventLogTotal.getUserIds();
+            String result = String.join(",", userIds);
+            List<CompanyUser> companyUserList = companyService.selectCompanyListByIds(result);
+            String qwUserIds = companyUserList.stream()
+                    .map(CompanyUser::getQwUserId)
+                    .filter(Objects::nonNull) // 过滤掉 null 的 qwUserId
+                    .flatMap(userId -> Arrays.stream(userId.split(","))) // 安全 split
+                    .map(String::trim)
+                    .distinct() // 去重
+                    .collect(Collectors.joining(",")); // 收集为逗号分隔的字符串
+            fastgptEventLogTotal.setQwUserIds(qwUserIds);
+        }
+        List<FastgptEventLogTotal> totalList = fastgptEventLogTotalMapper.selectFastgptEventLogTotalVoInfoList(fastgptEventLogTotal);
+        List<SysDictData> dictCache = getDictCache("sys_fastgpt_event_log_type");
+        if(dictCache == null){
+            return null;
+        }
+        List<FastgptEventLogTotalVo> totalVoList = new ArrayList<>();
+        List<Integer> typeList = new ArrayList<>();
+        dictCache.forEach(n -> typeList.add(Integer.parseInt(n.getDictValue())));
+        if(totalList != null && !totalList.isEmpty()){
+            Map<String, List<FastgptEventLogTotal>> groupedByDateStr = totalList.stream()
+                    .collect(Collectors.groupingBy(FastgptEventLogTotal::getStatTime));
+
+            List<Long> roleIds = totalList.stream().map(FastgptEventLogTotal::getRoleId).collect(Collectors.toList());
+            List<FastGptRole> fastGptRoles = fastGptRoleService.selectFastGptRoleByRoleIds(roleIds);
+
+            for (String date : groupedByDateStr.keySet()) {
+                List<FastgptEventLogTotal> list = groupedByDateStr.get(date);
+                Map<Long, List<FastgptEventLogTotal>> roleIdGrouped = list.stream()
+                        .collect(Collectors.groupingBy(FastgptEventLogTotal::getRoleId));
+                for (Long roleId : roleIdGrouped.keySet()) {
+                    List<FastgptEventLogTotal> logTotalList = roleIdGrouped.get(roleId);
+                    FastgptEventLogTotalVo eventLogTotalVo = new FastgptEventLogTotalVo();
+                    eventLogTotalVo.setRoleId(roleId);
+                    eventLogTotalVo.setStatTime(date);
+                    List<Integer> types = logTotalList.stream().map(FastgptEventLogTotal::getType).collect(Collectors.toList());
+                    typeList.forEach(m -> logTotalList.forEach(n ->{
+                        if(types.contains(m)){
+                            if(eventLogTotalVo.getTypeCountMap() == null){
+                                Map<Integer, Long> map = new HashMap<>();
+                                map.put(n.getType(), n.getCount());
+                                eventLogTotalVo.setTypeCountMap(map);
+                            }else{
+                                Map<Integer, Long> countMap = eventLogTotalVo.getTypeCountMap();
+                                countMap.put(n.getType(), n.getCount());
+                                eventLogTotalVo.setTypeCountMap(countMap);
+                            }
+                        }else{
+                            if(eventLogTotalVo.getTypeCountMap() == null){
+                                Map<Integer, Long> map = new HashMap<>();
+                                map.put(m, 0L);
+                                eventLogTotalVo.setTypeCountMap(map);
+                            }else{
+                                Map<Integer, Long> countMap = eventLogTotalVo.getTypeCountMap();
+                                countMap.put(m, 0L);
+                                eventLogTotalVo.setTypeCountMap(countMap);
+                            }
+                        }
+                    }));
+                    for (FastGptRole fastGptRole : fastGptRoles) {
+                        if(Objects.equals(fastGptRole.getRoleId(), eventLogTotalVo.getRoleId())){
+                            eventLogTotalVo.setRoleName(fastGptRole.getRoleName());
+                        }
+                    }
+
+                    totalVoList.add(eventLogTotalVo);
+                }
+            }
+            totalVoList.sort(Comparator.comparing(FastgptEventLogTotalVo::getStatTime).thenComparing(FastgptEventLogTotalVo::getRoleId).reversed());
+            return totalVoList;
+        }else{
+            return null;
+        }
+    }
+
+    @Override
+    public List<FastGptEventTokenLog> selectFastgptEventTokenLogTotalList(FastGptEventTokenLog fastGptEventTokenLog) {
+        return fastgptEventLogTotalMapper.selectFastgptEventTokenLogTotalList(fastGptEventTokenLog);
+    }
+
+
+
+    public static List<String> generateDateStrings(String startDateStr, int days) {
+        List<String> dateList = new ArrayList<>();
+        for (int i = 0; i < days; i++) {
+            String dateStr = DateUtil.offsetDay(DateUtil.parse(startDateStr), i).toDateStr();
+            dateList.add(dateStr);
+        }
+        return dateList;
+    }
+
+    /**
+     * 批量新增ai事件埋点统计
+     *
+     * @param fastgptEventLogTotalList ai事件埋点统计列表
+     * @return 结果
+     */
+    @Override
+    public int insertFastgptEventLogTotalBatch(List<FastgptEventLogTotal> fastgptEventLogTotalList) {
+        return baseMapper.insertFastgptEventLogTotalBatch(fastgptEventLogTotalList);
+    }
+
+    /**
+     * 批量修改ai事件埋点统计
+     *
+     * @param fastgptEventLogTotalList ai事件埋点统计列表
+     * @return 结果
+     */
+    @Override
+    public int updateFastgptEventLogTotalBatch(List<FastgptEventLogTotal> fastgptEventLogTotalList) {
+        return baseMapper.updateFastgptEventLogTotalBatch(fastgptEventLogTotalList);
+    }
+
+    @Override
+    public List<FastgptEventLogTotalVo> selectFastgptEventLogTotalListByStatTime(String dateTime) {
+        return fastgptEventLogTotalMapper.selectFastgptEventLogTotalListByStatTime(dateTime);
+    }
+
+
+}

+ 19 - 0
fs-service/src/main/java/com/fs/fastGpt/vo/FastGptRoleDataVO.java

@@ -0,0 +1,19 @@
+package com.fs.fastGpt.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class FastGptRoleDataVO implements Serializable {
+    /**
+     * 节点名称
+     */
+    private Long roleId;
+
+    private String roleName;
+
+    private List<FastGptRoleDataVO> roleList;
+
+}

+ 70 - 0
fs-service/src/main/java/com/fs/fastGpt/vo/FastgptEventLogTotalVo.java

@@ -0,0 +1,70 @@
+package com.fs.fastGpt.vo;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ai事件埋点统计对象 fastgpt_event_log_total
+ *
+ * @author fs
+ * @date 2025-06-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FastgptEventLogTotalVo extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 角色id */
+    //@Excel(name = "角色id")
+    private Long roleId;
+
+    //@Excel(name = "角色名称")
+    private String roleName;
+
+    @Excel(name = "日志统计时间")
+    private String statTime;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    @Excel(name = "公司名称")
+    private String companyName;
+    /** 数量 */
+    @Excel(name = "token数量")
+    private Long count;
+
+    /** 日志类型 */
+    //@Excel(name = "日志类型")
+    private Integer type;
+
+
+
+    /** 公司用户id */
+    //@Excel(name = "公司用户id")
+    private Long companyUserId;
+
+    /** 企微用户id */
+    //@Excel(name = "企微用户id")
+    private Long qwUserId;
+
+
+    private Map<Integer,Long> typeCountMap;
+
+    private String qwUserIds;
+
+    private List<String> userIds;
+
+    private String appKey;
+
+    private List<String> roleIds;
+
+
+}

+ 110 - 8
fs-service/src/main/java/com/fs/fastgptApi/util/AiImgUtil.java

@@ -4,18 +4,18 @@ import com.alibaba.fastjson.JSON;
 import com.fs.fastgptApi.param.DouBaoAiParam;
 import com.fs.fastgptApi.param.DouBaoAiParam;
 import com.fs.fastgptApi.result.AiImgResult;
 import com.fs.fastgptApi.result.AiImgResult;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
+import java.io.*;
 import java.net.HttpURLConnection;
 import java.net.HttpURLConnection;
+import java.net.SocketTimeoutException;
 import java.net.URL;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 
 
+@Slf4j
 @Service
 @Service
 public class AiImgUtil {
 public class AiImgUtil {
 
 
@@ -98,8 +98,9 @@ public class AiImgUtil {
             textContent.setText(
             textContent.setText(
                     "识别图片内容 \n" +
                     "识别图片内容 \n" +
                             "情况一:图片为表情包的时候或是明确意义图片的时候,单独提取出表情包的含义为图片,并输出:【表情包:XXX】XXX为表情表达的内容,例如这个表情包是很开心的感谢,那么XXX就是谢谢。在【】外不进行其他的解释直接结束 \n" +
                             "情况一:图片为表情包的时候或是明确意义图片的时候,单独提取出表情包的含义为图片,并输出:【表情包:XXX】XXX为表情表达的内容,例如这个表情包是很开心的感谢,那么XXX就是谢谢。在【】外不进行其他的解释直接结束 \n" +
-                            "情况二:图片是舌头的时候,根据他的舌苔进行简单的分析,直接输出 \n" +
-                            "情况三:图片是其他的时候,正常提取图片内容,如果是身体异常部位要进行简单分析,直接输出,如果是卡通图片,需要在结尾输出【这是卡通图片】这几个字");
+                            "情况二:图片是舌头的时候,根据他的舌苔进行简单的分析,直接输出,如果是张开嘴的时候,对舌下进行简单的舌诊分析 \n" +
+                            "情况三:图片是其他的时候,正常提取图片内容,如果是身体异常部位要进行简单分析,直接输出,如果是卡通图片,需要在结尾输出【这是卡通图片】这几个字\n" +
+                            "情况四:图片如果是微信支付界面,如果最下方的一条信息为收款金额,那么输出【用户完课,领取红包】,如果最下方的一条信息为支付成功,那么输出【用户购买产品,支付成功】");
 
 
 
 
             List<DouBaoAiParam.Content> contents = new ArrayList<>();
             List<DouBaoAiParam.Content> contents = new ArrayList<>();
@@ -147,9 +148,110 @@ public class AiImgUtil {
         }
         }
     }
     }
 
 
+    /**
+     * 发送AI图像生成请求
+     * @param requestBody 请求体(JSON字符串)
+     * @return 响应结果(JSON字符串)
+     * @throws IOException 网络请求异常
+     */
+    public String sendAiImgHttpRequest(String requestBody) throws IOException {
+        long startTime = System.currentTimeMillis();
+        log.info("开始发送AI图像请求,URL: " + "https://ark.cn-beijing.volces.com/api/v3/chat/completions" + ",请求体长度: " + requestBody.length());
+
+        HttpURLConnection connection = null;
+        try {
+            // 1. 创建连接
+            URL url = new URL("https://ark.cn-beijing.volces.com/api/v3/chat/completions");
+            connection = (HttpURLConnection) url.openConnection();
+
+            // 2. 配置连接参数
+            configureConnection(connection);
+
+            // 3. 发送请求体
+            sendRequestBody(connection, requestBody);
+
+            // 4. 处理响应
+            int statusCode = connection.getResponseCode();
+            log.info("AI图像请求完成,耗时: " + (System.currentTimeMillis() - startTime) +
+                    "ms,状态码: " + statusCode);
+
+            if (statusCode == HttpURLConnection.HTTP_OK) {
+                return readResponse(connection.getInputStream());
+            } else {
+                String errorResponse = readResponse(connection.getErrorStream());
+                String errorMsg = "请求失败,状态码: " + statusCode + ",响应体: " + errorResponse;
+                log.error(errorMsg);
+                throw new IOException(errorMsg);
+            }
+        } catch (SocketTimeoutException e) {
+            // 区分超时类型(连接超时/读取超时)
+            String timeoutType = e.getMessage().contains("connect") ? "连接" : "读取";
+            String errorMsg = timeoutType + "超时,耗时: " + (System.currentTimeMillis() - startTime) + "ms";
+            log.error(errorMsg);
+            throw new IOException(errorMsg, e);
+        } catch (IOException e) {
+            log.error("请求发生异常,耗时: " + (System.currentTimeMillis() - startTime) + "ms", e);
+            throw e;
+        } finally {
+            // 确保连接关闭
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+    }
+
+    /**
+     * 配置HTTP连接参数
+     */
+    private void configureConnection(HttpURLConnection connection) {
+        try {
+            connection.setRequestMethod("POST");
+            connection.setRequestProperty("Authorization", "Bearer " + "208d3549-8dc9-4ef6-b3fa-5aa358f1ab20");
+            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+            connection.setRequestProperty("Accept", "application/json");
 
 
+            // 基础配置
+            connection.setDoOutput(true);
+            connection.setDoInput(true);
+            connection.setUseCaches(false);
+            connection.setConnectTimeout(10000);
+            connection.setReadTimeout(30000);
+        } catch (Exception e) {
+            log.error("配置连接参数失败: " + e.getMessage());
+        }
+    }
 
 
-    private  String sendAiImgHttpRequest(String requestBody) throws IOException {
+    /**
+     * 发送请求体
+     */
+    private void sendRequestBody(HttpURLConnection connection, String requestBody) throws IOException {
+        try (OutputStream os = connection.getOutputStream()) {
+            byte[] input = requestBody.getBytes(StandardCharsets.UTF_8);
+            os.write(input, 0, input.length);
+            os.flush();
+        }
+    }
+
+    /**
+     * 读取响应流
+     */
+    private String readResponse(InputStream inputStream) throws IOException {
+        if (inputStream == null) {
+            return "";
+        }
+
+        try (BufferedReader br = new BufferedReader(
+                new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
+            StringBuilder response = new StringBuilder();
+            String line;
+            while ((line = br.readLine()) != null) {
+                response.append(line);
+            }
+            return response.toString();
+        }
+    }
+
+    /*private  String sendAiImgHttpRequest(String requestBody) throws IOException {
         HttpURLConnection connection = null;
         HttpURLConnection connection = null;
         try {
         try {
             // 配置连接
             // 配置连接
@@ -196,5 +298,5 @@ public class AiImgUtil {
                 connection.disconnect();
                 connection.disconnect();
             }
             }
         }
         }
-    }
+    }*/
 }
 }

+ 2 - 2
fs-service/src/main/java/com/fs/fastgptApi/util/EventLogUtils.java

@@ -79,8 +79,8 @@ public class EventLogUtils {
         fastGptEventLog.setCreateTime(new Date());
         fastGptEventLog.setCreateTime(new Date());
 
 
 
 
-        //EventLogQueue.addEventLog(fastGptEventLog); // 入队
-        //fastGptChatMsgService.insertFastGptEventLog(fastGptEventLog);
+        EventLogQueue.addEventLog(fastGptEventLog); // 入队
+        fastGptChatMsgService.insertFastGptEventLog(fastGptEventLog);
     }
     }
 
 
     /**
     /**

+ 20 - 1
fs-service/src/main/java/com/fs/gtPush/domain/PushReqBean.java

@@ -1,5 +1,6 @@
 package com.fs.gtPush.domain;
 package com.fs.gtPush.domain;
 
 
+import com.google.common.collect.ImmutableMap;
 import lombok.Data;
 import lombok.Data;
 
 
 import javax.security.sasl.SaslServer;
 import javax.security.sasl.SaslServer;
@@ -9,8 +10,26 @@ import java.util.Map;
 @Data
 @Data
 public class PushReqBean implements Serializable {
 public class PushReqBean implements Serializable {
 
 
-    private Object cids;
+    public PushReqBean(Object push_clientid, String title, String content,Map<String, Object> payload,Map<String, Object> options) {
+        this.push_clientid = push_clientid;
+        this.title = title;
+        this.content = content;
+        this.payload = payload;
+        this.options = options;
+        this.force_notification=false;
+        this.category= ImmutableMap.of("harmony","EXPRESS", "huawei","EXPRESS", "vivo","ORDER");
+
+    }
+
+    private Object push_clientid;
     private String title;
     private String title;
     private String content;
     private String content;
+    private boolean force_notification;
+    private Map<String,String> category;
     private Map<String,Object> payload;
     private Map<String,Object> payload;
+    private Map<String,Object> options;
+    private String badge;
+
+    public PushReqBean() {
+    }
 }
 }

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

@@ -2,19 +2,112 @@ package com.fs.gtPush.service.impl;
 
 
 import cn.hutool.http.HttpUtil;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.gtPush.domain.PushReqBean;
 import com.fs.gtPush.domain.PushReqBean;
 import com.fs.gtPush.domain.PushResult;
 import com.fs.gtPush.domain.PushResult;
+import com.fs.gtPush.domain.UniPushLog;
+import com.fs.gtPush.service.UniPushLogService;
 import com.fs.gtPush.service.uniPush2Service;
 import com.fs.gtPush.service.uniPush2Service;
+import com.fs.gtPush.utils.PushUtils;
+import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import java.util.HashMap;
+import java.util.Map;
+
 @Service
 @Service
 public class uniPush2ServiceImpl implements uniPush2Service {
 public class uniPush2ServiceImpl implements uniPush2Service {
     private static final String url = "https://fc-mp-de6e03a9-c1a3-439b-9eec-d0dc3c565e4e.next.bspapp.com/push";
     private static final String url = "https://fc-mp-de6e03a9-c1a3-439b-9eec-d0dc3c565e4e.next.bspapp.com/push";
+
+    @Autowired
+    private IFsUserService userService;
+
+    @Autowired
+    private UniPushLogService logService;
+
     @Override
     @Override
     public PushResult pushMessage(PushReqBean push) {
     public PushResult pushMessage(PushReqBean push) {
         String result = HttpUtil.post(url, push.toString());
         String result = HttpUtil.post(url, push.toString());
         PushResult pushResult = JSONUtil.toBean(result, PushResult.class);
         PushResult pushResult = JSONUtil.toBean(result, PushResult.class);
         return pushResult;
         return pushResult;
     }
     }
+
+    @Override
+    public void pushOne(Long userId, Long businessId, String purl, String title, String content, Float type, Integer desType) {
+        PushReqBean param = getParam(userId, purl,title,content,type,desType,"");
+        PushResult pushResult = null;
+        UniPushLog pushAddLog = new UniPushLog();
+        if (param != null) {
+            pushResult = pushMessage(param); //推送消息
+            pushAddLog.setJpushId(param.getPush_clientid().toString());
+            pushAddLog.setPushMsg(JSON.toJSONString(param));
+            pushAddLog.setType(type);
+            pushAddLog.setDesType(desType);
+            pushAddLog.setUserId(userId);
+            pushAddLog.setBusinessId(businessId);
+            pushAddLog.setCreateTime(DateUtils.getNowDate());
+            UniPushLog uniPushLog = PushUtils.returnMsg(pushResult,pushAddLog);
+            logService.insertUniPushLog(uniPushLog);
+        }
+    }
+
+    @Override
+    public PushReqBean getParam(Long userId,String purl,String title,String content,Float type,Integer desType,String imJsonString){
+        if (userId !=null) {
+            FsUser fsUser = userService.selectFsUserByUserId(userId);
+            if (fsUser !=null){
+                String jpushId = fsUser.getJpushId();
+                if (StringUtils.isNotBlank(jpushId) && !"0".equals(jpushId) && !"string".equals(jpushId)){
+                    HashMap<String, Object> map = new HashMap<>();
+                    HashMap<String, Object> map2 = new HashMap<>();
+                    if (StringUtils.isNotBlank(purl)){
+                        map.put("url",purl);
+                        if (StringUtils.isNotEmpty(imJsonString)){
+                            map.put("data",imJsonString);
+                        }
+                    }
+                    if (content.length()>50 || title.length()>20){
+                        return null;//通知栏标题,长度小于20;通知栏内容,长度小于50
+                    }
+                    Map<String, Object> xmConfig = new HashMap<>();
+                    Map<String, Object> vvConfig = new HashMap<>();
+
+                    if (type!=null){
+                        String channel = "";
+                        if (type.toString().contains("0")){
+                            channel = "113892"; //订单
+                        } else if (type.toString().contains("1")){
+                            channel = "113891";
+                            vvConfig.put("/classification",0);
+                        } else if (type.toString().contains("2")){
+                            channel = "113791"; //系统类
+                            vvConfig.put("/classification",1);
+                        }
+                        if (StringUtils.isNotBlank(channel)){
+                            xmConfig.put("/extra.channel_id", channel);
+                            map2.put("XM", xmConfig);
+                        }
+                        vvConfig.put("/category","IM");
+                        map2.put("VV",vvConfig);
+
+                    }
+                    return new PushReqBean(
+                            jpushId,
+                            title,
+                            content,
+                            map,
+                            map2
+                    );
+                }
+            }
+        }
+        return null;
+    }
+
+
 }
 }

+ 4 - 0
fs-service/src/main/java/com/fs/gtPush/service/uniPush2Service.java

@@ -6,4 +6,8 @@ import com.fs.gtPush.domain.PushResult;
 
 
 public interface uniPush2Service {
 public interface uniPush2Service {
     PushResult pushMessage(PushReqBean push);
     PushResult pushMessage(PushReqBean push);
+
+    void pushOne(Long userId,Long businessId,String purl,String title,String content, Float type, Integer desType);
+
+    PushReqBean getParam(Long userId,String purl,String title,String content,Float type,Integer desType,String imJsonString);
 }
 }

+ 120 - 0
fs-service/src/main/java/com/fs/gtPush/utils/PushUtils.java

@@ -0,0 +1,120 @@
+package com.fs.gtPush.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.fs.gtPush.domain.PushResult;
+import com.fs.gtPush.domain.UniPushLog;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+@Slf4j
+public class PushUtils {
+
+    /**
+     * 推送单个 返回结果解析
+     * @param pushResult
+     * @param addLog
+     */
+    public static UniPushLog returnMsg(PushResult pushResult, UniPushLog addLog) {
+        if(pushResult != null){
+            if ("success".equals(pushResult.getErrMsg())){
+                Map<String, Object> dataMap = JSON.parseObject(JSON.toJSONString(pushResult.getData()), new TypeReference<Map<String, Object>>() {});
+                if (dataMap != null) {
+                    for (Map.Entry<String, Object> outerEntry : dataMap.entrySet()) {
+                        String outerKey = outerEntry.getKey(); // 外层键
+                        Map<String, String> innerMap = (Map<String, String>) outerEntry.getValue(); // 内层 Map
+                        log.info("Outer Key: " + outerKey);
+                        // 遍历内层 Map
+                        for (Map.Entry<String, String> innerEntry : innerMap.entrySet()) {
+                            String innerKey = innerEntry.getKey();
+                            String innerValue = innerEntry.getValue();
+                            log.info("    Inner Key: " + innerKey + ", Inner Value: " + innerValue);
+                            //匹配对应log (因不确定返回值是否按序排列 )
+                            if (addLog.getJpushId().equals(innerKey)) {
+                                addLog.setReturnMsg(innerValue);
+                                if (innerValue.contains("successed")) {
+                                    addLog.setPushRes(1);
+                                } else {
+                                    addLog.setPushRes(0);
+                                }
+                            }
+                        }
+                    }
+                }
+
+            } else {
+                    addLog.setPushRes(0);
+                    addLog.setReturnMsg(pushResult.getErrMsg());
+            }
+        } else {
+            addLog.setPushRes(0);
+        }
+        return addLog;
+    }
+
+    /**
+     * 推送列表 返回结果解析
+     * @param pushResult
+     * @param addLogs
+     */
+    public static ArrayList<UniPushLog> returnArrayMsg(PushResult pushResult, ArrayList<UniPushLog> addLogs) {
+        if(pushResult != null){
+            if ("success".equals(pushResult.getErrMsg())){
+                Map<String, Object> dataMap = JSON.parseObject(JSON.toJSONString(pushResult.getData()), new TypeReference<Map<String, Object>>() {});
+                if (dataMap != null) {
+
+                    for (Map.Entry<String, Object> outerEntry : dataMap.entrySet()) {
+                        String outerKey = outerEntry.getKey(); // 外层键
+                        Map<String, String> innerMap = (Map<String, String>) outerEntry.getValue(); // 内层 Map
+                        log.info("Outer Key: " + outerKey);
+                        // 遍历内层 Map
+                        int i = 0;
+                        for (Map.Entry<String, String> innerEntry : innerMap.entrySet()) {
+                            String innerKey = innerEntry.getKey();
+                            String innerValue = innerEntry.getValue();
+                            log.info("    Inner Key: " + innerKey + ", Inner Value: " + innerValue);
+                            if (addLogs.get(i).getJpushId().equals(innerKey)) {
+                                if (innerValue.contains("successed")){
+                                    addLogs.get(i).setPushRes(1);
+
+                                } else {
+                                    addLogs.get(i).setPushRes(0);
+                                }
+                                addLogs.get(i).setReturnMsg(innerValue);
+                            } else {
+                                //匹配对应log (因不确定返回值是否按序排列 )
+                                for (UniPushLog addLog : addLogs) {
+                                    if (addLog.getJpushId().equals(innerKey)) {
+                                        addLogs.get(i).setReturnMsg(innerValue);
+                                        if (innerValue.contains("successed")) {
+                                            addLog.setPushRes(1);
+                                        } else {
+                                            addLog.setPushRes(0);
+                                        }
+                                        addLogs.get(i).setReturnMsg(innerValue);
+                                        break;
+                                    }
+                                }
+                            }
+                            i++;
+                        }
+                    }
+                }
+
+            } else {
+                addLogs.forEach(log->{
+                    log.setPushRes(0);
+                    log.setReturnMsg(pushResult.getErrMsg());
+                });
+            }
+
+        } else {
+            addLogs.forEach(log->{
+                log.setPushRes(0);
+            });
+        }
+        return addLogs;
+    }
+}

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

@@ -70,5 +70,11 @@ public class FsFirstDiagnosis extends BaseEntity{
     @Excel(name = "医生证号")
     @Excel(name = "医生证号")
     private String doctorCertificate;
     private String doctorCertificate;
 
 
+    /** 医生是否填写:0-未填写 1-已填写 */
+    private Integer doctorStatus;
 
 
+    /** 用户是否答复:0-未答复 1-已答复 */
+    private Integer userStatus;
+
+    private Long qwUserId;
 }
 }

+ 12 - 0
fs-service/src/main/java/com/fs/his/dto/FindUsersByDTO.java

@@ -0,0 +1,12 @@
+package com.fs.his.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FindUsersByDTO implements Serializable {
+    private Long id;
+    private Long type;
+    private String name;
+}

+ 35 - 0
fs-service/src/main/java/com/fs/his/enums/PushLogDesTypeEnum.java

@@ -0,0 +1,35 @@
+package com.fs.his.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.stream.Stream;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public enum PushLogDesTypeEnum {
+    ORDER_UN_PAY(0,"订单未支付"),
+    ORDER_SUCCESS_PAY(1,"订单支付成功"),
+    ORDER_SEND(2,"订单已发货"),
+    ORDER_DISPATCH(3,"订单派送中"),
+    ORDER_SIGN(4,"订单已签收"),
+    HEALTH_RECEIVE(5,"接诊提醒"),
+    IM_MSG(6,"消息提醒"),
+    STUDY_COURSE(7,"课程学习提醒"),
+    MARKET_PUSH(8,"营销推送提醒");
+
+
+
+
+    private Integer value;
+    private String desc;
+
+    public static PushLogDesTypeEnum toType(int value) {
+        return Stream.of(PushLogDesTypeEnum.values())
+                .filter(p -> p.value == value)
+                .findAny()
+                .orElse(null);
+    }
+}

+ 34 - 0
fs-service/src/main/java/com/fs/his/enums/PushLogTypeEnum.java

@@ -0,0 +1,34 @@
+package com.fs.his.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.stream.Stream;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public enum PushLogTypeEnum {
+    ORDER(0f,"订单通知"),
+    ORDER_STORE(0.1f,"药品订单通知"),
+    ORDER_PACKAGE(0.2f,"套餐包订单通知"),
+    ORDER_INQUIRY(0.3f,"问诊订单通知"),
+    ORDER_INTEGRAL(0.4f,"积分订单通知"),
+    HEALTH(1f,"健康管理类通知"),
+    MARKET(2f,"营销类通知"),
+    COURSE(3f,"课程类通知");
+
+
+
+
+    private Float value;
+    private String desc;
+
+    public static PushLogTypeEnum toType(int value) {
+        return Stream.of(PushLogTypeEnum.values())
+                .filter(p -> p.value == value)
+                .findAny()
+                .orElse(null);
+    }
+}

+ 53 - 0
fs-service/src/main/java/com/fs/his/mapper/FsFirstDiagnosisMapper.java

@@ -2,7 +2,15 @@ package com.fs.his.mapper;
 
 
 import java.util.List;
 import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.param.FsFirstDiagnosisListUParam;
+import com.fs.course.vo.FsFirstDiagnosisListUVO;
 import com.fs.his.domain.FsFirstDiagnosis;
 import com.fs.his.domain.FsFirstDiagnosis;
+import com.fs.his.param.FsDiagnosisListDParam;
+import com.fs.his.param.FsFirstDiagnosisParam;
+import com.fs.his.vo.FsDiagnosisListDVO;
+import com.fs.his.vo.FsFirstDiagnosisVO;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
 
 /**
 /**
  * 初诊单Mapper接口
  * 初诊单Mapper接口
@@ -65,4 +73,49 @@ public interface FsFirstDiagnosisMapper extends BaseMapper<FsFirstDiagnosis>{
      * @return 初诊单数据
      * @return 初诊单数据
      */
      */
     FsFirstDiagnosis getByUserId(Long userId);
     FsFirstDiagnosis getByUserId(Long userId);
+
+    @Select({"<script> " +
+            "SELECT id,doctor_id,patient_name,gender,age,phone,date_time,physical_condition,doctor_status,user_status FROM fs_first_diagnosis " +
+            "WHERE 1 = 1" +
+            "<if test='maps.type == 0' > and  doctor_status = 0 and doctor_id is null</if>" +
+            "<if test='maps.type == 1' > and  doctor_id = #{maps.doctorId}</if>" +
+            "ORDER BY create_time desc" +
+            "</script>"})
+    List<FsDiagnosisListDVO> selectFsDiagnosisListDVO(@Param("maps") FsDiagnosisListDParam param);
+
+    @Select({"<script>" +
+            "SELECT fd.*,u.qw_user_name,d.sign_url FROM fs_first_diagnosis fd " +
+            " LEFT JOIN qw_user u ON u.id = fd.qw_user_id " +
+            " LEFT JOIN fs_doctor d ON d.doctor_id = fd.doctor_id " +
+            " WHERE fd.doctor_status = 1 " +
+            "<if test='param.doctorStatus != null'> AND fd.doctor_status = #{param.doctorStatus} </if>" +
+            "<if test='param.userId != null'> AND fd.user_id = #{param.userId} </if>" +
+            " ORDER BY fd.create_time desc " +
+            "</script>"})
+    List<FsFirstDiagnosisListUVO> selectFsFirstDiagnosisListUVO(@Param("param") FsFirstDiagnosisListUParam param);
+
+    @Select({"<script>" +
+            "SELECT fd.*,u.qw_user_name,d.sign_url FROM fs_first_diagnosis fd " +
+            "LEFT JOIN qw_user u ON u.id = fd.qw_user_id " +
+            " LEFT JOIN fs_doctor d ON d.doctor_id = fd.doctor_id " +
+            "WHERE fd.id = #{id}" +
+            "</script>"})
+    FsFirstDiagnosisListUVO getInfo(Long id);
+
+    @Select({"<script>" +
+            "SELECT fd.*,u.nick_name userName,qu.qw_user_name FROM fs_first_diagnosis fd  " +
+            " LEFT JOIN fs_user u ON u.user_id = fd.user_id " +
+            " LEFT JOIN qw_user qu ON qu.id = fd.qw_user_id " +
+            " WHERE 1 = 1 " +
+            "<if test='param.doctorStatus != null'> AND fd.doctor_status = #{param.doctorStatus} </if>" +
+            "<if test='param.userStatus != null'> AND fd.user_status = #{param.userStatus} </if>" +
+            "<if test='param.doctorCertificate != null'> AND fd.doctor_certificate = #{param.doctorCertificate} </if>" +
+            "<if test='param.phone != null'> AND fd.phone = like concat('%',#{param.phone},'%') </if>" +
+            "<if test='param.patientName != null'> and fd.patient_name like concat('%',#{param.patientName},'%') </if>" +
+            "<if test='param.doctorName != null'> and fd.doctor_name like concat('%',#{param.doctorName},'%') </if>" +
+            "<if test='param.userName != null'> and u.nick_name  like concat('%',#{param.userName},'%') </if>" +
+            "<if test='param.qwUserName != null'> and qu.qw_user_name like concat('%',#{param.qwUserName},'%') </if>" +
+            " ORDER BY fd.create_time desc " +
+            "</script>"})
+    List<FsFirstDiagnosisVO> selectFsFirstDiagnosisVOList(@Param("param") FsFirstDiagnosisParam param);
 }
 }

+ 25 - 0
fs-service/src/main/java/com/fs/his/mapper/FsInquiryPatientInfoMapper.java

@@ -1,9 +1,14 @@
 package com.fs.his.mapper;
 package com.fs.his.mapper;
 
 
+import com.fs.course.param.FsInquiryPatientInfoUParam;
+import com.fs.course.vo.FsInquiryPatientInfoListUVO;
 import com.fs.his.domain.FsInquiryPatientInfo;
 import com.fs.his.domain.FsInquiryPatientInfo;
 import com.fs.his.vo.FsInquiryPatientVO;
 import com.fs.his.vo.FsInquiryPatientVO;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Select;
 
 
+import java.util.List;
+
 public interface FsInquiryPatientInfoMapper {
 public interface FsInquiryPatientInfoMapper {
 
 
     int insertFsInquiryPatientInfo(FsInquiryPatientInfo fsInquiryPatientInfo);
     int insertFsInquiryPatientInfo(FsInquiryPatientInfo fsInquiryPatientInfo);
@@ -13,4 +18,24 @@ public interface FsInquiryPatientInfoMapper {
     FsInquiryPatientInfo selectFsInquiryPatientInfoInquiryOrderId(Long inquiryOrderId);
     FsInquiryPatientInfo selectFsInquiryPatientInfoInquiryOrderId(Long inquiryOrderId);
 
 
     FsInquiryPatientVO selectUserAndCompanyUserByInquiryOrderId(Long inquiryOrderId);
     FsInquiryPatientVO selectUserAndCompanyUserByInquiryOrderId(Long inquiryOrderId);
+
+    @Select({"<script>" +
+            "SELECT pi.*,p.patient_name,p.birthday,p.sex, u.nick_name companyUserName,d.doctor_name FROM fs_inquiry_patient_info pi " +
+            "LEFT JOIN fs_patient p ON p.patient_id  = pi.patient_id " +
+            "LEFT JOIN company_user u ON u.user_id = pi.company_user_id " +
+            " left join fs_doctor d on d.doctor_id = pi.sub_doctor_id  " +
+            " 1=1 " +
+            "<if test='param.userId != null'> AND pi.user_id = #{param.userId} </if> " +
+            "ORDER BY pi.create_time desc " +
+            "</script>"})
+    List<FsInquiryPatientInfoListUVO> selectFsInquiryPatientInfoListUVO(@Param("param") FsInquiryPatientInfoUParam param);
+
+    @Select({"<script>" +
+            "SELECT pi.*,p.patient_name,p.birthday,p.sex, u.nick_name companyUserName,d.doctor_name FROM fs_inquiry_patient_info pi " +
+            "LEFT JOIN fs_patient p ON p.patient_id  = pi.patient_id " +
+            "LEFT JOIN company_user u ON u.user_id = pi.company_user_id " +
+            " left join fs_doctor d on d.doctor_id = pi.sub_doctor_id  " +
+            "WHERE pi.id = #{id} " +
+            "</script>"})
+    FsInquiryPatientInfoListUVO getInfo(Long id);
 }
 }

+ 4 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -8,6 +8,8 @@ import com.fs.course.domain.FsUserWatchStatistics;
 import com.fs.course.param.CourseAnalysisParam;
 import com.fs.course.param.CourseAnalysisParam;
 import com.fs.course.vo.newfs.FsCourseAnalysisCountVO;
 import com.fs.course.vo.newfs.FsCourseAnalysisCountVO;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUser;
+import com.fs.his.dto.FindUsersByDTO;
+import com.fs.his.param.FindUserByParam;
 import com.fs.his.param.FsUserParam;
 import com.fs.his.param.FsUserParam;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.FsUserExportListVO;
 import com.fs.his.vo.FsUserExportListVO;
@@ -395,4 +397,6 @@ public interface FsUserMapper
     List<FsCompanyUserListQueryVO> selectFsCompanyUserListQuery(@Param("maps")FsUser fsUser);
     List<FsCompanyUserListQueryVO> selectFsCompanyUserListQuery(@Param("maps")FsUser fsUser);
 
 
     List<FsUser> selectFsUserListLimit(FsUser fsUser);
     List<FsUser> selectFsUserListLimit(FsUser fsUser);
+
+    List<FindUsersByDTO> findUsersByParam(FindUserByParam param);
 }
 }

+ 12 - 0
fs-service/src/main/java/com/fs/his/param/FindUserByParam.java

@@ -0,0 +1,12 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FindUserByParam implements Serializable {
+    private Integer pageNum;
+    private Integer pageSize;
+    private String keywords;
+}

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

@@ -0,0 +1,17 @@
+package com.fs.his.param;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class FsDiagnosisFillDParam {
+    private Long id;
+    private String firstDiagnosis;
+    private String physicalCondition;
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date dateTime;
+    private Long doctorId;
+
+}

+ 13 - 0
fs-service/src/main/java/com/fs/his/param/FsDiagnosisListDParam.java

@@ -0,0 +1,13 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class FsDiagnosisListDParam extends BaseParam{
+    Long doctorId;
+
+    /**
+     * 0-全部 1-我的
+     */
+    private Integer type;
+}

+ 25 - 0
fs-service/src/main/java/com/fs/his/param/FsFirstDiagnosisParam.java

@@ -0,0 +1,25 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class FsFirstDiagnosisParam extends BaseParam{
+
+    private String patientName;
+
+    private String phone;
+
+    private String doctorName;
+
+    private String qwUserName;
+
+    private String userName;
+
+    private String doctorCertificate;
+
+    /** 医生是否填写:0-未填写 1-已填写 */
+    private Integer doctorStatus;
+
+    /** 用户是否答复:0-未答复 1-已答复 */
+    private Integer userStatus;
+}

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

@@ -9,4 +9,6 @@ public class FsInquiryOrderDoPayParam implements Serializable {
     Long orderId;
     Long orderId;
     Long userId;
     Long userId;
 
 
+    private String appId;
+
 }
 }

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

@@ -10,4 +10,6 @@ public class FsPackageOrderDoPayParam implements Serializable {
     @NotNull(message = "订单号不能为空")
     @NotNull(message = "订单号不能为空")
     Long orderId;
     Long orderId;
     Long userId;
     Long userId;
+
+    private String appId;
 }
 }

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

@@ -10,4 +10,6 @@ public class FsStoreOrderDoPayParam implements Serializable {
     @NotNull(message = "订单号不能为空")
     @NotNull(message = "订单号不能为空")
     Long orderId;
     Long orderId;
     Long userId;
     Long userId;
+
+    private String appId;
 }
 }

+ 26 - 5
fs-service/src/main/java/com/fs/his/service/IFsFirstDiagnosisService.java

@@ -2,7 +2,15 @@ package com.fs.his.service;
 
 
 import java.util.List;
 import java.util.List;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.course.param.FsFirstDiagnosisListUParam;
+import com.fs.course.vo.FsFirstDiagnosisListUVO;
 import com.fs.his.domain.FsFirstDiagnosis;
 import com.fs.his.domain.FsFirstDiagnosis;
+import com.fs.his.param.FsDiagnosisFillDParam;
+import com.fs.his.param.FsDiagnosisListDParam;
+import com.fs.his.param.FsFirstDiagnosisParam;
+import com.fs.his.vo.FsDiagnosisListDVO;
+import com.fs.his.vo.FsFirstDiagnosisVO;
 
 
 /**
 /**
  * 初诊单Service接口
  * 初诊单Service接口
@@ -27,6 +35,8 @@ public interface IFsFirstDiagnosisService extends IService<FsFirstDiagnosis>{
      */
      */
     List<FsFirstDiagnosis> selectFsFirstDiagnosisList(FsFirstDiagnosis fsFirstDiagnosis);
     List<FsFirstDiagnosis> selectFsFirstDiagnosisList(FsFirstDiagnosis fsFirstDiagnosis);
 
 
+    List<FsFirstDiagnosisVO> selectFsFirstDiagnosisVOList(FsFirstDiagnosisParam param);
+
     /**
     /**
      * 新增初诊单
      * 新增初诊单
      * 
      * 
@@ -59,10 +69,21 @@ public interface IFsFirstDiagnosisService extends IService<FsFirstDiagnosis>{
      */
      */
     int deleteFsFirstDiagnosisById(Long id);
     int deleteFsFirstDiagnosisById(Long id);
 
 
-/**
- * 根据用户ID获取首次诊断信息
- * @param userId 用户ID
- * @return 返回对应的首次诊断信息对象,如果不存在则可能返回null
- */
+    /**
+     * 根据用户ID获取首次诊断信息
+     * @param userId 用户ID
+     * @return 返回对应的首次诊断信息对象,如果不存在则可能返回null
+     */
     FsFirstDiagnosis getByUserId(Long userId);
     FsFirstDiagnosis getByUserId(Long userId);
+
+
+    List<FsDiagnosisListDVO> getDiagnosisList(FsDiagnosisListDParam param);
+
+    R fill(FsDiagnosisFillDParam param);
+
+    List<FsFirstDiagnosisListUVO> selectFsFirstDiagnosisListUVO(FsFirstDiagnosisListUParam param);
+
+    FsFirstDiagnosisListUVO getInfo(Long id);
+
+    R confirm(Long id);
 }
 }

+ 8 - 0
fs-service/src/main/java/com/fs/his/service/IFsInquiryPatientInfoService.java

@@ -1,8 +1,13 @@
 package com.fs.his.service;
 package com.fs.his.service;
 
 
+import com.fs.course.param.FsInquiryPatientInfoUParam;
+import com.fs.course.vo.FsInquiryPatientInfoListUVO;
 import com.fs.his.domain.FsInquiryPatientInfo;
 import com.fs.his.domain.FsInquiryPatientInfo;
 import com.fs.his.param.FsInquiryPatientParam;
 import com.fs.his.param.FsInquiryPatientParam;
 import com.fs.his.vo.FsInquiryPatientVO;
 import com.fs.his.vo.FsInquiryPatientVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 
 /**
 /**
  * 问诊患者信息Service接口
  * 问诊患者信息Service接口
@@ -16,4 +21,7 @@ public interface IFsInquiryPatientInfoService {
 
 
     FsInquiryPatientVO selectFsInquiryPatientInfo(Long inquiryOrderId);
     FsInquiryPatientVO selectFsInquiryPatientInfo(Long inquiryOrderId);
 
 
+    List<FsInquiryPatientInfoListUVO> selectFsInquiryPatientInfoListUVO(FsInquiryPatientInfoUParam param);
+
+    FsInquiryPatientInfoListUVO getInfo(Long id);
 }
 }

+ 8 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserService.java

@@ -12,6 +12,8 @@ import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
 import com.fs.course.vo.newfs.FsCourseAnalysisVO;
 import com.fs.course.vo.newfs.FsCourseAnalysisVO;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserAddress;
 import com.fs.his.domain.FsUserAddress;
+import com.fs.his.dto.FindUsersByDTO;
+import com.fs.his.param.FindUserByParam;
 import com.fs.his.param.FsUserParam;
 import com.fs.his.param.FsUserParam;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.FsUserExportListVO;
 import com.fs.his.vo.FsUserExportListVO;
@@ -46,6 +48,12 @@ public interface IFsUserService
      */
      */
     public FsUser selectFsUserByUserId(Long userId);
     public FsUser selectFsUserByUserId(Long userId);
 
 
+    /**
+     * 通过参数查找用户
+     * @param param 参数
+     * @return 用户列表
+     */
+    public List<FindUsersByDTO> findUserByParam(FindUserByParam param);
     /**
     /**
      * 查询用户列表
      * 查询用户列表
      *
      *

+ 110 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsFirstDiagnosisServiceImpl.java

@@ -1,13 +1,28 @@
 package com.fs.his.service.impl;
 package com.fs.his.service.impl;
 
 
+import java.util.Collections;
 import java.util.List;
 import java.util.List;
+
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.course.param.FsFirstDiagnosisListUParam;
+import com.fs.course.vo.FsFirstDiagnosisListUVO;
+import com.fs.his.domain.FsDoctor;
+import com.fs.his.param.FsDiagnosisFillDParam;
+import com.fs.his.param.FsDiagnosisListDParam;
+import com.fs.his.param.FsFirstDiagnosisParam;
+import com.fs.his.service.IFsDoctorService;
+import com.fs.his.vo.FsDiagnosisListDVO;
+import com.fs.his.vo.FsFirstDiagnosisVO;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import com.fs.his.mapper.FsFirstDiagnosisMapper;
 import com.fs.his.mapper.FsFirstDiagnosisMapper;
 import com.fs.his.domain.FsFirstDiagnosis;
 import com.fs.his.domain.FsFirstDiagnosis;
 import com.fs.his.service.IFsFirstDiagnosisService;
 import com.fs.his.service.IFsFirstDiagnosisService;
+import org.springframework.util.CollectionUtils;
 
 
 /**
 /**
  * 初诊单Service业务层处理
  * 初诊单Service业务层处理
@@ -18,6 +33,13 @@ import com.fs.his.service.IFsFirstDiagnosisService;
 @Service
 @Service
 public class FsFirstDiagnosisServiceImpl extends ServiceImpl<FsFirstDiagnosisMapper, FsFirstDiagnosis> implements IFsFirstDiagnosisService {
 public class FsFirstDiagnosisServiceImpl extends ServiceImpl<FsFirstDiagnosisMapper, FsFirstDiagnosis> implements IFsFirstDiagnosisService {
 
 
+
+    @Autowired
+    private FsFirstDiagnosisMapper diagnosisMapper;
+
+    @Autowired
+    private IFsDoctorService doctorService;
+
     /**
     /**
      * 查询初诊单
      * 查询初诊单
      * 
      * 
@@ -42,6 +64,11 @@ public class FsFirstDiagnosisServiceImpl extends ServiceImpl<FsFirstDiagnosisMap
         return baseMapper.selectFsFirstDiagnosisList(fsFirstDiagnosis);
         return baseMapper.selectFsFirstDiagnosisList(fsFirstDiagnosis);
     }
     }
 
 
+    @Override
+    public List<FsFirstDiagnosisVO> selectFsFirstDiagnosisVOList(FsFirstDiagnosisParam param) {
+        return diagnosisMapper.selectFsFirstDiagnosisVOList(param);
+    }
+
     /**
     /**
      * 新增初诊单
      * 新增初诊单
      * 
      * 
@@ -94,6 +121,88 @@ public class FsFirstDiagnosisServiceImpl extends ServiceImpl<FsFirstDiagnosisMap
 
 
     @Override
     @Override
     public FsFirstDiagnosis getByUserId(Long userId) {
     public FsFirstDiagnosis getByUserId(Long userId) {
-        return baseMapper.getByUserId(userId);
+        FsFirstDiagnosis firstDiagnosis = baseMapper.getByUserId(userId);
+        if (firstDiagnosis == null) {
+            firstDiagnosis = new FsFirstDiagnosis();
+        }
+        return firstDiagnosis;
+    }
+
+    @Override
+    public List<FsDiagnosisListDVO> getDiagnosisList(FsDiagnosisListDParam param) {
+        return diagnosisMapper.selectFsDiagnosisListDVO(param);
+    }
+
+    @Override
+    public List<FsFirstDiagnosisListUVO> selectFsFirstDiagnosisListUVO(FsFirstDiagnosisListUParam param) {
+        List<FsFirstDiagnosisListUVO> listUVOS = diagnosisMapper.selectFsFirstDiagnosisListUVO(param);
+        if (!CollectionUtils.isEmpty(listUVOS)) {
+            listUVOS.forEach(listUVO -> {
+                if(listUVO.getDoctorStatus() != 1) {
+                    listUVO.setSignUrl(null);
+                }
+            });
+        }
+        return listUVOS;
+    }
+
+    @Override
+    public FsFirstDiagnosisListUVO getInfo(Long id) {
+        FsFirstDiagnosisListUVO info = diagnosisMapper.getInfo(id);
+        if (info != null && info.getDoctorStatus() != 1) {
+            info.setSignUrl(null);
+        }
+        return info;
+    }
+
+    @Override
+    public R confirm(Long id) {
+        FsFirstDiagnosis diagnosis = diagnosisMapper.selectById(id);
+        if (diagnosis == null) {
+            return R.error("初诊单不存在");
+        }
+        if (diagnosis.getUserStatus() != 0) {
+            return R.error("初诊单已确认");
+        }
+        if (diagnosis.getDoctorStatus() != 1) {
+            return R.error("医生未签字无法确认");
+        }
+        FsFirstDiagnosis map = new FsFirstDiagnosis();
+        map.setId(diagnosis.getId());
+        map.setUserStatus(1);
+        int i = diagnosisMapper.updateFsFirstDiagnosis(diagnosis);
+        if (i > 0) {
+            return R.ok();
+        }
+        return R.error();
+    }
+
+    @Override
+    public R fill(FsDiagnosisFillDParam param) {
+        if (param.getId() == null) {
+            return R.error("初诊单id不能为空");
+        }
+        FsFirstDiagnosis diagnosis = diagnosisMapper.selectById(param.getId());
+        FsFirstDiagnosis map = new FsFirstDiagnosis();
+        if (diagnosis == null) {
+            return R.error("初诊单不存在");
+        }
+        if (diagnosis.getDoctorId() == null){
+            FsDoctor doctor = doctorService.selectFsDoctorByDoctorId(param.getDoctorId());
+            if (doctor == null) {
+                return R.error("医生不存在");
+            }
+            map.setDoctorName(doctor.getDoctorName());
+            map.setDoctorDep(doctor.getPosition());
+            map.setDoctorCertificate(doctor.getCertificateCode());
+            map.setDoctorId(doctor.getDoctorId());
+        }
+        map.setId(diagnosis.getId());
+        map.setDoctorStatus(1);
+        int i = diagnosisMapper.updateFsFirstDiagnosis(diagnosis);
+        if (i > 0) {
+            return R.ok();
+        }
+        return R.error();
     }
     }
 }
 }

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

@@ -4,6 +4,8 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.CustomException;
+import com.fs.course.param.FsInquiryPatientInfoUParam;
+import com.fs.course.vo.FsInquiryPatientInfoListUVO;
 import com.fs.his.domain.FsInquiryPatientInfo;
 import com.fs.his.domain.FsInquiryPatientInfo;
 import com.fs.his.mapper.FsInquiryOrderMapper;
 import com.fs.his.mapper.FsInquiryOrderMapper;
 import com.fs.his.mapper.FsInquiryPatientInfoMapper;
 import com.fs.his.mapper.FsInquiryPatientInfoMapper;
@@ -17,6 +19,9 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import java.util.Collections;
+import java.util.List;
+
 /**
 /**
  * 问诊患者信息Service业务层处理
  * 问诊患者信息Service业务层处理
  */
  */
@@ -55,7 +60,19 @@ public class FsInquiryPatientInfoServiceImpl implements IFsInquiryPatientInfoSer
         if (fsInquiryPatientInfo != null) {
         if (fsInquiryPatientInfo != null) {
             BeanCopyUtils.copy(fsInquiryPatientInfo, inquiryPatientVO);
             BeanCopyUtils.copy(fsInquiryPatientInfo, inquiryPatientVO);
             inquiryPatientVO.setDoctorAdviceJson(JSONUtil.toBean(fsInquiryPatientInfo.getDoctorAdviceJson(), DoctorAdviceVO.class));
             inquiryPatientVO.setDoctorAdviceJson(JSONUtil.toBean(fsInquiryPatientInfo.getDoctorAdviceJson(), DoctorAdviceVO.class));
+        } else {
+            inquiryPatientVO = new FsInquiryPatientVO();
         }
         }
         return inquiryPatientVO;
         return inquiryPatientVO;
     }
     }
+
+    @Override
+    public List<FsInquiryPatientInfoListUVO> selectFsInquiryPatientInfoListUVO(FsInquiryPatientInfoUParam param) {
+        return fsInquiryPatientInfoMapper.selectFsInquiryPatientInfoListUVO(param);
+    }
+
+    @Override
+    public FsInquiryPatientInfoListUVO getInfo(Long id) {
+        return fsInquiryPatientInfoMapper.getInfo(id);
+    }
 }
 }

+ 52 - 32
fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java

@@ -21,10 +21,7 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.CustomException;
-import com.fs.common.utils.DateUtils;
-import com.fs.common.utils.SecurityUtils;
-import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.*;
 import com.fs.common.utils.ip.IpUtils;
 import com.fs.common.utils.ip.IpUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.Company;
 import com.fs.company.domain.Company;
@@ -165,6 +162,9 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
     @Autowired
     @Autowired
     private FsUserWxMapper fsUserWxMapper;
     private FsUserWxMapper fsUserWxMapper;
 
 
+    @Autowired
+    private IFsUserWxService userWxService;
+
     /**
     /**
      * 查询套餐订单
      * 查询套餐订单
      *
      *
@@ -315,28 +315,26 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
             param.setUserCouponId(order.getUserCouponId());
             param.setUserCouponId(order.getUserCouponId());
         }
         }
         FsUser user=userService.selectFsUserByUserId(order.getUserId());
         FsUser user=userService.selectFsUserByUserId(order.getUserId());
+        if (Objects.isNull(user)){
+            return R.error("用户不存在");
+        }
+
         if (param.getType()==1) {
         if (param.getType()==1) {
-            if(user!=null&& StringUtils.isNotEmpty(user.getMaOpenId())){
-                param.setCompanyId(order.getCompanyId());
-                param.setCompanyUserId(order.getUserId());
-                param.setStoreId(order.getStoreId());
-                Map<String,Object> moneys=computeOrderMoney(order.getTotalPrice(),param);
-                return R.ok().put("moneys",moneys);
-            }
-            else{
+            if (StringUtils.isBlank(user.getMaOpenId()) && !CloudHostUtils.isCloudHostName("弘德堂")) {
                 return R.error("用户OPENID不存在");
                 return R.error("用户OPENID不存在");
             }
             }
+
+            param.setCompanyId(order.getCompanyId());
+            param.setCompanyUserId(order.getUserId());
+            param.setStoreId(order.getStoreId());
+            Map<String,Object> moneys=computeOrderMoney(order.getTotalPrice(),param);
+            return R.ok().put("moneys",moneys);
         }else if (param.getType()==2){
         }else if (param.getType()==2){
-            if(user!=null){
-                param.setCompanyId(order.getCompanyId());
-                param.setCompanyUserId(order.getUserId());
-                param.setStoreId(order.getStoreId());
-                Map<String,Object> moneys=computeOrderMoney(order.getTotalPrice(),param);
-                return R.ok().put("moneys",moneys);
-            }
-            else{
-                return R.error("用户不存在");
-            }
+            param.setCompanyId(order.getCompanyId());
+            param.setCompanyUserId(order.getUserId());
+            param.setStoreId(order.getStoreId());
+            Map<String,Object> moneys=computeOrderMoney(order.getTotalPrice(),param);
+            return R.ok().put("moneys",moneys);
         }else {
         }else {
             return R.error("无效的类型参数");
             return R.error("无效的类型参数");
         }
         }
@@ -881,20 +879,42 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
             return R.error("非法操作");
             return R.error("非法操作");
         }
         }
 
 
-        FsUser user=userService.selectFsUserByUserId(param.getUserId());
-
+//        FsUser user=userService.selectFsUserByUserId(param.getUserId());
+//
+//        String json = configService.selectConfigByKey("his.pay");
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//
+//        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+//        if (StringUtils.isBlank(openId)){
+//            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+//                    .eq(FsUserWx::getFsUserId, param.getUserId())
+//                    .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+//            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+//            if (Objects.nonNull(fsUserWx)){
+//                openId = fsUserWx.getOpenId();
+//            }
+//        }
+        FsUser user = userService.selectFsUserByUserId(param.getUserId());
+        //在线支付
         String json = configService.selectConfigByKey("his.pay");
         String json = configService.selectConfigByKey("his.pay");
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
-
-        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
-        if (StringUtils.isBlank(openId)){
-            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
-                    .eq(FsUserWx::getFsUserId, param.getUserId())
-                    .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
-            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
-            if (Objects.nonNull(fsUserWx)){
+        String openId = "";
+        if (StringUtils.isNotEmpty(param.getAppId())) {
+            FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), param.getUserId(), 1);
+            if (fsUserWx != null) {
                 openId = fsUserWx.getOpenId();
                 openId = fsUserWx.getOpenId();
             }
             }
+        } else {
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
         }
         }
 
 
         if(user!=null&& StringUtils.isNotEmpty(openId)){
         if(user!=null&& StringUtils.isNotEmpty(openId)){

+ 123 - 49
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -38,9 +38,7 @@ import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.*;
 import com.fs.his.domain.*;
 import com.fs.his.dto.*;
 import com.fs.his.dto.*;
-import com.fs.his.enums.FsStoreOrderLogEnum;
-import com.fs.his.enums.FsStoreOrderStatusEnum;
-import com.fs.his.enums.ShipperCodeEnum;
+import com.fs.his.enums.*;
 import com.fs.his.mapper.*;
 import com.fs.his.mapper.*;
 import com.fs.his.param.*;
 import com.fs.his.param.*;
 import com.fs.his.service.*;
 import com.fs.his.service.*;
@@ -82,7 +80,14 @@ import com.github.binarywang.wxpay.service.WxPayService;
 import com.google.gson.Gson;
 import com.google.gson.Gson;
 import lombok.Synchronized;
 import lombok.Synchronized;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
 import org.json.JSONObject;
 import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.aop.framework.AopContext;
 import org.springframework.aop.framework.AopContext;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -96,6 +101,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.CollectionUtils;
 
 
+import java.io.IOException;
 import java.lang.reflect.Field;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.math.RoundingMode;
@@ -120,6 +126,7 @@ import static com.fs.his.utils.PhoneUtil.encryptPhone;
 @Slf4j
 @Slf4j
 @EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
 @EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
 public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
+    Logger logger = LoggerFactory.getLogger(getClass());
     @Autowired
     @Autowired
     private WxPayService wxPayService;
     private WxPayService wxPayService;
     @Autowired
     @Autowired
@@ -270,9 +277,15 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Autowired
     @Autowired
     private FsUserWxMapper fsUserWxMapper;
     private FsUserWxMapper fsUserWxMapper;
 
 
+    @Autowired
+    private IFsUserWxService userWxService;
+
     @Value("${express.omsCode}")
     @Value("${express.omsCode}")
     private String expressOmsCode;
     private String expressOmsCode;
 
 
+    @Autowired
+    private com.fs.gtPush.service.uniPush2Service uniPush2Service;
+
     /**
     /**
      * 查询订单
      * 查询订单
      *
      *
@@ -1405,14 +1418,14 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
     @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
     public R payConfirm(String orderCode, String payCode, String tradeNo, String payType, Integer type) {
     public R payConfirm(String orderCode, String payCode, String tradeNo, String payType, Integer type) {
         try {
         try {
-            FsStoreOrderScrm order = null;
+            FsStoreOrder order = null;
             if (type.equals(1)) {
             if (type.equals(1)) {
 
 
-                FsStorePaymentScrm storePayment = fsStorePaymentScrmMapper.selectFsStorePaymentByPaymentCode(payCode);
+                FsStorePayment storePayment = fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
                 if (storePayment != null) {
                 if (storePayment != null) {
                     if (storePayment.getStatus().equals(0)) {
                     if (storePayment.getStatus().equals(0)) {
                         log.info(payCode + "待支付");
                         log.info(payCode + "待支付");
-                        FsStorePaymentScrm paymentMap = new FsStorePaymentScrm();
+                        FsStorePayment paymentMap = new FsStorePayment();
                         paymentMap.setPaymentId(storePayment.getPaymentId());
                         paymentMap.setPaymentId(storePayment.getPaymentId());
                         paymentMap.setStatus(1);
                         paymentMap.setStatus(1);
                         paymentMap.setPayTime(new Date());
                         paymentMap.setPayTime(new Date());
@@ -1429,42 +1442,33 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                             paymentMap.setBankSerialNo(orderResult.getBankOrderId());
                             paymentMap.setBankSerialNo(orderResult.getBankOrderId());
                             paymentMap.setBankTransactionId(orderResult.getBankTrxId());
                             paymentMap.setBankTransactionId(orderResult.getBankTrxId());
                         }
                         }
-                        fsStorePaymentScrmMapper.updateFsStorePayment(paymentMap);
+                        fsStorePaymentMapper.updateFsStorePayment(paymentMap);
                         log.info(payCode + "已支付");
                         log.info(payCode + "已支付");
-                        order = fsStoreOrderScrmMapper.selectFsStoreOrderById(Long.parseLong(storePayment.getBusinessOrderId()));
+                        order = fsStoreOrderMapper.selectFsStoreOrderByOrderId(Long.parseLong(storePayment.getBusinessId()));
                     }
                     }
                 } else {
                 } else {
                     log.info(payCode + "支付单号不存在");
                     log.info(payCode + "支付单号不存在");
                     return R.error("支付单号不存在");
                     return R.error("支付单号不存在");
                 }
                 }
             } else if (type.equals(2)) {
             } else if (type.equals(2)) {
-                order = fsStoreOrderScrmMapper.selectFsStoreOrderByOrderCode(orderCode);
+                order = fsStoreOrderMapper.selectFsStoreOrderByOrderCode(orderCode);
             }
             }
-//            if (order != null && !order.getStatus().equals(FsStoreOrderStatusEnum.STATUS_1.getValue())) {
-//                log.info(payCode + "订单号不为待支付回退");
-//                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
-//                return R.error();
-//            }
-
-            //orderScrm迁移的表待支付状态码为:0
-            if (order != null && !order.getStatus().equals(0)) {//判断订单状态是否待支付
+            if (order != null && !order.getStatus().equals(FsStoreOrderStatusEnum.STATUS_1.getValue())) {
                 log.info(payCode + "订单号不为待支付回退");
                 log.info(payCode + "订单号不为待支付回退");
                 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                 return R.error();
                 return R.error();
             }
             }
-
-            if (order != null && !order.getPaid().equals(0)) {
+            if (order != null && !order.getIsPay().equals(0)) {
                 log.info(payCode + "订单号支付不为待支付回退");
                 log.info(payCode + "订单号支付不为待支付回退");
                 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                 return R.error();
                 return R.error();
             }
             }
-            fsStoreOrderLogsService.create(order.getId(), FsStoreOrderLogEnum.PAY_ORDER_SUCCESS.getValue(),
+            fsStoreOrderLogsService.create(order.getOrderId(), FsStoreOrderLogEnum.PAY_ORDER_SUCCESS.getValue(),
                     FsStoreOrderLogEnum.PAY_ORDER_SUCCESS.getDesc());
                     FsStoreOrderLogEnum.PAY_ORDER_SUCCESS.getDesc());
-            FsStoreOrderScrm storeOrder = new FsStoreOrderScrm();
-            storeOrder.setId(order.getId());
-            storeOrder.setPaid(1);
-//            storeOrder.setStatus(2);
-            storeOrder.setStatus(1);//代发货
+            FsStoreOrder storeOrder = new FsStoreOrder();
+            storeOrder.setOrderId(order.getOrderId());
+            storeOrder.setIsPay(1);
+            storeOrder.setStatus(2);
             storeOrder.setPrescribePrice(order.getTotalPrice());
             storeOrder.setPrescribePrice(order.getTotalPrice());
             SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
             SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
             Map<String, Object> config = (Map<String, Object>) JSON.parse(sysConfig.getConfigValue());
             Map<String, Object> config = (Map<String, Object>) JSON.parse(sysConfig.getConfigValue());
@@ -1477,20 +1481,20 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             } else {
             } else {
                 storeOrder.setFollowDoctorId(iFsDoctorService.selectFollowDoctorDoctorByPackage());
                 storeOrder.setFollowDoctorId(iFsDoctorService.selectFollowDoctorDoctorByPackage());
             }
             }
-            if (order.getCycle() != null && order.getCycle() >= followRate) {
+            if (order.getCycle() >= followRate) {
                 Calendar calendar = Calendar.getInstance();
                 Calendar calendar = Calendar.getInstance();
                 calendar.setTime(new Date());
                 calendar.setTime(new Date());
                 calendar.add(Calendar.DAY_OF_MONTH, followRate);
                 calendar.add(Calendar.DAY_OF_MONTH, followRate);
                 storeOrder.setFollowTime(calendar.getTime());
                 storeOrder.setFollowTime(calendar.getTime());
             }
             }
             storeOrder.setPayTime(new Date());
             storeOrder.setPayTime(new Date());
-            fsStoreOrderScrmMapper.updateFsStoreOrder(storeOrder);
+            fsStoreOrderMapper.updateFsStoreOrder(storeOrder);
             //更新优惠券状态
             //更新优惠券状态
-            if (order.getCouponId() != null && order.getCouponId() > 0) {
-                FsUserCoupon userCoupon = userCouponService.selectFsUserCouponById(order.getCouponId());
+            if (order.getUserCouponId() != null && order.getUserCouponId() > 0) {
+                FsUserCoupon userCoupon = userCouponService.selectFsUserCouponById(order.getUserCouponId());
                 if (userCoupon != null && userCoupon.getStatus().equals(0)) {
                 if (userCoupon != null && userCoupon.getStatus().equals(0)) {
                     userCoupon.setUseTime(new Date());
                     userCoupon.setUseTime(new Date());
-                    userCoupon.setBusinessId(order.getId());
+                    userCoupon.setBusinessId(order.getOrderId());
                     userCoupon.setBusinessType(2);
                     userCoupon.setBusinessType(2);
                     userCoupon.setStatus(1);
                     userCoupon.setStatus(1);
                     userCouponService.updateFsUserCoupon(userCoupon);
                     userCouponService.updateFsUserCoupon(userCoupon);
@@ -1895,7 +1899,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     public ExpressResultDTO updateDeliveryItem(ExpressNotifyDTO notifyDTO) {
     public ExpressResultDTO updateDeliveryItem(ExpressNotifyDTO notifyDTO) {
         String data = URLDecoder.decode(notifyDTO.getRequestData(), Charset.forName("UTF-8"));
         String data = URLDecoder.decode(notifyDTO.getRequestData(), Charset.forName("UTF-8"));
         //ExpressInfoDTO
         //ExpressInfoDTO
-        log.info("快递根踪回调: {}", data);
+        logger.info("快递根踪回调:" + data);
         FsSysConfig sysConfig = configUtil.getSysConfig();
         FsSysConfig sysConfig = configUtil.getSysConfig();
         ExpressDataDTO expressDataDTO = JSONUtil.toBean(data, ExpressDataDTO.class);
         ExpressDataDTO expressDataDTO = JSONUtil.toBean(data, ExpressDataDTO.class);
         if (expressDataDTO != null && expressDataDTO.getData() != null) {
         if (expressDataDTO != null && expressDataDTO.getData() != null) {
@@ -1903,8 +1907,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 List<FsStoreOrder> orders = this.selectFsStoreOrderListByDeliveryId(dto.getLogisticCode());
                 List<FsStoreOrder> orders = this.selectFsStoreOrderListByDeliveryId(dto.getLogisticCode());
                 if (orders != null) {
                 if (orders != null) {
                     for (FsStoreOrder order : orders) {
                     for (FsStoreOrder order : orders) {
-                        log.info("订单信息: {}", JSONUtil.toJsonStr(order));
-                        log.info("运单号: {}", dto.getLogisticCode());
+                        logger.info("订单信息:" + JSONUtil.toJsonStr(order));
+                        logger.info("运单号:" + dto.getLogisticCode());
                         if (order != null && (order.getDeliveryStatus() == null || order.getDeliveryStatus() != 3)) {
                         if (order != null && (order.getDeliveryStatus() == null || order.getDeliveryStatus() != 3)) {
                             if (dto.getState() != null && dto.getStateEx() != null) {
                             if (dto.getState() != null && dto.getStateEx() != null) {
                                 FsStoreOrder map = new FsStoreOrder();
                                 FsStoreOrder map = new FsStoreOrder();
@@ -1915,16 +1919,47 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                                 this.updateFsStoreOrder(map);
                                 this.updateFsStoreOrder(map);
                                 //如果是正常签收,更新订单状态
                                 //如果是正常签收,更新订单状态
                                 if (dto.getState().equals("3") && (dto.getStateEx().equals("301") || dto.getStateEx().equals("302") || dto.getStateEx().equals("304") || dto.getStateEx().equals("311"))) {
                                 if (dto.getState().equals("3") && (dto.getStateEx().equals("301") || dto.getStateEx().equals("302") || dto.getStateEx().equals("304") || dto.getStateEx().equals("311"))) {
-                                    SysConfig storeConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
-                                    Map<String, Object> config = (Map<String, Object>) JSON.parse(storeConfig.getConfigValue());
-                                    Object isUpdateOrder = config.get("isUpdateOrder");
-                                    if (isUpdateOrder == null || "1".equals(isUpdateOrder.toString())) {
-                                        this.getGoods(order.getOrderId());
+                                    this.getGoods(order.getOrderId());
+                                    //app订单签收通知
+                                    try {
+                                        uniPush2Service.pushOne(
+                                                order.getUserId(),
+                                                order.getOrderId(),
+                                                null,
+                                                "订单已签收",
+                                                "您的订单:" + order.getOrderCode() + "快递单号为:" + dto.getLogisticCode() + "已签收",
+                                                PushLogTypeEnum.ORDER_STORE.getValue(),
+                                                PushLogDesTypeEnum.ORDER_SIGN.getValue()
+                                        );
+                                    } catch (Exception e) {
+                                        log.error("app订单通知推送失败:{}", e.getMessage());
+                                    }
+                                }
+                                //app派件通知
+                                if (dto.getState().equals("2") && (dto.getStateEx().equals("211"))) {
+                                    //ai向客户发送发货物流信息
+                                    requestExpressInfo(order.getOrderId());
+                                }
+                                //app派件通知
+                                if (dto.getState().equals("2") && (dto.getStateEx().equals("202"))) {
+                                    //app订单签收通知
+                                    try {
+                                        uniPush2Service.pushOne(
+                                                order.getUserId(),
+                                                order.getOrderId(),
+                                                null,
+                                                "订单正在派送",
+                                                "您的订单:" + order.getOrderCode() + "快递单号为:" + dto.getLogisticCode() + "正在派送",
+                                                PushLogTypeEnum.ORDER_STORE.getValue(),
+                                                PushLogDesTypeEnum.ORDER_SIGN.getValue()
+                                        );
+                                    } catch (Exception e) {
+                                        log.error("app订单通知推送失败:{}", e.getMessage());
                                     }
                                     }
                                 }
                                 }
                             }
                             }
                             if (!dto.isSuccess()) {
                             if (!dto.isSuccess()) {
-                                log.info("物流状态异常:{}", dto);
+                                logger.info("物流状态异常:{}" + dto);
                             }
                             }
                             if ((!dto.isSuccess() && dto.getReason() != null && dto.getReason().equals("三天无轨迹")) || (!dto.isSuccess() && dto.getReason() != null && dto.getReason().equals("七天内无轨迹变化"))) {
                             if ((!dto.isSuccess() && dto.getReason() != null && dto.getReason().equals("三天无轨迹")) || (!dto.isSuccess() && dto.getReason() != null && dto.getReason().equals("七天内无轨迹变化"))) {
                                 //订阅物流回调
                                 //订阅物流回调
@@ -1936,7 +1971,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                                     }
                                     }
                                 }
                                 }
                                 expressService.subscribeEspress(order.getOrderCode(), order.getDeliveryCode(), order.getDeliverySn(), lastFourNumber);
                                 expressService.subscribeEspress(order.getOrderCode(), order.getDeliveryCode(), order.getDeliverySn(), lastFourNumber);
-                                log.info("物流重新订阅:{}", order.getDeliverySn());
+                                logger.info("物流重新订阅:{}", order.getDeliverySn());
                             }
                             }
 
 
                         }
                         }
@@ -1954,6 +1989,23 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         return fsStoreOrderMapper.selectFsStoreOrderListByDeliverySn(logisticCode);
         return fsStoreOrderMapper.selectFsStoreOrderListByDeliverySn(logisticCode);
     }
     }
 
 
+    public static R requestExpressInfo(Long orderId){
+        String fileUrl = "http://ipad.cdwjyyh.com/msg/sendExpressInfo/" + orderId;
+
+        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+            HttpGet httpGet = new HttpGet(fileUrl);
+            HttpResponse response = httpClient.execute(httpGet);
+
+            // 检查响应状态码
+            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+                return R.ok();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
     @Override
     @Override
     @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
     @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
     public R syncExpress(Long id) {
     public R syncExpress(Long id) {
@@ -2598,21 +2650,43 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             return R.error("订单状态不正确");
             return R.error("订单状态不正确");
         }
         }
 
 
+//        FsUser user = userService.selectFsUserByUserId(param.getUserId());
+//
+//        //在线支付
+//        String json = configService.selectConfigByKey("his.pay");
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//
+//        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+//        if (StringUtils.isBlank(openId)){
+//            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+//                    .eq(FsUserWx::getFsUserId, param.getUserId())
+//                    .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+//            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+//            if (Objects.nonNull(fsUserWx)){
+//                openId = fsUserWx.getOpenId();
+//            }
+//        }
         FsUser user = userService.selectFsUserByUserId(param.getUserId());
         FsUser user = userService.selectFsUserByUserId(param.getUserId());
-
         //在线支付
         //在线支付
         String json = configService.selectConfigByKey("his.pay");
         String json = configService.selectConfigByKey("his.pay");
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
-
-        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
-        if (StringUtils.isBlank(openId)){
-            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
-                    .eq(FsUserWx::getFsUserId, param.getUserId())
-                    .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
-            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
-            if (Objects.nonNull(fsUserWx)){
+        String openId = "";
+        if (StringUtils.isNotEmpty(param.getAppId())) {
+            FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), param.getUserId(), 1);
+            if (fsUserWx != null) {
                 openId = fsUserWx.getOpenId();
                 openId = fsUserWx.getOpenId();
             }
             }
+        } else {
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
         }
         }
 
 
         if (user != null && StringUtils.isNotEmpty(openId)) {
         if (user != null && StringUtils.isNotEmpty(openId)) {

+ 7 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -40,8 +40,10 @@ import com.fs.his.config.IntegralConfig;
 import com.fs.his.domain.*;
 import com.fs.his.domain.*;
 import com.fs.his.domain.FsUserAddress;
 import com.fs.his.domain.FsUserAddress;
 import com.fs.his.domain.FsUserIntegralLogs;
 import com.fs.his.domain.FsUserIntegralLogs;
+import com.fs.his.dto.FindUsersByDTO;
 import com.fs.his.enums.FsUserIntegralLogTypeEnum;
 import com.fs.his.enums.FsUserIntegralLogTypeEnum;
 import com.fs.his.mapper.*;
 import com.fs.his.mapper.*;
+import com.fs.his.param.FindUserByParam;
 import com.fs.his.param.FsUserAddIntegralTemplateParam;
 import com.fs.his.param.FsUserAddIntegralTemplateParam;
 import com.fs.his.param.FsUserParam;
 import com.fs.his.param.FsUserParam;
 import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.service.IFsUserIntegralLogsService;
@@ -173,6 +175,11 @@ public class FsUserServiceImpl implements IFsUserService
         return fsUserMapper.selectFsUserByUserId(userId);
         return fsUserMapper.selectFsUserByUserId(userId);
     }
     }
 
 
+    @Override
+    public List<FindUsersByDTO> findUserByParam(FindUserByParam param) {
+        return fsUserMapper.findUsersByParam(param);
+    }
+
     /**
     /**
      * 查询用户列表
      * 查询用户列表
      *
      *

+ 33 - 0
fs-service/src/main/java/com/fs/his/vo/FsDiagnosisListDVO.java

@@ -0,0 +1,33 @@
+package com.fs.his.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class FsDiagnosisListDVO {
+
+    private Long id;
+
+    private Long doctorId;
+
+    private String patientName;
+
+    private Integer gender;
+
+    private String phone;
+
+    private String firstDiagnosis;
+
+    private String age;
+
+    private String physicalCondition;
+
+    /** 日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date dateTime;
+
+    private Integer doctorStatus;
+    private Integer userStatus;
+}

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

@@ -32,5 +32,7 @@ public class FsDoctorArticleUVO implements Serializable {
     private Date createTime;
     private Date createTime;
     private String videoUrl;
     private String videoUrl;
 
 
+    private String fileId; //vod文件id
+
 
 
 }
 }

+ 81 - 0
fs-service/src/main/java/com/fs/his/vo/FsFirstDiagnosisVO.java

@@ -0,0 +1,81 @@
+package com.fs.his.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class FsFirstDiagnosisVO {
+    /** $column.columnComment */
+    private Long id;
+
+    /** 患者姓名 */
+    @Excel(name = "患者姓名")
+    private String patientName;
+
+    /** 年龄 */
+    @Excel(name = "年龄")
+    private String age;
+
+    /** 0-未知 1-男性 2-女性 */
+    @Excel(name = "性别",readConverterExp = "0=未知,1=男,2=女")
+    private Long gender;
+
+    /** 电话 */
+    @Excel(name = "电话")
+    private String phone;
+
+    /** 身体状况 */
+    @Excel(name = "身体状况")
+    private String physicalCondition;
+
+    /** 日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "日期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date dateTime;
+
+    /** 出版诊断 */
+    @Excel(name = "出版诊断")
+    private String firstDiagnosis;
+
+    /** 医生id */
+    @Excel(name = "医生id")
+    private Long doctorId;
+
+    /** 医生名称 */
+    @Excel(name = "医生名称")
+    private String doctorName;
+
+    /** 职称 */
+    @Excel(name = "职称")
+    private String doctorDep;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 医生证号 */
+    @Excel(name = "医生证号")
+    private String doctorCertificate;
+
+    /** 医生是否填写:0-未填写 1-已填写 */
+    @Excel(name = "")
+    private Integer doctorStatus;
+
+    /** 用户是否答复:0-未答复 1-已答复 */
+    private Integer userStatus;
+
+    /**
+     * 销售id
+     */
+    private Long qwUserId;
+
+    /**
+     * 销售名称
+     */
+    private String qwUserName;
+
+    private String userName;
+}

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

@@ -756,7 +756,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService
             if (flag==0) {
             if (flag==0) {
                 return R.error("订单创建失败");
                 return R.error("订单创建失败");
             }
             }
-            if (!isPay){
+            if (!isPay && storeOrder.getCompanyId()!=null){
                 // 添加订单审核
                 // 添加订单审核
                 addOrderAudit(storeOrder);
                 addOrderAudit(storeOrder);
             }
             }

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

@@ -182,8 +182,10 @@ public class FsStoreProductScrmServiceImpl implements IFsStoreProductScrmService
                 String[] split = item.getCompanyIds().split(",");
                 String[] split = item.getCompanyIds().split(",");
 
 
                 for (String companyId : split) {
                 for (String companyId : split) {
-                    String companyName = companyCacheService.selectCompanyNameById(Long.valueOf(companyId));
-                    companyNameList.add(companyName);
+                    if(StringUtils.isNotBlank(companyId)) {
+                        String companyName = companyCacheService.selectCompanyNameById(Long.valueOf(companyId));
+                        companyNameList.add(companyName);
+                    }
                 }
                 }
                 item.setCompanyName(String.join(",",companyNameList));
                 item.setCompanyName(String.join(",",companyNameList));
             }
             }

+ 3 - 0
fs-service/src/main/java/com/fs/qw/domain/QwExternalContact.java

@@ -145,4 +145,7 @@ public class QwExternalContact extends BaseEntity
     // 是否已购0 否 1程序内下单 2程序外下单
     // 是否已购0 否 1程序内下单 2程序外下单
     private Integer payOrder;
     private Integer payOrder;
 
 
+    //用户是否回复  0未回复  1已回复
+    private Integer isReply;
+
 }
 }

+ 4 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java

@@ -433,4 +433,8 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
     int insertQwUserDelLossLog(@Param("param") QwUserDelLossLog qwUserDelLossLog);
     int insertQwUserDelLossLog(@Param("param") QwUserDelLossLog qwUserDelLossLog);
 
 
     List<QwUserDelLossLogVO> selectQwUserDelLossList(@Param("param") QwUserDelLossLogParam param);
     List<QwUserDelLossLogVO> selectQwUserDelLossList(@Param("param") QwUserDelLossLogParam param);
+
+    List<QwExternalContact> selectQwExternalContactByFsUserIdAndCompany(@Param("userId")Long userId,@Param("companyUserId") Long companyUserId);
+
+    void updateQwExternalContactIsRePlyById(@Param("id")Long id);
 }
 }

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