24 Commits d2581c5d88 ... fc553a33a8

Author SHA1 Message Date
  caoliqin fc553a33a8 Merge branch 'refs/heads/master' into openIm 3 days ago
  caoliqin 9f2b0ae771 Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java 3 days ago
  zyp 71e63cc3f2 Merge remote-tracking branch 'origin/master' 3 days ago
  zyp ab9f6ea65f zyp 3 days ago
  jzp e258485949 1.提交ai对话配套的后端代码 3 days ago
  ct e83314dda1 add:会员看课统计添加上线数 4 days ago
  caoliqin 3beb33550b feat:小程序评论添加头像返回 4 days ago
  Long 01cf544025 问诊和套餐包下单前计算openid判断红德堂特殊处理 4 days ago
  caoliqin 1ac2dda08b Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java 4 days ago
  caoliqin 79e1e4b9d0 feat:修复companyapp redis的hash序列化问题(不确定其他服务是否存在此问题) 4 days ago
  wjj ff8bc78518 1.小程序问诊单新增返回数据 4 days ago
  ct 1cdef1a408 Merge remote-tracking branch 'origin/master' 5 days ago
  ct 77eb9cfb77 fix:销售查询今日课程,会员看课统计 5 days ago
  wjj a3a51f5536 用户确认初诊单 5 days ago
  wjj b0461741e2 fixBug:修复初诊单,问诊单BUG 5 days ago
  wjj 8c03792497 医生填写初诊单 5 days ago
  yjwang 7b24c69a8c 汇付回调还原2 5 days ago
  yjwang 3318c00420 Merge remote-tracking branch 'origin/master' 5 days ago
  yjwang 784c9fe360 汇付回调还原 5 days ago
  wjj a1e45b0fd8 merge 5 days ago
  wjj ebd0440909 初诊单,问诊单小程序接口 5 days ago
  sgw 0f146ca7de 修改数据库最大连接数配置/getVideoDuration 方法 5 days ago
  三七 5d338720ab 管理端 重置 销售密码bug 6 days ago
  三七 bfcdc6c117 益寿源-自定义小程序 6 days ago
69 changed files with 3278 additions and 198 deletions
  1. 20 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchCommentController.java
  2. 1 0
      fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  3. 97 0
      fs-admin/src/main/java/com/fs/fastGpt/FastGptChatReplaceTextController.java
  4. 112 0
      fs-admin/src/main/java/com/fs/fastGpt/FastGptKeywordSendController.java
  5. 139 0
      fs-admin/src/main/java/com/fs/fastGpt/FastgptEventLogTotalController.java
  6. 224 5
      fs-admin/src/main/java/com/fs/his/task/Task.java
  7. 4 0
      fs-company-app/src/main/java/com/fs/core/config/RedisConfig.java
  8. 24 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  9. 1 0
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java
  10. 1 0
      fs-company/src/main/java/com/fs/company/controller/course/qw/FsQwCourseWatchLogController.java
  11. 134 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptKeywordSendController.java
  12. 148 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastgptEventLogTotalController.java
  13. 1 0
      fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java
  14. 1 0
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  15. 1 1
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  16. 118 41
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  17. 52 16
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  18. 5 0
      fs-service/src/main/java/com/fs/company/domain/Company.java
  19. 3 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  20. 7 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  21. 5 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  22. 36 6
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  23. 2 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogStatisticsListParam.java
  24. 3 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchCommentVO.java
  25. 96 0
      fs-service/src/main/java/com/fs/fastGpt/domain/FastGptChatReplaceText.java
  26. 2 0
      fs-service/src/main/java/com/fs/fastGpt/domain/FastGptRole.java
  27. 68 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptChatReplaceTextMapper.java
  28. 10 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptRoleMapper.java
  29. 93 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastgptEventLogTotalMapper.java
  30. 76 0
      fs-service/src/main/java/com/fs/fastGpt/param/FastgptEventLogTotalParam.java
  31. 62 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastGptChatReplaceTextService.java
  32. 8 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastGptRoleService.java
  33. 94 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastgptEventLogTotalService.java
  34. 67 30
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java
  35. 0 2
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptChatMsgServiceImpl.java
  36. 93 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptChatReplaceTextServiceImpl.java
  37. 77 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptRoleServiceImpl.java
  38. 290 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptEventLogTotalServiceImpl.java
  39. 19 0
      fs-service/src/main/java/com/fs/fastGpt/vo/FastGptRoleDataVO.java
  40. 70 0
      fs-service/src/main/java/com/fs/fastGpt/vo/FastgptEventLogTotalVo.java
  41. 110 8
      fs-service/src/main/java/com/fs/fastgptApi/util/AiImgUtil.java
  42. 2 2
      fs-service/src/main/java/com/fs/fastgptApi/util/EventLogUtils.java
  43. 20 1
      fs-service/src/main/java/com/fs/gtPush/domain/PushReqBean.java
  44. 93 0
      fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java
  45. 4 0
      fs-service/src/main/java/com/fs/gtPush/service/uniPush2Service.java
  46. 120 0
      fs-service/src/main/java/com/fs/gtPush/utils/PushUtils.java
  47. 35 0
      fs-service/src/main/java/com/fs/his/enums/PushLogDesTypeEnum.java
  48. 34 0
      fs-service/src/main/java/com/fs/his/enums/PushLogTypeEnum.java
  49. 17 22
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java
  50. 84 27
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  51. 2 0
      fs-service/src/main/java/com/fs/his/vo/FsDoctorArticleUVO.java
  52. 2 0
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java
  53. 1 1
      fs-service/src/main/java/com/fs/qw/service/IQwExternalContactService.java
  54. 26 5
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  55. 1 1
      fs-service/src/main/java/com/fs/qw/vo/QwSopTempSetting.java
  56. 1 1
      fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java
  57. 58 5
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  58. 45 0
      fs-service/src/main/java/com/fs/utils/SensitiveDataUtils.java
  59. 5 5
      fs-service/src/main/resources/application-druid-jzzx.yml
  60. 5 5
      fs-service/src/main/resources/application-druid-kyt.yml
  61. 17 1
      fs-service/src/main/resources/mapper/company/CompanyMapper.xml
  62. 2 2
      fs-service/src/main/resources/mapper/course/FsCourseWatchCommentMapper.xml
  63. 1 1
      fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml
  64. 80 0
      fs-service/src/main/resources/mapper/fastGpt/FastGptChatReplaceTextMapper.xml
  65. 24 0
      fs-service/src/main/resources/mapper/fastGpt/FastGptRoleMapper.xml
  66. 211 0
      fs-service/src/main/resources/mapper/fastGpt/FastgptEventLogTotalMapper.xml
  67. 5 1
      fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml
  68. 1 0
      fs-user-app/src/main/java/com/fs/app/controller/DoctorArticleController.java
  69. 8 8
      fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

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

