From 838a393abc748bc6b4c8c311a49a8e02ff42c32c Mon Sep 17 00:00:00 2001 From: l90215 Date: Thu, 7 Aug 2025 21:13:02 +0800 Subject: [PATCH 01/33] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=A9=BA?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/ruoyi/generator/impl/GenTableServiceImpl.java | 1 + 1 file changed, 1 insertion(+) 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 9ef76085..e4a85949 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 @@ -69,6 +69,7 @@ public class GenTableServiceImpl implements IGenTableService { log.warn("Schema不存在,表名: {}", tableName); return; } + // 查询Schema字段信息 List fields = schemaFieldService.queryListByTableName(tableName); if (CollUtil.isEmpty(fields)) { From 5a4d76ac097da8d7f41bdf9f8076132f1fe9f693 Mon Sep 17 00:00:00 2001 From: fy53888 Date: Sat, 9 Aug 2025 21:55:23 +0800 Subject: [PATCH 02/33] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E7=94=9F=E6=88=90=E9=A1=9E=E5=9E=8B=20Integer=E5=87=BA?= =?UTF-8?q?=E9=8C=AF=E7=9A=84=E5=95=8F=E9=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 2 +- ruoyi-modules/ruoyi-generator/pom.xml | 4 + .../generator/impl/GenTableServiceImpl.java | 2 +- .../impl/SchemaFieldServiceImpl.java | 2 +- .../system/controller/SysDemoController.java | 105 ++++++++++++++++ .../java/org/ruoyi/system/domain/SysDemo.java | 75 +++++++++++ .../org/ruoyi/system/domain/bo/SysDemoBo.java | 84 +++++++++++++ .../org/ruoyi/system/domain/vo/SysDemoVo.java | 86 +++++++++++++ .../ruoyi/system/mapper/SysDemoMapper.java | 17 +++ .../ruoyi/system/service/SysDemoService.java | 48 ++++++++ .../service/impl/SysDemoServiceImpl.java | 116 ++++++++++++++++++ .../org/ruoyi/system/sql/sys_demo_menu.sql | 19 +++ .../resources/mapper/system/SysDemoMapper.xml | 7 ++ 13 files changed, 564 insertions(+), 3 deletions(-) create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/SysDemoController.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/SysDemo.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/SysDemoBo.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/SysDemoVo.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/SysDemoMapper.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/SysDemoService.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/SysDemoServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/sys_demo_menu.sql create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/SysDemoMapper.xml diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 8abf1a68..0b1661e2 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -18,7 +18,7 @@ spring: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true username: root - password: root + password: 123456 hikari: # 最大连接池数量 diff --git a/ruoyi-modules/ruoyi-generator/pom.xml b/ruoyi-modules/ruoyi-generator/pom.xml index c6ab5e3c..e545d91b 100644 --- a/ruoyi-modules/ruoyi-generator/pom.xml +++ b/ruoyi-modules/ruoyi-generator/pom.xml @@ -48,6 +48,10 @@ org.apache.velocity velocity-engine-core + + org.ruoyi + ruoyi-common-excel + 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 9ef76085..fd83f558 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 @@ -412,7 +412,7 @@ public class GenTableServiceImpl implements IGenTableService { return "String"; } String type = dbType.toLowerCase(); - if (type.contains("int") || type.contains("tinyint") || type.contains("smallint")) { + if (Objects.equals(type,"int") || type.contains("tinyint") || type.contains("smallint")) { return "Integer"; } else if (type.contains("bigint")) { return "Long"; diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java index e8295f88..ebae5510 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java @@ -363,7 +363,7 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { } String type = dbType.toLowerCase(); - if (type.contains("int") || type.contains("tinyint") || type.contains("smallint")) { + if (Objects.equals(type,"int")|| type.contains("tinyint") || type.contains("smallint")) { return "Integer"; } else if (type.contains("bigint")) { return "Long"; diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/SysDemoController.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/SysDemoController.java new file mode 100644 index 00000000..0c795ed9 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/SysDemoController.java @@ -0,0 +1,105 @@ +package org.ruoyi.system.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.ruoyi.common.idempotent.annotation.RepeatSubmit; +import org.ruoyi.common.log.annotation.Log; +import org.ruoyi.common.web.core.BaseController; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.common.core.domain.R; +import org.ruoyi.common.core.validate.AddGroup; +import org.ruoyi.common.core.validate.EditGroup; +import org.ruoyi.common.log.enums.BusinessType; +import org.ruoyi.common.excel.utils.ExcelUtil; +import org.ruoyi.system.domain.vo.SysDemoVo; +import org.ruoyi.system.domain.bo.SysDemoBo; +import org.ruoyi.system.service.SysDemoService; +import org.ruoyi.core.page.TableDataInfo; + +/** + * dome管理 + * + * @author ageerle + * @date Sat Aug 09 21:38:09 CST 2025 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("dev/sysDemo") +public class SysDemoController extends BaseController { + + private final SysDemoService sysDemoService; + +/** + * 查询dome管理列表 + */ +@SaCheckPermission("system:sysDemo:list") +@GetMapping("/list") + public TableDataInfo list(SysDemoBo bo, PageQuery pageQuery) { + return sysDemoService.queryPageList(bo, pageQuery); + } + + /** + * 导出dome管理列表 + */ + @SaCheckPermission("system:sysDemo:export") + @Log(title = "dome管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysDemoBo bo, HttpServletResponse response) { + List list = sysDemoService.queryList(bo); + ExcelUtil.exportExcel(list, "dome管理", SysDemoVo.class, response); + } + + /** + * 获取dome管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:sysDemo:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Integer id) { + return R.ok(sysDemoService.queryById(id)); + } + + /** + * 新增dome管理 + */ + @SaCheckPermission("system:sysDemo:add") + @Log(title = "dome管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysDemoBo bo) { + return toAjax(sysDemoService.insertByBo(bo)); + } + + /** + * 修改dome管理 + */ + @SaCheckPermission("system:sysDemo:edit") + @Log(title = "dome管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysDemoBo bo) { + return toAjax(sysDemoService.updateByBo(bo)); + } + + /** + * 删除dome管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:sysDemo:remove") + @Log(title = "dome管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Integer[] ids) { + return toAjax(sysDemoService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/SysDemo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/SysDemo.java new file mode 100644 index 00000000..81187bf2 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/SysDemo.java @@ -0,0 +1,75 @@ +package org.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + import java.util.Date; + import java.io.Serializable; + +import org.ruoyi.core.domain.BaseEntity; + +/** + * dome管理对象 sys_demo + * + * @author ageerle + * @date Sat Aug 09 21:38:09 CST 2025 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_demo") +public class SysDemo extends BaseEntity { + + + /** + * ID + */ + @TableId(value = "id") + private Integer id; + + /** + * 系统代码 + */ + private String sysCode; + + /** + * 系统名称 + */ + private String sysName; + + /** + * 系统状态 + */ + private Integer sysStatus; + + /** + * 创建部门 + */ + private Integer createDept; + + /** + * 创建者 + */ + private Integer createBy; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新者 + */ + private Integer updateBy; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/SysDemoBo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/SysDemoBo.java new file mode 100644 index 00000000..caca34c1 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/SysDemoBo.java @@ -0,0 +1,84 @@ +package org.ruoyi.system.domain.bo; + +import org.ruoyi.system.domain.SysDemo; +import org.ruoyi.core.domain.BaseEntity; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.util.Date; +import java.io.Serializable; +import org.ruoyi.common.core.validate.AddGroup; +import org.ruoyi.common.core.validate.EditGroup; +import java.io.Serializable; +import java.io.Serializable; +import org.ruoyi.common.core.validate.AddGroup; +import org.ruoyi.common.core.validate.EditGroup; + +/** + * dome管理业务对象 sys_demo + * + * @author ageerle + * @date Sat Aug 09 21:38:09 CST 2025 + */ +@Data + +@AutoMapper(target = SysDemo.class, reverseConvertGenerate = false) +public class SysDemoBo implements Serializable { + + /** + * ID + */ + @NotNull(message = "ID不能为空", groups = { EditGroup.class }) + private Integer id; + + /** + * 系统代码 + */ + @NotBlank(message = "系统代码不能为空", groups = { AddGroup.class, EditGroup.class }) + private String sysCode; + + /** + * 系统名称 + */ + @NotBlank(message = "系统名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String sysName; + + /** + * 系统状态 + */ + @NotNull(message = "系统状态不能为空", groups = { AddGroup.class, EditGroup.class }) + private Integer sysStatus; + + /** + * 创建部门 + */ + private Integer createDept; + + /** + * 创建者 + */ + private Integer createBy; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新者 + */ + private Integer updateBy; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/SysDemoVo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/SysDemoVo.java new file mode 100644 index 00000000..0fd9f1a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/SysDemoVo.java @@ -0,0 +1,86 @@ +package org.ruoyi.system.domain.vo; + + import java.util.Date; + import java.io.Serializable; +import org.ruoyi.system.domain.SysDemo; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.util.Date; + + +/** + * dome管理视图对象 sys_demo + * + * @author ageerle + * @date Sat Aug 09 21:38:09 CST 2025 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDemo.class) +public class SysDemoVo implements Serializable { + + /** + * ID + */ + @ExcelProperty(value = "ID") + private Integer id; + + /** + * 系统代码 + */ + @ExcelProperty(value = "系统代码") + private String sysCode; + + /** + * 系统名称 + */ + @ExcelProperty(value = "系统名称") + private String sysName; + + /** + * 系统状态 + */ + @ExcelProperty(value = "系统状态") + private Integer sysStatus; + + /** + * 创建部门 + */ + @ExcelProperty(value = "创建部门") + private Integer createDept; + + /** + * 创建者 + */ + @ExcelProperty(value = "创建者") + private Integer createBy; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 更新者 + */ + @ExcelProperty(value = "更新者") + private Integer updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updateTime; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/SysDemoMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/SysDemoMapper.java new file mode 100644 index 00000000..94351479 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/SysDemoMapper.java @@ -0,0 +1,17 @@ +package org.ruoyi.system.mapper; + +import org.ruoyi.system.domain.SysDemo; +import org.ruoyi.system.domain.vo.SysDemoVo; +import org.ruoyi.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Mapper; + +/** + * dome管理Mapper接口 + * + * @author ageerle + * @date Sat Aug 09 21:38:09 CST 2025 + */ +@Mapper +public interface SysDemoMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/SysDemoService.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/SysDemoService.java new file mode 100644 index 00000000..ae7f4901 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/SysDemoService.java @@ -0,0 +1,48 @@ +package org.ruoyi.system.service; + +import org.ruoyi.system.domain.vo.SysDemoVo; +import org.ruoyi.system.domain.bo.SysDemoBo; + import org.ruoyi.core.page.TableDataInfo; + import org.ruoyi.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * dome管理Service接口 + * + * @author ageerle + * @date Sat Aug 09 21:38:09 CST 2025 + */ +public interface SysDemoService { + + /** + * 查询dome管理 + */ + SysDemoVo queryById(Integer id); + + /** + * 查询dome管理列表 + */ + TableDataInfo queryPageList(SysDemoBo bo, PageQuery pageQuery); + + /** + * 查询dome管理列表 + */ + List queryList(SysDemoBo bo); + + /** + * 新增dome管理 + */ + Boolean insertByBo(SysDemoBo bo); + + /** + * 修改dome管理 + */ + Boolean updateByBo(SysDemoBo bo); + + /** + * 校验并批量删除dome管理信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/SysDemoServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/SysDemoServiceImpl.java new file mode 100644 index 00000000..a0bd9054 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/SysDemoServiceImpl.java @@ -0,0 +1,116 @@ +package org.ruoyi.system.service.impl; + +import org.ruoyi.common.core.utils.MapstructUtils; + import org.ruoyi.core.page.TableDataInfo; + import org.ruoyi.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 org.ruoyi.system.domain.bo.SysDemoBo; +import org.ruoyi.system.domain.vo.SysDemoVo; +import org.ruoyi.system.domain.SysDemo; +import org.ruoyi.system.mapper.SysDemoMapper; +import org.ruoyi.system.service.SysDemoService; +import org.ruoyi.common.core.utils.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * dome管理Service业务层处理 + * + * @author ageerle + * @date Sat Aug 09 21:38:09 CST 2025 + */ +@RequiredArgsConstructor +@Service +public class SysDemoServiceImpl implements SysDemoService { + + private final SysDemoMapper baseMapper; + + /** + * 查询dome管理 + */ + @Override + public SysDemoVo queryById(Integer id) { + return baseMapper.selectVoById(id); + } + + /** + * 查询dome管理列表 + */ + @Override + public TableDataInfo queryPageList(SysDemoBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询dome管理列表 + */ + @Override + public List queryList(SysDemoBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysDemoBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getSysCode()), SysDemo::getSysCode, bo.getSysCode()); + lqw.eq(StringUtils.isNotBlank(bo.getSysName()), SysDemo::getSysName, bo.getSysName()); + lqw.eq(bo.getSysStatus() != null, SysDemo::getSysStatus, bo.getSysStatus()); + lqw.eq(bo.getCreateDept() != null, SysDemo::getCreateDept, bo.getCreateDept()); + lqw.eq(bo.getCreateBy() != null, SysDemo::getCreateBy, bo.getCreateBy()); + lqw.eq(bo.getCreateTime() != null, SysDemo::getCreateTime, bo.getCreateTime()); + lqw.eq(bo.getUpdateBy() != null, SysDemo::getUpdateBy, bo.getUpdateBy()); + lqw.eq(bo.getUpdateTime() != null, SysDemo::getUpdateTime, bo.getUpdateTime()); + lqw.eq(StringUtils.isNotBlank(bo.getRemark()), SysDemo::getRemark, bo.getRemark()); + return lqw; + } + + /** + * 新增dome管理 + */ + @Override + public Boolean insertByBo(SysDemoBo bo) { + SysDemo add = MapstructUtils.convert(bo, SysDemo. class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改dome管理 + */ + @Override + public Boolean updateByBo(SysDemoBo bo) { + SysDemo update = MapstructUtils.convert(bo, SysDemo. class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysDemo entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除dome管理 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/sys_demo_menu.sql b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/sys_demo_menu.sql new file mode 100644 index 00000000..5b19392a --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/sys_demo_menu.sql @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1954175368920645632, 'dome管理', '2000', '1', 'sysDemo', 'system/sysDemo/index', 1, 0, 'C', '0', '0', 'system:sysDemo:list', '#', 103, 1, sysdate(), null, null, 'dome管理菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1954175368920645633, 'dome管理查询', 1954175368920645632, '1', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1954175368920645634, 'dome管理新增', 1954175368920645632, '2', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1954175368920645635, 'dome管理修改', 1954175368920645632, '3', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1954175368920645636, 'dome管理删除', 1954175368920645632, '4', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1954175368920645637, 'dome管理导出', 1954175368920645632, '5', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:export', '#', 103, 1, sysdate(), null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/SysDemoMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/SysDemoMapper.xml new file mode 100644 index 00000000..c35ba06c --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/SysDemoMapper.xml @@ -0,0 +1,7 @@ + + + + + From 9f4a2256b4523aaa3f126a04f39bc6847504fa6f Mon Sep 17 00:00:00 2001 From: fy53888 Date: Sat, 9 Aug 2025 21:56:16 +0800 Subject: [PATCH 03/33] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E7=94=9F=E6=88=90=E9=A1=9E=E5=9E=8B=20Integer=E5=87=BA?= =?UTF-8?q?=E9=8C=AF=E7=9A=84=E5=95=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/controller/SysDemoController.java | 105 ---------------- .../java/org/ruoyi/system/domain/SysDemo.java | 75 ----------- .../org/ruoyi/system/domain/bo/SysDemoBo.java | 84 ------------- .../org/ruoyi/system/domain/vo/SysDemoVo.java | 86 ------------- .../ruoyi/system/mapper/SysDemoMapper.java | 17 --- .../ruoyi/system/service/SysDemoService.java | 48 -------- .../service/impl/SysDemoServiceImpl.java | 116 ------------------ .../org/ruoyi/system/sql/sys_demo_menu.sql | 19 --- 8 files changed, 550 deletions(-) delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/SysDemoController.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/SysDemo.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/SysDemoBo.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/SysDemoVo.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/SysDemoMapper.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/SysDemoService.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/SysDemoServiceImpl.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/sys_demo_menu.sql diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/SysDemoController.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/SysDemoController.java deleted file mode 100644 index 0c795ed9..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/SysDemoController.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.ruoyi.system.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.ruoyi.common.idempotent.annotation.RepeatSubmit; -import org.ruoyi.common.log.annotation.Log; -import org.ruoyi.common.web.core.BaseController; -import org.ruoyi.core.page.PageQuery; -import org.ruoyi.common.core.domain.R; -import org.ruoyi.common.core.validate.AddGroup; -import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.common.log.enums.BusinessType; -import org.ruoyi.common.excel.utils.ExcelUtil; -import org.ruoyi.system.domain.vo.SysDemoVo; -import org.ruoyi.system.domain.bo.SysDemoBo; -import org.ruoyi.system.service.SysDemoService; -import org.ruoyi.core.page.TableDataInfo; - -/** - * dome管理 - * - * @author ageerle - * @date Sat Aug 09 21:38:09 CST 2025 - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("dev/sysDemo") -public class SysDemoController extends BaseController { - - private final SysDemoService sysDemoService; - -/** - * 查询dome管理列表 - */ -@SaCheckPermission("system:sysDemo:list") -@GetMapping("/list") - public TableDataInfo list(SysDemoBo bo, PageQuery pageQuery) { - return sysDemoService.queryPageList(bo, pageQuery); - } - - /** - * 导出dome管理列表 - */ - @SaCheckPermission("system:sysDemo:export") - @Log(title = "dome管理", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(SysDemoBo bo, HttpServletResponse response) { - List list = sysDemoService.queryList(bo); - ExcelUtil.exportExcel(list, "dome管理", SysDemoVo.class, response); - } - - /** - * 获取dome管理详细信息 - * - * @param id 主键 - */ - @SaCheckPermission("system:sysDemo:query") - @GetMapping("/{id}") - public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Integer id) { - return R.ok(sysDemoService.queryById(id)); - } - - /** - * 新增dome管理 - */ - @SaCheckPermission("system:sysDemo:add") - @Log(title = "dome管理", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping() - public R add(@Validated(AddGroup.class) @RequestBody SysDemoBo bo) { - return toAjax(sysDemoService.insertByBo(bo)); - } - - /** - * 修改dome管理 - */ - @SaCheckPermission("system:sysDemo:edit") - @Log(title = "dome管理", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping() - public R edit(@Validated(EditGroup.class) @RequestBody SysDemoBo bo) { - return toAjax(sysDemoService.updateByBo(bo)); - } - - /** - * 删除dome管理 - * - * @param ids 主键串 - */ - @SaCheckPermission("system:sysDemo:remove") - @Log(title = "dome管理", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Integer[] ids) { - return toAjax(sysDemoService.deleteWithValidByIds(List.of(ids), true)); - } -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/SysDemo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/SysDemo.java deleted file mode 100644 index 81187bf2..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/SysDemo.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.ruoyi.system.domain; - -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - import java.util.Date; - import java.io.Serializable; - -import org.ruoyi.core.domain.BaseEntity; - -/** - * dome管理对象 sys_demo - * - * @author ageerle - * @date Sat Aug 09 21:38:09 CST 2025 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@TableName("sys_demo") -public class SysDemo extends BaseEntity { - - - /** - * ID - */ - @TableId(value = "id") - private Integer id; - - /** - * 系统代码 - */ - private String sysCode; - - /** - * 系统名称 - */ - private String sysName; - - /** - * 系统状态 - */ - private Integer sysStatus; - - /** - * 创建部门 - */ - private Integer createDept; - - /** - * 创建者 - */ - private Integer createBy; - - /** - * 创建时间 - */ - private Date createTime; - - /** - * 更新者 - */ - private Integer updateBy; - - /** - * 更新时间 - */ - private Date updateTime; - - /** - * 备注 - */ - private String remark; - - -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/SysDemoBo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/SysDemoBo.java deleted file mode 100644 index caca34c1..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/SysDemoBo.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.ruoyi.system.domain.bo; - -import org.ruoyi.system.domain.SysDemo; -import org.ruoyi.core.domain.BaseEntity; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; -import lombok.EqualsAndHashCode; -import jakarta.validation.constraints.*; -import java.util.Date; -import java.io.Serializable; -import org.ruoyi.common.core.validate.AddGroup; -import org.ruoyi.common.core.validate.EditGroup; -import java.io.Serializable; -import java.io.Serializable; -import org.ruoyi.common.core.validate.AddGroup; -import org.ruoyi.common.core.validate.EditGroup; - -/** - * dome管理业务对象 sys_demo - * - * @author ageerle - * @date Sat Aug 09 21:38:09 CST 2025 - */ -@Data - -@AutoMapper(target = SysDemo.class, reverseConvertGenerate = false) -public class SysDemoBo implements Serializable { - - /** - * ID - */ - @NotNull(message = "ID不能为空", groups = { EditGroup.class }) - private Integer id; - - /** - * 系统代码 - */ - @NotBlank(message = "系统代码不能为空", groups = { AddGroup.class, EditGroup.class }) - private String sysCode; - - /** - * 系统名称 - */ - @NotBlank(message = "系统名称不能为空", groups = { AddGroup.class, EditGroup.class }) - private String sysName; - - /** - * 系统状态 - */ - @NotNull(message = "系统状态不能为空", groups = { AddGroup.class, EditGroup.class }) - private Integer sysStatus; - - /** - * 创建部门 - */ - private Integer createDept; - - /** - * 创建者 - */ - private Integer createBy; - - /** - * 创建时间 - */ - private Date createTime; - - /** - * 更新者 - */ - private Integer updateBy; - - /** - * 更新时间 - */ - private Date updateTime; - - /** - * 备注 - */ - private String remark; - - -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/SysDemoVo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/SysDemoVo.java deleted file mode 100644 index 0fd9f1a5..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/SysDemoVo.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.ruoyi.system.domain.vo; - - import java.util.Date; - import java.io.Serializable; -import org.ruoyi.system.domain.SysDemo; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; - -import java.util.Date; - - -/** - * dome管理视图对象 sys_demo - * - * @author ageerle - * @date Sat Aug 09 21:38:09 CST 2025 - */ -@Data -@ExcelIgnoreUnannotated -@AutoMapper(target = SysDemo.class) -public class SysDemoVo implements Serializable { - - /** - * ID - */ - @ExcelProperty(value = "ID") - private Integer id; - - /** - * 系统代码 - */ - @ExcelProperty(value = "系统代码") - private String sysCode; - - /** - * 系统名称 - */ - @ExcelProperty(value = "系统名称") - private String sysName; - - /** - * 系统状态 - */ - @ExcelProperty(value = "系统状态") - private Integer sysStatus; - - /** - * 创建部门 - */ - @ExcelProperty(value = "创建部门") - private Integer createDept; - - /** - * 创建者 - */ - @ExcelProperty(value = "创建者") - private Integer createBy; - - /** - * 创建时间 - */ - @ExcelProperty(value = "创建时间") - private Date createTime; - - /** - * 更新者 - */ - @ExcelProperty(value = "更新者") - private Integer updateBy; - - /** - * 更新时间 - */ - @ExcelProperty(value = "更新时间") - private Date updateTime; - - /** - * 备注 - */ - @ExcelProperty(value = "备注") - private String remark; - - -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/SysDemoMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/SysDemoMapper.java deleted file mode 100644 index 94351479..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/SysDemoMapper.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.ruoyi.system.mapper; - -import org.ruoyi.system.domain.SysDemo; -import org.ruoyi.system.domain.vo.SysDemoVo; -import org.ruoyi.core.mapper.BaseMapperPlus; -import org.apache.ibatis.annotations.Mapper; - -/** - * dome管理Mapper接口 - * - * @author ageerle - * @date Sat Aug 09 21:38:09 CST 2025 - */ -@Mapper -public interface SysDemoMapper extends BaseMapperPlus { - -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/SysDemoService.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/SysDemoService.java deleted file mode 100644 index ae7f4901..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/SysDemoService.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.ruoyi.system.service; - -import org.ruoyi.system.domain.vo.SysDemoVo; -import org.ruoyi.system.domain.bo.SysDemoBo; - import org.ruoyi.core.page.TableDataInfo; - import org.ruoyi.core.page.PageQuery; - -import java.util.Collection; -import java.util.List; - -/** - * dome管理Service接口 - * - * @author ageerle - * @date Sat Aug 09 21:38:09 CST 2025 - */ -public interface SysDemoService { - - /** - * 查询dome管理 - */ - SysDemoVo queryById(Integer id); - - /** - * 查询dome管理列表 - */ - TableDataInfo queryPageList(SysDemoBo bo, PageQuery pageQuery); - - /** - * 查询dome管理列表 - */ - List queryList(SysDemoBo bo); - - /** - * 新增dome管理 - */ - Boolean insertByBo(SysDemoBo bo); - - /** - * 修改dome管理 - */ - Boolean updateByBo(SysDemoBo bo); - - /** - * 校验并批量删除dome管理信息 - */ - Boolean deleteWithValidByIds(Collection ids, Boolean isValid); -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/SysDemoServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/SysDemoServiceImpl.java deleted file mode 100644 index a0bd9054..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/SysDemoServiceImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.ruoyi.system.service.impl; - -import org.ruoyi.common.core.utils.MapstructUtils; - import org.ruoyi.core.page.TableDataInfo; - import org.ruoyi.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 org.ruoyi.system.domain.bo.SysDemoBo; -import org.ruoyi.system.domain.vo.SysDemoVo; -import org.ruoyi.system.domain.SysDemo; -import org.ruoyi.system.mapper.SysDemoMapper; -import org.ruoyi.system.service.SysDemoService; -import org.ruoyi.common.core.utils.StringUtils; - -import java.util.List; -import java.util.Map; -import java.util.Collection; - -/** - * dome管理Service业务层处理 - * - * @author ageerle - * @date Sat Aug 09 21:38:09 CST 2025 - */ -@RequiredArgsConstructor -@Service -public class SysDemoServiceImpl implements SysDemoService { - - private final SysDemoMapper baseMapper; - - /** - * 查询dome管理 - */ - @Override - public SysDemoVo queryById(Integer id) { - return baseMapper.selectVoById(id); - } - - /** - * 查询dome管理列表 - */ - @Override - public TableDataInfo queryPageList(SysDemoBo bo, PageQuery pageQuery) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); - return TableDataInfo.build(result); - } - - /** - * 查询dome管理列表 - */ - @Override - public List queryList(SysDemoBo bo) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - return baseMapper.selectVoList(lqw); - } - - private LambdaQueryWrapper buildQueryWrapper(SysDemoBo bo) { - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(StringUtils.isNotBlank(bo.getSysCode()), SysDemo::getSysCode, bo.getSysCode()); - lqw.eq(StringUtils.isNotBlank(bo.getSysName()), SysDemo::getSysName, bo.getSysName()); - lqw.eq(bo.getSysStatus() != null, SysDemo::getSysStatus, bo.getSysStatus()); - lqw.eq(bo.getCreateDept() != null, SysDemo::getCreateDept, bo.getCreateDept()); - lqw.eq(bo.getCreateBy() != null, SysDemo::getCreateBy, bo.getCreateBy()); - lqw.eq(bo.getCreateTime() != null, SysDemo::getCreateTime, bo.getCreateTime()); - lqw.eq(bo.getUpdateBy() != null, SysDemo::getUpdateBy, bo.getUpdateBy()); - lqw.eq(bo.getUpdateTime() != null, SysDemo::getUpdateTime, bo.getUpdateTime()); - lqw.eq(StringUtils.isNotBlank(bo.getRemark()), SysDemo::getRemark, bo.getRemark()); - return lqw; - } - - /** - * 新增dome管理 - */ - @Override - public Boolean insertByBo(SysDemoBo bo) { - SysDemo add = MapstructUtils.convert(bo, SysDemo. class); - validEntityBeforeSave(add); - boolean flag = baseMapper.insert(add) > 0; - if (flag) { - bo.setId(add.getId()); - } - return flag; - } - - /** - * 修改dome管理 - */ - @Override - public Boolean updateByBo(SysDemoBo bo) { - SysDemo update = MapstructUtils.convert(bo, SysDemo. class); - validEntityBeforeSave(update); - return baseMapper.updateById(update) > 0; - } - - /** - * 保存前的数据校验 - */ - private void validEntityBeforeSave(SysDemo entity) { - //TODO 做一些数据校验,如唯一约束 - } - - /** - * 批量删除dome管理 - */ - @Override - public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if (isValid) { - //TODO 做一些业务上的校验,判断是否需要校验 - } - return baseMapper.deleteBatchIds(ids) > 0; - } -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/sys_demo_menu.sql b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/sys_demo_menu.sql deleted file mode 100644 index 5b19392a..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/sys_demo_menu.sql +++ /dev/null @@ -1,19 +0,0 @@ --- 菜单 SQL -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1954175368920645632, 'dome管理', '2000', '1', 'sysDemo', 'system/sysDemo/index', 1, 0, 'C', '0', '0', 'system:sysDemo:list', '#', 103, 1, sysdate(), null, null, 'dome管理菜单'); - --- 按钮 SQL -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1954175368920645633, 'dome管理查询', 1954175368920645632, '1', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:query', '#', 103, 1, sysdate(), null, null, ''); - -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1954175368920645634, 'dome管理新增', 1954175368920645632, '2', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:add', '#', 103, 1, sysdate(), null, null, ''); - -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1954175368920645635, 'dome管理修改', 1954175368920645632, '3', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:edit', '#', 103, 1, sysdate(), null, null, ''); - -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1954175368920645636, 'dome管理删除', 1954175368920645632, '4', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:remove', '#', 103, 1, sysdate(), null, null, ''); - -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1954175368920645637, 'dome管理导出', 1954175368920645632, '5', '#', '', 1, 0, 'F', '0', '0', 'system:sysDemo:export', '#', 103, 1, sysdate(), null, null, ''); From 22c0c733f60d6c53087b4aab993e40bae505cd55 Mon Sep 17 00:00:00 2001 From: fy53888 Date: Sat, 9 Aug 2025 22:01:29 +0800 Subject: [PATCH 04/33] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=8E=B7=E5=8F=96Java?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=90=8E=E7=AB=AF=E7=94=9F=E6=88=90=E9=A1=9E?= =?UTF-8?q?=E5=9E=8B=20Integer=E5=87=BA=E9=8C=AF=E7=9A=84=E5=95=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/ruoyi/generator/impl/GenTableServiceImpl.java | 1 + .../java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java | 1 + 2 files changed, 2 insertions(+) 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 fd83f558..226f404b 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 @@ -412,6 +412,7 @@ public class GenTableServiceImpl implements IGenTableService { return "String"; } String type = dbType.toLowerCase(); + if (Objects.equals(type,"int") || type.contains("tinyint") || type.contains("smallint")) { return "Integer"; } else if (type.contains("bigint")) { diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java index ebae5510..8cfd33e7 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java @@ -363,6 +363,7 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { } String type = dbType.toLowerCase(); + if (Objects.equals(type,"int")|| type.contains("tinyint") || type.contains("smallint")) { return "Integer"; } else if (type.contains("bigint")) { From 579beb6833e6241fd63163be7db1fec951a5c9c5 Mon Sep 17 00:00:00 2001 From: fy53888 Date: Sat, 9 Aug 2025 22:03:31 +0800 Subject: [PATCH 05/33] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E7=94=9F=E6=88=90=E7=B1=BB=E5=9E=8B=20Integer=20=E5=87=BA?= =?UTF-8?q?=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/ruoyi/generator/impl/GenTableServiceImpl.java | 1 - .../java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java | 1 - 2 files changed, 2 deletions(-) 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 226f404b..fd83f558 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 @@ -412,7 +412,6 @@ public class GenTableServiceImpl implements IGenTableService { return "String"; } String type = dbType.toLowerCase(); - if (Objects.equals(type,"int") || type.contains("tinyint") || type.contains("smallint")) { return "Integer"; } else if (type.contains("bigint")) { diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java index 8cfd33e7..ebae5510 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java @@ -363,7 +363,6 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { } String type = dbType.toLowerCase(); - if (Objects.equals(type,"int")|| type.contains("tinyint") || type.contains("smallint")) { return "Integer"; } else if (type.contains("bigint")) { From 503f86644e485557f03b8d72feaea6f2ff999a2a Mon Sep 17 00:00:00 2001 From: l90215 Date: Sun, 10 Aug 2025 00:25:49 +0800 Subject: [PATCH 06/33] =?UTF-8?q?feat:=20fix=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=B1=BB=E5=9E=8B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generator/impl/GenTableServiceImpl.java | 106 ++++++++---------- .../impl/SchemaFieldServiceImpl.java | 12 +- .../src/main/resources/vm/java/bo.java.vm | 4 +- .../src/main/resources/vm/java/domain.java.vm | 26 +---- 4 files changed, 60 insertions(+), 88 deletions(-) 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 e4a85949..bc885cb9 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 @@ -129,17 +129,17 @@ public class GenTableServiceImpl implements IGenTableService { */ private VelocityContext prepareSchemaContext(SchemaVo schema, List fields) { VelocityContext context = new VelocityContext(); - + // 从配置文件读取基本配置 String packageName = GenConfig.getPackageName(); String author = GenConfig.getAuthor(); String tablePrefix = GenConfig.getTablePrefix(); boolean autoRemovePre = GenConfig.getAutoRemovePre(); - + // 处理表名和类名 String tableName = schema.getTableName(); String baseClassName = schema.getTableName(); - + // 自动去除表前缀 if (autoRemovePre && StrUtil.isNotBlank(tablePrefix)) { String[] prefixes = tablePrefix.split(","); @@ -150,12 +150,12 @@ public class GenTableServiceImpl implements IGenTableService { } } } - + String className = toCamelCase(baseClassName, true); // 首字母大写的类名,如:SysRole String classname = toCamelCase(baseClassName, false); // 首字母小写的类名,如:sysRole String businessName = toCamelCase(baseClassName, false); String moduleName = getModuleName(packageName); - + // 基本信息 context.put("tableName", tableName); context.put("tableComment", schema.getComment()); @@ -169,18 +169,18 @@ public class GenTableServiceImpl implements IGenTableService { context.put("packageName", packageName); context.put("moduleName", moduleName); context.put("businessName", businessName); - + // 权限相关 context.put("permissionPrefix", moduleName + ":" + businessName); context.put("parentMenuId", "2000"); // 默认父菜单ID,可配置 - + // 生成菜单ID List menuIds = new ArrayList<>(); for (int i = 0; i < 6; i++) { menuIds.add(IdUtil.getSnowflakeNextId()); } context.put("menuIds", menuIds); - + // 创建table对象,包含menuIds等信息和方法 Map table = new HashMap<>(); table.put("menuIds", menuIds); @@ -189,29 +189,19 @@ public class GenTableServiceImpl implements IGenTableService { table.put("className", className); table.put("classname", classname); table.put("functionName", schema.getName()); - + // 添加表类型属性(默认为crud类型) table.put("crud", true); table.put("sub", false); table.put("tree", false); - - // 添加isSuperColumn方法 - table.put("isSuperColumn", new Object() { - public boolean isSuperColumn(String javaField) { - // 定义超类字段(BaseEntity中的字段) - return "createBy".equals(javaField) || "createTime".equals(javaField) - || "updateBy".equals(javaField) || "updateTime".equals(javaField) - || "remark".equals(javaField) || "tenantId".equals(javaField); - } - }); - + context.put("table", table); - + // 处理字段信息 List> columns = new ArrayList<>(); Map pkColumn = null; Set importList = new HashSet<>(); - + // 添加基础导入 importList.add("java.io.Serializable"); @@ -219,7 +209,7 @@ public class GenTableServiceImpl implements IGenTableService { Map column = new HashMap<>(); String javaType = getJavaType(field.getType()); String javaField = StrUtil.toCamelCase(field.getCode()); - + column.put("columnName", field.getCode()); column.put("columnComment", field.getName()); column.put("comment", field.getName()); // 添加comment别名 @@ -227,7 +217,7 @@ public class GenTableServiceImpl implements IGenTableService { column.put("javaType", javaType); column.put("javaField", javaField); column.put("capJavaField", toCamelCase(field.getCode(), true)); - + // 布尔值属性(兼容两种格式) boolean isPk = "1".equals(field.getIsPk()); boolean isRequired = "1".equals(field.getIsRequired()); @@ -235,7 +225,7 @@ public class GenTableServiceImpl implements IGenTableService { boolean isEdit = "1".equals(field.getIsEdit()); boolean isList = "1".equals(field.getIsList()); boolean isQuery = "1".equals(field.getIsQuery()); - + column.put("isPk", isPk ? 1 : 0); column.put("pk", isPk); // 添加pk别名 column.put("isRequired", isRequired); @@ -248,27 +238,27 @@ public class GenTableServiceImpl implements IGenTableService { column.put("list", isList); // 添加list别名 column.put("isQuery", isQuery); column.put("query", isQuery); // 添加query别名 - + column.put("queryType", field.getQueryType()); column.put("htmlType", field.getHtmlType()); column.put("dictType", field.getDictType()); column.put("sort", field.getSort()); - + // 添加readConverterExp方法 column.put("readConverterExp", new Object() { }); - + // 根据Java类型添加相应的导入 addImportForJavaType(javaType, importList); - + columns.add(column); - + // 设置主键列 if (isPk) { pkColumn = column; } } - + // 如果没有主键,使用第一个字段作为主键 if (pkColumn == null && !columns.isEmpty()) { pkColumn = columns.get(0); @@ -276,27 +266,28 @@ public class GenTableServiceImpl implements IGenTableService { pkColumn.put("isPk", 1); pkColumn.put("pk", true); } - + context.put("columns", columns); context.put("pkColumn", pkColumn); context.put("importList", new ArrayList<>(importList)); - + return context; } - + /** - * 根据Java类型添加相应的导入 - */ - private void addImportForJavaType(String javaType, Set importList) { - switch (javaType) { - case "BigDecimal" -> importList.add("java.math.BigDecimal"); - case "Date" -> importList.add("java.util.Date"); - case "LocalDateTime" -> importList.add("java.time.LocalDateTime"); - case "LocalDate" -> importList.add("java.time.LocalDate"); - case "LocalTime" -> importList.add("java.time.LocalTime"); - default -> {} - } - } + * 根据Java类型添加相应的导入 + */ + private void addImportForJavaType(String javaType, Set importList) { + switch (javaType) { + case "BigDecimal" -> importList.add("java.math.BigDecimal"); + case "Date" -> importList.add("java.util.Date"); + case "LocalDateTime" -> importList.add("java.time.LocalDateTime"); + case "LocalDate" -> importList.add("java.time.LocalDate"); + case "LocalTime" -> importList.add("java.time.LocalTime"); + default -> { + } + } + } /** * 从包名中提取模块名 @@ -320,10 +311,10 @@ public class GenTableServiceImpl implements IGenTableService { String packageName = GenConfig.getPackageName(); String tablePrefix = GenConfig.getTablePrefix(); boolean autoRemovePre = GenConfig.getAutoRemovePre(); - + // 处理类名 String baseClassName = schema.getTableName(); - + // 自动去除表前缀 if (autoRemovePre && StrUtil.isNotBlank(tablePrefix)) { String[] prefixes = tablePrefix.split(","); @@ -334,13 +325,13 @@ public class GenTableServiceImpl implements IGenTableService { } } } - + String className = toCamelCase(baseClassName, true); // 首字母大写,如:SysRole // 首字母小写,如:sysRole String moduleName = getModuleName(packageName); String javaPath = "src/main/java/"; String mybatisPath = "src/main/resources/mapper/"; - + if (template.contains("domain.java.vm")) { return javaPath + packageName.replace(".", "/") + "/domain/" + className + ".java"; } else if (template.contains("mapper.java.vm")) { @@ -413,16 +404,17 @@ public class GenTableServiceImpl implements IGenTableService { return "String"; } String type = dbType.toLowerCase(); - if (type.contains("int") || type.contains("tinyint") || type.contains("smallint")) { + if (StrUtil.equalsAny(type, "int", "tinyint")) { return "Integer"; - } else if (type.contains("bigint")) { + } else if (StrUtil.equalsAny(type, "bigint")) { return "Long"; - } else if (type.contains("decimal") || type.contains("numeric") || type.contains("float") || type.contains( - "double")) { + } else if (StrUtil.equalsAny(type, "decimal", "numeric", "float", "double")) { return "BigDecimal"; - } else if (type.contains("date") || type.contains("time")) { - return "Date"; - } else if (type.contains("bit") || type.contains("boolean")) { + } else if (StrUtil.equalsAny(type, "date")) { + return "LocalDate"; + } else if (StrUtil.equalsAny(type, "datetime", "timestamp")) { + return "LocalDateTime"; + } else if (StrUtil.equalsAny(type, "bit", "boolean")) { return "Boolean"; } else { return "String"; diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java index e8295f88..a0e40f95 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java @@ -211,7 +211,6 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { result.put("tableName", schema.getTableName()); result.put("tableComment", schema.getComment()); result.put("className", toCamelCase(schema.getTableName(), true)); - // result.put("className", StrUtil.toCamelCase(schema.getTableName())); result.put("tableCamelName", StrUtil.toCamelCase(schema.getTableName())); result.put("functionName", schema.getName()); result.put("schemaName", schema.getName()); @@ -363,16 +362,15 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { } String type = dbType.toLowerCase(); - if (type.contains("int") || type.contains("tinyint") || type.contains("smallint")) { + if (StrUtil.equalsAny(type, "int", "tinyint", "smallint")) { return "Integer"; - } else if (type.contains("bigint")) { + } else if (StrUtil.equalsAny(type, "bigint")) { return "Long"; - } else if (type.contains("decimal") || type.contains("numeric") || type.contains("float") || type.contains( - "double")) { + } else if (StrUtil.equalsAny(type, "decimal", "numeric", "float", "double")) { return "BigDecimal"; - } else if (type.contains("date") || type.contains("time")) { + } else if (StrUtil.equalsAny(type, "date", "datetime","timestamp")) { return "Date"; - } else if (type.contains("bit") || type.contains("boolean")) { + } else if (StrUtil.equalsAny(type, "bit", "boolean")) { return "Boolean"; } else { return "String"; diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm index 65835a77..491f8bc0 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm @@ -25,11 +25,11 @@ import org.ruoyi.common.core.validate.EditGroup; public class ${ClassName}Bo implements Serializable { #foreach ($column in $columns) - #if(!$table.isSuperColumn($column.javaField) && ($column.isPk || $column.query || $column.insert || $column.edit)) + #if($column.isPk || $column.query || $column.insert || $column.edit|| $column.required) /** * $column.columnComment */ - #if($column.insert && $column.edit) + #if(($column.insert && $column.edit) || $column.required) #set($Group="AddGroup.class, EditGroup.class") #elseif($column.insert) #set($Group="AddGroup.class") diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm index d9aa46a7..d32dff79 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm @@ -1,22 +1,10 @@ package ${packageName}.domain; - #foreach ($column in $columns) - #if($column.javaField=='tenantId') - #set($IsTenant=1) - #end - #end - #if($IsTenant==1) - import core.tenant.common.org.ruoyi.TenantEntity; - #else - #end import com.baomidou.mybatisplus.annotation.*; import lombok.Data; -import lombok.EqualsAndHashCode; - #foreach ($import in $importList) - import ${import}; - #end - -import org.ruoyi.core.domain.BaseEntity; +#foreach ($import in $importList) +import ${import}; +#end /** * ${functionName}对象 ${tableName} @@ -24,15 +12,9 @@ import org.ruoyi.core.domain.BaseEntity; * @author ${author} * @date ${datetime} */ -#if($IsTenant==1) - #set($Entity="TenantEntity") -#else - #set($Entity="BaseEntity") -#end @Data -@EqualsAndHashCode(callSuper = true) @TableName("${tableName}") -public class ${ClassName} extends ${Entity} { +public class ${ClassName} implements Serializable { #foreach ($column in $columns) From 5fe8bd7706ad7c463ffdd59e3b7486fd15e2ee8e Mon Sep 17 00:00:00 2001 From: violateer <1828257089@qq.com> Date: Sun, 10 Aug 2025 17:06:32 +0800 Subject: [PATCH 07/33] =?UTF-8?q?feature:=20=E6=96=B0=E5=A2=9E=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=89=8D=E7=AB=AF=E6=96=87=E4=BB=B6=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generator/controller/GenController.java | 18 ++- .../generator/impl/GenTableServiceImpl.java | 137 +++++++++++------- .../generator/service/IGenTableService.java | 8 + script/sql/update/knowledge-role-bak.sql | 2 +- 4 files changed, 108 insertions(+), 57 deletions(-) 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 9ef76085..932bb46f 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 @@ -19,18 +19,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.*; /** * 业务 服务层实现 @@ -59,6 +50,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 */ @@ -128,17 +154,17 @@ public class GenTableServiceImpl implements IGenTableService { */ private VelocityContext prepareSchemaContext(SchemaVo schema, List fields) { VelocityContext context = new VelocityContext(); - + // 从配置文件读取基本配置 String packageName = GenConfig.getPackageName(); String author = GenConfig.getAuthor(); String tablePrefix = GenConfig.getTablePrefix(); boolean autoRemovePre = GenConfig.getAutoRemovePre(); - + // 处理表名和类名 String tableName = schema.getTableName(); String baseClassName = schema.getTableName(); - + // 自动去除表前缀 if (autoRemovePre && StrUtil.isNotBlank(tablePrefix)) { String[] prefixes = tablePrefix.split(","); @@ -149,12 +175,12 @@ public class GenTableServiceImpl implements IGenTableService { } } } - + String className = toCamelCase(baseClassName, true); // 首字母大写的类名,如:SysRole String classname = toCamelCase(baseClassName, false); // 首字母小写的类名,如:sysRole String businessName = toCamelCase(baseClassName, false); String moduleName = getModuleName(packageName); - + // 基本信息 context.put("tableName", tableName); context.put("tableComment", schema.getComment()); @@ -168,18 +194,18 @@ public class GenTableServiceImpl implements IGenTableService { context.put("packageName", packageName); context.put("moduleName", moduleName); context.put("businessName", businessName); - + // 权限相关 context.put("permissionPrefix", moduleName + ":" + businessName); context.put("parentMenuId", "2000"); // 默认父菜单ID,可配置 - + // 生成菜单ID List menuIds = new ArrayList<>(); for (int i = 0; i < 6; i++) { menuIds.add(IdUtil.getSnowflakeNextId()); } context.put("menuIds", menuIds); - + // 创建table对象,包含menuIds等信息和方法 Map table = new HashMap<>(); table.put("menuIds", menuIds); @@ -188,29 +214,29 @@ public class GenTableServiceImpl implements IGenTableService { table.put("className", className); table.put("classname", classname); table.put("functionName", schema.getName()); - + // 添加表类型属性(默认为crud类型) table.put("crud", true); table.put("sub", false); table.put("tree", false); - + // 添加isSuperColumn方法 table.put("isSuperColumn", new Object() { public boolean isSuperColumn(String javaField) { // 定义超类字段(BaseEntity中的字段) - return "createBy".equals(javaField) || "createTime".equals(javaField) - || "updateBy".equals(javaField) || "updateTime".equals(javaField) - || "remark".equals(javaField) || "tenantId".equals(javaField); + return "createBy".equals(javaField) || "createTime".equals(javaField) + || "updateBy".equals(javaField) || "updateTime".equals(javaField) + || "remark".equals(javaField) || "tenantId".equals(javaField); } }); - + context.put("table", table); - + // 处理字段信息 List> columns = new ArrayList<>(); Map pkColumn = null; Set importList = new HashSet<>(); - + // 添加基础导入 importList.add("java.io.Serializable"); @@ -218,7 +244,7 @@ public class GenTableServiceImpl implements IGenTableService { Map column = new HashMap<>(); String javaType = getJavaType(field.getType()); String javaField = StrUtil.toCamelCase(field.getCode()); - + column.put("columnName", field.getCode()); column.put("columnComment", field.getName()); column.put("comment", field.getName()); // 添加comment别名 @@ -226,7 +252,7 @@ public class GenTableServiceImpl implements IGenTableService { column.put("javaType", javaType); column.put("javaField", javaField); column.put("capJavaField", toCamelCase(field.getCode(), true)); - + // 布尔值属性(兼容两种格式) boolean isPk = "1".equals(field.getIsPk()); boolean isRequired = "1".equals(field.getIsRequired()); @@ -234,7 +260,7 @@ public class GenTableServiceImpl implements IGenTableService { boolean isEdit = "1".equals(field.getIsEdit()); boolean isList = "1".equals(field.getIsList()); boolean isQuery = "1".equals(field.getIsQuery()); - + column.put("isPk", isPk ? 1 : 0); column.put("pk", isPk); // 添加pk别名 column.put("isRequired", isRequired); @@ -247,27 +273,27 @@ public class GenTableServiceImpl implements IGenTableService { column.put("list", isList); // 添加list别名 column.put("isQuery", isQuery); column.put("query", isQuery); // 添加query别名 - + column.put("queryType", field.getQueryType()); column.put("htmlType", field.getHtmlType()); column.put("dictType", field.getDictType()); column.put("sort", field.getSort()); - + // 添加readConverterExp方法 column.put("readConverterExp", new Object() { }); - + // 根据Java类型添加相应的导入 addImportForJavaType(javaType, importList); - + columns.add(column); - + // 设置主键列 if (isPk) { pkColumn = column; } } - + // 如果没有主键,使用第一个字段作为主键 if (pkColumn == null && !columns.isEmpty()) { pkColumn = columns.get(0); @@ -275,27 +301,28 @@ public class GenTableServiceImpl implements IGenTableService { pkColumn.put("isPk", 1); pkColumn.put("pk", true); } - + context.put("columns", columns); context.put("pkColumn", pkColumn); context.put("importList", new ArrayList<>(importList)); - + return context; } - + /** - * 根据Java类型添加相应的导入 - */ - private void addImportForJavaType(String javaType, Set importList) { - switch (javaType) { - case "BigDecimal" -> importList.add("java.math.BigDecimal"); - case "Date" -> importList.add("java.util.Date"); - case "LocalDateTime" -> importList.add("java.time.LocalDateTime"); - case "LocalDate" -> importList.add("java.time.LocalDate"); - case "LocalTime" -> importList.add("java.time.LocalTime"); - default -> {} - } - } + * 根据Java类型添加相应的导入 + */ + private void addImportForJavaType(String javaType, Set importList) { + switch (javaType) { + case "BigDecimal" -> importList.add("java.math.BigDecimal"); + case "Date" -> importList.add("java.util.Date"); + case "LocalDateTime" -> importList.add("java.time.LocalDateTime"); + case "LocalDate" -> importList.add("java.time.LocalDate"); + case "LocalTime" -> importList.add("java.time.LocalTime"); + default -> { + } + } + } /** * 从包名中提取模块名 @@ -319,10 +346,10 @@ public class GenTableServiceImpl implements IGenTableService { String packageName = GenConfig.getPackageName(); String tablePrefix = GenConfig.getTablePrefix(); boolean autoRemovePre = GenConfig.getAutoRemovePre(); - + // 处理类名 String baseClassName = schema.getTableName(); - + // 自动去除表前缀 if (autoRemovePre && StrUtil.isNotBlank(tablePrefix)) { String[] prefixes = tablePrefix.split(","); @@ -333,13 +360,13 @@ public class GenTableServiceImpl implements IGenTableService { } } } - + String className = toCamelCase(baseClassName, true); // 首字母大写,如:SysRole // 首字母小写,如:sysRole String moduleName = getModuleName(packageName); String javaPath = "src/main/java/"; String mybatisPath = "src/main/resources/mapper/"; - + if (template.contains("domain.java.vm")) { return javaPath + packageName.replace(".", "/") + "/domain/" + className + ".java"; } else if (template.contains("mapper.java.vm")) { 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/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 From e5011e0dd9a7b8a05ff2536703ffe448a2a7af9b Mon Sep 17 00:00:00 2001 From: violateer <1828257089@qq.com> Date: Sun, 10 Aug 2025 17:19:59 +0800 Subject: [PATCH 08/33] =?UTF-8?q?feature:=20=E6=96=B0=E5=A2=9E=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=89=8D=E7=AB=AF=E6=96=87=E4=BB=B6=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generator/controller/GenController.java | 18 ++- .../generator/impl/GenTableServiceImpl.java | 137 +++++++++++------- .../generator/service/IGenTableService.java | 8 + script/sql/update/knowledge-role-bak.sql | 2 +- 4 files changed, 108 insertions(+), 57 deletions(-) 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 9ef76085..932bb46f 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 @@ -19,18 +19,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.*; /** * 业务 服务层实现 @@ -59,6 +50,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 */ @@ -128,17 +154,17 @@ public class GenTableServiceImpl implements IGenTableService { */ private VelocityContext prepareSchemaContext(SchemaVo schema, List fields) { VelocityContext context = new VelocityContext(); - + // 从配置文件读取基本配置 String packageName = GenConfig.getPackageName(); String author = GenConfig.getAuthor(); String tablePrefix = GenConfig.getTablePrefix(); boolean autoRemovePre = GenConfig.getAutoRemovePre(); - + // 处理表名和类名 String tableName = schema.getTableName(); String baseClassName = schema.getTableName(); - + // 自动去除表前缀 if (autoRemovePre && StrUtil.isNotBlank(tablePrefix)) { String[] prefixes = tablePrefix.split(","); @@ -149,12 +175,12 @@ public class GenTableServiceImpl implements IGenTableService { } } } - + String className = toCamelCase(baseClassName, true); // 首字母大写的类名,如:SysRole String classname = toCamelCase(baseClassName, false); // 首字母小写的类名,如:sysRole String businessName = toCamelCase(baseClassName, false); String moduleName = getModuleName(packageName); - + // 基本信息 context.put("tableName", tableName); context.put("tableComment", schema.getComment()); @@ -168,18 +194,18 @@ public class GenTableServiceImpl implements IGenTableService { context.put("packageName", packageName); context.put("moduleName", moduleName); context.put("businessName", businessName); - + // 权限相关 context.put("permissionPrefix", moduleName + ":" + businessName); context.put("parentMenuId", "2000"); // 默认父菜单ID,可配置 - + // 生成菜单ID List menuIds = new ArrayList<>(); for (int i = 0; i < 6; i++) { menuIds.add(IdUtil.getSnowflakeNextId()); } context.put("menuIds", menuIds); - + // 创建table对象,包含menuIds等信息和方法 Map table = new HashMap<>(); table.put("menuIds", menuIds); @@ -188,29 +214,29 @@ public class GenTableServiceImpl implements IGenTableService { table.put("className", className); table.put("classname", classname); table.put("functionName", schema.getName()); - + // 添加表类型属性(默认为crud类型) table.put("crud", true); table.put("sub", false); table.put("tree", false); - + // 添加isSuperColumn方法 table.put("isSuperColumn", new Object() { public boolean isSuperColumn(String javaField) { // 定义超类字段(BaseEntity中的字段) - return "createBy".equals(javaField) || "createTime".equals(javaField) - || "updateBy".equals(javaField) || "updateTime".equals(javaField) - || "remark".equals(javaField) || "tenantId".equals(javaField); + return "createBy".equals(javaField) || "createTime".equals(javaField) + || "updateBy".equals(javaField) || "updateTime".equals(javaField) + || "remark".equals(javaField) || "tenantId".equals(javaField); } }); - + context.put("table", table); - + // 处理字段信息 List> columns = new ArrayList<>(); Map pkColumn = null; Set importList = new HashSet<>(); - + // 添加基础导入 importList.add("java.io.Serializable"); @@ -218,7 +244,7 @@ public class GenTableServiceImpl implements IGenTableService { Map column = new HashMap<>(); String javaType = getJavaType(field.getType()); String javaField = StrUtil.toCamelCase(field.getCode()); - + column.put("columnName", field.getCode()); column.put("columnComment", field.getName()); column.put("comment", field.getName()); // 添加comment别名 @@ -226,7 +252,7 @@ public class GenTableServiceImpl implements IGenTableService { column.put("javaType", javaType); column.put("javaField", javaField); column.put("capJavaField", toCamelCase(field.getCode(), true)); - + // 布尔值属性(兼容两种格式) boolean isPk = "1".equals(field.getIsPk()); boolean isRequired = "1".equals(field.getIsRequired()); @@ -234,7 +260,7 @@ public class GenTableServiceImpl implements IGenTableService { boolean isEdit = "1".equals(field.getIsEdit()); boolean isList = "1".equals(field.getIsList()); boolean isQuery = "1".equals(field.getIsQuery()); - + column.put("isPk", isPk ? 1 : 0); column.put("pk", isPk); // 添加pk别名 column.put("isRequired", isRequired); @@ -247,27 +273,27 @@ public class GenTableServiceImpl implements IGenTableService { column.put("list", isList); // 添加list别名 column.put("isQuery", isQuery); column.put("query", isQuery); // 添加query别名 - + column.put("queryType", field.getQueryType()); column.put("htmlType", field.getHtmlType()); column.put("dictType", field.getDictType()); column.put("sort", field.getSort()); - + // 添加readConverterExp方法 column.put("readConverterExp", new Object() { }); - + // 根据Java类型添加相应的导入 addImportForJavaType(javaType, importList); - + columns.add(column); - + // 设置主键列 if (isPk) { pkColumn = column; } } - + // 如果没有主键,使用第一个字段作为主键 if (pkColumn == null && !columns.isEmpty()) { pkColumn = columns.get(0); @@ -275,27 +301,28 @@ public class GenTableServiceImpl implements IGenTableService { pkColumn.put("isPk", 1); pkColumn.put("pk", true); } - + context.put("columns", columns); context.put("pkColumn", pkColumn); context.put("importList", new ArrayList<>(importList)); - + return context; } - + /** - * 根据Java类型添加相应的导入 - */ - private void addImportForJavaType(String javaType, Set importList) { - switch (javaType) { - case "BigDecimal" -> importList.add("java.math.BigDecimal"); - case "Date" -> importList.add("java.util.Date"); - case "LocalDateTime" -> importList.add("java.time.LocalDateTime"); - case "LocalDate" -> importList.add("java.time.LocalDate"); - case "LocalTime" -> importList.add("java.time.LocalTime"); - default -> {} - } - } + * 根据Java类型添加相应的导入 + */ + private void addImportForJavaType(String javaType, Set importList) { + switch (javaType) { + case "BigDecimal" -> importList.add("java.math.BigDecimal"); + case "Date" -> importList.add("java.util.Date"); + case "LocalDateTime" -> importList.add("java.time.LocalDateTime"); + case "LocalDate" -> importList.add("java.time.LocalDate"); + case "LocalTime" -> importList.add("java.time.LocalTime"); + default -> { + } + } + } /** * 从包名中提取模块名 @@ -319,10 +346,10 @@ public class GenTableServiceImpl implements IGenTableService { String packageName = GenConfig.getPackageName(); String tablePrefix = GenConfig.getTablePrefix(); boolean autoRemovePre = GenConfig.getAutoRemovePre(); - + // 处理类名 String baseClassName = schema.getTableName(); - + // 自动去除表前缀 if (autoRemovePre && StrUtil.isNotBlank(tablePrefix)) { String[] prefixes = tablePrefix.split(","); @@ -333,13 +360,13 @@ public class GenTableServiceImpl implements IGenTableService { } } } - + String className = toCamelCase(baseClassName, true); // 首字母大写,如:SysRole // 首字母小写,如:sysRole String moduleName = getModuleName(packageName); String javaPath = "src/main/java/"; String mybatisPath = "src/main/resources/mapper/"; - + if (template.contains("domain.java.vm")) { return javaPath + packageName.replace(".", "/") + "/domain/" + className + ".java"; } else if (template.contains("mapper.java.vm")) { 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/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 From d964e86b232b28b3244a050b4de0503cf2651918 Mon Sep 17 00:00:00 2001 From: likunlong Date: Mon, 11 Aug 2025 09:33:35 +0800 Subject: [PATCH 09/33] =?UTF-8?q?feat:=20=E8=8E=B7=E5=8F=96=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=8E=A5=E5=8F=A3=E6=94=AF=E6=8C=81=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E8=83=BD=E5=8A=9B=EF=BC=9B=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E8=A1=A8=E5=A2=9E=E5=8A=A0=E6=A8=A1=E5=9E=8B=E8=83=BD=E5=8A=9B?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/ruoyi/domain/ChatModel.java | 6 + .../java/org/ruoyi/domain/vo/ChatModelVo.java | 140 +++++++++++++++++- script/sql/update/20250808.sql | 3 + 3 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 script/sql/update/20250808.sql 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/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 '模型能力'; From e83d70e9c3f01ea33104da0f6a23edd63f8f2b67 Mon Sep 17 00:00:00 2001 From: l90215 Date: Mon, 11 Aug 2025 21:59:02 +0800 Subject: [PATCH 10/33] =?UTF-8?q?feat:=20fix=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=B1=BB=E5=9E=8B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../knowledge/KnowledgeController.java | 20 +- .../controller/SchemaGroupController.java | 1 + .../org/ruoyi/generator/domain/Schema.java | 76 +++---- .../ruoyi/generator/domain/SchemaField.java | 51 +++-- .../ruoyi/generator/domain/SchemaGroup.java | 51 +++-- .../ruoyi/generator/domain/bo/SchemaBo.java | 49 +---- .../generator/domain/bo/SchemaFieldBo.java | 19 +- .../generator/domain/bo/SchemaGroupBo.java | 17 +- .../generator/domain/vo/SchemaFieldVo.java | 22 -- .../generator/domain/vo/SchemaGroupVo.java | 9 - .../ruoyi/generator/domain/vo/SchemaVo.java | 3 - .../generator/impl/GenTableServiceImpl.java | 7 +- .../impl/SchemaFieldServiceImpl.java | 17 +- .../impl/SchemaGroupServiceImpl.java | 8 +- .../generator/impl/SchemaServiceImpl.java | 34 ++-- .../src/main/resources/vm/java/bo.java.vm | 38 ++-- script/sql/ruoyi-ai.sql | 188 ++++++------------ 17 files changed, 235 insertions(+), 375 deletions(-) diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java index 54ef52e9..76443156 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java @@ -27,10 +27,18 @@ import org.ruoyi.service.IKnowledgeAttachService; import org.ruoyi.service.IKnowledgeFragmentService; import org.ruoyi.service.IKnowledgeInfoService; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.util.List; +import java.util.Objects; /** * 知识库管理 @@ -60,7 +68,9 @@ public class KnowledgeController extends BaseController { if (!StpUtil.isLogin()) { throw new SecurityException("请先去登录!"); } - bo.setUid(LoginHelper.getUserId()); + if (!Objects.equals(LoginHelper.getUserId(), 1L)) { + bo.setUid(LoginHelper.getUserId()); + } return knowledgeInfoService.queryPageList(bo, pageQuery); } @@ -72,13 +82,15 @@ public class KnowledgeController extends BaseController { if (!StpUtil.isLogin()) { throw new SecurityException("请先去登录!"); } - LoginUser loginUser = LoginHelper.getLoginUser(); // 管理员跳过权限 - if (loginUser.getUserId().equals(1L) || !knowledgeRoleConfig.getEnable()) { + if (Objects.equals(LoginHelper.getUserId(), 1L)) { + return knowledgeInfoService.queryPageList(bo, pageQuery); + } else if (!knowledgeRoleConfig.getEnable()) { bo.setUid(LoginHelper.getUserId()); return knowledgeInfoService.queryPageList(bo, pageQuery); } else { + // TODO 自己创建的知识库+角色分配的知识库 return knowledgeInfoService.queryPageListByRole(pageQuery); } } diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/controller/SchemaGroupController.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/controller/SchemaGroupController.java index d19fe54c..d930c71a 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/controller/SchemaGroupController.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/controller/SchemaGroupController.java @@ -53,6 +53,7 @@ public class SchemaGroupController extends BaseController { /** * 获取数据模型分组选择列表 */ + @SaCheckPermission("dev:schemaGroup:select") @GetMapping("/select") public R> select() { SchemaGroupBo bo = new SchemaGroupBo(); diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/Schema.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/Schema.java index f12fb823..c1c26870 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/Schema.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/Schema.java @@ -1,13 +1,14 @@ package org.ruoyi.generator.domain; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; -import lombok.EqualsAndHashCode; -import org.ruoyi.core.domain.BaseEntity; -import java.io.Serial; +import java.io.Serializable; +import java.util.Date; /** * 数据模型对象 dev_schema @@ -16,12 +17,9 @@ import java.io.Serial; * @date 2024-01-01 */ @Data -@EqualsAndHashCode(callSuper = true) @TableName("dev_schema") -public class Schema extends BaseEntity { +public class Schema implements Serializable { - @Serial - private static final long serialVersionUID = 1L; /** * 主键 @@ -49,41 +47,6 @@ public class Schema extends BaseEntity { */ private String tableName; - /** - * 表注释 - */ - private String comment; - - /** - * 存储引擎 - */ - private String engine; - - /** - * 列表字段 - */ - private String listKeys; - - /** - * 搜索表单字段 - */ - private String searchFormKeys; - - /** - * 表单设计 - */ - private String designer; - - /** - * 状态 - */ - private String status; - - /** - * 排序 - */ - private Integer sort; - /** * 备注 */ @@ -96,8 +59,33 @@ public class Schema extends BaseEntity { private String delFlag; /** - * 租户编号 + * 创建部门 */ - private String tenantId; + @TableField(fill = FieldFill.INSERT) + private Long createDept; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; } \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/SchemaField.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/SchemaField.java index c683a92a..f02f548d 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/SchemaField.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/SchemaField.java @@ -1,13 +1,14 @@ package org.ruoyi.generator.domain; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; -import lombok.EqualsAndHashCode; -import org.ruoyi.core.domain.BaseEntity; -import java.io.Serial; +import java.io.Serializable; +import java.util.Date; /** * 数据模型字段对象 dev_schema_field @@ -16,12 +17,8 @@ import java.io.Serial; * @date 2024-01-01 */ @Data -@EqualsAndHashCode(callSuper = true) @TableName("dev_schema_field") -public class SchemaField extends BaseEntity { - - @Serial - private static final long serialVersionUID = 1L; +public class SchemaField implements Serializable { /** * 主键 @@ -129,15 +126,6 @@ public class SchemaField extends BaseEntity { */ private String dictType; - /** - * 状态 - */ - private String status; - - /** - * 扩展JSON - */ - private String extendJson; /** * 备注 @@ -151,8 +139,33 @@ public class SchemaField extends BaseEntity { private String delFlag; /** - * 租户编号 + * 创建部门 */ - private String tenantId; + @TableField(fill = FieldFill.INSERT) + private Long createDept; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; } \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/SchemaGroup.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/SchemaGroup.java index c921e285..bf3ee605 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/SchemaGroup.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/SchemaGroup.java @@ -1,13 +1,14 @@ package org.ruoyi.generator.domain; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; -import lombok.EqualsAndHashCode; -import org.ruoyi.core.domain.BaseEntity; -import java.io.Serial; +import java.io.Serializable; +import java.util.Date; /** * 数据模型分组对象 dev_schema_group @@ -16,12 +17,8 @@ import java.io.Serial; * @date 2024-01-01 */ @Data -@EqualsAndHashCode(callSuper = true) @TableName("dev_schema_group") -public class SchemaGroup extends BaseEntity { - - @Serial - private static final long serialVersionUID = 1L; +public class SchemaGroup implements Serializable { /** * 主键 @@ -44,16 +41,6 @@ public class SchemaGroup extends BaseEntity { */ private String icon; - /** - * 排序 - */ - private Integer sort; - - /** - * 状态 - */ - private String status; - /** * 备注 */ @@ -66,8 +53,32 @@ public class SchemaGroup extends BaseEntity { private String delFlag; /** - * 租户编号 + * 创建部门 */ - private String tenantId; + @TableField(fill = FieldFill.INSERT) + private Long createDept; + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; } \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaBo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaBo.java index cb5ee424..4c91a52a 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaBo.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaBo.java @@ -4,12 +4,12 @@ import io.github.linpeilie.annotations.AutoMapper; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; -import lombok.EqualsAndHashCode; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.core.domain.BaseEntity; import org.ruoyi.generator.domain.Schema; +import java.io.Serializable; + /** * 数据模型业务对象 SchemaBo * @@ -17,9 +17,8 @@ import org.ruoyi.generator.domain.Schema; * @date 2024-01-01 */ @Data -@EqualsAndHashCode(callSuper = true) @AutoMapper(target = Schema.class, reverseConvertGenerate = false) -public class SchemaBo extends BaseEntity { +public class SchemaBo implements Serializable { /** * 主键 @@ -38,52 +37,12 @@ public class SchemaBo extends BaseEntity { @NotBlank(message = "模型名称不能为空", groups = {AddGroup.class, EditGroup.class}) private String name; - /** - * 模型编码 - */ - @NotBlank(message = "模型编码不能为空", groups = {AddGroup.class, EditGroup.class}) - private String code; - /** * 表名 */ + @NotBlank(message = "表名不能为空", groups = {AddGroup.class, EditGroup.class}) private String tableName; - /** - * 表注释 - */ - private String comment; - - /** - * 存储引擎 - */ - private String engine; - - /** - * 列表字段 - */ - private String listKeys; - - /** - * 搜索表单字段 - */ - private String searchFormKeys; - - /** - * 表单设计 - */ - private String designer; - - /** - * 状态 - */ - private String status; - - /** - * 排序 - */ - private Integer sort; - /** * 备注 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaFieldBo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaFieldBo.java index 491d8d2d..161c60c0 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaFieldBo.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaFieldBo.java @@ -4,12 +4,12 @@ import io.github.linpeilie.annotations.AutoMapper; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; -import lombok.EqualsAndHashCode; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.core.domain.BaseEntity; import org.ruoyi.generator.domain.SchemaField; +import java.io.Serializable; + /** * 数据模型字段业务对象 SchemaFieldBo * @@ -17,9 +17,8 @@ import org.ruoyi.generator.domain.SchemaField; * @date 2024-01-01 */ @Data -@EqualsAndHashCode(callSuper = true) @AutoMapper(target = SchemaField.class, reverseConvertGenerate = false) -public class SchemaFieldBo extends BaseEntity { +public class SchemaFieldBo implements Serializable { /** * 主键 @@ -36,7 +35,7 @@ public class SchemaFieldBo extends BaseEntity { /** * 模型名称 */ - @NotNull(message = "模型名称不能为空", groups = {AddGroup.class, EditGroup.class}) + // @NotNull(message = "模型名称不能为空", groups = {AddGroup.class, EditGroup.class}) private String schemaName; /** @@ -131,16 +130,6 @@ public class SchemaFieldBo extends BaseEntity { */ private String dictType; - /** - * 状态 - */ - private String status; - - /** - * 扩展JSON - */ - private String extendJson; - /** * 备注 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaGroupBo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaGroupBo.java index 21c49d26..9a1f7057 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaGroupBo.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/bo/SchemaGroupBo.java @@ -4,12 +4,12 @@ import io.github.linpeilie.annotations.AutoMapper; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; -import lombok.EqualsAndHashCode; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.core.domain.BaseEntity; import org.ruoyi.generator.domain.SchemaGroup; +import java.io.Serializable; + /** * 数据模型分组业务对象 SchemaGroupBo * @@ -17,9 +17,8 @@ import org.ruoyi.generator.domain.SchemaGroup; * @date 2024-01-01 */ @Data -@EqualsAndHashCode(callSuper = true) @AutoMapper(target = SchemaGroup.class, reverseConvertGenerate = false) -public class SchemaGroupBo extends BaseEntity { +public class SchemaGroupBo implements Serializable { /** * 主键 @@ -44,16 +43,6 @@ public class SchemaGroupBo extends BaseEntity { */ private String icon; - /** - * 排序 - */ - private Integer sort; - - /** - * 状态 - */ - private String status; - /** * 备注 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaFieldVo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaFieldVo.java index 7897d87b..dd672320 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaFieldVo.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaFieldVo.java @@ -6,9 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.ruoyi.generator.domain.SchemaField; -import java.io.Serial; import java.io.Serializable; -import java.util.Date; /** * 数据模型字段视图对象 SchemaFieldVo @@ -20,9 +18,6 @@ import java.util.Date; @AutoMapper(target = SchemaField.class) public class SchemaFieldVo implements Serializable { - @Serial - private static final long serialVersionUID = 1L; - /** * 主键 */ @@ -136,25 +131,8 @@ public class SchemaFieldVo implements Serializable { @Schema(description = "字典类型") private String dictType; - /** - * 状态 - */ - @Schema(description = "状态") - private String status; - - /** - * 扩展JSON - */ - private String extendJson; - /** * 备注 */ private String remark; - - /** - * 创建时间 - */ - private Date createTime; - } \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaGroupVo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaGroupVo.java index 76741e45..66780b5e 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaGroupVo.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaGroupVo.java @@ -4,7 +4,6 @@ import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; import org.ruoyi.generator.domain.SchemaGroup; -import java.io.Serial; import java.io.Serializable; import java.util.Date; @@ -18,9 +17,6 @@ import java.util.Date; @AutoMapper(target = SchemaGroup.class) public class SchemaGroupVo implements Serializable { - @Serial - private static final long serialVersionUID = 1L; - /** * 主键 */ @@ -46,11 +42,6 @@ public class SchemaGroupVo implements Serializable { */ private Integer sort; - /** - * 状态 - */ - private String status; - /** * 备注 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaVo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaVo.java index c2dfd90a..378017bd 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaVo.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/vo/SchemaVo.java @@ -19,9 +19,6 @@ import java.util.Date; @AutoMapper(target = Schema.class) public class SchemaVo implements Serializable { - @Serial - private static final long serialVersionUID = 1L; - /** * 主键 */ 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 bc885cb9..6ecbfd15 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 @@ -11,9 +11,11 @@ import org.apache.velocity.app.Velocity; import org.ruoyi.common.core.constant.Constants; import org.ruoyi.generator.config.GenConfig; import org.ruoyi.generator.domain.vo.SchemaFieldVo; +import org.ruoyi.generator.domain.vo.SchemaGroupVo; import org.ruoyi.generator.domain.vo.SchemaVo; import org.ruoyi.generator.service.IGenTableService; import org.ruoyi.generator.service.SchemaFieldService; +import org.ruoyi.generator.service.SchemaGroupService; import org.ruoyi.generator.service.SchemaService; import org.ruoyi.generator.util.VelocityInitializer; import org.ruoyi.generator.util.VelocityUtils; @@ -44,6 +46,7 @@ public class GenTableServiceImpl implements IGenTableService { private final SchemaService schemaService; private final SchemaFieldService schemaFieldService; + private final SchemaGroupService schemaGroupService; /** * 基于表名称批量生成代码到classpath路径 @@ -137,6 +140,8 @@ public class GenTableServiceImpl implements IGenTableService { boolean autoRemovePre = GenConfig.getAutoRemovePre(); // 处理表名和类名 + Long schemaGroupId = schema.getSchemaGroupId(); + SchemaGroupVo schemaGroupVo = schemaGroupService.queryById(schemaGroupId); String tableName = schema.getTableName(); String baseClassName = schema.getTableName(); @@ -154,7 +159,7 @@ public class GenTableServiceImpl implements IGenTableService { String className = toCamelCase(baseClassName, true); // 首字母大写的类名,如:SysRole String classname = toCamelCase(baseClassName, false); // 首字母小写的类名,如:sysRole String businessName = toCamelCase(baseClassName, false); - String moduleName = getModuleName(packageName); + String moduleName = schemaGroupVo.getCode(); // 基本信息 context.put("tableName", tableName); diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java index a0e40f95..3240c366 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaFieldServiceImpl.java @@ -79,7 +79,6 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { lqw.eq(StringUtils.isNotBlank(bo.getQueryType()), SchemaField::getQueryType, bo.getQueryType()); lqw.eq(StringUtils.isNotBlank(bo.getHtmlType()), SchemaField::getHtmlType, bo.getHtmlType()); lqw.like(StringUtils.isNotBlank(bo.getDictType()), SchemaField::getDictType, bo.getDictType()); - lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SchemaField::getStatus, bo.getStatus()); lqw.orderByAsc(SchemaField::getSort); return lqw; } @@ -150,7 +149,6 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { public List queryListBySchemaId(Long schemaId) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.eq(SchemaField::getSchemaId, schemaId); - lqw.eq(SchemaField::getStatus, "0"); // 只查询正常状态的字段 lqw.orderByAsc(SchemaField::getSort); return baseMapper.selectVoList(lqw); } @@ -264,8 +262,7 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { return false; } LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(SchemaField::getSchemaName, tableName); - lqw.eq(SchemaField::getStatus, "0"); + lqw.eq(SchemaField::getSchemaId, schemaId); // 检查是否已存在字段数据 List existingFields = baseMapper.selectVoList(lqw); if (CollUtil.isNotEmpty(existingFields)) { @@ -279,20 +276,26 @@ public class SchemaFieldServiceImpl implements SchemaFieldService { SchemaField field = new SchemaField(); field.setSchemaId(schemaId); field.setSchemaName(tableName); + field.setDefaultValue((String) columnInfo.get("columnDefault")); + field.setComment((String) columnInfo.get("columnComment")); field.setName((String) columnInfo.get("columnComment")); field.setCode(StrUtil.toCamelCase((String) columnInfo.get("columnName"))); field.setType((String) columnInfo.get("dataType")); field.setLength(Integer.valueOf(String.valueOf(columnInfo.get("columnSize")))); field.setIsPk((Boolean) columnInfo.get("isPrimaryKey") ? "1" : "0"); field.setIsRequired(!(Boolean) columnInfo.get("isNullable") ? "1" : "0"); - field.setIsInsert("1"); - field.setIsEdit("1"); + if ("1".equals(field.getIsPk())) { + field.setIsInsert("0"); + field.setIsEdit("0"); + }else { + field.setIsInsert("1"); + field.setIsEdit("1"); + } field.setIsList("1"); field.setIsQuery("1"); field.setQueryType("EQ"); field.setHtmlType(getDefaultHtmlType((String) columnInfo.get("dataType"))); field.setSort(sort++); - field.setStatus("0"); // 如果字段名为空,使用字段代码作为名称 if (StringUtils.isBlank(field.getName())) { field.setName(field.getCode()); diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaGroupServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaGroupServiceImpl.java index cf2be19b..809c364d 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaGroupServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaGroupServiceImpl.java @@ -60,9 +60,6 @@ public class SchemaGroupServiceImpl implements SchemaGroupService { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.like(StringUtils.isNotBlank(bo.getName()), SchemaGroup::getName, bo.getName()); lqw.eq(StringUtils.isNotBlank(bo.getCode()), SchemaGroup::getCode, bo.getCode()); - lqw.eq(bo.getSort() != null, SchemaGroup::getSort, bo.getSort()); - lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SchemaGroup::getStatus, bo.getStatus()); - lqw.orderByAsc(SchemaGroup::getSort); return lqw; } @@ -102,9 +99,6 @@ public class SchemaGroupServiceImpl implements SchemaGroupService { */ @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if (isValid) { - //TODO 做一些业务上的校验,判断是否需要校验 - } - return baseMapper.deleteBatchIds(ids) > 0; + return baseMapper.deleteByIds(ids) > 0; } } \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaServiceImpl.java index 9e9906fa..4b552dd8 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/impl/SchemaServiceImpl.java @@ -8,7 +8,10 @@ import org.ruoyi.common.core.utils.MapstructUtils; import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.core.page.PageQuery; import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.generator.domain.SchemaGroup; +import org.ruoyi.generator.domain.vo.SchemaGroupVo; import org.ruoyi.generator.event.SchemaDeletedEvent; +import org.ruoyi.generator.service.SchemaGroupService; import org.ruoyi.generator.service.SchemaService; import org.ruoyi.generator.domain.Schema; import org.ruoyi.generator.domain.bo.SchemaBo; @@ -20,6 +23,8 @@ import org.springframework.stereotype.Service; import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.Optional; /** * 数据模型Service业务层处理 @@ -31,6 +36,7 @@ import java.util.List; public class SchemaServiceImpl implements SchemaService { private final SchemaMapper baseMapper; + private final SchemaGroupService schemaGroupService; private final ApplicationEventPublisher eventPublisher; /** @@ -64,10 +70,7 @@ public class SchemaServiceImpl implements SchemaService { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.eq(bo.getSchemaGroupId() != null, Schema::getSchemaGroupId, bo.getSchemaGroupId()); lqw.like(StringUtils.isNotBlank(bo.getName()), Schema::getName, bo.getName()); - lqw.eq(StringUtils.isNotBlank(bo.getCode()), Schema::getCode, bo.getCode()); lqw.eq(StringUtils.isNotBlank(bo.getTableName()), Schema::getTableName, bo.getTableName()); - lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Schema::getStatus, bo.getStatus()); - lqw.orderByAsc(Schema::getSort); return lqw; } @@ -76,15 +79,18 @@ public class SchemaServiceImpl implements SchemaService { */ @Override public Boolean insertByBo(SchemaBo bo) { - Schema add = MapstructUtils.convert(bo, Schema.class); - validEntityBeforeSave(add); - boolean flag = baseMapper.insert(add) > 0; + Schema schema = MapstructUtils.convert(bo, Schema.class); + Long schemaGroupId = bo.getSchemaGroupId(); + SchemaGroupVo schemaGroupVo = schemaGroupService.queryById(schemaGroupId); + if (Objects.nonNull(schemaGroupVo)) { + schema.setCode(schemaGroupVo.getCode()); + } + boolean flag = baseMapper.insert(schema) > 0; if (flag) { - bo.setId(add.getId()); - + bo.setId(schema.getId()); // 发布数据模型添加事件,由事件监听器处理字段插入 if (StringUtils.isNotBlank(bo.getTableName())) { - eventPublisher.publishEvent(new SchemaAddedEvent(this, add.getId(), bo.getTableName())); + eventPublisher.publishEvent(new SchemaAddedEvent(this, schema.getId(), bo.getTableName())); } } return flag; @@ -96,17 +102,9 @@ public class SchemaServiceImpl implements SchemaService { @Override public Boolean updateByBo(SchemaBo bo) { Schema update = MapstructUtils.convert(bo, Schema.class); - validEntityBeforeSave(update); return baseMapper.updateById(update) > 0; } - /** - * 保存前的数据校验 - */ - private void validEntityBeforeSave(Schema entity) { - //TODO 做一些数据校验,如唯一约束 - } - /** * 批量删除数据模型 */ @@ -127,8 +125,6 @@ public class SchemaServiceImpl implements SchemaService { public SchemaVo queryByTableName(String tableName) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.eq(Schema::getTableName, tableName); - // 只查询正常状态的模型 - lqw.eq(Schema::getStatus, "0"); return baseMapper.selectVoOne(lqw); } } \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm index 491f8bc0..939c1b2e 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm @@ -25,26 +25,28 @@ import org.ruoyi.common.core.validate.EditGroup; public class ${ClassName}Bo implements Serializable { #foreach ($column in $columns) - #if($column.isPk || $column.query || $column.insert || $column.edit|| $column.required) - /** - * $column.columnComment - */ - #if(($column.insert && $column.edit) || $column.required) - #set($Group="AddGroup.class, EditGroup.class") - #elseif($column.insert) - #set($Group="AddGroup.class") - #elseif($column.edit) - #set($Group="EditGroup.class") - #end - #if($column.required) - #if($column.javaType == 'String') - @NotBlank(message = "$column.columnComment不能为空", groups = { $Group }) - #else - @NotNull(message = "$column.columnComment不能为空", groups = { $Group }) - #end - #end + #if($column.isPk) private $column.javaType $column.javaField; + #elseif($column.insert || $column.edit) + /** + * $column.columnComment + */ + #if($column.insert && $column.edit) + #set($Group="AddGroup.class, EditGroup.class") + #elseif($column.insert) + #set($Group="AddGroup.class") + #elseif($column.edit) + #set($Group="EditGroup.class") + #end + #if($column.required) + #if($column.javaType == 'String') + @NotBlank(message = "$column.columnComment不能为空", groups = { $Group }) + #else + @NotNull(message = "$column.columnComment不能为空", groups = { $Group }) + #end + #end + private $column.javaType $column.javaField; #end #end diff --git a/script/sql/ruoyi-ai.sql b/script/sql/ruoyi-ai.sql index 47892e9d..2c824c8f 100644 --- a/script/sql/ruoyi-ai.sql +++ b/script/sql/ruoyi-ai.sql @@ -2496,11 +2496,56 @@ CREATE TABLE prompt_template ROW_FORMAT = Dynamic; +DROP TABLE IF EXISTS `dev_schema_group`; +create table dev_schema_group +( + id bigint auto_increment comment '主键' primary key, + name varchar(100) null comment '分组名称', + code varchar(100) null comment '分组编码', + icon varchar(100) null comment '图标', + remark varchar(500) null comment '备注', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '数据模型分组表'; + +INSERT INTO dev_schema_group (id, name, code, icon, remark, del_flag, create_dept, create_by, create_time, update_by, update_time) VALUES +(1944240213530648567, '系统管理', 'system', 'eos-icons:system-group', '系统默认分组', '0', null, null, '2025-07-13 11:37:28', 1, '2025-07-13 18:42:48'); +INSERT INTO dev_schema_group (id, name, code, icon, remark, del_flag, create_dept, create_by, create_time, update_by, update_time) VALUES +(1944240213530648577, '运营管理', 'operator', 'icon-park-outline:appointment', '运营管理', '0', null, null, '2025-07-13 11:39:24', 1, '2025-07-13 18:42:31'); +INSERT INTO dev_schema_group (id, name, code, icon, remark, del_flag, create_dept, create_by, create_time, update_by, update_time) VALUES +(1944346023254429697, '在线开发', 'dev', 'carbon:development', '在线开发', '0', null, null, '2025-07-13 18:39:51', 1, '2025-07-13 18:42:07'); + + + +DROP TABLE IF EXISTS `dev_schema`; +create table dev_schema +( + id bigint auto_increment comment '主键' primary key, + schema_group_id bigint null comment '分组ID', + name varchar(100) null comment '模型名称', + code varchar(100) null comment '模型编码', + table_name varchar(100) null comment '表名', + remark varchar(500) null comment '备注', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '数据模型表'; + DROP TABLE IF EXISTS `dev_schema_field`; create table dev_schema_field ( - id bigint auto_increment comment '主键' - primary key, + id bigint auto_increment comment '主键' primary key, schema_id bigint null comment '模型ID', schema_name varchar(64) null comment '模型名称', name varchar(100) null comment '字段名称', @@ -2513,17 +2558,6 @@ create table dev_schema_field default_value varchar(200) null comment '默认值', length int null comment '字段长度', scale int null comment '小数位数', - sort int null comment '排序', - status char default '0' null comment '状态(0正常 1停用)', - extend_json text null comment '扩展配置', - remark varchar(500) null comment '备注', - del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', - tenant_id varchar(20) default '000000' null comment '租户编号', - create_dept bigint null comment '创建部门', - create_by bigint null comment '创建者', - create_time datetime null comment '创建时间', - update_by bigint null comment '更新者', - update_time datetime null comment '更新时间', is_list char default '1' null comment '是否列表显示(0否 1是)', is_query char default '1' null comment '是否查询字段(0否 1是)', is_insert char default '1' null comment '是否插入字段(0否 1是)', @@ -2531,125 +2565,23 @@ create table dev_schema_field query_type varchar(200) default null comment '查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围)', html_type varchar(200) default 'input' null comment '显示类型(input输入框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传、upload文件上传、editor富文本编辑器)', dict_type varchar(200) default '' null comment '字典类型', - constraint fk_schema_field_schema - foreign key (schema_id) references dev_schema (id) - on delete cascade -) comment '数据模型字段表'; - -create index idx_html_type - on dev_schema_field (html_type); - -create index idx_is_list - on dev_schema_field (is_list); - -create index idx_is_query - on dev_schema_field (is_query); - -create index idx_query_type - on dev_schema_field (query_type); - -create index idx_schema_field_code - on dev_schema_field (code); - -create index idx_schema_field_schema_id - on dev_schema_field (schema_id); - -create index idx_schema_field_status - on dev_schema_field (status); - -create index idx_schema_field_tenant - on dev_schema_field (tenant_id); - - -DROP TABLE IF EXISTS `dev_schema`; -create table dev_schema -( - id bigint auto_increment comment '主键' - primary key, - schema_group_id bigint null comment '分组ID', - name varchar(100) null comment '模型名称', - code varchar(100) null comment '模型编码', - table_name varchar(100) null comment '表名', - comment varchar(500) null comment '表注释', - engine varchar(50) default 'InnoDB' null comment '存储引擎', - list_keys text null comment '列表字段', - search_form_keys text null comment '搜索表单字段', - designer longtext null comment '表单设计', - status char default '0' null comment '状态(0正常 1停用)', - sort int null comment '排序', - remark varchar(500) null comment '备注', - del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', - tenant_id varchar(20) default '000000' null comment '租户编号', - create_dept bigint null comment '创建部门', - create_by bigint null comment '创建者', - create_time datetime null comment '创建时间', - update_by bigint null comment '更新者', - update_time datetime null comment '更新时间', - constraint fk_schema_group - foreign key (schema_group_id) references dev_schema_group (id) - on delete set null -) - comment '数据模型表'; - -create index idx_schema_code - on dev_schema (code); - -create index idx_schema_group_id - on dev_schema (schema_group_id); - -create index idx_schema_status - on dev_schema (status); - -create index idx_schema_table_name - on dev_schema (table_name); - -create index idx_schema_tenant - on dev_schema (tenant_id); - - -DROP TABLE IF EXISTS `dev_schema_group`; -create table dev_schema_group -( - id bigint auto_increment comment '主键' - primary key, - name varchar(100) null comment '分组名称', - code varchar(100) null comment '分组编码', - icon varchar(100) null comment '图标', - sort int null comment '排序', - status char default '0' null comment '状态(0正常 1停用)', - remark varchar(500) null comment '备注', - del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', - tenant_id varchar(20) default '000000' null comment '租户编号', - create_dept bigint null comment '创建部门', - create_by bigint null comment '创建者', - create_time datetime null comment '创建时间', - update_by bigint null comment '更新者', - update_time datetime null comment '更新时间' -) - comment '数据模型分组表'; - -create index idx_schema_group_code - on dev_schema_group (code); - -create index idx_schema_group_status - on dev_schema_group (status); - -create index idx_schema_group_tenant - on dev_schema_group (tenant_id); - - -INSERT INTO dev_schema_group (id, name, code, icon, sort, status, remark, del_flag, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1944240213530648567, '系统管理', 'system', 'eos-icons:system-group', 2, '0', '系统默认分组', '0', '000000', null, null, '2025-07-13 11:37:28', 1, '2025-07-13 18:42:48'); -INSERT INTO dev_schema_group (id, name, code, icon, sort, status, remark, del_flag, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1944240213530648577, '运营管理', 'operator', 'icon-park-outline:appointment', 1, '0', null, '0', '000000', null, null, '2025-07-13 11:39:24', 1, '2025-07-13 18:42:31'); -INSERT INTO dev_schema_group (id, name, code, icon, sort, status, remark, del_flag, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1944346023254429697, '在线开发', 'dev', 'carbon:development', 3, '0', null, '0', '000000', null, null, '2025-07-13 18:39:51', 1, '2025-07-13 18:42:07'); - - - + sort int null comment '排序', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar(500) null comment '备注' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '数据模型字段表'; +DROP TABLE IF EXISTS `knowledge_role`; -- ---------------------------- -- Table structure for knowledge_role -- ---------------------------- -DROP TABLE IF EXISTS `knowledge_role`; CREATE TABLE `knowledge_role` ( `id` bigint NOT NULL COMMENT '知识库角色id', `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库角色name', @@ -2664,10 +2596,10 @@ CREATE TABLE `knowledge_role` ( PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '知识库角色表' ROW_FORMAT = DYNAMIC; +DROP TABLE IF EXISTS `knowledge_role_group`; -- ---------------------------- -- Table structure for knowledge_role_group -- ---------------------------- -DROP TABLE IF EXISTS `knowledge_role_group`; CREATE TABLE `knowledge_role_group` ( `id` bigint NOT NULL COMMENT '知识库角色组id', `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库角色组name', From 7108727395d46695e5a3a0c9fdd50fadb66a2099 Mon Sep 17 00:00:00 2001 From: l90215 Date: Wed, 13 Aug 2025 12:37:10 +0800 Subject: [PATCH 11/33] =?UTF-8?q?feat:=20fix=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=B1=BB=E5=9E=8B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/vm/java/vo.java.vm | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm index 15e437c9..aa9b8543 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm @@ -23,29 +23,30 @@ import java.util.Date; @AutoMapper(target = ${ClassName}.class) public class ${ClassName}Vo implements Serializable { - #foreach ($column in $columns) - #if($column.list) - /** - * $column.columnComment - */ - #set($parentheseIndex=$column.columnComment.indexOf("(")) - #if($parentheseIndex != -1) - #set($comment=$column.columnComment.substring(0, $parentheseIndex)) - #else - #set($comment=$column.columnComment) - #end - #if(${column.dictType} && ${column.dictType} != '') - @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "${column.dictType}") - #elseif($parentheseIndex != -1) - @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) - @ExcelDictFormat(readConverterExp = "$column.readConverterExp()") - #else - @ExcelProperty(value = "${comment}") - #end - private $column.javaType $column.javaField; - - #end +#foreach ($column in $columns) + #if($column.isPk) + private $column.javaType $column.javaField; + #elseif($column.list) + /** + * $column.columnComment + */ + #set($parentheseIndex=$column.columnComment.indexOf("(")) + #if($parentheseIndex != -1) + #set($comment=$column.columnComment.substring(0, $parentheseIndex)) + #else + #set($comment=$column.columnComment) #end + #if(${column.dictType} && ${column.dictType} != '') + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "${column.dictType}") + #elseif($parentheseIndex != -1) + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "$column.readConverterExp()") + #else + @ExcelProperty(value = "${comment}") + #end + private $column.javaType $column.javaField; + #end +#end } From 099c94e3cb6934ecb6f102a6e4e2cb40477c635e Mon Sep 17 00:00:00 2001 From: l90215 Date: Fri, 15 Aug 2025 09:56:47 +0800 Subject: [PATCH 12/33] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E5=8F=AA?= =?UTF-8?q?=E6=98=AF=E5=BA=93=E8=A7=92=E8=89=B2=E9=BB=98=E8=AE=A4=E4=B8=8D?= =?UTF-8?q?=E5=BC=80=E5=90=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-admin/src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index f6abd846..1992a5ab 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -162,7 +162,7 @@ tenant: - sys_user_role knowledge-role: - enable: true + enable: false # MyBatisPlus配置 # https://baomidou.com/config/ From b52f7a711208de39575fff795c514e95dd47bec4 Mon Sep 17 00:00:00 2001 From: violateer <1828257089@qq.com> Date: Fri, 15 Aug 2025 20:41:59 +0800 Subject: [PATCH 13/33] =?UTF-8?q?feature:=20=E6=B7=BB=E5=8A=A0=E5=BC=80?= =?UTF-8?q?=E5=90=AF=E7=9F=A5=E8=AF=86=E5=BA=93=E8=A7=92=E8=89=B2=EF=BC=8C?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=8F=AF=E8=A7=81=E4=B8=AA=E4=BA=BA=E7=9F=A5?= =?UTF-8?q?=E8=AF=86=E5=BA=93=E5=8F=8A=E8=A7=92=E8=89=B2=E5=88=86=E9=85=8D?= =?UTF-8?q?=E7=9F=A5=E8=AF=86=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-admin/src/main/resources/application.yml | 2 +- .../org/ruoyi/service/IKnowledgeInfoService.java | 2 +- .../controller/knowledge/KnowledgeController.java | 14 +++----------- .../knowledge/KnowledgeInfoServiceImpl.java | 13 ++++++++++--- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 1992a5ab..f6abd846 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -162,7 +162,7 @@ tenant: - sys_user_role knowledge-role: - enable: false + enable: true # MyBatisPlus配置 # https://baomidou.com/config/ diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java index 3972677d..754ba7c7 100644 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java @@ -31,7 +31,7 @@ public interface IKnowledgeInfoService { /** * 查询知识库列表 */ - TableDataInfo queryPageListByRole(PageQuery pageQuery); + TableDataInfo queryPageListByRole(KnowledgeInfoBo bo, PageQuery pageQuery); /** * 查询知识库列表 diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java index 76443156..a1a72e1a 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java @@ -7,7 +7,6 @@ import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.ruoyi.chat.config.KnowledgeRoleConfig; import org.ruoyi.common.core.domain.R; -import org.ruoyi.common.core.domain.model.LoginUser; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.excel.utils.ExcelUtil; import org.ruoyi.common.log.annotation.Log; @@ -27,14 +26,7 @@ import org.ruoyi.service.IKnowledgeAttachService; import org.ruoyi.service.IKnowledgeFragmentService; import org.ruoyi.service.IKnowledgeInfoService; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -90,8 +82,8 @@ public class KnowledgeController extends BaseController { bo.setUid(LoginHelper.getUserId()); return knowledgeInfoService.queryPageList(bo, pageQuery); } else { - // TODO 自己创建的知识库+角色分配的知识库 - return knowledgeInfoService.queryPageListByRole(pageQuery); + bo.setUid(LoginHelper.getUserId()); + return knowledgeInfoService.queryPageListByRole(bo, pageQuery); } } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java index d2eb1276..12ccab1f 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java @@ -89,7 +89,7 @@ public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService { * 根据知识库角色查询知识库列表 */ @Override - public TableDataInfo queryPageListByRole(PageQuery pageQuery) { + public TableDataInfo queryPageListByRole(KnowledgeInfoBo bo, PageQuery pageQuery) { // 查询用户关联角色 LoginUser loginUser = LoginHelper.getLoginUser(); if (StringUtils.isEmpty(loginUser.getKroleGroupIds()) || StringUtils.isEmpty(loginUser.getKroleGroupType())) { @@ -122,8 +122,15 @@ public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService { return new TableDataInfo<>(); } - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.in(KnowledgeInfo::getId, knowledgeRoleRelations.stream().map(KnowledgeRoleRelation::getKnowledgeId).filter(Objects::nonNull).collect(Collectors.toList())); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + // 在查询用户创建的知识库条件下,拼接角色分配知识库 + lqw.or(q -> q.in( + KnowledgeInfo::getId, + knowledgeRoleRelations.stream() + .map(KnowledgeRoleRelation::getKnowledgeId) + .filter(Objects::nonNull) + .collect(Collectors.toList()) + )); Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); return TableDataInfo.build(result); } From e9cd9e84d458d6ff589fb87830c8ac649c40f172 Mon Sep 17 00:00:00 2001 From: violateer <1828257089@qq.com> Date: Fri, 15 Aug 2025 20:43:14 +0800 Subject: [PATCH 14/33] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9krole=5Fgroup=5F?= =?UTF-8?q?ids=E5=AD=97=E6=AE=B5=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/sql/update/knowledge-role-bak.sql | 97 ++++++++++++++---------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/script/sql/update/knowledge-role-bak.sql b/script/sql/update/knowledge-role-bak.sql index 62a7ce67..e2e4842e 100644 --- a/script/sql/update/knowledge-role-bak.sql +++ b/script/sql/update/knowledge-role-bak.sql @@ -21,63 +21,80 @@ SET FOREIGN_KEY_CHECKS = 0; -- Table structure for knowledge_role -- ---------------------------- DROP TABLE IF EXISTS `knowledge_role`; -CREATE TABLE `knowledge_role` ( - `id` bigint NOT NULL COMMENT '知识库角色id', - `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库角色name', - `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', - `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门', - `create_by` bigint NULL DEFAULT NULL COMMENT '创建者', - `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', - `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', - `group_id` bigint NULL DEFAULT NULL COMMENT '知识库角色组id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '知识库角色表' ROW_FORMAT = DYNAMIC; +CREATE TABLE `knowledge_role` +( + `id` bigint NOT NULL COMMENT '知识库角色id', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库角色name', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `group_id` bigint NULL DEFAULT NULL COMMENT '知识库角色组id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '知识库角色表' + ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for knowledge_role_group -- ---------------------------- DROP TABLE IF EXISTS `knowledge_role_group`; -CREATE TABLE `knowledge_role_group` ( - `id` bigint NOT NULL COMMENT '知识库角色组id', - `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库角色组name', - `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', - `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门', - `create_by` bigint NULL DEFAULT NULL COMMENT '创建者', - `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', - `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '知识库角色组表' ROW_FORMAT = DYNAMIC; +CREATE TABLE `knowledge_role_group` +( + `id` bigint NOT NULL COMMENT '知识库角色组id', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库角色组name', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '知识库角色组表' + ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for knowledge_role_relation -- ---------------------------- DROP TABLE IF EXISTS `knowledge_role_relation`; -CREATE TABLE `knowledge_role_relation` ( - `id` bigint NOT NULL COMMENT 'id', - `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', - `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门', - `create_by` bigint NULL DEFAULT NULL COMMENT '创建者', - `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', - `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', - `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', - `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', - `knowledge_role_id` bigint NULL DEFAULT NULL COMMENT '知识库角色id', - `knowledge_id` bigint NULL DEFAULT NULL COMMENT '知识库id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '知识库角色与知识库关联表' ROW_FORMAT = DYNAMIC; +CREATE TABLE `knowledge_role_relation` +( + `id` bigint NOT NULL COMMENT 'id', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `knowledge_role_id` bigint NULL DEFAULT NULL COMMENT '知识库角色id', + `knowledge_id` bigint NULL DEFAULT NULL COMMENT '知识库id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '知识库角色与知识库关联表' + ROW_FORMAT = DYNAMIC; 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', 'operator/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 ADD COLUMN `krole_group_type` VARCHAR(50) COMMENT '关联知识库角色/角色组', -ADD COLUMN `krole_group_id` TEXT COMMENT '关联知识库角色/角色组id'; + ADD COLUMN `krole_group_ids` TEXT COMMENT '关联知识库角色/角色组id'; From d7b89cd1b383d333101908d2be5c2178349929fd Mon Sep 17 00:00:00 2001 From: lixiang <17851857880@163.com> Date: Mon, 18 Aug 2025 11:12:06 +0800 Subject: [PATCH 15/33] =?UTF-8?q?=E5=90=91=E9=87=8F=E5=BA=93sql=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=8E=BB=E9=99=A4=E5=8C=B9=E9=85=8D=E5=88=86=E5=80=BC?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/VectorStoreServiceImpl.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/VectorStoreServiceImpl.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/VectorStoreServiceImpl.java index 85534b2c..f3e83b11 100644 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/VectorStoreServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/VectorStoreServiceImpl.java @@ -42,7 +42,7 @@ public class VectorStoreServiceImpl implements VectorStoreService { private final ConfigService configService; - private EmbeddingStore embeddingStore; +// private EmbeddingStore embeddingStore; private WeaviateClient client; @@ -82,14 +82,14 @@ public class VectorStoreServiceImpl implements VectorStoreService { log.info("Schema 创建成功: {}", className); } } - embeddingStore = WeaviateEmbeddingStore.builder() - .scheme(protocol) - .host(host) - .objectClass(className) - .scheme(protocol) - .avoidDups(true) - .consistencyLevel("ALL") - .build(); +// embeddingStore = WeaviateEmbeddingStore.builder() +// .scheme(protocol) +// .host(host) +// .objectClass(className) +// .scheme(protocol) +// .avoidDups(true) +// .consistencyLevel("ALL") +// .build(); } @Override @@ -148,7 +148,7 @@ public class VectorStoreServiceImpl implements VectorStoreService { String graphQLQuery = String.format( "{\n" + " Get {\n" + - " %s(nearVector: {vector: [%s], certainty: %f} limit: %d) {\n" + + " %s(nearVector: {vector: [%s]} limit: %d) {\n" + " text\n" + " fid\n" + " kid\n" + From 8d0c557bdbb3c96db02cc3f2417134249bb52160 Mon Sep 17 00:00:00 2001 From: likunlong Date: Mon, 18 Aug 2025 14:30:08 +0800 Subject: [PATCH 16/33] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=8E=B7=E5=8F=96=E9=AB=98=E4=BC=98=E5=85=88=E7=BA=A7?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=92=8C=E6=9C=8D=E5=8A=A1=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/ruoyi/domain/ChatModel.java | 5 + .../java/org/ruoyi/domain/bo/ChatModelBo.java | 5 + .../org/ruoyi/service/IChatModelService.java | 6 + .../service/impl/ChatModelServiceImpl.java | 13 ++ .../service/chat/impl/SseServiceImpl.java | 220 +++++++++++++----- 5 files changed, 186 insertions(+), 63 deletions(-) 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..dd443d97 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 @@ -75,6 +75,11 @@ public class ChatModel extends BaseEntity { */ private String apiKey; + /** + * 优先级 + */ + private Integer priority; + /** * 备注 */ diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java index f333ed0c..b828515b 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatModelBo.java @@ -74,6 +74,11 @@ public class ChatModelBo extends BaseEntity { @NotBlank(message = "请求地址不能为空", groups = { AddGroup.class, EditGroup.class }) private String apiHost; + /** + * 优先级 + */ + private Integer priority; + /** * 密钥 */ diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java index 62dbf970..d93b527e 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java @@ -57,6 +57,12 @@ public interface IChatModelService { * 通过模型分类获取模型信息 */ ChatModelVo selectModelByCategory(String image); + + /** + * 通过模型分类获取优先级最高的模型信息 + */ + ChatModelVo selectModelByCategoryWithHighestPriority(String category); + /** * 获取ppt模型信息 */ diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java index d0b5f5cd..b7acfaa9 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java @@ -136,6 +136,19 @@ public class ChatModelServiceImpl implements IChatModelService { public ChatModelVo selectModelByCategory(String category) { return baseMapper.selectVoOne(Wrappers.lambdaQuery().eq(ChatModel::getCategory, category)); } + + /** + * 通过模型分类获取优先级最高的模型信息 + */ + @Override + public ChatModelVo selectModelByCategoryWithHighestPriority(String category) { + return baseMapper.selectVoOne( + Wrappers.lambdaQuery() + .eq(ChatModel::getCategory, category) + .orderByDesc(ChatModel::getPriority) + .last("LIMIT 1") + ); + } @Override public ChatModel getPPT() { diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java index 269fcac0..e0d72866 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java @@ -113,8 +113,8 @@ public class SseServiceImpl implements ISseService { chatRequest.setSessionId(chatSessionBo.getId()); } } - // 根据模型分类调用不同的处理逻辑 - IChatService chatService = chatServiceFactory.getChatService(chatModelVo.getCategory()); + // 自动选择模型并获取对应的聊天服务 + IChatService chatService = autoSelectModelAndGetService(chatRequest); chatService.chat(chatRequest, sseEmitter); } catch (Exception e) { log.error(e.getMessage(),e); @@ -123,6 +123,45 @@ public class SseServiceImpl implements ISseService { return sseEmitter; } + /** + * 自动选择模型并获取对应的聊天服务 + */ + private IChatService autoSelectModelAndGetService(ChatRequest chatRequest) { + try { + // 处理特殊模型类型 + if ("gpt-image".equals(chatRequest.getModel())) { + chatModelVo = selectModelByCategory("image"); + return chatServiceFactory.getChatService(chatModelVo.getCategory()); + } + + // 根据模型名称获取模型分类,然后获取该分类下优先级最高的模型 + ChatModelVo tempModel = chatModelService.selectModelByName(chatRequest.getModel()); + if (tempModel == null) { + throw new IllegalStateException("未找到模型名称:" + chatRequest.getModel()); + } + + chatModelVo = selectModelByCategory(tempModel.getCategory()); + + // 直接返回对应的聊天服务 + return chatServiceFactory.getChatService(chatModelVo.getCategory()); + + } catch (Exception e) { + log.error("模型选择和服务获取失败: {}", e.getMessage(), e); + throw new IllegalStateException("模型选择和服务获取失败: " + e.getMessage()); + } + } + + /** + * 根据分类选择优先级最高的模型 + */ + private ChatModelVo selectModelByCategory(String category) { + ChatModelVo model = chatModelService.selectModelByCategoryWithHighestPriority(category); + if (model == null) { + throw new IllegalStateException("未找到" + category + "分类的模型配置"); + } + return model; + } + /** * 获取对话标题 * @@ -144,66 +183,20 @@ public class SseServiceImpl implements ISseService { * 构建消息列表 */ private void buildChatMessageList(ChatRequest chatRequest){ - String sysPrompt; - // 矫正模型名称 如果是gpt-image 则查询image类型模型 获取模型名称 - if(chatRequest.getModel().equals("gpt-image")) { - chatModelVo = chatModelService.selectModelByCategory("image"); - if (chatModelVo == null) { - log.error("未找到image类型的模型配置"); - throw new IllegalStateException("未找到image类型的模型配置"); - } - }else{ - chatModelVo = chatModelService.selectModelByName(chatRequest.getModel()); - } - // 获取对话消息列表 List messages = chatRequest.getMessages(); - // 查询向量库相关信息加入到上下文 - if(StringUtils.isNotEmpty(chatRequest.getKid())){ - List knMessages = new ArrayList<>(); - String content = messages.get(messages.size() - 1).getContent().toString(); - // 通过kid查询知识库信息 - KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(chatRequest.getKid())); - // 查询向量模型配置信息 - ChatModelVo chatModel = chatModelService.selectModelByName(knowledgeInfoVo.getEmbeddingModelName()); - - QueryVectorBo queryVectorBo = new QueryVectorBo(); - queryVectorBo.setQuery(content); - queryVectorBo.setKid(chatRequest.getKid()); - queryVectorBo.setApiKey(chatModel.getApiKey()); - queryVectorBo.setBaseUrl(chatModel.getApiHost()); - queryVectorBo.setVectorModelName(knowledgeInfoVo.getVectorModelName()); - queryVectorBo.setEmbeddingModelName(knowledgeInfoVo.getEmbeddingModelName()); - queryVectorBo.setMaxResults(knowledgeInfoVo.getRetrieveLimit()); - List nearestList = vectorStoreService.getQueryVector(queryVectorBo); - for (String prompt : nearestList) { - Message userMessage = Message.builder().content(prompt).role(Message.Role.USER).build(); - knMessages.add(userMessage); - } - messages.addAll(knMessages); - // 设置知识库系统提示词 - sysPrompt = knowledgeInfoVo.getSystemPrompt(); - if(StringUtils.isEmpty(sysPrompt)){ - sysPrompt ="###角色设定\n" + - "你是一个智能知识助手,专注于利用上下文中的信息来提供准确和相关的回答。\n" + - "###指令\n" + - "当用户的问题与上下文知识匹配时,利用上下文信息进行回答。如果问题与上下文不匹配,运用自身的推理能力生成合适的回答。\n" + - "###限制\n" + - "确保回答清晰简洁,避免提供不必要的细节。始终保持语气友好" + - "当前时间:"+ DateUtils.getDate(); - } - }else { - sysPrompt = chatModelVo.getSystemPrompt(); - if(StringUtils.isEmpty(sysPrompt)){ - sysPrompt ="你是一个由RuoYI-AI开发的人工智能助手,名字叫熊猫助手。你擅长中英文对话,能够理解并处理各种问题,提供安全、有帮助、准确的回答。" + - "当前时间:"+ DateUtils.getDate()+ - "#注意:回复之前注意结合上下文和工具返回内容进行回复。"; - } - } - // 设置系统默认提示词 - Message sysMessage = Message.builder().content(sysPrompt).role(Message.Role.SYSTEM).build(); - messages.add(0,sysMessage); - + + // 处理知识库相关逻辑 + String sysPrompt = processKnowledgeBase(chatRequest, messages); + + // 设置系统提示词 + Message sysMessage = Message.builder() + .content(sysPrompt) + .role(Message.Role.SYSTEM) + .build(); + messages.add(0, sysMessage); + chatRequest.setSysPrompt(sysPrompt); + // 用户对话内容 String chatString = null; // 获取用户对话信息 @@ -212,12 +205,113 @@ public class SseServiceImpl implements ISseService { if (CollectionUtil.isNotEmpty(listContent)) { chatString = listContent.get(0).toString(); } - } else if (content instanceof String) { - chatString = (String) content; + } else { + chatString = content.toString(); } - // 设置对话信息 chatRequest.setPrompt(chatString); } + + /** + * 处理知识库相关逻辑 + */ + private String processKnowledgeBase(ChatRequest chatRequest, List messages) { + if (StringUtils.isEmpty(chatRequest.getKid())) { + return getDefaultSystemPrompt(); + } + + try { + // 查询知识库信息 + KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(chatRequest.getKid())); + if (knowledgeInfoVo == null) { + log.warn("知识库信息不存在,kid: {}", chatRequest.getKid()); + return getDefaultSystemPrompt(); + } + + // 查询向量模型配置信息 + ChatModelVo chatModel = chatModelService.selectModelByName(knowledgeInfoVo.getEmbeddingModelName()); + if (chatModel == null) { + log.warn("向量模型配置不存在,模型名称: {}", knowledgeInfoVo.getEmbeddingModelName()); + return getDefaultSystemPrompt(); + } + + // 构建向量查询参数 + QueryVectorBo queryVectorBo = buildQueryVectorBo(chatRequest, knowledgeInfoVo, chatModel); + + // 获取向量查询结果 + List nearestList = vectorStoreService.getQueryVector(queryVectorBo); + + // 添加知识库消息到上下文 + addKnowledgeMessages(messages, nearestList); + + // 返回知识库系统提示词 + return getKnowledgeSystemPrompt(knowledgeInfoVo); + + } catch (Exception e) { + log.error("处理知识库信息失败: {}", e.getMessage(), e); + return getDefaultSystemPrompt(); + } + } + + /** + * 构建向量查询参数 + */ + private QueryVectorBo buildQueryVectorBo(ChatRequest chatRequest, KnowledgeInfoVo knowledgeInfoVo, ChatModelVo chatModel) { + String content = chatRequest.getMessages().get(chatRequest.getMessages().size() - 1).getContent().toString(); + + QueryVectorBo queryVectorBo = new QueryVectorBo(); + queryVectorBo.setQuery(content); + queryVectorBo.setKid(chatRequest.getKid()); + queryVectorBo.setApiKey(chatModel.getApiKey()); + queryVectorBo.setBaseUrl(chatModel.getApiHost()); + queryVectorBo.setVectorModelName(knowledgeInfoVo.getVectorModelName()); + queryVectorBo.setEmbeddingModelName(knowledgeInfoVo.getEmbeddingModelName()); + queryVectorBo.setMaxResults(knowledgeInfoVo.getRetrieveLimit()); + + return queryVectorBo; + } + + /** + * 添加知识库消息到上下文 + */ + private void addKnowledgeMessages(List messages, List nearestList) { + for (String prompt : nearestList) { + Message userMessage = Message.builder() + .content(prompt) + .role(Message.Role.USER) + .build(); + messages.add(userMessage); + } + } + + /** + * 获取知识库系统提示词 + */ + private String getKnowledgeSystemPrompt(KnowledgeInfoVo knowledgeInfoVo) { + String sysPrompt = knowledgeInfoVo.getSystemPrompt(); + if (StringUtils.isEmpty(sysPrompt)) { + sysPrompt = "###角色设定\n" + + "你是一个智能知识助手,专注于利用上下文中的信息来提供准确和相关的回答。\n" + + "###指令\n" + + "当用户的问题与上下文知识匹配时,利用上下文信息进行回答。如果问题与上下文不匹配,运用自身的推理能力生成合适的回答。\n" + + "###限制\n" + + "确保回答清晰简洁,避免提供不必要的细节。始终保持语气友好\n" + + "当前时间:" + DateUtils.getDate(); + } + return sysPrompt; + } + + /** + * 获取默认系统提示词 + */ + private String getDefaultSystemPrompt() { + String sysPrompt = chatModelVo != null ? chatModelVo.getSystemPrompt() : null; + if (StringUtils.isEmpty(sysPrompt)) { + sysPrompt = "你是一个由RuoYI-AI开发的人工智能助手,名字叫熊猫助手。你擅长中英文对话,能够理解并处理各种问题,提供安全、有帮助、准确的回答。" + + "当前时间:" + DateUtils.getDate() + + "#注意:回复之前注意结合上下文和工具返回内容进行回复。"; + } + return sysPrompt; + } /** From 8751bb5104d47e8035d7c1be72800f6b21921b64 Mon Sep 17 00:00:00 2001 From: likunlong Date: Mon, 18 Aug 2025 14:49:56 +0800 Subject: [PATCH 17/33] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E5=BA=93chat?= =?UTF-8?q?=5Fmodel=E6=B7=BB=E5=8A=A0=E4=BC=98=E5=85=88=E7=BA=A7=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/sql/update/chat-model-priority.sql | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 script/sql/update/chat-model-priority.sql diff --git a/script/sql/update/chat-model-priority.sql b/script/sql/update/chat-model-priority.sql new file mode 100644 index 00000000..b7249fa0 --- /dev/null +++ b/script/sql/update/chat-model-priority.sql @@ -0,0 +1,26 @@ +alter table chat_model + add priority int default 1 null comment '模型优先级(值越大优先级越高)'; + +UPDATE `ruoyi-ai`.chat_model t +SET t.priority = 3 +WHERE t.id = 1782792839548735492; + +UPDATE `ruoyi-ai`.chat_model t +SET t.priority = 6 +WHERE t.id = 1859570229117022212; + +UPDATE `ruoyi-ai`.chat_model t +SET t.priority = 5 +WHERE t.id = 1859570229117022211; + +UPDATE `ruoyi-ai`.chat_model t +SET t.priority = 4 +WHERE t.id = 1782792839548735493; + +UPDATE `ruoyi-ai`.chat_model t +SET t.priority = 2 +WHERE t.id = 1828324413241466881; + +UPDATE `ruoyi-ai`.chat_model t +SET t.priority = 2 +WHERE t.id = 1782792839548735491; \ No newline at end of file From 645c754dd0dc02daed2d9da8e3cd1123430cb49d Mon Sep 17 00:00:00 2001 From: fy53888 Date: Mon, 18 Aug 2025 19:56:26 +0800 Subject: [PATCH 18/33] =?UTF-8?q?=E5=A4=87=E5=88=86=E4=B8=80=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 4 +- .../src/main/resources/application.yml | 2 +- .../main/java/org/ruoyi/domain/ChatModel.java | 6 + .../java/org/ruoyi/domain/vo/ChatModelVo.java | 140 ++++++++++++- .../knowledge/KnowledgeController.java | 20 +- script/sql/ruoyi-ai.sql | 188 ++++++------------ script/sql/update/20250808.sql | 3 + script/sql/update/knowledge-role-bak.sql | 2 +- 8 files changed, 226 insertions(+), 139 deletions(-) create mode 100644 script/sql/update/20250808.sql diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 0b1661e2..15ed79b8 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -16,9 +16,9 @@ spring: master: type: ${spring.datasource.type} driverClassName: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true + url: jdbc:mysql://127.0.0.1:3306/ruoyistore?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true username: root - password: 123456 + password: root hikari: # 最大连接池数量 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index f6abd846..1992a5ab 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -162,7 +162,7 @@ tenant: - sys_user_role knowledge-role: - enable: true + enable: false # MyBatisPlus配置 # https://baomidou.com/config/ 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-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java index 54ef52e9..76443156 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java @@ -27,10 +27,18 @@ import org.ruoyi.service.IKnowledgeAttachService; import org.ruoyi.service.IKnowledgeFragmentService; import org.ruoyi.service.IKnowledgeInfoService; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.util.List; +import java.util.Objects; /** * 知识库管理 @@ -60,7 +68,9 @@ public class KnowledgeController extends BaseController { if (!StpUtil.isLogin()) { throw new SecurityException("请先去登录!"); } - bo.setUid(LoginHelper.getUserId()); + if (!Objects.equals(LoginHelper.getUserId(), 1L)) { + bo.setUid(LoginHelper.getUserId()); + } return knowledgeInfoService.queryPageList(bo, pageQuery); } @@ -72,13 +82,15 @@ public class KnowledgeController extends BaseController { if (!StpUtil.isLogin()) { throw new SecurityException("请先去登录!"); } - LoginUser loginUser = LoginHelper.getLoginUser(); // 管理员跳过权限 - if (loginUser.getUserId().equals(1L) || !knowledgeRoleConfig.getEnable()) { + if (Objects.equals(LoginHelper.getUserId(), 1L)) { + return knowledgeInfoService.queryPageList(bo, pageQuery); + } else if (!knowledgeRoleConfig.getEnable()) { bo.setUid(LoginHelper.getUserId()); return knowledgeInfoService.queryPageList(bo, pageQuery); } else { + // TODO 自己创建的知识库+角色分配的知识库 return knowledgeInfoService.queryPageListByRole(pageQuery); } } diff --git a/script/sql/ruoyi-ai.sql b/script/sql/ruoyi-ai.sql index 47892e9d..2c824c8f 100644 --- a/script/sql/ruoyi-ai.sql +++ b/script/sql/ruoyi-ai.sql @@ -2496,11 +2496,56 @@ CREATE TABLE prompt_template ROW_FORMAT = Dynamic; +DROP TABLE IF EXISTS `dev_schema_group`; +create table dev_schema_group +( + id bigint auto_increment comment '主键' primary key, + name varchar(100) null comment '分组名称', + code varchar(100) null comment '分组编码', + icon varchar(100) null comment '图标', + remark varchar(500) null comment '备注', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '数据模型分组表'; + +INSERT INTO dev_schema_group (id, name, code, icon, remark, del_flag, create_dept, create_by, create_time, update_by, update_time) VALUES +(1944240213530648567, '系统管理', 'system', 'eos-icons:system-group', '系统默认分组', '0', null, null, '2025-07-13 11:37:28', 1, '2025-07-13 18:42:48'); +INSERT INTO dev_schema_group (id, name, code, icon, remark, del_flag, create_dept, create_by, create_time, update_by, update_time) VALUES +(1944240213530648577, '运营管理', 'operator', 'icon-park-outline:appointment', '运营管理', '0', null, null, '2025-07-13 11:39:24', 1, '2025-07-13 18:42:31'); +INSERT INTO dev_schema_group (id, name, code, icon, remark, del_flag, create_dept, create_by, create_time, update_by, update_time) VALUES +(1944346023254429697, '在线开发', 'dev', 'carbon:development', '在线开发', '0', null, null, '2025-07-13 18:39:51', 1, '2025-07-13 18:42:07'); + + + +DROP TABLE IF EXISTS `dev_schema`; +create table dev_schema +( + id bigint auto_increment comment '主键' primary key, + schema_group_id bigint null comment '分组ID', + name varchar(100) null comment '模型名称', + code varchar(100) null comment '模型编码', + table_name varchar(100) null comment '表名', + remark varchar(500) null comment '备注', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '数据模型表'; + DROP TABLE IF EXISTS `dev_schema_field`; create table dev_schema_field ( - id bigint auto_increment comment '主键' - primary key, + id bigint auto_increment comment '主键' primary key, schema_id bigint null comment '模型ID', schema_name varchar(64) null comment '模型名称', name varchar(100) null comment '字段名称', @@ -2513,17 +2558,6 @@ create table dev_schema_field default_value varchar(200) null comment '默认值', length int null comment '字段长度', scale int null comment '小数位数', - sort int null comment '排序', - status char default '0' null comment '状态(0正常 1停用)', - extend_json text null comment '扩展配置', - remark varchar(500) null comment '备注', - del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', - tenant_id varchar(20) default '000000' null comment '租户编号', - create_dept bigint null comment '创建部门', - create_by bigint null comment '创建者', - create_time datetime null comment '创建时间', - update_by bigint null comment '更新者', - update_time datetime null comment '更新时间', is_list char default '1' null comment '是否列表显示(0否 1是)', is_query char default '1' null comment '是否查询字段(0否 1是)', is_insert char default '1' null comment '是否插入字段(0否 1是)', @@ -2531,125 +2565,23 @@ create table dev_schema_field query_type varchar(200) default null comment '查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围)', html_type varchar(200) default 'input' null comment '显示类型(input输入框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传、upload文件上传、editor富文本编辑器)', dict_type varchar(200) default '' null comment '字典类型', - constraint fk_schema_field_schema - foreign key (schema_id) references dev_schema (id) - on delete cascade -) comment '数据模型字段表'; - -create index idx_html_type - on dev_schema_field (html_type); - -create index idx_is_list - on dev_schema_field (is_list); - -create index idx_is_query - on dev_schema_field (is_query); - -create index idx_query_type - on dev_schema_field (query_type); - -create index idx_schema_field_code - on dev_schema_field (code); - -create index idx_schema_field_schema_id - on dev_schema_field (schema_id); - -create index idx_schema_field_status - on dev_schema_field (status); - -create index idx_schema_field_tenant - on dev_schema_field (tenant_id); - - -DROP TABLE IF EXISTS `dev_schema`; -create table dev_schema -( - id bigint auto_increment comment '主键' - primary key, - schema_group_id bigint null comment '分组ID', - name varchar(100) null comment '模型名称', - code varchar(100) null comment '模型编码', - table_name varchar(100) null comment '表名', - comment varchar(500) null comment '表注释', - engine varchar(50) default 'InnoDB' null comment '存储引擎', - list_keys text null comment '列表字段', - search_form_keys text null comment '搜索表单字段', - designer longtext null comment '表单设计', - status char default '0' null comment '状态(0正常 1停用)', - sort int null comment '排序', - remark varchar(500) null comment '备注', - del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', - tenant_id varchar(20) default '000000' null comment '租户编号', - create_dept bigint null comment '创建部门', - create_by bigint null comment '创建者', - create_time datetime null comment '创建时间', - update_by bigint null comment '更新者', - update_time datetime null comment '更新时间', - constraint fk_schema_group - foreign key (schema_group_id) references dev_schema_group (id) - on delete set null -) - comment '数据模型表'; - -create index idx_schema_code - on dev_schema (code); - -create index idx_schema_group_id - on dev_schema (schema_group_id); - -create index idx_schema_status - on dev_schema (status); - -create index idx_schema_table_name - on dev_schema (table_name); - -create index idx_schema_tenant - on dev_schema (tenant_id); - - -DROP TABLE IF EXISTS `dev_schema_group`; -create table dev_schema_group -( - id bigint auto_increment comment '主键' - primary key, - name varchar(100) null comment '分组名称', - code varchar(100) null comment '分组编码', - icon varchar(100) null comment '图标', - sort int null comment '排序', - status char default '0' null comment '状态(0正常 1停用)', - remark varchar(500) null comment '备注', - del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', - tenant_id varchar(20) default '000000' null comment '租户编号', - create_dept bigint null comment '创建部门', - create_by bigint null comment '创建者', - create_time datetime null comment '创建时间', - update_by bigint null comment '更新者', - update_time datetime null comment '更新时间' -) - comment '数据模型分组表'; - -create index idx_schema_group_code - on dev_schema_group (code); - -create index idx_schema_group_status - on dev_schema_group (status); - -create index idx_schema_group_tenant - on dev_schema_group (tenant_id); - - -INSERT INTO dev_schema_group (id, name, code, icon, sort, status, remark, del_flag, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1944240213530648567, '系统管理', 'system', 'eos-icons:system-group', 2, '0', '系统默认分组', '0', '000000', null, null, '2025-07-13 11:37:28', 1, '2025-07-13 18:42:48'); -INSERT INTO dev_schema_group (id, name, code, icon, sort, status, remark, del_flag, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1944240213530648577, '运营管理', 'operator', 'icon-park-outline:appointment', 1, '0', null, '0', '000000', null, null, '2025-07-13 11:39:24', 1, '2025-07-13 18:42:31'); -INSERT INTO dev_schema_group (id, name, code, icon, sort, status, remark, del_flag, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1944346023254429697, '在线开发', 'dev', 'carbon:development', 3, '0', null, '0', '000000', null, null, '2025-07-13 18:39:51', 1, '2025-07-13 18:42:07'); - - - + sort int null comment '排序', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar(500) null comment '备注' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_general_ci COMMENT = '数据模型字段表'; +DROP TABLE IF EXISTS `knowledge_role`; -- ---------------------------- -- Table structure for knowledge_role -- ---------------------------- -DROP TABLE IF EXISTS `knowledge_role`; CREATE TABLE `knowledge_role` ( `id` bigint NOT NULL COMMENT '知识库角色id', `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库角色name', @@ -2664,10 +2596,10 @@ CREATE TABLE `knowledge_role` ( PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '知识库角色表' ROW_FORMAT = DYNAMIC; +DROP TABLE IF EXISTS `knowledge_role_group`; -- ---------------------------- -- Table structure for knowledge_role_group -- ---------------------------- -DROP TABLE IF EXISTS `knowledge_role_group`; CREATE TABLE `knowledge_role_group` ( `id` bigint NOT NULL COMMENT '知识库角色组id', `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库角色组name', 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 From 5db116ec882cd3e7137c5c064819bbe0033b5be0 Mon Sep 17 00:00:00 2001 From: fy53888 Date: Mon, 18 Aug 2025 22:03:51 +0800 Subject: [PATCH 19/33] =?UTF-8?q?=E5=A4=87=E5=88=86=E4=B8=80=E4=B8=8B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/StoreEmployeeController.java | 105 +++++++++++++++++ .../ruoyi/system/domain/StoreEmployee.java | 56 +++++++++ .../system/domain/bo/StoreEmployeeBo.java | 59 ++++++++++ .../system/domain/vo/StoreEmployeeVo.java | 59 ++++++++++ .../system/mapper/StoreEmployeeMapper.java | 17 +++ .../system/service/StoreEmployeeService.java | 48 ++++++++ .../impl/StoreEmployeeServiceImpl.java | 109 ++++++++++++++++++ .../ruoyi/system/sql/store_employee_menu.sql | 19 +++ .../mapper/system/StoreEmployeeMapper.xml | 7 ++ 9 files changed, 479 insertions(+) create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/StoreEmployeeController.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/StoreEmployee.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/StoreEmployeeBo.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/StoreEmployeeMapper.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/StoreEmployeeService.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/StoreEmployeeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/store_employee_menu.sql create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/StoreEmployeeMapper.xml diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/StoreEmployeeController.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/StoreEmployeeController.java new file mode 100644 index 00000000..6b59cb93 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/StoreEmployeeController.java @@ -0,0 +1,105 @@ +package org.ruoyi.system.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.ruoyi.common.idempotent.annotation.RepeatSubmit; +import org.ruoyi.common.log.annotation.Log; +import org.ruoyi.common.web.core.BaseController; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.common.core.domain.R; +import org.ruoyi.common.core.validate.AddGroup; +import org.ruoyi.common.core.validate.EditGroup; +import org.ruoyi.common.log.enums.BusinessType; +import org.ruoyi.common.excel.utils.ExcelUtil; +import org.ruoyi.system.domain.vo.StoreEmployeeVo; +import org.ruoyi.system.domain.bo.StoreEmployeeBo; +import org.ruoyi.system.service.StoreEmployeeService; +import org.ruoyi.core.page.TableDataInfo; + +/** + * 员工分配 + * + * @author ageerle + * @date Mon Aug 18 21:33:27 CST 2025 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/store/storeEmployee") +public class StoreEmployeeController extends BaseController { + + private final StoreEmployeeService storeEmployeeService; + +/** + * 查询员工分配列表 + */ +@SaCheckPermission("store:storeEmployee:list") +@GetMapping("/list") + public TableDataInfo list(StoreEmployeeBo bo, PageQuery pageQuery) { + return storeEmployeeService.queryPageList(bo, pageQuery); + } + + /** + * 导出员工分配列表 + */ + @SaCheckPermission("store:storeEmployee:export") + @Log(title = "员工分配", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(StoreEmployeeBo bo, HttpServletResponse response) { + List list = storeEmployeeService.queryList(bo); + ExcelUtil.exportExcel(list, "员工分配", StoreEmployeeVo.class, response); + } + + /** + * 获取员工分配详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("store:storeEmployee:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(storeEmployeeService.queryById(id)); + } + + /** + * 新增员工分配 + */ + @SaCheckPermission("store:storeEmployee:add") + @Log(title = "员工分配", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody StoreEmployeeBo bo) { + return toAjax(storeEmployeeService.insertByBo(bo)); + } + + /** + * 修改员工分配 + */ + @SaCheckPermission("store:storeEmployee:edit") + @Log(title = "员工分配", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody StoreEmployeeBo bo) { + return toAjax(storeEmployeeService.updateByBo(bo)); + } + + /** + * 删除员工分配 + * + * @param ids 主键串 + */ + @SaCheckPermission("store:storeEmployee:remove") + @Log(title = "员工分配", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(storeEmployeeService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/StoreEmployee.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/StoreEmployee.java new file mode 100644 index 00000000..dff96453 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/StoreEmployee.java @@ -0,0 +1,56 @@ +package org.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; +import java.io.Serializable; + +/** + * 员工分配对象 store_employee + * + * @author ageerle + * @date Mon Aug 18 21:33:27 CST 2025 + */ +@Data +@TableName("store_employee") +public class StoreEmployee implements Serializable { + + + /** + * 主键ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 门店ID + */ + private Long storeId; + + /** + * 员工ID + */ + private Long userId; + + /** + * 职位 + */ + private String roleInStore; + + /** + * 分配时间 + */ + private LocalDateTime assignTime; + + /** + * 门店类型 + */ + private String isPrimary; + + /** + * 分配到期时间 + */ + private LocalDateTime expireTime; + + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/StoreEmployeeBo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/StoreEmployeeBo.java new file mode 100644 index 00000000..40cdbd96 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/StoreEmployeeBo.java @@ -0,0 +1,59 @@ +package org.ruoyi.system.domain.bo; + +import org.ruoyi.system.domain.StoreEmployee; +import org.ruoyi.core.domain.BaseEntity; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.time.LocalDateTime; +import java.io.Serializable; +import org.ruoyi.common.core.validate.AddGroup; +import org.ruoyi.common.core.validate.EditGroup; +import java.io.Serializable; +import java.io.Serializable; +import org.ruoyi.common.core.validate.AddGroup; +import org.ruoyi.common.core.validate.EditGroup; + +/** + * 员工分配业务对象 store_employee + * + * @author ageerle + * @date Mon Aug 18 21:33:27 CST 2025 + */ +@Data + +@AutoMapper(target = StoreEmployee.class, reverseConvertGenerate = false) +public class StoreEmployeeBo implements Serializable { + + private Long id; + + /** + * 门店ID + */ + @NotNull(message = "门店ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long storeId; + /** + * 员工ID + */ + @NotNull(message = "员工ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long userId; + /** + * 职位 + */ + private String roleInStore; + /** + * 分配时间 + */ + @NotNull(message = "分配时间不能为空", groups = { AddGroup.class, EditGroup.class }) + private LocalDateTime assignTime; + /** + * 门店类型 + */ + private String isPrimary; + /** + * 分配到期时间 + */ + private LocalDateTime expireTime; + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java new file mode 100644 index 00000000..0b8b0248 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java @@ -0,0 +1,59 @@ +package org.ruoyi.system.domain.vo; + + import java.time.LocalDateTime; + import java.io.Serializable; +import org.ruoyi.system.domain.StoreEmployee; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.util.Date; + + +/** + * 员工分配视图对象 store_employee + * + * @author ageerle + * @date Mon Aug 18 21:33:27 CST 2025 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = StoreEmployee.class) +public class StoreEmployeeVo implements Serializable { + + private Long id; + /** + * 门店ID + */ + @ExcelProperty(value = "门店ID") + private Long storeId; + /** + * 员工ID + */ + @ExcelProperty(value = "员工ID") + private Long userId; + /** + * 职位 + */ + @ExcelProperty(value = "职位", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "title_name") + private String roleInStore; + /** + * 分配时间 + */ + @ExcelProperty(value = "分配时间") + private LocalDateTime assignTime; + /** + * 门店类型 + */ + @ExcelProperty(value = "门店类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "store_type") + private String isPrimary; + /** + * 分配到期时间 + */ + @ExcelProperty(value = "分配到期时间") + private LocalDateTime expireTime; + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/StoreEmployeeMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/StoreEmployeeMapper.java new file mode 100644 index 00000000..a73e581f --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/StoreEmployeeMapper.java @@ -0,0 +1,17 @@ +package org.ruoyi.system.mapper; + +import org.ruoyi.system.domain.StoreEmployee; +import org.ruoyi.system.domain.vo.StoreEmployeeVo; +import org.ruoyi.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Mapper; + +/** + * 员工分配Mapper接口 + * + * @author ageerle + * @date Mon Aug 18 21:33:27 CST 2025 + */ +@Mapper +public interface StoreEmployeeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/StoreEmployeeService.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/StoreEmployeeService.java new file mode 100644 index 00000000..5235c942 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/StoreEmployeeService.java @@ -0,0 +1,48 @@ +package org.ruoyi.system.service; + +import org.ruoyi.system.domain.vo.StoreEmployeeVo; +import org.ruoyi.system.domain.bo.StoreEmployeeBo; + import org.ruoyi.core.page.TableDataInfo; + import org.ruoyi.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 员工分配Service接口 + * + * @author ageerle + * @date Mon Aug 18 21:33:27 CST 2025 + */ +public interface StoreEmployeeService { + + /** + * 查询员工分配 + */ + StoreEmployeeVo queryById(Long id); + + /** + * 查询员工分配列表 + */ + TableDataInfo queryPageList(StoreEmployeeBo bo, PageQuery pageQuery); + + /** + * 查询员工分配列表 + */ + List queryList(StoreEmployeeBo bo); + + /** + * 新增员工分配 + */ + Boolean insertByBo(StoreEmployeeBo bo); + + /** + * 修改员工分配 + */ + Boolean updateByBo(StoreEmployeeBo bo); + + /** + * 校验并批量删除员工分配信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/StoreEmployeeServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/StoreEmployeeServiceImpl.java new file mode 100644 index 00000000..44b8ec86 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/StoreEmployeeServiceImpl.java @@ -0,0 +1,109 @@ +package org.ruoyi.system.service.impl; + +import org.ruoyi.common.core.utils.MapstructUtils; + import org.ruoyi.core.page.TableDataInfo; + import org.ruoyi.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 org.ruoyi.system.domain.bo.StoreEmployeeBo; +import org.ruoyi.system.domain.vo.StoreEmployeeVo; +import org.ruoyi.system.domain.StoreEmployee; +import org.ruoyi.system.mapper.StoreEmployeeMapper; +import org.ruoyi.system.service.StoreEmployeeService; +import org.ruoyi.common.core.utils.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 员工分配Service业务层处理 + * + * @author ageerle + * @date Mon Aug 18 21:33:27 CST 2025 + */ +@RequiredArgsConstructor +@Service +public class StoreEmployeeServiceImpl implements StoreEmployeeService { + + private final StoreEmployeeMapper baseMapper; + + /** + * 查询员工分配 + */ + @Override + public StoreEmployeeVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 查询员工分配列表 + */ + @Override + public TableDataInfo queryPageList(StoreEmployeeBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询员工分配列表 + */ + @Override + public List queryList(StoreEmployeeBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(StoreEmployeeBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getStoreId() != null, StoreEmployee::getStoreId, bo.getStoreId()); + lqw.eq(bo.getUserId() != null, StoreEmployee::getUserId, bo.getUserId()); + return lqw; + } + + /** + * 新增员工分配 + */ + @Override + public Boolean insertByBo(StoreEmployeeBo bo) { + StoreEmployee add = MapstructUtils.convert(bo, StoreEmployee. class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改员工分配 + */ + @Override + public Boolean updateByBo(StoreEmployeeBo bo) { + StoreEmployee update = MapstructUtils.convert(bo, StoreEmployee. class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(StoreEmployee entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除员工分配 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/store_employee_menu.sql b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/store_employee_menu.sql new file mode 100644 index 00000000..6277f1db --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/store_employee_menu.sql @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1957435675864506368, '员工分配', '2000', '1', 'storeEmployee', 'store/storeEmployee/index', 1, 0, 'C', '0', '0', 'store:storeEmployee:list', '#', 103, 1, sysdate(), null, null, '员工分配菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1957435675864506369, '员工分配查询', 1957435675864506368, '1', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1957435675864506370, '员工分配新增', 1957435675864506368, '2', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1957435675864506371, '员工分配修改', 1957435675864506368, '3', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1957435675864506372, '员工分配删除', 1957435675864506368, '4', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(1957435675864506373, '员工分配导出', 1957435675864506368, '5', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:export', '#', 103, 1, sysdate(), null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/StoreEmployeeMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/StoreEmployeeMapper.xml new file mode 100644 index 00000000..82d21190 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/StoreEmployeeMapper.xml @@ -0,0 +1,7 @@ + + + + + From 5b6605c345300274855a8dcef1188dd86f3edb82 Mon Sep 17 00:00:00 2001 From: fy53888 Date: Mon, 18 Aug 2025 22:04:15 +0800 Subject: [PATCH 20/33] =?UTF-8?q?=E5=A4=87=E5=88=86=E4=B8=80=E4=B8=8B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java index 0b8b0248..a9123c2e 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java @@ -2,7 +2,9 @@ package org.ruoyi.system.domain.vo; import java.time.LocalDateTime; import java.io.Serializable; -import org.ruoyi.system.domain.StoreEmployee; + import org.ruoyi.common.excel.annotation.ExcelDictFormat; + import org.ruoyi.common.excel.convert.ExcelDictConvert; + import org.ruoyi.system.domain.StoreEmployee; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; From 951ee6bd8ac7c430ab309918a1c2621a8eff7554 Mon Sep 17 00:00:00 2001 From: fy53888 Date: Tue, 19 Aug 2025 09:48:35 +0800 Subject: [PATCH 21/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AD=97=E5=85=B8?= =?UTF-8?q?=E4=B8=8B=E6=8B=89=E5=B8=A6=E6=9F=A5=E6=89=BE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/system/service/ISysDictTypeService.java | 9 +++++++++ .../system/service/impl/SysDictTypeServiceImpl.java | 13 +++++++++++++ .../controller/system/SysDictTypeController.java | 8 ++++++++ 3 files changed, 30 insertions(+) diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysDictTypeService.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysDictTypeService.java index fb94c017..7a420805 100644 --- a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysDictTypeService.java +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysDictTypeService.java @@ -16,6 +16,15 @@ import java.util.List; public interface ISysDictTypeService { + +/** + * Select all dictionary types based on the specified conditions + * + * @param dictType The business object containing query conditions for dictionary types + * @return TableDataInfo containing a list of SysDictTypeVo objects that match the query criteria + */ + TableDataInfo selectAll(SysDictTypeBo dictType); + TableDataInfo selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery); /** diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysDictTypeServiceImpl.java index 6797e200..518048a9 100644 --- a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysDictTypeServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysDictTypeServiceImpl.java @@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; import org.ruoyi.common.core.constant.CacheConstants; import org.ruoyi.common.core.constant.CacheNames; +import org.ruoyi.common.core.constant.HttpStatus; import org.ruoyi.common.core.exception.ServiceException; import org.ruoyi.common.core.service.DictService; import org.ruoyi.common.core.utils.MapstructUtils; @@ -50,6 +51,18 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService private final SysDictTypeMapper baseMapper; private final SysDictDataMapper dictDataMapper; + @Override + public TableDataInfo selectAll(SysDictTypeBo dictType) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictType); + // 2. 查询所有数据(不分页) + List list = baseMapper.selectVoList(lqw); + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.SUCCESS); // 200 + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(list.size()); // 总数为列表大小 + return rspData; + } @Override public TableDataInfo selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(dictType); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysDictTypeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysDictTypeController.java index 9a1a09ff..71dc63e6 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysDictTypeController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysDictTypeController.java @@ -31,6 +31,14 @@ public class SysDictTypeController extends BaseController { private final ISysDictTypeService dictTypeService; + /** + * 查询所有字典类型列表 + */ + + @GetMapping("/all") + public TableDataInfo all(SysDictTypeBo dictType, PageQuery pageQuery) { + return dictTypeService.selectAll(dictType); + } /** * 查询字典类型列表 */ From 07cb351807a09c499d659594bae0ea8d07a2958f Mon Sep 17 00:00:00 2001 From: likunlong Date: Tue, 19 Aug 2025 10:32:17 +0800 Subject: [PATCH 22/33] =?UTF-8?q?feat:=20=E6=A0=B9=E6=8D=AE=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E6=9C=89=E9=99=84=E4=BB=B6=E5=92=8C=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=EF=BC=8C=E8=87=AA=E5=8A=A8=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=B9=B6=E4=B8=94=E8=8E=B7=E5=8F=96=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/common/chat/request/ChatRequest.java | 10 ++++++++++ .../chat/service/chat/impl/SseServiceImpl.java | 15 ++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java index 20a021de..276f5dc8 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java @@ -67,4 +67,14 @@ public class ChatRequest { */ private Long uuid; + /** + * 是否有附件 + */ + private Boolean hasAttachment; + + /** + * 是否自动切换模型 + */ + private Boolean autoSelectModel; + } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java index e0d72866..6dfa302a 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java @@ -128,23 +128,20 @@ public class SseServiceImpl implements ISseService { */ private IChatService autoSelectModelAndGetService(ChatRequest chatRequest) { try { - // 处理特殊模型类型 - if ("gpt-image".equals(chatRequest.getModel())) { + if (Boolean.TRUE.equals(chatRequest.getHasAttachment())) { chatModelVo = selectModelByCategory("image"); - return chatServiceFactory.getChatService(chatModelVo.getCategory()); + } else if (Boolean.TRUE.equals(chatRequest.getAutoSelectModel())) { + chatModelVo = selectModelByCategory("chat"); + } else { + chatModelVo = chatModelService.selectModelByName(chatRequest.getModel()); } - // 根据模型名称获取模型分类,然后获取该分类下优先级最高的模型 - ChatModelVo tempModel = chatModelService.selectModelByName(chatRequest.getModel()); - if (tempModel == null) { + if (chatModelVo == null) { throw new IllegalStateException("未找到模型名称:" + chatRequest.getModel()); } - chatModelVo = selectModelByCategory(tempModel.getCategory()); - // 直接返回对应的聊天服务 return chatServiceFactory.getChatService(chatModelVo.getCategory()); - } catch (Exception e) { log.error("模型选择和服务获取失败: {}", e.getMessage(), e); throw new IllegalStateException("模型选择和服务获取失败: " + e.getMessage()); From 50d9e0e843837e14c7427f124064837803f0bb7e Mon Sep 17 00:00:00 2001 From: l90215 Date: Tue, 19 Aug 2025 12:43:34 +0800 Subject: [PATCH 23/33] =?UTF-8?q?feat:=20=E5=90=88=E5=B9=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20=E5=88=A0=E9=99=A4=E4=B8=8D=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 2 +- ruoyi-modules/ruoyi-generator/pom.xml | 4 - .../controller/StoreEmployeeController.java | 105 ----------------- .../ruoyi/system/domain/StoreEmployee.java | 56 --------- .../system/domain/bo/StoreEmployeeBo.java | 59 ---------- .../system/domain/vo/StoreEmployeeVo.java | 61 ---------- .../system/mapper/StoreEmployeeMapper.java | 17 --- .../system/service/StoreEmployeeService.java | 48 -------- .../impl/StoreEmployeeServiceImpl.java | 109 ------------------ .../ruoyi/system/sql/store_employee_menu.sql | 19 --- .../mapper/system/StoreEmployeeMapper.xml | 7 -- .../resources/mapper/system/SysDemoMapper.xml | 7 -- 12 files changed, 1 insertion(+), 493 deletions(-) delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/StoreEmployeeController.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/StoreEmployee.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/StoreEmployeeBo.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/StoreEmployeeMapper.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/StoreEmployeeService.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/StoreEmployeeServiceImpl.java delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/store_employee_menu.sql delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/StoreEmployeeMapper.xml delete mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/SysDemoMapper.xml diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 15ed79b8..8abf1a68 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -16,7 +16,7 @@ spring: master: type: ${spring.datasource.type} driverClassName: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/ruoyistore?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true + url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true username: root password: root diff --git a/ruoyi-modules/ruoyi-generator/pom.xml b/ruoyi-modules/ruoyi-generator/pom.xml index e545d91b..c6ab5e3c 100644 --- a/ruoyi-modules/ruoyi-generator/pom.xml +++ b/ruoyi-modules/ruoyi-generator/pom.xml @@ -48,10 +48,6 @@ org.apache.velocity velocity-engine-core - - org.ruoyi - ruoyi-common-excel - diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/StoreEmployeeController.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/StoreEmployeeController.java deleted file mode 100644 index 6b59cb93..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/controller/StoreEmployeeController.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.ruoyi.system.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.ruoyi.common.idempotent.annotation.RepeatSubmit; -import org.ruoyi.common.log.annotation.Log; -import org.ruoyi.common.web.core.BaseController; -import org.ruoyi.core.page.PageQuery; -import org.ruoyi.common.core.domain.R; -import org.ruoyi.common.core.validate.AddGroup; -import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.common.log.enums.BusinessType; -import org.ruoyi.common.excel.utils.ExcelUtil; -import org.ruoyi.system.domain.vo.StoreEmployeeVo; -import org.ruoyi.system.domain.bo.StoreEmployeeBo; -import org.ruoyi.system.service.StoreEmployeeService; -import org.ruoyi.core.page.TableDataInfo; - -/** - * 员工分配 - * - * @author ageerle - * @date Mon Aug 18 21:33:27 CST 2025 - */ -@Validated -@RequiredArgsConstructor -@RestController -@RequestMapping("/store/storeEmployee") -public class StoreEmployeeController extends BaseController { - - private final StoreEmployeeService storeEmployeeService; - -/** - * 查询员工分配列表 - */ -@SaCheckPermission("store:storeEmployee:list") -@GetMapping("/list") - public TableDataInfo list(StoreEmployeeBo bo, PageQuery pageQuery) { - return storeEmployeeService.queryPageList(bo, pageQuery); - } - - /** - * 导出员工分配列表 - */ - @SaCheckPermission("store:storeEmployee:export") - @Log(title = "员工分配", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(StoreEmployeeBo bo, HttpServletResponse response) { - List list = storeEmployeeService.queryList(bo); - ExcelUtil.exportExcel(list, "员工分配", StoreEmployeeVo.class, response); - } - - /** - * 获取员工分配详细信息 - * - * @param id 主键 - */ - @SaCheckPermission("store:storeEmployee:query") - @GetMapping("/{id}") - public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { - return R.ok(storeEmployeeService.queryById(id)); - } - - /** - * 新增员工分配 - */ - @SaCheckPermission("store:storeEmployee:add") - @Log(title = "员工分配", businessType = BusinessType.INSERT) - @RepeatSubmit() - @PostMapping() - public R add(@Validated(AddGroup.class) @RequestBody StoreEmployeeBo bo) { - return toAjax(storeEmployeeService.insertByBo(bo)); - } - - /** - * 修改员工分配 - */ - @SaCheckPermission("store:storeEmployee:edit") - @Log(title = "员工分配", businessType = BusinessType.UPDATE) - @RepeatSubmit() - @PutMapping() - public R edit(@Validated(EditGroup.class) @RequestBody StoreEmployeeBo bo) { - return toAjax(storeEmployeeService.updateByBo(bo)); - } - - /** - * 删除员工分配 - * - * @param ids 主键串 - */ - @SaCheckPermission("store:storeEmployee:remove") - @Log(title = "员工分配", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Long[] ids) { - return toAjax(storeEmployeeService.deleteWithValidByIds(List.of(ids), true)); - } -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/StoreEmployee.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/StoreEmployee.java deleted file mode 100644 index dff96453..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/StoreEmployee.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.ruoyi.system.domain; - -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import java.time.LocalDateTime; -import java.io.Serializable; - -/** - * 员工分配对象 store_employee - * - * @author ageerle - * @date Mon Aug 18 21:33:27 CST 2025 - */ -@Data -@TableName("store_employee") -public class StoreEmployee implements Serializable { - - - /** - * 主键ID - */ - @TableId(value = "id", type = IdType.AUTO) - private Long id; - - /** - * 门店ID - */ - private Long storeId; - - /** - * 员工ID - */ - private Long userId; - - /** - * 职位 - */ - private String roleInStore; - - /** - * 分配时间 - */ - private LocalDateTime assignTime; - - /** - * 门店类型 - */ - private String isPrimary; - - /** - * 分配到期时间 - */ - private LocalDateTime expireTime; - - -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/StoreEmployeeBo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/StoreEmployeeBo.java deleted file mode 100644 index 40cdbd96..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/bo/StoreEmployeeBo.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.ruoyi.system.domain.bo; - -import org.ruoyi.system.domain.StoreEmployee; -import org.ruoyi.core.domain.BaseEntity; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; -import lombok.EqualsAndHashCode; -import jakarta.validation.constraints.*; -import java.time.LocalDateTime; -import java.io.Serializable; -import org.ruoyi.common.core.validate.AddGroup; -import org.ruoyi.common.core.validate.EditGroup; -import java.io.Serializable; -import java.io.Serializable; -import org.ruoyi.common.core.validate.AddGroup; -import org.ruoyi.common.core.validate.EditGroup; - -/** - * 员工分配业务对象 store_employee - * - * @author ageerle - * @date Mon Aug 18 21:33:27 CST 2025 - */ -@Data - -@AutoMapper(target = StoreEmployee.class, reverseConvertGenerate = false) -public class StoreEmployeeBo implements Serializable { - - private Long id; - - /** - * 门店ID - */ - @NotNull(message = "门店ID不能为空", groups = { AddGroup.class, EditGroup.class }) - private Long storeId; - /** - * 员工ID - */ - @NotNull(message = "员工ID不能为空", groups = { AddGroup.class, EditGroup.class }) - private Long userId; - /** - * 职位 - */ - private String roleInStore; - /** - * 分配时间 - */ - @NotNull(message = "分配时间不能为空", groups = { AddGroup.class, EditGroup.class }) - private LocalDateTime assignTime; - /** - * 门店类型 - */ - private String isPrimary; - /** - * 分配到期时间 - */ - private LocalDateTime expireTime; - -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java deleted file mode 100644 index a9123c2e..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/domain/vo/StoreEmployeeVo.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.ruoyi.system.domain.vo; - - import java.time.LocalDateTime; - import java.io.Serializable; - import org.ruoyi.common.excel.annotation.ExcelDictFormat; - import org.ruoyi.common.excel.convert.ExcelDictConvert; - import org.ruoyi.system.domain.StoreEmployee; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; - -import java.util.Date; - - -/** - * 员工分配视图对象 store_employee - * - * @author ageerle - * @date Mon Aug 18 21:33:27 CST 2025 - */ -@Data -@ExcelIgnoreUnannotated -@AutoMapper(target = StoreEmployee.class) -public class StoreEmployeeVo implements Serializable { - - private Long id; - /** - * 门店ID - */ - @ExcelProperty(value = "门店ID") - private Long storeId; - /** - * 员工ID - */ - @ExcelProperty(value = "员工ID") - private Long userId; - /** - * 职位 - */ - @ExcelProperty(value = "职位", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "title_name") - private String roleInStore; - /** - * 分配时间 - */ - @ExcelProperty(value = "分配时间") - private LocalDateTime assignTime; - /** - * 门店类型 - */ - @ExcelProperty(value = "门店类型", converter = ExcelDictConvert.class) - @ExcelDictFormat(dictType = "store_type") - private String isPrimary; - /** - * 分配到期时间 - */ - @ExcelProperty(value = "分配到期时间") - private LocalDateTime expireTime; - -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/StoreEmployeeMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/StoreEmployeeMapper.java deleted file mode 100644 index a73e581f..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/mapper/StoreEmployeeMapper.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.ruoyi.system.mapper; - -import org.ruoyi.system.domain.StoreEmployee; -import org.ruoyi.system.domain.vo.StoreEmployeeVo; -import org.ruoyi.core.mapper.BaseMapperPlus; -import org.apache.ibatis.annotations.Mapper; - -/** - * 员工分配Mapper接口 - * - * @author ageerle - * @date Mon Aug 18 21:33:27 CST 2025 - */ -@Mapper -public interface StoreEmployeeMapper extends BaseMapperPlus { - -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/StoreEmployeeService.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/StoreEmployeeService.java deleted file mode 100644 index 5235c942..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/StoreEmployeeService.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.ruoyi.system.service; - -import org.ruoyi.system.domain.vo.StoreEmployeeVo; -import org.ruoyi.system.domain.bo.StoreEmployeeBo; - import org.ruoyi.core.page.TableDataInfo; - import org.ruoyi.core.page.PageQuery; - -import java.util.Collection; -import java.util.List; - -/** - * 员工分配Service接口 - * - * @author ageerle - * @date Mon Aug 18 21:33:27 CST 2025 - */ -public interface StoreEmployeeService { - - /** - * 查询员工分配 - */ - StoreEmployeeVo queryById(Long id); - - /** - * 查询员工分配列表 - */ - TableDataInfo queryPageList(StoreEmployeeBo bo, PageQuery pageQuery); - - /** - * 查询员工分配列表 - */ - List queryList(StoreEmployeeBo bo); - - /** - * 新增员工分配 - */ - Boolean insertByBo(StoreEmployeeBo bo); - - /** - * 修改员工分配 - */ - Boolean updateByBo(StoreEmployeeBo bo); - - /** - * 校验并批量删除员工分配信息 - */ - Boolean deleteWithValidByIds(Collection ids, Boolean isValid); -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/StoreEmployeeServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/StoreEmployeeServiceImpl.java deleted file mode 100644 index 44b8ec86..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/service/impl/StoreEmployeeServiceImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.ruoyi.system.service.impl; - -import org.ruoyi.common.core.utils.MapstructUtils; - import org.ruoyi.core.page.TableDataInfo; - import org.ruoyi.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 org.ruoyi.system.domain.bo.StoreEmployeeBo; -import org.ruoyi.system.domain.vo.StoreEmployeeVo; -import org.ruoyi.system.domain.StoreEmployee; -import org.ruoyi.system.mapper.StoreEmployeeMapper; -import org.ruoyi.system.service.StoreEmployeeService; -import org.ruoyi.common.core.utils.StringUtils; - -import java.util.List; -import java.util.Map; -import java.util.Collection; - -/** - * 员工分配Service业务层处理 - * - * @author ageerle - * @date Mon Aug 18 21:33:27 CST 2025 - */ -@RequiredArgsConstructor -@Service -public class StoreEmployeeServiceImpl implements StoreEmployeeService { - - private final StoreEmployeeMapper baseMapper; - - /** - * 查询员工分配 - */ - @Override - public StoreEmployeeVo queryById(Long id) { - return baseMapper.selectVoById(id); - } - - /** - * 查询员工分配列表 - */ - @Override - public TableDataInfo queryPageList(StoreEmployeeBo bo, PageQuery pageQuery) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); - return TableDataInfo.build(result); - } - - /** - * 查询员工分配列表 - */ - @Override - public List queryList(StoreEmployeeBo bo) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - return baseMapper.selectVoList(lqw); - } - - private LambdaQueryWrapper buildQueryWrapper(StoreEmployeeBo bo) { - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(bo.getStoreId() != null, StoreEmployee::getStoreId, bo.getStoreId()); - lqw.eq(bo.getUserId() != null, StoreEmployee::getUserId, bo.getUserId()); - return lqw; - } - - /** - * 新增员工分配 - */ - @Override - public Boolean insertByBo(StoreEmployeeBo bo) { - StoreEmployee add = MapstructUtils.convert(bo, StoreEmployee. class); - validEntityBeforeSave(add); - boolean flag = baseMapper.insert(add) > 0; - if (flag) { - bo.setId(add.getId()); - } - return flag; - } - - /** - * 修改员工分配 - */ - @Override - public Boolean updateByBo(StoreEmployeeBo bo) { - StoreEmployee update = MapstructUtils.convert(bo, StoreEmployee. class); - validEntityBeforeSave(update); - return baseMapper.updateById(update) > 0; - } - - /** - * 保存前的数据校验 - */ - private void validEntityBeforeSave(StoreEmployee entity) { - //TODO 做一些数据校验,如唯一约束 - } - - /** - * 批量删除员工分配 - */ - @Override - public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if (isValid) { - //TODO 做一些业务上的校验,判断是否需要校验 - } - return baseMapper.deleteBatchIds(ids) > 0; - } -} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/store_employee_menu.sql b/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/store_employee_menu.sql deleted file mode 100644 index 6277f1db..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/system/sql/store_employee_menu.sql +++ /dev/null @@ -1,19 +0,0 @@ --- 菜单 SQL -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1957435675864506368, '员工分配', '2000', '1', 'storeEmployee', 'store/storeEmployee/index', 1, 0, 'C', '0', '0', 'store:storeEmployee:list', '#', 103, 1, sysdate(), null, null, '员工分配菜单'); - --- 按钮 SQL -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1957435675864506369, '员工分配查询', 1957435675864506368, '1', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:query', '#', 103, 1, sysdate(), null, null, ''); - -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1957435675864506370, '员工分配新增', 1957435675864506368, '2', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:add', '#', 103, 1, sysdate(), null, null, ''); - -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1957435675864506371, '员工分配修改', 1957435675864506368, '3', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:edit', '#', 103, 1, sysdate(), null, null, ''); - -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1957435675864506372, '员工分配删除', 1957435675864506368, '4', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:remove', '#', 103, 1, sysdate(), null, null, ''); - -insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) -values(1957435675864506373, '员工分配导出', 1957435675864506368, '5', '#', '', 1, 0, 'F', '0', '0', 'store:storeEmployee:export', '#', 103, 1, sysdate(), null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/StoreEmployeeMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/StoreEmployeeMapper.xml deleted file mode 100644 index 82d21190..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/StoreEmployeeMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/SysDemoMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/SysDemoMapper.xml deleted file mode 100644 index c35ba06c..00000000 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/system/SysDemoMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - From 119483df86f82c82bd3150aa87b737365be87b3e Mon Sep 17 00:00:00 2001 From: likunlong Date: Tue, 19 Aug 2025 15:12:24 +0800 Subject: [PATCH 24/33] =?UTF-8?q?feat:=20=E8=87=AA=E5=8A=A8=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E8=AF=B7=E6=B1=82=E5=8F=82=E6=95=B0=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=90=8D=E7=A7=B0=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java index 6dfa302a..49035da7 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java @@ -139,7 +139,8 @@ public class SseServiceImpl implements ISseService { if (chatModelVo == null) { throw new IllegalStateException("未找到模型名称:" + chatRequest.getModel()); } - + // 自动设置请求参数中的模型名称 + chatRequest.setModel(chatModelVo.getModelName()); // 直接返回对应的聊天服务 return chatServiceFactory.getChatService(chatModelVo.getCategory()); } catch (Exception e) { From 4434d8346ca80262971bb71bc4baa7944ca42187 Mon Sep 17 00:00:00 2001 From: likunlong Date: Tue, 19 Aug 2025 16:46:25 +0800 Subject: [PATCH 25/33] =?UTF-8?q?feat:=20=E9=97=AE=E7=AD=94=E6=97=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BB=9F=E4=B8=80=E9=87=8D=E8=AF=95=E5=92=8C?= =?UTF-8?q?=E9=99=8D=E7=BA=A7=E9=80=BB=E8=BE=91=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/ruoyi/domain/vo/ChatModelVo.java | 6 + .../org/ruoyi/service/IChatModelService.java | 5 + .../service/impl/ChatModelServiceImpl.java | 14 +++ .../chat/listener/SSEEventSourceListener.java | 17 ++- .../service/chat/impl/DeepSeekChatImpl.java | 5 + .../service/chat/impl/OpenAIServiceImpl.java | 9 +- .../service/chat/impl/SseServiceImpl.java | 32 ++++- .../ruoyi/chat/support/ChatRetryHelper.java | 115 ++++++++++++++++++ .../org/ruoyi/chat/support/RetryNotifier.java | 39 ++++++ .../java/org/ruoyi/chat/util/SSEUtil.java | 2 +- 10 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/ChatRetryHelper.java create mode 100644 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java 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..256d8d4d 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 @@ -90,6 +90,12 @@ public class ChatModelVo implements Serializable { @ExcelProperty(value = "密钥") private String apiKey; + /** + * 优先级(值越大优先级越高) + */ + @ExcelProperty(value = "优先级") + private Integer priority; + /** * 备注 */ diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java index d93b527e..9e90e46b 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java @@ -63,6 +63,11 @@ public interface IChatModelService { */ ChatModelVo selectModelByCategoryWithHighestPriority(String category); + /** + * 在同一分类下,查找优先级小于当前优先级的最高优先级模型(用于降级)。 + */ + ChatModelVo selectFallbackModelByCategoryAndLessPriority(String category, Integer currentPriority); + /** * 获取ppt模型信息 */ diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java index b7acfaa9..069d75a6 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java @@ -150,6 +150,20 @@ public class ChatModelServiceImpl implements IChatModelService { ); } + /** + * 在同一分类下,查找优先级小于当前优先级的最高优先级模型(用于降级)。 + */ + @Override + public ChatModelVo selectFallbackModelByCategoryAndLessPriority(String category, Integer currentPriority) { + return baseMapper.selectVoOne( + Wrappers.lambdaQuery() + .eq(ChatModel::getCategory, category) + .lt(ChatModel::getPriority, currentPriority) + .orderByDesc(ChatModel::getPriority) + .last("LIMIT 1") + ); + } + @Override public ChatModel getPPT() { return baseMapper.selectOne(Wrappers.lambdaQuery().eq(ChatModel::getModelName, "ppt")); diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java index c91e28de..20adc22b 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java @@ -21,6 +21,8 @@ import org.ruoyi.common.core.utils.SpringUtils; import org.ruoyi.common.core.utils.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.ruoyi.chat.util.SSEUtil; +import org.ruoyi.chat.support.RetryNotifier; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.Objects; @@ -77,6 +79,8 @@ public class SSEEventSourceListener extends EventSourceListener { if ("[DONE]".equals(data)) { //成功响应 emitter.complete(); + // 清理失败回调 + RetryNotifier.clear(sessionId); // 扣除费用 ChatRequest chatRequest = new ChatRequest(); // 设置对话角色 @@ -113,20 +117,31 @@ public class SSEEventSourceListener extends EventSourceListener { @Override public void onClosed(EventSource eventSource) { log.info("OpenAI关闭sse连接..."); + // 清理失败回调 + RetryNotifier.clear(sessionId); } @SneakyThrows @Override public void onFailure(EventSource eventSource, Throwable t, Response response) { if (Objects.isNull(response)) { + // 透传错误到前端 + SSEUtil.sendErrorEvent(emitter, t != null ? t.getMessage() : "SSE连接失败"); + // 通知重试 + RetryNotifier.notifyFailure(sessionId); return; } ResponseBody body = response.body(); if (Objects.nonNull(body)) { - log.error("OpenAI sse连接异常data:{},异常:{}", body.string(), t); + String msg = body.string(); + log.error("OpenAI sse连接异常data:{},异常:{}", msg, t); + SSEUtil.sendErrorEvent(emitter, msg); } else { log.error("OpenAI sse连接异常data:{},异常:{}", response, t); + SSEUtil.sendErrorEvent(emitter, String.valueOf(response)); } + // 通知重试 + RetryNotifier.notifyFailure(sessionId); eventSource.cancel(); } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java index 9e59fdd7..f0ddd77b 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java @@ -16,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import org.ruoyi.chat.support.RetryNotifier; /** * deepseek */ @@ -57,11 +58,15 @@ public class DeepSeekChatImpl implements IChatService { @Override public void onError(Throwable error) { System.err.println("错误: " + error.getMessage()); + // 通知上层失败,进入重试/降级 + RetryNotifier.notifyFailure(chatRequest.getSessionId()); } }); } catch (Exception e) { log.error("deepseek请求失败:{}", e.getMessage()); + // 同步异常直接通知失败 + RetryNotifier.notifyFailure(chatRequest.getSessionId()); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java index 50693617..b46fa03d 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java @@ -22,6 +22,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.List; +import org.ruoyi.chat.support.RetryNotifier; /** @@ -65,7 +66,13 @@ public class OpenAIServiceImpl implements IChatService { .model(chatRequest.getModel()) .stream(true) .build(); - openAiStreamClient.streamChatCompletion(completion, listener); + try { + openAiStreamClient.streamChatCompletion(completion, listener); + } catch (Exception ex) { + // 同步异常也触发失败回调,按会话维度 + RetryNotifier.notifyFailure(chatRequest.getSessionId()); + throw ex; + } return emitter; } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java index 49035da7..40bd9929 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java @@ -9,6 +9,8 @@ import org.ruoyi.chat.factory.ChatServiceFactory; import org.ruoyi.chat.service.chat.IChatCostService; import org.ruoyi.chat.service.chat.IChatService; import org.ruoyi.chat.service.chat.ISseService; +import org.ruoyi.chat.support.ChatRetryHelper; +import org.ruoyi.chat.support.RetryNotifier; import org.ruoyi.chat.util.SSEUtil; import org.ruoyi.common.chat.entity.Tts.TextToSpeech; import org.ruoyi.common.chat.entity.chat.Message; @@ -115,7 +117,27 @@ public class SseServiceImpl implements ISseService { } // 自动选择模型并获取对应的聊天服务 IChatService chatService = autoSelectModelAndGetService(chatRequest); - chatService.chat(chatRequest, sseEmitter); + + // 统一重试与降级:封装启动逻辑,并通过ThreadLocal传递失败回调 + ChatModelVo currentModel = this.chatModelVo; + String currentCategory = currentModel.getCategory(); + ChatRetryHelper.executeWithRetry( + currentModel, + currentCategory, + chatModelService, + sseEmitter, + (modelForTry, onFailure) -> { + // 替换请求中的模型名称 + chatRequest.setModel(modelForTry.getModelName()); + // 将回调注册到ThreadLocal,供底层SSE失败时触发 + RetryNotifier.setFailureCallback(chatRequest.getSessionId(), onFailure); + try { + autoSelectServiceByCategoryAndInvoke(chatRequest, sseEmitter, modelForTry.getCategory()); + } finally { + // 不在此处清理,待下游结束/失败时清理 + } + } + ); } catch (Exception e) { log.error(e.getMessage(),e); SSEUtil.sendErrorEvent(sseEmitter,e.getMessage()); @@ -148,6 +170,14 @@ public class SseServiceImpl implements ISseService { throw new IllegalStateException("模型选择和服务获取失败: " + e.getMessage()); } } + + /** + * 根据给定分类获取服务并发起调用(避免在降级时重复选择模型) + */ + private void autoSelectServiceByCategoryAndInvoke(ChatRequest chatRequest, SseEmitter sseEmitter, String category) { + IChatService service = chatServiceFactory.getChatService(category); + service.chat(chatRequest, sseEmitter); + } /** * 根据分类选择优先级最高的模型 diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/ChatRetryHelper.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/ChatRetryHelper.java new file mode 100644 index 00000000..bf4a4a74 --- /dev/null +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/ChatRetryHelper.java @@ -0,0 +1,115 @@ +package org.ruoyi.chat.support; + +import lombok.extern.slf4j.Slf4j; +import org.ruoyi.chat.util.SSEUtil; +import org.ruoyi.domain.vo.ChatModelVo; +import org.ruoyi.service.IChatModelService; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; + +/** + * 统一的聊天重试与降级调度器。 + * + * 策略: + * - 当前模型最多重试 3 次;仍失败则降级到同分类内、优先级小于当前的最高优先级模型。 + * - 降级模型同样最多重试 3 次;仍失败则向前端返回失败信息并停止。 + * + * 注意:实现依赖调用方在底层异步失败时执行 onFailure.run() 通知本调度器。 + */ +@Slf4j +public class ChatRetryHelper { + + public interface AttemptStarter { + void start(ChatModelVo model, Runnable onFailure) throws Exception; + } + + public static void executeWithRetry( + ChatModelVo primaryModel, + String category, + IChatModelService chatModelService, + SseEmitter emitter, + AttemptStarter attemptStarter + ) { + Objects.requireNonNull(primaryModel, "primaryModel must not be null"); + Objects.requireNonNull(category, "category must not be null"); + Objects.requireNonNull(chatModelService, "chatModelService must not be null"); + Objects.requireNonNull(emitter, "emitter must not be null"); + Objects.requireNonNull(attemptStarter, "attemptStarter must not be null"); + + AtomicInteger mainAttempts = new AtomicInteger(0); + AtomicInteger fallbackAttempts = new AtomicInteger(0); + AtomicBoolean inFallback = new AtomicBoolean(false); + AtomicBoolean scheduling = new AtomicBoolean(false); + + class Scheduler { + volatile ChatModelVo current = primaryModel; + volatile ChatModelVo fallback = null; + + void startAttempt() { + try { + if (!inFallback.get()) { + if (mainAttempts.incrementAndGet() > 3) { + // 进入降级 + inFallback.set(true); + if (fallback == null) { + Integer curPriority = primaryModel.getPriority(); + if (curPriority == null) { + curPriority = Integer.MAX_VALUE; + } + fallback = chatModelService.selectFallbackModelByCategoryAndLessPriority(category, curPriority); + } + if (fallback == null) { + SSEUtil.sendErrorEvent(emitter, "当前模型重试3次均失败,且无可用降级模型"); + emitter.complete(); + return; + } + current = fallback; + mainAttempts.set(3); // 锁定 + fallbackAttempts.set(0); + } + } else { + if (fallbackAttempts.incrementAndGet() > 3) { + SSEUtil.sendErrorEvent(emitter, "降级模型重试3次仍失败"); + emitter.complete(); + return; + } + } + + Runnable onFailure = () -> { + // 去抖:避免同一次失败触发多次重试 + if (scheduling.compareAndSet(false, true)) { + try { + SSEUtil.sendErrorEvent(emitter, (inFallback.get() ? "降级模型" : "当前模型") + "调用失败,准备重试..."); + // 立即发起下一次尝试 + startAttempt(); + } finally { + scheduling.set(false); + } + } + }; + + attemptStarter.start(current, onFailure); + } catch (Exception ex) { + log.error("启动聊天尝试失败: {}", ex.getMessage(), ex); + SSEUtil.sendErrorEvent(emitter, "启动聊天尝试失败: " + ex.getMessage()); + // 直接按失败处理,继续重试/降级 + if (scheduling.compareAndSet(false, true)) { + try { + startAttempt(); + } finally { + scheduling.set(false); + } + } + } + } + } + + new Scheduler().startAttempt(); + } +} + + diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java new file mode 100644 index 00000000..77044081 --- /dev/null +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java @@ -0,0 +1,39 @@ +package org.ruoyi.chat.support; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 失败回调通知器:基于 sessionId 绑定回调,底层失败时按 sessionId 通知上层重试调度器。 + */ +public class RetryNotifier { + + private static final Map FAILURE_CALLBACKS = new ConcurrentHashMap<>(); + + public static void setFailureCallback(Long sessionId, Runnable callback) { + if (sessionId == null || callback == null) { + return; + } + FAILURE_CALLBACKS.put(sessionId, callback); + } + + public static void clear(Long sessionId) { + if (sessionId == null) { + return; + } + FAILURE_CALLBACKS.remove(sessionId); + } + + public static void notifyFailure(Long sessionId) { + if (sessionId == null) { + return; + } + Runnable cb = FAILURE_CALLBACKS.get(sessionId); + if (Objects.nonNull(cb)) { + cb.run(); + } + } +} + + diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/SSEUtil.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/SSEUtil.java index 9bfb6bf0..293e486e 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/SSEUtil.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/SSEUtil.java @@ -25,6 +25,6 @@ public class SSEUtil { } catch (IOException e) { log.error("SSE发送失败: {}", e.getMessage()); } - sseEmitter.complete(); + // 不立即关闭,由上层策略决定是否继续重试或降级 } } From 1638b9dd75bfc15a6d860c67c7a75748d75aac8d Mon Sep 17 00:00:00 2001 From: likunlong Date: Tue, 19 Aug 2025 16:51:51 +0800 Subject: [PATCH 26/33] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E7=9B=AE?= =?UTF-8?q?=E5=89=8D=E5=AE=9E=E7=8E=B0=E7=B1=BB=E4=BD=BF=E7=94=A8=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E9=87=8D=E8=AF=95=E9=99=8D=E7=BA=A7=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FastGPTSSEEventSourceListener.java | 26 +++++++++++++++- .../service/chat/impl/CozeServiceImpl.java | 31 ++++++++++++------- .../service/chat/impl/DifyServiceImpl.java | 5 +++ .../service/chat/impl/FastGPTServiceImpl.java | 9 ++++-- .../service/chat/impl/OllamaServiceImpl.java | 4 +++ .../chat/impl/QianWenAiChatServiceImpl.java | 3 ++ .../chat/impl/ZhipuAiChatServiceImpl.java | 5 ++- 7 files changed, 67 insertions(+), 16 deletions(-) diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/FastGPTSSEEventSourceListener.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/FastGPTSSEEventSourceListener.java index 0d58176d..dd8519f2 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/FastGPTSSEEventSourceListener.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/FastGPTSSEEventSourceListener.java @@ -14,6 +14,8 @@ import org.springframework.stereotype.Component; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.Objects; +import org.ruoyi.chat.support.RetryNotifier; +import org.ruoyi.chat.util.SSEUtil; @Slf4j @Component @@ -21,12 +23,18 @@ import java.util.Objects; public class FastGPTSSEEventSourceListener extends EventSourceListener { private SseEmitter emitter; + private Long sessionId; @Autowired(required = false) public FastGPTSSEEventSourceListener(SseEmitter emitter) { this.emitter = emitter; } + public FastGPTSSEEventSourceListener(SseEmitter emitter, Long sessionId) { + this.emitter = emitter; + this.sessionId = sessionId; + } + @Override public void onOpen(EventSource eventSource, Response response) { log.info("FastGPT sse连接成功"); @@ -40,6 +48,9 @@ public class FastGPTSSEEventSourceListener extends EventSourceListener { if ("flowResponses".equals(type)){ emitter.send(data); emitter.complete(); + if (sessionId != null) { + RetryNotifier.clear(sessionId); + } } else { emitter.send(data); } @@ -57,13 +68,26 @@ public class FastGPTSSEEventSourceListener extends EventSourceListener { @SneakyThrows public void onFailure(EventSource eventSource, Throwable t, Response response) { if (Objects.isNull(response)) { + if (sessionId != null) { + SSEUtil.sendErrorEvent(emitter, t != null ? t.getMessage() : "SSE连接失败"); + RetryNotifier.notifyFailure(sessionId); + } return; } ResponseBody body = response.body(); if (Objects.nonNull(body)) { - log.error("FastGPT sse连接异常data:{},异常:{}", body.string(), t); + String msg = body.string(); + log.error("FastGPT sse连接异常data:{},异常:{}", msg, t); + if (sessionId != null) { + SSEUtil.sendErrorEvent(emitter, msg); + RetryNotifier.notifyFailure(sessionId); + } } else { log.error("FastGPT sse连接异常data:{},异常:{}", response, t); + if (sessionId != null) { + SSEUtil.sendErrorEvent(emitter, String.valueOf(response)); + RetryNotifier.notifyFailure(sessionId); + } } eventSource.cancel(); } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java index 7cbb5927..54269b08 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java @@ -20,6 +20,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.Collections; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.ruoyi.chat.support.RetryNotifier; /** * 扣子聊天管理 @@ -53,19 +54,25 @@ public class CozeServiceImpl implements IChatService { Flowable resp = coze.chat().stream(req); ExecutorService executor = Executors.newFixedThreadPool(10); executor.submit(() -> { - resp.blockingForEach( - event -> { - if (ChatEventType.CONVERSATION_MESSAGE_DELTA.equals(event.getEvent())) { - emitter.send(event.getMessage().getContent()); - log.info("coze: {}", event.getMessage().getContent()); + try { + resp.blockingForEach( + event -> { + if (ChatEventType.CONVERSATION_MESSAGE_DELTA.equals(event.getEvent())) { + emitter.send(event.getMessage().getContent()); + log.info("coze: {}", event.getMessage().getContent()); + } + if (ChatEventType.CONVERSATION_CHAT_COMPLETED.equals(event.getEvent())) { + emitter.complete(); + log.info("Token usage: {}", event.getChat().getUsage().getTokenCount()); + RetryNotifier.clear(chatRequest.getSessionId()); + } } - if (ChatEventType.CONVERSATION_CHAT_COMPLETED.equals(event.getEvent())) { - emitter.complete(); - log.info("Token usage: {}", event.getChat().getUsage().getTokenCount()); - } - } - ); - coze.shutdownExecutor(); + ); + } catch (Exception ex) { + RetryNotifier.notifyFailure(chatRequest.getSessionId()); + } finally { + coze.shutdownExecutor(); + } }); diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java index ac3ebab7..748d89c0 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java @@ -27,6 +27,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.Objects; +import org.ruoyi.chat.support.RetryNotifier; /** * dify 聊天管理 @@ -112,20 +113,24 @@ public class DifyServiceImpl implements IChatService { chatRequestResponse.setSessionId(chatRequest.getSessionId()); chatRequestResponse.setPrompt(respMessage.toString()); chatCostService.deductToken(chatRequestResponse); + RetryNotifier.clear(chatRequest.getSessionId()); } @Override public void onError(ErrorEvent event) { System.err.println("错误: " + event.getMessage()); + RetryNotifier.notifyFailure(chatRequest.getSessionId()); } @Override public void onException(Throwable throwable) { System.err.println("异常: " + throwable.getMessage()); + RetryNotifier.notifyFailure(chatRequest.getSessionId()); } }); } catch (Exception e) { log.error("dify请求失败:{}", e.getMessage()); + RetryNotifier.notifyFailure(chatRequest.getSessionId()); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/FastGPTServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/FastGPTServiceImpl.java index 15acf6f2..b3f41431 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/FastGPTServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/FastGPTServiceImpl.java @@ -33,7 +33,7 @@ public class FastGPTServiceImpl implements IChatService { ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel()); OpenAiStreamClient openAiStreamClient = ChatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey()); List messages = chatRequest.getMessages(); - FastGPTSSEEventSourceListener listener = new FastGPTSSEEventSourceListener(emitter); + FastGPTSSEEventSourceListener listener = new FastGPTSSEEventSourceListener(emitter, chatRequest.getSessionId()); FastGPTChatCompletion completion = FastGPTChatCompletion .builder() .messages(messages) @@ -41,7 +41,12 @@ public class FastGPTServiceImpl implements IChatService { .detail(true) .stream(true) .build(); - openAiStreamClient.streamChatCompletion(completion, listener); + try { + openAiStreamClient.streamChatCompletion(completion, listener); + } catch (Exception ex) { + org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); + throw ex; + } return emitter; } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java index 532b052e..669f1c2f 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; +import org.ruoyi.chat.support.RetryNotifier; /** @@ -66,12 +67,15 @@ public class OllamaServiceImpl implements IChatService { emitter.send(substr); } catch (IOException e) { SSEUtil.sendErrorEvent(emitter, e.getMessage()); + RetryNotifier.notifyFailure(chatRequest.getSessionId()); } }; api.chat(requestModel, streamHandler); emitter.complete(); + RetryNotifier.clear(chatRequest.getSessionId()); } catch (Exception e) { SSEUtil.sendErrorEvent(emitter, e.getMessage()); + RetryNotifier.notifyFailure(chatRequest.getSessionId()); } }); diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java index 850ebf6c..8462529c 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java @@ -51,15 +51,18 @@ public class QianWenAiChatServiceImpl implements IChatService { public void onCompleteResponse(ChatResponse completeResponse) { emitter.complete(); log.info("消息结束,完整消息ID: {}", completeResponse); + org.ruoyi.chat.support.RetryNotifier.clear(chatRequest.getSessionId()); } @Override public void onError(Throwable error) { error.printStackTrace(); + org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); } }); } catch (Exception e) { log.error("千问请求失败:{}", e.getMessage()); + org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java index da44d6c0..1fd12406 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java @@ -51,14 +51,16 @@ public class ZhipuAiChatServiceImpl implements IChatService { @SneakyThrows @Override public void onError(Throwable error) { - // System.out.println(error.getMessage()); + // 透传错误并触发重试 emitter.send(error.getMessage()); + org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); } @Override public void onCompleteResponse(ChatResponse response) { emitter.complete(); log.info("消息结束,完整消息ID: {}", response.aiMessage()); + org.ruoyi.chat.support.RetryNotifier.clear(chatRequest.getSessionId()); } }; @@ -71,6 +73,7 @@ public class ZhipuAiChatServiceImpl implements IChatService { model.chat(chatRequest.getPrompt(), handler); } catch (Exception e) { log.error("智谱清言请求失败:{}", e.getMessage()); + org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); } return emitter; From c3ab13ae6799712c31f1c1e54ad27b112abd24d6 Mon Sep 17 00:00:00 2001 From: likunlong Date: Tue, 19 Aug 2025 17:39:20 +0800 Subject: [PATCH 27/33] =?UTF-8?q?feat:=20=E5=A4=84=E7=90=86=E5=9C=A8?= =?UTF-8?q?=E9=9D=9EWeb=E7=BA=BF=E7=A8=8B=E4=B8=AD=E8=8E=B7=E5=8F=96Reques?= =?UTF-8?q?t=E4=B8=ADtoken=E5=A4=B1=E8=B4=A5=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/ruoyi/common/chat/request/ChatRequest.java | 5 +++++ .../org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java | 4 ++-- .../ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java | 2 +- .../org/ruoyi/chat/service/chat/impl/SseServiceImpl.java | 7 +++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java index 276f5dc8..71ebc4e5 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java @@ -77,4 +77,9 @@ public class ChatRequest { */ private Boolean autoSelectModel; + /** + * 会话令牌(为避免在非Web线程中获取Request,入口处注入) + */ + private String token; + } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java index 709c58ef..1c4af69d 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java @@ -128,8 +128,8 @@ public class ImageServiceImpl implements IChatService { OpenAiStreamClient openAiStreamClient = ChatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey()); List messages = chatRequest.getMessages(); - // 获取会话token - String token = StpUtil.getTokenValue(); + // 获取会话token(从入口透传,避免非Web线程取值报错) + String token = chatRequest.getToken(); // 创建 SSE 事件源监听器 SSEEventSourceListener listener = new SSEEventSourceListener(emitter, chatRequest.getUserId(), chatRequest.getSessionId(), token); diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java index b46fa03d..c81cc0ea 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java @@ -58,7 +58,7 @@ public class OpenAIServiceImpl implements IChatService { Message userMessage = Message.builder().content("工具返回信息:"+toolString).role(Message.Role.USER).build(); messages.add(userMessage); } - String token = StpUtil.getTokenValue(); + String token = chatRequest.getToken(); SSEEventSourceListener listener = new SSEEventSourceListener(emitter,chatRequest.getUserId(),chatRequest.getSessionId(), token); ChatCompletion completion = ChatCompletion .builder() diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java index 40bd9929..dfab7316 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java @@ -47,6 +47,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import cn.dev33.satoken.stp.StpUtil; /** * @author ageer @@ -77,6 +78,12 @@ public class SseServiceImpl implements ISseService { public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) { SseEmitter sseEmitter = new SseEmitter(0L); try { + // 记录当前会话令牌,供异步线程使用 + try { + chatRequest.setToken(StpUtil.getTokenValue()); + } catch (Exception ignore) { + // 保底:无token场景下忽略 + } // 构建消息列表 buildChatMessageList(chatRequest); // 设置对话角色 From 498135b7fda0a7f1f5e3d51bb3907128dab9382b Mon Sep 17 00:00:00 2001 From: likunlong Date: Tue, 19 Aug 2025 17:53:27 +0800 Subject: [PATCH 28/33] =?UTF-8?q?feat:=20=E5=A4=B1=E8=B4=A5=E5=9B=9E?= =?UTF-8?q?=E8=B0=83=E5=99=A8=E4=B8=AD=E4=BD=BF=E7=94=A8emitter=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E7=9A=84=E5=94=AF=E4=B8=80hash=E4=BD=9C=E4=B8=BAkey?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E5=86=8D=E4=BD=BF=E7=94=A8session=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E4=B8=8E=E4=B8=9A=E5=8A=A1=E8=BF=9B=E8=A1=8C=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=EF=BC=8C=E5=90=8C=E6=97=B6=E4=B9=9F=E4=BF=9D=E8=AF=81?= =?UTF-8?q?=E8=B7=A8=E7=BA=BF=E7=A8=8B=E8=B0=83=E7=94=A8=E7=9A=84=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E6=80=A7=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FastGPTSSEEventSourceListener.java | 22 +++++-------- .../chat/listener/SSEEventSourceListener.java | 12 +++---- .../service/chat/impl/CozeServiceImpl.java | 4 +-- .../service/chat/impl/DeepSeekChatImpl.java | 6 ++-- .../service/chat/impl/DifyServiceImpl.java | 8 ++--- .../service/chat/impl/OllamaServiceImpl.java | 6 ++-- .../service/chat/impl/OpenAIServiceImpl.java | 4 +-- .../chat/impl/QianWenAiChatServiceImpl.java | 6 ++-- .../service/chat/impl/SseServiceImpl.java | 4 +-- .../chat/impl/ZhipuAiChatServiceImpl.java | 8 ++--- .../org/ruoyi/chat/support/RetryNotifier.java | 31 +++++++++++-------- 11 files changed, 54 insertions(+), 57 deletions(-) diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/FastGPTSSEEventSourceListener.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/FastGPTSSEEventSourceListener.java index dd8519f2..3895c1a3 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/FastGPTSSEEventSourceListener.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/FastGPTSSEEventSourceListener.java @@ -48,9 +48,7 @@ public class FastGPTSSEEventSourceListener extends EventSourceListener { if ("flowResponses".equals(type)){ emitter.send(data); emitter.complete(); - if (sessionId != null) { - RetryNotifier.clear(sessionId); - } + RetryNotifier.clear(emitter); } else { emitter.send(data); } @@ -68,26 +66,20 @@ public class FastGPTSSEEventSourceListener extends EventSourceListener { @SneakyThrows public void onFailure(EventSource eventSource, Throwable t, Response response) { if (Objects.isNull(response)) { - if (sessionId != null) { - SSEUtil.sendErrorEvent(emitter, t != null ? t.getMessage() : "SSE连接失败"); - RetryNotifier.notifyFailure(sessionId); - } + SSEUtil.sendErrorEvent(emitter, t != null ? t.getMessage() : "SSE连接失败"); + RetryNotifier.notifyFailure(emitter); return; } ResponseBody body = response.body(); if (Objects.nonNull(body)) { String msg = body.string(); log.error("FastGPT sse连接异常data:{},异常:{}", msg, t); - if (sessionId != null) { - SSEUtil.sendErrorEvent(emitter, msg); - RetryNotifier.notifyFailure(sessionId); - } + SSEUtil.sendErrorEvent(emitter, msg); + RetryNotifier.notifyFailure(emitter); } else { log.error("FastGPT sse连接异常data:{},异常:{}", response, t); - if (sessionId != null) { - SSEUtil.sendErrorEvent(emitter, String.valueOf(response)); - RetryNotifier.notifyFailure(sessionId); - } + SSEUtil.sendErrorEvent(emitter, String.valueOf(response)); + RetryNotifier.notifyFailure(emitter); } eventSource.cancel(); } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java index 20adc22b..ddcfcaaa 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java @@ -79,8 +79,8 @@ public class SSEEventSourceListener extends EventSourceListener { if ("[DONE]".equals(data)) { //成功响应 emitter.complete(); - // 清理失败回调 - RetryNotifier.clear(sessionId); + // 清理失败回调(以 emitter 为键) + RetryNotifier.clear(emitter); // 扣除费用 ChatRequest chatRequest = new ChatRequest(); // 设置对话角色 @@ -118,7 +118,7 @@ public class SSEEventSourceListener extends EventSourceListener { public void onClosed(EventSource eventSource) { log.info("OpenAI关闭sse连接..."); // 清理失败回调 - RetryNotifier.clear(sessionId); + RetryNotifier.clear(emitter); } @SneakyThrows @@ -127,8 +127,8 @@ public class SSEEventSourceListener extends EventSourceListener { if (Objects.isNull(response)) { // 透传错误到前端 SSEUtil.sendErrorEvent(emitter, t != null ? t.getMessage() : "SSE连接失败"); - // 通知重试 - RetryNotifier.notifyFailure(sessionId); + // 通知重试(以 emitter 为键) + RetryNotifier.notifyFailure(emitter); return; } ResponseBody body = response.body(); @@ -141,7 +141,7 @@ public class SSEEventSourceListener extends EventSourceListener { SSEUtil.sendErrorEvent(emitter, String.valueOf(response)); } // 通知重试 - RetryNotifier.notifyFailure(sessionId); + RetryNotifier.notifyFailure(emitter); eventSource.cancel(); } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java index 54269b08..e9863b6c 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java @@ -64,12 +64,12 @@ public class CozeServiceImpl implements IChatService { if (ChatEventType.CONVERSATION_CHAT_COMPLETED.equals(event.getEvent())) { emitter.complete(); log.info("Token usage: {}", event.getChat().getUsage().getTokenCount()); - RetryNotifier.clear(chatRequest.getSessionId()); + RetryNotifier.clear(emitter); } } ); } catch (Exception ex) { - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + RetryNotifier.notifyFailure(emitter); } finally { coze.shutdownExecutor(); } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java index f0ddd77b..0a6e6693 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java @@ -58,15 +58,15 @@ public class DeepSeekChatImpl implements IChatService { @Override public void onError(Throwable error) { System.err.println("错误: " + error.getMessage()); - // 通知上层失败,进入重试/降级 - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + // 通知上层失败,进入重试/降级(以 emitter 为键) + RetryNotifier.notifyFailure(emitter); } }); } catch (Exception e) { log.error("deepseek请求失败:{}", e.getMessage()); // 同步异常直接通知失败 - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + RetryNotifier.notifyFailure(emitter); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java index 748d89c0..9327e5a1 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java @@ -113,24 +113,24 @@ public class DifyServiceImpl implements IChatService { chatRequestResponse.setSessionId(chatRequest.getSessionId()); chatRequestResponse.setPrompt(respMessage.toString()); chatCostService.deductToken(chatRequestResponse); - RetryNotifier.clear(chatRequest.getSessionId()); + RetryNotifier.clear(emitter); } @Override public void onError(ErrorEvent event) { System.err.println("错误: " + event.getMessage()); - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + RetryNotifier.notifyFailure(emitter); } @Override public void onException(Throwable throwable) { System.err.println("异常: " + throwable.getMessage()); - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + RetryNotifier.notifyFailure(emitter); } }); } catch (Exception e) { log.error("dify请求失败:{}", e.getMessage()); - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + RetryNotifier.notifyFailure(emitter); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java index 669f1c2f..2401b83e 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java @@ -67,15 +67,15 @@ public class OllamaServiceImpl implements IChatService { emitter.send(substr); } catch (IOException e) { SSEUtil.sendErrorEvent(emitter, e.getMessage()); - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + RetryNotifier.notifyFailure(emitter); } }; api.chat(requestModel, streamHandler); emitter.complete(); - RetryNotifier.clear(chatRequest.getSessionId()); + RetryNotifier.clear(emitter); } catch (Exception e) { SSEUtil.sendErrorEvent(emitter, e.getMessage()); - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + RetryNotifier.notifyFailure(emitter); } }); diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java index c81cc0ea..cc264803 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java @@ -69,8 +69,8 @@ public class OpenAIServiceImpl implements IChatService { try { openAiStreamClient.streamChatCompletion(completion, listener); } catch (Exception ex) { - // 同步异常也触发失败回调,按会话维度 - RetryNotifier.notifyFailure(chatRequest.getSessionId()); + // 同步异常也触发失败回调(以 emitter 为键) + RetryNotifier.notifyFailure(emitter); throw ex; } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java index 8462529c..3f5c00b0 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java @@ -51,18 +51,18 @@ public class QianWenAiChatServiceImpl implements IChatService { public void onCompleteResponse(ChatResponse completeResponse) { emitter.complete(); log.info("消息结束,完整消息ID: {}", completeResponse); - org.ruoyi.chat.support.RetryNotifier.clear(chatRequest.getSessionId()); + org.ruoyi.chat.support.RetryNotifier.clear(emitter); } @Override public void onError(Throwable error) { error.printStackTrace(); - org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); + org.ruoyi.chat.support.RetryNotifier.notifyFailure(emitter); } }); } catch (Exception e) { log.error("千问请求失败:{}", e.getMessage()); - org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); + org.ruoyi.chat.support.RetryNotifier.notifyFailure(emitter); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java index dfab7316..84602ade 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java @@ -136,8 +136,8 @@ public class SseServiceImpl implements ISseService { (modelForTry, onFailure) -> { // 替换请求中的模型名称 chatRequest.setModel(modelForTry.getModelName()); - // 将回调注册到ThreadLocal,供底层SSE失败时触发 - RetryNotifier.setFailureCallback(chatRequest.getSessionId(), onFailure); + // 以 emitter 实例为唯一键注册失败回调 + RetryNotifier.setFailureCallback(sseEmitter, onFailure); try { autoSelectServiceByCategoryAndInvoke(chatRequest, sseEmitter, modelForTry.getCategory()); } finally { diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java index 1fd12406..7405a77b 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java @@ -51,16 +51,16 @@ public class ZhipuAiChatServiceImpl implements IChatService { @SneakyThrows @Override public void onError(Throwable error) { - // 透传错误并触发重试 + // 透传错误并触发重试(以 emitter 为键) emitter.send(error.getMessage()); - org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); + org.ruoyi.chat.support.RetryNotifier.notifyFailure(emitter); } @Override public void onCompleteResponse(ChatResponse response) { emitter.complete(); log.info("消息结束,完整消息ID: {}", response.aiMessage()); - org.ruoyi.chat.support.RetryNotifier.clear(chatRequest.getSessionId()); + org.ruoyi.chat.support.RetryNotifier.clear(emitter); } }; @@ -73,7 +73,7 @@ public class ZhipuAiChatServiceImpl implements IChatService { model.chat(chatRequest.getPrompt(), handler); } catch (Exception e) { log.error("智谱清言请求失败:{}", e.getMessage()); - org.ruoyi.chat.support.RetryNotifier.notifyFailure(chatRequest.getSessionId()); + org.ruoyi.chat.support.RetryNotifier.notifyFailure(emitter); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java index 77044081..25f65c44 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java @@ -5,31 +5,36 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** - * 失败回调通知器:基于 sessionId 绑定回调,底层失败时按 sessionId 通知上层重试调度器。 + * 失败回调通知器:基于发射器实例(SseEmitter 等对象地址)绑定回调, + * 避免与业务标识绑定,且能跨线程正确关联。 */ public class RetryNotifier { - private static final Map FAILURE_CALLBACKS = new ConcurrentHashMap<>(); + private static final Map FAILURE_CALLBACKS = new ConcurrentHashMap<>(); - public static void setFailureCallback(Long sessionId, Runnable callback) { - if (sessionId == null || callback == null) { - return; - } - FAILURE_CALLBACKS.put(sessionId, callback); + private static int keyOf(Object obj) { + return System.identityHashCode(obj); } - public static void clear(Long sessionId) { - if (sessionId == null) { + public static void setFailureCallback(Object emitterLike, Runnable callback) { + if (emitterLike == null || callback == null) { return; } - FAILURE_CALLBACKS.remove(sessionId); + FAILURE_CALLBACKS.put(keyOf(emitterLike), callback); } - public static void notifyFailure(Long sessionId) { - if (sessionId == null) { + public static void clear(Object emitterLike) { + if (emitterLike == null) { return; } - Runnable cb = FAILURE_CALLBACKS.get(sessionId); + FAILURE_CALLBACKS.remove(keyOf(emitterLike)); + } + + public static void notifyFailure(Object emitterLike) { + if (emitterLike == null) { + return; + } + Runnable cb = FAILURE_CALLBACKS.get(keyOf(emitterLike)); if (Objects.nonNull(cb)) { cb.run(); } From 9fba91c35f9d7c43a94b8f0690a271d29a30d987 Mon Sep 17 00:00:00 2001 From: likunlong Date: Tue, 19 Aug 2025 18:00:20 +0800 Subject: [PATCH 29/33] =?UTF-8?q?feat:=20=E4=B8=8D=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E8=87=AA=E5=8A=A8=E9=80=89=E6=8B=A9=E6=97=B6?= =?UTF-8?q?=E8=B5=B0=E5=8E=9F=E5=A7=8B=E9=BB=98=E8=AE=A4=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/chat/impl/SseServiceImpl.java | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java index 84602ade..18cf3713 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java @@ -125,26 +125,31 @@ public class SseServiceImpl implements ISseService { // 自动选择模型并获取对应的聊天服务 IChatService chatService = autoSelectModelAndGetService(chatRequest); - // 统一重试与降级:封装启动逻辑,并通过ThreadLocal传递失败回调 - ChatModelVo currentModel = this.chatModelVo; - String currentCategory = currentModel.getCategory(); - ChatRetryHelper.executeWithRetry( - currentModel, - currentCategory, - chatModelService, - sseEmitter, - (modelForTry, onFailure) -> { - // 替换请求中的模型名称 - chatRequest.setModel(modelForTry.getModelName()); - // 以 emitter 实例为唯一键注册失败回调 - RetryNotifier.setFailureCallback(sseEmitter, onFailure); - try { - autoSelectServiceByCategoryAndInvoke(chatRequest, sseEmitter, modelForTry.getCategory()); - } finally { - // 不在此处清理,待下游结束/失败时清理 + // 仅当 autoSelectModel = true 时,才启用重试与降级 + if (Boolean.TRUE.equals(chatRequest.getAutoSelectModel())) { + ChatModelVo currentModel = this.chatModelVo; + String currentCategory = currentModel.getCategory(); + ChatRetryHelper.executeWithRetry( + currentModel, + currentCategory, + chatModelService, + sseEmitter, + (modelForTry, onFailure) -> { + // 替换请求中的模型名称 + chatRequest.setModel(modelForTry.getModelName()); + // 以 emitter 实例为唯一键注册失败回调 + RetryNotifier.setFailureCallback(sseEmitter, onFailure); + try { + autoSelectServiceByCategoryAndInvoke(chatRequest, sseEmitter, modelForTry.getCategory()); + } finally { + // 不在此处清理,待下游结束/失败时清理 + } } - } - ); + ); + } else { + // 不重试不降级,直接调用 + chatService.chat(chatRequest, sseEmitter); + } } catch (Exception e) { log.error(e.getMessage(),e); SSEUtil.sendErrorEvent(sseEmitter,e.getMessage()); From 842a39d6d2a0ea5680c24b56e4ebac681f3c3a63 Mon Sep 17 00:00:00 2001 From: likunlong Date: Tue, 19 Aug 2025 20:28:53 +0800 Subject: [PATCH 30/33] =?UTF-8?q?feat:=20=E5=85=BC=E5=AE=B9=E4=B8=8D?= =?UTF-8?q?=E9=80=89=E8=87=AA=E5=8A=A8=E6=A8=A1=E5=9E=8B=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E5=8E=9F=E5=85=88=E9=80=BB=E8=BE=91=EF=BC=9B=E5=B0=81=E8=A3=85?= =?UTF-8?q?=E9=80=9A=E7=94=A8=E6=96=B9=E6=B3=95=EF=BC=8C=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=9C=89=E7=9B=91=E6=8E=A7=E7=9A=84SSE?= =?UTF-8?q?=EF=BC=8C=E7=AE=80=E5=8C=96=E6=B5=81=E5=BC=8F=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E5=B9=B6=E9=80=9A=E7=9F=A5=E9=87=8D=E8=AF=95?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/listener/SSEEventSourceListener.java | 21 ++++++--- .../service/chat/impl/CozeServiceImpl.java | 3 +- .../service/chat/impl/DeepSeekChatImpl.java | 8 ++-- .../service/chat/impl/DifyServiceImpl.java | 7 +-- .../service/chat/impl/ImageServiceImpl.java | 10 ++++- .../service/chat/impl/OllamaServiceImpl.java | 7 ++- .../service/chat/impl/OpenAIServiceImpl.java | 9 ++-- .../chat/impl/QianWenAiChatServiceImpl.java | 5 ++- .../chat/impl/ZhipuAiChatServiceImpl.java | 7 ++- .../ruoyi/chat/support/ChatServiceHelper.java | 45 +++++++++++++++++++ .../org/ruoyi/chat/support/RetryNotifier.java | 7 +++ 11 files changed, 97 insertions(+), 32 deletions(-) create mode 100644 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/ChatServiceHelper.java diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java index ddcfcaaa..d10f8036 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java @@ -46,12 +46,15 @@ public class SSEEventSourceListener extends EventSourceListener { private String token; + private boolean retryEnabled; + @Autowired(required = false) - public SSEEventSourceListener(SseEmitter emitter,Long userId,Long sessionId, String token) { + public SSEEventSourceListener(SseEmitter emitter,Long userId,Long sessionId, String token, boolean retryEnabled) { this.emitter = emitter; this.userId = userId; this.sessionId = sessionId; this.token = token; + this.retryEnabled = retryEnabled; } @@ -127,8 +130,12 @@ public class SSEEventSourceListener extends EventSourceListener { if (Objects.isNull(response)) { // 透传错误到前端 SSEUtil.sendErrorEvent(emitter, t != null ? t.getMessage() : "SSE连接失败"); - // 通知重试(以 emitter 为键) - RetryNotifier.notifyFailure(emitter); + if (retryEnabled) { + // 通知重试(以 emitter 为键) + RetryNotifier.notifyFailure(emitter); + } else { + emitter.complete(); + } return; } ResponseBody body = response.body(); @@ -140,8 +147,12 @@ public class SSEEventSourceListener extends EventSourceListener { log.error("OpenAI sse连接异常data:{},异常:{}", response, t); SSEUtil.sendErrorEvent(emitter, String.valueOf(response)); } - // 通知重试 - RetryNotifier.notifyFailure(emitter); + if (retryEnabled) { + // 通知重试 + RetryNotifier.notifyFailure(emitter); + } else { + emitter.complete(); + } eventSource.cancel(); } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java index e9863b6c..730c0181 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/CozeServiceImpl.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.ruoyi.chat.support.RetryNotifier; +import org.ruoyi.chat.support.ChatServiceHelper; /** * 扣子聊天管理 @@ -69,7 +70,7 @@ public class CozeServiceImpl implements IChatService { } ); } catch (Exception ex) { - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, ex.getMessage()); } finally { coze.shutdownExecutor(); } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java index 0a6e6693..c2697c11 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java @@ -9,14 +9,13 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.ruoyi.chat.enums.ChatModeType; import org.ruoyi.chat.service.chat.IChatService; +import org.ruoyi.chat.support.ChatServiceHelper; import org.ruoyi.common.chat.request.ChatRequest; import org.ruoyi.domain.vo.ChatModelVo; import org.ruoyi.service.IChatModelService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; - -import org.ruoyi.chat.support.RetryNotifier; /** * deepseek */ @@ -58,15 +57,14 @@ public class DeepSeekChatImpl implements IChatService { @Override public void onError(Throwable error) { System.err.println("错误: " + error.getMessage()); - // 通知上层失败,进入重试/降级(以 emitter 为键) - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, error.getMessage()); } }); } catch (Exception e) { log.error("deepseek请求失败:{}", e.getMessage()); // 同步异常直接通知失败 - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, e.getMessage()); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java index 9327e5a1..51f9a960 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DifyServiceImpl.java @@ -25,6 +25,7 @@ import org.ruoyi.service.IChatSessionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import org.ruoyi.chat.support.ChatServiceHelper; import java.util.Objects; import org.ruoyi.chat.support.RetryNotifier; @@ -119,18 +120,18 @@ public class DifyServiceImpl implements IChatService { @Override public void onError(ErrorEvent event) { System.err.println("错误: " + event.getMessage()); - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, event.getMessage()); } @Override public void onException(Throwable throwable) { System.err.println("异常: " + throwable.getMessage()); - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, throwable.getMessage()); } }); } catch (Exception e) { log.error("dify请求失败:{}", e.getMessage()); - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, e.getMessage()); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java index 1c4af69d..36aa9c54 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java @@ -18,6 +18,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.*; +import org.ruoyi.chat.support.ChatServiceHelper; /** * 图片识别模型 @@ -131,7 +132,7 @@ public class ImageServiceImpl implements IChatService { // 获取会话token(从入口透传,避免非Web线程取值报错) String token = chatRequest.getToken(); // 创建 SSE 事件源监听器 - SSEEventSourceListener listener = new SSEEventSourceListener(emitter, chatRequest.getUserId(), chatRequest.getSessionId(), token); + SSEEventSourceListener listener = ChatServiceHelper.createOpenAiListener(emitter, chatRequest); // 构建聊天完成请求 ChatCompletion completion = ChatCompletion @@ -142,7 +143,12 @@ public class ImageServiceImpl implements IChatService { .build(); // 发起流式聊天完成请求 - openAiStreamClient.streamChatCompletion(completion, listener); + try { + openAiStreamClient.streamChatCompletion(completion, listener); + } catch (Exception ex) { + ChatServiceHelper.onStreamError(emitter, ex.getMessage()); + throw ex; + } return emitter; } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java index 2401b83e..7ce42215 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import org.ruoyi.chat.support.RetryNotifier; +import org.ruoyi.chat.support.ChatServiceHelper; /** @@ -66,16 +67,14 @@ public class OllamaServiceImpl implements IChatService { try { emitter.send(substr); } catch (IOException e) { - SSEUtil.sendErrorEvent(emitter, e.getMessage()); - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, e.getMessage()); } }; api.chat(requestModel, streamHandler); emitter.complete(); RetryNotifier.clear(emitter); } catch (Exception e) { - SSEUtil.sendErrorEvent(emitter, e.getMessage()); - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, e.getMessage()); } }); diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java index cc264803..6b8f72d6 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java @@ -1,12 +1,12 @@ package org.ruoyi.chat.service.chat.impl; -import cn.dev33.satoken.stp.StpUtil; import io.modelcontextprotocol.client.McpSyncClient; import lombok.extern.slf4j.Slf4j; import org.ruoyi.chat.config.ChatConfig; import org.ruoyi.chat.enums.ChatModeType; import org.ruoyi.chat.listener.SSEEventSourceListener; import org.ruoyi.chat.service.chat.IChatService; +import org.ruoyi.chat.support.ChatServiceHelper; import org.ruoyi.common.chat.entity.chat.ChatCompletion; import org.ruoyi.common.chat.entity.chat.Message; import org.ruoyi.common.chat.openai.OpenAiStreamClient; @@ -22,7 +22,6 @@ import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.List; -import org.ruoyi.chat.support.RetryNotifier; /** @@ -58,8 +57,7 @@ public class OpenAIServiceImpl implements IChatService { Message userMessage = Message.builder().content("工具返回信息:"+toolString).role(Message.Role.USER).build(); messages.add(userMessage); } - String token = chatRequest.getToken(); - SSEEventSourceListener listener = new SSEEventSourceListener(emitter,chatRequest.getUserId(),chatRequest.getSessionId(), token); + SSEEventSourceListener listener = ChatServiceHelper.createOpenAiListener(emitter, chatRequest); ChatCompletion completion = ChatCompletion .builder() .messages(messages) @@ -69,8 +67,7 @@ public class OpenAIServiceImpl implements IChatService { try { openAiStreamClient.streamChatCompletion(completion, listener); } catch (Exception ex) { - // 同步异常也触发失败回调(以 emitter 为键) - RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, ex.getMessage()); throw ex; } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java index 3f5c00b0..4128b84a 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java @@ -14,6 +14,7 @@ import org.ruoyi.service.IChatModelService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import org.ruoyi.chat.support.ChatServiceHelper; /** @@ -57,12 +58,12 @@ public class QianWenAiChatServiceImpl implements IChatService { @Override public void onError(Throwable error) { error.printStackTrace(); - org.ruoyi.chat.support.RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, error.getMessage()); } }); } catch (Exception e) { log.error("千问请求失败:{}", e.getMessage()); - org.ruoyi.chat.support.RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, e.getMessage()); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java index 7405a77b..50e545e0 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ZhipuAiChatServiceImpl.java @@ -15,6 +15,7 @@ import org.ruoyi.service.IChatModelService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import org.ruoyi.chat.support.ChatServiceHelper; @@ -51,9 +52,7 @@ public class ZhipuAiChatServiceImpl implements IChatService { @SneakyThrows @Override public void onError(Throwable error) { - // 透传错误并触发重试(以 emitter 为键) - emitter.send(error.getMessage()); - org.ruoyi.chat.support.RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, error.getMessage()); } @Override @@ -73,7 +72,7 @@ public class ZhipuAiChatServiceImpl implements IChatService { model.chat(chatRequest.getPrompt(), handler); } catch (Exception e) { log.error("智谱清言请求失败:{}", e.getMessage()); - org.ruoyi.chat.support.RetryNotifier.notifyFailure(emitter); + ChatServiceHelper.onStreamError(emitter, e.getMessage()); } return emitter; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/ChatServiceHelper.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/ChatServiceHelper.java new file mode 100644 index 00000000..042dee9c --- /dev/null +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/ChatServiceHelper.java @@ -0,0 +1,45 @@ +package org.ruoyi.chat.support; + +import org.ruoyi.chat.listener.SSEEventSourceListener; +import org.ruoyi.common.chat.request.ChatRequest; +import org.ruoyi.chat.util.SSEUtil; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +/** + * 抽取各聊天实现类的通用逻辑: + * - 创建带开关的 SSE 监听器 + * - 统一的流错误处理(根据是否在重试场景决定通知或直接结束) + * - 统一的完成处理(清理回调并 complete) + */ +public class ChatServiceHelper { + + public static SSEEventSourceListener createOpenAiListener(SseEmitter emitter, ChatRequest chatRequest) { + boolean retryEnabled = Boolean.TRUE.equals(chatRequest.getAutoSelectModel()); + return new SSEEventSourceListener( + emitter, + chatRequest.getUserId(), + chatRequest.getSessionId(), + chatRequest.getToken(), + retryEnabled + ); + } + + public static void onStreamError(SseEmitter emitter, String errorMessage) { + SSEUtil.sendErrorEvent(emitter, errorMessage); + if (RetryNotifier.hasCallback(emitter)) { + RetryNotifier.notifyFailure(emitter); + } else { + emitter.complete(); + } + } + + public static void onStreamComplete(SseEmitter emitter) { + try { + emitter.complete(); + } finally { + RetryNotifier.clear(emitter); + } + } +} + + diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java index 25f65c44..c37f82cb 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/support/RetryNotifier.java @@ -39,6 +39,13 @@ public class RetryNotifier { cb.run(); } } + + public static boolean hasCallback(Object emitterLike) { + if (emitterLike == null) { + return false; + } + return FAILURE_CALLBACKS.containsKey(keyOf(emitterLike)); + } } From d1e98a2001129820dcc6a118fceddfe48b1a1c81 Mon Sep 17 00:00:00 2001 From: likunlong Date: Wed, 20 Aug 2025 16:09:53 +0800 Subject: [PATCH 31/33] =?UTF-8?q?feat:=20=E4=B8=8B=E6=8E=89=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E8=83=BD=E5=8A=9B=E9=80=BB=E8=BE=91=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/ruoyi/domain/ChatModel.java | 7 +- .../java/org/ruoyi/domain/vo/ChatModelVo.java | 136 +----------------- script/sql/update/20250808.sql | 3 - 3 files changed, 2 insertions(+), 144 deletions(-) delete mode 100644 script/sql/update/20250808.sql 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 e2c75c7e..e8f0e308 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,7 +8,7 @@ import lombok.EqualsAndHashCode; import org.ruoyi.core.domain.BaseEntity; import java.io.Serial; -import java.util.List; + /** * 聊天模型对象 chat_model @@ -86,10 +86,5 @@ 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 257c0ec3..0638c13a 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,13 @@ 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; + /** @@ -102,138 +101,5 @@ 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/script/sql/update/20250808.sql b/script/sql/update/20250808.sql deleted file mode 100644 index 3c54c207..00000000 --- a/script/sql/update/20250808.sql +++ /dev/null @@ -1,3 +0,0 @@ --- 聊天模型表添加模型能力字段 -alter table chat_model - add model_capability varchar(255) default '[]' not null comment '模型能力'; From b9276c5dcc112205bdebf0693c51f97a3e6e3136 Mon Sep 17 00:00:00 2001 From: l90215 Date: Wed, 20 Aug 2025 17:52:51 +0800 Subject: [PATCH 32/33] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E7=9F=A5?= =?UTF-8?q?=E8=AF=86=E5=BA=93=E9=97=AE=E7=AD=94=E6=8E=A5=E5=85=A5=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E8=AF=8D=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/service/IPromptTemplateService.java | 7 + .../impl/PromptTemplateServiceImpl.java | 9 ++ .../ruoyi/chat/enums/promptTemplateEnum.java | 22 +++ .../service/chat/impl/SseServiceImpl.java | 131 ++++++++++-------- script/sql/ruoyi-ai.sql | 35 +++-- 5 files changed, 130 insertions(+), 74 deletions(-) create mode 100644 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/promptTemplateEnum.java diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IPromptTemplateService.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IPromptTemplateService.java index 89cff106..5a123ef0 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IPromptTemplateService.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IPromptTemplateService.java @@ -46,4 +46,11 @@ public interface IPromptTemplateService { * 校验并批量删除提示词模板信息 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据分类查询提示词模板 + * + * @param category 分类 + */ + PromptTemplateVo queryByCategory(String category); } diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/PromptTemplateServiceImpl.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/PromptTemplateServiceImpl.java index 85fdcd40..2f3a7572 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/PromptTemplateServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/PromptTemplateServiceImpl.java @@ -109,4 +109,13 @@ public class PromptTemplateServiceImpl implements IPromptTemplateService { } return baseMapper.deleteBatchIds(ids) > 0; } + + @Override + public PromptTemplateVo queryByCategory(String category) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(PromptTemplate.class); + queryWrapper.eq(PromptTemplate::getCategory, category); + queryWrapper.orderByDesc(PromptTemplate::getUpdateTime); + queryWrapper.last("limit 1"); + return baseMapper.selectVoOne(queryWrapper); + } } \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/promptTemplateEnum.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/promptTemplateEnum.java new file mode 100644 index 00000000..f71128fd --- /dev/null +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/promptTemplateEnum.java @@ -0,0 +1,22 @@ +package org.ruoyi.chat.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 提示词模板分类 + * + * @author evo + */ +@Getter +@AllArgsConstructor +public enum promptTemplateEnum { + CHAT(1, "chat"), + VECTOR(2, "vector"), + ; + + private final Integer code; + private final String desc; + +} + diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java index 18cf3713..a3892eeb 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java @@ -1,10 +1,12 @@ package org.ruoyi.chat.service.chat.impl; +import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.collection.CollectionUtil; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import okhttp3.ResponseBody; +import org.ruoyi.chat.enums.promptTemplateEnum; import org.ruoyi.chat.factory.ChatServiceFactory; import org.ruoyi.chat.service.chat.IChatCostService; import org.ruoyi.chat.service.chat.IChatService; @@ -27,9 +29,11 @@ import org.ruoyi.domain.bo.ChatSessionBo; import org.ruoyi.domain.bo.QueryVectorBo; import org.ruoyi.domain.vo.ChatModelVo; import org.ruoyi.domain.vo.KnowledgeInfoVo; +import org.ruoyi.domain.vo.PromptTemplateVo; import org.ruoyi.service.IChatModelService; import org.ruoyi.service.IChatSessionService; import org.ruoyi.service.IKnowledgeInfoService; +import org.ruoyi.service.IPromptTemplateService; import org.ruoyi.service.VectorStoreService; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; @@ -45,9 +49,8 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.List; -import cn.dev33.satoken.stp.StpUtil; +import java.util.Objects; /** * @author ageer @@ -73,6 +76,9 @@ public class SseServiceImpl implements ISseService { private ChatModelVo chatModelVo; + // 提示词模板服务 + private final IPromptTemplateService promptTemplateService; + @Override public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) { @@ -89,9 +95,9 @@ public class SseServiceImpl implements ISseService { // 设置对话角色 chatRequest.setRole(Message.Role.USER.getName()); - if(LoginHelper.isLogin()){ + if (LoginHelper.isLogin()) { - // 设置用户id + // 设置用户id chatRequest.setUserId(LoginHelper.getUserId()); @@ -100,10 +106,10 @@ public class SseServiceImpl implements ISseService { //待优化的地方 (这里请前端提交send的时候传递uuid进来或者sessionId) { // 设置会话id - if (chatRequest.getUuid() == null){ + if (chatRequest.getUuid() == null) { //暂时随机生成会话id chatRequest.setSessionId(System.currentTimeMillis()); - }else{ + } else { //这里或许需要修改一下,这里应该用uuid 或者 前端传递 sessionId chatRequest.setSessionId(chatRequest.getUuid()); } @@ -113,7 +119,7 @@ public class SseServiceImpl implements ISseService { // 保存消息记录 并扣除费用 chatCostService.deductToken(chatRequest); chatRequest.setUserId(chatCostService.getUserId()); - if(chatRequest.getSessionId()==null){ + if (chatRequest.getSessionId() == null) { ChatSessionBo chatSessionBo = new ChatSessionBo(); chatSessionBo.setUserId(chatCostService.getUserId()); chatSessionBo.setSessionTitle(getFirst10Characters(chatRequest.getPrompt())); @@ -130,29 +136,30 @@ public class SseServiceImpl implements ISseService { ChatModelVo currentModel = this.chatModelVo; String currentCategory = currentModel.getCategory(); ChatRetryHelper.executeWithRetry( - currentModel, - currentCategory, - chatModelService, - sseEmitter, - (modelForTry, onFailure) -> { - // 替换请求中的模型名称 - chatRequest.setModel(modelForTry.getModelName()); - // 以 emitter 实例为唯一键注册失败回调 - RetryNotifier.setFailureCallback(sseEmitter, onFailure); - try { - autoSelectServiceByCategoryAndInvoke(chatRequest, sseEmitter, modelForTry.getCategory()); - } finally { - // 不在此处清理,待下游结束/失败时清理 + currentModel, + currentCategory, + chatModelService, + sseEmitter, + (modelForTry, onFailure) -> { + // 替换请求中的模型名称 + chatRequest.setModel(modelForTry.getModelName()); + // 以 emitter 实例为唯一键注册失败回调 + RetryNotifier.setFailureCallback(sseEmitter, onFailure); + try { + autoSelectServiceByCategoryAndInvoke(chatRequest, sseEmitter, + modelForTry.getCategory()); + } finally { + // 不在此处清理,待下游结束/失败时清理 + } } - } ); } else { // 不重试不降级,直接调用 chatService.chat(chatRequest, sseEmitter); } } catch (Exception e) { - log.error(e.getMessage(),e); - SSEUtil.sendErrorEvent(sseEmitter,e.getMessage()); + log.error(e.getMessage(), e); + SSEUtil.sendErrorEvent(sseEmitter, e.getMessage()); } return sseEmitter; } @@ -169,7 +176,7 @@ public class SseServiceImpl implements ISseService { } else { chatModelVo = chatModelService.selectModelByName(chatRequest.getModel()); } - + if (chatModelVo == null) { throw new IllegalStateException("未找到模型名称:" + chatRequest.getModel()); } @@ -190,7 +197,7 @@ public class SseServiceImpl implements ISseService { IChatService service = chatServiceFactory.getChatService(category); service.chat(chatRequest, sseEmitter); } - + /** * 根据分类选择优先级最高的模型 */ @@ -220,23 +227,23 @@ public class SseServiceImpl implements ISseService { } /** - * 构建消息列表 + * 构建消息列表 */ - private void buildChatMessageList(ChatRequest chatRequest){ + private void buildChatMessageList(ChatRequest chatRequest) { List messages = chatRequest.getMessages(); - + // 处理知识库相关逻辑 String sysPrompt = processKnowledgeBase(chatRequest, messages); - + // 设置系统提示词 Message sysMessage = Message.builder() .content(sysPrompt) .role(Message.Role.SYSTEM) .build(); messages.add(0, sysMessage); - + chatRequest.setSysPrompt(sysPrompt); - + // 用户对话内容 String chatString = null; // 获取用户对话信息 @@ -250,54 +257,55 @@ public class SseServiceImpl implements ISseService { } chatRequest.setPrompt(chatString); } - + /** * 处理知识库相关逻辑 */ private String processKnowledgeBase(ChatRequest chatRequest, List messages) { if (StringUtils.isEmpty(chatRequest.getKid())) { - return getDefaultSystemPrompt(); + return getPromptTemplatePrompt(promptTemplateEnum.VECTOR.getDesc()); } - + try { // 查询知识库信息 KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(chatRequest.getKid())); if (knowledgeInfoVo == null) { log.warn("知识库信息不存在,kid: {}", chatRequest.getKid()); - return getDefaultSystemPrompt(); + return getPromptTemplatePrompt(promptTemplateEnum.VECTOR.getDesc()); } - + // 查询向量模型配置信息 ChatModelVo chatModel = chatModelService.selectModelByName(knowledgeInfoVo.getEmbeddingModelName()); if (chatModel == null) { log.warn("向量模型配置不存在,模型名称: {}", knowledgeInfoVo.getEmbeddingModelName()); - return getDefaultSystemPrompt(); + return getPromptTemplatePrompt(promptTemplateEnum.VECTOR.getDesc()); } - + // 构建向量查询参数 QueryVectorBo queryVectorBo = buildQueryVectorBo(chatRequest, knowledgeInfoVo, chatModel); - + // 获取向量查询结果 List nearestList = vectorStoreService.getQueryVector(queryVectorBo); - + // 添加知识库消息到上下文 addKnowledgeMessages(messages, nearestList); - + // 返回知识库系统提示词 return getKnowledgeSystemPrompt(knowledgeInfoVo); - + } catch (Exception e) { log.error("处理知识库信息失败: {}", e.getMessage(), e); - return getDefaultSystemPrompt(); + return getPromptTemplatePrompt(promptTemplateEnum.VECTOR.getDesc()); } } - + /** * 构建向量查询参数 */ - private QueryVectorBo buildQueryVectorBo(ChatRequest chatRequest, KnowledgeInfoVo knowledgeInfoVo, ChatModelVo chatModel) { + private QueryVectorBo buildQueryVectorBo(ChatRequest chatRequest, KnowledgeInfoVo knowledgeInfoVo, + ChatModelVo chatModel) { String content = chatRequest.getMessages().get(chatRequest.getMessages().size() - 1).getContent().toString(); - + QueryVectorBo queryVectorBo = new QueryVectorBo(); queryVectorBo.setQuery(content); queryVectorBo.setKid(chatRequest.getKid()); @@ -306,10 +314,10 @@ public class SseServiceImpl implements ISseService { queryVectorBo.setVectorModelName(knowledgeInfoVo.getVectorModelName()); queryVectorBo.setEmbeddingModelName(knowledgeInfoVo.getEmbeddingModelName()); queryVectorBo.setMaxResults(knowledgeInfoVo.getRetrieveLimit()); - + return queryVectorBo; } - + /** * 添加知识库消息到上下文 */ @@ -322,7 +330,7 @@ public class SseServiceImpl implements ISseService { messages.add(userMessage); } } - + /** * 获取知识库系统提示词 */ @@ -339,16 +347,29 @@ public class SseServiceImpl implements ISseService { } return sysPrompt; } - + + + /** + * 获取提示词模板提示词 + */ + private String getPromptTemplatePrompt(String category) { + PromptTemplateVo promptTemplateVo = promptTemplateService.queryByCategory(category); + if (Objects.isNull(promptTemplateVo) || StringUtils.isEmpty(promptTemplateVo.getTemplateContent())) { + return getDefaultSystemPrompt(); + } + return promptTemplateVo.getTemplateContent(); + } + /** * 获取默认系统提示词 */ private String getDefaultSystemPrompt() { String sysPrompt = chatModelVo != null ? chatModelVo.getSystemPrompt() : null; if (StringUtils.isEmpty(sysPrompt)) { - sysPrompt = "你是一个由RuoYI-AI开发的人工智能助手,名字叫熊猫助手。你擅长中英文对话,能够理解并处理各种问题,提供安全、有帮助、准确的回答。" + - "当前时间:" + DateUtils.getDate() + - "#注意:回复之前注意结合上下文和工具返回内容进行回复。"; + sysPrompt = "你是一个由RuoYI-AI开发的人工智能助手,名字叫RuoYI人工智能助手。" + + "你擅长中英文对话,能够理解并处理各种问题,提供安全、有帮助、准确的回答。" + + "当前时间:" + DateUtils.getDate() + + "#注意:回复之前注意结合上下文和工具返回内容进行回复。"; } return sysPrompt; } @@ -365,8 +386,8 @@ public class SseServiceImpl implements ISseService { InputStreamResource resource = new InputStreamResource(body.byteStream()); // 创建并返回ResponseEntity return ResponseEntity.ok() - .contentType(MediaType.parseMediaType("audio/mpeg")) - .body(resource); + .contentType(MediaType.parseMediaType("audio/mpeg")) + .body(resource); } else { // 如果ResponseBody为空,返回404状态码 return ResponseEntity.notFound().build(); diff --git a/script/sql/ruoyi-ai.sql b/script/sql/ruoyi-ai.sql index 2c824c8f..663fa1b4 100644 --- a/script/sql/ruoyi-ai.sql +++ b/script/sql/ruoyi-ai.sql @@ -647,28 +647,25 @@ INSERT INTO `sys_menu` VALUES (1929170702299045893, '提示词模板修改', 192 INSERT INTO `sys_menu` VALUES (1929170702299045894, '提示词模板删除', 1929170702299045890, '4', '#', '', NULL, 1, 0, 'F', '0', '0', 'system:promptTemplate:remove', '#', 103, 1, sysdate(), null, null, ''); INSERT INTO `sys_menu` VALUES (1929170702299045895, '提示词模板导出', 1929170702299045890, '5', '#', '', NULL, 1, 0, 'F', '0', '0', 'system:promptTemplate:export', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES (2000, '在线开发', 0, 20, 'dev', '', '', 1, 0, 'M', '0', '0', '', 'carbon:development', 103, 1, '2025-07-11 19:38:05', 1, '2025-07-11 19:43:03', '在线开发目录'); +INSERT INTO sys_menu VALUES (1944213468857495553, '模型分组', 2000, 1, 'schemaGroup', 'dev/schemaGroup/index', null, 1, 0, 'C', '0', '0', null, '#', 103, 1, '2025-07-13 09:53:07', 1, '2025-07-13 09:54:45', '模型分组菜单'); +INSERT INTO sys_menu VALUES (1944229086906281985, '数据模型', 2000, 2, 'schema', 'dev/schema/index', null, 1, 0, 'C', '0', '0', null, '#', 103, 1, '2025-07-13 10:55:11', null, '2025-07-13 10:55:11', '数据模型菜单'); +INSERT INTO sys_menu VALUES (1946466176918249473, '模型字段管理', 2000, 3, 'schemaField', 'dev/schemaField/index', null, 1, 0, 'C', '0', '0', null, '#', 103, 1, '2025-07-19 15:04:35', null, '2025-07-19 15:04:35', '模型字段管理菜单'); -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 (2000, '在线开发', 0, 20, 'dev', '', '', 1, 0, 'M', '0', '0', '', 'carbon:development', 103, 1, '2025-07-11 19:38:05', 1, '2025-07-11 19:43:03', '在线开发目录'); -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 (1944213468857495553, '模型分组', 2000, 1, 'schemaGroup', 'dev/schemaGroup/index', null, 1, 0, 'C', '0', '0', null, '#', 103, 1, '2025-07-13 09:53:07', 1, '2025-07-13 09:54:45', '模型分组菜单'); -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 (1944229086906281985, '数据模型', 2000, 2, 'schema', 'dev/schema/index', null, 1, 0, 'C', '0', '0', null, '#', 103, 1, '2025-07-13 10:55:11', null, '2025-07-13 10:55:11', '数据模型菜单'); -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 (1946466176918249473, '模型字段管理', 2000, 3, 'schemaField', 'dev/schemaField/index', null, 1, 0, 'C', '0', '0', null, '#', 103, 1, '2025-07-19 15:04:35', null, '2025-07-19 15:04:35', '模型字段管理菜单'); +INSERT INTO sys_menu VALUES (1944213468857495554, '模型分组查询', 1944213468857495553, 1, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaGroup:list', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1944213468857495555, '模型分组新增', 1944213468857495553, 2, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaGroup:add', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1944213468857495556, '模型分组修改', 1944213468857495553, 3, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaGroup:edit', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1944213468857495557, '模型分组删除', 1944213468857495553, 4, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaGroup:remove', '#', 103, 1, '2025-06-24 19:06:58', 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 (1944213468857495554, '模型分组查询', 1944213468857495553, 1, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaGroup:list', '#', 103, 1, '2025-06-24 19:06:58', 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 (1944213468857495555, '模型分组新增', 1944213468857495553, 2, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaGroup:add', '#', 103, 1, '2025-06-24 19:06:58', 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 (1944213468857495556, '模型分组修改', 1944213468857495553, 3, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaGroup:edit', '#', 103, 1, '2025-06-24 19:06:58', 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 (1944213468857495557, '模型分组删除', 1944213468857495553, 4, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaGroup:remove', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1944229086906281986, '模型数据查询', 1944229086906281985, 1, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schema:list', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1944229086906281987, '模型数据新增', 1944229086906281985, 2, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schema:add', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1944229086906281988, '模型数据修改', 1944229086906281985, 3, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schema:edit', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1944229086906281989, '模型数据删除', 1944229086906281985, 4, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schema:remove', '#', 103, 1, '2025-06-24 19:06:58', 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 (1944229086906281986, '模型数据查询', 1944229086906281985, 1, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schema:list', '#', 103, 1, '2025-06-24 19:06:58', 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 (1944229086906281987, '模型数据新增', 1944229086906281985, 2, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schema:add', '#', 103, 1, '2025-06-24 19:06:58', 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 (1944229086906281988, '模型数据修改', 1944229086906281985, 3, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schema:edit', '#', 103, 1, '2025-06-24 19:06:58', 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 (1944229086906281989, '模型数据删除', 1944229086906281985, 4, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schema:remove', '#', 103, 1, '2025-06-24 19:06:58', 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 (1946466176918249474, '模型字段管理查询', 1946466176918249473, 1, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaField:list', '#', 103, 1, '2025-06-24 19:06:58', 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 (1946466176918249475, '模型字段管理新增', 1946466176918249473, 2, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaField:add', '#', 103, 1, '2025-06-24 19:06:58', 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 (1946466176918249476, '模型字段管理修改', 1946466176918249473, 3, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaField:edit', '#', 103, 1, '2025-06-24 19:06:58', 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 (1946466176918249477, '模型字段管理删除', 1946466176918249473, 4, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaField:remove', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1946466176918249474, '模型字段管理查询', 1946466176918249473, 1, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaField:list', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1946466176918249475, '模型字段管理新增', 1946466176918249473, 2, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaField:add', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1946466176918249476, '模型字段管理修改', 1946466176918249473, 3, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaField:edit', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); +INSERT INTO sys_menu VALUES (1946466176918249477, '模型字段管理删除', 1946466176918249473, 4, '#', '', null, 1, 0, 'F', '0', '0', 'dev:schemaField:remove', '#', 103, 1, '2025-06-24 19:06:58', null, null, ''); From bb9c85ac3cdeccc880bf067dc34576126a6f4a6e Mon Sep 17 00:00:00 2001 From: AmAzing129 Date: Fri, 22 Aug 2025 14:29:03 +0800 Subject: [PATCH 33/33] docs: add contributors bubble --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 75be1549..9b223e4e 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,10 @@ > 💡 **小贴士**:建议将 PR 提交到 GitHub,我们会自动同步到其他代码托管平台 + + Contribution Leaderboard + + ## 📄 开源协议 本项目采用 **MIT 开源协议**,详情请查看 [LICENSE](LICENSE) 文件。