Преглед на файлове

新增:新增设备绑定知识库逻辑,代替原始配置知识库方案

范志成 преди 3 месеца
родител
ревизия
b93bdfc4f0
променени са 12 файла, в които са добавени 816 реда и са изтрити 105 реда
  1. 116 0
      smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/controller/SmsbDatasetsIdentifierRelController.java
  2. 52 0
      smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/domain/SmsbDatasetsIdentifierRel.java
  3. 42 0
      smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/domain/bo/SmsbDatasetsIdentifierRelBo.java
  4. 50 0
      smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/domain/vo/SmsbDatasetsIdentifierRelVo.java
  5. 19 0
      smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/mapper/SmsbDatasetsIdentifierRelMapper.java
  6. 70 0
      smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/service/ISmsbDatasetsIdentifierRelService.java
  7. 68 100
      smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/service/impl/SmsbAppointmentInfoServiceImpl.java
  8. 136 0
      smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/service/impl/SmsbDatasetsIdentifierRelServiceImpl.java
  9. 32 0
      smsb-modules/smsb-digital-promotion/src/main/resources/mapper/digital/SmsbDatasetsIdentifierRelMapper.xml
  10. 75 0
      smsb-plus-ui/src/api/smsb/digital/datasetsIdentifierRel/index.ts
  11. 56 0
      smsb-plus-ui/src/api/smsb/digital/datasetsIdentifierRel/types.ts
  12. 100 5
      smsb-plus-ui/src/views/smsb/deviceGroup/index.vue

+ 116 - 0
smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/controller/SmsbDatasetsIdentifierRelController.java

