6 Commity 3a7fb3a8b0 ... cf816c3c10

Autor SHA1 Wiadomość Data
  caoliqin cf816c3c10 Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java 2 dni temu
  caoliqin b1e346c940 feat:复制增加app发红包回调接口 2 dni temu
  caoliqin 403502c645 feat:复制增加app发红包回调接口 2 dni temu
  caoliqin 6819c2cf2c Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java 2 dni temu
  caoliqin b038bbff53 feat:ai回复高频问题内容调整 2 dni temu
  caoliqin 6a76312fc5 feat:ai回复高频问题内容展示 3 dni temu

+ 16 - 7
fs-company/src/main/java/com/fs/company/controller/fastGpt/FastgptChatQuestionStatisticsController.java

@@ -1,6 +1,8 @@
 package com.fs.company.controller.fastGpt;
 
 import java.util.List;
+
+import com.fs.fastGpt.domain.FastgptChatQuestion;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -15,14 +17,12 @@ import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.enums.BusinessType;
-import com.fs.fastGpt.domain.FastgptChatQuestion;
 import com.fs.fastGpt.domain.FastgptChatQuestionStatistics;
 import com.fs.fastGpt.service.IFastgptChatQuestionService;
 import com.fs.fastGpt.service.IFastgptChatQuestionStatisticsService;
 import com.fs.fastGpt.vo.FastgptChatQuestionDetailVO;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.core.page.TableDataInfo;
-import com.fs.common.BeanCopyUtils;
 
 /**
  * 高频聊天问题统计Controller
@@ -118,9 +118,8 @@ public class FastgptChatQuestionStatisticsController extends BaseController
         startPage();
         FastgptChatQuestion q = new FastgptChatQuestion();
         q.setQuestionStatisticsId(questionStatisticsId);
-        List<FastgptChatQuestion> list = fastgptChatQuestionService.selectFastgptChatQuestionList(q);
-        List<FastgptChatQuestionDetailVO> voList = BeanCopyUtils.copyList(list, FastgptChatQuestionDetailVO.class);
-        return getDataTable(voList);
+        List<FastgptChatQuestionDetailVO> list = fastgptChatQuestionService.selectFastgptChatQuestionDetailVOList(q);
+        return getDataTable(list);
     }
 
     /**
@@ -131,9 +130,19 @@ public class FastgptChatQuestionStatisticsController extends BaseController
     @PutMapping("/question/reply")
     public AjaxResult saveOrUpdateQuestionReply(@RequestBody FastgptChatQuestionDetailVO param)
     {
-        FastgptChatQuestion q = new FastgptChatQuestion();
+        com.fs.fastGpt.domain.FastgptChatQuestion q = new com.fs.fastGpt.domain.FastgptChatQuestion();
         q.setId(param.getId());
         q.setCompanyUserContent(param.getCompanyUserContent());
-        return toAjax(fastgptChatQuestionService.updateFastgptChatQuestion(q));
+        int rows = fastgptChatQuestionService.updateFastgptChatQuestion(q);
+
+        // 同步更新统计表:标记为已解决
+        if (param.getQuestionStatisticsId() != null) {
+            FastgptChatQuestionStatistics statistics = new FastgptChatQuestionStatistics();
+            statistics.setId(param.getQuestionStatisticsId());
+            statistics.setIsResolve(1);
+            rows += fastgptChatQuestionStatisticsService.updateFastgptChatQuestionStatistics(statistics);
+        }
+
+        return toAjax(rows);
     }
 }

+ 15 - 7
fs-service/src/main/java/com/fs/fastGpt/mapper/FastgptChatQuestionMapper.java

@@ -3,18 +3,19 @@ package com.fs.fastGpt.mapper;
 import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.fastGpt.domain.FastgptChatQuestion;
+import com.fs.fastGpt.vo.FastgptChatQuestionDetailVO;
 import org.apache.ibatis.annotations.Param;
 
 /**
  * 聊天问题收集Mapper接口
- * 
+ *
  * @author fs
  * @date 2026-04-20
  */
 public interface FastgptChatQuestionMapper extends BaseMapper<FastgptChatQuestion>{
     /**
      * 查询聊天问题收集
-     * 
+     *
      * @param id 聊天问题收集主键
      * @return 聊天问题收集
      */
@@ -22,15 +23,22 @@ public interface FastgptChatQuestionMapper extends BaseMapper<FastgptChatQuestio
 
     /**
      * 查询聊天问题收集列表
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 聊天问题收集集合
      */
     List<FastgptChatQuestion> selectFastgptChatQuestionList(FastgptChatQuestion fastgptChatQuestion);
 
+    /**
+     * 查询聊天问题明细
+     * @param fastgptChatQuestion 入参
+     * @return vo
+     */
+    List<FastgptChatQuestionDetailVO> selectFastgptChatQuestionDetailVOList(FastgptChatQuestion fastgptChatQuestion);
+
     /**
      * 新增聊天问题收集
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 结果
      */
@@ -38,7 +46,7 @@ public interface FastgptChatQuestionMapper extends BaseMapper<FastgptChatQuestio
 
     /**
      * 修改聊天问题收集
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 结果
      */
@@ -46,7 +54,7 @@ public interface FastgptChatQuestionMapper extends BaseMapper<FastgptChatQuestio
 
     /**
      * 删除聊天问题收集
-     * 
+     *
      * @param id 聊天问题收集主键
      * @return 结果
      */
@@ -54,7 +62,7 @@ public interface FastgptChatQuestionMapper extends BaseMapper<FastgptChatQuestio
 
     /**
      * 批量删除聊天问题收集
-     * 
+     *
      * @param ids 需要删除的数据主键集合
      * @return 结果
      */

+ 7 - 0
fs-service/src/main/java/com/fs/fastGpt/mapper/FastgptChatQuestionStatisticsMapper.java

@@ -67,4 +67,11 @@ public interface FastgptChatQuestionStatisticsMapper extends BaseMapper<FastgptC
     int incrementFrequencyById(@Param("id") Long id, @Param("updateTime") Date updateTime);
 
     FastgptChatQuestionStatistics selectFirstByQuestionCategory(@Param("questionCategory") Integer questionCategory);
+
+    /**
+     * 按 SimHash 候选列表(包含 dist 计算列,供 Java 侧二次筛选)
+     */
+    List<FastgptChatQuestionStatistics> selectCandidatesBySimhash(@Param("simhash") Long simhash,
+                                                                  @Param("threshold") Integer threshold,
+                                                                  @Param("limit") Integer limit);
 }

