diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java index c4e25a1b..b708b0a3 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatModel.java @@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode; import org.ruoyi.core.domain.BaseEntity; import java.io.Serial; +import java.util.List; /** * 聊天模型对象 chat_model @@ -80,5 +81,10 @@ public class ChatModel extends BaseEntity { */ private String remark; + /** + * 模型能力 + */ + private String modelCapability; + } diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java index 77afe2f4..8472929d 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java @@ -5,14 +5,14 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import lombok.Getter; import org.ruoyi.common.sensitive.annotation.Sensitive; import org.ruoyi.common.sensitive.core.SensitiveStrategy; import org.ruoyi.domain.ChatModel; import java.io.Serial; import java.io.Serializable; - - +import java.util.List; /** @@ -96,4 +96,138 @@ public class ChatModelVo implements Serializable { @ExcelProperty(value = "备注") private String remark; -} + /** + * 模型能力 + */ + @ExcelProperty(value = "模型能力") + private String modelCapability; + + /** + * 模型能力列表 + */ + private List modelAbilities = getModelAbilities(); + + /** + * 模型能力类,类似枚举的静态内部类 + */ + @Getter + public static final class Ability { + // 获取能力名称 + private final String name; + private final String description; + + // 静态字段存储默认能力(类似枚举常量) + public static final Ability IMAGE = new Ability("IMAGE", "图片理解"); + public static final Ability VIDEO = new Ability("VIDEO", "视频理解"); + public static final Ability SPEECH = new Ability("SPEECH", "语音理解"); + + // 动态扩展能力存储 + private static final java.util.Map EXTENDED_ABILITIES = new java.util.HashMap<>(); + + // 私有构造确保受限 + private Ability(String name, String description) { + this.name = name; + this.description = description; + } + + // 静态工厂方法(类似枚举valueOf) + public static Ability valueOf(String name) { + // 先检查默认能力 + switch (name) { + case "IMAGE": return IMAGE; + case "VIDEO": return VIDEO; + case "SPEECH": return SPEECH; + default: + // 检查扩展能力 + Ability ability = EXTENDED_ABILITIES.get(name); + if (ability != null) return ability; + throw new IllegalArgumentException("Unknown ability: " + name); + } + } + + // 动态注册新能力(后期从数据库调用) + public static synchronized Ability registerAbility(String name, String description) { + if (name == null || name.trim().isEmpty()) { + throw new IllegalArgumentException("Ability name cannot be empty"); + } + + // 避免重复注册 + if (EXTENDED_ABILITIES.containsKey(name)) { + return EXTENDED_ABILITIES.get(name); + } + + // 检查是否与默认能力冲突 + try { + valueOf(name); + throw new IllegalArgumentException("Ability already exists as default: " + name); + } catch (IllegalArgumentException e) { + // 正常情况,继续注册 + } + + Ability newAbility = new Ability(name, description); + EXTENDED_ABILITIES.put(name, newAbility); + return newAbility; + } + + // 获取所有能力(默认+扩展) + public static java.util.Set getAllAbilities() { + java.util.Map all = new java.util.HashMap<>(); + all.put(IMAGE.name, IMAGE); + all.put(VIDEO.name, VIDEO); + all.put(SPEECH.name, SPEECH); + all.putAll(EXTENDED_ABILITIES); + return java.util.Collections.unmodifiableSet((java.util.Set) all.values()); + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Ability ability = (Ability) o; + return name.equals(ability.name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + } + + /** + * 将 modelCapability 字符串转换为 Ability 列表 + * @return Ability 列表 + */ + public java.util.List getModelAbilities() { + if (modelCapability == null || modelCapability.trim().isEmpty()) { + return java.util.Collections.emptyList(); + } + + // 解析 JSON 格式的字符串数组 + String trimmed = modelCapability.trim(); + if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) { + throw new IllegalArgumentException("Invalid modelCapability format: " + modelCapability); + } + + String content = trimmed.substring(1, trimmed.length() - 1).trim(); + if (content.isEmpty()) { + return java.util.Collections.emptyList(); + } + + java.util.List abilities = new java.util.ArrayList<>(); + String[] items = content.split(","); + for (String item : items) { + String cleanedItem = item.trim(); + if (cleanedItem.startsWith("\"") && cleanedItem.endsWith("\"") && cleanedItem.length() >= 2) { + String abilityName = cleanedItem.substring(1, cleanedItem.length() - 1); + abilities.add(Ability.valueOf(abilityName)); + } + } + + return abilities; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/controller/GenController.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/controller/GenController.java index 52f78ecd..2e394a05 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/controller/GenController.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/controller/GenController.java @@ -1,5 +1,6 @@ package org.ruoyi.generator.controller; +import cn.hutool.core.net.URLDecoder; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.ruoyi.common.core.domain.R; @@ -8,10 +9,11 @@ import org.ruoyi.generator.service.IGenTableService; import org.ruoyi.generator.service.SchemaFieldService; import org.springframework.context.annotation.Profile; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.nio.charset.StandardCharsets; + /** * 代码生成 操作处理 * @@ -46,4 +48,18 @@ public class GenController extends BaseController { genTableService.generateCodeToClasspathByTableNames(tableNameStr); return R.ok("代码生成成功"); } + + /** + * 生成前端代码 + * + * @param workPath 执行命令路径 + * @param previewCode 执行生成前端文件命令 + */ + @GetMapping("/batchGenFrontendCode") + public R batchGenFrontendCode(@NotNull(message = "路径不能为空") String workPath, @NotNull(message = "指令不能为空") String previewCode) { + String decodedWorkPath = URLDecoder.decode(workPath, StandardCharsets.UTF_8); + String decodedPreviewCode = URLDecoder.decode(previewCode, StandardCharsets.UTF_8); + genTableService.generateFrontendTemplateFiles(decodedWorkPath, decodedPreviewCode); + return R.ok("代码生成成功"); + } } diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/GenTableServiceImpl.java index 6ecbfd15..7d6da9f7 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/GenTableServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/GenTableServiceImpl.java @@ -21,18 +21,9 @@ import org.ruoyi.generator.util.VelocityInitializer; import org.ruoyi.generator.util.VelocityUtils; import org.springframework.stereotype.Service; -import java.io.File; -import java.io.FileWriter; -import java.io.StringWriter; +import java.io.*; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; /** * 业务 服务层实现 @@ -62,6 +53,41 @@ public class GenTableServiceImpl implements IGenTableService { } } + @Override + public void generateFrontendTemplateFiles(String workPath, String previewCode) { + String os = System.getProperty("os.name").toLowerCase(); + + ProcessBuilder builder; + if (os.contains("win")) { + // Windows下用 cmd /c 执行 previewCode + builder = new ProcessBuilder("cmd.exe", "/c", previewCode); + } else { + // macOS/Linux 用 bash -c 执行 previewCode + builder = new ProcessBuilder("bash", "-c", previewCode); + } + + // 设置工作目录 + builder.directory(new File(workPath)); + builder.redirectErrorStream(true); + + try (BufferedReader reader = new BufferedReader( + new InputStreamReader( + builder.start().getInputStream(), + StandardCharsets.UTF_8 + ) + )) { + String line; + log.info("执行结果:"); + while ((line = reader.readLine()) != null) { + log.info(line); + } + + } catch (Exception e) { + log.error("生成前端代码出错", e); + throw new RuntimeException("生成前端代码失败", e); + } + } + /** * 根据表名称生成代码到classpath */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/service/IGenTableService.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/service/IGenTableService.java index bd8e291a..4403d3b7 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/service/IGenTableService.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/service/IGenTableService.java @@ -13,4 +13,12 @@ public interface IGenTableService { * @param tableName 表名称数组 */ void generateCodeToClasspathByTableNames(String tableName); + + /** + * 生成前端文件 + * + * @param workPath 执行命令路径 + * @param previewCode 执行生成前端文件命令 + */ + void generateFrontendTemplateFiles(String workPath, String previewCode); } diff --git a/script/sql/update/20250808.sql b/script/sql/update/20250808.sql new file mode 100644 index 00000000..3c54c207 --- /dev/null +++ b/script/sql/update/20250808.sql @@ -0,0 +1,3 @@ +-- 聊天模型表添加模型能力字段 +alter table chat_model + add model_capability varchar(255) default '[]' not null comment '模型能力'; diff --git a/script/sql/update/knowledge-role-bak.sql b/script/sql/update/knowledge-role-bak.sql index 5dfd35e7..62a7ce67 100644 --- a/script/sql/update/knowledge-role-bak.sql +++ b/script/sql/update/knowledge-role-bak.sql @@ -74,7 +74,7 @@ SET FOREIGN_KEY_CHECKS = 1; -- 菜单 -INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1946483381643743233, '知识库角色管理', 1775500307898949634, '12', 'knowledgeRole', 'system/knowledgeRole/index', NULL, 1, 0, 'C', '0', '0', NULL, 'ri:user-3-fill', 103, 1, '2025-07-19 16:41:17', NULL, NULL, '知识库角色管理'); +INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1946483381643743233, '知识库角色管理', 1775500307898949634, '12', 'knowledgeRole', 'operator/knowledgeRole/index', NULL, 1, 0, 'C', '0', '0', NULL, 'ri:user-3-fill', 103, 1, '2025-07-19 16:41:17', NULL, NULL, '知识库角色管理'); -- 用户表添加字段 ALTER TABLE sys_user