浏览代码

1.提交ai对话配套的后端代码

jzp 2 天之前
父节点
当前提交
e258485949
共有 46 个文件被更改,包括 3026 次插入108 次删除
  1. 20 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchCommentController.java
  2. 97 0
      fs-admin/src/main/java/com/fs/fastGpt/FastGptChatReplaceTextController.java
  3. 112 0
      fs-admin/src/main/java/com/fs/fastGpt/FastGptKeywordSendController.java
  4. 139 0
      fs-admin/src/main/java/com/fs/fastGpt/FastgptEventLogTotalController.java
  5. 224 4
      fs-admin/src/main/java/com/fs/his/task/Task.java
  6. 134 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptKeywordSendController.java
  7. 148 0
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastgptEventLogTotalController.java
  8. 1 0
      fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java
  9. 118 41
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  10. 2 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  11. 7 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  12. 5 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  13. 96 0
      fs-service/src/main/java/com/fs/fastGpt/domain/FastGptChatReplaceText.java
  14. 2 0
      fs-service/src/main/java/com/fs/fastGpt/domain/FastGptRole.java
  15. 68 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptChatReplaceTextMapper.java
  16. 10 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptRoleMapper.java
  17. 93 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastgptEventLogTotalMapper.java
  18. 76 0
      fs-service/src/main/java/com/fs/fastGpt/param/FastgptEventLogTotalParam.java
  19. 62 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastGptChatReplaceTextService.java
  20. 8 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastGptRoleService.java
  21. 94 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastgptEventLogTotalService.java
  22. 67 30
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java
  23. 0 2
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptChatMsgServiceImpl.java
  24. 93 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptChatReplaceTextServiceImpl.java
  25. 77 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastGptRoleServiceImpl.java
  26. 290 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptEventLogTotalServiceImpl.java
  27. 19 0
      fs-service/src/main/java/com/fs/fastGpt/vo/FastGptRoleDataVO.java
  28. 70 0
      fs-service/src/main/java/com/fs/fastGpt/vo/FastgptEventLogTotalVo.java
  29. 110 8
      fs-service/src/main/java/com/fs/fastgptApi/util/AiImgUtil.java
  30. 2 2
      fs-service/src/main/java/com/fs/fastgptApi/util/EventLogUtils.java
  31. 20 1
      fs-service/src/main/java/com/fs/gtPush/domain/PushReqBean.java
  32. 93 0
      fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java
  33. 4 0
      fs-service/src/main/java/com/fs/gtPush/service/uniPush2Service.java
  34. 120 0
      fs-service/src/main/java/com/fs/gtPush/utils/PushUtils.java
  35. 35 0
      fs-service/src/main/java/com/fs/his/enums/PushLogDesTypeEnum.java
  36. 34 0
      fs-service/src/main/java/com/fs/his/enums/PushLogTypeEnum.java
  37. 71 13
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  38. 2 0
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java
  39. 1 1
      fs-service/src/main/java/com/fs/qw/service/IQwExternalContactService.java
  40. 26 5
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  41. 45 0
      fs-service/src/main/java/com/fs/utils/SensitiveDataUtils.java
  42. 11 0
      fs-service/src/main/resources/mapper/company/CompanyMapper.xml
  43. 80 0
      fs-service/src/main/resources/mapper/fastGpt/FastGptChatReplaceTextMapper.xml
  44. 24 0
      fs-service/src/main/resources/mapper/fastGpt/FastGptRoleMapper.xml
  45. 211 0
      fs-service/src/main/resources/mapper/fastGpt/FastgptEventLogTotalMapper.xml
  46. 5 1
      fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml

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

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

+ 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 - 4
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -27,7 +27,10 @@ import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.dto.ErpOrderResponse;
 import com.fs.erp.mapper.FsErpFinishPushMapper;
 import com.fs.erp.service.IErpOrderService;
