From 547953cd00b0affb8db851822bbda93fa846fc90 Mon Sep 17 00:00:00 2001 From: shenaowei <450702724@qq.com> Date: Sun, 22 Feb 2026 23:19:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tik/muye/aiagent/AiAgentController.java | 32 +++++ .../muye/aiagent/service/AiAgentService.java | 10 ++ .../aiagent/service/AiAgentServiceImpl.java | 72 ++++++++++ .../muye/aiagent/vo/AiAgentImportExcelVO.java | 46 +++++++ .../muye/aiagent/vo/AiAgentImportRespVO.java | 34 +++++ .../public/ai_agent_import_template.xlsx | Bin 0 -> 5433 bytes .../src/api/muye/aiagent/index.ts | 7 +- .../src/views/muye/aiagent/AiAgentForm.vue | 55 ++++---- .../views/muye/aiagent/AiAgentImportForm.vue | 125 ++++++++++++++++++ .../src/views/muye/aiagent/index.vue | 90 ++++++++----- 10 files changed, 403 insertions(+), 68 deletions(-) create mode 100644 yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/vo/AiAgentImportExcelVO.java create mode 100644 yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/vo/AiAgentImportRespVO.java create mode 100644 yudao-ui-admin-vue3/public/ai_agent_import_template.xlsx create mode 100644 yudao-ui-admin-vue3/src/views/muye/aiagent/AiAgentImportForm.vue diff --git a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/AiAgentController.java b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/AiAgentController.java index 46e8acfed7..0fdede9cb2 100644 --- a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/AiAgentController.java +++ b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/AiAgentController.java @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.tik.muye.aiagent; import cn.iocoder.yudao.module.tik.muye.aiagent.dal.AiAgentDO; import cn.iocoder.yudao.module.tik.muye.aiagent.service.AiAgentService; +import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentImportExcelVO; +import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentImportRespVO; import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentPageReqVO; import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentRespVO; import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentSaveReqVO; @@ -18,6 +20,8 @@ import jakarta.servlet.http.*; import java.util.*; import java.io.IOException; +import org.springframework.web.multipart.MultipartFile; + import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -101,4 +105,32 @@ public class AiAgentController { BeanUtils.toBean(list, AiAgentRespVO.class)); } + @GetMapping("/get-import-template") + @Operation(summary = "获得AI智能体导入模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 构造示例数据 + List list = Arrays.asList( + AiAgentImportExcelVO.builder() + .agentId("12345") + .agentName("示例智能体") + .categoryName("文案创作") + .icon("https://example.com/icon.png") + .status(1) + .description("这是一个示例智能体的描述") + .systemPrompt("你是一个有帮助的AI助手") + .remark("备注信息") + .build() + ); + // 导出 Excel + ExcelUtils.write(response, "AI智能体导入模板.xls", "智能体列表", AiAgentImportExcelVO.class, list); + } + + @PostMapping("/import") + @Operation(summary = "导入AI智能体") + @PreAuthorize("@ss.hasPermission('muye:ai-agent:create')") + public CommonResult importExcel(@RequestParam("file") MultipartFile file) throws Exception { + List list = ExcelUtils.read(file, AiAgentImportExcelVO.class); + return success(aiAgentService.importAiAgentList(list)); + } + } \ No newline at end of file diff --git a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/service/AiAgentService.java b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/service/AiAgentService.java index c79e835eb0..8ca7792f49 100644 --- a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/service/AiAgentService.java +++ b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/service/AiAgentService.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.tik.muye.aiagent.service; import java.util.*; import cn.iocoder.yudao.module.tik.muye.aiagent.dal.AiAgentDO; +import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentImportExcelVO; +import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentImportRespVO; import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentPageReqVO; import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentSaveReqVO; import jakarta.validation.*; @@ -67,4 +69,12 @@ public interface AiAgentService { */ List getEnabledAgentList(); + /** + * 批量导入AI智能体 + * + * @param importAgents 导入数据列表 + * @return 导入结果 + */ + AiAgentImportRespVO importAiAgentList(List importAgents); + } \ No newline at end of file diff --git a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/service/AiAgentServiceImpl.java b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/service/AiAgentServiceImpl.java index 766e9919b1..1d8d05a844 100644 --- a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/service/AiAgentServiceImpl.java +++ b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/service/AiAgentServiceImpl.java @@ -1,10 +1,14 @@ package cn.iocoder.yudao.module.tik.muye.aiagent.service; import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.tik.muye.aiagent.dal.AiAgentDO; import cn.iocoder.yudao.module.tik.muye.aiagent.mapper.AiAgentMapper; +import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentImportExcelVO; +import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentImportRespVO; import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentPageReqVO; import cn.iocoder.yudao.module.tik.muye.aiagent.vo.AiAgentSaveReqVO; +import cn.hutool.core.collection.CollUtil; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; @@ -12,6 +16,7 @@ import org.springframework.validation.annotation.Validated; import java.util.*; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** @@ -80,4 +85,71 @@ public class AiAgentServiceImpl implements AiAgentService { return aiAgentMapper.selectEnabledList(); } + @Override + public AiAgentImportRespVO importAiAgentList(List importAgents) { + // 1. 参数校验 + if (CollUtil.isEmpty(importAgents)) { + throw exception(new ErrorCode(1005, "导入数据不能为空")); + } + + // 2. 初始化返回结果 + AiAgentImportRespVO respVO = AiAgentImportRespVO.builder() + .createAgentNames(new ArrayList<>()) + .failureAgentNames(new LinkedHashMap<>()) + .build(); + + // 3. 获取当前登录用户信息 + Long operatorId = SecurityFrameworkUtils.getLoginUserId(); + String operatorName = String.valueOf(SecurityFrameworkUtils.getLoginUserNickname()); + + // 4. 遍历逐条处理 + importAgents.forEach(importAgent -> { + try { + // 4.1 必填字段校验 + if (importAgent.getAgentId() == null || importAgent.getAgentId().isEmpty()) { + throw new RuntimeException("智能体ID不能为空"); + } + if (importAgent.getAgentName() == null || importAgent.getAgentName().isEmpty()) { + throw new RuntimeException("智能体名称不能为空"); + } + if (importAgent.getCategoryName() == null || importAgent.getCategoryName().isEmpty()) { + throw new RuntimeException("分类不能为空"); + } + if (importAgent.getIcon() == null || importAgent.getIcon().isEmpty()) { + throw new RuntimeException("图标URL不能为空"); + } + if (importAgent.getStatus() == null) { + throw new RuntimeException("状态不能为空"); + } + if (importAgent.getDescription() == null || importAgent.getDescription().isEmpty()) { + throw new RuntimeException("设定描述不能为空"); + } + if (importAgent.getSystemPrompt() == null || importAgent.getSystemPrompt().isEmpty()) { + throw new RuntimeException("预置提示词不能为空"); + } + + // 4.2 检查 agentId 是否已存在 + AiAgentDO existAgent = aiAgentMapper.selectOne( + new LambdaQueryWrapperX() + .eq(AiAgentDO::getAgentId, importAgent.getAgentId()) + ); + if (existAgent != null) { + respVO.getFailureAgentNames().put(importAgent.getAgentName(), "智能体ID已存在"); + return; + } + + // 4.3 创建智能体 + AiAgentDO aiAgent = BeanUtils.toBean(importAgent, AiAgentDO.class); + aiAgent.setOperatorId(operatorId); + aiAgent.setOperatorName(operatorName); + aiAgentMapper.insert(aiAgent); + respVO.getCreateAgentNames().add(importAgent.getAgentName()); + } catch (Exception ex) { + respVO.getFailureAgentNames().put(importAgent.getAgentName(), ex.getMessage()); + } + }); + + return respVO; + } + } \ No newline at end of file diff --git a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/vo/AiAgentImportExcelVO.java b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/vo/AiAgentImportExcelVO.java new file mode 100644 index 0000000000..ead27a1733 --- /dev/null +++ b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/vo/AiAgentImportExcelVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.tik.muye.aiagent.vo; + +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * AI智能体导入 Excel VO + * + * @author 芋道源码 + */ +@Schema(description = "管理后台 - AI智能体导入 Excel VO") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class AiAgentImportExcelVO { + + @ExcelProperty("智能体ID") + private String agentId; + + @ExcelProperty("智能体名称") + private String agentName; + + @ExcelProperty("分类") + private String categoryName; + + @ExcelProperty("图标URL") + private String icon; + + @ExcelProperty("状态") + private Integer status; + + @ExcelProperty("设定描述") + private String description; + + @ExcelProperty("预置提示词") + private String systemPrompt; + + @ExcelProperty("备注") + private String remark; + +} diff --git a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/vo/AiAgentImportRespVO.java b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/vo/AiAgentImportRespVO.java new file mode 100644 index 0000000000..9b5c52a764 --- /dev/null +++ b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/muye/aiagent/vo/AiAgentImportRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.tik.muye.aiagent.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * AI智能体导入结果 Response VO + * + * @author 芋道源码 + */ +@Schema(description = "管理后台 - AI智能体导入结果 Response VO") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class AiAgentImportRespVO { + + @Schema(description = "创建成功的智能体名称数组") + @Builder.Default + private List createAgentNames = new ArrayList<>(); + + @Schema(description = "导入失败的智能体集合,key 为智能体名称,value 为失败原因") + @Builder.Default + private Map failureAgentNames = new LinkedHashMap<>(); + +} diff --git a/yudao-ui-admin-vue3/public/ai_agent_import_template.xlsx b/yudao-ui-admin-vue3/public/ai_agent_import_template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..38518e4a18e52e19965208d543e2c6523ff5aedb GIT binary patch literal 5433 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 o{6AEGG0sIP{S)T}&M*8AVd-fR;A}GhfCRV6 { return await request.download({ url: `/muye/ai-agent/export-excel`, params }) }, + + // 下载AI智能体导入模板 + importAiAgentTemplate: async () => { + return await request.download({ url: `/muye/ai-agent/get-import-template` }) + } } \ No newline at end of file diff --git a/yudao-ui-admin-vue3/src/views/muye/aiagent/AiAgentForm.vue b/yudao-ui-admin-vue3/src/views/muye/aiagent/AiAgentForm.vue index 22b46e5519..224c6fc577 100644 --- a/yudao-ui-admin-vue3/src/views/muye/aiagent/AiAgentForm.vue +++ b/yudao-ui-admin-vue3/src/views/muye/aiagent/AiAgentForm.vue @@ -13,20 +13,23 @@ + + + - 禁用 - 启用 + 禁用 + 启用 - + - + @@ -41,40 +44,35 @@ diff --git a/yudao-ui-admin-vue3/src/views/muye/aiagent/index.vue b/yudao-ui-admin-vue3/src/views/muye/aiagent/index.vue index a5c30789ce..5802a1a518 100644 --- a/yudao-ui-admin-vue3/src/views/muye/aiagent/index.vue +++ b/yudao-ui-admin-vue3/src/views/muye/aiagent/index.vue @@ -17,10 +17,13 @@ class="!w-240px" /> + + + - - + + @@ -43,6 +46,14 @@ > 导出 + + 导入 + - - - - - - - - - - + + + + + + + + + + + + +