Jelajahi Sumber

1.提交ai是否回复代码
2.提交舌诊代码

jzp 1 bulan lalu
induk
melakukan
cfd5e87f2e
22 mengubah file dengan 974 tambahan dan 62 penghapusan
  1. 126 0
      fs-admin/src/main/java/com/fs/fastGpt/FastgptExtUserTagController.java
  2. 12 0
      fs-admin/src/main/java/com/fs/qw/controller/QwTagGroupController.java
  3. 2 0
      fs-service/src/main/java/com/fs/aiTongueApi/config/AiTongueConfig.java
  4. 58 0
      fs-service/src/main/java/com/fs/aiTongueApi/domain/enums/TongueTypeEnums.java
  5. 14 0
      fs-service/src/main/java/com/fs/aiTongueApi/domain/inner/ConfidenceDataNew.java
  6. 14 0
      fs-service/src/main/java/com/fs/aiTongueApi/domain/inner/TongueInfo.java
  7. 3 0
      fs-service/src/main/java/com/fs/aiTongueApi/service/AiTongueService.java
  8. 187 2
      fs-service/src/main/java/com/fs/aiTongueApi/service/impl/AiTongueServiceImpl.java
  9. 31 0
      fs-service/src/main/java/com/fs/fastGpt/domain/FastgptExtUserTag.java
  10. 67 0
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastgptExtUserTagMapper.java
  11. 66 0
      fs-service/src/main/java/com/fs/fastGpt/service/IFastgptExtUserTagService.java
  12. 58 2
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java
  13. 145 0
      fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptExtUserTagServiceImpl.java
  14. 34 0
      fs-service/src/main/java/com/fs/fastGpt/vo/FastgptExtUserTagVO.java
  15. 3 0
      fs-service/src/main/java/com/fs/his/mapper/FsHealthTongueMapper.java
  16. 3 0
      fs-service/src/main/java/com/fs/his/service/IFsHealthTongueService.java
  17. 60 57
      fs-service/src/main/java/com/fs/his/service/impl/FsHealthTongueServiceImpl.java
  18. 5 0
      fs-service/src/main/java/com/fs/qw/param/QwExternalContactParam.java
  19. 5 0
      fs-service/src/main/java/com/fs/qw/vo/QwExternalContactVO.java
  20. 75 0
      fs-service/src/main/resources/mapper/fastGpt/FastgptExtUserTagMapper.xml
  21. 4 0
      fs-service/src/main/resources/mapper/his/FsHealthTongueMapper.xml
  22. 2 1
      fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 31 - 0
fs-service/src/main/java/com/fs/fastGpt/domain/FastgptExtUserTag.java

@@ -0,0 +1,31 @@
+package com.fs.fastGpt.domain;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 处理新客标签对象 fastgpt_ext_user_tag
+ *
+ * @author fs
+ * @date 2025-09-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FastgptExtUserTag extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 标签id */
+    @Excel(name = "标签id")
+    private String tagId;
+
+    /** 企业id */
+    @Excel(name = "企业id")
+    private String corpId;
+
+
+
+}

+ 67 - 0
fs-service/src/main/java/com/fs/fastGpt/mapper/FastgptExtUserTagMapper.java