+ 224 - 5
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -28,7 +28,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;
@@ -61,11 +64,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.RedisTemplate;
 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.stream.Collectors;
+import java.util.*;
 
 
 @Slf4j
 @Slf4j
 @Component("task")
 @Component("task")
@@ -169,6 +168,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); // 昨天

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

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

+ 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()

+ 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/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;

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

@@ -5,6 +5,7 @@ import java.util.List;
 import java.util.Set;
 import 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;
@@ -189,4 +190,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);
 }
 }

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

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

@@ -1320,4 +1320,9 @@ public class CompanyServiceImpl implements ICompanyService
             }
             }
         }
         }
     }
     }
+
+    @Override
+    public List<CompanyUser> selectCompanyListByIds(String result) {
+        return companyMapper.selectCompanyListByIds(result);
+    }
 }
 }

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

@@ -220,32 +220,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 企微
 }
 }

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

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

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

+ 67 - 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,10 +441,12 @@ 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);
@@ -455,7 +461,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 +478,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 +523,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 +533,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 +584,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);
             }
             }
         }
         }
@@ -636,7 +651,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 +677,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 +694,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 +828,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,20 +2,39 @@ 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.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.JsonProcessingException;
 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.im.service.OpenIMService;
 import com.fs.im.service.OpenIMService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
+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 {
     @Autowired
     @Autowired
     private OpenIMService openIMService;
     private OpenIMService openIMService;
     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());
@@ -30,4 +49,78 @@ public class uniPush2ServiceImpl implements uniPush2Service {
         }
         }
 
 
     }
     }
+
+    @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

@@ -7,6 +7,10 @@ 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);
     void pushSopAppLinkMsgByExternalIM(String cropId,String linkTile,String linkDescribe,String linkImageUrl,String link,Long companyUserId,Long fsUserId) throws JsonProcessingException;
     void pushSopAppLinkMsgByExternalIM(String cropId,String linkTile,String linkDescribe,String linkImageUrl,String link,Long companyUserId,Long fsUserId) throws JsonProcessingException;
 
 
 }
 }

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

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

+ 17 - 22
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;
@@ -315,28 +312,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("无效的类型参数");
         }
         }

+ 84 - 27
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
@@ -273,6 +280,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Value("${express.omsCode}")
     @Value("${express.omsCode}")
     private String expressOmsCode;
     private String expressOmsCode;
 
 
+    @Autowired
+    private com.fs.gtPush.service.uniPush2Service uniPush2Service;
+
     /**
     /**
      * 查询订单
      * 查询订单
      *
      *
@@ -1405,10 +1415,10 @@ 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 + "待支付");
@@ -1431,31 +1441,30 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                         }
                         }
                         fsStorePaymentMapper.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())) {
             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();
             }
             }
-            FsStoreOrder order1=new FsStoreOrder();
-            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);
+            FsStoreOrder storeOrder = new FsStoreOrder();
+            storeOrder.setOrderId(order.getOrderId());
+            storeOrder.setIsPay(1);
             storeOrder.setStatus(2);
             storeOrder.setStatus(2);
             storeOrder.setPrescribePrice(order.getTotalPrice());
             storeOrder.setPrescribePrice(order.getTotalPrice());
             SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
             SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
@@ -1476,13 +1485,13 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 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);
@@ -1887,7 +1896,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) {
@@ -1895,8 +1904,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();
@@ -1907,16 +1916,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("七天内无轨迹变化"))) {
                                 //订阅物流回调
                                 //订阅物流回调
@@ -1928,7 +1968,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());
                             }
                             }
 
 
                         }
                         }
@@ -1946,6 +1986,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) {

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

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

@@ -434,4 +434,6 @@ 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);
 }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/qw/service/IQwExternalContactService.java

@@ -232,7 +232,7 @@ public interface IQwExternalContactService extends IService<QwExternalContact> {
      */
      */
     int updateExternalContactTag(TagGroupUpdateParam param);
     int updateExternalContactTag(TagGroupUpdateParam param);
 
 
-    List<QwExternalContact> selectQwExternalContactByFsUserId(Long userId);
+    List<QwExternalContact> selectQwExternalContactByFsUserIdAndCompany(Long userId,Long companyUserId);
 
 
     /**
     /**
      * 企微用户流失删除统计
      * 企微用户流失删除统计

+ 26 - 5
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -366,7 +366,27 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
 
 
     @Override
     @Override
     public int updateQwExternalContactByFsUserId(Integer commentStatus, Long fsUserId) {
     public int updateQwExternalContactByFsUserId(Integer commentStatus, Long fsUserId) {
-        return qwExternalContactMapper.updateQwExternalContactByFsUserId(commentStatus, fsUserId);
+        int i = qwExternalContactMapper.updateQwExternalContactByFsUserId(commentStatus, fsUserId);
+        try {
+            if (i > 0){
+                FsUser fsUser = new FsUser();
+                fsUser.setUserId(fsUserId);
+                //commentStatus是外部联系人状态 1是拉黑 0是正常
+                if(commentStatus == 1){
+                    //fsUser的状态 0是拉黑 1是正常
+                    fsUser.setStatus(0);
+                    fsUser.setRemark("投诉拉黑外部联系人用户成功");
+                    logger.error("投诉拉黑外部联系人用户成功:{}",fsUserId);
+                }else{
+                    fsUser.setStatus(1);
+                    logger.error("投诉解除拉黑外部联系人用户成功:{}",fsUserId);
+                }
+                fsUserMapper.updateFsUser(fsUser);
+            }
+        } catch (Exception e) {
+            logger.error("更新用户状态失败:{},{}", e.getMessage(),fsUserId);
+        }
+        return i;
     }
     }
 
 
     @Override
     @Override
@@ -5513,6 +5533,11 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         return 0;
         return 0;
     }
     }
 
 
+    @Override
+    public List<QwExternalContact> selectQwExternalContactByFsUserIdAndCompany(Long userId, Long companyUserId) {
+        return qwExternalContactMapper.selectQwExternalContactByFsUserIdAndCompany(userId,companyUserId);
+    }
+
 
 
     //发送好友欢迎语
     //发送好友欢迎语
        void   SyncAddSendWelcome(QwExternalContact qwExternalContact, QwUser qwUser, String corpId){
        void   SyncAddSendWelcome(QwExternalContact qwExternalContact, QwUser qwUser, String corpId){
@@ -5627,10 +5652,6 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         }
         }
     }
     }
 
 
-    @Override
-    public List<QwExternalContact> selectQwExternalContactByFsUserId(Long userId) {
-        return qwExternalContactMapper.selectQwExternalContactByFsUserId(userId);
-    }
 
 
     @Override
     @Override
     public List<QwUserDelLossLogVO> selectQwUserDelLossLogList(QwUserDelLossLogParam param) {
     public List<QwUserDelLossLogVO> selectQwUserDelLossLogList(QwUserDelLossLogParam param) {

+ 1 - 1
fs-service/src/main/java/com/fs/qw/vo/QwSopTempSetting.java

@@ -81,7 +81,7 @@ public class QwSopTempSetting implements Serializable{
              * 客户的id(用于发送)
              * 客户的id(用于发送)
              */
              */
             private String externalUserId;
             private String externalUserId;