+import com.fs.fastGpt.domain.FastGptEventTokenLog;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
+import com.fs.fastGpt.service.IFastgptEventLogTotalService;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.FsInquiryOrder;
@@ -58,10 +61,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Slf4j
 @Component("task")
@@ -161,6 +161,226 @@ public class Task {
     @Autowired
     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点执行一次
     public void totalIpadTask(){
         String dateTime = DateUtils.addDateDays(-1); // 昨天

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

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

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

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

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

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

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

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

+ 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 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 com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.vo.FastGptRoleVO;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
 import com.fs.his.vo.OptionsVO;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
@@ -88,4 +90,12 @@ public interface FastGptRoleMapper
     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}")
     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.fastGpt.domain.FastGptRole;
+import com.fs.fastGpt.vo.FastGptRoleDataVO;
 import com.fs.fastGpt.vo.FastGptRoleVO;
 import com.fs.his.vo.OptionsVO;
 
@@ -73,4 +74,11 @@ public interface IFastGptRoleService
     List<OptionsVO> selectFastGptRoleType();
 
     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.sop.domain.QwSopLogs;
 import com.fs.sop.mapper.QwSopLogsMapper;
+import com.fs.utils.SensitiveDataUtils;
 import com.fs.voice.utils.StringUtil;
 import com.fs.wxwork.dto.*;
 import com.fs.wxwork.service.WxWorkService;
@@ -61,6 +62,7 @@ import com.vdurmont.emoji.EmojiParser;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.Nullable;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Async;
@@ -156,6 +158,8 @@ public class AiHookServiceImpl implements AiHookService {
     private IFsExpressService expressService;
     @Autowired
     private CompanyConfigMapper companyConfigMapper;
+    @Autowired
+    private IFastGptChatReplaceTextService fastGptChatReplaceTextService;
 
     /** Ai半小时未回复提醒 **/
     /**
@@ -363,38 +367,38 @@ public class AiHookServiceImpl implements AiHookService {
         if (qwContent.contains("我已经添加了你")){
             return R.ok();
         }
-        System.out.println(qwUserId);
+        log.info("数据:{}", qwUserId);
         QwUser user = qwUserMapper.selectQwUserById(qwUserId);
         //查询接收人
         if(user==null){
-            System.out.println("查询接收人为空");
+            log.error("查询接收人为空");
             return R.ok();
         }
         if(user.getFastGptRoleId()==null){
-            System.out.println("未绑定角色");
+            log.error("未绑定角色");
             return R.ok();
         }
         Long serverId = user.getServerId();
-        System.out.println("服务器id"+serverId);
+        log.info("服务器id"+serverId);
         if (serverId == null) {
-            System.out.println("服务id为空");
+            log.error("服务id为空");
             return R.ok();
         }
         FastGptRole role=roleService.selectFastGptRoleTypeByRoleId(user.getFastGptRoleId());
         //没用ai角色跳过
         if(role==null){
-            System.out.println("没用ai角色跳过");
+            log.error("没用ai角色跳过");
             return R.ok();
         }
         String modeConfig=role.getModeConfigJson();
         //key不为空
         if(StringUtils.isEmpty(modeConfig)){
-            System.out.println("没有aiKey");
+            log.error("没有aiKey");
             return R.ok();
         }
         ModeConfig config=JSONUtil.toBean(modeConfig,ModeConfig.class);
         if(StringUtils.isEmpty(config.getAPPKey())){
-            System.out.println("没有aiKey");
+            log.error("没有aiKey");
             return R.ok();
         }
         WxWorkVid2UserIdDTO wxWorkVid2UserIdDTO = new WxWorkVid2UserIdDTO();
@@ -404,14 +408,14 @@ public class AiHookServiceImpl implements AiHookService {
         List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
         if (data==null|| data.isEmpty()){
 
-            System.out.println("未获取到extId"+wxWorkVid2UserIdDTO);
+            log.error("未获取到extId"+wxWorkVid2UserIdDTO);
             return R.ok();
         }
         com.fs.wxwork.dto.WxWorkVid2UserIdRespDTO dto = data.get(0);
 
         QwExternalContact qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByExternalUserIdAndQwUserId(dto.getOpenid(), user.getCorpId(),user.getQwUserId());
         if (qwExternalContacts==null){
-            System.out.println("没有外部联系人");
+            log.error("没有外部联系人" + "user:" + user);
             return R.ok();
         }
         if(qwExternalContacts.getType()==2){
@@ -437,10 +441,12 @@ public class AiHookServiceImpl implements AiHookService {
                     }
                 }
             }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.isEmpty()){
                     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){
-                System.out.println("转人工了");
+                log.error("转人工了,sessionId:" + fastGptChatSession.getSessionId());
                 return R.ok();
             }
             //获取是用户是否发送消息
@@ -472,22 +478,32 @@ public class AiHookServiceImpl implements AiHookService {
                     redisCache.setCacheObject("msg:" + fastGptChatSession.getSessionId(),msg+","+contentEmj,5,TimeUnit.MINUTES);
                 }
                 //本次跳过
-                System.out.println("正在对话");
+                log.info("正在对话");
                 return R.ok();
             }
             //用户首次发送消息
             redisCache.setCacheObject("reply:" + fastGptChatSession.getSessionId(),1,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);
             EventLogUtils.recordEventLog(sender,1L,1,user);
             EventLogUtils.recordEventLog(sender,1L,2,user);
-            System.out.println(r);
+            log.info("数据:{}", r);
             //完成对话 删除消息记录
             redisCache.deleteObject("reply:" + fastGptChatSession.getSessionId());
             redisCache.deleteObject("msg:" + fastGptChatSession.getSessionId());
             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);
                 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);
-            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()){
                 addSaveAiMsg(1,2,content,user,fastGptChatSession.getSessionId(),role.getRoleId(),qwExternalContacts,fastGptChatSession.getUserId(),null,null,null);
                 //从fastgpt_chat_artificial_words表中查询所有转人工文本
@@ -524,6 +533,12 @@ public class AiHookServiceImpl implements AiHookService {
                     notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," 触发关键词",qwExternalContacts.getId(),sender);
                     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()){
                     //新增用户信息
                     addUserInfo(contentKh, qwExternalContacts.getId(),fastGptChatSession);
@@ -569,7 +584,7 @@ public class AiHookServiceImpl implements AiHookService {
 
 
             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);
             }
         }
@@ -636,7 +651,7 @@ public class AiHookServiceImpl implements AiHookService {
         Random random = new Random();
         FastGptKeywordSend fastGptKeywordSend = keywordSendList.get(random.nextInt(keywordSendList.size()));
         if (fastGptKeywordSend == null){
-            System.out.println("输出为空格");
+            log.info("输出为空格");
             return;
         }
         if(fastGptKeywordSend.getKeywordType() == 1L && "物流".equals(fastGptKeywordSend.getKeyword())){
@@ -662,11 +677,11 @@ public class AiHookServiceImpl implements AiHookService {
                                 fastGptChatSessionMapper.updateFastGptChatSession(fastGptChatSession);
                                 break;
                             case 2:
-                                sBuilder.append("您购买的 ").append(fsStoreOrder.getPackageName()).append(" 正在准备发货,请耐心等待;\n");
-                                break;
+                                sBuilder.append("您好,您有一个包裹正在准备发货,请耐心等待;\n")
+                                        .append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
                             case 3:
                                 ExpressInfoDTO expressInfo = getExpress(fsStoreOrder.getOrderId());
-                                sBuilder.append("您购买的 ").append(fsStoreOrder.getPackageName());
+                                sBuilder.append("您购买的有一个包裹 ");
                                 sBuilder.append(" 已经查询到了,正在配送中了。\n");
                                 if(expressInfo != null && expressInfo.getTraces() != null && !expressInfo.getTraces().isEmpty()){
                                     List<TracesDTO> traces = expressInfo.getTraces();
@@ -679,7 +694,7 @@ public class AiHookServiceImpl implements AiHookService {
                             case 5:
                                 ExpressInfoDTO express = getExpress(fsStoreOrder.getOrderId());
                                 //你好,这边查询到您购买的XXX(购买套餐)在XXX(时间)已经送到了,送货员电话为XXX(送货员信息)
-                                sBuilder.append("这边查询到您购买的 ").append(fsStoreOrder.getPackageName());
+                                sBuilder.append("这边查询到您有一个包裹");
                                 if(express != null && express.getTraces() != null && !express.getTraces().isEmpty()){
                                     List<TracesDTO> traces = express.getTraces();
                                     TracesDTO tracesDTO = traces.get(traces.size() - 1);
@@ -813,6 +828,28 @@ public class AiHookServiceImpl implements AiHookService {
         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) {
         if (content == null || content.trim().isEmpty()){
             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
-    @DataSource(DataSourceType.CLICKHOUSE)
     public void insertFastGptEventLog(FastGptEventLog fastGptEventLog) {
         fastGptChatMsgMapper.insertFastGptEventLog(fastGptEventLog);
     }
 
     @Override
-    @DataSource(DataSourceType.CLICKHOUSE)
     public void insertFastGptEventTokenLog(FastGptEventTokenLog 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.Collections;
 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.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.fastGpt.domain.FastGptRoleTag;
 import com.fs.fastGpt.mapper.FastGptRoleTagMapper;
+import com.fs.fastGpt.vo.FastGptRoleDataVO;
 import com.fs.fastGpt.vo.FastGptRoleVO;
+import com.fs.fastGpt.vo.FastgptEventLogTotalVo;
 import com.fs.his.vo.OptionsVO;
 import com.fs.qw.mapper.QwUserMapper;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -171,5 +176,77 @@ public class FastGptRoleServiceImpl implements IFastGptRoleService
         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.result.AiImgResult;
 import com.fs.qw.domain.QwUser;
+import lombok.extern.slf4j.Slf4j;
 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.SocketTimeoutException;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
+@Slf4j
 @Service
 public class AiImgUtil {
 
@@ -98,8 +98,9 @@ public class AiImgUtil {
             textContent.setText(
                     "识别图片内容 \n" +
                             "情况一:图片为表情包的时候或是明确意义图片的时候,单独提取出表情包的含义为图片,并输出:【表情包:XXX】XXX为表情表达的内容,例如这个表情包是很开心的感谢,那么XXX就是谢谢。在【】外不进行其他的解释直接结束 \n" +
-                            "情况二:图片是舌头的时候,根据他的舌苔进行简单的分析,直接输出 \n" +
-                            "情况三:图片是其他的时候,正常提取图片内容,如果是身体异常部位要进行简单分析,直接输出,如果是卡通图片,需要在结尾输出【这是卡通图片】这几个字");
+                            "情况二:图片是舌头的时候,根据他的舌苔进行简单的分析,直接输出,如果是张开嘴的时候,对舌下进行简单的舌诊分析 \n" +
+                            "情况三:图片是其他的时候,正常提取图片内容,如果是身体异常部位要进行简单分析,直接输出,如果是卡通图片,需要在结尾输出【这是卡通图片】这几个字\n" +
+                            "情况四:图片如果是微信支付界面,如果最下方的一条信息为收款金额,那么输出【用户完课,领取红包】,如果最下方的一条信息为支付成功,那么输出【用户购买产品,支付成功】");
 
 
             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;
         try {
             // 配置连接
@@ -196,5 +298,5 @@ public class AiImgUtil {
                 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());
 
 
-        //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;
 
+import com.google.common.collect.ImmutableMap;
 import lombok.Data;
 
 import javax.security.sasl.SaslServer;
@@ -9,8 +10,26 @@ import java.util.Map;
 @Data
 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 content;
+    private boolean force_notification;
+    private Map<String,String> category;
     private Map<String,Object> payload;
+    private Map<String,Object> options;
+    private String badge;
+
+    public PushReqBean() {
+    }
 }

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

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

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

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

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

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

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

+ 71 - 13
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.domain.*;
 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.param.*;
 import com.fs.his.service.*;
@@ -82,7 +80,14 @@ import com.github.binarywang.wxpay.service.WxPayService;
 import com.google.gson.Gson;
 import lombok.Synchronized;
 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.aop.framework.AopContext;
 import org.springframework.beans.factory.annotation.Autowired;
 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.util.CollectionUtils;
 
+import java.io.IOException;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -120,6 +126,7 @@ import static com.fs.his.utils.PhoneUtil.encryptPhone;
 @Slf4j
 @EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
 public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
+    Logger logger = LoggerFactory.getLogger(getClass());
     @Autowired
     private WxPayService wxPayService;
     @Autowired
@@ -273,6 +280,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Value("${express.omsCode}")
     private String expressOmsCode;
 
+    @Autowired
+    private com.fs.gtPush.service.uniPush2Service uniPush2Service;
+
     /**
      * 查询订单
      *
@@ -1886,7 +1896,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     public ExpressResultDTO updateDeliveryItem(ExpressNotifyDTO notifyDTO) {
         String data = URLDecoder.decode(notifyDTO.getRequestData(), Charset.forName("UTF-8"));
         //ExpressInfoDTO
-        log.info("快递根踪回调: {}", data);
+        logger.info("快递根踪回调:" + data);
         FsSysConfig sysConfig = configUtil.getSysConfig();
         ExpressDataDTO expressDataDTO = JSONUtil.toBean(data, ExpressDataDTO.class);
         if (expressDataDTO != null && expressDataDTO.getData() != null) {
@@ -1894,8 +1904,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 List<FsStoreOrder> orders = this.selectFsStoreOrderListByDeliveryId(dto.getLogisticCode());
                 if (orders != null) {
                     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 (dto.getState() != null && dto.getStateEx() != null) {
                                 FsStoreOrder map = new FsStoreOrder();
@@ -1906,16 +1916,47 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                                 this.updateFsStoreOrder(map);
                                 //如果是正常签收,更新订单状态
                                 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()) {
-                                log.info("物流状态异常:{}", dto);
+                                logger.info("物流状态异常:{}" + dto);
                             }
                             if ((!dto.isSuccess() && dto.getReason() != null && dto.getReason().equals("三天无轨迹")) || (!dto.isSuccess() && dto.getReason() != null && dto.getReason().equals("七天内无轨迹变化"))) {
                                 //订阅物流回调
@@ -1927,7 +1968,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                                     }
                                 }
                                 expressService.subscribeEspress(order.getOrderCode(), order.getDeliveryCode(), order.getDeliverySn(), lastFourNumber);
-                                log.info("物流重新订阅:{}", order.getDeliverySn());
+                                logger.info("物流重新订阅:{}", order.getDeliverySn());
                             }
 
                         }
@@ -1945,6 +1986,23 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         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
     @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
     public R syncExpress(Long id) {

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

@@ -433,4 +433,6 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
     int insertQwUserDelLossLog(@Param("param") QwUserDelLossLog qwUserDelLossLog);
 
     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);
 
-    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
     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
@@ -5513,6 +5533,11 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         return 0;
     }
 
+    @Override
+    public List<QwExternalContact> selectQwExternalContactByFsUserIdAndCompany(Long userId, Long companyUserId) {
+        return qwExternalContactMapper.selectQwExternalContactByFsUserIdAndCompany(userId,companyUserId);
+    }
+
 
     //发送好友欢迎语
        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
     public List<QwUserDelLossLogVO> selectQwUserDelLossLogList(QwUserDelLossLogParam param) {

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

+ 11 - 0
fs-service/src/main/resources/mapper/company/CompanyMapper.xml

@@ -227,5 +227,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{companyId}
         </foreach>
     </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>

+ 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"/>
         where role_id = #{roleId}
     </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 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>
         GROUP BY udl.qw_user_id
     </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>