@@ -0,0 +1,67 @@
+package com.fs.fastGpt.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.fastGpt.domain.FastgptExtUserTag;
+import com.fs.fastGpt.vo.FastgptExtUserTagVO;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 处理新客标签Mapper接口
+ * 
+ * @author fs
+ * @date 2025-09-10
+ */
+public interface FastgptExtUserTagMapper extends BaseMapper<FastgptExtUserTag>{
+    /**
+     * 查询处理新客标签
+     * 
+     * @param id 处理新客标签主键
+     * @return 处理新客标签
+     */
+    FastgptExtUserTag selectFastgptExtUserTagById(Long id);
+
+    /**
+     * 查询处理新客标签列表
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 处理新客标签集合
+     */
+    List<FastgptExtUserTag> selectFastgptExtUserTagList(FastgptExtUserTag fastgptExtUserTag);
+
+    /**
+     * 新增处理新客标签
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 结果
+     */
+    int insertFastgptExtUserTag(FastgptExtUserTag fastgptExtUserTag);
+
+    /**
+     * 修改处理新客标签
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 结果
+     */
+    int updateFastgptExtUserTag(FastgptExtUserTag fastgptExtUserTag);
+
+    /**
+     * 删除处理新客标签
+     * 
+     * @param id 处理新客标签主键
+     * @return 结果
+     */
+    int deleteFastgptExtUserTagById(Long id);
+
+    /**
+     * 批量删除处理新客标签
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFastgptExtUserTagByIds(Long[] ids);
+
+    int addFastGptTagByCorpId(@Param("data") FastgptExtUserTagVO fastgptExtUserTag);
+
+    List<FastgptExtUserTag> selectFastgptExtUserTagByIds(@Param("ids") Long[] ids);
+}

+ 66 - 0
fs-service/src/main/java/com/fs/fastGpt/service/IFastgptExtUserTagService.java

@@ -0,0 +1,66 @@
+package com.fs.fastGpt.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.fastGpt.domain.FastgptExtUserTag;
+import com.fs.fastGpt.vo.FastgptExtUserTagVO;
+
+/**
+ * 处理新客标签Service接口
+ * 
+ * @author fs
+ * @date 2025-09-10
+ */
+public interface IFastgptExtUserTagService extends IService<FastgptExtUserTag>{
+    /**
+     * 查询处理新客标签
+     * 
+     * @param id 处理新客标签主键
+     * @return 处理新客标签
+     */
+    FastgptExtUserTag selectFastgptExtUserTagById(Long id);
+
+    /**
+     * 查询处理新客标签列表
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 处理新客标签集合
+     */
+    List<FastgptExtUserTag> selectFastgptExtUserTagList(FastgptExtUserTag fastgptExtUserTag);
+
+    /**
+     * 新增处理新客标签
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 结果
+     */
+    int insertFastgptExtUserTag(FastgptExtUserTag fastgptExtUserTag);
+
+    /**
+     * 修改处理新客标签
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 结果
+     */
+    int updateFastgptExtUserTag(FastgptExtUserTag fastgptExtUserTag);
+
+    /**
+     * 批量删除处理新客标签
+     * 
+     * @param ids 需要删除的处理新客标签主键集合
+     * @return 结果
+     */
+    int deleteFastgptExtUserTagByIds(Long[] ids);
+
+    /**
+     * 删除处理新客标签信息
+     * 
+     * @param id 处理新客标签主键
+     * @return 结果
+     */
+    int deleteFastgptExtUserTagById(Long id);
+
+    R addFastGptTagByCorpId(FastgptExtUserTagVO fastgptExtUserTag);
+
+}

+ 58 - 2
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -3,6 +3,7 @@ package com.fs.fastGpt.service.impl;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
 import com.fs.common.annotation.Excel;
 import com.fs.common.config.FSConfig;
 import com.fs.common.core.domain.R;
@@ -161,6 +162,10 @@ public class AiHookServiceImpl implements AiHookService {
     @Autowired
     private IFastGptChatReplaceTextService fastGptChatReplaceTextService;
 
+    private static final String AI_REPLY = "AI_REPLY:";
+    private static final String AI_REPLY_TAG = "AI_REPLY_TAG:";
+
+
     /** Ai半小时未回复提醒 **/
     /**
      *
@@ -376,7 +381,7 @@ public class AiHookServiceImpl implements AiHookService {
         }
         if(user.getFastGptRoleId()==null){
             log.error("未绑定角色");
-            return R.ok();
+            return userIsReply(sender, uid, user);
         }
         Long serverId = user.getServerId();
         log.info("服务器id"+serverId);
@@ -388,7 +393,7 @@ public class AiHookServiceImpl implements AiHookService {
         //没用ai角色跳过
         if(role==null){
             log.error("没用ai角色跳过");
-            return R.ok();
+            return userIsReply(sender, uid, user);
         }
         String modeConfig=role.getModeConfigJson();
         //key不为空
@@ -598,6 +603,57 @@ public class AiHookServiceImpl implements AiHookService {
         return R.ok();
     }
 
+    /**
+     * 根据发送者id设置用户是否为首次回复
+     * @param sender 发送者id
+     * @param uid   企微用户的uuid
+     * @param user  企微用户信息
+     * @return
+     */
+    private @Nullable R userIsReply(Long sender, String uid, QwUser user) {
+        Long qwExternalContactId = redisCache.getCacheObject(AI_REPLY + sender);
+        if(qwExternalContactId == null){
+            WxWorkVid2UserIdDTO wxWorkVid2UserIdDTO = new WxWorkVid2UserIdDTO();
+            wxWorkVid2UserIdDTO.setUser_id(Arrays.asList(sender));
+            wxWorkVid2UserIdDTO.setUuid(uid);
+            WxWorkResponseDTO<List<WxWorkVid2UserIdRespDTO>> WxWorkVid2UserIdRespDTO = wxWorkService.Vid2UserId(wxWorkVid2UserIdDTO, user.getServerId());
+            List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
+            if (data==null|| data.isEmpty()){
+                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){
+                log.error("没有外部联系人" + "user:" + user);
+                return R.ok();
+            }
+            List<String> oldCache = redisCache.getCacheObject(AI_REPLY_TAG + user.getCorpId());
+            if(oldCache != null && !oldCache.isEmpty()){
+                QwExternalContact qwExternalContact = new QwExternalContact();
+                if(qwExternalContacts.getTagIds() != null && !qwExternalContacts.getTagIds().isEmpty() && !"[]".equals(qwExternalContacts.getTagIds())){
+                    List<String> parsedTags = JSON.parseArray(qwExternalContacts.getTagIds(), String.class);
+                    if (parsedTags != null && !parsedTags.isEmpty()) {
+                        for (String parsedTag : oldCache) {
+                            if (!oldCache.contains(parsedTag)) {
+                                oldCache.add(parsedTag);
+                            }
+                        }
+                    }
+                    qwExternalContact.setTagIds(JSON.toJSONString(oldCache));
+                }else if("[]".equals(qwExternalContacts.getTagIds()) || qwExternalContacts.getTagIds() == null){
+                    qwExternalContact.setTagIds(JSON.toJSONString(oldCache));
+                }
+                qwExternalContact.setId(qwExternalContacts.getId());
+                qwExternalContactMapper.updateQwExternalContact(qwExternalContact);
+            }
+            qwExternalContactMapper.updateQwExternalContactIsRePlyById(qwExternalContacts.getId());
+            redisCache.setCacheObject(AI_REPLY + sender,qwExternalContacts.getId());
+        }
+        return R.ok();
+    }
+
     /**
      * 通过用户发送的对话去查询用户是否为新客,是就删除sop,否就不做处理
      * @param user

+ 145 - 0
fs-service/src/main/java/com/fs/fastGpt/service/impl/FastgptExtUserTagServiceImpl.java

@@ -0,0 +1,145 @@
+package com.fs.fastGpt.service.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.fastGpt.vo.FastgptExtUserTagVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.fastGpt.mapper.FastgptExtUserTagMapper;
+import com.fs.fastGpt.domain.FastgptExtUserTag;
+import com.fs.fastGpt.service.IFastgptExtUserTagService;
+
+/**
+ * 处理新客标签Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-09-10
+ */
+@Service
+public class FastgptExtUserTagServiceImpl extends ServiceImpl<FastgptExtUserTagMapper, FastgptExtUserTag> implements IFastgptExtUserTagService {
+
+    @Autowired
+    private FastgptExtUserTagMapper fastgptExtUserTagMapper;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    private static final String AI_REPLY_TAG = "AI_REPLY_TAG:";
+
+    /**
+     * 查询处理新客标签
+     * 
+     * @param id 处理新客标签主键
+     * @return 处理新客标签
+     */
+    @Override
+    public FastgptExtUserTag selectFastgptExtUserTagById(Long id)
+    {
+        return baseMapper.selectFastgptExtUserTagById(id);
+    }
+
+    /**
+     * 查询处理新客标签列表
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 处理新客标签
+     */
+    @Override
+    public List<FastgptExtUserTag> selectFastgptExtUserTagList(FastgptExtUserTag fastgptExtUserTag)
+    {
+        return baseMapper.selectFastgptExtUserTagList(fastgptExtUserTag);
+    }
+
+    /**
+     * 新增处理新客标签
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 结果
+     */
+    @Override
+    public int insertFastgptExtUserTag(FastgptExtUserTag fastgptExtUserTag)
+    {
+        fastgptExtUserTag.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFastgptExtUserTag(fastgptExtUserTag);
+    }
+
+    /**
+     * 修改处理新客标签
+     * 
+     * @param fastgptExtUserTag 处理新客标签
+     * @return 结果
+     */
+    @Override
+    public int updateFastgptExtUserTag(FastgptExtUserTag fastgptExtUserTag)
+    {
+        return baseMapper.updateFastgptExtUserTag(fastgptExtUserTag);
+    }
+
+    /**
+     * 批量删除处理新客标签
+     * 
+     * @param ids 需要删除的处理新客标签主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFastgptExtUserTagByIds(Long[] ids)
+    {
+        List<FastgptExtUserTag> fastgptExtUserTags = fastgptExtUserTagMapper.selectFastgptExtUserTagByIds(ids);
+        int i = baseMapper.deleteFastgptExtUserTagByIds(ids);
+        if(i > 0){
+            if(fastgptExtUserTags != null && !fastgptExtUserTags.isEmpty()){
+                String corpId = fastgptExtUserTags.get(0).getCorpId();
+                List<String> oldCache = redisCache.getCacheObject(AI_REPLY_TAG + corpId);
+                for (FastgptExtUserTag fastgptExtUserTag : fastgptExtUserTags) {
+                    if(fastgptExtUserTag != null && fastgptExtUserTag.getTagId() != null){
+                        if(oldCache != null && !oldCache.isEmpty()){
+                            oldCache.remove(fastgptExtUserTag.getTagId());
+                        }
+                    }
+                }
+                redisCache.setCacheObject(AI_REPLY_TAG + corpId,oldCache);
+            }
+        }
+        return i;
+    }
+
+    /**
+     * 删除处理新客标签信息
+     * 
+     * @param id 处理新客标签主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFastgptExtUserTagById(Long id)
+    {
+        return baseMapper.deleteFastgptExtUserTagById(id);
+    }
+
+    @Override
+    public R addFastGptTagByCorpId(FastgptExtUserTagVO fastgptExtUserTag) {
+        int i = 0;
+        try {
+            i = fastgptExtUserTagMapper.addFastGptTagByCorpId(fastgptExtUserTag);
+        } catch (Exception e) {
+            return R.error("添加失败,存在重复的标签");
+        }
+        if(i > 0){
+            if(fastgptExtUserTag != null && fastgptExtUserTag.getTagIds() != null){
+                List<String> oldCache = redisCache.getCacheObject(AI_REPLY_TAG + fastgptExtUserTag.getCorpId());
+                if(oldCache != null && !oldCache.isEmpty()){
+                    oldCache.addAll(fastgptExtUserTag.getTagIds());
+                    redisCache.setCacheObject(AI_REPLY_TAG + fastgptExtUserTag.getCorpId(),oldCache);
+                }else{
+                    List<String> newCacheTagList = new ArrayList<>(fastgptExtUserTag.getTagIds());
+                    redisCache.setCacheObject(AI_REPLY_TAG + fastgptExtUserTag.getCorpId(),newCacheTagList);
+                }
+            }
+        }
+        return R.ok("添加成功");
+    }
+}

+ 34 - 0
fs-service/src/main/java/com/fs/fastGpt/vo/FastgptExtUserTagVO.java

@@ -0,0 +1,34 @@
+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;
+
+/**
+ * 处理新客标签对象 fastgpt_ext_user_tag
+ *
+ * @author fs
+ * @date 2025-09-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FastgptExtUserTagVO extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 标签id */
+    @Excel(name = "标签id")
+    private String tagId;
+
+    /** 企业id */
+    @Excel(name = "企业id")
+    private String corpId;
+
+    List<String> tagIds;
+
+
+}

+ 3 - 0
fs-service/src/main/java/com/fs/his/mapper/FsHealthTongueMapper.java

@@ -2,6 +2,7 @@ package com.fs.his.mapper;
 
 import java.util.List;
 
+import com.fs.aiTongueApi.domain.inner.TongueInfo;
 import com.fs.common.core.domain.R;
 import com.fs.his.domain.FsHealthTongue;
 import com.fs.his.param.FsHealthTongueListUParam;
@@ -95,4 +96,6 @@ public interface FsHealthTongueMapper
     FsHealthTongueUVO selectFsHealthTongueUVOById(Long id);
 
     List<String> selectListByDateAndUserId(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("userId") Long userId);
+
+    TongueInfo selectFsTongueInfo(TongueInfo tongueInfo);
 }

+ 3 - 0
fs-service/src/main/java/com/fs/his/service/IFsHealthTongueService.java

@@ -2,6 +2,7 @@ package com.fs.his.service;
 
 import java.util.List;
 
+import com.fs.aiTongueApi.domain.inner.TongueInfo;
 import com.fs.common.core.domain.R;
 import com.fs.his.domain.FsHealthTongue;
 import com.fs.his.param.FsHealthTongueListUParam;
@@ -80,4 +81,6 @@ public interface IFsHealthTongueService
     FsHealthTongueUVO selectFsHealthTongueUVOById(Long id);
 
     Long selectFsHealthTongueAllCountByUserId(Long l);
+
+    TongueInfo selectFsTongueInfo(TongueInfo tongueInfo);
 }