-            //文本-图片-链接-小程序-文件-视频-语音-视频号-app
+            //文本-图片-链接-小程序-文件-视频-语音-视频号-app-自定义小程序
             private String contentType;
             private String contentType;
             //文本
             //文本
             private String value;
             private String value;

+ 1 - 1
fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java

@@ -321,7 +321,7 @@ public interface QwSopLogsMapper extends BaseMapper<QwSopLogs> {
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
     List<QwSopLogs> selectIpadByCorpId(@Param("corpId") String corpId, @Param("now") LocalDateTime now);
     List<QwSopLogs> selectIpadByCorpId(@Param("corpId") String corpId, @Param("now") LocalDateTime now);
 
 
-    @DataSource(DataSourceType.SopREAD)
+    @DataSource(DataSourceType.SOP)
     List<QwSopLogs> selectByQwUserId(@Param("id") Long id);
     List<QwSopLogs> selectByQwUserId(@Param("id") Long id);
 
 
     @Select("select * from qw_sop_logs where send_type=8 and send_status=3 and  create_time <= DATE_SUB(NOW(), INTERVAL 2 HOUR) ")
     @Select("select * from qw_sop_logs where send_type=8 and send_status=3 and  create_time <= DATE_SUB(NOW(), INTERVAL 2 HOUR) ")

+ 58 - 5
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -9,7 +9,9 @@ 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.common.utils.date.DateUtil;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyMiniapp;
 import com.fs.company.domain.CompanyMiniapp;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.config.cloud.CloudHostProper;
@@ -162,6 +164,10 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     @Autowired
     @Autowired
     private CloudHostProper cloudHostProper;
     private CloudHostProper cloudHostProper;
 
 
+    @Autowired
+    private CompanyMapper companyMapper;
+
+
     @Override
     @Override
     public void save(SopUserLogsInfo sopUserLogsInfo) {
     public void save(SopUserLogsInfo sopUserLogsInfo) {
         sopUserLogsInfoMapper.insertSopUserLogsInfo(sopUserLogsInfo);
         sopUserLogsInfoMapper.insertSopUserLogsInfo(sopUserLogsInfo);
@@ -751,10 +757,11 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                 return R.error().put("msg","企业微信用户不存在未绑定销售公司-请绑定后重试:"+qwUser.getQwUserName()+"|"+qwUser.getQwUserId());
                 return R.error().put("msg","企业微信用户不存在未绑定销售公司-请绑定后重试:"+qwUser.getQwUserName()+"|"+qwUser.getQwUserId());
             }
             }
 
 
+            Company company = companyMapper.selectCompanyById(qwUser.getCompanyId());
+
             String companyUserId = String.valueOf(qwUser.getCompanyUserId()).trim();
             String companyUserId = String.valueOf(qwUser.getCompanyUserId()).trim();
             String companyId = String.valueOf(qwUser.getCompanyId()).trim();
             String companyId = String.valueOf(qwUser.getCompanyId()).trim();
 
 
-
             //域名
             //域名
 //            String domainName = companyUserMapper.selectDomainByUserId(Long.parseLong(companyUserId));
 //            String domainName = companyUserMapper.selectDomainByUserId(Long.parseLong(companyUserId));
 //            if (StringUtils.isEmpty(domainName)){
 //            if (StringUtils.isEmpty(domainName)){
@@ -892,6 +899,23 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             st.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
                             st.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
                             st.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));
                             st.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));
 
 
+                            break;
+                        //自定义小程序
+                        case "10":
+                            addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),item.getStartTime(),createTime );
+                            if (company!=null){
+
+                                String customMiniAppId = company.getCustomMiniAppId();
+
+                                if (customMiniAppId != null && !customMiniAppId.trim().isEmpty()) {
+                                    st.setMiniprogramAppid(customMiniAppId);
+                                } else {
+                                    st.setMiniprogramAppid("该公司未配置自定义小程序:"+companyId);
+                                }
+                            }else {
+                                st.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
+                            }
+
                             break;
                             break;
                         default:
                         default:
                             break;
                             break;
@@ -997,6 +1021,9 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         List<CompanyMiniapp> miniList = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().orderByAsc("sort_num"));
         List<CompanyMiniapp> miniList = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().orderByAsc("sort_num"));
         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();
+
         //排序
         //排序
         int sort = 0;
         int sort = 0;
         //发送类型
         //发送类型