+ 15 - 7
fs-service/src/main/java/com/fs/fastGpt/service/IFastgptChatQuestionService.java

@@ -3,17 +3,18 @@ package com.fs.fastGpt.service;
 import java.util.List;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.fastGpt.domain.FastgptChatQuestion;
+import com.fs.fastGpt.vo.FastgptChatQuestionDetailVO;
 
 /**
  * 聊天问题收集Service接口
- * 
+ *
  * @author fs
  * @date 2026-04-20
  */
 public interface IFastgptChatQuestionService extends IService<FastgptChatQuestion>{
     /**
      * 查询聊天问题收集
-     * 
+     *
      * @param id 聊天问题收集主键
      * @return 聊天问题收集
      */
@@ -21,15 +22,22 @@ public interface IFastgptChatQuestionService extends IService<FastgptChatQuestio
 
     /**
      * 查询聊天问题收集列表
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 聊天问题收集集合
      */
     List<FastgptChatQuestion> selectFastgptChatQuestionList(FastgptChatQuestion fastgptChatQuestion);
 
+    /**
+     * 查询聊天问题明细
+     * @param fastgptChatQuestion 参数
+     * @return vo
+     */
+    List<FastgptChatQuestionDetailVO> selectFastgptChatQuestionDetailVOList(FastgptChatQuestion fastgptChatQuestion);
+
     /**
      * 新增聊天问题收集
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 结果
      */
@@ -37,7 +45,7 @@ public interface IFastgptChatQuestionService extends IService<FastgptChatQuestio
 
     /**
      * 修改聊天问题收集
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 结果
      */
@@ -45,7 +53,7 @@ public interface IFastgptChatQuestionService extends IService<FastgptChatQuestio
 
     /**
      * 批量删除聊天问题收集
-     * 
+     *
      * @param ids 需要删除的聊天问题收集主键集合
      * @return 结果
      */
@@ -53,7 +61,7 @@ public interface IFastgptChatQuestionService extends IService<FastgptChatQuestio
 
     /**
      * 删除聊天问题收集信息
-     * 
+     *
      * @param id 聊天问题收集主键
      * @return 结果
      */

+ 66 - 40
fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptChatQuestionCollectServiceImpl.java

@@ -35,8 +35,17 @@ import java.util.Map;
 @Service
 public class FastgptChatQuestionCollectServiceImpl {
 
-    private static final int SIMHASH_THRESHOLD = 14;
-    private static final double JACCARD_THRESHOLD = 0.55d;
+    /**
+     * 本地匹配阈值(越大越松:允许更大的 SimHash 汉明距离)
+     */
+    private static final int SIMHASH_THRESHOLD = 30;
+
+    /**
+     * 本地 Jaccard 阈值(越小越松)
+     */
+    private static final double JACCARD_THRESHOLD = 0.45d;
+
+    private static final int LOCAL_CANDIDATE_LIMIT = 30;
 
     private static final String MODEL_TYPE_HIGH_FREQ = "高频问题类别";
 
@@ -77,31 +86,22 @@ public class FastgptChatQuestionCollectServiceImpl {
             Date now = DateUtils.getNowDate();
             long sh = FastgptQuestionNormalizeUtil.simhash64(display);
 
-            // 本地匹配已有统计,获取数据id
-            Long statId = tryMergeByLocalTextMatch(display, sh, now);
+            // ① 先本地匹配:命中则频次+1,并且才会继续走 AI;未命中则不走 AI
+            LocalMatch localMatch = findBestLocalMatch(display, sh);
+            Long statId = null;
+            if (localMatch != null) {
+                statId = localMatch.statId;
+                fastgptChatQuestionStatisticsMapper.incrementFrequencyById(statId, now);
 
-            if (statId == null) {
-                // 如果没有匹配,就调用 AI
+                // ② 只有本地命中时,才调用 AI 做类别归类(用于给统计行补齐/修正 question_category)
                 Integer aiCategory = getHighFreqCategoryByAi(param);
                 if (aiCategory != null) {
-                    FastgptChatQuestionStatistics questionStatistics =
-                            fastgptChatQuestionStatisticsMapper.selectFirstByQuestionCategory(aiCategory);
-                    if (questionStatistics != null && questionStatistics.getId() != null) {
-                        statId = questionStatistics.getId();
-                        fastgptChatQuestionStatisticsMapper.incrementFrequencyById(statId, now);
-                    } else {
-                        FastgptChatQuestionStatistics row = new FastgptChatQuestionStatistics();
-                        row.setQuestionCategory(aiCategory);
-                        row.setContentSummary(display.length() > 200 ? display.substring(0, 200) : display);
-                        row.setSimhash(sh);
-                        row.setIsResolve(0);
-                        row.setQuestionId(detailId);
-                        row.setFrequency(1);
-                        row.setCreateTime(now);
-                        row.setUpdateTime(now);
-                        fastgptChatQuestionStatisticsMapper.insertFastgptChatQuestionStatistics(row);
-                        statId = row.getId();
-                    }
+                    FastgptChatQuestionStatistics upd = new FastgptChatQuestionStatistics();
+                    upd.setId(statId);
+                    upd.setQuestionCategory(aiCategory);
+                    upd.setUpdateTime(now);
+                    // 只更新类别(不覆盖其他字段)
+                    fastgptChatQuestionStatisticsMapper.updateFastgptChatQuestionStatistics(upd);
                 }
             }
 
@@ -207,29 +207,45 @@ public class FastgptChatQuestionCollectServiceImpl {
     /**
      * 本地 SimHash + Jaccard 与已有统计行比对,命中则频次+1 并返回该统计 id;不插入新行。
      */
-    private Long tryMergeByLocalTextMatch(String display, long sh, Date now) {
-        FastgptChatQuestionStatistics best = fastgptChatQuestionStatisticsMapper.selectBestMatchBySimhash(sh, SIMHASH_THRESHOLD);
-        if (best != null && best.getId() != null) {
-            double jac = FastgptQuestionNormalizeUtil.jaccard(
-                    FastgptQuestionNormalizeUtil.ngramTokens(display),
-                    FastgptQuestionNormalizeUtil.ngramTokens(best.getContentSummary())
-            );
+    private LocalMatch findBestLocalMatch(String display, long sh) {
+        // 取一批候选,Java 侧算 Jaccard 再挑最优
+        java.util.List<FastgptChatQuestionStatistics> candidates =
+                fastgptChatQuestionStatisticsMapper.selectCandidatesBySimhash(sh, SIMHASH_THRESHOLD, LOCAL_CANDIDATE_LIMIT);
+        if (candidates == null || candidates.isEmpty()) {
+            return null;
+        }
+        java.util.Set<String> a = FastgptQuestionNormalizeUtil.ngramTokens(display);
+        LocalMatch best = null;
+        for (FastgptChatQuestionStatistics c : candidates) {
+            if (c == null || c.getId() == null || StringUtils.isBlank(c.getContentSummary())) {
+                continue;
+            }
+            double jac = FastgptQuestionNormalizeUtil.jaccard(a, FastgptQuestionNormalizeUtil.ngramTokens(c.getContentSummary()));
             if (jac < JACCARD_THRESHOLD) {
-                best = null;
+                continue;
+            }
+            // dist 列未映射到实体,这里拿不到;所以只用 jac + id 做选择
+            if (best == null) {
+                best = new LocalMatch(c.getId(), jac);
+                continue;
+            }
+            // 选择“匹配值更大”的(这里用 Jaccard 作为匹配分数)
+            if (jac > best.jaccard) {
+                best = new LocalMatch(c.getId(), jac);
+            } else if (Double.compare(jac, best.jaccard) == 0 && c.getId() > best.statId) {
+                // 分数相同取最新(id 更大)
+                best = new LocalMatch(c.getId(), jac);
             }
         }
-        if (best != null && best.getId() != null) {
-            fastgptChatQuestionStatisticsMapper.incrementFrequencyById(best.getId(), now);
-            return best.getId();
-        }
-        return null;
+        return best;
     }
 
     /** AI 也未归类时:再按 SimHash 找一遍(与本地逻辑一致),仍无则插入 question_category=0 的新统计行 */
     private Long mergeBySimhashFallback(String display, long sh, Long detailId, Date now) {
-        Long localId = tryMergeByLocalTextMatch(display, sh, now);
-        if (localId != null) {
-            return localId;
+        LocalMatch localMatch = findBestLocalMatch(display, sh);
+        if (localMatch != null) {
+            fastgptChatQuestionStatisticsMapper.incrementFrequencyById(localMatch.statId, now);
+            return localMatch.statId;
         }
         FastgptChatQuestionStatistics row = new FastgptChatQuestionStatistics();
         row.setQuestionCategory(0);
@@ -249,6 +265,16 @@ public class FastgptChatQuestionCollectServiceImpl {
         return statId;
     }
 
+    private static class LocalMatch {
+        private final Long statId;
+        private final double jaccard;
+
+        private LocalMatch(Long statId, double jaccard) {
+            this.statId = statId;
+            this.jaccard = jaccard;
+        }
+    }
+
     private static FastgptChatQuestion buildQuestion(FastgptKnowledgeMissCollectParam param, String userContent) {
         FastgptChatQuestion q = new FastgptChatQuestion();
         BeanCopyUtils.copy(param, q);

+ 15 - 8
fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptChatQuestionServiceImpl.java

@@ -3,15 +3,15 @@ package com.fs.fastGpt.service.impl;
 import java.util.List;
 import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.fastGpt.mapper.FastgptChatQuestionMapper;
 import com.fs.fastGpt.domain.FastgptChatQuestion;
 import com.fs.fastGpt.service.IFastgptChatQuestionService;
+import com.fs.fastGpt.vo.FastgptChatQuestionDetailVO;
 
 /**
  * 聊天问题收集Service业务层处理
- * 
+ *
  * @author fs
  * @date 2026-04-20
  */
@@ -20,7 +20,7 @@ public class FastgptChatQuestionServiceImpl extends ServiceImpl<FastgptChatQuest
 
     /**
      * 查询聊天问题收集
-     * 
+     *
      * @param id 聊天问题收集主键
      * @return 聊天问题收集
      */
@@ -32,7 +32,7 @@ public class FastgptChatQuestionServiceImpl extends ServiceImpl<FastgptChatQuest
 
     /**
      * 查询聊天问题收集列表
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 聊天问题收集
      */
@@ -42,9 +42,15 @@ public class FastgptChatQuestionServiceImpl extends ServiceImpl<FastgptChatQuest
         return baseMapper.selectFastgptChatQuestionList(fastgptChatQuestion);
     }
 
+    @Override
+    public List<FastgptChatQuestionDetailVO> selectFastgptChatQuestionDetailVOList(FastgptChatQuestion fastgptChatQuestion)
+    {
+        return baseMapper.selectFastgptChatQuestionDetailVOList(fastgptChatQuestion);
+    }
+
     /**
      * 新增聊天问题收集
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 结果
      */
@@ -57,19 +63,20 @@ public class FastgptChatQuestionServiceImpl extends ServiceImpl<FastgptChatQuest
 
     /**
      * 修改聊天问题收集
-     * 
+     *
      * @param fastgptChatQuestion 聊天问题收集
      * @return 结果
      */
     @Override
     public int updateFastgptChatQuestion(FastgptChatQuestion fastgptChatQuestion)
     {
+        fastgptChatQuestion.setUpdateTime(DateUtils.getNowDate());
         return baseMapper.updateFastgptChatQuestion(fastgptChatQuestion);
     }
 
     /**
      * 批量删除聊天问题收集
-     * 
+     *
      * @param ids 需要删除的聊天问题收集主键
      * @return 结果
      */
@@ -81,7 +88,7 @@ public class FastgptChatQuestionServiceImpl extends ServiceImpl<FastgptChatQuest
 
     /**
      * 删除聊天问题收集信息
-     * 
+     *
      * @param id 聊天问题收集主键
      * @return 结果
      */

+ 13 - 1
fs-service/src/main/java/com/fs/fastGpt/vo/FastgptChatQuestionDetailVO.java

@@ -5,7 +5,7 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 /**
- * 高频聊天问题明细 VO(对应 fastgpt_chat_question 全字段返回)
+ * 高频聊天问题明细 VO
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -29,9 +29,15 @@ public class FastgptChatQuestionDetailVO extends BaseEntity {
     /** 公司ID */
     private Long companyId;
 
+    /** 公司名称 */
+    private String companyName;
+
     /** 销售ID */
     private Long companyUserId;
 
+    /** 销售昵称 */
+    private String companyUserNickName;
+
     /** 角色ID */
     private Long roleId;
 
@@ -49,5 +55,11 @@ public class FastgptChatQuestionDetailVO extends BaseEntity {
 
     /** 高频问题统计id,关联高频聊天问题统计表 */
     private Long questionStatisticsId;
+
+    /** 外部联系人ID */
+    private Long externalContactId;
+
+    /** 外部联系人名称 */
+    private String externalContactName;
 }
 

+ 1 - 0
fs-service/src/main/java/com/fs/his/service/IFsStorePaymentService.java

@@ -117,6 +117,7 @@ public interface IFsStorePaymentService
 
     String v3TransferNotify(String notifyData, HttpServletRequest request);
 
+    String v3TransferNotifyApp(String notifyData, HttpServletRequest request);
 
     String v3TransferNotifyWithCompanyId(Long companyId,String notifyData, HttpServletRequest request);
 

+ 36 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -1154,6 +1154,42 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         }
     }
 
+    @Override
+    public String v3TransferNotifyApp(String notifyData, HttpServletRequest request) {
+        logger.info("zyp \n【app-收到转账回调V3】:{}",notifyData);
+        try {
+            String json = configService.selectConfigByKey("his.AppRedPacket");
+            RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
+            //创建微信订单
+            WxPayConfig payConfig = new WxPayConfig();
+            BeanUtils.copyProperties(config,payConfig);
+            WxPayService wxPayService = new WxPayServiceImpl();
+            wxPayService.setConfig(payConfig);
+            SignatureHeader signatureHeader = new SignatureHeader();
+            signatureHeader.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
+            signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
+            signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
+            signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
+            TransferBillsNotifyResult result = wxPayService.parseTransferBillsNotifyV3Result(notifyData,signatureHeader);
+            logger.info("app-到零钱回调:{}",result.getResult());
+            if (result.getResult().getState().equals("SUCCESS")) {
+                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBillNo(),result.getResult().getTransferBillNo());
+                logger.info("app,result:{}",r);
+                if (r.get("code").equals(200)){
+                    return WxPayNotifyResponse.success("处理成功");
+                }else {
+                    return WxPayNotifyResponse.fail("");
+                }
+            }else {
+                return WxPayNotifyResponse.fail("");
+            }
+        } catch (WxPayException e) {
+            e.printStackTrace();
+            logger.error("zyp \n【app-转账回调异常】:{}", e.getReturnMsg());
+            return WxPayNotifyResponse.fail(e.getMessage());
+        }
+    }
+
     @Override
     public String v3TransferNotifyWithCompanyId(Long companyId, String notifyData, HttpServletRequest request) {
         logger.info("分公司回调V3::companyId:{}",companyId);

+ 36 - 1
fs-service/src/main/resources/mapper/fastGpt/FastgptChatQuestionMapper.xml

@@ -18,13 +18,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="userContent"    column="user_content"    />
         <result property="companyUserContent"    column="company_user_content"    />
         <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
         <result property="questionStatisticsId"    column="question_statistics_id"    />
     </resultMap>
 
     <sql id="selectFastgptChatQuestionVo">
-        select id, session_id, msg_id, ext_id, user_id, company_id, company_user_id, role_id, nick_name, user_type, user_content, company_user_content, create_time, question_statistics_id from fastgpt_chat_question
+        select id, session_id, msg_id, ext_id, user_id, company_id, company_user_id, role_id, nick_name, user_type, user_content, company_user_content, create_time, update_time, question_statistics_id from fastgpt_chat_question
     </sql>
 
+    <select id="selectFastgptChatQuestionDetailVOList" parameterType="FastgptChatQuestion" resultType="com.fs.fastGpt.vo.FastgptChatQuestionDetailVO">
+        select
+            q.id,
+            q.session_id,
+            q.msg_id,
+            q.ext_id,
+            q.user_id,
+            q.company_id,
+            q.company_user_id,
+            q.role_id,
+            q.nick_name,
+            q.user_type,
+            q.user_content,
+            q.company_user_content,
+            q.create_time,
+            q.update_time,
+            q.question_statistics_id,
+            c.company_name,
+            cu.nick_name as company_user_nick_name,
+            ec.id as external_contact_id,
+            ec.name as external_contact_name
+        from fastgpt_chat_question q
+        left join company c on c.company_id = q.company_id
+        left join company_user cu on cu.user_id = q.company_user_id
+        left join qw_external_contact ec on ec.id = q.ext_id
+        <where>
+            <if test="questionStatisticsId != null"> and q.question_statistics_id = #{questionStatisticsId}</if>
+        </where>
+        order by q.create_time desc, q.id desc
+    </select>
+
     <select id="selectFastgptChatQuestionList" parameterType="FastgptChatQuestion" resultMap="FastgptChatQuestionResult">
         <include refid="selectFastgptChatQuestionVo"/>
         <where>
@@ -63,6 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="userContent != null">user_content,</if>
             <if test="companyUserContent != null">company_user_content,</if>
             <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
             <if test="questionStatisticsId != null">question_statistics_id,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
@@ -78,6 +111,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="userContent != null">#{userContent},</if>
             <if test="companyUserContent != null">#{companyUserContent},</if>
             <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
             <if test="questionStatisticsId != null">#{questionStatisticsId},</if>
          </trim>
     </insert>
@@ -97,6 +131,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="userContent != null">user_content = #{userContent},</if>
             <if test="companyUserContent != null">company_user_content = #{companyUserContent},</if>
             <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="questionStatisticsId != null">question_statistics_id = #{questionStatisticsId},</if>
         </trim>
         where id = #{id}

+ 10 - 0
fs-service/src/main/resources/mapper/fastGpt/FastgptChatQuestionStatisticsMapper.xml

@@ -101,6 +101,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         LIMIT 1
     </select>
 
+    <select id="selectCandidatesBySimhash" resultMap="FastgptChatQuestionStatisticsResult">
+        SELECT s.*,
+               BIT_COUNT(s.simhash ^ #{simhash}) AS dist
+        FROM fastgpt_chat_question_statistics s
+        WHERE s.simhash IS NOT NULL
+        HAVING dist &lt;= #{threshold}
+        ORDER BY dist ASC, s.frequency DESC, s.id DESC
+        LIMIT #{limit}
+    </select>
+
     <update id="incrementFrequencyById">
         update fastgpt_chat_question_statistics
         set frequency = frequency + 1,

+ 5 - 0
fs-user-app/src/main/java/com/fs/app/controller/course/CourseTransferController.java

@@ -50,6 +50,11 @@ public class CourseTransferController {
         return paymentService.v3TransferNotify(notifyData,request);
     }
 
+    @PostMapping( "/app/v3TransferNotify")
+    public String v3TransferNotifyApp(@RequestBody String notifyData,HttpServletRequest request, HttpServletResponse response) throws Exception {
+        return paymentService.v3TransferNotifyApp(notifyData,request);
+    }
+
     @GetMapping("/test")
     public void test(){
         iSopUserLogsInfoService.updateSopUserInfoByExternalId(1L,123456L);