+ 60 - 57
fs-service/src/main/java/com/fs/his/service/impl/FsHealthTongueServiceImpl.java

@@ -4,15 +4,18 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import com.alibaba.fastjson.JSON;
 import com.fs.aiTongueApi.domain.AITongueResult;
 import com.fs.aiTongueApi.domain.QueryQuanXi;
 import com.fs.aiTongueApi.domain.inner.TongueData;
+import com.fs.aiTongueApi.domain.inner.TongueInfo;
 import com.fs.aiTongueApi.service.AiTongueService;
 import com.fs.aiTongueApi.service.impl.AiTongueServiceImpl;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.spring.SpringUtils;
 import com.fs.his.param.FsHealthTongueListUParam;
 import com.fs.his.param.FsHealthTongueParam;
 import com.fs.his.param.FsHealthTongueUParam;
@@ -20,6 +23,8 @@ import com.fs.his.vo.FsHealthTongueListUVO;
 import com.fs.his.vo.FsHealthTongueListVO;
 import com.fs.his.vo.FsHealthTongueUVO;
 import com.qiniu.util.Json;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.his.mapper.FsHealthTongueMapper;
@@ -125,66 +130,59 @@ public class FsHealthTongueServiceImpl implements IFsHealthTongueService
     @Override
     public R insertFsHealthTongueByImgUrl(FsHealthTongueUParam param) {
 
-        QueryQuanXi queryQuanXi = new QueryQuanXi();
-        if (param.getName()!=null&&!param.getName().equals("")){
-            queryQuanXi.setName(param.getName());
-        }{
-            queryQuanXi.setName("匿名");
-        }
-        if (param.getAge()!=null){
-            queryQuanXi.setAge(param.getAge()+"");
-        }else {
-            queryQuanXi.setAge("55");
-        }
+        // 使用Redisson分布式锁保证高并发下的同步执行
+        RedissonClient redissonClient = SpringUtils.getBean(RedissonClient.class);
+        String lockKey = "tongueAnalysis:" + param.getUserId();
+        RLock lock = redissonClient.getLock(lockKey);
 
-        queryQuanXi.setFile(param.getTongueUrl());
-        if (param.getSex()!=null){
-            queryQuanXi.setMale(param.getSex()==1?"1":"0");
-        }else {
-            queryQuanXi.setMale("0");
-        }
+        try {
+            // 尝试获取锁,最多等待3秒,持有锁时间最多30秒
+            boolean isLocked = lock.tryLock(3,  30, TimeUnit.SECONDS);
+            if (!isLocked) {
+                return R.error("系统繁忙,请稍后再试");
+            }
+
+            // 检查用户使用频率限制(每天最多3次)
+            /*Long count = selectFsHealthTongueCountByUserId(param.getUserId());
+            if (count >= 5) {
+                return R.error("今日使用次数已达上限");
+            }*/
+
+            AITongueResult<FsHealthTongue> tongueDataAITongueResult = aiTongueService.newCheckTongue(param.getTongueUrl());
+            FsHealthTongue data = tongueDataAITongueResult.getData();
+
+            if (param.getName()!=null&&!param.getName().isEmpty()){
+                data.setName(param.getName());
+            }
 
-        AITongueResult<TongueData> tongueDataAITongueResult = aiTongueService.quanXiTongue(queryQuanXi);
-
-        if (tongueDataAITongueResult.getCode().equals("40001")){
-            FsHealthTongue fsHealthTongue = new FsHealthTongue();
-            fsHealthTongue.setAge(param.getAge());
-            fsHealthTongue.setPatientId(param.getPatientId());
-            fsHealthTongue.setName(param.getName());
-            fsHealthTongue.setSex(param.getSex());
-            fsHealthTongue.setStatus(0);
-            fsHealthTongue.setUserId(param.getUserId());
-            fsHealthTongue.setTongueUrl(param.getTongueUrl());
-            TongueData data = tongueDataAITongueResult.getData();
-            fsHealthTongue.setTongueId(data.getId());
-            fsHealthTongue.setCreateTime(new Date());
-            fsHealthTongue.setTypeName(data.getTypeName()+"质");
-
-            fsHealthTongue.setBotai(data.getBotai());
-            fsHealthTongue.setBotaiDesc(data.getBotaiDesc());
-            fsHealthTongue.setChihen(data.getChihen());
-            fsHealthTongue.setChihenDesc(data.getChihenDesc());
-            fsHealthTongue.setLiewen(data.getLiewen());
-            fsHealthTongue.setLiewenDesc(data.getLiewenDesc());
-            fsHealthTongue.setShemianName(data.getShemianName());
-            fsHealthTongue.setShemianDesc(data.getShemianDesc());
-            fsHealthTongue.setTaiseName(data.getTaiseName());
-            fsHealthTongue.setTaiseDesc(data.getTaiseDesc());
-            String json =fsHealthTongueMapper.selectTypeJSON();
-            String typeName = fsHealthTongue.getTypeName();
-            String itemTypeJSonValue="[]";
-            List<Map<String, Object>> itemTypeJsonList = (List<Map<String, Object>>) JSON.parse(json);
-            for (Map<String, Object> stringStringMap : itemTypeJsonList) {
-                String itemType = (String) stringStringMap.get("itemType");
-                if (itemType.equals(typeName)){
-                    itemTypeJSonValue= Json.encode(stringStringMap.get("item"));
-                }
+            if (param.getAge()!=null){
+                data.setAge(param.getAge());
+            }
+
+            if (param.getSex()!=null){
+                data.setSex(param.getSex());
+            }
+
+            if (tongueDataAITongueResult.getCode().equals("40001")){
+                data.setPatientId(param.getPatientId());
+                data.setStatus(0);
+                data.setUserId(param.getUserId());
+                data.setCreateTime(new Date());
+                fsHealthTongueMapper.insertFsHealthTongue(data);
+                return R.ok().put("data",data);
+            }else {
+                return R.error(tongueDataAITongueResult.getMeta().getMsg());
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            return R.error("系统繁忙,请稍后再试");
+        } catch (Exception e) {
+            return R.error("系统异常,请稍后再试!");
+        } finally {
+            // 释放锁
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
             }
-            fsHealthTongue.setTypeJson(itemTypeJSonValue);
-            fsHealthTongueMapper.insertFsHealthTongue(fsHealthTongue);
-            return R.ok().put("data",fsHealthTongue);
-        }else {
-            return R.error(tongueDataAITongueResult.getMeta().getMsg());
         }
     }
 
@@ -207,4 +205,9 @@ public class FsHealthTongueServiceImpl implements IFsHealthTongueService
     public Long selectFsHealthTongueAllCountByUserId(Long id) {
         return fsHealthTongueMapper.selectFsHealthTongueAllCountByUserId(id);
     }
+
+    @Override
+    public TongueInfo selectFsTongueInfo(TongueInfo tongueInfo) {
+        return fsHealthTongueMapper.selectFsTongueInfo(tongueInfo);
+    }
 }

+ 5 - 0
fs-service/src/main/java/com/fs/qw/param/QwExternalContactParam.java

@@ -122,4 +122,9 @@ public class QwExternalContactParam {
      */
     private String userType;
 
+    /**
+     * 是否回复
+     */
+    private Integer isReply;
+
 }

+ 5 - 0
fs-service/src/main/java/com/fs/qw/vo/QwExternalContactVO.java

@@ -117,4 +117,9 @@ public class QwExternalContactVO {
     private Long level;
     @Excel(name = "等级升降")
     private Long levelType;
+
+    /**
+     * 是否回复
+     */
+    private Integer isReply;
 }

+ 75 - 0
fs-service/src/main/resources/mapper/fastGpt/FastgptExtUserTagMapper.xml

@@ -0,0 +1,75 @@
+<?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.FastgptExtUserTagMapper">
+    
+    <resultMap type="FastgptExtUserTag" id="FastgptExtUserTagResult">
+        <result property="id"    column="id"    />
+        <result property="tagId"    column="tag_id"    />
+        <result property="corpId"    column="corp_id"    />
+        <result property="createTime"    column="create_time"    />
+    </resultMap>
+
+    <sql id="selectFastgptExtUserTagVo">
+        select id, tag_id, corp_id, create_time from fastgpt_ext_user_tag
+    </sql>
+
+    <select id="selectFastgptExtUserTagList" parameterType="FastgptExtUserTag" resultMap="FastgptExtUserTagResult">
+        <include refid="selectFastgptExtUserTagVo"/>
+        <where>  
+            <if test="tagId != null  and tagId != ''"> and tag_id = #{tagId}</if>
+            <if test="corpId != null  and corpId != ''"> and corp_id = #{corpId}</if>
+        </where>
+    </select>
+    
+    <select id="selectFastgptExtUserTagById" parameterType="Long" resultMap="FastgptExtUserTagResult">
+        <include refid="selectFastgptExtUserTagVo"/>
+        where id = #{id}
+    </select>
+    <select id="selectFastgptExtUserTagByIds" resultType="com.fs.fastGpt.domain.FastgptExtUserTag">
+        <include refid="selectFastgptExtUserTagVo"/> where id in
+        <foreach item="id" collection="ids" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </select>
+
+    <insert id="insertFastgptExtUserTag" parameterType="FastgptExtUserTag" useGeneratedKeys="true" keyProperty="id">
+        insert into fastgpt_ext_user_tag
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="tagId != null">tag_id,</if>
+            <if test="corpId != null">corp_id,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="tagId != null">#{tagId},</if>
+            <if test="corpId != null">#{corpId},</if>
+         </trim>
+    </insert>
+    <insert id="addFastGptTagByCorpId">
+        insert into fastgpt_ext_user_tag (tag_id, corp_id)
+        <foreach item="tagId" collection="data.tagIds" separator="," open="values ">
+            (#{tagId}, #{data.corpId})
+        </foreach>
+    </insert>
+
+    <update id="updateFastgptExtUserTag" parameterType="FastgptExtUserTag">
+        update fastgpt_ext_user_tag
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="tagId != null">tag_id = #{tagId},</if>
+            <if test="corpId != null">corp_id = #{corpId},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFastgptExtUserTagById" parameterType="Long">
+        delete from fastgpt_ext_user_tag where id = #{id}
+    </delete>
+
+    <delete id="deleteFastgptExtUserTagByIds" parameterType="String">
+        delete from fastgpt_ext_user_tag where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 4 - 0
fs-service/src/main/resources/mapper/his/FsHealthTongueMapper.xml

@@ -78,6 +78,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </where>
         GROUP BY DATE(create_time)
     </select>
+    <select id="selectFsTongueInfo" resultType="com.fs.aiTongueApi.domain.inner.TongueInfo">
+        select botai,houdu,shemian_name shemianName,taise_name taiseName,type_name typeName,type_json typeJson from fs_tongue_info
+        where botai = #{botai} and houdu = #{houdu} and shemian_name = #{shemianName} and taise_name = #{taiseName}
+    </select>
 
     <insert id="insertFsHealthTongue" parameterType="FsHealthTongue" useGeneratedKeys="true" keyProperty="id">
         insert into fs_health_tongue

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

@@ -43,10 +43,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="firstTime"    column="first_time"    />
         <result property="lastWatchTime"    column="last_watch_time"    />
         <result property="registerTime"    column="register_time"    />
+        <result property="isReply"    column="is_reply"    />
     </resultMap>
 
     <sql id="selectQwExternalContactVo">
-        select id,qw_user_id,register_time,state,way_id,stage_status,first_time,open_id,is_interact,level, unionid, user_id,transfer_time,loss_time,del_time,transfer_num, external_user_id,transfer_status,status,create_time, name, avatar, type, gender, remark, description, tag_ids, remark_mobiles, remark_corp_name, add_way, oper_userid, corp_id, company_id, company_user_id, customer_id, fs_user_id from qw_external_contact
+        select id,qw_user_id,register_time,state,way_id,stage_status,first_time,open_id,is_interact,level, unionid, user_id,transfer_time,loss_time,del_time,transfer_num, external_user_id,transfer_status,status,create_time, name, avatar, type, gender, remark, description, tag_ids, remark_mobiles, remark_corp_name, add_way, oper_userid, corp_id, company_id, company_user_id, customer_id, fs_user_id,is_reply from qw_external_contact
     </sql>
 
     <select id="selectQwExternalContactList" parameterType="QwExternalContact" resultMap="QwExternalContactResult">