@@ -1038,7 +1065,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
 
                 if (qwUser.getCompanyUserId()!=null && qwUser.getCompanyId()!=null){
                 if (qwUser.getCompanyUserId()!=null && qwUser.getCompanyId()!=null){
                     List<QwSopLogs> sopLogsList = processInsertSopUserLogsInfo(logs, qwUser, param, words, config, qwCompany, finalSort,
                     List<QwSopLogs> sopLogsList = processInsertSopUserLogsInfo(logs, qwUser, param, words, config, qwCompany, finalSort,
-                            finalSendType,miniMap );
+                            finalSendType,miniMap,companies);
 
 
                     //批量插入 发送记录
                     //批量插入 发送记录
                     if (!sopLogsList.isEmpty()) {
                     if (!sopLogsList.isEmpty()) {
@@ -1061,7 +1088,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     private List<QwSopLogs> processInsertSopUserLogsInfo(List<SopUserLogsInfo> sopUserLogsInfos,QwUser qwUser,
     private List<QwSopLogs> processInsertSopUserLogsInfo(List<SopUserLogsInfo> sopUserLogsInfos,QwUser qwUser,
                                                          SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                          SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                          CourseConfig config,QwCompany qwCompany,int finalSort,int finalSendType,
                                                          CourseConfig config,QwCompany qwCompany,int finalSort,int finalSendType,
-                                                         Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap){
+                                                         Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,List<Company> companies ){
 
 
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
 
@@ -1116,7 +1143,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
             switch (finalSendType){
             switch (finalSendType){
                 case 5:
                 case 5:
                     List<QwSopCourseFinishTempSetting.Setting> list = processSetting(item,qwUser, param, words, config, qwCompany,companyUserId,companyId,
                     List<QwSopCourseFinishTempSetting.Setting> list = processSetting(item,qwUser, param, words, config, qwCompany,companyUserId,companyId,
-                            contact,dataTime, finalDomainName,miniMap);
+                            contact,dataTime, finalDomainName,miniMap,companies);
                     setting.setSetting(list);
                     setting.setSetting(list);
                     break;
                     break;
                 case 9:
                 case 9:
@@ -1179,7 +1206,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                                                       SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                                       SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                                       CourseConfig config,QwCompany qwCompany,String companyUserId, String companyId,
                                                                       CourseConfig config,QwCompany qwCompany,String companyUserId, String companyId,
                                                                       QwExternalContact contact,Date dataTime,String domainName,
                                                                       QwExternalContact contact,Date dataTime,String domainName,
-                                                                      Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap){
+                                                                      Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
+                                                                      List<Company> companies ){
         List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
         List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
 
 
         for (QwSopCourseFinishTempSetting.Setting st : list) {
         for (QwSopCourseFinishTempSetting.Setting st : list) {
@@ -1273,6 +1301,31 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
 
                     st.setMiniprogramPage(linkByMiniApp);
                     st.setMiniprogramPage(linkByMiniApp);
                     break;
                     break;
+
+                //自定义小程序
+                case "10":
+
+                    addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), String.valueOf(qwUser.getId()), companyUserId, companyId,
+                            item.getExternalId(),item.getStartTime(),dataTime );
+
+                    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()) {
+                            st.setMiniprogramAppid(customMiniAppId);
+                        } else {
+                            st.setMiniprogramAppid("该公司未配置自定义小程序:"+companyId);
+                        }
+                    } else {
+                        st.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
+                    }
+
+                    break;
                 default:
                 default:
                     break;
                     break;
 
 

+ 45 - 0
fs-service/src/main/java/com/fs/utils/SensitiveDataUtils.java

@@ -0,0 +1,45 @@
+package com.fs.utils;
+
+import java.util.Random;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class SensitiveDataUtils {
+
+    private static final Pattern MOBILE_PATTERN = Pattern.compile("(?<!\\d)1[3-9]\\d{9}(?!\\d)");
+
+
+
+    /**
+     * 对文本中的手机号进行脱敏处理,保留前3位,后8位随机替换
+     */
+    public static String maskMobileNumbers(String content) {
+        try {
+            if (content == null || content.isEmpty()) {
+                return content;
+            }
+
+            Matcher matcher = MOBILE_PATTERN.matcher(content);
+            StringBuffer sb = new StringBuffer();
+
+            while (matcher.find()) {
+                String maskedMobile = getPhoneNumber();
+                matcher.appendReplacement(sb, maskedMobile);
+            }
+
+            matcher.appendTail(sb);
+            return sb.toString();
+        } catch (Exception e) {
+            return content;
+        }
+    }
+
+    private static String getPhoneNumber() {
+        String phoneNumbers = "16623962137,15523238506,17749925835,15923875456,18305948549,13883332012,15057469844,13618796139,18620430041,18584668114,18580017521,15111845257,15275039316,18201444980,18813118010,17726645677,15223482407,17623042467,15123822149,18623062201,17749925836,18323465069,18580176027,13452385636,13608870842,17685274759,15315437944,15998971322,18623079553,15025306414,18623592546,17264203997,18983650852,19823410818,15528133197,18987692003,15364612795,15364612795,17782358851,13452011251,13527318467,13637935049,15123970077,18166348566,13668096347,18883781302,18780014073,18602325964,15086929910,15320525962,15210865639,13671138824,19936630315,18223553039,18290561680,18883557568,18280114551,15086823485,18280406822,15084440304,18680821042,19115284897,15823539658,13718194200,13521390467,18253105683,15866702785,18697568671,13435694935,17347643607,15002351429,13640582745,18716432052,13167916563,15523238507,14678903116,18324157410,18121887854,19923671431,17388206297,18225226941,15111111111,18324199200,15223337413,13633333333,15523524367,15376779826,18580137367,13983381612,15523004683,18996016507,15683164217,19946754704,13983370856,15870485887,18280237531,15223298047,18580466998,15923377066,17353257273,18067773557,18103269005,17775537029,15730089438,13668480682,13183501165,13101083915,19102330681,15084400940";
+        String[] split = phoneNumbers.split(",");
+        return split[new Random().nextInt(split.length)];
+    }
+
+
+
+}

+ 5 - 5
fs-service/src/main/resources/application-druid-jzzx.yml

@@ -21,7 +21,7 @@ spring:
                 # 连接池中的最大空闲连接
                 # 连接池中的最大空闲连接
                 max-idle: 8
                 max-idle: 8
                 # 连接池的最大数据库连接数
                 # 连接池的最大数据库连接数
-                max-active: 8
+                max-active: 100
                 # #连接池最大阻塞等待时间(使用负值表示没有限制)
                 # #连接池最大阻塞等待时间(使用负值表示没有限制)
                 max-wait: -1ms
                 max-wait: -1ms
     datasource:
     datasource:
@@ -56,7 +56,7 @@ spring:
                 # 最小连接池数量
                 # 最小连接池数量
                 minIdle: 10
                 minIdle: 10
                 # 最大连接池数量
                 # 最大连接池数量
-                maxActive: 20
+                maxActive: 200
                 # 配置获取连接等待超时的时间
                 # 配置获取连接等待超时的时间
                 maxWait: 60000
                 maxWait: 60000
                 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
                 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
@@ -73,7 +73,7 @@ spring:
                 webStatFilter:
                 webStatFilter:
                     enabled: true
                     enabled: true
                 statViewServlet:
                 statViewServlet:
-                    enabled: true
+                    enabled: false
                     # 设置白名单,不填则允许所有访问
                     # 设置白名单,不填则允许所有访问
                     allow:
                     allow:
                     url-pattern: /druid/*
                     url-pattern: /druid/*
@@ -108,7 +108,7 @@ spring:
                 # 最小连接池数量
                 # 最小连接池数量
                 minIdle: 10
                 minIdle: 10
                 # 最大连接池数量
                 # 最大连接池数量
-                maxActive: 20
+                maxActive: 200
                 # 配置获取连接等待超时的时间
                 # 配置获取连接等待超时的时间
                 maxWait: 60000
                 maxWait: 60000
                 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
                 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
@@ -125,7 +125,7 @@ spring:
                 webStatFilter:
                 webStatFilter:
                     enabled: true
                     enabled: true
                 statViewServlet:
                 statViewServlet:
-                    enabled: true
+                    enabled: false
                     # 设置白名单,不填则允许所有访问
                     # 设置白名单,不填则允许所有访问
                     allow:
                     allow:
                     url-pattern: /druid/*
                     url-pattern: /druid/*

+ 5 - 5
fs-service/src/main/resources/application-druid-kyt.yml

@@ -22,7 +22,7 @@ spring:
         # 连接池中的最大空闲连接
         # 连接池中的最大空闲连接
         max-idle: 8
         max-idle: 8
         # 连接池的最大数据库连接数
         # 连接池的最大数据库连接数
-        max-active: 8
+        max-active: 100
         # #连接池最大阻塞等待时间(使用负值表示没有限制)
         # #连接池最大阻塞等待时间(使用负值表示没有限制)
         max-wait: -1ms
         max-wait: -1ms
     database: 0
     database: 0
@@ -49,7 +49,7 @@ spring:
         # 最小连接池数量
         # 最小连接池数量
         minIdle: 10
         minIdle: 10
         # 最大连接池数量
         # 最大连接池数量
-        maxActive: 20
+        maxActive: 200
         # 配置获取连接等待超时的时间
         # 配置获取连接等待超时的时间
         maxWait: 60000
         maxWait: 60000
         # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
         # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
@@ -66,7 +66,7 @@ spring:
         webStatFilter:
         webStatFilter:
           enabled: true
           enabled: true
         statViewServlet:
         statViewServlet:
-          enabled: true
+          enabled: false
           # 设置白名单,不填则允许所有访问
           # 设置白名单,不填则允许所有访问
           allow:
           allow:
           url-pattern: /druid/*
           url-pattern: /druid/*
@@ -98,7 +98,7 @@ spring:
         # 最小连接池数量
         # 最小连接池数量
         minIdle: 10
         minIdle: 10
         # 最大连接池数量
         # 最大连接池数量
-        maxActive: 20
+        maxActive: 200
         # 配置获取连接等待超时的时间
         # 配置获取连接等待超时的时间
         maxWait: 60000
         maxWait: 60000
         # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
         # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
@@ -115,7 +115,7 @@ spring:
         webStatFilter:
         webStatFilter:
           enabled: true
           enabled: true
         statViewServlet:
         statViewServlet:
-          enabled: true
+          enabled: false
           # 设置白名单,不填则允许所有访问
           # 设置白名单,不填则允许所有访问
           allow:
           allow:
           url-pattern: /druid/*
           url-pattern: /druid/*

+ 17 - 1
fs-service/src/main/resources/mapper/company/CompanyMapper.xml

@@ -35,6 +35,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="packageCateIds"    column="package_cate_ids"    />
         <result property="packageCateIds"    column="package_cate_ids"    />
         <result property="courseMaAppId"    column="course_ma_app_id"    />
         <result property="courseMaAppId"    column="course_ma_app_id"    />
         <result property="courseMiniAppId"    column="course_mini_app_id"    />
         <result property="courseMiniAppId"    column="course_mini_app_id"    />
+        <result property="customMiniAppId"    column="custom_mini_app_id"    />
         <result property="repeat"    column="repeat"    />
         <result property="repeat"    column="repeat"    />
         <result property="sendIfType"    column="send_if_type"    />
         <result property="sendIfType"    column="send_if_type"    />
         <result property="ifNum"    column="if_num"    />
         <result property="ifNum"    column="if_num"    />
@@ -59,6 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageCateIds != null "> and package_cate_ids = #{packageCateIds}</if>
             <if test="packageCateIds != null "> and package_cate_ids = #{packageCateIds}</if>
             <if test="courseMaAppId != null "> and course_ma_app_id = #{courseMaAppId}</if>
             <if test="courseMaAppId != null "> and course_ma_app_id = #{courseMaAppId}</if>
             <if test="courseMiniAppId != null "> and course_mini_app_id = #{courseMiniAppId}</if>
             <if test="courseMiniAppId != null "> and course_mini_app_id = #{courseMiniAppId}</if>
+            <if test="customMiniAppId != null "> and custom_mini_app_id = #{customMiniAppId}</if>
         </where>
         </where>
     </select>
     </select>
 
 
@@ -73,7 +75,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
          </foreach>
          </foreach>
     </select>
     </select>
     <select id="selectCompanyAllList" resultType="com.fs.company.domain.Company">
     <select id="selectCompanyAllList" resultType="com.fs.company.domain.Company">
-        select company_id,company_name from company where is_del=0
+        select company_id,company_name,custom_mini_app_id from company where is_del=0
     </select>
     </select>
     <select id="selectDoctorIdsByCompanyId" resultType="java.lang.String">
     <select id="selectDoctorIdsByCompanyId" resultType="java.lang.String">
         select doctor_ids from company where company_id = #{companyId}
         select doctor_ids from company where company_id = #{companyId}
@@ -109,6 +111,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageCateIds != null">package_cate_ids,</if>
             <if test="packageCateIds != null">package_cate_ids,</if>
             <if test="courseMaAppId != null">course_ma_app_id,</if>
             <if test="courseMaAppId != null">course_ma_app_id,</if>
             <if test="courseMiniAppId != null">course_mini_app_id,</if>
             <if test="courseMiniAppId != null">course_mini_app_id,</if>
+            <if test="customMiniAppId != null">custom_mini_app_id,</if>
             <if test="repeat != null">`repeat`,</if>
             <if test="repeat != null">`repeat`,</if>
             <if test="sendIfType != null">send_if_type,</if>
             <if test="sendIfType != null">send_if_type,</if>
             <if test="ifNum != null">if_num,</if>
             <if test="ifNum != null">if_num,</if>
@@ -142,6 +145,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageCateIds != null">#{packageCateIds},</if>
             <if test="packageCateIds != null">#{packageCateIds},</if>
             <if test="courseMaAppId != null">#{courseMaAppId},</if>
             <if test="courseMaAppId != null">#{courseMaAppId},</if>
             <if test="courseMiniAppId != null">#{courseMiniAppId},</if>
             <if test="courseMiniAppId != null">#{courseMiniAppId},</if>
+            <if test="customMiniAppId != null">#{customMiniAppId},</if>
             <if test="repeat != null">#{repeat},</if>
             <if test="repeat != null">#{repeat},</if>
             <if test="sendIfType != null">#{sendIfType},</if>
             <if test="sendIfType != null">#{sendIfType},</if>
             <if test="ifNum != null">#{ifNum},</if>
             <if test="ifNum != null">#{ifNum},</if>
@@ -180,6 +184,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageCateIds != null">package_cate_ids = #{packageCateIds},</if>
             <if test="packageCateIds != null">package_cate_ids = #{packageCateIds},</if>
             <if test="courseMaAppId != null">course_ma_app_id = #{courseMaAppId},</if>
             <if test="courseMaAppId != null">course_ma_app_id = #{courseMaAppId},</if>
             <if test="courseMiniAppId != null">course_mini_app_id = #{courseMiniAppId},</if>
             <if test="courseMiniAppId != null">course_mini_app_id = #{courseMiniAppId},</if>
+            <if test="customMiniAppId != null">custom_mini_app_id = #{customMiniAppId},</if>
             <if test="fsUserIsDefaultBlack != null ">fs_user_is_default_black = #{fsUserIsDefaultBlack},</if>
             <if test="fsUserIsDefaultBlack != null ">fs_user_is_default_black = #{fsUserIsDefaultBlack},</if>
             <if test="repeat != null">`repeat` = #{repeat},</if>
             <if test="repeat != null">`repeat` = #{repeat},</if>
             <if test="sendIfType != null">send_if_type = #{sendIfType},</if>
             <if test="sendIfType != null">send_if_type = #{sendIfType},</if>
@@ -222,5 +227,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{companyId}
             #{companyId}
         </foreach>
         </foreach>
     </select>
     </select>
+    <select id="selectCompanyListByIds" resultType="com.fs.company.domain.CompanyUser">
+        select role_id roleId,role_name roleName from fastgpt_role
+        <where>
+            <if test="roleIds != null">
+                role_id in
+                <foreach collection="roleIds" item="roleId" separator="," open="(" close=")">
+                    #{roleId}
+                </foreach>
+            </if>
+        </where>
+    </select>
 
 
 </mapper>
 </mapper>

+ 2 - 2
fs-service/src/main/resources/mapper/course/FsCourseWatchCommentMapper.xml

@@ -143,7 +143,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
 
     <select id="selectH5CourseWatchComments" resultType="com.fs.course.vo.FsCourseWatchCommentVO">
     <select id="selectH5CourseWatchComments" resultType="com.fs.course.vo.FsCourseWatchCommentVO">
         select cwc.comment_id, cwc.user_id, cwc.user_type, cwc.course_id, cwc.video_id, cwc.type, cwc.content, cwc.create_time,
         select cwc.comment_id, cwc.user_id, cwc.user_type, cwc.course_id, cwc.video_id, cwc.type, cwc.content, cwc.create_time,
-        fs_user.nick_name,cwc.time,cwc.font_size, cwc.mode, cwc.color from fs_course_watch_comment cwc
+        fs_user.nick_name, fs_user.avatar, cwc.time,cwc.font_size, cwc.mode, cwc.color from fs_course_watch_comment cwc
         left join fs_user on fs_user.user_id = cwc.user_id
         left join fs_user on fs_user.user_id = cwc.user_id
         <where>
         <where>
            and cwc.is_revoke = 0
            and cwc.is_revoke = 0
@@ -161,7 +161,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select * from (
         select * from (
         select cwc.comment_id, cwc.user_id, cwc.user_type, cwc.course_id, cwc.video_id, cwc.type, cwc.content,
         select cwc.comment_id, cwc.user_id, cwc.user_type, cwc.course_id, cwc.video_id, cwc.type, cwc.content,
         cwc.create_time,
         cwc.create_time,
-        fs_user.nick_name,cwc.time,cwc.font_size, cwc.mode, cwc.color from fs_course_watch_comment cwc
+        fs_user.nick_name, fs_user.avatar,cwc.time,cwc.font_size, cwc.mode, cwc.color from fs_course_watch_comment cwc
         left join fs_user on fs_user.user_id = cwc.user_id
         left join fs_user on fs_user.user_id = cwc.user_id
         <where>
         <where>
             and cwc.is_revoke = 0
             and cwc.is_revoke = 0

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

@@ -328,7 +328,7 @@
         AND ccut.course_id = fcpd.course_id
         AND ccut.course_id = fcpd.course_id
         AND ccut.video_id = fcpd.video_id
         AND ccut.video_id = fcpd.video_id
         AND ccut.company_user_id = #{params.companyUserId}
         AND ccut.company_user_id = #{params.companyUserId}
-        where course.is_del = 0
+        where course.is_del = 0 and fcp.del_flag = '0' and fcpd.del_flag = '0'
         <if test="params.companyId != null">
         <if test="params.companyId != null">
             and FIND_IN_SET(#{params.companyId}, fcp.company_id)
             and FIND_IN_SET(#{params.companyId}, fcp.company_id)
         </if>
         </if>

+ 80 - 0
fs-service/src/main/resources/mapper/fastGpt/FastGptChatReplaceTextMapper.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.fastGpt.mapper.FastGptChatReplaceTextMapper">
+
+    <resultMap type="FastGptChatReplaceText" id="FastGptChatReplaceTextResult">
+        <result property="id"    column="id"    />
+        <result property="type"    column="type"    />
+        <result property="content"    column="content"    />
+        <result property="changeCount"    column="change_count"    />
+        <result property="status"    column="status"    />
+        <result property="sort"    column="sort"    />
+        <result property="createTime"    column="create_time"    />
+    </resultMap>
+
+    <sql id="selectFastGptChatReplaceTextVo">
+        select id, type, content, change_count, status, sort, create_time from fastgpt_chat_replace_text
+    </sql>
+
+    <select id="selectFastGptChatReplaceTextList" parameterType="FastGptChatReplaceText" resultMap="FastGptChatReplaceTextResult">
+        <include refid="selectFastGptChatReplaceTextVo"/>
+        <where>
+            <if test="type != null "> and type = #{type}</if>
+            <if test="content != null  and content != ''"> and content like concat('%', #{content}, '%')</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="sort != null "> and sort = #{sort}</if>
+        </where>
+        order by sort desc,id desc
+    </select>
+
+    <select id="selectFastGptChatReplaceTextById" parameterType="Long" resultMap="FastGptChatReplaceTextResult">
+        <include refid="selectFastGptChatReplaceTextVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertFastGptChatReplaceText" parameterType="FastGptChatReplaceText" useGeneratedKeys="true" keyProperty="id">
+        insert into fastgpt_chat_replace_text
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="type != null">type,</if>
+            <if test="content != null">content,</if>
+            <if test="changeCount != null">change_count,</if>
+            <if test="status != null">status,</if>
+            <if test="sort != null">sort,</if>
+            <if test="createTime != null">create_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="type != null">#{type},</if>
+            <if test="content != null">#{content},</if>
+            <if test="changeCount != null">#{changeCount},</if>
+            <if test="status != null">#{status},</if>
+            <if test="sort != null">#{sort},</if>
+            <if test="createTime != null">#{createTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFastGptChatReplaceText" parameterType="FastGptChatReplaceText">
+        update fastgpt_chat_replace_text
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="type != null">type = #{type},</if>
+            <if test="content != null">content = #{content},</if>
+            <if test="changeCount != null">change_count = #{changeCount},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="sort != null">sort = #{sort},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFastGptChatReplaceTextById" parameterType="Long">
+        delete from fastgpt_chat_replace_text where id = #{id}
+    </delete>
+
+    <delete id="deleteFastGptChatReplaceTextByIds" parameterType="String">
+        delete from fastgpt_chat_replace_text where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 24 - 0
fs-service/src/main/resources/mapper/fastGpt/FastGptRoleMapper.xml

@@ -48,6 +48,30 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectFastGptRoleVo"/>
         <include refid="selectFastGptRoleVo"/>
         where role_id = #{roleId}
         where role_id = #{roleId}
     </select>
     </select>
+    <select id="selectFastGptRoleByRoleIds" resultType="com.fs.fastGpt.domain.FastGptRole">
+        select role_id roleId,role_name roleName from fastgpt_role
+        <where>
+            <if test="roleIds != null">
+                role_id in
+                <foreach collection="roleIds" item="roleId" separator="," open="(" close=")">
+                    #{roleId}
+                </foreach>
+            </if>
+        </where>
+    </select>
+
+    <select id="selectFastGptRoleRoleIdsByAppKey" resultType="java.lang.String">
+        select
+            role_id as roleId
+        from fastgpt_role
+        where mode_config_json like concat('{"APPKey":"', #{appKey}, '%')
+    </select>
+
+    <select id="selectFastGptRoleAppKeyList" resultType="com.fs.fastGpt.vo.FastgptEventLogTotalVo">
+        select
+            role_id as roleId,role_name as roleName,mode_config_json as appKey
+        from fastgpt_role
+    </select>
 
 
     <insert id="insertFastGptRole" parameterType="FastGptRole" useGeneratedKeys="true" keyProperty="roleId">
     <insert id="insertFastGptRole" parameterType="FastGptRole" useGeneratedKeys="true" keyProperty="roleId">
         insert into fastgpt_role
         insert into fastgpt_role

+ 211 - 0
fs-service/src/main/resources/mapper/fastGpt/FastgptEventLogTotalMapper.xml

@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.fastGpt.mapper.FastgptEventLogTotalMapper">
+    
+    <resultMap type="FastgptEventLogTotal" id="FastgptEventLogTotalResult">
+        <result property="id"    column="id"    />
+        <result property="roleId"    column="role_id"    />
+        <result property="count"    column="count"    />
+        <result property="type"    column="type"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="qwUserId"    column="qw_user_id"    />
+        <result property="statTime"    column="stat_time"    />
+    </resultMap>
+
+    <sql id="selectFastgptEventLogTotalVo">
+        select id, role_id, `count`, `type`, company_id, company_user_id, qw_user_id, stat_time from fastgpt_event_log_total
+    </sql>
+
+    <select id="selectFastgptEventLogTotalList" parameterType="FastgptEventLogTotal" resultMap="FastgptEventLogTotalResult">
+        <include refid="selectFastgptEventLogTotalVo"/>
+        <where>
+            <if test="roleId != null "> and role_id = #{roleId}</if>
+            <if test="count != null "> and `count` = #{count}</if>
+            <if test="type != null "> and `type` = #{type}</if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="qwUserId != null "> and qw_user_id = #{qwUserId}</if>
+            <if test="beginTime != null and endTime != null"> <![CDATA[and DATE_FORMAT(create_time, '%Y-%m-%d') >= #{beginTime}
+                                                                 and DATE_FORMAT(create_time, '%Y-%m-%d') <= #{endTime} ]]></if>
+        </where>
+    </select>
+    
+    <select id="selectFastgptEventLogTotalById" parameterType="Long" resultMap="FastgptEventLogTotalResult">
+        <include refid="selectFastgptEventLogTotalVo"/>
+        where id = #{id}
+    </select>
+    <select id="selectFastgptEventLogTotalInfoList" resultType="com.fs.fastGpt.domain.FastgptEventLogTotal">
+        SELECT role_id roleId,company_id companyId,company_user_id companyUserId,qw_user_id qwUserId,event_name eventName,`type`,
+        DATE_FORMAT(create_time,'%Y-%m-%d') as statTime,sum(count) count,count(distinct sender_id) senderCount from fastgpt_event_log
+        <where>
+            <if test="roleId != null "> and role_id = #{roleId}</if>
+            <if test="roleId == null "> and role_id is not null</if>
+            <if test="createTime != null "> and DATE_FORMAT(create_time,'%Y-%m-%d') = DATE_FORMAT(#{createTime},'%Y-%m-%d')</if>
+            <if test="beginTime != null and endTime != null"> <![CDATA[and DATE_FORMAT(create_time,'%Y-%m-%d') > DATE_FORMAT(#{beginTime},'%Y-%m-%d')
+                                                                 and DATE_FORMAT(create_time,'%Y-%m-%d') <= DATE_FORMAT(#{endTime},'%Y-%m-%d') ]]></if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId == null "> and company_user_id is not null</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="qwUserId == null "> and qw_user_id is not null</if>
+            <if test="qwUserId != null "> and qw_user_id = #{qwUserId}</if>
+        </where>
+        group by role_id,company_id,company_user_id,qw_user_id,event_name,`type`,DATE_FORMAT(create_time,'%Y-%m-%d')
+        order by `type`
+    </select>
+
+    <select id="selectFastgptEventLogTotalVoInfoList" resultType="com.fs.fastGpt.domain.FastgptEventLogTotal">
+        SELECT
+            role_id roleId,type,
+            sum(count) AS count,stat_time statTime
+        FROM fastgpt_event_log_total
+        <where>
+            <if test="roleId != null "> and role_id = #{roleId}</if>
+            <if test="count != null "> and `count` = #{count}</if>
+            <if test="type != null "> and `type` = #{type}</if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="qwUserIds != null">
+                and qw_user_id in
+                <foreach collection="qwUserIds.split(',')" item="qwUserId" open="(" close=")" separator=",">
+                    #{qwUserId}
+                </foreach>
+            </if>
+            <if test="roleIds != null">
+                and role_id in
+                <foreach collection="roleIds" item="roleId" open="(" close=")" separator=",">
+                    #{roleId}
+                </foreach>
+            </if>
+            <if test="beginTime != null and endTime != null"> <![CDATA[and DATE_FORMAT(stat_time, '%Y-%m-%d') >= #{beginTime}
+                                                                 and DATE_FORMAT(stat_time, '%Y-%m-%d') <= #{endTime} ]]></if>
+        </where>
+        GROUP BY role_id,stat_time,type WITH ROLLUP
+        HAVING role_id is not null and type is not null
+    </select>
+    <select id="selectFastgptEventTokenLogTotalList" resultType="com.fs.fastGpt.domain.FastGptEventTokenLog">
+        SELECT role_id roleId,company_id companyId,company_user_id companyUserId,qw_user_id qwUserId,
+        DATE_FORMAT(create_time, '%Y-%m-%d') as statTime,sum(token_count) tokenCount from fastgpt_event_token_log
+        where token_type = 0
+            <if test="roleId != null "> and role_id = #{roleId}</if>
+            <if test="roleId == null "> and role_id is not null</if>
+            <if test="createTime != null "> and DATE_FORMAT(create_time, '%Y-%m-%d') = DATE_FORMAT(#{createTime})</if>
+            <if test="beginTime != null and endTime != null"> <![CDATA[and DATE_FORMAT(create_time, '%Y-%m-%d') > DATE_FORMAT(#{beginTime}, '%Y-%m-%d')
+                                                                 and DATE_FORMAT(create_time, '%Y-%m-%d') <= DATE_FORMAT(#{endTime}, '%Y-%m-%d') ]]></if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="companyUserId == null "> and company_user_id is not null</if>
+            <if test="qwUserId == null "> and qw_user_id is not null</if>
+            <if test="qwUserId != null "> and qw_user_id = #{qwUserId}</if>
+        group by role_id,company_id,company_user_id,qw_user_id,DATE_FORMAT(create_time, '%Y-%m-%d')
+    </select>
+
+    <select id="selectFastgptEventTokenLogTotalByRoleIdAndType" resultMap="FastgptEventLogTotalResult">
+        <include refid="selectFastgptEventLogTotalVo"/>
+        where `type` = 11
+            <if test="roleId != null "> and role_id = #{roleId}</if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="qwUserId != null "> and qw_user_id = #{qwUserId}</if>
+            <if test="statTime != null "> and stat_time = #{statTime}</if>
+    </select>
+    <select id="selectFastgptEventLogTotalByRoleIdAndType" resultMap="FastgptEventLogTotalResult">
+        <include refid="selectFastgptEventLogTotalVo"/>
+        <where>
+            <if test="roleId != null "> and role_id = #{roleId}</if>
+            <if test="type != null "> and `type` = #{type}</if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="qwUserId != null "> and qw_user_id = #{qwUserId}</if>
+            <if test="statTime != null "> and stat_time = #{statTime}</if>
+        </where>
+    </select>
+    <select id="selectFastgptEventLogTotalListByStatTime"
+            resultType="com.fs.fastGpt.vo.FastgptEventLogTotalVo">
+        SELECT fe.stat_time statTime,c.company_id companyId,c.company_name companyName,sum(`count`) `count`
+        FROM `fastgpt_event_log_total` fe left join  company c on fe.company_id = c.company_id
+        where fe.stat_time like concat(#{dateTime},'%')
+        GROUP BY fe.company_id
+        order by fe.company_id
+    </select>
+
+    <insert id="insertFastgptEventLogTotal" parameterType="FastgptEventLogTotal" useGeneratedKeys="true" keyProperty="id">
+        insert into fastgpt_event_log_total
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="roleId != null">role_id,</if>
+            <if test="count != null">`count`,</if>
+            <if test="type != null">`type`,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="qwUserId != null">qw_user_id,</if>
+            <if test="statTime != null">stat_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="roleId != null">#{roleId},</if>
+            <if test="count != null">#{count},</if>
+            <if test="type != null">#{type},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="qwUserId != null">#{qwUserId},</if>
+            <if test="statTime != null">#{statTime},</if>
+         </trim>
+    </insert>
+    <insert id="insertFastgptEventLogTotalBatch" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
+        INSERT INTO fastgpt_event_log_total
+        (role_id, `count`, `type`, company_id, company_user_id, qw_user_id, stat_time)
+        VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.roleId},
+            #{item.count},
+            #{item.type},
+            #{item.companyId},
+            #{item.companyUserId},
+            #{item.qwUserId},
+            #{item.statTime}
+            )
+        </foreach>
+    </insert>
+
+    <update id="updateFastgptEventLogTotal" parameterType="FastgptEventLogTotal">
+        update fastgpt_event_log_total
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="roleId != null">role_id = #{roleId},</if>
+            <if test="count != null">`count` = #{count},</if>
+            <if test="type != null">`type` = #{type},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="qwUserId != null">qw_user_id = #{qwUserId},</if>
+            <if test="statTime != null">stat_time = #{statTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+    <update id="updateFastgptEventLogTotalBatch" parameterType="java.util.List">
+        <foreach collection="list" item="item" separator=";">
+            UPDATE fastgpt_event_log_total
+            <set>
+                <if test="item.roleId != null">role_id = #{item.roleId},</if>
+                <if test="item.count != null">`count` = #{item.count},</if>
+                <if test="item.type != null">`type` = #{item.type},</if>
+                <if test="item.companyId != null">company_id = #{item.companyId},</if>
+                <if test="item.companyUserId != null">company_user_id = #{item.companyUserId},</if>
+                <if test="item.qwUserId != null">qw_user_id = #{item.qwUserId},</if>
+                <if test="item.statTime != null">stat_time = #{item.statTime},</if>
+            </set>
+            WHERE id = #{item.id}
+        </foreach>
+    </update>
+
+    <delete id="deleteFastgptEventLogTotalById" parameterType="Long">
+        delete from fastgpt_event_log_total where id = #{id}
+    </delete>
+
+    <delete id="deleteFastgptEventLogTotalByIds" parameterType="String">
+        delete from fastgpt_event_log_total where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 5 - 1
fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml

@@ -644,6 +644,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </if>
         </if>
         GROUP BY udl.qw_user_id
         GROUP BY udl.qw_user_id
     </select>
     </select>
-    
+    <select id="selectQwExternalContactByFsUserIdAndCompany" resultType="com.fs.qw.domain.QwExternalContact">
+        <include refid="selectQwExternalContactVo"/>
+        where fs_user_id = #{userId} and company_user_id = #{companyUserId}
+    </select>
+
 
 
 </mapper>
 </mapper>

+ 1 - 0
fs-user-app/src/main/java/com/fs/app/controller/DoctorArticleController.java

@@ -46,6 +46,7 @@ public class DoctorArticleController extends  AppBaseController {
         List<FsDoctorArticleCate> list=articleCateService.selectFsDoctorArticleCateList(map);
         List<FsDoctorArticleCate> list=articleCateService.selectFsDoctorArticleCateList(map);
         return R.ok().put("data",list);
         return R.ok().put("data",list);
     }
     }
+
     @GetMapping("/getDoctorArticleList")
     @GetMapping("/getDoctorArticleList")
     @Cacheable(value = "getDoctorArticleList", key = "#param")
     @Cacheable(value = "getDoctorArticleList", key = "#param")
     public R getDoctorArticleList(FsDoctorArticleListUParam param)
     public R getDoctorArticleList(FsDoctorArticleListUParam param)

+ 8 - 8
fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

@@ -138,18 +138,18 @@ public class InquiryOrderController extends  AppBaseController {
         }
         }
 
 
         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())) {
-                return inquiryOrderService.computeOrder(param, order, user);
-            } else {
+            if (StringUtils.isBlank(user.getMaOpenId()) && !CloudHostUtils.isCloudHostName("弘德堂")) {
                 return R.error("用户OPENID不存在");
                 return R.error("用户OPENID不存在");
             }
             }
+
+            return inquiryOrderService.computeOrder(param, order, user);
         } else if (param.getType() == 2) {
         } else if (param.getType() == 2) {
-            if (user != null) {
-                return inquiryOrderService.computeOrder(param, order, user);
-            } else {
-                return R.error("用户不存在");
-            }
+            return inquiryOrderService.computeOrder(param, order, user);
         } else {
         } else {
             return R.error("无效的类型参数");
             return R.error("无效的类型参数");
         }
         }