@@ -0,0 +1,116 @@
+package com.inspur.digital.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import com.inspur.digital.domain.vo.SmsbDatasetsIdentifierRelVo;
+import com.inspur.digital.domain.bo.SmsbDatasetsIdentifierRelBo;
+import com.inspur.digital.service.ISmsbDatasetsIdentifierRelService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 知识库与设备关联关系
+ *
+ * @author ZhiCheng Fan
+ * @date 2025-07-18
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/digital/datasetsIdentifierRel")
+public class SmsbDatasetsIdentifierRelController extends BaseController {
+
+    private final ISmsbDatasetsIdentifierRelService smsbDatasetsIdentifierRelService;
+
+    /**
+     * 查询知识库与设备关联关系列表
+     */
+    @SaCheckPermission("digital:datasetsIdentifierRel:list")
+    @GetMapping("/list")
+    public TableDataInfo<SmsbDatasetsIdentifierRelVo> list(SmsbDatasetsIdentifierRelBo bo, PageQuery pageQuery) {
+        return smsbDatasetsIdentifierRelService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出知识库与设备关联关系列表
+     */
+    @SaCheckPermission("digital:datasetsIdentifierRel:export")
+    @Log(title = "知识库与设备关联关系", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(SmsbDatasetsIdentifierRelBo bo, HttpServletResponse response) {
+        List<SmsbDatasetsIdentifierRelVo> list = smsbDatasetsIdentifierRelService.queryList(bo);
+        ExcelUtil.exportExcel(list, "知识库与设备关联关系", SmsbDatasetsIdentifierRelVo.class, response);
+    }
+
+    /**
+     * 获取知识库与设备关联关系详细信息
+     *
+     * @param id 主键
+     */
+    @SaCheckPermission("digital:datasetsIdentifierRel:query")
+    @GetMapping("/{id}")
+    public R<SmsbDatasetsIdentifierRelVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable Long id) {
+        return R.ok(smsbDatasetsIdentifierRelService.queryById(id));
+    }
+
+    /**
+     * 获取知识库与设备关联关系详细信息
+     *
+     * @param identifier 设备标识
+     */
+    @SaCheckPermission("digital:datasetsIdentifierRel:query")
+    @GetMapping("/getInfoByIdentifier")
+    public R<SmsbDatasetsIdentifierRelVo> getInfoByIdentifier(@RequestParam String identifier) {
+        return R.ok(smsbDatasetsIdentifierRelService.queryByIdentifier(identifier));
+    }
+
+    /**
+     * 新增知识库与设备关联关系
+     */
+    @SaCheckPermission("digital:datasetsIdentifierRel:add")
+    @Log(title = "知识库与设备关联关系", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody SmsbDatasetsIdentifierRelBo bo) {
+        return toAjax(smsbDatasetsIdentifierRelService.insertByBo(bo));
+    }
+
+    /**
+     * 修改知识库与设备关联关系
+     */
+    @SaCheckPermission("digital:datasetsIdentifierRel:edit")
+    @Log(title = "知识库与设备关联关系", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SmsbDatasetsIdentifierRelBo bo) {
+        return toAjax(smsbDatasetsIdentifierRelService.updateByBo(bo));
+    }
+
+    /**
+     * 删除知识库与设备关联关系
+     *
+     * @param ids 主键串
+     */
+    @SaCheckPermission("digital:datasetsIdentifierRel:remove")
+    @Log(title = "知识库与设备关联关系", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable Long[] ids) {
+        return toAjax(smsbDatasetsIdentifierRelService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 52 - 0
smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/domain/SmsbDatasetsIdentifierRel.java

@@ -0,0 +1,52 @@
+package com.inspur.digital.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+import java.util.Date;
+
+/**
+ * 知识库与设备关联关系对象 smsb_datasets_identifier_rel
+ *
+ * @author ZhiCheng Fan
+ * @date 2025-07-18
+ */
+@Data
+@EqualsAndHashCode
+@TableName("smsb_datasets_identifier_rel")
+public class SmsbDatasetsIdentifierRel {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键id
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 知识库id
+     */
+    private Long datasetsId;
+
+    /**
+     * 设备唯一标识
+     */
+    private String deviceIdentifier;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    /**
+     * 租户编号
+     */
+    private String tenantId;
+
+}

+ 42 - 0
smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/domain/bo/SmsbDatasetsIdentifierRelBo.java

@@ -0,0 +1,42 @@
+package com.inspur.digital.domain.bo;
+
+import com.inspur.digital.domain.SmsbDatasetsIdentifierRel;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 知识库与设备关联关系业务对象 smsb_datasets_identifier_rel
+ *
+ * @author ZhiCheng Fan
+ * @date 2025-07-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SmsbDatasetsIdentifierRel.class, reverseConvertGenerate = false)
+public class SmsbDatasetsIdentifierRelBo extends BaseEntity {
+
+    /**
+     * 主键id
+     */
+    @NotNull(message = "主键id不能为空", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 知识库id
+     */
+    @NotNull(message = "知识库id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long datasetsId;
+
+    /**
+     * 设备唯一标识
+     */
+    @NotNull(message = "设备唯一标识不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String deviceIdentifier;
+
+
+}

+ 50 - 0
smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/domain/vo/SmsbDatasetsIdentifierRelVo.java

@@ -0,0 +1,50 @@
+package com.inspur.digital.domain.vo;
+
+import com.inspur.digital.domain.SmsbDatasetsIdentifierRel;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 知识库与设备关联关系视图对象 smsb_datasets_identifier_rel
+ *
+ * @author ZhiCheng Fan
+ * @date 2025-07-18
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SmsbDatasetsIdentifierRel.class)
+public class SmsbDatasetsIdentifierRelVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键id
+     */
+    @ExcelProperty(value = "主键id")
+    private Long id;
+
+    /**
+     * 知识库id
+     */
+    @ExcelProperty(value = "知识库id")
+    private Long datasetsId;
+
+    /**
+     * 设备唯一标识
+     */
+    @ExcelProperty(value = "设备唯一标识")
+    private String deviceIdentifier;
+
+
+}

+ 19 - 0
smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/mapper/SmsbDatasetsIdentifierRelMapper.java

@@ -0,0 +1,19 @@
+package com.inspur.digital.mapper;
+
+import com.inspur.digital.domain.SmsbDatasetsIdentifierRel;
+import com.inspur.digital.domain.vo.SmsbDatasetsIdentifierRelVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 知识库与设备关联关系Mapper接口
+ *
+ * @author ZhiCheng Fan
+ * @date 2025-07-18
+ */
+public interface SmsbDatasetsIdentifierRelMapper extends BaseMapperPlus<SmsbDatasetsIdentifierRel, SmsbDatasetsIdentifierRelVo> {
+
+    // 根据设备identifier查询关联的知识库id
+    String queryDifyIdByIdentifier(String identifier);
+
+    SmsbDatasetsIdentifierRelVo selectVoByIdentifier(String identifier);
+}

+ 70 - 0
smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/service/ISmsbDatasetsIdentifierRelService.java

@@ -0,0 +1,70 @@
+package com.inspur.digital.service;
+
+import com.inspur.digital.domain.vo.SmsbDatasetsIdentifierRelVo;
+import com.inspur.digital.domain.bo.SmsbDatasetsIdentifierRelBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 知识库与设备关联关系Service接口
+ *
+ * @author ZhiCheng Fan
+ * @date 2025-07-18
+ */
+public interface ISmsbDatasetsIdentifierRelService {
+
+    /**
+     * 查询知识库与设备关联关系
+     *
+     * @param id 主键
+     * @return 知识库与设备关联关系
+     */
+    SmsbDatasetsIdentifierRelVo queryById(Long id);
+
+    /**
+     * 分页查询知识库与设备关联关系列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 知识库与设备关联关系分页列表
+     */
+    TableDataInfo<SmsbDatasetsIdentifierRelVo> queryPageList(SmsbDatasetsIdentifierRelBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的知识库与设备关联关系列表
+     *
+     * @param bo 查询条件
+     * @return 知识库与设备关联关系列表
+     */
+    List<SmsbDatasetsIdentifierRelVo> queryList(SmsbDatasetsIdentifierRelBo bo);
+
+    /**
+     * 新增知识库与设备关联关系
+     *
+     * @param bo 知识库与设备关联关系
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(SmsbDatasetsIdentifierRelBo bo);
+
+    /**
+     * 修改知识库与设备关联关系
+     *
+     * @param bo 知识库与设备关联关系
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(SmsbDatasetsIdentifierRelBo bo);
+
+    /**
+     * 校验并批量删除知识库与设备关联关系信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    SmsbDatasetsIdentifierRelVo queryByIdentifier(String identifier);
+}

+ 68 - 100
smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/service/impl/SmsbAppointmentInfoServiceImpl.java

@@ -72,6 +72,7 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
     private final SmsbDeviceChatScCaseMapper smsbDeviceChatScCaseMapper;
     private final SmsbDeviceScScanCodeMapper smsbDeviceScScanCodeMapper;
     private final SmsbDifyDatasetsQuestionMapper smsbDifyDatasetsQuestionMapper;
+    private final SmsbDatasetsIdentifierRelMapper smsbDatasetsIdentifierRelMapper;
     @Autowired
     private SmsbDeviceMapper smsbDeviceMapper;
     @Autowired
@@ -659,14 +660,20 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
                 List<String> qaList = questionVoList.stream()
                     .map(questionVo -> questionVo.getQuestion() + ":" + questionVo.getAnswer())
                     .toList();
-                // 线程1 更新诊断报告的知识库
-                syncDatasetsReport(qaList, difyScDatasetReportId);
-                // 线程2 更新有样学样的知识库
-                syncDatasetsCase(qaList, difyScDatasetCaseId);
-                // 线程3 更新套餐推荐的知识库
-                syncDatasetsProduct(qaList, difyScDatasetProductId);
-                // 线程4 更新场景推荐的知识库
-                syncDatasetsScene(qaList, difyScDatasetSceneId);
+
+                // 根据identifier查询设备组中其他设备,拿到其他设备的identifierList
+                List<SmsbDeviceGroupRelVo> groupRelList = smsbDeviceGroupRelMapper.queryGroupRelVoListByIdentifier(smsbStartInfoBo.getIdentifier());
+                // 循环遍历查到的List,根据identifier查询知识库关联表,拿到数据库id更新知识库
+                if (groupRelList == null || groupRelList.isEmpty()) {
+                    return R.fail("未找到设备的设备组");
+                }
+
+                groupRelList.forEach(groupRel -> {
+                    String difyId = smsbDatasetsIdentifierRelMapper.queryDifyIdByIdentifier(groupRel.getDeviceIdentifier());
+                    // 创建线程,将设备组中设备关联的知识库更新
+                    syncDatasets(qaList, difyId);
+                });
+
                 // 3、同步成功 设置key的value为common
                 RedisUtils.setCacheObject(REDIS_SYNC_DATASETS_FLAG_KEY, REDIS_SYNC_DATASETS_FLAG_VALUE_COMMON);
             }
@@ -691,14 +698,16 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
             return R.ok(result);
         }
         List<SmsbScDeviceStartInfoVo> deviceStartInfoList = new ArrayList<>();
-        // 针对评估所有内容集合
-        List<String> reportContentList = new ArrayList<>();
-        // 针对有样学样的内容集合
-        List<String> caseContentList = new ArrayList<>();
-        // 针对套餐推荐的内容集合
-        List<String> productContentList = new ArrayList<>();
-        // 针对场景推荐的内容集合
-        List<String> sceneContentList = new ArrayList<>();
+        var ref = new Object() {
+            // 针对评估所有内容集合
+            List<String> reportContentList = new ArrayList<>();
+            // 针对有样学样的内容集合
+            List<String> caseContentList = new ArrayList<>();
+            // 针对套餐推荐的内容集合
+            List<String> productContentList = new ArrayList<>();
+            // 针对场景推荐的内容集合
+            List<String> sceneContentList = new ArrayList<>();
+        };
 
         for (SmsbDeviceGroupRelVo deviceGroupRel : deviceGroupRelList) {
             SmsbScDeviceStartInfoVo deviceStartInfo = new SmsbScDeviceStartInfoVo();
@@ -719,7 +728,7 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
                     .eq(SmsbDeviceChatScReport::getAppointmentId, appointmentInfo.getId())
                     .eq(SmsbDeviceChatScReport::getType, 2));
                 if (CollectionUtils.isNotEmpty(reportVoList)) {
-                    reportContentList = reportVoList.stream().map(SmsbDeviceChatScReportVo::getContent).collect(Collectors.toList());
+                    ref.reportContentList = reportVoList.stream().map(SmsbDeviceChatScReportVo::getContent).collect(Collectors.toList());
                 }
             } else if (deviceGroupRel.getSceneSort().equals(DEFAULT_SCENE_SORT_2)) {
                 List<SmsbScDeviceStartProductVO> productVOList = new ArrayList<>();
@@ -748,7 +757,7 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
                     }else {
                         deviceStartInfo.setProductVOList(productVOList);
                     }
-                    caseContentList = createCaseContentList(caseVoList);
+                    ref.caseContentList = createCaseContentList(caseVoList);
                 }
             } else if (deviceGroupRel.getSceneSort().equals(DEFAULT_SCENE_SORT_3)) {
                 List<SmsbScDeviceStartProductVO> productVOList = new ArrayList<>();
@@ -780,7 +789,7 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
                     }else {
                         deviceStartInfo.setProductVOList(productVOList);
                     }
-                    sceneContentList = createSceneContentList(sceneVoList);
+                    ref.sceneContentList = createSceneContentList(sceneVoList);
                 }
             } else if (deviceGroupRel.getSceneSort().equals(DEFAULT_SCENE_SORT_4)) {
                 SmsbDeviceChatScProductVo productVo = smsbDeviceChatScProductMapper.selectVoOne(new LambdaQueryWrapper<SmsbDeviceChatScProduct>()
@@ -796,21 +805,46 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
                     .eq(SmsbDeviceChatScProduct::getAppointmentId, appointmentInfo.getId())
                     .eq(SmsbDeviceChatScProduct::getType, 2));
                 if (CollectionUtils.isNotEmpty(productVoList)) {
-                    productContentList = createProductContentList(productVoList);
+                    ref.productContentList = createProductContentList(productVoList);
                 }
             }
             deviceStartInfoList.add(deviceStartInfo);
         }
         result.setDeviceStartInfoList(deviceStartInfoList);
-        // 线程1 更新评估报告知识库
-        syncDatasetsReport(reportContentList, difyScDatasetReportId);
-        // 线程2 更新有样学样的知识库
-        syncDatasetsCase(caseContentList, difyScDatasetCaseId);
-        // 线程3 更新套餐推荐的知识库
-        syncDatasetsProduct(productContentList, difyScDatasetProductId);
-        // 线程4 更新场景推荐的知识库
-        syncDatasetsScene(sceneContentList, difyScDatasetSceneId);
-        // TODO redis缓存同步标识为企业扫识
+
+        // 根据identifier查询设备组中其他设备,拿到其他设备的identifierList
+        List<SmsbDeviceGroupRelVo> groupRelList = smsbDeviceGroupRelMapper.queryGroupRelVoListByIdentifier(smsbStartInfoBo.getIdentifier());
+        // 循环遍历查到的List,根据identifier查询知识库关联表,拿到数据库id更新知识库
+        if (groupRelList == null || groupRelList.isEmpty()) {
+            return R.fail("未找到设备的设备组");
+        }
+
+        groupRelList.forEach(groupRel -> {
+            String difyId = smsbDatasetsIdentifierRelMapper.queryDifyIdByIdentifier(groupRel.getDeviceIdentifier());
+            Long sort = groupRel.getSceneSort();
+            switch (sort.toString()) {
+                case "1":
+                    // 线程1 更新诊断报告的知识库
+                    syncDatasets(ref.reportContentList, difyId);
+                    break;
+                case "2":
+                    // 线程2 更新有样学样的知识库
+                    syncDatasets(ref.caseContentList, difyId);
+                    break;
+                case "3":
+                    // 线程3 更新套餐推荐的知识库
+                    syncDatasets(ref.productContentList, difyId);
+                    break;
+                case "4":
+                    // 线程4 更新场景推荐的知识库
+                    syncDatasets(ref.sceneContentList, difyId);
+                    break;
+                default:
+                    break;
+            }
+        });
+
+        // redis缓存同步标识为企业扫识
         RedisUtils.setCacheObject(REDIS_SYNC_DATASETS_FLAG_KEY, REDIS_SYNC_DATASETS_FLAG_VALUE_ENTERPRISE);
         return R.ok(result);
     }
@@ -865,89 +899,23 @@ public class SmsbAppointmentInfoServiceImpl implements ISmsbAppointmentInfoServi
         return contentList;
     }
 
-    private synchronized void syncDatasetsReport(List<String> contentList, String datasetsId) {
-        Runnable transTask = () -> {
-            try {
-                log.info("syncDatasetsReport thread begin contentList.size(): " + contentList.size() + ",datasetsId : " + datasetsId);
-                // 组装条目
-                StringBuilder allContentStr = new StringBuilder();
-                for (String content : contentList) {
-                    allContentStr.append("###").append("\n");
-                    allContentStr.append(content).append("\n");
-                }
-                String filePath = createTempFile(allContentStr.toString(), "report_");
-                log.info("syncDatasetsReport thread createTempFile success tempFilePath = " + filePath);
-                boolean uploadResult = uploadDatasetsToDify(datasetsId,filePath);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-            log.info("syncDatasetsReport thread end !");
-        };
-        // 提交Runnable任务到线程池
-        threadPoolTaskExecutor.submit(transTask);
-    }
-
-    private synchronized void syncDatasetsCase(List<String> contentList, String datasetsId) {
-        Runnable transTask = () -> {
-            try {
-                log.info("syncDatasetsCase thread begin contentList.size(): " + contentList.size() + ",datasetsId : " + datasetsId);
-                // 组装条目
-                StringBuilder allContentStr = new StringBuilder();
-                for (String content : contentList) {
-                    allContentStr.append("###").append("\n");
-                    allContentStr.append(content).append("\n");
-                }
-                String filePath = createTempFile(allContentStr.toString(), "case_");
-                log.info("syncDatasetsCase thread createTempFile success tempFilePath = " + filePath);
-                boolean uploadResult = uploadDatasetsToDify(datasetsId,filePath);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-            log.info("syncDatasetsCase thread end !");
-        };
-        // 提交Runnable任务到线程池
-        threadPoolTaskExecutor.submit(transTask);
-    }
-
-    private synchronized void syncDatasetsProduct(List<String> contentList, String datasetsId) {
+    private synchronized void syncDatasets(List<String> contentList, String datasetsId) {
         Runnable transTask = () -> {
             try {
-                log.info("syncDatasetsProduct thread begin contentList.size(): " + contentList.size() + ",datasetsId : " + datasetsId);
+                log.info("syncDatasets thread begin contentList.size(): " + contentList.size() + ",datasetsId : " + datasetsId);
                 // 组装条目
                 StringBuilder allContentStr = new StringBuilder();
                 for (String content : contentList) {
                     allContentStr.append("###").append("\n");
                     allContentStr.append(content).append("\n");
                 }
-                String filePath = createTempFile(allContentStr.toString(), "product_");
-                log.info("syncDatasetsProduct thread createTempFile success tempFilePath = " + filePath);
+                String filePath = createTempFile(allContentStr.toString(), datasetsId);
+                log.info("syncDatasets thread createTempFile success tempFilePath = " + filePath);
                 boolean uploadResult = uploadDatasetsToDify(datasetsId,filePath);
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
-            log.info("syncDatasetsProduct thread end !");
-        };
-        // 提交Runnable任务到线程池
-        threadPoolTaskExecutor.submit(transTask);
-    }
-
-    private void syncDatasetsScene(List<String> sceneContentList, String difyScDatasetSceneId) {
-        Runnable transTask = () -> {
-            try {
-                log.info("syncDatasetsScene thread begin contentList.size(): " + sceneContentList.size() + ",datasetsId : " + difyScDatasetSceneId);
-                // 组装条目
-                StringBuilder allContentStr = new StringBuilder();
-                for (String content : sceneContentList) {
-                    allContentStr.append("###").append("\n");
-                    allContentStr.append(content).append("\n");
-                }
-                String filePath = createTempFile(allContentStr.toString(), "scene_");
-                log.info("syncDatasetsScene thread createTempFile success tempFilePath = " + filePath);
-                boolean uploadResult = uploadDatasetsToDify(difyScDatasetSceneId,filePath);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-            log.info("syncDatasetsScene thread end !");
+            log.info("syncDatasets thread end !");
         };
         // 提交Runnable任务到线程池
         threadPoolTaskExecutor.submit(transTask);

+ 136 - 0
smsb-modules/smsb-digital-promotion/src/main/java/com/inspur/digital/service/impl/SmsbDatasetsIdentifierRelServiceImpl.java

@@ -0,0 +1,136 @@
+package com.inspur.digital.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import com.inspur.digital.domain.bo.SmsbDatasetsIdentifierRelBo;
+import com.inspur.digital.domain.vo.SmsbDatasetsIdentifierRelVo;
+import com.inspur.digital.domain.SmsbDatasetsIdentifierRel;
+import com.inspur.digital.mapper.SmsbDatasetsIdentifierRelMapper;
+import com.inspur.digital.service.ISmsbDatasetsIdentifierRelService;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 知识库与设备关联关系Service业务层处理
+ *
+ * @author ZhiCheng Fan
+ * @date 2025-07-18
+ */
+@RequiredArgsConstructor
+@Service
+public class SmsbDatasetsIdentifierRelServiceImpl implements ISmsbDatasetsIdentifierRelService {
+
+    private final SmsbDatasetsIdentifierRelMapper baseMapper;
+
+    /**
+     * 查询知识库与设备关联关系
+     *
+     * @param id 主键
+     * @return 知识库与设备关联关系
+     */
+    @Override
+    public SmsbDatasetsIdentifierRelVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    @Override
+    public SmsbDatasetsIdentifierRelVo queryByIdentifier(String identifier) {
+        return baseMapper.selectVoByIdentifier(identifier);
+    }
+
+    /**
+     * 分页查询知识库与设备关联关系列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 知识库与设备关联关系分页列表
+     */
+    @Override
+    public TableDataInfo<SmsbDatasetsIdentifierRelVo> queryPageList(SmsbDatasetsIdentifierRelBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SmsbDatasetsIdentifierRel> lqw = buildQueryWrapper(bo);
+        Page<SmsbDatasetsIdentifierRelVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的知识库与设备关联关系列表
+     *
+     * @param bo 查询条件
+     * @return 知识库与设备关联关系列表
+     */
+    @Override
+    public List<SmsbDatasetsIdentifierRelVo> queryList(SmsbDatasetsIdentifierRelBo bo) {
+        LambdaQueryWrapper<SmsbDatasetsIdentifierRel> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SmsbDatasetsIdentifierRel> buildQueryWrapper(SmsbDatasetsIdentifierRelBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<SmsbDatasetsIdentifierRel> lqw = Wrappers.lambdaQuery();
+        lqw.eq(bo.getDatasetsId() != null, SmsbDatasetsIdentifierRel::getDatasetsId, bo.getDatasetsId());
+        lqw.eq(bo.getDeviceIdentifier() != null, SmsbDatasetsIdentifierRel::getDeviceIdentifier, bo.getDeviceIdentifier());
+        return lqw;
+    }
+
+    /**
+     * 新增知识库与设备关联关系
+     *
+     * @param bo 知识库与设备关联关系
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(SmsbDatasetsIdentifierRelBo bo) {
+        SmsbDatasetsIdentifierRel add = MapstructUtils.convert(bo, SmsbDatasetsIdentifierRel.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改知识库与设备关联关系
+     *
+     * @param bo 知识库与设备关联关系
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(SmsbDatasetsIdentifierRelBo bo) {
+        SmsbDatasetsIdentifierRel update = MapstructUtils.convert(bo, SmsbDatasetsIdentifierRel.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(SmsbDatasetsIdentifierRel entity){
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除知识库与设备关联关系信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 32 - 0
smsb-modules/smsb-digital-promotion/src/main/resources/mapper/digital/SmsbDatasetsIdentifierRelMapper.xml

@@ -0,0 +1,32 @@
+<?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.inspur.digital.mapper.SmsbDatasetsIdentifierRelMapper">
+
+    <select id="queryDifyIdByIdentifier" resultType="java.lang.String">
+        SELECT
+            dify_id
+        FROM
+            smsb_dify_datasets
+        WHERE
+            id = (
+                SELECT
+                    datasets_id
+                FROM
+                    smsb_datasets_identifier_rel
+                WHERE
+                    device_identifier = #{identifier})
+    </select>
+
+    <select id="selectVoByIdentifier" resultType="com.inspur.digital.domain.vo.SmsbDatasetsIdentifierRelVo">
+        SELECT
+            id,
+            datasets_id AS datasetsId,
+            device_identifier AS deviceIdentifier
+        FROM
+            smsb_datasets_identifier_rel
+        WHERE
+            device_identifier = #{identifier}
+    </select>
+</mapper>

+ 75 - 0
smsb-plus-ui/src/api/smsb/digital/datasetsIdentifierRel/index.ts

@@ -0,0 +1,75 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { DatasetsIdentifierRelVO, DatasetsIdentifierRelForm, DatasetsIdentifierRelQuery } from '@/api/smsb/digital/datasetsIdentifierRel/types';
+
+/**
+ * 查询知识库与设备关联关系列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listDatasetsIdentifierRel = (query?: DatasetsIdentifierRelQuery): AxiosPromise<DatasetsIdentifierRelVO[]> => {
+  return request({
+    url: '/digital/datasetsIdentifierRel/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询知识库与设备关联关系详细
+ * @param id
+ */
+export const getDatasetsIdentifierRel = (id: string | number): AxiosPromise<DatasetsIdentifierRelVO> => {
+  return request({
+    url: '/digital/datasetsIdentifierRel/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 根据identifier查询知识库与设备关联关系详细
+ * @param identifier
+ */
+export const getDatasetsIdentifierRelByIdentifier = (identifier: string | number): AxiosPromise<DatasetsIdentifierRelVO> => {
+  return request({
+    url: '/digital/datasetsIdentifierRel/getInfoByIdentifier',
+    method: 'get',
+    params: { identifier }
+  });
+};
+
+/**
+ * 新增知识库与设备关联关系
+ * @param data
+ */
+export const addDatasetsIdentifierRel = (data: DatasetsIdentifierRelForm) => {
+  return request({
+    url: '/digital/datasetsIdentifierRel',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改知识库与设备关联关系
+ * @param data
+ */
+export const updateDatasetsIdentifierRel = (data: DatasetsIdentifierRelForm) => {
+  return request({
+    url: '/digital/datasetsIdentifierRel',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除知识库与设备关联关系
+ * @param id
+ */
+export const delDatasetsIdentifierRel = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/digital/datasetsIdentifierRel/' + id,
+    method: 'delete'
+  });
+};

+ 56 - 0
smsb-plus-ui/src/api/smsb/digital/datasetsIdentifierRel/types.ts

@@ -0,0 +1,56 @@
+export interface DatasetsIdentifierRelVO {
+  /**
+   * 主键id
+   */
+  id: string | number;
+
+  /**
+   * 知识库id
+   */
+  datasetsId: string | number;
+
+  /**
+   * 设备唯一标识
+   */
+  deviceIdentifier: string | number;
+
+}
+
+export interface DatasetsIdentifierRelForm extends BaseEntity {
+  /**
+   * 主键id
+   */
+  id?: string | number;
+
+  /**
+   * 知识库id
+   */
+  datasetsId?: string | number;
+
+  /**
+   * 设备唯一标识
+   */
+  deviceIdentifier?: string | number;
+
+}
+
+export interface DatasetsIdentifierRelQuery extends PageQuery {
+
+  /**
+   * 知识库id
+   */
+  datasetsId?: string | number;
+
+  /**
+   * 设备唯一标识
+   */
+  deviceIdentifier?: string | number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 100 - 5
smsb-plus-ui/src/views/smsb/deviceGroup/index.vue

@@ -113,19 +113,23 @@
         </template>
         <el-table v-loading="loading" :data="deviceList" @selection-change="handleDevicesSelectionChange">
           <!--          <el-table-column type="selection" width="55" align="center"/>-->
-          <el-table-column label="设备名称" align="left" prop="deviceName" :show-overflow-tooltip="true"/>
+          <el-table-column label="设备名称" align="left" prop="deviceName" width="200" :show-overflow-tooltip="true"/>
           <el-table-column label="场景名称" align="center" prop="sceneName" width="200" :show-overflow-tooltip="true"/>
           <el-table-column label="场景序号" align="center" prop="sceneSort" width="150"/>
-          <el-table-column label="备注" align="left" prop="remark" width="250" :show-overflow-tooltip="true"/>
-          <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100">
+          <el-table-column label="备注" align="left" prop="remark" :show-overflow-tooltip="true"/>
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
             <template #default="scope">
+              <el-tooltip content="分配知识库" placement="top">
+                <el-button link type="primary" icon="Switch" @click="handleRelDevice(scope.row)"
+                           v-hasPermi="['digital:datasetsIdentifierRel:query']"></el-button>
+              </el-tooltip>
               <el-tooltip content="修改" placement="top">
                 <el-button link type="primary" icon="Edit" @click="handleUpdateDevice(scope.row)"
-                           v-hasPermi="['digital:deviceGroup:edit']"></el-button>
+                           v-hasPermi="['digital:deviceGroupRel:edit']"></el-button>
               </el-tooltip>
               <el-tooltip content="删除" placement="top">
                 <el-button link type="primary" icon="Delete" @click="handleDeleteDevice(scope.row)"
-                           v-hasPermi="['digital:deviceGroup:remove']"></el-button>
+                           v-hasPermi="['digital:deviceGroupRel:remove']"></el-button>
               </el-tooltip>
             </template>
           </el-table-column>
@@ -176,6 +180,18 @@
         </div>
       </template>
     </el-dialog>
+
+    <el-dialog :title="datasetsRelLog.title" v-model="datasetsRelLog.visible" width="700px" append-to-body>
+      <el-select v-model="datasetsData.form.datasetsId" filterable placeholder="请选择知识库">
+        <el-option v-for="item in datasetsList" :key="item.id" :value="item.id" :label="item.name"></el-option>
+      </el-select>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitDatasetsRel">确 定</el-button>
+          <el-button @click="cancelDatasets">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -199,12 +215,21 @@ import {
 import {DeviceGroupVO, DeviceGroupQuery, DeviceGroupForm} from '@/api/smsb/digital/deviceGroup/types';
 import {DeviceGroupRelVO, DeviceGroupRelForm, DeviceGroupRelQuery} from '@/api/smsb/digital/deviceGroupRel/types';
 import {DeviceQuery, DeviceVO, DeviceForm} from '@/api/smsb/device/device_type';
+import {DatasetsIdentifierRelForm, DatasetsIdentifierRelQuery} from "@/api/smsb/digital/datasetsIdentifierRel/types";
+import {
+  addDatasetsIdentifierRel,
+  getDatasetsIdentifierRelByIdentifier,
+  updateDatasetsIdentifierRel
+} from "@/api/smsb/digital/datasetsIdentifierRel";
+import {DifyDatasetsQuery, DifyDatasetsVO} from "@/api/smsb/device/datasets_type";
+import {listDifyDatasets} from "@/api/smsb/device/datasets";
 
 const {proxy} = getCurrentInstance() as ComponentInternalInstance;
 
 const deviceGroupList = ref<DeviceGroupVO[]>([]);
 const deviceList = ref<DeviceGroupRelVO[]>([]);
 const devices = ref<DeviceVO[]>([]);
+const datasetsList = ref<DifyDatasetsVO[]>([]);
 const groupId = ref<string | number>();
 const buttonLoading = ref(false);
 const loading = ref(true);
@@ -233,6 +258,11 @@ const addDeviceLog = reactive<DialogOption>({
   title: ''
 });
 
+const datasetsRelLog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
 const initFormData: DeviceGroupForm = {
   id: undefined,
   name: undefined,
@@ -309,6 +339,33 @@ const dataRel = reactive<PageData<DeviceGroupRelForm, DeviceQuery>>({
   }
 });
 
+const initDatasetsFormData: DatasetsIdentifierRelForm = {
+  id: undefined,
+  datasetsId: undefined,
+  deviceIdentifier: undefined,
+}
+const datasetsData = reactive<PageData<DatasetsIdentifierRelForm, DatasetsIdentifierRelQuery>>({
+  form: {...initDatasetsFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    datasetsId: undefined,
+    deviceIdentifier: undefined,
+    params: {}
+  },
+  rules: {
+    id: [
+      {required: false, message: "主键id不能为空", trigger: "blur"}
+    ],
+    datasetsId: [
+      {required: true, message: "知识库id不能为空", trigger: "blur"}
+    ],
+    deviceIdentifier: [
+      {required: true, message: "设备标识不能为空", trigger: "blur"}
+    ],
+  }
+});
+
 const {queryParams, form, rules} = toRefs(data);
 // const { queryParams, form, rules } = toRefs(dataRe);
 
@@ -360,6 +417,26 @@ const handleUpdateDevice = async (row?: DeviceGroupRelVO) => {
   addDeviceLog.title = "修改设备信息";
 }
 
+/** 设备分配知识库 */
+const handleRelDevice = async (row?: DeviceGroupRelVO) => {
+  reset();
+  // const _id = row?.id || ids.value[0]
+  // const res = await getDeviceGroup(_id);
+  datasetsData.form.deviceIdentifier = row.deviceIdentifier;
+  // console.error(datasetsData.form.deviceIdentifier);
+  const res = await getDatasetsIdentifierRelByIdentifier(datasetsData.form.deviceIdentifier);
+  Object.assign(datasetsData.form, res.data);
+  const queryDify: DifyDatasetsQuery = {
+    tag: 1,
+    pageNum: undefined,
+    pageSize: undefined,
+  }
+  let response = await listDifyDatasets(queryDify);
+  datasetsList.value = response.rows;
+  datasetsRelLog.visible = true;
+  datasetsRelLog.title = "分配知识库";
+}
+
 /** 取消按钮 */
 const cancel = () => {
   reset();
@@ -367,6 +444,11 @@ const cancel = () => {
   devicesLog.visible = false;
 }
 
+const cancelDatasets = () => {
+  reset();
+  datasetsRelLog.visible = false;
+}
+
 const cancelAddDevice = () => {
   reset();
   addDeviceLog.visible = false;
@@ -448,6 +530,19 @@ const submitFormRel = () => {
     }
   });
 }
+
+const submitDatasetsRel = async () => {
+  // datasetsData.form.deviceGroupId = groupId.value;
+  buttonLoading.value = true;
+  if (datasetsData.form.id) {
+    await updateDatasetsIdentifierRel(datasetsData.form).finally(() => buttonLoading.value = false);
+  } else {
+    await addDatasetsIdentifierRel(datasetsData.form).finally(() => buttonLoading.value = false);
+  }
+  proxy?.$modal.msgSuccess("操作成功");
+  datasetsRelLog.visible = false;
+}
+
 /** 提交按钮 */
 const submitForm = () => {
   deviceGroupFormRef.value?.validate(async (valid: boolean) => {