commit 51cac459b3f17c639ebd87cae4eab445b82d1db1 Author: admin Date: Sun Aug 9 17:51:11 2026 +0800 init: 导入RuoYi‑Vue‑Plus 6.X完整代码 diff --git a/.claude/agents/backend-common-infrastructure.md b/.claude/agents/backend-common-infrastructure.md new file mode 100644 index 000000000..3e1c3d60f --- /dev/null +++ b/.claude/agents/backend-common-infrastructure.md @@ -0,0 +1,42 @@ +--- +name: backend-common-infrastructure +description: 公共基础模块专家。用于修改 ruoyi-common 下的 mybatis、translation、json enhance、excel、oss、redis、web、encrypt 等公共能力,强调 API 兼容、调用点检查和同包风格一致。 +--- + +你负责 `ruoyi-common` 公共基础模块的增量修改。 + +## 核心原则 + +1. 先阅读同包接口、实现类和调用点,再改公共 API。 +2. 优先保持公开方法签名、泛型、返回值、异常语义兼容。 +3. 新增能力要贴合已有命名和链式调用风格,不自造平行体系。 +4. 只补注释时不改实现、不重排 import、不运行无关格式化。 + +## common-mybatis + +- 链式查询能力沿用 `QueryBuilder.lambda(...)`、`QueryBuilder.lambdaJoin(...)`、`BaseMapperPlus#lambda()`、`LambdaCrudChainWrapper`、`LambdaQueryBuilder`、`LambdaJoinQueryBuilder`、`LambdaQueryCondition`。 +- 条件辅助方法命名沿用 `eqIfPresent`、`eqIfText`、`neIfPresent`、`likeIfText`、`betweenIfPresent`、`betweenParams`、`inIfNotEmpty`、`findInSetIfPresent`。 +- `LambdaCrudChainWrapper` 同时维护查询字段和更新 set 片段;新增状态时必须检查 `instance()` 与 `clear()`。 +- 返回链式对象时保持 `this` / `typedThis`,不要暴露底层 wrapper 破坏调用链。 + +## translation / JSON 增强 + +- 翻译实现类实现 `TranslationInterface` 并标注 `@TranslationType(type = ...)`。 +- 批量翻译优先实现 `translationBatch(Set keys, String other)`,避免默认逐条查询。 +- 支持逗号分隔 ID 时复用 `collectLongIds`、`parseLongIds`、`joinMappedValues`。 +- `TranslationJsonFieldProcessor` 按 `collect` / `prepare` / `process` 三阶段组织。 +- 翻译失败应降级返回原值或 `null`,不要让响应增强中断主流程。 + +## excel / oss / json / web + +- Excel 导入监听器保持 `ExcelListener#getExcelResult()` 回执语义和错误聚合方式。 +- OSS 结果、异常、配置对象的工厂方法保持现有 `form...` 命名,不随意改成通用 builder。 +- JSON 响应增强处理器优先实现 `JsonFieldProcessor`,并按字段上下文读取注解。 +- Web、Redis、Encrypt、Sa-Token 自动配置类新增 bean 时检查条件注解、配置属性和已有命名。 + +## 自检 + +- 是否破坏已有调用点。 +- 是否遗漏 `instance()` / `clear()` / 批量翻译 / 缓存失效等公共模块关键路径。 +- 是否新增了与现有工具重复的临时类或临时方法。 +- JavaDoc 是否简洁说明公共 API 的参数、返回值和兼容语义。 diff --git a/.claude/agents/backend-crud.md b/.claude/agents/backend-crud.md new file mode 100644 index 000000000..87565ea67 --- /dev/null +++ b/.claude/agents/backend-crud.md @@ -0,0 +1,64 @@ +--- +name: backend-crud +description: 标准后端 CRUD 专家。用于当前项目中的新增单表 CRUD、补 entity/bo/vo/mapper/service/controller、分页查询、导出、删除前校验等任务。 +--- + +你负责当前项目中的标准后端 CRUD 实现。 + +## 核心原则 + +1. 先参考 `ruoyi-modules/ruoyi-gen/src/main/resources/vm/` 下的模板。 +2. 再参考当前模块内最近似的标准管理模块。 +3. 分层保持稳定: + `domain`、`domain.bo`、`domain.vo`、`mapper`、`service`、`service.impl`、`controller` + +## 结构约定 + +- entity 默认继承 `BaseEntity` +- entity 使用 `@TableName`,主键使用 `@TableId`;存在 `delFlag`、乐观锁字段时保留 `@TableLogic`、`@Version` +- mapper 默认继承 `BaseMapperPlus` +- BO 使用 `@AutoMapper(target = Entity.class, reverseConvertGenerate = false)` +- VO 使用 `@AutoMapper(target = Entity.class)` +- BO/VO/Entity 职责分离:请求、查询扩展字段放 BO;展示派生字段和 `@Translation` 放 VO +- 代码生成器模板按类名首字母小写命名 Mapper 字段,例如 `SysRoleMapper` -> `sysRoleMapper`;手写业务代码可使用具体业务短名 + +## 默认方法集合 + +- `queryById` +- `queryPageList` +- `queryList` +- `insertByBo` +- `updateByBo` +- `deleteWithValidByIds` + +## 查询规则 + +- 单表查询优先返回 `LambdaQueryWrapper`,新增 generator 风格代码优先用 `QueryBuilder.lambda(Entity.class).build()` +- 项目公共链式查询可使用 `QueryBuilder.lambda(...)`、`BaseMapperPlus#lambda()`、`LambdaCrudChainWrapper`、`LambdaQueryCondition` 的 `IfPresent` / `IfText` / `IfNotEmpty` 风格 +- 日期范围默认从 `bo.getParams()` 中读取 begin/end +- 分页优先返回 `PageResult` +- BO 转实体使用 `MapstructUtils.convert(bo, Entity.class)` +- 写入前校验优先放在 `validEntityBeforeSave(...)` + +## 接口规则 + +- controller 继承 `BaseController` +- 返回值使用 `R` 或 `R` +- 标准 CRUD 路由通常是: + `GET /list` + `POST /export` + `GET /{id}` + `POST` + `PUT` + `DELETE /{ids}` +- 默认检查是否需要 `@SaCheckPermission`、`@Log`、`@RepeatSubmit` +- 权限标识遵循 `${module}:${business}:${action}` +- 导出接口通常保持 `POST /export` + +## 自检 + +- CRUD 链路是否完整 +- BO / VO / Entity 是否职责分离 +- 导出、分页、删除前校验是否齐全 +- 是否只是 generator 裸产物,如果是要继续补齐项目约定 +- 前端 `api/types` 和 Vue `index.vue` 或 React `index.tsx` 如需同步,接口路径、返回结构、日期范围参数要与后端一致 diff --git a/.claude/agents/backend-engineering.md b/.claude/agents/backend-engineering.md new file mode 100644 index 000000000..d442a7be3 --- /dev/null +++ b/.claude/agents/backend-engineering.md @@ -0,0 +1,32 @@ +--- +name: backend-engineering +description: 后端工程总入口。用于在当前 RuoYi-Vue-Plus 项目中识别任务属于标准 CRUD、复杂模块增强、联表与数据权限、公共 common 模块、JavaDoc 注释、或前后端联动,并选择合适的后端子 agent。 +--- + +你是当前后端工程的总入口 agent。 + +先判断任务类型,再按下面规则处理: + +1. 如果是新增标准单表 CRUD、从表结构补 entity/bo/vo/mapper/service/controller,优先使用 `backend-crud.md` 的规则。 +2. 如果是修改 `system`、`workflow` 等已经很复杂的模块,优先使用 `backend-module-enhancement.md` 的规则。 +3. 如果重点在 MPJ 联表、`@DataPermission`、复杂查询、数据范围控制,优先使用 `backend-query-permission.md` 的规则。 +4. 如果是修改 `ruoyi-common` 公共基础能力,例如 `common-mybatis`、`common-translation`、`common-json`、`common-excel`、`common-oss`,优先使用 `backend-common-infrastructure.md` 的规则。 +5. 如果只要求补充或修正 JavaDoc 注释,优先使用 `backend-javadoc.md` 的规则。 +6. 如果同时要求同步前端接口或前端页面骨架,先确认目标前端是 Vue 还是 React,保持后端路由与 generator 风格稳定,便于前端 agent 对接。 + +文档读取顺序: + +- 后端 Java、Mapper、Service、Controller、BO、VO、Entity、权限、查询、公共模块或 JavaDoc 任务,先读 `.codex/skills/ruoyi-plus-ai-coding/references/backend.md`。 +- 同步前端 Vue、React、TypeScript、api、types 或页面骨架时,再读 `.codex/skills/ruoyi-plus-ai-coding/references/frontend.md`。 +- 任务边界不清晰或需要标准场景示例时,再读 `.codex/skills/ruoyi-plus-ai-coding/references/examples.md`。 +- 只读取当前任务相关的 reference,不一次性展开全部文档。 +- reference 用来约束实现方式和检查范围;如果 reference、generator 模板和真实代码冲突,优先相信当前模块真实代码和实际调用点。 + +通用要求: + +- 先读同模块最近似实现,再动代码。 +- 发生冲突时优先相信当前模块真实代码,其次是公共基础设施,再其次才是 generator 模板。 +- 默认直接产出可落地代码,而不是只给抽象建议。 +- 不要把 `BaseMapperPlus`、`PageQuery`、`PageResult`、`R`、`MapstructUtils`、`StringUtils`、`StreamUtils` 等项目工具替换成临时自造方案。 +- import、注解顺序、文件结构以附近代码为准,不做无关重排。 +- 修改公开 API 前先查调用点;公共模块优先保持方法签名、泛型、返回值和异常语义兼容。 diff --git a/.claude/agents/backend-javadoc.md b/.claude/agents/backend-javadoc.md new file mode 100644 index 000000000..a65d7b99d --- /dev/null +++ b/.claude/agents/backend-javadoc.md @@ -0,0 +1,42 @@ +--- +name: backend-javadoc +description: JavaDoc 注释专家。用于当前项目中补充或修正 JavaDoc 注释,覆盖公共 API、接口、BO/VO/Entity 字段、Mapper 默认方法、Service/Controller 方法和复杂私有辅助方法。 +--- + +你负责只补充或修正注释,不改变代码行为。 + +## 核心原则 + +1. 默认补 JavaDoc,保持当前文件和同包注释风格。 +2. 不改方法签名、泛型、返回值、实现逻辑。 +3. 不重排 import,不格式化全文件,不改无关注解顺序。 +4. 先确认注释是否准确反映当前实现,发现明显错注释要修正。 + +## 优先补充范围 + +- 公共 API、接口方法、record 参数、构造器。 +- BO / VO / Entity 字段,尤其是导入导出、翻译、权限相关字段。 +- Mapper 默认方法、Service/Controller 公开方法。 +- 公共模块里的私有辅助方法,如果涉及映射、批量处理、状态复制、降级语义。 + +## 注释风格 + +- 描述“做什么”和关键参数语义,不复述每行实现。 +- `@param` 名称必须和方法签名一致。 +- `void` 方法不要写 `@return`。 +- 布尔返回值说明 true/false 含义。 +- 简单框架覆写方法可不重复注释;如果当前文件已有统一注释风格,保持一致。 +- 只修正错注释时,尽量保持最小 diff。 + +## 常见错注释 + +- 方法实际查询全部数据,注释写成“根据用户查询”。 +- 方法返回树、映射、分页,`@return` 只写笼统“结果”。 +- 参数从 ID 集合变成 Collection,注释还写“ID 串”。 +- `translationBatch`、`buildValue`、`collect/prepare/process` 这类公共扩展点缺少批量语义说明。 + +## 自检 + +- 运行 `git diff --check`。 +- 检查是否只改注释或文档。 +- 检查新增 JavaDoc 是否和当前实现一致。 diff --git a/.claude/agents/backend-module-enhancement.md b/.claude/agents/backend-module-enhancement.md new file mode 100644 index 000000000..fe25515e2 --- /dev/null +++ b/.claude/agents/backend-module-enhancement.md @@ -0,0 +1,39 @@ +--- +name: backend-module-enhancement +description: 复杂后端模块增强专家。用于修改当前项目中已经存在较重业务逻辑的模块,例如 system、workflow 等,强调增量修改、保留现有权限、事务、缓存、导入导出和业务校验。 +--- + +你负责复杂后端模块的增量增强,不是从零生成裸 CRUD。 + +## 核心原则 + +1. 优先阅读当前模块最近似实现。 +2. 增量修改,不重写整块 service/controller。 +3. 保留已有的数据权限、事务、缓存、导入导出、唯一性校验、删除前校验。 +4. 不能为了“简洁”把复杂模块退化成模板式单表 CRUD。 +5. 修改 workflow 模块时检查同包是否需要 `@ConditionalOnEnable`。 + +## 常见任务 + +- 修改 `system`、`workflow` 模块的查询与导出逻辑 +- 新增或调整写入前校验 +- 维护角色、岗位、用户等关联数据 +- 增加复杂页面所需的特殊接口 +- 增加或调整缓存、翻译、字典、OSS、导入导出能力 + +## 约束 + +- controller 不堆重业务逻辑 +- service 里的旧逻辑要先理解再改 +- 如果附近已有 `ServiceException`、缓存注解、事务注解、数据权限判断,新增逻辑默认保持一致 +- 如果存在联动前端页面,接口路径与返回结构尽量稳定 +- 已有 `@Cacheable`、`@CacheEvict`、`@Caching` 的 service,新增写操作要同步考虑缓存失效 +- 工作流分类、任务、实例等查询常带分类权限或用户维度过滤,不要绕过旧逻辑 +- 翻译实现仍遵守 `TranslationInterface` + `@TranslationType` + `translationBatch` 批量查询规则 + +## 自检 + +- 是否破坏了原模块的权限边界 +- 是否误删了旧逻辑中的事务或校验 +- 是否错误简化了复杂关系维护 +- 是否漏掉缓存失效、导入导出回执、翻译字段、前端调用路径等联动点 diff --git a/.claude/agents/backend-query-permission.md b/.claude/agents/backend-query-permission.md new file mode 100644 index 000000000..adcc168d8 --- /dev/null +++ b/.claude/agents/backend-query-permission.md @@ -0,0 +1,44 @@ +--- +name: backend-query-permission +description: 后端查询、联表与数据权限专家。用于当前项目中的 MPJ 联表、DataPermission、复杂分页查询、范围控制和查询增强任务。 +--- + +你负责当前项目中的复杂查询和数据权限类任务。 + +## 核心原则 + +1. 优先看当前模块已有的 mapper 查询实现。 +2. 涉及数据权限时优先复用 `@DataPermission` 与已有字段映射方式。 +3. 复杂联表优先参考 MPJ 风格,不轻易改回手写零散 SQL。 +4. 如果 `BaseMapperPlus + wrapper` 足够,不要额外补 XML。 +5. wrapper 查询条件优先使用项目已有工具和命名,不自造查询 DSL。 + +## 重点关注 + +- `BaseMapperPlus` +- `QueryBuilder` +- `LambdaCrudChainWrapper` +- `LambdaQueryBuilder` +- `LambdaJoinQueryBuilder` +- `LambdaQueryCondition` +- `@DataPermission` +- `DataColumn` +- `MPJBaseMapper` +- `QueryBuilder.lambdaJoin(...)` +- 复杂分页与列表查询 + +## 项目写法 + +- MPJ 联表查询沿用别名风格,例如 `QueryBuilder.lambdaJoin("u", SysUser.class)`。 +- 带别名字段条件使用 `.eq("u", Entity::getField, value)`、`.orderByAsc("m", SysMenu::getOrderNum)`。 +- 数据权限列名要和真实 SQL 别名一致,例如 `d.dept_id`、`u.create_by`。 +- `ruoyi-system` 的用户、角色、菜单、部门查询常带角色状态、删除标识、部门权限过滤,修改前先读对应 mapper/service。 +- 日期范围参数继续从 `bo.getParams()` 获取,避免前端 `addDateRange` 对不上。 +- 简单查询默认留在 service wrapper;短小且复用性强的 mapper 默认方法可以保留在 mapper。 + +## 输出要求 + +- 明确说明查询是单表、联表还是带权限控制 +- 保持与当前模块 mapper 风格一致 +- 不要让查询参数风格和前端现有调用脱节 +- 不要为了“易读”移除已有数据权限、角色状态、删除标识过滤 diff --git a/.codex/skills/ruoyi-plus-ai-coding/SKILL.md b/.codex/skills/ruoyi-plus-ai-coding/SKILL.md new file mode 100644 index 000000000..488da20ee --- /dev/null +++ b/.codex/skills/ruoyi-plus-ai-coding/SKILL.md @@ -0,0 +1,181 @@ +--- +name: ruoyi-plus-ai-coding +description: 在仓库内按代码生成器模板、项目 reference 文档和既有约定生成或修改代码。用于新增或修改 CRUD 模块、controller/service/mapper/BO/VO/entity、MyBatis-Plus/MPJ 查询、数据权限、缓存、翻译/JSON 增强、公共 common 模块能力、JavaDoc 注释,以及与后端接口配套的 Vue 或 React 前端页面、types 和 api 文件;触发后应先按任务类型读取对应 references,再阅读目标模块真实代码和 generator 模板。 +--- + +# RuoYi Plus AI 编码规范 + +先对齐代码生成器产物,再叠加仓库里真实业务代码已经形成的更强约定。 + +## 适用场景 + +在下面这些任务里优先使用此 skill: + +- 新增标准 CRUD 模块。 +- 根据新表结构补齐 entity、bo、vo、mapper、service、controller。 +- 修改已有模块的查询、校验、导入导出、数据权限、事务逻辑。 +- 修改 `ruoyi-common` 公共能力,例如 mybatis 查询构造器、translation、json enhance、excel、oss、redis、web 配置。 +- 补充或修正 JavaDoc 注释,尤其是公共 API、接口、BO/VO/Entity 字段、Mapper 默认方法、Service/Controller 方法。 +- 在系统、监控、工作流、demo 等模块内按现有约定扩展业务代码。 +- 为后端新增接口同步补前端 `api/types` 和 Vue `index.vue` 或 React `index.tsx` 页面骨架。 + +## 不适用场景 + +下面这些任务不要机械套用本 skill 的 CRUD 规则: + +- 基础框架升级、Spring Boot 主版本迁移。 +- 与当前分层明显不同的实验性模块。 +- 第三方中间件深度接入、基础设施改造。 +- 完全脱离 generator 体系的独立子系统。 + +## 执行流程 + +1. 先判断任务类型,并按“文档读取规则”读取当前任务需要的 reference。 +2. 确认目标模块,优先复用同模块中最近似功能的写法。 +3. 新增标准 CRUD 代码前,先读取 `ruoyi-modules/ruoyi-gen/src/main/resources/fm/` 下的 FreeMarker 模板。 +4. 命名和分层保持与仓库一致: + `domain` entity、`domain.bo`、`domain.vo`、`mapper`、`service`、`service.impl`、`controller`。 +5. 优先在生成器结构上扩展,不要自行发明新的分层。 +6. 修改 `ruoyi-system` 这类复杂模块前,先阅读同类现有实现,因为这些模块通常比生成器默认产物多出数据权限、联表、缓存、安全校验等逻辑。 +7. 修改 `ruoyi-common` 公共模块前,先阅读同包接口、实现类和调用点,优先保持已有 API 语义与兼容性。 +8. 只补注释或文档时,不运行无关格式化,不重排 import,不改代码逻辑。 + +## 文档读取规则 + +使用本 skill 时,先按任务类型读取适用 reference,不一次性展开所有文档: + +- 后端 Java、Mapper、Service、Controller、BO、VO、Entity、权限、查询、公共模块或 JavaDoc 任务,先读 [references/backend.md](references/backend.md)。 +- 前端 Vue、React、TypeScript、api、types 或页面任务,先读 [references/frontend.md](references/frontend.md)。 +- 不确定任务边界、需要标准调用方式或需要对照典型场景时,再读 [references/examples.md](references/examples.md)。 + +reference 用来约束实现方式和自检范围;发生冲突时,仍以当前模块真实代码和实际调用点为准。 + +## 优先级规则 + +发生冲突时按下面顺序决策: + +1. 当前模块内最近似业务代码。 +2. 当前仓库公共基础模块约定,例如 `common-mybatis`、`common-core`、`common-web`。 +3. 代码生成器模板。 +4. 通用 Spring Boot / MyBatis-Plus 习惯。 + +也就是说: + +- 同模块已有成熟实现时,优先复用该实现。 +- 同模块没有现成代码时,再参考 generator 模板。 +- 不要因为“更通用”就覆盖掉项目已形成的强约定。 + +## 后端规则 + +Java、MyBatis-Plus、BO/VO/entity、controller、mapper、service 的具体规则见 [references/backend.md](references/backend.md)。 + +## 前端规则 + +Vue 3、React、TypeScript API 文件、生成式列表页、表单状态、字典和日期范围约定见 [references/frontend.md](references/frontend.md)。 + +## 使用案例 + +具体调用方式见 [references/examples.md](references/examples.md)。 + +## 仓库通用规则 + +- 遵循 [`.editorconfig`](../../../.editorconfig):UTF-8、LF,默认 4 空格,JSON/YAML 为 2 空格。 +- 不要把 `BaseMapperPlus`、`PageQuery`、`PageResult`、`R`、`MapstructUtils` 或项目工具类替换成临时自造方案。 +- 仓库已使用 `List.of(...)` 的地方,数组转列表优先继续沿用。 +- import、注解顺序、文件结构以附近代码为准,不要顺手重排整个文件。 +- 只有在业务逻辑不直观时才加简短注释。 + +## 决策规则 + +- 如果任务是围绕单表的标准 CRUD,尽量贴近生成器默认产物。 +- 如果目标模块已经存在自定义校验、数据权限、事务、缓存、Excel 导入导出、联表查询等逻辑,应在此基础上扩展,不要为了“简洁”把它们削平。 +- 如果附近 controller 接口已经带有权限、日志、防重、加密、分组校验等注解,新接口默认同步保持一致,除非有明确理由不这样做。 +- 如果 BO 或 VO 需要字段校验、翻译、Excel 注解,应优先参考同模块同用途对象,不要机械套通用注解。 +- 如果修改公共基础模块,优先保持公开 API 兼容,新增能力要查调用点和同包风格。 +- 如果任务只涉及注释,默认补 JavaDoc 并保持实现不变;框架覆写方法不强行重复注释,除非业务语义不直观。 + +## 目录映射规则 + +标准后端模块通常按下面结构组织: + +- `src/main/java/.../domain/Entity.java` +- `src/main/java/.../domain/bo/EntityBo.java` +- `src/main/java/.../domain/vo/EntityVo.java` +- `src/main/java/.../mapper/EntityMapper.java` +- `src/main/java/.../service/IEntityService.java` +- `src/main/java/.../service/impl/EntityServiceImpl.java` +- `src/main/java/.../controller/EntityController.java` + +标准生成器模板通常对应: + +- `fm/java/domain.java.ftl` -> entity +- `fm/java/bo.java.ftl` -> bo +- `fm/java/vo.java.ftl` -> vo +- `fm/java/mapper.java.ftl` -> mapper +- `fm/java/service.java.ftl` -> service interface +- `fm/java/serviceImpl.java.ftl` -> service impl +- `fm/java/controller.java.ftl` -> controller +- `fm/xml/mapper.xml.ftl` -> 自定义 XML mapper 起点 + +## 任务分型 + +### 1. 标准单表 CRUD + +优先按 generator 模板落骨架,再补校验、权限、导出、翻译等项目约定。 + +### 2. 强业务模块扩展 + +如果目标模块像 `system`、`workflow` 一样已经有复杂逻辑,优先增量修改,不要回退成模板式简化代码。 + +### 3. 基础能力复用 + +如果涉及数据权限、缓存、事务、导入导出、字典、翻译、加密、分组校验,优先查项目已有做法并复用公共能力。 + +### 4. 公共基础模块修改 + +修改 `ruoyi-common` 下的基础能力时,优先保证二进制/API 兼容:不要轻易改公开方法签名、泛型、返回值或异常语义。新增注释和小范围能力时,先查同包现有风格,例如 `common-mybatis` 的链式 wrapper、`common-translation` 的 `TranslationInterface` 实现、`common-json` 的字段处理器。 + +### 5. 注释修正任务 + +只要求“加注释/完善注释”时,默认补 JavaDoc,不改实现。优先补公共 API、接口方法、字段含义、复杂私有辅助方法;覆写框架回调方法只有在当前文件已有注释风格或业务语义不直观时才补。 + +## 输出要求 + +使用本 skill 时,默认期望产出应满足: + +- 后端分层完整,不直接在 controller 里堆业务逻辑。 +- `BO/VO/Entity` 职责分明。 +- 查询、分页、删除校验、写入校验逻辑闭环完整。 +- 权限、日志、防重、事务、数据权限尽量贴近同模块现有实现。 +- 如果同步改前端,前端 API 路径和后端接口保持一致。 + +## 快速检查清单 + +- 包路径和 `@RequestMapping` 与模块保持一致。 +- 权限标识遵循 `${module}:${business}:${action}`。 +- Mapper 继承 `BaseMapperPlus`。 +- 手写 Service 注入 Mapper 时使用具体业务短名;代码生成器模板按类名首字母小写命名,例如 `SysRoleMapper` 生成 `sysRoleMapper`。 +- Service 按场景返回 `PageResult` 或 `List`。 +- 查询代码优先使用 `LambdaQueryWrapper`,复杂模块沿用既有 MPJ 联表风格。 +- 公共 Mapper 链式能力优先沿用 `LambdaCrudChainWrapper`、`LambdaQueryBuilder`、`LambdaQueryCondition` 的 `IfPresent` / `IfText` / `IfNotEmpty` 风格。 +- 翻译能力优先沿用 `TranslationInterface` + `@TranslationType` + `@Translation`,批量翻译实现 `translationBatch`,避免退化成逐条查询。 +- JSON 响应增强优先沿用 `JsonFieldProcessor` 的 `collect` / `prepare` / `process` 三阶段模型。 +- BO 使用 `@AutoMapper(target = Entity.class, reverseConvertGenerate = false)`。 +- VO 使用 `@AutoMapper(target = Entity.class)`。 +- 前端 API 路径与后端路由完全对应。 +- 前端列表页继续使用对应前端工程已有工具:Vue 侧如 `proxy?.addDateRange`、`proxy?.$modal`、`proxy?.download`、`useDict`、`pagination`;React 侧如 `ProTable`、`ModalForm`、`useTableSelection`、`useDateRangeQuery`、`useTableExport`。 + +## 推荐提问方式 + +推荐把任务描述到下面这个粒度: + +- 目标模块和业务名 +- 是新建模块还是修改已有模块 +- 表名或接口前缀 +- 是否需要分页、导出、导入、数据权限、字典、翻译、联表 +- 希望参考哪个现有模块 + +例如: + +- 使用 `$ruoyi-plus-ai-coding` 在 `system` 模块新增一个标准单表 CRUD,参考 `SysConfig` 与 generator 模板。 +- 使用 `$ruoyi-plus-ai-coding` 修改 `workflow/category` 的查询和导出逻辑,保持现有模块风格。 diff --git a/.codex/skills/ruoyi-plus-ai-coding/agents/openai.yaml b/.codex/skills/ruoyi-plus-ai-coding/agents/openai.yaml new file mode 100644 index 000000000..9f0080421 --- /dev/null +++ b/.codex/skills/ruoyi-plus-ai-coding/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: "RuoYi Plus 编码" + short_description: "先读适用 reference,再按生成器与仓库约定编码" + default_prompt: "使用 $ruoyi-plus-ai-coding 在这个仓库里先读取适用 reference,再按生成器、公共模块和业务模块风格实现代码修改。" + +policy: + allow_implicit_invocation: true diff --git a/.codex/skills/ruoyi-plus-ai-coding/references/backend.md b/.codex/skills/ruoyi-plus-ai-coding/references/backend.md new file mode 100644 index 000000000..cc9841fac --- /dev/null +++ b/.codex/skills/ruoyi-plus-ai-coding/references/backend.md @@ -0,0 +1,268 @@ +# 后端约定 + +## 优先参考的代码来源 + +- `ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/*.ftl` +- `ruoyi-modules/ruoyi-demo/...` +- `ruoyi-modules/ruoyi-system/...` +- `ruoyi-modules/ruoyi-workflow/...` +- `ruoyi-common/ruoyi-common-mybatis/...` + +## 决策顺序 + +写代码时按下面顺序取样: + +1. 当前业务模块下最近似实现。 +2. 当前仓库公共能力模块中的统一约定。 +3. generator 模板。 +4. 通用 Spring / MyBatis-Plus 默认习惯。 + +如果规则冲突,优先相信当前仓库真实代码。 + +## 分层结构 + +标准 CRUD 代码应优先遵循下面这套结构: + +- `domain/Entity.java` +- `domain/bo/EntityBo.java` +- `domain/vo/EntityVo.java` +- `mapper/EntityMapper.java` +- `service/IEntityService.java` +- `service/impl/EntityServiceImpl.java` +- `controller/EntityController.java` + +## Entity 规则 + +- 除非所在模块明显另有约定,否则实体类继承 `org.dromara.common.mybatis.core.domain.BaseEntity`。 +- 使用 Lombok `@Data` 和 `@EqualsAndHashCode(callSuper = true)`。 +- 使用 `@TableName("table_name")`。 +- 主键使用 `@TableId`。 +- 存在 `delFlag` 时保留 `@TableLogic`,存在乐观锁字段时保留 `@Version`。 +- 如果附近实体已经使用 `@OrderBy` 等额外注解,应继续保持。 + +## BO 规则 + +- 实现 `Serializable`。 +- 添加 `@AutoMapper(target = Entity.class, reverseConvertGenerate = false)`。 +- 请求专用字段、查询专用字段放在 BO 中,包括 `params`。 +- 在生成器或附近代码已有分组校验时,继续使用:`AddGroup`、`EditGroup`、`QueryGroup`。 +- `@Xss`、`@Email`、`@Size`、`@NotBlank`、`@NotNull` 要按真实业务语义添加,不要一股脑全套上。 +- 查询存在日期范围或扩展条件时,保留 `params = new HashMap<>()`。 + +## VO 规则 + +- 实现 `Serializable`。 +- 添加 `@AutoMapper(target = Entity.class)`。 +- 生成器风格的导出对象通常带 `@ExcelIgnoreUnannotated`。 +- `@ExcelProperty`、`@ExcelDictFormat`、`ExcelDictConvert`、`@ExcelRequired`、`@ExcelNotation`、`@DateTimeFormat` 只在导入导出场景下使用。 +- 如果附近代码会把 ID 翻译成展示字段,沿用 `@Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")` 这类写法。 +- 展示型派生字段放在 VO,不放在 Entity。 + +## Mapper 规则 + +- 默认形式是 `interface XxxMapper extends BaseMapperPlus`。 +- 不要为简单的 entity 转 vo 手写重复代码,优先依赖 `BaseMapperPlus`。 +- 模块已经使用 `@DataPermission` 时,在重写方法和自定义查询上继续保留。 +- 复杂模块里 mapper 可能同时继承 `MPJBaseMapper` 并使用 `QueryBuilder.lambdaJoin(...)` 构造 MPJ 查询,遇到这种风格要延续,不要换一种写法。 +- 只有在 `selectVoList/selectVoPage` 不够用时,才补 XML 或自定义 mapper 方法。 +- Mapper 默认方法可以承载短小的 wrapper 查询;涉及复杂业务编排、缓存、事务或跨 mapper 写入时放到 service。 +- `ruoyi-system` 的用户、角色、菜单、部门等模块常带数据权限、MPJ 联表、角色状态过滤,修改前先读对应 mapper/service。 + +### Mapper 建议结构 + +标准 mapper 一般按这个顺序组织: + +1. 接口声明 +2. 默认查询方法 +3. 自定义分页或列表方法 +4. 特殊数据权限重写 +5. 辅助构造方法 + +### 什么时候需要 XML + +- 复杂联表 SQL 无法仅靠 wrapper 清晰表达时。 +- 需要手写查询列和结果映射时。 +- 项目当前模块已经大量使用 XML 时。 + +如果 `BaseMapperPlus + wrapper` 已足够,优先不要补 XML。 + +## Service 规则 + +- 类声明通常是 `@RequiredArgsConstructor`、`@Service`,按需补 `@Slf4j`。 +- 手写 mapper 注入字段使用具体业务短名;代码生成器模板按类名首字母小写命名。 +- 命名时去掉清晰的模块/系统前缀后使用 lowerCamel + `Mapper`,例如 `SysRoleMapper` -> `roleMapper`、`SysDictDataMapper` -> `dictDataMapper`。 +- 如果去掉前缀会产生歧义或命名冲突,保留必要前缀。 +- 读操作通常返回 `Vo`、`List` 或 `PageResult`。 +- BO 转实体用 `MapstructUtils.convert(bo, Entity.class)`。 +- 查询条件优先返回 `LambdaQueryWrapper`;新增 generator 风格代码优先用 `QueryBuilder.lambda(Entity.class)`,老模块已有 `Wrappers.lambdaQuery()` 时可继续保持。 +- 字符串和空值条件优先用 `eqIfText`、`likeIfText`、`eqIfPresent`、`inIfNotEmpty`、`betweenParams` 等项目扩展;老代码已有直接 `StringUtils.isNotBlank(...)` 和 null 判断时可增量保持。 +- 分页查询优先采用: + `Page result = entityMapper.selectVoPage(pageQuery.build(), lqw);` + `return PageResult.build(result.getRecords(), result.getTotal());` +- 生成器风格模块保留 `validEntityBeforeSave(...)` 这种扩展点。 +- 多表写操作使用 `@Transactional(rollbackFor = Exception.class)`。 +- 明确的业务失败,尤其是权限、数据完整性、删除校验,使用 `ServiceException`。 +- 不要绕过模块现有的数据权限、角色校验、删除前校验。 + +### Service 建议结构 + +标准 service impl 一般按下面顺序组织: + +1. 查询单条 +2. 分页查询 +3. 列表查询 +4. 构建查询条件 +5. 新增 +6. 修改 +7. 保存前校验 +8. 删除前校验与删除 +9. 其他扩展业务方法 + +### 查询逻辑建议 + +- 单表查询优先返回 `LambdaQueryWrapper`,生成器风格优先通过 `QueryBuilder.lambda(Entity.class).build()` 构造。 +- 条件判断直接放在 wrapper 链式条件上,不要额外写大量 if 套壳。 +- 日期范围统一从 `bo.getParams()` 取 begin/end;生成器默认使用 `betweenParams(Entity::getField, params, "beginField", "endField")`。 +- 复杂联表查询优先查同模块是否已有 MPJ 风格可复用;新写法优先用 `QueryBuilder.lambdaJoin("u", Entity.class)`。 + +### 写入逻辑建议 + +- BO 转实体统一走 `MapstructUtils.convert`。 +- 批量关系维护时优先拆成私有方法,例如角色、岗位、用户关联。 +- 修改前优先保留已有防误删、防越权、防并发覆盖逻辑。 + +## Controller 规则 + +- 继承 `BaseController`。 +- 类上通常带 `@Validated`、`@RestController`、`@RequiredArgsConstructor`、`@RequestMapping`。 +- 返回值使用 `R` 或 `R`。 +- 标准 CRUD 接口通常是:`GET /list`、`POST /export`、`GET /{id}`、`POST`、`PUT`、`DELETE /{ids}`。 +- 树表接口通常不分页,`list` 返回 `R>`;导出路由以目标模块或 generator 模板为准,旧 demo 树表存在 `GET /export`,新版生成器通常是 `POST /export`。 +- `@SaCheckPermission` 权限格式遵循 `${module}:${business}:${action}`。 +- 写操作、导入导出接口通常加 `@Log(title = "...", businessType = BusinessType.X)`。 +- 附近接口已有防重时,写接口继续使用 `@RepeatSubmit`。 +- 适合分组校验时,使用 `@Validated(AddGroup.class)` 和 `@Validated(EditGroup.class)`。 +- 特殊接口直接复用模块内现成做法,例如导入导出、`@ApiEncrypt`、multipart 上传、数据权限检查、写入前唯一性校验。 + +### Controller 建议结构 + +标准 controller 一般按下面顺序组织: + +1. 列表 +2. 导出 +3. 详情 +4. 新增 +5. 修改 +6. 删除 +7. 特殊接口 + +### Controller 边界 + +- controller 负责接参、校验、权限、日志、返回值转换。 +- 重业务逻辑尽量放 service,不要在 controller 里堆长逻辑。 +- 但前置权限检查、唯一性提示、显式业务失败提示可以留在 controller,前提是同模块已有这种习惯。 + +## 查询与工具规则 + +- 分页统一使用 `PageQuery` 和 `PageResult`,不要无故引入新的分页 DTO。 +- 优先使用项目工具类:`MapstructUtils`、`StringUtils`、`StreamUtils`、`ValidatorUtils`、`SpringUtils`、`RedisUtils`。 +- 数组转列表按附近代码习惯使用 `List.of(ids)` 或 `Arrays.asList(ids)`。 +- 日期范围查询通常从 `bo.getParams()` 中读取 `beginTime`、`endTime` 或 `beginFieldName`、`endFieldName`。 +- 构建查询优先识别 `QueryBuilder.lambda(...)`、`QueryBuilder.lambdaJoin(...)`、`BaseMapperPlus#lambda()` 三类入口,不要退回临时手写 SQL 或自造 wrapper。 + +## common-mybatis 规则 + +- 链式查询能力优先沿用 `QueryBuilder.lambda(...)`、`QueryBuilder.lambdaJoin(...)`、`BaseMapperPlus#lambda()`、`LambdaCrudChainWrapper`、`LambdaQueryBuilder`、`LambdaJoinQueryBuilder`、`LambdaQueryCondition`。 +- 条件辅助方法使用项目已有命名:`eqIfPresent`、`eqIfText`、`neIfPresent`、`likeIfText`、`betweenIfPresent`、`betweenParams`、`inIfNotEmpty`、`findInSetIfPresent`。 +- 新增 wrapper 方法时保持链式返回 `this` / `typedThis`,不要返回底层 `LambdaQueryWrapper` 破坏调用链。 +- `LambdaCrudChainWrapper` 既承担查询又承担更新 set 片段,新增能力时要同时考虑 `getSqlSelect`、`getSqlSet`、`clear`、`instance` 的状态复制和清理。 +- MPJ 联表查询沿用别名风格,例如 `QueryBuilder.lambdaJoin("u", SysUser.class)`、`.leftJoin(..., "d", ...)`、`.eq("u", Entity::getField, value)`。 +- 数据权限注解使用 `@DataPermission` + `@DataColumn`,列名需和实际 SQL 别名一致,例如 `d.dept_id`、`u.create_by`。 + +## translation / JSON 增强规则 + +- 翻译实现类实现 `TranslationInterface` 并标注 `@TranslationType(type = ...)`。 +- 使用方在 VO 字段上通过 `@Translation(type = ..., mapper = "...", other = "...")` 指定翻译来源。 +- 批量翻译必须优先实现 `translationBatch(Set keys, String other)`,避免默认逐条查询。 +- 支持逗号分隔 ID 的翻译实现应复用 `collectLongIds`、`parseLongIds`、`joinMappedValues`。 +- `TranslationJsonFieldProcessor` 遵循三阶段:`collect` 收集待翻译值,`prepare` 批量查询,`process` 写入翻译结果;新增处理器也应优先套这个模型。 +- 翻译失败时保持降级返回原值或 `null` 的现有语义,不要让响应增强中断主流程。 + +## 缓存与异步/监听规则 + +- 已有 service 使用 `@Cacheable`、`@CachePut`、`@CacheEvict`、`@Caching` 或 `CacheUtils.evict/clear` 时,新增写操作要同步考虑缓存失效。 +- 部门、字典、OSS 配置等模块已有缓存初始化或失效逻辑,不要只改数据库不处理缓存;字典这类模块常同时维护 `CacheNames.SYS_DICT` 与 `CacheNames.SYS_DICT_TYPE`。 +- Excel 导入监听器实现 `ExcelListener` 时,保留 `getExcelResult()` 的回执语义和错误聚合方式。 +- 定时任务、MQTT、SSE、异步回调等框架方法一般按接口覆写语义实现,除非业务不直观,不要添加冗长注释。 + +## 工作流模块规则 + +- `ruoyi-workflow` 通常带 `@ConditionalOnEnable`,新增 workflow bean、controller、service 时检查同包是否需要该条件。 +- 流程分类、任务、实例等查询常带分类权限或用户维度过滤,先读同类 mapper/service 再改。 +- 工作流的翻译实现可以放在 workflow 模块内,例如流程分类 ID 到名称,仍应遵守 `TranslationInterface` 批量翻译规则。 + +## JavaDoc 注释规则 + +- 公共 API、接口、VO/BO/Entity 字段、Mapper 默认方法、Service/Controller 方法应有简洁 JavaDoc。 +- 注释描述“做什么”和关键参数语义,不复述显而易见的实现细节。 +- `void` 方法不要写 `@return`;返回布尔值时说明 `true/false` 含义。 +- 私有方法只有在业务规则、算法、映射关系不直观时补注释。 +- 框架覆写方法如果只是标准回调,可不重复注释;但当前文件已有统一注释风格时保持一致。 +- 只改注释时,不重排 import、不格式化全文件、不修改代码行为。 + +## 前后端联动规则 + +- 新增后端接口时,路径和权限前缀尽量保持 generator 约定,方便前端目录和 API 命名同步。 +- 新增日期范围查询时,记得保留 `bo.params` 结构,避免前端 `addDateRange` 无法对接。 +- 导出接口通常保持 `POST /export` 风格,便于前端直接复用现有下载逻辑。 +- 批量删除接口通常使用 `DELETE /{ids}`,便于前端直接传数组或逗号串。 + +## 生成器优先模式 + +从零新增 CRUD 时,优先对齐生成器默认方法集合: + +- `queryById` +- `queryPageList` +- `queryList` +- `insertByBo` +- `updateByBo` +- `deleteWithValidByIds` + +然后再叠加模块内已有增强,例如: + +- 唯一性校验 +- 数据权限注解 +- MPJ 联表查询 +- 缓存注解 +- Excel 导入导出监听器 +- 关联表维护逻辑 + +## 什么时候优先看 generator + +- 新增一个标准单表 CRUD 时。 +- 只有表结构和基本接口需求,没有现成业务模块可参考时。 +- 需要快速补齐整套骨架代码时。 + +## 什么时候优先看现有模块 + +- 目标模块已经有类似业务。 +- 涉及数据权限、联表、缓存、角色岗位关系、导入导出、工作流扩展时。 +- 任务是“修改已有模块”而不是“新建模块”时。 + +## 避免事项 + +- 不要在 controller 里直接暴露 entity 代替 BO/VO。 +- 不要给新的管理接口漏掉权限注解。 +- 没有明确必要时,不要从 `BaseMapperPlus` 风格退回手工映射。 +- 前端查询页用了日期范围时,不要删掉后端 `params` 相关处理。 +- 不要把 `ruoyi-system` 这类复杂逻辑强行简化成生成器式单表 CRUD。 + +## 交付前自检 + +交付前至少检查这些点: + +- CRUD 主链路是否完整。 +- BO / VO / Entity 职责是否清晰。 +- 分页、查询、删除校验是否与前端对得上。 +- 权限、日志、防重、事务是否遗漏。 +- 是否只是 generator 裸产物,如果是,需要继续补齐同模块已有增强。 diff --git a/.codex/skills/ruoyi-plus-ai-coding/references/examples.md b/.codex/skills/ruoyi-plus-ai-coding/references/examples.md new file mode 100644 index 000000000..91b7d8fa5 --- /dev/null +++ b/.codex/skills/ruoyi-plus-ai-coding/references/examples.md @@ -0,0 +1,101 @@ +# 使用案例 + +## 案例 1:新增标准单表 CRUD + +### 用户提问示例 + +```text +使用 $ruoyi-plus-ai-coding 在 system 模块新增一个 client 管理的标准 CRUD。 +请参考 generator 模板和现有 system 模块写法,补齐 entity、bo、vo、mapper、service、controller。 +``` + +### 期望执行方式 + +- 先读 generator 的 `domain/bo/vo/service/serviceImpl/controller` 模板。 +- 再读 `system` 模块里最接近的现有管理模块。 +- 先生成骨架,再补权限、日志、校验、导出等细节。 + +## 案例 2:修改已有复杂模块 + +### 用户提问示例 + +```text +使用 $ruoyi-plus-ai-coding 修改 workflow/category 的查询和导出逻辑,保持现有模块风格,不要简化成模板式单表 CRUD。 +``` + +### 期望执行方式 + +- 先读当前 workflow 模块同类代码。 +- 判断这是“复杂模块增强”,不是“从零生成”。 +- 增量修改原逻辑,不要重写整个 service/controller。 + +## 案例 3:补唯一性校验与删除前校验 + +### 用户提问示例 + +```text +使用 $ruoyi-plus-ai-coding 为 demo/demo 模块补充新增和修改时的唯一性校验,并补充删除前校验。 +``` + +### 期望执行方式 + +- 优先修改 `validEntityBeforeSave(...)`。 +- 根据模块现有风格补 `ServiceException` 或显式失败返回。 +- 删除逻辑只补必要校验,不重构整套 CRUD。 + +## 案例 4:补数据权限与联表查询 + +### 用户提问示例 + +```text +使用 $ruoyi-plus-ai-coding 为 system 模块某个列表查询增加部门数据权限和联表字段返回,参考现有 user mapper 的 MPJ 与 DataPermission 写法。 +``` + +### 期望执行方式 + +- 先看 `SysUserMapper` 和相关 service。 +- 判断需要 `BaseMapperPlus` 重写还是 MPJ 联表。 +- 保持权限注解和联表风格一致。 + +## 案例 5:新增后端接口并同步前端骨架 + +### 用户提问示例 + +```text +使用 $ruoyi-plus-ai-coding 为 monitor/cache 新增一个导出接口,并同步补齐 Vue 或 React 前端 api/types 调用骨架。 +``` + +### 期望执行方式 + +- 先补后端 `controller/service`。 +- 再根据后端路由和目标前端类型补 `src/api` 或 generator 风格的前端骨架。 +- 保证导出接口路径和前端下载调用一致。 + +## 案例 6:推荐的高质量任务描述 + +下面这种描述最容易得到稳定结果: + +```text +使用 $ruoyi-plus-ai-coding 在 workflow 模块新增一个标准列表管理功能: +1. 需要分页、导出、详情、增删改 +2. 查询包含状态和创建时间范围 +3. 保持现有 workflow 模块风格 +4. 参考 generator 模板生成基础骨架 +5. 删除前需要做业务校验 +``` + +## 不推荐的任务描述 + +下面这种描述太模糊,容易导致产物偏离项目: + +```text +帮我加个后端接口 +``` + +更好的写法至少要补充: + +- 模块名 +- 表或业务名 +- 是新增还是修改 +- 是否需要分页、导出、权限、数据范围、联表 +- 想参考哪个现有模块 diff --git a/.codex/skills/ruoyi-plus-ai-coding/references/frontend.md b/.codex/skills/ruoyi-plus-ai-coding/references/frontend.md new file mode 100644 index 000000000..1a3a4379c --- /dev/null +++ b/.codex/skills/ruoyi-plus-ai-coding/references/frontend.md @@ -0,0 +1,101 @@ +# 前端约定 + +## 优先参考的代码来源 + +- `ruoyi-modules/ruoyi-gen/src/main/resources/fm//*.ftl` +- 默认 Vue 模板在 `fm/vue`,React 模板在 `fm/react` +- 前端工程中与目标模块最接近的现有页面 + +当前 boot4 仓库通常只含后端与 generator 前端模板;如果前端工程不在当前仓库根目录,先以 generator 模板约定为准,再对照用户提供的前端工程或官方前端分支: + +- Vue 前端:`https://gitee.com/JavaLionLi/plus-ui/tree/6.X-Vue` +- React 前端:`https://gitee.com/JavaLionLi/plus-ui/tree/6.X-React` + +## 前端模板选择规则 + +- `gen_table.frontend_type` 存字符串,值直接对应 `fm` 下的模板目录,例如 `vue`、`react`。 +- 生成器按 `fm//api.ts.ftl`、`types.ts.ftl`、`index.*.ftl`、`index-tree.*.ftl` 查找模板。 +- 页面输出后缀由页面模板文件名决定:`index.vue.ftl` 输出 `index.vue`,`index.tsx.ftl` 输出 `index.tsx`。 +- 新增其他前端时优先只新增 `fm/` 目录和对应 FTL 文件,不在 Java 代码里增加数字枚举或硬编码分支。 + +## API 文件规则 + +- Vue 模板从 `@/utils/request` 引入 `request`,从 `@/utils/api-types` 引入 `AxiosPromise`,从 `@/api/types` 引入 `PageResult`。 +- React 模板从 `@/api/request` 引入 `request`,从 `@/api/types` 引入 `R`、`PageResult`。 +- 本模块类型:Vue 模板从 `@/api///types` 引入,React 模板从 `./types` 引入。 +- Vue 列表接口通常返回 `AxiosPromise>`;React 列表接口通常返回 `request>>(...)`。 +- 常规接口命名和路由保持: + `listXxx` -> `GET ///list` + `getXxx` -> `GET ///{id}` + `addXxx` -> `POST //` + `updateXxx` -> `PUT //` + `delXxx` -> `DELETE ///{id or ids}` + +## 类型文件规则 + +- 定义 `VO`、`Form`、`Query`。 +- `Form` 通常继承 `BaseEntity`。 +- 非树表页面的 `Query` 通常继承 `PageQuery`。 +- 各类 ID 字段通常用 `string | number`。 +- Java 数值类型通常映射为 `number`。 +- Boolean 映射为 `boolean`。 +- 其他生成字段默认多为 `string`。 +- 存在日期范围查询时保留 `params`:Vue 模板通常是 `params?: any`,React 模板通常是 `params?: Record`。 + +## Vue 页面规则 + +- 使用 ` diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/fm/vue/index.vue.ftl b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/vue/index.vue.ftl new file mode 100644 index 000000000..59df6cc5c --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/vue/index.vue.ftl @@ -0,0 +1,615 @@ + + + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/fm/vue/types.ts.ftl b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/vue/types.ts.ftl new file mode 100644 index 000000000..de4d9c9af --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/vue/types.ts.ftl @@ -0,0 +1,48 @@ +export interface ${BusinessName}VO { +<#list columns as column> +<#if column.list> + /** + * ${column.columnComment} + */ + ${column.javaField}: ${column.tsType}; +<#if column.htmlType == "imageUpload"> + /** + * ${column.columnComment}Url + */ + ${column.javaField}Url: string; + + + +<#if table.tree> + /** + * 子对象 + */ + children: ${BusinessName}VO[]; + +} + +export interface ${BusinessName}Form extends BaseEntity { +<#list columns as column> +<#if column.insert || column.edit> + /** + * ${column.columnComment} + */ + ${column.javaField}?: ${column.tsType}; + + +} + +export interface ${BusinessName}Query<#if !table.tree> extends PageQuery { +<#list columns as column> +<#if column.query> + /** + * ${column.columnComment} + */ + ${column.javaField}?: ${column.tsType}; + + + /** + * 日期范围参数 + */ + params?: any; +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/fm/xml/mapper.xml.ftl b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/xml/mapper.xml.ftl new file mode 100644 index 000000000..1c76ad8de --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/xml/mapper.xml.ftl @@ -0,0 +1,6 @@ + + + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/generator.yml b/ruoyi-modules/ruoyi-gen/src/main/resources/generator.yml new file mode 100644 index 000000000..d779d9794 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/generator.yml @@ -0,0 +1,10 @@ +# 代码生成 +gen: + # 作者 + author: Lion Li + # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool + packageName: org.dromara.system + # 自动去除表前缀,默认是false + autoRemovePre: false + # 表前缀(生成类名不会包含表前缀,多个用逗号分隔) + tablePrefix: sys_ diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/gen/GenTableColumnMapper.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/gen/GenTableColumnMapper.xml new file mode 100644 index 000000000..f48af47f9 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/gen/GenTableColumnMapper.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/gen/GenTableMapper.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/gen/GenTableMapper.xml new file mode 100644 index 000000000..0e5ce4d86 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/gen/GenTableMapper.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/package-info.md new file mode 100644 index 000000000..c938b1e50 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/pom.xml b/ruoyi-modules/ruoyi-job/pom.xml new file mode 100644 index 000000000..d0e3cc4b2 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/pom.xml @@ -0,0 +1,35 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + + ruoyi-job + + + 任务调度 + + + + + + + org.dromara + ruoyi-common-json + + + + + org.dromara + ruoyi-common-job + + + + + + diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/entity/BillDTO.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/entity/BillDTO.java new file mode 100644 index 000000000..d9f4912b5 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/entity/BillDTO.java @@ -0,0 +1,19 @@ +package org.dromara.job.entity; + +import java.math.BigDecimal; + +/** + * 账单数据传输对象。 + * + * @param billId 账单 ID + * @param billChannel 账单渠道 + * @param billDate 账单日期 + * @param billAmount 账单金额 + */ +public record BillDTO( + Long billId, + String billChannel, + String billDate, + BigDecimal billAmount +) { +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java new file mode 100644 index 000000000..2f118b071 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java @@ -0,0 +1 @@ +package org.dromara.job; diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/AlipayBillTask.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/AlipayBillTask.java new file mode 100644 index 000000000..4b3e7ffc9 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/AlipayBillTask.java @@ -0,0 +1,45 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.common.log.SnailJobLog; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.job.entity.BillDTO; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; + +/** + * DAG工作流任务-模拟支付宝账单任务 + * + * + * @author 老马 + */ +@Component +@JobExecutor(name = "alipayBillTask") +public class AlipayBillTask { + + /** + * 执行支付宝账单模拟任务,并将结果写入工作流上下文。 + * + * @param jobArgs 任务执行参数 + * @return 执行结果 + * @throws InterruptedException 任务被中断时抛出 + */ + public ExecuteResult jobExecute(JobArgs jobArgs) throws InterruptedException { + // 设置清算日期 + String settlementDate = (String) jobArgs.getWfContext().get("settlementDate"); + if (StringUtils.equals(settlementDate, "sysdate")) { + settlementDate = DateUtils.now(); + } + BillDTO billDTO = new BillDTO(23456789L, "alipay", settlementDate, new BigDecimal("2345.67")); + // 把billDTO对象放入上下文进行传递 + jobArgs.appendContext("alipay", JsonUtils.toJsonString(billDTO)); + SnailJobLog.REMOTE.info("上下文: {}", jobArgs.getWfContext()); + return ExecuteResult.success(billDTO); + } + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SummaryBillTask.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SummaryBillTask.java new file mode 100644 index 000000000..9800d8bdd --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SummaryBillTask.java @@ -0,0 +1,52 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.common.log.SnailJobLog; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.job.entity.BillDTO; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; + +/** + * DAG工作流任务-模拟汇总账单任务 + * + * + * @author 老马 + */ +@Component +@JobExecutor(name = "summaryBillTask") +public class SummaryBillTask { + + /** + * 汇总工作流上下文中的微信与支付宝账单金额。 + * + * @param jobArgs 任务执行参数 + * @return 汇总执行结果 + * @throws InterruptedException 任务被中断时抛出 + */ + public ExecuteResult jobExecute(JobArgs jobArgs) throws InterruptedException { + // 获得微信账单 + BigDecimal wechatAmount = BigDecimal.valueOf(0); + String wechat = (String) jobArgs.getWfContext("wechat"); + if (StringUtils.isNotBlank(wechat)) { + BillDTO wechatBillDTO = JsonUtils.parseObject(wechat, BillDTO.class); + wechatAmount = wechatBillDTO.billAmount(); + } + // 获得支付宝账单 + BigDecimal alipayAmount = BigDecimal.valueOf(0); + String alipay = (String) jobArgs.getWfContext("alipay"); + if (StringUtils.isNotBlank(alipay)) { + BillDTO alipayBillDTO = JsonUtils.parseObject(alipay, BillDTO.class); + alipayAmount = alipayBillDTO.billAmount(); + } + // 汇总账单 + BigDecimal totalAmount = wechatAmount.add(alipayAmount); + SnailJobLog.REMOTE.info("总金额: {}", totalAmount); + return ExecuteResult.success(totalAmount); + } + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java new file mode 100644 index 000000000..44d2ad84f --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java @@ -0,0 +1,31 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.common.core.util.JsonUtil; +import com.aizuda.snailjob.common.log.SnailJobLog; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import org.springframework.stereotype.Component; + +/** + * 正常任务 + * + * + * @author 老马 + */ +@Component +@JobExecutor(name = "testJobExecutor") +public class TestAnnoJobExecutor { + + /** + * 执行示例注解任务。 + * + * @param jobArgs 任务参数 + * @return 执行结果 + */ + public ExecuteResult jobExecute(JobArgs jobArgs) { + SnailJobLog.LOCAL.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); + SnailJobLog.REMOTE.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); + return ExecuteResult.success("测试成功"); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestBroadcastJob.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestBroadcastJob.java new file mode 100644 index 000000000..a33d071d3 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestBroadcastJob.java @@ -0,0 +1,46 @@ +package org.dromara.job.snailjob; + +import cn.hutool.core.util.RandomUtil; +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.common.log.SnailJobLog; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * 广播任务 + * + * + * @author 老马 + */ +@Slf4j +@Component +@JobExecutor(name = "testBroadcastJob") +public class TestBroadcastJob { + + /** + * 客户端端口。 + */ + @Value("${snail-job.port}") + private int clientPort; + + /** + * 执行广播任务示例,随机模拟成功或失败。 + * + * @param jobArgs 任务执行参数 + * @return 执行结果 + */ + public ExecuteResult jobExecute(JobArgs jobArgs) { + int randomInt = RandomUtil.randomInt(100); + log.info("随机数: {}", randomInt); + SnailJobLog.REMOTE.info("随机数: {},客户端端口:{}", randomInt, clientPort); + if (randomInt < 50) { + throw new RuntimeException("随机数小于50,收集日志任务执行失败"); + } + // 获得jobArgs 中传入的相加的两个数 + return ExecuteResult.success("随机数大于50,收集日志任务执行成功"); + } + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java new file mode 100644 index 000000000..6465dd234 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java @@ -0,0 +1,25 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.client.job.core.executor.AbstractJobExecutor; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import org.springframework.stereotype.Component; + +/** + * @author opensnail + * @date 2024-05-17 + */ +@Component +public class TestClassJobExecutor extends AbstractJobExecutor { + + /** + * 执行测试类任务。 + * + * @param jobArgs 任务参数 + * @return 任务执行结果 + */ + @Override + protected ExecuteResult doJobExecute(JobArgs jobArgs) { + return ExecuteResult.success("TestJobExecutor测试成功"); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapJobAnnotation.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapJobAnnotation.java new file mode 100644 index 000000000..6e6047d18 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapJobAnnotation.java @@ -0,0 +1,66 @@ +package org.dromara.job.snailjob; + +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.aizuda.snailjob.client.job.core.MapHandler; +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.annotation.MapExecutor; +import com.aizuda.snailjob.client.job.core.dto.MapArgs; +import com.aizuda.snailjob.common.log.SnailJobLog; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import org.dromara.common.core.utils.StreamUtils; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +/** + * Map任务 动态分配 只分片不关注结果 + * + * + * @author 老马 + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +@Component +@JobExecutor(name = "testMapJobAnnotation") +public class TestMapJobAnnotation { + + /** + * 根 Map 任务,将示例数据拆分为多个分片任务。 + * + * @param mapArgs Map 任务参数 + * @param mapHandler 分片调度处理器 + * @return 分片调度结果 + */ + @MapExecutor + public ExecuteResult doJobMapExecute(MapArgs mapArgs, MapHandler mapHandler) { + // 生成1~200数值并分片 + int partitionSize = 50; + List sourceList = IntStream.rangeClosed(1, 200).boxed().toList(); + List> partition = StreamUtils.groupByKey(sourceList, i -> (i - 1) / partitionSize) + .values() + .stream() + .toList(); + SnailJobLog.REMOTE.info("端口:{}完成分配任务", SpringUtil.getProperty("server.port")); + return mapHandler.doMap(partition, "doCalc"); + } + + /** + * 执行单个分片的累加计算。 + * + * @param mapArgs 分片任务参数 + * @return 分片计算结果 + */ + @MapExecutor(taskName = "doCalc") + public ExecuteResult doCalc(MapArgs mapArgs) { + List sourceList = (List) mapArgs.getMapResult(); + // 遍历sourceList的每一个元素,计算出一个累加值partitionTotal + int partitionTotal = sourceList.stream().mapToInt(i -> i).sum(); + // 打印日志到服务器 + ThreadUtil.sleep(3, TimeUnit.SECONDS); + SnailJobLog.REMOTE.info("端口:{},partitionTotal:{}", SpringUtil.getProperty("server.port"), partitionTotal); + return ExecuteResult.success(partitionTotal); + } + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapReduceAnnotation1.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapReduceAnnotation1.java new file mode 100644 index 000000000..f31310ad9 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapReduceAnnotation1.java @@ -0,0 +1,79 @@ +package org.dromara.job.snailjob; + +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.aizuda.snailjob.client.job.core.MapHandler; +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.annotation.MapExecutor; +import com.aizuda.snailjob.client.job.core.annotation.ReduceExecutor; +import com.aizuda.snailjob.client.job.core.dto.MapArgs; +import com.aizuda.snailjob.client.job.core.dto.ReduceArgs; +import com.aizuda.snailjob.common.log.SnailJobLog; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import org.dromara.common.core.utils.StreamUtils; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +/** + * MapReduce任务 动态分配 分片后合并结果 + * + * + * @author 老马 + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +@Component +@JobExecutor(name = "testMapReduceAnnotation1") +public class TestMapReduceAnnotation1 { + + /** + * 根 Map 任务,将示例数据拆分为多个分片任务。 + * + * @param mapArgs Map 任务参数 + * @param mapHandler 分片调度处理器 + * @return 分片调度结果 + */ + @MapExecutor + public ExecuteResult rootMapExecute(MapArgs mapArgs, MapHandler mapHandler) { + int partitionSize = 50; + List sourceList = IntStream.rangeClosed(1, 200).boxed().toList(); + List> partition = StreamUtils.groupByKey(sourceList, i -> (i - 1) / partitionSize) + .values() + .stream() + .toList(); + SnailJobLog.REMOTE.info("端口:{}完成分配任务", SpringUtil.getProperty("server.port")); + return mapHandler.doMap(partition, "doCalc"); + } + + /** + * 执行单个分片的累加计算。 + * + * @param mapArgs 分片任务参数 + * @return 分片计算结果 + */ + @MapExecutor(taskName = "doCalc") + public ExecuteResult doCalc(MapArgs mapArgs) { + List sourceList = (List) mapArgs.getMapResult(); + // 遍历sourceList的每一个元素,计算出一个累加值partitionTotal + int partitionTotal = sourceList.stream().mapToInt(i -> i).sum(); + // 打印日志到服务器 + ThreadUtil.sleep(3, TimeUnit.SECONDS); + SnailJobLog.REMOTE.info("端口:{},partitionTotal:{}", SpringUtil.getProperty("server.port"), partitionTotal); + return ExecuteResult.success(partitionTotal); + } + + /** + * 汇总所有 Map 分片的计算结果。 + * + * @param reduceArgs Reduce 任务参数 + * @return 汇总结果 + */ + @ReduceExecutor + public ExecuteResult reduceExecute(ReduceArgs reduceArgs) { + int reduceTotal = reduceArgs.getMapResult().stream().mapToInt(i -> Integer.parseInt((String) i)).sum(); + SnailJobLog.REMOTE.info("端口:{},reduceTotal:{}", SpringUtil.getProperty("server.port"), reduceTotal); + return ExecuteResult.success(reduceTotal); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestStaticShardingJob.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestStaticShardingJob.java new file mode 100644 index 000000000..0f4e6e79c --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestStaticShardingJob.java @@ -0,0 +1,43 @@ +package org.dromara.job.snailjob; + +import cn.hutool.core.convert.Convert; +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.common.log.SnailJobLog; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import org.springframework.stereotype.Component; + +/** + * 静态分片 根据服务端任务参数分片 + * + * + * @author 老马 + */ +@Component +@JobExecutor(name = "testStaticShardingJob") +public class TestStaticShardingJob { + + /** + * 执行静态分片任务示例。 + * + * @param jobArgs 任务执行参数 + * @return 执行结果 + */ + public ExecuteResult jobExecute(JobArgs jobArgs) { + String jobParams = Convert.toStr(jobArgs.getJobParams()); + SnailJobLog.LOCAL.info("开始执行分片任务,参数:{}", jobParams); + // 获得jobArgs 中传入的开始id和结束id + String[] split = jobParams.split(","); + Long fromId = Long.parseLong(split[0]); + Long toId = Long.parseLong(split[1]); + // 模拟数据库操作,对范围id,进行加密处理 + try { + SnailJobLog.REMOTE.info("开始对id范围:{}进行加密处理", fromId + "-" + toId); + Thread.sleep(3000); + SnailJobLog.REMOTE.info("对id范围:{}进行加密处理完成", fromId + "-" + toId); + } catch (InterruptedException e) { + return ExecuteResult.failure("任务执行失败"); + } + return ExecuteResult.success("执行分片任务完成"); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/WechatBillTask.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/WechatBillTask.java new file mode 100644 index 000000000..899b0fb79 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/WechatBillTask.java @@ -0,0 +1,46 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.common.log.SnailJobLog; +import com.aizuda.snailjob.model.dto.ExecuteResult; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.job.entity.BillDTO; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; + +/** + * DAG工作流任务-模拟微信账单任务 + * + * + * @author 老马 + */ +@Component +@JobExecutor(name = "wechatBillTask") +public class WechatBillTask { + + /** + * 执行微信账单模拟任务,并将结果写入工作流上下文。 + * + * @param jobArgs 任务执行参数 + * @return 执行结果 + * @throws InterruptedException 任务被中断时抛出 + */ + public ExecuteResult jobExecute(JobArgs jobArgs) throws InterruptedException { + // 从上下文中获得清算日期并设置,如果上下文中清算日期 + // 是sysdate设置为当前日期;否则取管理页面设置的值 + String settlementDate = (String) jobArgs.getWfContext().get("settlementDate"); + if (StringUtils.equals(settlementDate, "sysdate")) { + settlementDate = DateUtils.now(); + } + BillDTO billDTO = new BillDTO(123456789L, "wechat", settlementDate, new BigDecimal("1234.56")); + // 把billDTO对象放入上下文进行传递 + jobArgs.appendContext("wechat", JsonUtils.toJsonString(billDTO)); + SnailJobLog.REMOTE.info("上下文: {}", jobArgs.getWfContext()); + return ExecuteResult.success(billDTO); + } + +} diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml new file mode 100644 index 000000000..03aa0b95d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/pom.xml @@ -0,0 +1,105 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + + ruoyi-system + + + system系统模块 + + + + + + org.dromara + ruoyi-common-core + + + + + org.dromara + ruoyi-api + + + + + org.dromara + ruoyi-common-doc + + + + + org.dromara + ruoyi-common-mybatis + + + + + org.dromara + ruoyi-common-translation + + + + + org.dromara + ruoyi-common-oss + + + + + org.dromara + ruoyi-common-log + + + + + org.dromara + ruoyi-common-excel + + + + + org.dromara + ruoyi-common-sms + + + + + org.dromara + ruoyi-common-security + + + + + org.dromara + ruoyi-common-web + + + + + org.dromara + ruoyi-common-sensitive + + + + + org.dromara + ruoyi-common-encrypt + + + + + org.dromara + ruoyi-common-push + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java new file mode 100644 index 000000000..40ce04075 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java @@ -0,0 +1,68 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.redisson.spring.data.connection.RedissonConnectionFactory; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.core.RedisConnectionUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 缓存监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/cache") +public class CacheController { + + private final RedissonConnectionFactory connectionFactory; + + /** + * 获取 Redis 缓存监控信息。 + * + * @return Redis 信息、库大小与命令统计 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping() + public R getInfo() throws Exception { + RedisConnection connection = connectionFactory.getConnection(); + try { + Properties commandStats = connection.commands().info("commandstats"); + List> pieList = new ArrayList<>(); + if (commandStats != null) { + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + } + return R.ok(new CacheListInfoVo( + connection.commands().info(), + connection.commands().dbSize(), pieList)); + } finally { + // 归还连接给连接池 + RedisConnectionUtils.releaseConnection(connection, connectionFactory); + } + } + + /** + * 缓存监控列表信息 + * + * @param info 信息 + * @param dbSize 数据库 + * @param commandStats 命令统计 + */ + public record CacheListInfoVo(Properties info, Long dbSize, List> commandStats) { + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLoginInfoController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLoginInfoController.java new file mode 100644 index 000000000..6690b4ba2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLoginInfoController.java @@ -0,0 +1,110 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.baomidou.lock.annotation.Lock4j; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysLoginInfoBo; +import org.dromara.system.domain.vo.SysLoginInfoVo; +import org.dromara.system.service.ISysLoginInfoService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 系统访问记录 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/loginInfo") +public class SysLoginInfoController extends BaseController { + + private final ISysLoginInfoService loginInfoService; + + /** + * 分页查询系统访问记录。 + * + * @param loginInfo 查询条件 + * @param pageQuery 分页参数 + * @return 登录日志分页结果 + */ + @SaCheckPermission("monitor:logininfo:list") + @GetMapping("/list") + public R> list(SysLoginInfoBo loginInfo, PageQuery pageQuery) { + return R.ok(loginInfoService.selectPageLoginInfoList(loginInfo, pageQuery)); + } + + /** + * 导出系统访问记录列表。 + * + * @param loginInfo 查询条件 + * @param response HTTP 响应 + */ + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:logininfo:export") + @PostMapping("/export") + public void export(SysLoginInfoBo loginInfo, HttpServletResponse response) { + List list = loginInfoService.selectLoginInfoList(loginInfo); + ExcelBuilder.of(list, SysLoginInfoVo.class).sheetName("登录日志").toResponse(response); + } + + /** + * 批量删除登录日志 + * + * @param infoIds 日志ids + * @return 操作结果 + */ + @SaCheckPermission("monitor:logininfo:remove") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public R remove(@PathVariable Long[] infoIds) { + return toAjax(loginInfoService.deleteLoginInfoByIds(infoIds)); + } + + /** + * 清空系统访问记录。 + * + * @return 操作结果 + */ + @SaCheckPermission("monitor:logininfo:remove") + @Log(title = "登录日志", businessType = BusinessType.CLEAN) + @Lock4j + @DeleteMapping("/clean") + public R clean() { + loginInfoService.cleanLoginInfo(); + return R.ok(); + } + + /** + * 清除指定用户的登录失败锁定状态。 + * + * @param userName 用户名 + * @return 操作结果 + */ + @SaCheckPermission("monitor:logininfo:unlock") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @RepeatSubmit() + @GetMapping("/unlock/{userName}") + public R unlock(@PathVariable("userName") String userName) { + String loginName = CacheNames.PWD_ERR_CNT_KEY + userName; + if (RedisUtils.hasKey(loginName)) { + RedisUtils.deleteObject(loginName); + } + return R.ok(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java new file mode 100644 index 000000000..edf4bb222 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java @@ -0,0 +1,88 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.baomidou.lock.annotation.Lock4j; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; +import org.dromara.system.service.ISysOperLogService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 操作日志记录 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/operlog") +public class SysOperlogController extends BaseController { + + private final ISysOperLogService operLogService; + + /** + * 分页查询操作日志记录。 + * + * @param operLog 查询条件 + * @param pageQuery 分页参数 + * @return 操作日志分页结果 + */ + @SaCheckPermission("monitor:operlog:list") + @GetMapping("/list") + public R> list(SysOperLogBo operLog, PageQuery pageQuery) { + return R.ok(operLogService.selectPageOperLogList(operLog, pageQuery)); + } + + /** + * 导出操作日志记录列表。 + * + * @param operLog 查询条件 + * @param response HTTP 响应 + */ + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:operlog:export") + @PostMapping("/export") + public void export(SysOperLogBo operLog, HttpServletResponse response) { + List list = operLogService.selectOperLogList(operLog); + ExcelBuilder.of(list, SysOperLogVo.class).sheetName("操作日志").toResponse(response); + } + + /** + * 批量删除操作日志记录 + * + * @param operIds 日志ids + * @return 操作结果 + */ + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/{operIds}") + public R remove(@PathVariable Long[] operIds) { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + + /** + * 清空操作日志记录。 + * + * @return 操作结果 + */ + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @SaCheckPermission("monitor:operlog:remove") + @Lock4j + @DeleteMapping("/clean") + public R clean() { + operLogService.cleanOperLog(); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java new file mode 100644 index 000000000..77f5097aa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,142 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ThreadUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.api.domain.UserOnlineDTO; +import org.dromara.system.domain.SysUserOnline; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +/** + * 在线用户监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController { + + /** + * 获取在线用户监控列表,并按 IP 或用户名条件过滤当前有效会话。 + * + * @param ipaddr IP地址 + * @param userName 用户名 + * @return 在线用户分页数据 + */ + @SaCheckPermission("monitor:online:list") + @GetMapping("/list") + public R> list(String ipaddr, String userName) { + // 获取所有未过期的 token + Collection keys = RedisUtils.keys(CacheNames.ONLINE_TOKEN_KEY + "*"); + List> suppliers = keys.stream().map(key -> (Supplier) () -> { + String token = StringUtils.substringAfterLast(key, StringUtils.COLON); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return null; + } + return RedisUtils.getCacheObject(CacheNames.ONLINE_TOKEN_KEY + token); + }).toList(); + List userOnlineDTOList = ThreadUtils.virtualSubmitAll(suppliers); + userOnlineDTOList.removeAll(Collections.singleton(null)); + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) && + StringUtils.equals(userName, userOnline.getUserName()) + ); + } else if (StringUtils.isNotEmpty(ipaddr)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) + ); + } else if (StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(userName, userOnline.getUserName()) + ); + } + Collections.reverse(userOnlineDTOList); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return R.ok(PageResult.build(userOnlineList)); + } + + /** + * 按 token 强制用户下线,适用于管理员踢除异常会话。 + * + * @param tokenId token值 + * @return 操作结果 + */ + @SaCheckPermission("monitor:online:forceLogout") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @RepeatSubmit() + @DeleteMapping("/{tokenId}") + public R forceLogout(@PathVariable String tokenId) { + try { + StpUtil.kickoutByTokenValue(tokenId); + } catch (NotLoginException ignored) { + } + return R.ok(); + } + + /** + * 获取当前登录用户的在线设备列表,仅返回当前账号仍有效的 token 会话。 + * + * @return 当前用户在线设备列表 + */ + @GetMapping() + public R> getInfo() { + // 获取指定账号 id 的 token 集合 + List tokenIds = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString()); + List> suppliers = tokenIds.stream().map(token -> (Supplier) () -> { + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return null; + } + return RedisUtils.getCacheObject(CacheNames.ONLINE_TOKEN_KEY + token); + }).toList(); + List userOnlineDTOList = ThreadUtils.virtualSubmitAll(suppliers); + //复制和处理 SysUserOnline 对象列表 + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return R.ok(PageResult.build(userOnlineList)); + } + + /** + * 强退当前账号下指定在线设备,避免误踢其他账号的会话。 + * + * @param tokenId token值 + * @return 操作结果 + */ + @Log(title = "在线设备", businessType = BusinessType.FORCE) + @RepeatSubmit() + @DeleteMapping("/myself/{tokenId}") + public R remove(@PathVariable("tokenId") String tokenId) { + try { + // 获取指定账号 id 的 token 集合 + List keys = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString()); + keys.stream() + .filter(key -> key.equals(tokenId)) + .findFirst() + .ifPresent(key -> StpUtil.kickoutByTokenValue(tokenId)); + } catch (NotLoginException ignored) { + } + return R.ok(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java new file mode 100644 index 000000000..a30339d94 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java @@ -0,0 +1,140 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysClientBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.service.ISysClientService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 客户端管理 + * + * @author Michelle.Chung + * @date 2023-06-18 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/client") +public class SysClientController extends BaseController { + + private final ISysClientService sysClientService; + + /** + * 分页查询客户端管理列表。 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 客户端分页数据 + */ + @SaCheckPermission("system:client:list") + @GetMapping("/list") + public R> list(SysClientBo bo, PageQuery pageQuery) { + return R.ok(sysClientService.queryPageList(bo, pageQuery)); + } + + /** + * 导出客户端管理列表,便于离线审计与配置核查。 + * + * @param bo 查询条件 + * @param response 响应流 + */ + @SaCheckPermission("system:client:export") + @Log(title = "客户端管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysClientBo bo, HttpServletResponse response) { + List list = sysClientService.queryList(bo); + ExcelBuilder.of(list, SysClientVo.class).sheetName("客户端管理").toResponse(response); + } + + /** + * 获取单个客户端的详细配置信息。 + * + * @param id 主键 + * @return 客户端详情 + */ + @SaCheckPermission("system:client:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(sysClientService.queryById(id)); + } + + /** + * 新增客户端配置,入库前先校验客户端 key 是否唯一。 + * + * @param bo 客户端信息 + * @return 操作结果 + */ + @SaCheckPermission("system:client:add") + @Log(title = "客户端管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysClientBo bo) { + if (!sysClientService.checkClickKeyUnique(bo)) { + return R.fail("新增客户端'" + bo.getClientKey() + "'失败,客户端key已存在"); + } + return toAjax(sysClientService.insertByBo(bo)); + } + + /** + * 修改客户端配置,避免重复占用同一个客户端 key。 + * + * @param bo 客户端信息 + * @return 操作结果 + */ + @SaCheckPermission("system:client:edit") + @Log(title = "客户端管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysClientBo bo) { + if (!sysClientService.checkClickKeyUnique(bo)) { + return R.fail("修改客户端'" + bo.getClientKey() + "'失败,客户端key已存在"); + } + return toAjax(sysClientService.updateByBo(bo)); + } + + /** + * 修改客户端启停状态。 + * + * @param bo 客户端状态信息 + * @return 操作结果 + */ + @SaCheckPermission("system:client:edit") + @Log(title = "客户端管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysClientBo bo) { + return toAjax(sysClientService.updateClientStatus(bo.getClientId(), bo.getStatus())); + } + + /** + * 批量删除客户端配置。 + * + * @param ids 主键串 + * @return 操作结果 + */ + @SaCheckPermission("system:client:remove") + @Log(title = "客户端管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(sysClientService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java new file mode 100644 index 000000000..b3f2cf1a0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java @@ -0,0 +1,163 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; +import org.dromara.system.service.ISysConfigService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; + +/** + * 参数配置 信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/config") +public class SysConfigController extends BaseController { + + private final ISysConfigService configService; + + /** + * 分页查询参数配置列表。 + * + * @param config 查询条件 + * @param pageQuery 分页参数 + * @return 参数配置分页结果 + */ + @SaCheckPermission("system:config:list") + @GetMapping("/list") + public R> list(SysConfigBo config, PageQuery pageQuery) { + return R.ok(configService.selectPageConfigList(config, pageQuery)); + } + + /** + * 导出参数配置列表。 + * + * @param config 查询条件 + * @param response HTTP 响应 + */ + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:config:export") + @PostMapping("/export") + public void export(SysConfigBo config, HttpServletResponse response) { + List list = configService.selectConfigList(config); + ExcelBuilder.of(list, SysConfigVo.class).sheetName("参数数据").toResponse(response); + } + + /** + * 根据参数编号获取详细信息 + * + * @param configId 参数ID + * @return 参数配置详情 + */ + @SaCheckPermission("system:config:query") + @GetMapping(value = "/{configId}") + public R getInfo(@PathVariable Long configId) { + return R.ok(configService.selectConfigById(configId)); + } + + /** + * 根据参数键名查询参数值 + * + * @param configKey 参数Key + * @return 参数值 + */ + @GetMapping(value = "/configKey/{configKey}") + public R getConfigKey(@PathVariable String configKey) { + return R.data(configService.selectConfigByKey(configKey)); + } + + /** + * 新增参数配置。 + * + * @param config 参数配置 + * @return 操作结果 + */ + @SaCheckPermission("system:config:add") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysConfigBo config) { + if (!configService.checkConfigKeyUnique(config)) { + return R.fail("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.insertConfig(config); + return R.ok(); + } + + /** + * 修改参数配置。 + * + * @param config 参数配置 + * @return 操作结果 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysConfigBo config) { + if (!configService.checkConfigKeyUnique(config)) { + return R.fail("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.updateConfig(config); + return R.ok(); + } + + /** + * 根据参数键名修改参数配置。 + * + * @param config 参数配置 + * @return 操作结果 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/updateByKey") + public R updateByKey(@RequestBody SysConfigBo config) { + configService.updateConfig(config); + return R.ok(); + } + + /** + * 删除参数配置 + * + * @param configIds 参数ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public R remove(@PathVariable Long[] configIds) { + configService.deleteConfigByIds(Arrays.asList(configIds)); + return R.ok(); + } + + /** + * 刷新参数缓存。 + * + * @return 操作结果 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + configService.resetConfigCache(); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java new file mode 100644 index 000000000..3cb375fe7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java @@ -0,0 +1,159 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysPostService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 部门信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dept") +public class SysDeptController extends BaseController { + + private final ISysDeptService deptService; + private final ISysPostService postService; + + /** + * 查询部门列表。 + * + * @param dept 查询条件 + * @return 部门列表 + */ + @SaCheckPermission("system:dept:list") + @GetMapping("/list") + public R> list(SysDeptBo dept) { + List depts = deptService.selectDeptList(dept); + return R.ok(depts); + } + + /** + * 查询部门列表(排除节点) + * + * @param deptId 部门ID + * @return 过滤后的部门列表 + */ + @SaCheckPermission("system:dept:list") + @GetMapping("/list/exclude/{deptId}") + public R> excludeChild(@PathVariable(value = "deptId") Long deptId) { + List depts = deptService.selectDeptList(new SysDeptBo()); + depts.removeIf(d -> d.getDeptId().equals(deptId) + || StringUtils.splitList(d.getAncestors()).contains(Convert.toStr(deptId))); + return R.ok(depts); + } + + /** + * 根据部门编号获取详细信息 + * + * @param deptId 部门ID + * @return 部门详情 + */ + @SaCheckPermission("system:dept:query") + @GetMapping(value = "/{deptId}") + public R getInfo(@PathVariable Long deptId) { + deptService.checkDeptDataScope(deptId); + return R.ok(deptService.selectDeptById(deptId)); + } + + /** + * 新增部门。 + * + * @param dept 部门参数 + * @return 操作结果 + */ + @SaCheckPermission("system:dept:add") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysDeptBo dept) { + if (!deptService.checkDeptNameUnique(dept)) { + return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + return toAjax(deptService.insertDept(dept)); + } + + /** + * 修改部门。 + * + * @param dept 部门参数 + * @return 操作结果 + */ + @SaCheckPermission("system:dept:edit") + @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysDeptBo dept) { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (!deptService.checkDeptNameUnique(dept)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } else if (dept.getParentId().equals(deptId)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } else if (StringUtils.equals(SystemConstants.DISABLE, dept.getStatus())) { + if (deptService.selectNormalChildrenDeptById(deptId) > 0) { + return R.fail("该部门包含未停用的子部门!"); + } else if (deptService.checkDeptExistUser(deptId)) { + return R.fail("该部门下存在已分配用户,不能禁用!"); + } + } + return toAjax(deptService.updateDept(dept)); + } + + /** + * 删除部门 + * + * @param deptId 部门ID + * @return 操作结果 + */ + @SaCheckPermission("system:dept:remove") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public R remove(@PathVariable Long deptId) { + if (SystemConstants.DEFAULT_DEPT_ID.equals(deptId)) { + return R.warn("默认部门,不允许删除"); + } + if (deptService.hasChildByDeptId(deptId)) { + return R.warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) { + return R.warn("部门存在用户,不允许删除"); + } + if (postService.countPostByDeptId(deptId) > 0) { + return R.warn("部门存在岗位,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } + + /** + * 获取部门选择框列表 + * + * @param deptIds 部门ID串 + * @return 部门列表 + */ + @SaCheckPermission("system:dept:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] deptIds) { + return R.ok(deptService.selectDeptByIds(deptIds == null ? null : List.of(deptIds))); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java new file mode 100644 index 000000000..bd7ee7170 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java @@ -0,0 +1,143 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.system.service.ISysDictTypeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 数据字典信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/data") +public class SysDictDataController extends BaseController { + + private final ISysDictDataService dictDataService; + private final ISysDictTypeService dictTypeService; + + /** + * 分页查询字典数据列表。 + * + * @param dictData 查询条件 + * @param pageQuery 分页参数 + * @return 字典数据分页结果 + */ + @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public R> list(SysDictDataBo dictData, PageQuery pageQuery) { + return R.ok(dictDataService.selectPageDictDataList(dictData, pageQuery)); + } + + /** + * 导出字典数据列表。 + * + * @param dictData 查询条件 + * @param response HTTP 响应 + */ + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictDataBo dictData, HttpServletResponse response) { + List list = dictDataService.selectDictDataList(dictData); + ExcelBuilder.of(list, SysDictDataVo.class).sheetName("字典数据").toResponse(response); + } + + /** + * 查询字典数据详细 + * + * @param dictCode 字典code + * @return 字典数据详情 + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictCode}") + public R getInfo(@PathVariable Long dictCode) { + return R.ok(dictDataService.selectDictDataById(dictCode)); + } + + /** + * 根据字典类型查询字典数据信息 + * + * @param dictType 字典类型 + * @return 字典数据列表 + */ + @GetMapping(value = "/type/{dictType}") + public R> dictType(@PathVariable String dictType) { + List data = dictTypeService.selectDictDataByType(dictType); + if (ObjectUtil.isNull(data)) { + data = new ArrayList<>(); + } + return R.ok(data); + } + + /** + * 新增字典数据。 + * + * @param dict 字典数据参数 + * @return 操作结果 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysDictDataBo dict) { + if (!dictDataService.checkDictDataUnique(dict)) { + return R.fail("新增字典数据'" + dict.getDictValue() + "'失败,字典键值已存在"); + } + dictDataService.insertDictData(dict); + return R.ok(); + } + + /** + * 修改字典数据。 + * + * @param dict 字典数据参数 + * @return 操作结果 + */ + @SaCheckPermission("system:dict:edit") + @Log(title = "字典数据", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysDictDataBo dict) { + if (!dictDataService.checkDictDataUnique(dict)) { + return R.fail("修改字典数据'" + dict.getDictValue() + "'失败,字典键值已存在"); + } + dictDataService.updateDictData(dict); + return R.ok(); + } + + /** + * 删除字典数据 + * + * @param dictCodes 字典code串 + * @return 操作结果 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典数据", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public R remove(@PathVariable Long[] dictCodes) { + dictDataService.deleteDictDataByIds(Arrays.asList(dictCodes)); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java new file mode 100644 index 000000000..21c0581b8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java @@ -0,0 +1,150 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.baomidou.lock.annotation.Lock4j; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictTypeVo; +import org.dromara.system.service.ISysDictTypeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; + +/** + * 数据字典信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/type") +public class SysDictTypeController extends BaseController { + + private final ISysDictTypeService dictTypeService; + + /** + * 分页查询字典类型列表。 + * + * @param dictType 查询条件 + * @param pageQuery 分页参数 + * @return 字典类型分页结果 + */ + @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public R> list(SysDictTypeBo dictType, PageQuery pageQuery) { + return R.ok(dictTypeService.selectPageDictTypeList(dictType, pageQuery)); + } + + /** + * 导出字典类型列表。 + * + * @param dictType 查询条件 + * @param response HTTP 响应 + */ + @Log(title = "字典类型", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictTypeBo dictType, HttpServletResponse response) { + List list = dictTypeService.selectDictTypeList(dictType); + ExcelBuilder.of(list, SysDictTypeVo.class).sheetName("字典类型").toResponse(response); + } + + /** + * 查询字典类型详细 + * + * @param dictId 字典ID + * @return 字典类型详情 + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictId}") + public R getInfo(@PathVariable Long dictId) { + return R.ok(dictTypeService.selectDictTypeById(dictId)); + } + + /** + * 新增字典类型。 + * + * @param dict 字典类型参数 + * @return 操作结果 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典类型", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysDictTypeBo dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return R.fail("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.insertDictType(dict); + return R.ok(); + } + + /** + * 修改字典类型。 + * + * @param dict 字典类型参数 + * @return 操作结果 + */ + @SaCheckPermission("system:dict:edit") + @Log(title = "字典类型", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysDictTypeBo dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return R.fail("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.updateDictType(dict); + return R.ok(); + } + + /** + * 删除字典类型 + * + * @param dictIds 字典ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public R remove(@PathVariable Long[] dictIds) { + dictTypeService.deleteDictTypeByIds(Arrays.asList(dictIds)); + return R.ok(); + } + + /** + * 刷新字典缓存。 + * + * @return 操作结果 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @Lock4j + @DeleteMapping("/refreshCache") + public R refreshCache() { + dictTypeService.resetDictCache(); + return R.ok(); + } + + /** + * 获取字典类型下拉选择列表。 + * + * @return 字典类型列表 + */ + @GetMapping("/optionselect") + public R> optionselect() { + List dictTypes = dictTypeService.selectDictTypeAll(); + return R.ok(dictTypes); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java new file mode 100644 index 000000000..380d0ee2e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java @@ -0,0 +1,204 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.annotation.SaMode; +import cn.hutool.core.lang.tree.Tree; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; +import org.dromara.system.service.ISysMenuService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 菜单信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController { + + private final ISysMenuService menuService; + + /** + * 获取路由信息 + * + * @return 当前用户可访问的路由信息 + */ + @GetMapping("/getRouters") + public R> getRouters() { + List menus = menuService.selectMenuTreeByUserId(LoginHelper.getUserId()); + return R.ok(menuService.buildMenus(menus)); + } + + /** + * 查询菜单列表。 + * + * @param menu 查询条件 + * @return 菜单列表 + */ + @SaCheckRole(value = { + SystemConstants.SUPER_ADMIN_ROLE_KEY, + }, mode = SaMode.OR) + @SaCheckPermission("system:menu:list") + @GetMapping("/list") + public R> list(SysMenuBo menu) { + List menus = menuService.selectMenuList(menu, LoginHelper.getUserId()); + return R.ok(menus); + } + + /** + * 根据菜单编号获取详细信息 + * + * @param menuId 菜单ID + * @return 菜单详情 + */ + @SaCheckRole(value = { + SystemConstants.SUPER_ADMIN_ROLE_KEY, + }, mode = SaMode.OR) + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/{menuId}") + public R getInfo(@PathVariable Long menuId) { + return R.ok(menuService.selectMenuById(menuId)); + } + + /** + * 获取菜单下拉树列表。 + * + * @param menu 查询条件 + * @return 菜单树 + */ + @SaCheckPermission("system:menu:query") + @GetMapping("/treeselect") + public R>> treeselect(SysMenuBo menu) { + List menus = menuService.selectMenuList(menu, LoginHelper.getUserId()); + return R.ok(menuService.buildMenuTreeSelect(menus)); + } + + /** + * 加载对应角色菜单列表树 + * + * @param roleId 角色ID + * @return 角色菜单树及选中节点 + */ + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public R roleMenuTreeselect(@PathVariable("roleId") Long roleId) { + List menus = menuService.selectMenuList(LoginHelper.getUserId()); + MenuTreeSelectVo selectVo = new MenuTreeSelectVo( + menuService.selectMenuListByRoleId(roleId), + menuService.buildMenuTreeSelect(menus)); + return R.ok(selectVo); + } + + /** + * 新增菜单。 + * + * @param menu 菜单参数 + * @return 操作结果 + */ + @SaCheckRole(SystemConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:add") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysMenuBo menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (SystemConstants.YES.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (!menuService.checkRouteConfigUnique(menu)) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在"); + } + return toAjax(menuService.insertMenu(menu)); + } + + /** + * 修改菜单。 + * + * @param menu 菜单参数 + * @return 操作结果 + */ + @SaCheckRole(SystemConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:edit") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysMenuBo menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (SystemConstants.YES.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (menu.getMenuId().equals(menu.getParentId())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } else if (!menuService.checkRouteConfigUnique(menu)) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在"); + } + return toAjax(menuService.updateMenu(menu)); + } + + /** + * 删除菜单 + * + * @param menuId 菜单ID + * @return 操作结果 + */ + @SaCheckRole(SystemConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:remove") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public R remove(@PathVariable("menuId") Long menuId) { + if (menuService.hasChildByMenuId(menuId)) { + return R.warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) { + return R.warn("菜单已分配,不允许删除"); + } + return toAjax(menuService.deleteMenuById(menuId)); + } + + /** + * 角色菜单列表树信息 + * + * @param checkedKeys 选中菜单列表 + * @param menus 菜单下拉树结构列表 + */ + public record MenuTreeSelectVo(List checkedKeys, List> menus) { + } + + /** + * 批量级联删除菜单 + * + * @param menuIds 菜单ID串 + * @return 操作结果 + */ + @SaCheckRole(SystemConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:remove") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/cascade/{menuIds}") + public R remove(@PathVariable("menuIds") Long[] menuIds) { + List menuIdList = List.of(menuIds); + if (menuService.hasChildByMenuId(menuIdList)) { + return R.warn("存在子菜单,不允许删除"); + } + menuService.deleteMenuById(menuIdList); + return R.ok(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMessageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMessageController.java new file mode 100644 index 000000000..ba2e74a3e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMessageController.java @@ -0,0 +1,34 @@ +package org.dromara.system.controller.system; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.vo.SysMessageBoxVo; +import org.dromara.system.service.ISysMessageService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 消息记录控制器 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/resource/message") +public class SysMessageController extends BaseController { + + private final ISysMessageService messageService; + + /** + * 查询当前用户消息盒子数据 + * + * @return 消息盒子数据 + */ + @GetMapping("/box") + public R getBox() { + return R.ok(messageService.queryMessageBox(LoginHelper.getUserId())); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java new file mode 100644 index 000000000..fc36cfcb1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java @@ -0,0 +1,125 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.enums.PushSourceEnum; +import org.dromara.common.core.enums.PushTypeEnum; +import org.dromara.common.core.service.DictService; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.api.MessageService; +import org.dromara.system.api.domain.PushPayloadDTO; +import org.dromara.system.domain.bo.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; +import org.dromara.system.service.ISysNoticeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * 公告 信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/notice") +public class SysNoticeController extends BaseController { + + private final ISysNoticeService noticeService; + private final DictService dictService; + private final MessageService messageService; + + /** + * 分页查询通知公告列表。 + * + * @param notice 查询条件 + * @param pageQuery 分页参数 + * @return 公告分页结果 + */ + @SaCheckPermission("system:notice:list") + @GetMapping("/list") + public R> list(SysNoticeBo notice, PageQuery pageQuery) { + return R.ok(noticeService.selectPageNoticeList(notice, pageQuery)); + } + + /** + * 根据通知公告编号获取详细信息 + * + * @param noticeId 公告ID + * @return 公告详情 + */ + @SaCheckPermission("system:notice:query") + @GetMapping(value = "/{noticeId}") + public R getInfo(@PathVariable Long noticeId) { + return R.ok(noticeService.selectNoticeById(noticeId)); + } + + /** + * 新增通知公告,并向在线用户广播公告摘要。 + * + * @param notice 公告参数 + * @return 操作结果 + */ + @SaCheckPermission("system:notice:add") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysNoticeBo notice) { + int rows = noticeService.insertNotice(notice); + if (rows <= 0) { + return R.fail(); + } + String type = dictService.getDictLabel("sys_notice_type", notice.getNoticeType()); + Map data = new HashMap<>(4); + data.put("noticeType", notice.getNoticeType()); + data.put("noticeTypeLabel", type); + data.put("noticeTitle", notice.getNoticeTitle()); + data.put("noticeId", notice.getNoticeId()); + data.put("noticeContent", notice.getNoticeContent()); + data.put("status", notice.getStatus()); + messageService.publishAll(PushPayloadDTO.of( + PushTypeEnum.NOTICE, + PushSourceEnum.NOTICE, + "[" + type + "] " + notice.getNoticeTitle(), + data, + "/system/notice?noticeId=" + notice.getNoticeId() + )); + return R.ok(); + } + + /** + * 修改通知公告。 + * + * @param notice 公告参数 + * @return 操作结果 + */ + @SaCheckPermission("system:notice:edit") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysNoticeBo notice) { + return toAjax(noticeService.updateNotice(notice)); + } + + /** + * 删除通知公告 + * + * @param noticeIds 公告ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:notice:remove") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public R remove(@PathVariable Long[] noticeIds) { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java new file mode 100644 index 000000000..d633a3ce8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java @@ -0,0 +1,121 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; +import org.dromara.system.service.ISysOssConfigService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 对象存储配置 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/resource/oss/config") +public class SysOssConfigController extends BaseController { + + private final ISysOssConfigService ossConfigService; + + /** + * 分页查询对象存储配置列表。 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 配置分页数据 + */ + @SaCheckPermission("system:ossConfig:list") + @GetMapping("/list") + public R> list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) { + return R.ok(ossConfigService.queryPageList(bo, pageQuery)); + } + + /** + * 获取单个对象存储配置详情。 + * + * @param ossConfigId OSS配置ID + * @return 配置详情 + */ + @SaCheckPermission("system:ossConfig:list") + @GetMapping("/{ossConfigId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long ossConfigId) { + return R.ok(ossConfigService.queryById(ossConfigId)); + } + + /** + * 新增对象存储配置。 + * + * @param bo 配置信息 + * @return 操作结果 + */ + @SaCheckPermission("system:ossConfig:add") + @Log(title = "对象存储配置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.insertByBo(bo)); + } + + /** + * 修改对象存储配置。 + * + * @param bo 配置信息 + * @return 操作结果 + */ + @SaCheckPermission("system:ossConfig:edit") + @Log(title = "对象存储配置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.updateByBo(bo)); + } + + /** + * 批量删除对象存储配置。 + * + * @param ossConfigIds OSS配置ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:ossConfig:remove") + @Log(title = "对象存储配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossConfigIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossConfigIds) { + return toAjax(ossConfigService.deleteWithValidByIds(List.of(ossConfigIds), true)); + } + + /** + * 切换对象存储配置启用状态,并同步更新当前生效配置。 + * + * @param bo 状态变更信息 + * @return 操作结果 + */ + @SaCheckPermission("system:ossConfig:edit") + @Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.updateOssConfigStatus(bo)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java new file mode 100644 index 000000000..94aa490a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java @@ -0,0 +1,119 @@ +package org.dromara.system.controller.system; + + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.validation.constraints.NotEmpty; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysOssExt; +import org.dromara.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +/** + * 文件上传 控制层 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/resource/oss") +public class SysOssController extends BaseController { + + private final ISysOssService ossService; + + /** + * 分页查询 OSS 对象存储列表。 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return OSS 分页结果 + */ + @SaCheckPermission("system:oss:list") + @GetMapping("/list") + public R> list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) { + return R.ok(ossService.queryPageList(bo, pageQuery)); + } + + /** + * 查询OSS对象基于id串 + * + * @param ossIds OSS对象ID串 + * @return OSS 对象列表 + */ + @SaCheckPermission("system:oss:query") + @GetMapping("/listByIds/{ossIds}") + public R> listByIds(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + List list = ossService.listByIds(Arrays.asList(ossIds)); + return R.ok(list); + } + + /** + * 上传OSS对象存储 + * + * @param file 文件 + * @return 上传结果 + */ + @SaCheckPermission("system:oss:upload") + @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) + @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R upload(@RequestPart("file") MultipartFile file, @RequestParam(value = "ossExt", required = false) String ossExtJson) { + SysOssVo oss = ossService.upload(file, JsonUtils.parseObject(ossExtJson, SysOssExt.class)); + SysOssUploadVo uploadVo = new SysOssUploadVo(oss.getUrl(), oss.getOriginalName(), oss.getOssId().toString()); + return R.ok(uploadVo); + } + + /** + * 下载OSS对象 + * + * @param ossId OSS对象ID + * @throws IOException IO 异常 + */ + @SaCheckPermission("system:oss:download") + @GetMapping("/download/{ossId}") + public ResponseEntity download(@PathVariable Long ossId) throws IOException { + return ossService.download(ossId); + } + + /** + * 删除OSS对象存储 + * + * @param ossIds OSS对象ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:oss:remove") + @Log(title = "OSS对象存储", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + return toAjax(ossService.deleteWithValidByIds(List.of(ossIds), true)); + } + + /** + * OSS 上传响应对象。 + * + * @param url 文件访问地址 + * @param fileName 原始文件名 + * @param ossId OSS 对象 ID + */ + public record SysOssUploadVo(String url, String fileName, String ossId) { + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java new file mode 100644 index 000000000..04203978b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java @@ -0,0 +1,170 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysPostService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 岗位信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/post") +public class SysPostController extends BaseController { + + private final ISysPostService postService; + private final ISysDeptService deptService; + + /** + * 分页查询岗位列表。 + * + * @param post 查询条件 + * @param pageQuery 分页参数 + * @return 岗位分页结果 + */ + @SaCheckPermission("system:post:list") + @GetMapping("/list") + public R> list(SysPostBo post, PageQuery pageQuery) { + return R.ok(postService.selectPagePostList(post, pageQuery)); + } + + /** + * 导出岗位列表。 + * + * @param post 查询条件 + * @param response HTTP 响应 + */ + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:post:export") + @PostMapping("/export") + public void export(SysPostBo post, HttpServletResponse response) { + List list = postService.selectPostList(post); + ExcelBuilder.of(list, SysPostVo.class).sheetName("岗位数据").toResponse(response); + } + + /** + * 根据岗位编号获取详细信息 + * + * @param postId 岗位ID + * @return 岗位详情 + */ + @SaCheckPermission("system:post:query") + @GetMapping(value = "/{postId}") + public R getInfo(@PathVariable Long postId) { + return R.ok(postService.selectPostById(postId)); + } + + /** + * 新增岗位。 + * + * @param post 岗位参数 + * @return 操作结果 + */ + @SaCheckPermission("system:post:add") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysPostBo post) { + if (!postService.checkPostNameUnique(post)) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + return toAjax(postService.insertPost(post)); + } + + /** + * 修改岗位。 + * + * @param post 岗位参数 + * @return 操作结果 + */ + @SaCheckPermission("system:post:edit") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysPostBo post) { + if (!postService.checkPostNameUnique(post)) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } else if (SystemConstants.DISABLE.equals(post.getStatus()) + && postService.countUserPostById(post.getPostId()) > 0) { + return R.fail("该岗位下存在已分配用户,不能禁用!"); + } + return toAjax(postService.updatePost(post)); + } + + /** + * 删除岗位 + * + * @param postIds 岗位ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:post:remove") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public R remove(@PathVariable Long[] postIds) { + return toAjax(postService.deletePostByIds(Arrays.asList(postIds))); + } + + /** + * 获取岗位选择框列表 + * + * @param postIds 岗位ID串 + * @param deptId 部门id + * @return 岗位列表 + */ + @SaCheckPermission("system:post:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] postIds, @RequestParam(required = false) Long deptId) { + List list = new ArrayList<>(); + if (ObjectUtil.isNotNull(deptId)) { + SysPostBo post = new SysPostBo(); + post.setDeptId(deptId); + list = postService.selectPostList(post); + } else if (postIds != null) { + list = postService.selectPostByIds(List.of(postIds)); + } + return R.ok(list); + } + + /** + * 获取岗位筛选用的部门树。 + * + * @param dept 部门查询条件 + * @return 部门树列表 + */ + @SaCheckPermission("system:post:list") + @GetMapping("/deptTree") + public R>> deptTree(SysDeptBo dept) { + return R.ok(deptService.selectDeptTreeList(dept)); + } + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java new file mode 100644 index 000000000..05ed5e3f8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java @@ -0,0 +1,126 @@ +package org.dromara.system.controller.system; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.crypto.digest.BCrypt; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.bo.SysUserProfileBo; +import org.dromara.system.domain.vo.ProfileUserVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 个人信息 业务处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user/profile") +public class SysProfileController extends BaseController { + + private final ISysUserService userService; + + /** + * 获取当前登录用户的个人中心信息。 + * + * @return 用户信息、角色组和岗位组 + */ + @GetMapping + public R profile() { + SysUserVo user = userService.selectUserById(LoginHelper.getUserId()); + String roleGroup = userService.selectUserRoleGroup(user.getUserId()); + String postGroup = userService.selectUserPostGroup(user.getUserId()); + // 单独做一个vo专门给个人中心用 避免数据被脱敏 + ProfileUserVo profileUser = BeanUtil.toBean(user, ProfileUserVo.class); + ProfileVo profileVo = new ProfileVo(profileUser, roleGroup, postGroup); + return R.ok(profileVo); + } + + /** + * 修改当前登录用户的个人资料。 + * + * @param profile 个人资料参数 + * @return 操作结果 + */ + @RepeatSubmit + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public R updateProfile(@Validated @RequestBody SysUserProfileBo profile) { + SysUserBo user = BeanUtil.toBean(profile, SysUserBo.class); + user.setUserId(LoginHelper.getUserId()); + String username = LoginHelper.getUsername(); + if (StringUtils.isNotEmpty(user.getPhoneNumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("修改用户'" + username + "'失败,手机号码已存在"); + } + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("修改用户'" + username + "'失败,邮箱账号已存在"); + } + int rows = DataPermissionHelper.ignore(() -> userService.updateUserProfile(user)); + if (rows > 0) { + return R.ok(); + } + return R.fail("修改个人信息异常,请联系管理员"); + } + + /** + * 重置密码 + * + * @param bo 新旧密码 + * @return 操作结果 + */ + @RepeatSubmit + @ApiEncrypt + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping("/updatePwd") + public R updatePwd(@Validated @RequestBody SysUserPasswordBo bo) { + SysUserVo user = userService.selectUserById(LoginHelper.getUserId()); + String password = user.getPassword(); + if (!BCrypt.checkpw(bo.oldPassword(), password)) { + return R.fail("修改密码失败,旧密码错误"); + } + if (BCrypt.checkpw(bo.newPassword(), password)) { + return R.fail("新密码不能与旧密码相同"); + } + int rows = DataPermissionHelper.ignore(() -> userService.resetUserPwd(user.getUserId(), BCrypt.hashpw(bo.newPassword()))); + if (rows > 0) { + return R.ok(); + } + return R.fail("修改密码异常,请联系管理员"); + } + + /** + * 用户个人信息 + * + * @param user 用户信息 + * @param roleGroup 用户所属角色组 + * @param postGroup 用户所属岗位组 + */ + public record ProfileVo(ProfileUserVo user, String roleGroup, String postGroup) { + } + + /** + * 用户密码修改 + * + * @param oldPassword 旧密码 + * @param newPassword 新密码 + */ + public record SysUserPasswordBo( + @NotBlank(message = "旧密码不能为空") String oldPassword, + @NotBlank(message = "新密码不能为空") String newPassword) { + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java new file mode 100644 index 000000000..e25b16ea6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java @@ -0,0 +1,294 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.event.OnlineUserCleanEvent; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysRoleService; +import org.dromara.system.service.ISysUserService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.List; + +/** + * 角色信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/role") +public class SysRoleController extends BaseController { + + private final ISysRoleService roleService; + private final ISysUserService userService; + private final ISysDeptService deptService; + + /** + * 分页查询角色列表。 + * + * @param role 查询条件 + * @param pageQuery 分页参数 + * @return 角色分页结果 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/list") + public R> list(SysRoleBo role, PageQuery pageQuery) { + return R.ok(roleService.selectPageRoleList(role, pageQuery)); + } + + /** + * 导出角色信息列表。 + * + * @param role 查询条件 + * @param response HTTP 响应 + */ + @Log(title = "角色管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:role:export") + @PostMapping("/export") + public void export(SysRoleBo role, HttpServletResponse response) { + List list = roleService.selectRoleList(role); + ExcelBuilder.of(list, SysRoleVo.class).sheetName("角色数据").toResponse(response); + } + + /** + * 根据角色编号获取详细信息 + * + * @param roleId 角色ID + * @return 角色详情 + */ + @SaCheckPermission("system:role:query") + @GetMapping(value = "/{roleId}") + public R getInfo(@PathVariable Long roleId) { + roleService.checkRoleDataScope(roleId); + return R.ok(roleService.selectRoleById(roleId)); + } + + /** + * 新增角色。 + * + * @param role 角色参数 + * @return 操作结果 + */ + @SaCheckPermission("system:role:add") + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + if (!roleService.checkRoleNameUnique(role)) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + return toAjax(roleService.insertRole(role)); + + } + + /** + * 修改角色基础信息(不包含菜单权限、数据权限)。 + * + * @param role 角色参数 + * @return 操作结果 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (!roleService.checkRoleNameUnique(role)) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + + if (roleService.updateRoleBaseInfo(role) > 0) { + SpringUtils.context().publishEvent(OnlineUserCleanEvent.byRole(role.getRoleId())); + return R.ok(); + } + return R.fail("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); + } + + /** + * 修改角色权限信息(菜单权限 + 数据权限)。 + * + * @param role 角色参数 + * @return 操作结果 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/permission") + public R editPermission(@RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (roleService.updateRolePermission(role) > 0) { + SpringUtils.context().publishEvent(OnlineUserCleanEvent.byRole(role.getRoleId())); + return R.ok(); + } + return R.fail("修改角色'" + role.getRoleName() + "'权限失败,请联系管理员"); + } + + /** + * 修改角色状态。 + * + * @param role 角色参数 + * @return 操作结果 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (roleService.updateRoleStatus(role.getRoleId(), role.getStatus()) > 0) { + SpringUtils.context().publishEvent(OnlineUserCleanEvent.byRole(role.getRoleId())); + return R.ok(); + } + return R.fail("修改角色'" + role.getRoleName() + "'状态失败,请联系管理员"); + } + + /** + * 删除角色 + * + * @param roleIds 角色ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:role:remove") + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public R remove(@PathVariable Long[] roleIds) { + return toAjax(roleService.deleteRoleByIds(List.of(roleIds))); + } + + /** + * 获取角色选择框列表 + * + * @param roleIds 角色ID串 + * @return 角色列表 + */ + @SaCheckPermission("system:role:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] roleIds) { + return R.ok(roleService.selectRoleByIds(roleIds == null ? null : List.of(roleIds))); + } + + /** + * 查询已分配用户角色列表。 + * + * @param user 查询条件 + * @param pageQuery 分页参数 + * @return 用户分页结果 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/allocatedList") + public R> allocatedList(SysUserBo user, PageQuery pageQuery) { + return R.ok(userService.selectAllocatedList(user, pageQuery)); + } + + /** + * 查询未分配用户角色列表。 + * + * @param user 查询条件 + * @param pageQuery 分页参数 + * @return 用户分页结果 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/unallocatedList") + public R> unallocatedList(SysUserBo user, PageQuery pageQuery) { + return R.ok(userService.selectUnallocatedList(user, pageQuery)); + } + + /** + * 取消授权用户。 + * + * @param userRole 用户角色关系 + * @return 操作结果 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @RepeatSubmit() + @PutMapping("/authUser/cancel") + public R cancelAuthUser(@RequestBody SysUserRole userRole) { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 批量取消授权用户 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @RepeatSubmit() + @PutMapping("/authUser/cancelAll") + public R cancelAuthUserAll(Long roleId, Long[] userIds) { + return toAjax(roleService.deleteAuthUsers(roleId, List.of(userIds))); + } + + /** + * 批量选择用户授权 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @RepeatSubmit() + @PutMapping("/authUser/selectAll") + public R selectAuthUserAll(Long roleId, Long[] userIds) { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, List.of(userIds))); + } + + /** + * 获取对应角色部门树列表 + * + * @param roleId 角色ID + * @return 角色部门树信息 + */ + @SaCheckPermission("system:role:list") + @GetMapping(value = "/deptTree/{roleId}") + public R roleDeptTreeselect(@PathVariable("roleId") Long roleId) { + DeptTreeSelectVo selectVo = new DeptTreeSelectVo( + deptService.selectDeptListByRoleId(roleId), + deptService.selectDeptTreeList(new SysDeptBo())); + return R.ok(selectVo); + } + + /** + * 角色部门列表树信息 + * + * @param checkedKeys 选中部门列表 + * @param depts 下拉树结构列表 + */ + public record DeptTreeSelectVo(Collection checkedKeys, List> depts) { + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java new file mode 100644 index 000000000..c07f90982 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java @@ -0,0 +1,40 @@ +package org.dromara.system.controller.system; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.service.ISysSocialService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 社会化关系 + * + * @author thiszhc + * @date 2023-06-16 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/social") +public class SysSocialController extends BaseController { + + private final ISysSocialService socialUserService; + + /** + * 查询当前登录用户的社会化账号绑定列表。 + * + * @return 绑定关系列表 + */ + @GetMapping("/list") + public R> list() { + return R.ok(socialUserService.queryListByUserId(LoginHelper.getUserId())); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java new file mode 100644 index 000000000..e55390194 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java @@ -0,0 +1,358 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.digest.BCrypt; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.api.model.LoginUser; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.*; +import org.dromara.system.listener.SysUserImportListener; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysPostService; +import org.dromara.system.service.ISysRoleService; +import org.dromara.system.service.ISysUserService; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用户信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user") +public class SysUserController extends BaseController { + + private final ISysUserService userService; + private final ISysRoleService roleService; + private final ISysPostService postService; + private final ISysDeptService deptService; + + /** + * 分页查询用户列表。 + * + * @param user 用户查询条件 + * @param pageQuery 分页参数 + * @return 用户分页列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/list") + public R> list(SysUserBo user, PageQuery pageQuery) { + return R.ok(userService.selectPageUserList(user, pageQuery)); + } + + /** + * 导出符合条件的用户列表。 + * + * @param user 用户查询条件 + * @param response HTTP 响应 + */ + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:user:export") + @PostMapping("/export") + public void export(SysUserBo user, HttpServletResponse response) { + List list = userService.selectUserExportList(user); + ExcelBuilder.of(list, SysUserExportVo.class).sheetName("用户数据").toResponse(response); + } + + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:user:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { + ExcelResult result = ExcelBuilder.read(file.getInputStream(), SysUserImportVo.class) + .listener(new SysUserImportListener(updateSupport)) + .doRead(); + return R.ok(result.getAnalysis()); + } + + /** + * 导出用户导入模板。 + * + * @param response HTTP 响应 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelBuilder.of(new ArrayList<>(), SysUserImportVo.class).sheetName("用户数据").toResponse(response); + } + + /** + * 获取用户信息 + * + * @return 当前登录用户信息、角色与权限集合 + */ + @GetMapping("/getInfo") + public R getInfo() { + UserInfoVo userInfoVo = new UserInfoVo(); + LoginUser loginUser = LoginHelper.getLoginUser(); + + SysUserVo user = DataPermissionHelper.ignore(() -> userService.selectUserById(loginUser.getUserId())); + if (ObjectUtil.isNull(user)) { + return R.fail("没有权限访问用户数据!"); + } + userInfoVo.setUser(user); + userInfoVo.setPermissions(loginUser.getMenuPermission()); + userInfoVo.setRoles(loginUser.getRolePermission()); + return R.ok(userInfoVo); + } + + /** + * 根据用户编号获取详细信息 + * + * @param userId 用户ID + * @return 用户详情、角色与岗位信息 + */ + @SaCheckPermission("system:user:query") + @GetMapping(value = {"/", "/{userId}"}) + public R getInfo(@PathVariable(value = "userId", required = false) Long userId) { + SysUserInfoVo userInfoVo = new SysUserInfoVo(); + if (ObjectUtil.isNotNull(userId)) { + userService.checkUserDataScope(userId); + SysUserVo sysUser = userService.selectUserById(userId); + userInfoVo.setUser(sysUser); + userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId)); + Long deptId = sysUser.getDeptId(); + if (ObjectUtil.isNotNull(deptId)) { + SysPostBo postBo = new SysPostBo(); + postBo.setDeptId(deptId); + userInfoVo.setPosts(postService.selectPostList(postBo)); + userInfoVo.setPostIds(postService.selectPostListByUserId(userId)); + } + } + SysRoleBo roleBo = new SysRoleBo(); + roleBo.setStatus(SystemConstants.NORMAL); + List roles = roleService.selectRoleList(roleBo); + userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin())); + return R.ok(userInfoVo); + } + + /** + * 新增用户。 + * + * @param user 用户新增参数 + * @return 操作结果 + */ + @SaCheckPermission("system:user:add") + @Log(title = "用户管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping + public R add(@Validated @RequestBody SysUserBo user) { + deptService.checkDeptDataScope(user.getDeptId()); + if (!userService.checkUserNameUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhoneNumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.insertUser(user)); + } + + /** + * 修改用户。 + * + * @param user 用户编辑参数 + * @return 操作结果 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping + public R edit(@Validated @RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + deptService.checkDeptDataScope(user.getDeptId()); + if (!userService.checkUserNameUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhoneNumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + return toAjax(userService.updateUser(user)); + } + + /** + * 删除用户 + * + * @param userIds 用户ID数组 + * @return 操作结果 + */ + @SaCheckPermission("system:user:remove") + @Log(title = "用户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public R remove(@PathVariable Long[] userIds) { + if (ArrayUtil.contains(userIds, LoginHelper.getUserId())) { + return R.fail("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + + /** + * 根据用户ID串批量获取用户基础信息 + * + * @param userIds 用户ID串 + * @param deptId 部门ID + * @return 用户基础信息列表 + */ + @SaCheckPermission("system:user:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] userIds, + @RequestParam(required = false) Long deptId) { + return R.ok(userService.selectUserByIds(ArrayUtil.isEmpty(userIds) ? null : List.of(userIds), deptId)); + } + + /** + * 重置指定用户密码。 + * + * @param user 用户参数 + * @return 操作结果 + */ + @ApiEncrypt + @SaCheckPermission("system:user:resetPwd") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/resetPwd") + public R resetPwd(@RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.resetUserPwd(user.getUserId(), user.getPassword())); + } + + /** + * 修改用户状态。 + * + * @param user 用户参数 + * @return 操作结果 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + return toAjax(userService.updateUserStatus(user.getUserId(), user.getStatus())); + } + + /** + * 解锁用户 + * + * @param userId 用户ID + * @return 操作结果 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户解锁", businessType = BusinessType.OTHER) + @RepeatSubmit() + @GetMapping("/unlock/{userId}") + public R unlock(@PathVariable Long userId) { + SysUserVo user = userService.selectUserById(userId); + if (ObjectUtil.isNull(user)) { + return R.fail("用户不存在"); + } + String loginName = CacheNames.PWD_ERR_CNT_KEY + user.getUserName(); + if (RedisUtils.hasKey(loginName)) { + RedisUtils.deleteObject(loginName); + } + return R.ok(); + } + + /** + * 根据用户编号获取授权角色 + * + * @param userId 用户ID + * @return 用户及其可授权角色信息 + */ + @SaCheckPermission("system:user:query") + @GetMapping("/authRole/{userId}") + public R authRole(@PathVariable Long userId) { + userService.checkUserDataScope(userId); + SysUserVo user = userService.selectUserById(userId); + List roles = roleService.selectRolesAuthByUserId(userId); + SysUserInfoVo userInfoVo = new SysUserInfoVo(); + userInfoVo.setUser(user); + userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin())); + return R.ok(userInfoVo); + } + + /** + * 用户授权角色 + * + * @param userId 用户Id + * @param roleIds 角色ID串 + * @return 操作结果 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @RepeatSubmit() + @PutMapping("/authRole") + public R insertAuthRole(Long userId, Long[] roleIds) { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return R.ok(); + } + + /** + * 获取用户筛选用的部门树。 + * + * @param dept 部门查询条件 + * @return 部门树列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/deptTree") + public R>> deptTree(SysDeptBo dept) { + return R.ok(deptService.selectDeptTreeList(dept)); + } + + /** + * 获取指定部门下的全部用户信息。 + * + * @param deptId 部门ID + * @return 用户列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/list/dept/{deptId}") + public R> listByDept(@PathVariable @NotNull Long deptId) { + return R.ok(userService.selectUserListByDept(deptId)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java new file mode 100644 index 000000000..c3ae5220a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java @@ -0,0 +1,89 @@ +package org.dromara.system.domain; + +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.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 授权管理对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_client") +public class SysClient extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private Long id; + + /** + * 客户端id + */ + private String clientId; + + /** + * 客户端key + */ + private String clientKey; + + /** + * 客户端秘钥 + */ + private String clientSecret; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 允许访问路径 + */ + private String accessPath; + + /** + * IP白名单 + */ + private String ipWhitelist; + + /** + * token活跃超时时间 + */ + private Long activeTimeout; + + /** + * token固定超时时间 + */ + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java new file mode 100644 index 000000000..60a4ced61 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java @@ -0,0 +1,51 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 参数配置表 sys_config + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_config") +public class SysConfig extends BaseEntity { + + /** + * 参数主键 + */ + @TableId(value = "config_id") + private Long configId; + + /** + * 参数名称 + */ + private String configName; + + /** + * 参数键名 + */ + private String configKey; + + /** + * 参数键值 + */ + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + private String configType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java new file mode 100644 index 000000000..5ad19db14 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java @@ -0,0 +1,92 @@ +package org.dromara.system.domain; + +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.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.ArrayList; +import java.util.List; + +/** + * 部门表 sys_dept + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dept") +public class SysDept extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门ID + */ + @TableId(value = "dept_id") + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 部门类别编码 + */ + private String deptCategory; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人 + */ + private Long leader; + + /** + * 联系电话 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 部门状态:0正常,1停用 + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 子部门 + */ + @TableField(exist = false) + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java new file mode 100644 index 000000000..dbf15bd1a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java @@ -0,0 +1,66 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 字典数据表 sys_dict_data + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_data") +public class SysDictData extends BaseEntity { + + /** + * 字典编码 + */ + @TableId(value = "dict_code") + private Long dictCode; + + /** + * 字典排序 + */ + private Integer dictSort; + + /** + * 字典标签 + */ + private String dictLabel; + + /** + * 字典键值 + */ + private String dictValue; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + private String cssClass; + + /** + * 表格字典样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + private String isDefault; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java new file mode 100644 index 000000000..c8f099b2e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java @@ -0,0 +1,41 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 字典类型表 sys_dict_type + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_type") +public class SysDictType extends BaseEntity { + + /** + * 字典主键 + */ + @TableId(value = "dict_id") + private Long dictId; + + /** + * 字典名称 + */ + private String dictName; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLoginInfo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLoginInfo.java new file mode 100644 index 000000000..6ccd7b035 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLoginInfo.java @@ -0,0 +1,80 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 系统访问记录表 sys_login_info + * + * @author Lion Li + */ + +@Data +@TableName("sys_login_info") +public class SysLoginInfo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "info_id") + private Long infoId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录状态 0成功 1失败 + */ + private String status; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 提示消息 + */ + private String msg; + + /** + * 访问时间 + */ + private LocalDateTime loginTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java new file mode 100644 index 000000000..e7f34917c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java @@ -0,0 +1,201 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.util.ArrayList; +import java.util.List; + +/** + * 菜单权限表 sys_menu + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_menu") +public class SysMenu extends BaseEntity { + + /** + * 菜单ID + */ + @TableId(value = "menu_id") + private Long menuId; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(Y是 N否) + */ + private String isFrame; + + /** + * 是否缓存(Y缓存 N不缓存) + */ + private String isCache; + + /** + * 类型(M目录 C菜单 F按钮) + */ + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限字符串 + */ + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 激活菜单路径 + */ + private String activeMenu; + + /** + * 扩展字段 + */ + private String ext; + + /** + * 备注 + */ + private String remark; + + /** + * 父菜单名称 + */ + @TableField(exist = false) + private String parentName; + + /** + * 子菜单 + */ + @TableField(exist = false) + private List children = new ArrayList<>(); + + /** + * 获取路由名称 + */ + public String getRouteName() { + String routerName = StringUtils.capitalize(path); + // 非外链并且是一级目录(类型为目录) + if (isMenuFrame()) { + routerName = StringUtils.EMPTY; + } + return routerName; + } + + /** + * 获取路由地址 + */ + public String getRouterPath() { + String routerPath = this.path; + // 内链打开外网方式 + if (!Constants.TOP_PARENT_ID.equals(getParentId()) && isInnerLink()) { + routerPath = innerLinkReplaceEach(routerPath); + } + // 非外链并且是一级目录(类型为目录) + if (Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_DIR.equals(getMenuType()) + && SystemConstants.NO.equals(getIsFrame())) { + routerPath = "/" + this.path; + } + // 非外链并且是一级目录(类型为菜单) + else if (isMenuFrame()) { + routerPath = "/"; + } + return routerPath; + } + + /** + * 获取组件信息 + */ + public String getComponentInfo() { + String component = SystemConstants.LAYOUT; + if (StringUtils.isNotEmpty(this.component) && !isMenuFrame()) { + component = this.component; + } else if (StringUtils.isEmpty(this.component) && !Constants.TOP_PARENT_ID.equals(getParentId()) && isInnerLink()) { + component = SystemConstants.INNER_LINK; + } else if (StringUtils.isEmpty(this.component) && isParentView()) { + component = SystemConstants.PARENT_VIEW; + } + return component; + } + + /** + * 是否为菜单内部跳转 + */ + public boolean isMenuFrame() { + return Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO); + } + + /** + * 是否为内链组件 + */ + public boolean isInnerLink() { + return isFrame.equals(SystemConstants.NO) && StringUtils.ishttp(path); + } + + /** + * 是否为parent_view组件 + */ + public boolean isParentView() { + return !Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_DIR.equals(menuType); + } + + /** + * 内链域名特殊字符替换 + */ + public static String innerLinkReplaceEach(String path) { + return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", StringUtils.COLON}, + new String[]{"", "", "", "/", "/"}); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessage.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessage.java new file mode 100644 index 000000000..176e187f9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessage.java @@ -0,0 +1,69 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 消息记录表 sys_message + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_message") +public class SysMessage extends BaseEntity { + + /** + * 消息ID + */ + @TableId(value = "message_id") + private Long messageId; + + /** + * 消息分组 + */ + private String category; + + /** + * 消息类型 + */ + private String type; + + /** + * 消息来源 + */ + private String source; + + /** + * 标题 + */ + private String title; + + /** + * 摘要消息 + */ + private String message; + + /** + * 详细内容 + */ + private String content; + + /** + * 扩展数据 JSON + */ + private String dataJson; + + /** + * 前端跳转路径 + */ + private String path; + + /** + * 目标用户ID串,0 表示全局 + */ + private String sendUserIds; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java new file mode 100644 index 000000000..9ef00a484 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java @@ -0,0 +1,51 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + + +/** + * 通知公告表 sys_notice + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_notice") +public class SysNotice extends BaseEntity { + + /** + * 公告ID + */ + @TableId(value = "notice_id") + private Long noticeId; + + /** + * 公告标题 + */ + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java new file mode 100644 index 000000000..fff077cdc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java @@ -0,0 +1,140 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 操作日志记录表 oper_log + * + * @author Lion Li + */ + +@Data +@TableName("sys_oper_log") +public class SysOperLog implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + @TableId(value = "oper_id") + private Long operId; + + /** + * 操作模块 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 请求方法 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 操作用户ID + */ + private Long userId; + + /** + * 操作部门ID + */ + private Long deptId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 请求url + */ + private String operUrl; + + /** + * 操作地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private LocalDateTime operTime; + + /** + * 消耗时间 + */ + private Long costTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java new file mode 100644 index 000000000..374844531 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java @@ -0,0 +1,55 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * OSS对象存储对象 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_oss") +public class SysOss extends BaseEntity { + + /** + * 对象存储主键 + */ + @TableId(value = "oss_id") + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 服务商 + */ + private String service; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java new file mode 100644 index 000000000..397eb926a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java @@ -0,0 +1,89 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 对象存储配置对象 sys_oss_config + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_oss_config") +public class SysOssConfig extends BaseEntity { + + /** + * 主键 + */ + @TableId(value = "oss_config_id") + private Long ossConfigId; + + /** + * 配置key + */ + private String configKey; + + /** + * accessKey + */ + private String accessKey; + + /** + * 秘钥 + */ + private String secretKey; + + /** + * 桶名称 + */ + private String bucketName; + + /** + * 前缀 + */ + private String prefix; + + /** + * 访问站点 + */ + private String endpoint; + + /** + * 自定义域名 + */ + private String domainUrl; + + /** + * 是否https(0否 1是) + */ + private String isHttps; + + /** + * 域 + */ + private String region; + + /** + * 是否默认(Y=是,N=否) + */ + private String status; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 备注 + */ + private String remark; + + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssExt.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssExt.java new file mode 100644 index 000000000..15a95e760 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssExt.java @@ -0,0 +1,75 @@ +package org.dromara.system.domain; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 附件扩展字段对象(存储在 SysOss.ext1 的 JSON 字符串中) + * + * @author AprilWind + */ +@Data +public class SysOssExt implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 所属业务类型(如 avatar、report、contract) + */ + private String bizType; + + /** + * 文件大小(单位:字节) + */ + private Long fileSize; + + /** + * 文件类型(MIME类型,如 image/png) + */ + private String contentType; + + /** + * 来源标识(如 userUpload、systemImport) + */ + private String source; + + /** + * 上传 IP 地址,便于审计和追踪 + */ + private String uploadIp; + + /** + * 附件说明或备注 + */ + private String remark; + + /** + * 附件标签,如 ["图片", "证件"] + */ + private List tags; + + /** + * 业务绑定ID(如某业务记录ID) + */ + private String refId; + + /** + * 绑定业务类型 + */ + private String refType; + + /** + * 是否为临时文件,用于区分正式或待清理 + */ + private Boolean isTemp; + + /** + * 文件MD5值(可用于去重或校验) + */ + private String md5; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java new file mode 100644 index 000000000..cf99b87f2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java @@ -0,0 +1,68 @@ +package org.dromara.system.domain; + +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.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 岗位表 sys_post + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_post") +public class SysPost extends BaseEntity { + + /** + * 岗位序号 + */ + @TableId(value = "post_id") + private Long postId; + + /** + * 部门id + */ + private Long deptId; + + /** + * 岗位编码 + */ + private String postCode; + + /** + * 岗位名称 + */ + private String postName; + + /** + * 岗位类别编码 + */ + private String postCategory; + + /** + * 岗位排序 + */ + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java new file mode 100644 index 000000000..d59ab4c39 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java @@ -0,0 +1,75 @@ +package org.dromara.system.domain; + +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 lombok.NoArgsConstructor; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 角色表 sys_role + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_role") +public class SysRole extends BaseEntity { + + /** + * 角色ID + */ + @TableId(value = "role_id") + private Long roleId; + + /** + * 角色名称 + */ + private String roleName; + + /** + * 角色权限 + */ + private String roleKey; + + /** + * 角色排序 + */ + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限) + */ + private String dataScope; + + /** + * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) + */ + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) + */ + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java new file mode 100644 index 000000000..ba77694e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 角色和部门关联 sys_role_dept + * + * @author Lion Li + */ + +@Data +@TableName("sys_role_dept") +public class SysRoleDept { + + /** + * 角色ID + */ + @TableId(type = IdType.INPUT) + private Long roleId; + + /** + * 部门ID + */ + private Long deptId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java new file mode 100644 index 000000000..ba28f172d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 角色和菜单关联 sys_role_menu + * + * @author Lion Li + */ + +@Data +@TableName("sys_role_menu") +public class SysRoleMenu { + + /** + * 角色ID + */ + @TableId(type = IdType.INPUT) + private Long roleId; + + /** + * 菜单ID + */ + private Long menuId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java new file mode 100644 index 000000000..6210036ab --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java @@ -0,0 +1,136 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 社会化关系对象 sys_social + * + * @author thiszhc + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_social") +public class SysSocial extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 的唯一ID + */ + private String authId; + + /** + * 用户来源 + */ + private String source; + + /** + * 用户的授权令牌 + */ + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 用户的 open id + */ + private String openId; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java new file mode 100644 index 000000000..75031c810 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java @@ -0,0 +1,125 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.time.LocalDateTime; + +/** + * 用户对象 sys_user + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_user") +public class SysUser extends BaseEntity { + + /** + * 用户ID + */ + @TableId(value = "user_id") + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + private String email; + + /** + * 手机号码 + */ + private String phoneNumber; + + /** + * 用户性别 + */ + private String gender; + + /** + * 用户头像 + */ + private Long avatar; + + /** + * 密码 + */ + @TableField( + insertStrategy = FieldStrategy.NOT_EMPTY, + updateStrategy = FieldStrategy.NOT_EMPTY, + whereStrategy = FieldStrategy.NOT_EMPTY + ) + private String password; + + /** + * 账号状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private LocalDateTime loginDate; + + /** + * 备注 + */ + private String remark; + + + /** + * 使用用户ID构造系统用户对象。 + * + * @param userId 用户ID + */ + public SysUser(Long userId) { + this.userId = userId; + } + + /** + * 判断当前用户是否为超级管理员。 + * + * @return true 是超级管理员 false 不是超级管理员 + */ + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_USER_ID.equals(this.userId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java new file mode 100644 index 000000000..f3b5f87a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java @@ -0,0 +1,63 @@ +package org.dromara.system.domain; + +import lombok.Data; + +/** + * 当前在线会话 + * + * @author Lion Li + */ +@Data +public class SysUserOnline { + + /** + * 会话编号 + */ + private String tokenId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 用户账号 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地址 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java new file mode 100644 index 000000000..119c11710 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 用户和岗位关联 sys_user_post + * + * @author Lion Li + */ + +@Data +@TableName("sys_user_post") +public class SysUserPost { + + /** + * 用户ID + */ + @TableId(type = IdType.INPUT) + private Long userId; + + /** + * 岗位ID + */ + private Long postId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java new file mode 100644 index 000000000..0a50e8071 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 用户和角色关联 sys_user_role + * + * @author Lion Li + */ + +@Data +@TableName("sys_user_role") +public class SysUserRole { + + /** + * 用户ID + */ + @TableId(type = IdType.INPUT) + private Long userId; + + /** + * 角色ID + */ + private Long roleId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java new file mode 100644 index 000000000..07255b4bd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java @@ -0,0 +1,103 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.system.domain.SysClient; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 授权管理业务对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@AutoMapper(target = SysClient.class, reverseConvertGenerate = false) +public class SysClientBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @NotNull(message = "id不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 客户端id + */ + private String clientId; + + /** + * 客户端key + */ + @NotBlank(message = "客户端key不能为空", groups = {AddGroup.class, EditGroup.class}) + private String clientKey; + + /** + * 客户端秘钥 + */ + @NotBlank(message = "客户端秘钥不能为空", groups = {AddGroup.class, EditGroup.class}) + private String clientSecret; + + /** + * 授权类型 + */ + @NotNull(message = "授权类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private List grantTypeList; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 允许访问路径 + */ + private String accessPath; + + /** + * 允许访问路径列表 + */ + private List accessPathList; + + /** + * IP白名单 + */ + private String ipWhitelist; + + /** + * IP白名单列表 + */ + private List ipWhitelistList; + + /** + * token活跃超时时间 + */ + private Long activeTimeout; + + /** + * token固定超时时间 + */ + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java new file mode 100644 index 000000000..cbb1c8477 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java @@ -0,0 +1,64 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.dromara.system.domain.SysConfig; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 参数配置业务对象 sys_config + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysConfig.class, reverseConvertGenerate = false) +public class SysConfigBo implements Serializable { + + /** + * 参数主键 + */ + private Long configId; + + /** + * 参数名称 + */ + @NotBlank(message = "参数名称不能为空") + @Size(min = 0, max = 100, message = "参数名称不能超过{max}个字符") + private String configName; + + /** + * 参数键名 + */ + @NotBlank(message = "参数键名不能为空") + @Size(min = 0, max = 100, message = "参数键名长度不能超过{max}个字符") + private String configKey; + + /** + * 参数键值 + */ + @NotBlank(message = "参数键值不能为空") + @Size(min = 0, max = 500, message = "参数键值长度不能超过{max}个字符") + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + private String configType; + + /** + * 备注 + */ + private String remark; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java new file mode 100644 index 000000000..23677148c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java @@ -0,0 +1,91 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.dromara.system.domain.SysDept; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 部门业务对象 sys_dept + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysDept.class, reverseConvertGenerate = false) +public class SysDeptBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门id + */ + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 部门名称 + */ + @NotBlank(message = "部门名称不能为空") + @Size(min = 0, max = 30, message = "部门名称长度不能超过{max}个字符") + private String deptName; + + /** + * 部门类别编码 + */ + @Size(min = 0, max = 100, message = "部门类别编码长度不能超过{max}个字符") + private String deptCategory; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 负责人 + */ + private Long leader; + + /** + * 联系电话 + */ + @Size(min = 0, max = 11, message = "联系电话长度不能超过{max}个字符") + private String phone; + + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 部门状态(0正常 1停用) + */ + private String status; + + /** + * 归属部门id(部门树) + */ + private Long belongDeptId; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java new file mode 100644 index 000000000..34a30faf7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java @@ -0,0 +1,82 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.dromara.system.domain.SysDictData; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 字典数据业务对象 sys_dict_data + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysDictData.class, reverseConvertGenerate = false) +public class SysDictDataBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典编码 + */ + private Long dictCode; + + /** + * 字典排序 + */ + private Integer dictSort; + + /** + * 字典标签 + */ + @NotBlank(message = "字典标签不能为空") + @Size(min = 0, max = 100, message = "字典标签长度不能超过{max}个字符") + private String dictLabel; + + /** + * 字典键值 + */ + @NotBlank(message = "字典键值不能为空") + @Size(min = 0, max = 100, message = "字典键值长度不能超过{max}个字符") + private String dictValue; + + /** + * 字典类型 + */ + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型长度不能超过{max}个字符") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + @Size(min = 0, max = 100, message = "样式属性长度不能超过{max}个字符") + private String cssClass; + + /** + * 表格回显样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + private String isDefault; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java new file mode 100644 index 000000000..d822dbe5d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java @@ -0,0 +1,53 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.dromara.common.core.constant.RegexConstants; +import org.dromara.system.domain.SysDictType; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 字典类型业务对象 sys_dict_type + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysDictType.class, reverseConvertGenerate = false) +public class SysDictTypeBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典主键 + */ + private Long dictId; + + /** + * 字典名称 + */ + @NotBlank(message = "字典名称不能为空") + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过{max}个字符") + private String dictName; + + /** + * 字典类型 + */ + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过{max}个字符") + @Pattern(regexp = RegexConstants.DICTIONARY_TYPE, message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + private String dictType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLoginInfoBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLoginInfoBo.java new file mode 100644 index 000000000..bfcdcf1d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLoginInfoBo.java @@ -0,0 +1,87 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.system.domain.SysLoginInfo; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 系统访问记录业务对象 sys_login_info + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysLoginInfo.class, reverseConvertGenerate = false) +public class SysLoginInfoBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 访问ID + */ + private Long infoId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录状态(0成功 1失败) + */ + private String status; + + /** + * 提示消息 + */ + private String msg; + + /** + * 访问时间 + */ + private LocalDateTime loginTime; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java new file mode 100644 index 000000000..ef012bb1d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java @@ -0,0 +1,128 @@ +package org.dromara.system.domain.bo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.dromara.common.core.constant.RegexConstants; +import org.dromara.common.json.validate.JsonPattern; +import org.dromara.common.json.validate.JsonType; +import org.dromara.system.domain.SysMenu; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 菜单权限业务对象 sys_menu + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysMenu.class, reverseConvertGenerate = false) +public class SysMenuBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 菜单名称 + */ + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过{max}个字符") + private String menuName; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 路由地址 + */ + @Size(min = 0, max = 200, message = "路由地址不能超过{max}个字符") + private String path; + + /** + * 组件路径 + */ + @Size(min = 0, max = 200, message = "组件路径不能超过{max}个字符") + private String component; + + /** + * 路由参数 + */ + @JsonPattern(type = JsonType.OBJECT, message = "路由参数必须符合JSON格式") + private String queryParam; + + /** + * 是否为外链(Y是 N否) + */ + private String isFrame; + + /** + * 是否缓存(Y缓存 N不缓存) + */ + private String isCache; + + /** + * 菜单类型(M目录 C菜单 F按钮) + */ + @NotBlank(message = "菜单类型不能为空") + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限标识 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + @Size(min = 0, max = 100, message = "权限标识长度不能超过{max}个字符") + @Pattern(regexp = RegexConstants.PERMISSION_STRING, message = "权限标识必须符合 tool:build:list 格式") + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 激活菜单路径 + */ + @Size(min = 0, max = 255, message = "激活菜单路径长度不能超过{max}个字符") + private String activeMenu; + + /** + * 扩展字段 + */ + @Size(min = 0, max = 2000, message = "扩展字段长度不能超过{max}个字符") + private String ext; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java new file mode 100644 index 000000000..c5ac35198 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java @@ -0,0 +1,64 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.dromara.common.core.xss.Xss; +import org.dromara.system.domain.SysNotice; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 通知公告业务对象 sys_notice + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysNotice.class, reverseConvertGenerate = false) +public class SysNoticeBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 公告ID + */ + private Long noticeId; + + /** + * 公告标题 + */ + @Xss(message = "公告标题不能包含脚本字符") + @NotBlank(message = "公告标题不能为空") + @Size(min = 0, max = 50, message = "公告标题不能超过{max}个字符") + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建人名称 + */ + private String createByName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java new file mode 100644 index 000000000..454cf803f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java @@ -0,0 +1,157 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.AutoMappers; +import lombok.Data; +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.system.domain.SysOperLog; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 操作日志记录业务对象 sys_oper_log + * + * @author Michelle.Chung + * @date 2023-02-07 + */ + +@Data +@AutoMappers({ + @AutoMapper(target = SysOperLog.class, reverseConvertGenerate = false), + @AutoMapper(target = OperLogEvent.class) +}) +public class SysOperLogBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + private Long operId; + + /** + * 模块标题 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 方法名称 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 操作用户ID + */ + private Long userId; + + /** + * 操作部门ID + */ + private Long deptId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 请求URL + */ + private String operUrl; + + /** + * 主机地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private LocalDateTime operTime; + + /** + * 消耗时间 + */ + private Long costTime; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java new file mode 100644 index 000000000..c2df40403 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java @@ -0,0 +1,69 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.system.domain.SysOss; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * OSS对象存储分页查询对象 sys_oss + * + * @author Lion Li + */ +@Data +@AutoMapper(target = SysOss.class, reverseConvertGenerate = false) +public class SysOssBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ossId + */ + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 服务商 + */ + private String service; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java new file mode 100644 index 000000000..6551a8ec9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java @@ -0,0 +1,112 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.system.domain.SysOssConfig; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 对象存储配置业务对象 sys_oss_config + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ + +@Data +@AutoMapper(target = SysOssConfig.class, reverseConvertGenerate = false) +public class SysOssConfigBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long ossConfigId; + + /** + * 配置key + */ + @NotBlank(message = "配置key不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "configKey长度必须介于{min}和{max} 之间") + private String configKey; + + /** + * accessKey + */ + @NotBlank(message = "accessKey不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "accessKey长度必须介于{min}和{max} 之间") + private String accessKey; + + /** + * 秘钥 + */ + @NotBlank(message = "secretKey不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "secretKey长度必须介于{min}和{max} 之间") + private String secretKey; + + /** + * 桶名称 + */ + @NotBlank(message = "桶名称不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "bucketName长度必须介于{min}和{max}之间") + private String bucketName; + + /** + * 前缀 + */ + private String prefix; + + /** + * 访问站点 + */ + @NotBlank(message = "访问站点不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "endpoint长度必须介于{min}和{max}之间") + private String endpoint; + + /** + * 自定义域名 + */ + private String domainUrl; + + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + + /** + * 是否默认(Y=是,N=否) + */ + private String status; + + /** + * 域 + */ + private String region; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 备注 + */ + private String remark; + + /** + * 桶权限类型(0private 1public 2custom) + */ + @NotBlank(message = "桶权限类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String accessPolicy; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java new file mode 100644 index 000000000..164c20a40 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java @@ -0,0 +1,85 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.dromara.system.domain.SysPost; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 岗位信息业务对象 sys_post + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysPost.class, reverseConvertGenerate = false) +public class SysPostBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 岗位ID + */ + private Long postId; + + /** + * 部门id(单部门) + */ + @NotNull(message = "部门id不能为空") + private Long deptId; + + /** + * 归属部门id(部门树) + */ + private Long belongDeptId; + + /** + * 岗位编码 + */ + @NotBlank(message = "岗位编码不能为空") + @Size(min = 0, max = 64, message = "岗位编码长度不能超过{max}个字符") + private String postCode; + + /** + * 岗位名称 + */ + @NotBlank(message = "岗位名称不能为空") + @Size(min = 0, max = 50, message = "岗位名称长度不能超过{max}个字符") + private String postName; + + /** + * 岗位类别编码 + */ + @Size(min = 0, max = 100, message = "类别编码长度不能超过{max}个字符") + private String postCategory; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java new file mode 100644 index 000000000..0f5afadaf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java @@ -0,0 +1,105 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.system.domain.SysRole; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 角色信息业务对象 sys_role + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@AutoMapper(target = SysRole.class, reverseConvertGenerate = false) +public class SysRoleBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + private Long roleId; + + /** + * 角色名称 + */ + @NotBlank(message = "角色名称不能为空") + @Size(min = 0, max = 30, message = "角色名称长度不能超过{max}个字符") + private String roleName; + + /** + * 角色权限字符串 + */ + @NotBlank(message = "角色权限字符串不能为空") + @Size(min = 0, max = 100, message = "权限字符长度不能超过{max}个字符") + private String roleKey; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限) + */ + private String dataScope; + + /** + * 菜单树选择项是否关联显示 + */ + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示 + */ + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 菜单组 + */ + private Long[] menuIds; + + /** + * 部门组(数据权限) + */ + private Long[] deptIds; + + /** + * 判断当前角色是否为超级管理员角色。 + * + * @return true 是超级管理员角色 false 不是超级管理员角色 + */ + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ROLE_ID.equals(this.roleId); + } + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java new file mode 100644 index 000000000..66a992465 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java @@ -0,0 +1,143 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.system.domain.SysSocial; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 社会化关系业务对象 sys_social + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +@AutoMapper(target = SysSocial.class, reverseConvertGenerate = false) +public class SysSocialBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 认证唯一ID + */ + @NotBlank(message = "认证唯一ID不能为空", groups = {AddGroup.class, EditGroup.class}) + private String authId; + + /** + * 用户来源 + */ + @NotBlank(message = "用户来源不能为空", groups = {AddGroup.class, EditGroup.class}) + private String source; + + /** + * 用户的授权令牌 + */ + @NotBlank(message = "用户的授权令牌不能为空", groups = {AddGroup.class, EditGroup.class}) + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 平台唯一id + */ + private String openId; + + /** + * 用户的 ID + */ + @NotBlank(message = "用户的ID不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long userId; + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java new file mode 100644 index 000000000..93ce15029 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java @@ -0,0 +1,150 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.xss.Xss; +import org.dromara.system.domain.SysUser; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 用户信息业务对象 sys_user + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@AutoMapper(target = SysUser.class, reverseConvertGenerate = false) +public class SysUserBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + @Xss(message = "用户账号不能包含脚本字符") + @NotBlank(message = "用户账号不能为空") + @Size(min = 2, max = 30, message = "用户账号长度必须在{min}到{max}个字符之间") + private String userName; + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @NotBlank(message = "用户昵称不能为空") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + private String phoneNumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String gender; + + /** + * 头像 OSS ID + */ + private Long avatar; + + /** + * 密码 + */ + private String password; + + /** + * 账号状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 角色组 + */ + @Size(min = 1, message = "用户角色不能为空") + private Long[] roleIds; + + /** + * 岗位组 + */ + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + + /** + * 用户ID + */ + private String userIds; + + /** + * 排除不查询的用户(工作流用) + */ + private String excludeUserIds; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + + /** + * 判断当前用户是否为超级管理员。 + * + * @return true 是超级管理员 false 不是超级管理员 + */ + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_USER_ID.equals(this.userId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java new file mode 100644 index 000000000..2b6ee093b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java @@ -0,0 +1,61 @@ +package org.dromara.system.domain.bo; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.RegexConstants; +import org.dromara.common.core.xss.Xss; +import org.dromara.common.sensitive.annotation.Sensitive; +import org.dromara.common.sensitive.core.SensitiveStrategy; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 个人信息业务处理 + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +public class SysUserProfileBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户邮箱 + */ + @Sensitive(strategy = SensitiveStrategy.EMAIL) + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + @Pattern(regexp = RegexConstants.MOBILE, message = "手机号格式不正确") + @Sensitive(strategy = SensitiveStrategy.PHONE) + private String phoneNumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String gender; + + /** + * 头像 OSS ID + */ + private Long avatar; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java new file mode 100644 index 000000000..8d5e72b9a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java @@ -0,0 +1,115 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; +import org.dromara.common.core.utils.StringUtils; + +/** + * 路由显示信息 + * + * @author ruoyi + */ + +@Data +public class MetaVo { + + /** + * 设置该路由在侧边栏和面包屑中展示的名字 + */ + private String title; + + /** + * 设置该路由的图标,对应路径src/assets/icons/svg + */ + private String icon; + + /** + * 设置为true,则不会被 缓存 + */ + private Boolean noCache; + + /** + * 内链地址(http(s)://开头) + */ + private String link; + + /** + * 激活菜单 + */ + private String activeMenu; + + /** + * 构造路由显示信息。 + * + * @param title 路由标题 + * @param icon 路由图标 + */ + public MetaVo(String title, String icon) { + this.title = title; + this.icon = icon; + } + + /** + * 构造路由显示信息。 + * + * @param title 路由标题 + * @param icon 路由图标 + * @param noCache 是否不缓存 + */ + public MetaVo(String title, String icon, Boolean noCache) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + } + + /** + * 构造带内链地址的路由显示信息。 + * + * @param title 路由标题 + * @param icon 路由图标 + * @param link 内链地址 + */ + public MetaVo(String title, String icon, String link) { + this.title = title; + this.icon = icon; + this.link = link; + } + + /** + * 构造带缓存配置和内链地址的路由显示信息。 + * + * @param title 路由标题 + * @param icon 路由图标 + * @param noCache 是否不缓存 + * @param link 内链地址 + */ + public MetaVo(String title, String icon, Boolean noCache, String link) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) { + this.link = link; + } + } + + /** + * 构造带激活菜单的路由显示信息。 + * + * @param title 路由标题 + * @param icon 路由图标 + * @param noCache 是否不缓存 + * @param link 内链地址 + * @param activeMenu 激活菜单路径 + */ + public MetaVo(String title, String icon, Boolean noCache, String link, String activeMenu) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) { + this.link = link; + } + if (StringUtils.startWithAnyIgnoreCase(activeMenu, "/")) { + this.activeMenu = activeMenu; + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileUserVo.java new file mode 100644 index 000000000..18443ef46 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileUserVo.java @@ -0,0 +1,90 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 用户信息视图对象 sys_user + * + * @author Lion Li + */ +@Data +public class ProfileUserVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + private String email; + + /** + * 手机号码 + */ + private String phoneNumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String gender; + + /** + * 头像 OSS ID + */ + private Long avatar; + + /** + * 头像地址 + */ + @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "avatar") + private String avatarUrl; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private LocalDateTime loginDate; + + /** + * 部门名 + */ + @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId") + private String deptName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java new file mode 100644 index 000000000..e287f2faa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java @@ -0,0 +1,67 @@ +package org.dromara.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.util.List; + +/** + * 路由配置信息 + * + * @author Lion Li + */ +@Data +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class RouterVo { + + /** + * 路由名字 + */ + private String name; + + /** + * 路由地址 + */ + private String path; + + /** + * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 + */ + private Boolean hidden; + + /** + * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + */ + private String redirect; + + /** + * 组件地址 + */ + private String component; + + /** + * 路由参数:如 {"id": 1, "name": "ry"} + */ + private String query; + + /** + * 扩展字段 + */ + private String ext; + + /** + * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + */ + private Boolean alwaysShow; + + /** + * 其他元素 + */ + private MetaVo meta; + + /** + * 子路由 + */ + private List children; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java new file mode 100644 index 000000000..4ac4e18f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java @@ -0,0 +1,112 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysClient; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 授权管理视图对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysClient.class) +public class SysClientVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 客户端id + */ + @ExcelProperty(value = "客户端id") + private String clientId; + + /** + * 客户端key + */ + @ExcelProperty(value = "客户端key") + private String clientKey; + + /** + * 客户端秘钥 + */ + @ExcelProperty(value = "客户端秘钥") + private String clientSecret; + + /** + * 授权类型 + */ + private List grantTypeList; + + /** + * 授权类型 + */ + @ExcelProperty(value = "授权类型") + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 允许访问路径 + */ + @ExcelProperty(value = "允许访问路径") + private String accessPath; + + /** + * 允许访问路径列表 + */ + private List accessPathList; + + /** + * IP白名单 + */ + @ExcelProperty(value = "IP白名单") + private String ipWhitelist; + + /** + * IP白名单列表 + */ + private List ipWhitelistList; + + /** + * token活跃超时时间 + */ + @ExcelProperty(value = "token活跃超时时间") + private Long activeTimeout; + + /** + * token固定超时时间 + */ + @ExcelProperty(value = "token固定超时时间") + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java new file mode 100644 index 000000000..af1ca4e50 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java @@ -0,0 +1,72 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysConfig; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 参数配置视图对象 sys_config + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysConfig.class) +public class SysConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 参数主键 + */ + @ExcelProperty(value = "参数主键") + private Long configId; + + /** + * 参数名称 + */ + @ExcelProperty(value = "参数名称") + private String configName; + + /** + * 参数键名 + */ + @ExcelProperty(value = "参数键名") + private String configKey; + + /** + * 参数键值 + */ + @ExcelProperty(value = "参数键值") + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + @ExcelProperty(value = "系统内置", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String configType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java new file mode 100644 index 000000000..ba293e632 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java @@ -0,0 +1,109 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysDept; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * 部门视图对象 sys_dept + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDept.class) +public class SysDeptVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 父部门id + */ + private Long parentId; + + /** + * 父部门名称 + */ + private String parentName; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 部门类别编码 + */ + @ExcelProperty(value = "部门类别编码") + private String deptCategory; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人ID + */ + private Long leader; + + /** + * 负责人 + */ + @ExcelProperty(value = "负责人") + private String leaderName; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String phone; + + /** + * 邮箱 + */ + @ExcelProperty(value = "邮箱") + private String email; + + /** + * 部门状态(0正常 1停用) + */ + @ExcelProperty(value = "部门状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private LocalDateTime createTime; + + /** + * 子部门 + */ + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java new file mode 100644 index 000000000..887a8441f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java @@ -0,0 +1,88 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysDictData; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 字典数据视图对象 sys_dict_data + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDictData.class) +public class SysDictDataVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典编码 + */ + @ExcelProperty(value = "字典编码") + private Long dictCode; + + /** + * 字典排序 + */ + @ExcelProperty(value = "字典排序") + private Integer dictSort; + + /** + * 字典标签 + */ + @ExcelProperty(value = "字典标签") + private String dictLabel; + + /** + * 字典键值 + */ + @ExcelProperty(value = "字典键值") + private String dictValue; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + private String cssClass; + + /** + * 表格回显样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + @ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isDefault; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java new file mode 100644 index 000000000..db54e4696 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java @@ -0,0 +1,57 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.system.domain.SysDictType; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 字典类型视图对象 sys_dict_type + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDictType.class) +public class SysDictTypeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典主键 + */ + @ExcelProperty(value = "字典主键") + private Long dictId; + + /** + * 字典名称 + */ + @ExcelProperty(value = "字典名称") + private String dictName; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + private String dictType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLoginInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLoginInfoVo.java new file mode 100644 index 000000000..ed094625b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLoginInfoVo.java @@ -0,0 +1,100 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysLoginInfo; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 系统访问记录视图对象 sys_login_info + * + * @author Michelle.Chung + * @date 2023-02-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysLoginInfo.class) +public class SysLoginInfoVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 访问ID + */ + @ExcelProperty(value = "序号") + private Long infoId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "用户账号") + private String userName; + + /** + * 客户端 + */ + @ExcelProperty(value = "客户端") + private String clientKey; + + /** + * 设备类型 + */ + @ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_device_type") + private String deviceType; + + /** + * 登录状态(0成功 1失败) + */ + @ExcelProperty(value = "登录状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private String status; + + /** + * 登录IP地址 + */ + @ExcelProperty(value = "登录地址") + private String ipaddr; + + /** + * 登录地点 + */ + @ExcelProperty(value = "登录地点") + private String loginLocation; + + /** + * 浏览器类型 + */ + @ExcelProperty(value = "浏览器") + private String browser; + + /** + * 操作系统 + */ + @ExcelProperty(value = "操作系统") + private String os; + + + /** + * 提示消息 + */ + @ExcelProperty(value = "提示消息") + private String msg; + + /** + * 访问时间 + */ + @ExcelProperty(value = "访问时间") + private LocalDateTime loginTime; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java new file mode 100644 index 000000000..0c48eae5b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java @@ -0,0 +1,126 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.system.domain.SysMenu; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + + +/** + * 菜单权限视图对象 sys_menu + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysMenu.class) +public class SysMenuVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(Y是 N否) + */ + private String isFrame; + + /** + * 是否缓存(Y缓存 N不缓存) + */ + private String isCache; + + /** + * 菜单类型(M目录 C菜单 F按钮) + */ + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限标识 + */ + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 激活菜单路径 + */ + private String activeMenu; + + /** + * 扩展字段 + */ + private String ext; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 子菜单 + */ + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageBoxVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageBoxVo.java new file mode 100644 index 000000000..c466aa707 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageBoxVo.java @@ -0,0 +1,35 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 消息盒子视图对象 + * + * @author Lion Li + */ +@Data +public class SysMessageBoxVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 系统消息 + */ + private List systemList = new ArrayList<>(); + + /** + * 通知公告消息 + */ + private List noticeList = new ArrayList<>(); + + /** + * 工作流消息 + */ + private List workflowList = new ArrayList<>(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageVo.java new file mode 100644 index 000000000..1df507f17 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageVo.java @@ -0,0 +1,72 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.system.domain.SysMessage; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 消息记录视图对象 sys_message + * + * @author Lion Li + */ +@Data +@AutoMapper(target = SysMessage.class) +public class SysMessageVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 消息ID + */ + private Long messageId; + + /** + * 消息分组 + */ + private String category; + + /** + * 消息类型 + */ + private String type; + + /** + * 消息来源 + */ + private String source; + + /** + * 标题 + */ + private String title; + + /** + * 摘要消息 + */ + private String message; + + /** + * 详细内容 + */ + private String content; + + /** + * 扩展数据 + */ + private Object data; + + /** + * 前端跳转路径 + */ + private String path; + + /** + * 创建时间 + */ + private LocalDateTime createTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java new file mode 100644 index 000000000..15decbccd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java @@ -0,0 +1,72 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysNotice; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 通知公告视图对象 sys_notice + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysNotice.class) +public class SysNoticeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 公告ID + */ + private Long noticeId; + + /** + * 公告标题 + */ + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") + private String createByName; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java new file mode 100644 index 000000000..bf1c033eb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java @@ -0,0 +1,176 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysOperLog; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 操作日志记录视图对象 sys_oper_log + * + * @author Michelle.Chung + * @date 2023-02-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysOperLog.class) +public class SysOperLogVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + @ExcelProperty(value = "日志主键") + private Long operId; + + /** + * 模块标题 + */ + @ExcelProperty(value = "操作模块") + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + @ExcelProperty(value = "业务类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_oper_type") + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 方法名称 + */ + @ExcelProperty(value = "请求方法") + private String method; + + /** + * 请求方式 + */ + @ExcelProperty(value = "请求方式") + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + @ExcelProperty(value = "操作类别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Integer operatorType; + + /** + * 操作人员 + */ + @ExcelProperty(value = "操作人员") + private String operName; + + /** + * 操作用户ID + */ + @ExcelProperty(value = "操作用户ID") + private Long userId; + + /** + * 操作部门ID + */ + @ExcelProperty(value = "操作部门ID") + private Long deptId; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 客户端 + */ + @ExcelProperty(value = "客户端") + private String clientKey; + + /** + * 设备类型 + */ + @ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_device_type") + private String deviceType; + + /** + * 浏览器类型 + */ + @ExcelProperty(value = "浏览器") + private String browser; + + /** + * 操作系统 + */ + @ExcelProperty(value = "操作系统") + private String os; + + /** + * 请求URL + */ + @ExcelProperty(value = "请求地址") + private String operUrl; + + /** + * 主机地址 + */ + @ExcelProperty(value = "操作地址") + private String operIp; + + /** + * 操作地点 + */ + @ExcelProperty(value = "操作地点") + private String operLocation; + + /** + * 请求参数 + */ + @ExcelProperty(value = "请求参数") + private String operParam; + + /** + * 返回参数 + */ + @ExcelProperty(value = "返回参数") + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private Integer status; + + /** + * 错误消息 + */ + @ExcelProperty(value = "错误消息") + private String errorMsg; + + /** + * 操作时间 + */ + @ExcelProperty(value = "操作时间") + private LocalDateTime operTime; + + /** + * 消耗时间 + */ + @ExcelProperty(value = "消耗时间") + private Long costTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java new file mode 100644 index 000000000..d752282dc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java @@ -0,0 +1,97 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.dromara.system.domain.SysOssConfig; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 对象存储配置视图对象 sys_oss_config + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysOssConfig.class) +public class SysOssConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long ossConfigId; + + /** + * 配置key + */ + private String configKey; + + /** + * accessKey + */ + private String accessKey; + + /** + * 秘钥 + */ + private String secretKey; + + /** + * 桶名称 + */ + private String bucketName; + + /** + * 前缀 + */ + private String prefix; + + /** + * 访问站点 + */ + private String endpoint; + + /** + * 自定义域名 + */ + private String domainUrl; + + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + + /** + * 域 + */ + private String region; + + /** + * 是否默认(Y=是,N=否) + */ + private String status; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 备注 + */ + private String remark; + + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java new file mode 100644 index 000000000..e9f996329 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java @@ -0,0 +1,77 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysOss; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * OSS对象存储视图对象 sys_oss + * + * @author Lion Li + */ +@Data +@AutoMapper(target = SysOss.class) +public class SysOssVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 对象存储主键 + */ + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 上传人 + */ + private Long createBy; + + /** + * 上传人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") + private String createByName; + + /** + * 服务商 + */ + private String service; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java new file mode 100644 index 000000000..f844657c7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java @@ -0,0 +1,91 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysPost; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 岗位信息视图对象 sys_post + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysPost.class) +public class SysPostVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 岗位ID + */ + @ExcelProperty(value = "岗位序号") + private Long postId; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 岗位编码 + */ + @ExcelProperty(value = "岗位编码") + private String postCode; + + /** + * 岗位名称 + */ + @ExcelProperty(value = "岗位名称") + private String postName; + + /** + * 岗位类别编码 + */ + @ExcelProperty(value = "类别编码") + private String postCategory; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "岗位排序") + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private LocalDateTime createTime; + + /** + * 部门名 + */ + @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId") + private String deptName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleMenuPermVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleMenuPermVo.java new file mode 100644 index 000000000..863dfe3c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleMenuPermVo.java @@ -0,0 +1,26 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 角色菜单权限视图 + */ +@Data +public class SysRoleMenuPermVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + private Long roleId; + + /** + * 权限字符串 + */ + private String perms; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java new file mode 100644 index 000000000..fa9680c2e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java @@ -0,0 +1,105 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysRole; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 角色信息视图对象 sys_role + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysRole.class) +public class SysRoleVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + @ExcelProperty(value = "角色序号") + private Long roleId; + + /** + * 角色名称 + */ + @ExcelProperty(value = "角色名称") + private String roleName; + + /** + * 角色权限字符串 + */ + @ExcelProperty(value = "角色权限") + private String roleKey; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "角色排序") + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限) + */ + @ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=全部数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限,6=部门及以下或本人数据权限") + private String dataScope; + + /** + * 菜单树选择项是否关联显示 + */ + @ExcelProperty(value = "菜单树选择项是否关联显示") + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示 + */ + @ExcelProperty(value = "部门树选择项是否关联显示") + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + @ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private LocalDateTime createTime; + + /** + * 用户是否存在此角色标识 默认不存在 + */ + private boolean flag = false; + + /** + * 判断当前角色是否为超级管理员角色。 + * + * @return true 是超级管理员角色 false 不是超级管理员角色 + */ + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ROLE_ID.equals(this.roleId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java new file mode 100644 index 000000000..0ccf3c2b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java @@ -0,0 +1,139 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.system.domain.SysSocial; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 社会化关系视图对象 sys_social + * + * @author thiszhc + */ +@Data +@AutoMapper(target = SysSocial.class) +public class SysSocialVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 的唯一ID + */ + private String authId; + + /** + * 用户来源 + */ + private String source; + + /** + * 用户的授权令牌 + */ + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 用户的 open id + */ + private String openId; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + /** + * 创建时间 + */ + private LocalDateTime createTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java new file mode 100644 index 000000000..a1ed22c1e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java @@ -0,0 +1,94 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.listener.DeptExcelConverter; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 用户对象导出VO + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class SysUserExportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "用户账号") + private String userName; + + /** + * 部门ID + */ + @ExcelProperty(value = "部门名称", converter = DeptExcelConverter.class) + private Long deptId; + + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户昵称") + private String nickName; + + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phoneNumber; + + /** + * 用户性别(0男 1女 2未知) + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_gender") + private String gender; + + /** + * 账号状态(0正常 1停用) + */ + @ExcelProperty(value = "账号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 最后登录IP + */ + @ExcelProperty(value = "最后登录IP") + private String loginIp; + + /** + * 最后登录时间 + */ + @ExcelProperty(value = "最后登录时间") + private LocalDateTime loginDate; + + /** + * 负责人 + */ + @ExcelProperty(value = "部门负责人") + private String leaderName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java new file mode 100644 index 000000000..0af0d48c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java @@ -0,0 +1,80 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.annotation.ExcelDynamicOptions; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.listener.DeptExcelConverter; +import org.dromara.system.listener.DeptExcelOptions; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户对象导入VO + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +// @Accessors(chain = true) // 导入不允许使用 会找不到set方法 +public class SysUserImportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + /** + * 部门ID + */ + @ExcelProperty(value = "部门名称", converter = DeptExcelConverter.class) + @ExcelDynamicOptions(providerClass = DeptExcelOptions.class) + private Long deptId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "用户账号") + private String userName; + + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户昵称") + private String nickName; + + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phoneNumber; + + /** + * 用户性别(0男 1女 2未知) + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_gender") + private String gender; + + /** + * 账号状态(0正常 1停用) + */ + @ExcelProperty(value = "账号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java new file mode 100644 index 000000000..e41355d09 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java @@ -0,0 +1,40 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 用户信息 + * + * @author Michelle.Chung + */ +@Data +public class SysUserInfoVo { + + /** + * 用户信息 + */ + private SysUserVo user; + + /** + * 角色ID列表 + */ + private List roleIds; + + /** + * 角色列表 + */ + private List roles; + + /** + * 岗位ID列表 + */ + private List postIds; + + /** + * 岗位列表 + */ + private List posts; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java new file mode 100644 index 000000000..d46736309 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java @@ -0,0 +1,147 @@ +package org.dromara.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.sensitive.annotation.Sensitive; +import org.dromara.common.sensitive.core.SensitiveStrategy; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysUser; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + + +/** + * 用户信息视图对象 sys_user + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysUser.class) +public class SysUserVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + @Sensitive(strategy = SensitiveStrategy.EMAIL, perms = "system:user:edit") + private String email; + + /** + * 手机号码 + */ + @Sensitive(strategy = SensitiveStrategy.PHONE, perms = "system:user:edit") + private String phoneNumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String gender; + + /** + * 头像 OSS ID + */ + private Long avatar; + + /** + * 头像地址 + */ + @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "avatar") + private String avatarUrl; + + /** + * 密码 + */ + @JsonIgnore + @JsonProperty + private String password; + + /** + * 账号状态(0正常 1停用) + */ + private String status; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private LocalDateTime loginDate; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 部门名 + */ + @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId") + private String deptName; + + /** + * 角色对象 + */ + private List roles; + + /** + * 角色组 + */ + private Long[] roleIds; + + /** + * 岗位组 + */ + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java new file mode 100644 index 000000000..48fa92a54 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java @@ -0,0 +1,30 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.Set; + +/** + * 登录用户信息 + * + * @author Michelle.Chung + */ +@Data +public class UserInfoVo { + + /** + * 用户基本信息 + */ + private SysUserVo user; + + /** + * 菜单权限 + */ + private Set permissions; + + /** + * 角色权限 + */ + private Set roles; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/OnlineUserCleanEvent.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/OnlineUserCleanEvent.java new file mode 100644 index 000000000..e77c014bc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/OnlineUserCleanEvent.java @@ -0,0 +1,42 @@ +package org.dromara.system.event; + +import cn.hutool.core.collection.CollUtil; + +import java.util.Collection; +import java.util.List; + +/** + * 在线用户清理事件。 + * + * @param roleId 角色 ID,存在时清理拥有该角色的在线用户 + * @param userIds 用户 ID 集合,存在时清理指定在线用户 + */ +public record OnlineUserCleanEvent(Long roleId, Collection userIds) { + + public OnlineUserCleanEvent { + if (CollUtil.isNotEmpty(userIds)) { + userIds = List.copyOf(userIds); + } + } + + /** + * 创建按角色清理在线用户事件。 + * + * @param roleId 角色 ID + * @return 在线用户清理事件 + */ + public static OnlineUserCleanEvent byRole(Long roleId) { + return new OnlineUserCleanEvent(roleId, null); + } + + /** + * 创建按用户清理在线用户事件。 + * + * @param userIds 用户 ID 集合 + * @return 在线用户清理事件 + */ + public static OnlineUserCleanEvent byUsers(Collection userIds) { + return new OnlineUserCleanEvent(null, userIds); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/OssConfigChangeEvent.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/OssConfigChangeEvent.java new file mode 100644 index 000000000..64265e6b6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/OssConfigChangeEvent.java @@ -0,0 +1,50 @@ +package org.dromara.system.event; + +/** + * OSS 配置变更事件。 + * + * @param configKey 当前配置 key + * @param oldConfigKey 变更前配置 key + * @param configJson 当前配置 JSON,为空表示清理缓存 + * @param defaultConfig 是否设置为默认配置 + */ +public record OssConfigChangeEvent( + String configKey, + String oldConfigKey, + String configJson, + boolean defaultConfig +) { + + /** + * 创建保存 OSS 配置后的变更事件。 + * + * @param configKey 当前配置 key + * @param oldConfigKey 变更前配置 key + * @param configJson 当前配置 JSON + * @return OSS 配置变更事件 + */ + public static OssConfigChangeEvent save(String configKey, String oldConfigKey, String configJson) { + return new OssConfigChangeEvent(configKey, oldConfigKey, configJson, false); + } + + /** + * 创建删除 OSS 配置后的变更事件。 + * + * @param configKey 配置 key + * @return OSS 配置变更事件 + */ + public static OssConfigChangeEvent remove(String configKey) { + return new OssConfigChangeEvent(configKey, null, null, false); + } + + /** + * 创建切换默认 OSS 配置后的变更事件。 + * + * @param configKey 默认配置 key + * @return OSS 配置变更事件 + */ + public static OssConfigChangeEvent useDefault(String configKey) { + return new OssConfigChangeEvent(configKey, null, null, true); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelConverter.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelConverter.java new file mode 100644 index 000000000..e6a8b20d3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelConverter.java @@ -0,0 +1,125 @@ +package org.dromara.system.listener; + +import cn.hutool.core.lang.tree.Tree; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import lombok.RequiredArgsConstructor; +import org.apache.fesod.sheet.converters.Converter; +import org.apache.fesod.sheet.enums.CellDataTypeEnum; +import org.apache.fesod.sheet.metadata.GlobalConfiguration; +import org.apache.fesod.sheet.metadata.data.ReadCellData; +import org.apache.fesod.sheet.metadata.data.WriteCellData; +import org.apache.fesod.sheet.metadata.property.ExcelContentProperty; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.TreeBuildUtils; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.service.ISysDeptService; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * Excel 部门转换处理 + * + * @author AprilWind + */ +@RequiredArgsConstructor +public class DeptExcelConverter implements Converter { + + private static final String CACHE_KEY = "dept:excel"; + + /** + * Caffeine 缓存:key=CACHE_KEY,value=[idToName, nameToId],5分钟过期 + */ + private static final Cache DEPT_CACHE = Caffeine.newBuilder() + .expireAfterWrite(30, TimeUnit.SECONDS) + .build(); + + /** + * 获取部门导入导出映射缓存。 + * + * @return 部门 ID 与部门路径名称互转映射 + */ + private DeptMaps getDeptMaps() { + ISysDeptService deptService = SpringUtils.getBean(ISysDeptService.class); + return DEPT_CACHE.get(CACHE_KEY, k -> { + Map> deptPathToTreeMap = buildDeptPathMap(deptService); + Map idToName = new HashMap<>(); + Map nameToId = new HashMap<>(); + deptPathToTreeMap.forEach((name, treeNode) -> { + Long deptId = treeNode.getId(); + idToName.put(deptId, name); + nameToId.put(name, deptId); + }); + return new DeptMaps(idToName, nameToId); + }); + } + + /** + * 构建部门路径 → 树节点映射,供 Converter 和 Options 共用 + */ + private Map> buildDeptPathMap(ISysDeptService deptService) { + return TreeBuildUtils.buildTreeNodeMap( + deptService.selectDeptTreeList(new SysDeptBo()), + "/", + Tree::getName + ); + } + + /** + * 指定 Java 类型:Long(部门ID) + */ + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + /** + * 指定 Excel 类型:字符串 + */ + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + /** + * 【导入】Excel 填写的部门完整路径 → 转为 ID + */ + @Override + public Long convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + String deptName = cellData.getStringValue(); + if (StringUtils.isBlank(deptName)) { + return null; + } + Long deptId = getDeptMaps().nameToId().get(deptName); + if (deptId == null) { + throw new ServiceException("部门不存在:" + deptName); + } + return deptId; + } + + /** + * 【导出】部门 ID → 转为 Excel 显示的完整路径名称 + */ + @Override + public WriteCellData convertToExcelData(Long value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (value == null) { + return new WriteCellData<>(""); + } + String deptName = getDeptMaps().idToName().getOrDefault(value, ""); + return new WriteCellData<>(deptName); + } + + /** + * 部门导入导出映射缓存。 + * + * @param idToName 部门 ID 到部门名称的映射 + * @param nameToId 部门名称到部门 ID 的映射 + */ + private record DeptMaps(Map idToName, Map nameToId) { + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelOptions.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelOptions.java new file mode 100644 index 000000000..69038ad09 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelOptions.java @@ -0,0 +1,36 @@ +package org.dromara.system.listener; + +import cn.hutool.core.lang.tree.Tree; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.TreeBuildUtils; +import org.dromara.common.excel.core.ExcelOptionsProvider; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.service.ISysDeptService; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +/** + * Excel 部门下拉选项数据源 + * + * @author AprilWind + */ +@Component +@RequiredArgsConstructor +public class DeptExcelOptions implements ExcelOptionsProvider { + + /** + * 获取下拉选项数据 + * + * @return 下拉选项列表 + */ + @Override + public Set getOptions() { + ISysDeptService deptService = SpringUtils.getBean(ISysDeptService.class); + List> trees = deptService.selectDeptTreeList(new SysDeptBo()); + return TreeBuildUtils.buildTreeNodeMap(trees, "/", Tree::getName).keySet(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/OnlineUserCleanListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/OnlineUserCleanListener.java new file mode 100644 index 000000000..d1ab0d077 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/OnlineUserCleanListener.java @@ -0,0 +1,39 @@ +package org.dromara.system.listener; + +import cn.hutool.core.collection.CollUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.system.event.OnlineUserCleanEvent; +import org.dromara.system.service.ISysRoleService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +/** + * 在线用户清理监听器。 + * + * @author Lion Li + */ +@Component +@RequiredArgsConstructor +public class OnlineUserCleanListener { + + private final ISysRoleService roleService; + + /** + * 权限或用户角色关系变化后清理受影响的在线用户。 + * + * @param event 在线用户清理事件 + */ + @Async + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true) + public void cleanOnlineUser(OnlineUserCleanEvent event) { + if (event.roleId() != null) { + roleService.cleanOnlineUserByRole(event.roleId()); + } + if (CollUtil.isNotEmpty(event.userIds())) { + roleService.cleanOnlineUser(event.userIds()); + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/OssConfigChangeListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/OssConfigChangeListener.java new file mode 100644 index 000000000..330ab24ed --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/OssConfigChangeListener.java @@ -0,0 +1,48 @@ +package org.dromara.system.listener; + +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.oss.constant.OssConstant; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.system.event.OssConfigChangeEvent; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +/** + * OSS 配置变更监听器。 + * + * @author Lion Li + */ +@Component +public class OssConfigChangeListener { + + /** + * 数据提交后同步刷新 OSS 配置缓存与客户端实例。 + * + * @param event OSS 配置变更事件 + */ + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true) + public void refreshOssConfig(OssConfigChangeEvent event) { + if (event.defaultConfig()) { + RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, event.configKey()); + return; + } + if (StringUtils.isNotBlank(event.oldConfigKey()) && !StringUtils.equals(event.oldConfigKey(), event.configKey())) { + CacheUtils.evict(CacheNames.SYS_OSS_CONFIG, event.oldConfigKey()); + OssFactory.remove(event.oldConfigKey()); + } + if (StringUtils.isBlank(event.configKey())) { + return; + } + if (StringUtils.isBlank(event.configJson())) { + CacheUtils.evict(CacheNames.SYS_OSS_CONFIG, event.configKey()); + } else { + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, event.configKey(), event.configJson()); + } + OssFactory.remove(event.configKey()); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java new file mode 100644 index 000000000..db0361d67 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java @@ -0,0 +1,165 @@ +package org.dromara.system.listener; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.digest.BCrypt; +import cn.hutool.http.HtmlUtil; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import org.apache.fesod.sheet.context.AnalysisContext; +import org.apache.fesod.sheet.event.AnalysisEventListener; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.excel.core.ExcelListener; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserImportVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysConfigService; +import org.dromara.system.service.ISysUserService; + +import java.util.List; + +/** + * 系统用户自定义导入 + * + * @author Lion Li + */ +@Slf4j +public class SysUserImportListener extends AnalysisEventListener implements ExcelListener { + + private static final String NL = "\n"; + + private final ISysUserService userService; + + private final String password; + + private final Boolean isUpdateSupport; + + private final Long operUserId; + + private int successNum = 0; + private int failureNum = 0; + private final StringBuilder successMsg = new StringBuilder(); + private final StringBuilder failureMsg = new StringBuilder(); + + /** + * 构造用户导入监听器。 + * + * @param isUpdateSupport 是否允许更新已存在用户 + */ + public SysUserImportListener(Boolean isUpdateSupport) { + String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword"); + this.userService = SpringUtils.getBean(ISysUserService.class); + this.password = BCrypt.hashpw(initPassword); + this.isUpdateSupport = isUpdateSupport; + this.operUserId = LoginHelper.getUserId(); + } + + /** + * 逐行处理用户导入数据。 + * + * @param userVo 导入用户数据 + * @param context Excel 解析上下文 + */ + @Override + public void invoke(SysUserImportVo userVo, AnalysisContext context) { + SysUserVo sysUser = this.userService.selectUserByUserName(userVo.getUserName()); + try { + // 验证是否存在这个用户 + if (ObjectUtil.isNull(sysUser)) { + SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class); + ValidatorUtils.validate(user); + user.setPassword(password); + user.setCreateBy(operUserId); + userService.insertUser(user); + successNum++; + successMsg.append(NL).append(successNum).append("、账号 ").append(user.getUserName()).append(" 导入成功"); + } else if (isUpdateSupport) { + Long userId = sysUser.getUserId(); + SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class); + user.setUserId(userId); + ValidatorUtils.validate(user); + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + user.setUpdateBy(operUserId); + userService.updateUser(user); + successNum++; + successMsg.append(NL).append(successNum).append("、账号 ").append(user.getUserName()).append(" 更新成功"); + } else { + failureNum++; + failureMsg.append(NL).append(failureNum).append("、账号 ").append(sysUser.getUserName()).append(" 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = NL + failureNum + "、账号 " + HtmlUtil.cleanHtmlTag(userVo.getUserName()) + " 导入失败:"; + String message = e.getMessage(); + if (e instanceof ConstraintViolationException cvException) { + message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", "); + } + failureMsg.append(msg).append(message); + log.error(msg, e); + } + } + + /** + * 所有数据解析完成后的回调。 + * + * @param context Excel 解析上下文 + */ + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + + /** + * 获取用户导入结果。 + * + * @return Excel 导入结果 + */ + @Override + public ExcelResult getExcelResult() { + return new ExcelResult<>() { + + /** + * 获取导入结果分析消息。 + * + * @return 导入结果消息 + */ + @Override + public String getAnalysis() { + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + /** + * 获取导入成功数据列表。 + * + * @return 导入成功数据列表 + */ + @Override + public List getList() { + return null; + } + + /** + * 获取导入错误信息列表。 + * + * @return 导入错误信息列表 + */ + @Override + public List getErrorList() { + return null; + } + }; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java new file mode 100644 index 000000000..6a9719135 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java @@ -0,0 +1,15 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; + +/** + * 授权管理Mapper接口 + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +public interface SysClientMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java new file mode 100644 index 000000000..0eaaee8f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysConfig; +import org.dromara.system.domain.vo.SysConfigVo; + +/** + * 参数配置 数据层 + * + * @author Lion Li + */ +public interface SysConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java new file mode 100644 index 000000000..7bb170084 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java @@ -0,0 +1,121 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.base.MPJBaseMapper; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysRoleDept; +import org.dromara.system.domain.vo.SysDeptVo; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.dromara.common.core.constant.SystemConstants.NORMAL; + +/** + * 部门管理 数据层 + * + * @author Lion Li + */ +public interface SysDeptMapper extends BaseMapperPlus, MPJBaseMapper { + + /** + * 查询部门管理数据 + * + * @param queryWrapper 查询条件 + * @return 部门信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id") + }) + default List selectDeptList(Wrapper queryWrapper) { + return this.selectVoList(queryWrapper); + } + + /** + * 分页查询部门管理数据 + * + * @param page 分页信息 + * @param queryWrapper 查询条件 + * @return 部门信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + }) + default Page selectPageDeptList(Page page, Wrapper queryWrapper) { + return this.selectVoPage(page, queryWrapper); + } + + /** + * 统计指定部门ID的部门数量 + * + * @param deptId 部门ID + * @return 该部门ID的部门数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id") + }) + default long countDeptById(Long deptId) { + return this.lambda().eq(SysDept::getDeptId, deptId).count(); + } + + /** + * 根据父部门ID查询其所有子部门的列表 + * + * @param parentId 父部门ID + * @return 包含子部门的列表 + */ + default List selectListByParentId(Long parentId) { + return this.lambda() + .select(SysDept::getDeptId) + .findInSet(parentId, SysDept::getAncestors) + .list(); + } + + /** + * 查询某个部门及其所有子部门ID(含自身) + * + * @param parentId 父部门ID + * @return 部门ID集合 + */ + default List selectDeptAndChildById(Long parentId) { + List deptList = this.selectListByParentId(parentId); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(parentId); + return deptIds; + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @param deptCheckStrictly 部门树选择项是否关联显示 + * @return 选中部门列表 + */ + default List selectDeptListByRoleId(Long roleId, boolean deptCheckStrictly) { + List depts = this.selectJoinList(SysDept.class, QueryBuilder.lambdaJoin("d", SysDept.class) + .distinct() + .select(SysDept::getDeptId, SysDept::getParentId, SysDept::getOrderNum) + .leftJoin(SysRoleDept.class, "srd", SysRoleDept::getDeptId, SysDept::getDeptId) + .leftJoin(SysRole.class, "sr", SysRole::getRoleId, SysRoleDept::getRoleId) + .eq("srd", SysRoleDept::getRoleId, roleId) + .eq("sr", SysRole::getStatus, NORMAL) + .orderByAsc("d", SysDept::getParentId) + .orderByAsc("d", SysDept::getOrderNum) + .build()); + Set parentIds = deptCheckStrictly ? new HashSet<>(StreamUtils.toList(depts, SysDept::getParentId)) : Collections.emptySet(); + return depts.stream() + .map(SysDept::getDeptId) + .filter(deptId -> !parentIds.contains(deptId)) + .toList(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java new file mode 100644 index 000000000..8d5eba362 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java @@ -0,0 +1,28 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysDictData; +import org.dromara.system.domain.vo.SysDictDataVo; + +import java.util.List; + +/** + * 字典表 数据层 + * + * @author Lion Li + */ +public interface SysDictDataMapper extends BaseMapperPlus { + + /** + * 根据字典类型查询字典数据列表 + * + * @param dictType 字典类型 + * @return 符合条件的字典数据列表 + */ + default List selectDictDataByType(String dictType) { + return this.lambda() + .eq(SysDictData::getDictType, dictType) + .orderByAsc(SysDictData::getDictSort) + .voList(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java new file mode 100644 index 000000000..ae1563927 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysDictType; +import org.dromara.system.domain.vo.SysDictTypeVo; + +/** + * 字典表 数据层 + * + * @author Lion Li + */ +public interface SysDictTypeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLoginInfoMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLoginInfoMapper.java new file mode 100644 index 000000000..30240b2ec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLoginInfoMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysLoginInfo; +import org.dromara.system.domain.vo.SysLoginInfoVo; + +/** + * 系统访问日志情况信息 数据层 + * + * @author Lion Li + */ +public interface SysLoginInfoMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java new file mode 100644 index 000000000..36ea01858 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java @@ -0,0 +1,183 @@ +package org.dromara.system.mapper; + +import cn.hutool.core.collection.CollUtil; +import com.github.yulichang.base.MPJBaseMapper; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysRoleMenu; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.SysMenuVo; +import org.dromara.system.domain.vo.SysRoleMenuPermVo; + +import java.util.*; + +/** + * 菜单表 数据层 + * + * @author Lion Li + */ +public interface SysMenuMapper extends BaseMapperPlus, MPJBaseMapper { + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + default Set selectMenuPermsByUserId(Long userId) { + List list = this.selectJoinList(SysMenu.class, QueryBuilder.lambdaJoin("m", SysMenu.class) + .distinct() + .select(SysMenu::getPerms) + .leftJoin(SysRoleMenu.class, "srm", SysRoleMenu::getMenuId, SysMenu::getMenuId) + .leftJoin(SysUserRole.class, "sur", SysUserRole::getRoleId, SysRoleMenu::getRoleId) + .leftJoin(SysRole.class, "sr", SysRole::getRoleId, SysRoleMenu::getRoleId) + .eq("sur", SysUserRole::getUserId, userId) + .eq("sr", SysRole::getStatus, SystemConstants.NORMAL) + .isNotNull("m", SysMenu::getPerms) + .build()); + return new HashSet<>(StreamUtils.filter(StreamUtils.toList(list, SysMenu::getPerms), StringUtils::isNotBlank)); + } + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + default Set selectMenuPermsByRoleId(Long roleId) { + List list = this.selectJoinList(SysMenu.class, QueryBuilder.lambdaJoin("m", SysMenu.class) + .distinct() + .select(SysMenu::getPerms) + .leftJoin(SysRoleMenu.class, "srm", SysRoleMenu::getMenuId, SysMenu::getMenuId) + .leftJoin(SysRole.class, "sr", SysRole::getRoleId, SysRoleMenu::getRoleId) + .eq("srm", SysRoleMenu::getRoleId, roleId) + .eq("sr", SysRole::getStatus, SystemConstants.NORMAL) + .isNotNull("m", SysMenu::getPerms) + .build()); + return new HashSet<>(StreamUtils.filter(StreamUtils.toList(list, SysMenu::getPerms), StringUtils::isNotBlank)); + } + + /** + * 根据角色ID列表批量查询权限 + * + * @param roleIds 角色ID列表 + * @return 角色权限映射 + */ + default Map> selectMenuPermsByRoleIds(Collection roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return Map.of(); + } + List list = this.selectJoinList(SysRoleMenuPermVo.class, QueryBuilder.lambdaJoin("m", SysMenu.class) + .distinct() + .selectAs("srm", SysRoleMenu::getRoleId, SysRoleMenuPermVo::getRoleId) + .selectAs(SysMenu::getPerms, SysRoleMenuPermVo::getPerms) + .leftJoin(SysRoleMenu.class, "srm", SysRoleMenu::getMenuId, SysMenu::getMenuId) + .leftJoin(SysRole.class, "sr", SysRole::getRoleId, SysRoleMenu::getRoleId) + .in("srm", SysRoleMenu::getRoleId, roleIds) + .eq("sr", SysRole::getStatus, SystemConstants.NORMAL) + .isNotNull("m", SysMenu::getPerms) + .build()); + Map> result = new LinkedHashMap<>(); + for (SysRoleMenuPermVo item : list) { + if (StringUtils.isBlank(item.getPerms())) { + continue; + } + result.computeIfAbsent(item.getRoleId(), key -> new LinkedHashSet<>()).add(item.getPerms()); + } + return result; + } + + /** + * 查询全部正常状态的目录和菜单 + * + * @return 菜单列表 + */ + default List selectMenuTreeAll() { + return this.lambda() + .in(SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU) + .eq(SysMenu::getStatus, SystemConstants.NORMAL) + .orderByAsc(SysMenu::getParentId) + .orderByAsc(SysMenu::getOrderNum) + .list(); + } + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @param menuCheckStrictly 菜单树选择项是否关联显示 + * @return 选中菜单列表 + */ + default List selectMenuListByRoleId(Long roleId, boolean menuCheckStrictly) { + List menus = this.selectJoinList(SysMenu.class, QueryBuilder.lambdaJoin("m", SysMenu.class) + .distinct() + .select(SysMenu::getMenuId, SysMenu::getParentId, SysMenu::getOrderNum) + .leftJoin(SysRoleMenu.class, "srm", SysRoleMenu::getMenuId, SysMenu::getMenuId) + .leftJoin(SysRole.class, "sr", SysRole::getRoleId, SysRoleMenu::getRoleId) + .eq("srm", SysRoleMenu::getRoleId, roleId) + .eq("sr", SysRole::getStatus, SystemConstants.NORMAL) + .orderByAsc("m", SysMenu::getParentId) + .orderByAsc("m", SysMenu::getOrderNum) + .build()); + Set parentIds = menuCheckStrictly ? new HashSet<>(StreamUtils.toList(menus, SysMenu::getParentId)) : Collections.emptySet(); + return menus.stream() + .map(SysMenu::getMenuId) + .filter(menuId -> !parentIds.contains(menuId)) + .toList(); + } + + /** + * 根据用户ID和查询条件查询菜单列表 + * + * @param menu 菜单查询条件 + * @param userId 用户ID + * @return 菜单列表 + */ + default List selectMenuListByUserId(SysMenuBo menu, Long userId) { + return this.selectJoinList(SysMenuVo.class, QueryBuilder.lambdaJoin("m", SysMenu.class) + .distinct() + .selectAll(SysMenu.class) + .leftJoin(SysRoleMenu.class, "srm", SysRoleMenu::getMenuId, SysMenu::getMenuId) + .leftJoin(SysUserRole.class, "sur", SysUserRole::getRoleId, SysRoleMenu::getRoleId) + .leftJoin(SysRole.class, "sr", SysRole::getRoleId, SysRoleMenu::getRoleId) + .eq("sur", SysUserRole::getUserId, userId) + .eq("sr", SysRole::getStatus, SystemConstants.NORMAL) + .likeIfText("m", SysMenu::getMenuName, menu.getMenuName()) + .eqIfText("m", SysMenu::getVisible, menu.getVisible()) + .eqIfText("m", SysMenu::getStatus, menu.getStatus()) + .eqIfText("m", SysMenu::getMenuType, menu.getMenuType()) + .eqIfPresent("m", SysMenu::getParentId, menu.getParentId()) + .orderByAsc("m", SysMenu::getParentId) + .orderByAsc("m", SysMenu::getOrderNum) + .build()); + } + + /** + * 根据用户ID查询正常状态的目录和菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + default List selectMenuTreeByUserId(Long userId) { + return this.selectJoinList(SysMenu.class, QueryBuilder.lambdaJoin("m", SysMenu.class) + .distinct() + .selectAll(SysMenu.class) + .leftJoin(SysRoleMenu.class, "srm", SysRoleMenu::getMenuId, SysMenu::getMenuId) + .leftJoin(SysUserRole.class, "sur", SysUserRole::getRoleId, SysRoleMenu::getRoleId) + .leftJoin(SysRole.class, "sr", SysRole::getRoleId, SysRoleMenu::getRoleId) + .eq("sur", SysUserRole::getUserId, userId) + .eq("sr", SysRole::getStatus, SystemConstants.NORMAL) + .in("m", SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU) + .eq("m", SysMenu::getStatus, SystemConstants.NORMAL) + .orderByAsc("m", SysMenu::getParentId) + .orderByAsc("m", SysMenu::getOrderNum) + .build()); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageMapper.java new file mode 100644 index 000000000..39cfff7c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysMessage; +import org.dromara.system.domain.vo.SysMessageVo; + +/** + * 消息记录Mapper接口 + * + * @author Lion Li + */ +public interface SysMessageMapper extends BaseMapperPlus { +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java new file mode 100644 index 000000000..1e27b7780 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysNotice; +import org.dromara.system.domain.vo.SysNoticeVo; + +/** + * 通知公告表 数据层 + * + * @author Lion Li + */ +public interface SysNoticeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java new file mode 100644 index 000000000..5d2040417 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOperLog; +import org.dromara.system.domain.vo.SysOperLogVo; + +/** + * 操作日志 数据层 + * + * @author Lion Li + */ +public interface SysOperLogMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java new file mode 100644 index 000000000..f93d34d93 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java @@ -0,0 +1,16 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOssConfig; +import org.dromara.system.domain.vo.SysOssConfigVo; + +/** + * 对象存储配置Mapper接口 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +public interface SysOssConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java new file mode 100644 index 000000000..3da621de0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOss; +import org.dromara.system.domain.vo.SysOssVo; + +/** + * 文件上传 数据层 + * + * @author Lion Li + */ +public interface SysOssMapper extends BaseMapperPlus { +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java new file mode 100644 index 000000000..1265c666b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java @@ -0,0 +1,81 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.base.MPJBaseMapper; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.system.domain.SysPost; +import org.dromara.system.domain.SysUserPost; +import org.dromara.system.domain.vo.SysPostVo; + +import java.util.Collection; +import java.util.List; + +/** + * 岗位信息 数据层 + * + * @author Lion Li + */ +public interface SysPostMapper extends BaseMapperPlus, MPJBaseMapper { + + /** + * 分页查询岗位列表 + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 包含岗位信息的分页结果 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + default Page selectPagePostList(Page page, Wrapper queryWrapper) { + return this.selectVoPage(page, queryWrapper); + } + + /** + * 查询岗位列表 + * + * @param queryWrapper 查询条件 + * @return 岗位信息列表 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + default List selectPostList(Wrapper queryWrapper) { + return this.selectVoList(queryWrapper); + } + + /** + * 根据岗位ID集合查询岗位数量 + * + * @param postIds 岗位ID列表 + * @return 匹配的岗位数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + default long selectPostCount(Collection postIds) { + return this.lambda().in(SysPost::getPostId, postIds).count(); + } + + /** + * 根据用户ID查询其关联的岗位列表 + * + * @param userId 用户ID + * @return 岗位信息列表 + */ + default List selectPostsByUserId(Long userId) { + return this.selectJoinList(SysPostVo.class, QueryBuilder.lambdaJoin("p", SysPost.class) + .selectAll(SysPost.class) + .leftJoin(SysUserPost.class, "sup", SysUserPost::getPostId, SysPost::getPostId) + .eq("sup", SysUserPost::getUserId, userId) + .build()); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java new file mode 100644 index 000000000..3de0bb678 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysRoleDept; + +/** + * 角色与部门关联表 数据层 + * + * @author Lion Li + */ +public interface SysRoleDeptMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java new file mode 100644 index 000000000..9c9c6ec22 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java @@ -0,0 +1,98 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.base.MPJBaseMapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.vo.SysRoleVo; + +import java.util.Collection; +import java.util.List; + +/** + * 角色表 数据层 + * + * @author Lion Li + */ +public interface SysRoleMapper extends BaseMapperPlus, MPJBaseMapper { + + /** + * 分页查询角色列表 + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 包含角色信息的分页结果 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "create_dept"), + @DataColumn(key = "userName", value = "create_by") + }) + default Page selectPageRoleList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper) { + return this.selectVoPage(page, queryWrapper); + } + + /** + * 根据条件查询角色数据 + * + * @param queryWrapper 查询条件 + * @return 角色数据集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "create_dept"), + @DataColumn(key = "userName", value = "create_by") + }) + default List selectRoleList(@Param(Constants.WRAPPER) Wrapper queryWrapper) { + return this.selectVoList(queryWrapper); + } + + /** + * 根据角色ID集合查询角色数量 + * + * @param roleIds 角色ID列表 + * @return 匹配的角色数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "create_dept"), + @DataColumn(key = "userName", value = "create_by") + }) + default long selectRoleCount(Collection roleIds) { + return this.lambda().in(SysRole::getRoleId, roleIds).count(); + } + + /** + * 根据角色ID查询角色信息 + * + * @param roleId 角色ID + * @return 对应的角色信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "create_dept"), + @DataColumn(key = "userName", value = "create_by") + }) + default SysRoleVo selectRoleById(Long roleId) { + return this.selectVoById(roleId); + } + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + default List selectRolesByUserId(Long userId) { + return this.selectJoinList(SysRoleVo.class, QueryBuilder.lambdaJoin("r", SysRole.class) + .select(SysRole::getRoleId, SysRole::getRoleName, SysRole::getRoleKey, + SysRole::getRoleSort, SysRole::getDataScope, SysRole::getStatus) + .leftJoin(SysUserRole.class, "sur", SysUserRole::getRoleId, SysRole::getRoleId) + .eq("sur", SysUserRole::getUserId, userId) + .build()); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 000000000..e5eb4b883 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,25 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysRoleMenu; + +import java.util.Collection; + +/** + * 角色与菜单关联表 数据层 + * + * @author Lion Li + */ +public interface SysRoleMenuMapper extends BaseMapperPlus { + + /** + * 根据菜单ID串删除关联关系 + * + * @param menuIds 菜单ID串 + * @return 结果 + */ + default int deleteByMenuIds(Collection menuIds) { + return this.lambda().in(SysRoleMenu::getMenuId, menuIds).deleteCount(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java new file mode 100644 index 000000000..b94206137 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysSocial; +import org.dromara.system.domain.vo.SysSocialVo; + +/** + * 社会化关系Mapper接口 + * + * @author thiszhc + */ +public interface SysSocialMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java new file mode 100644 index 000000000..89196f5e9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java @@ -0,0 +1,184 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.base.MPJBaseMapper; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserExportVo; +import org.dromara.system.domain.vo.SysUserVo; + +import java.util.List; + +/** + * 用户表 数据层 + * + * @author Lion Li + */ +public interface SysUserMapper extends BaseMapperPlus, MPJBaseMapper { + + /** + * 分页查询用户列表,并进行数据权限控制 + * + * @param page 分页参数 + * @param queryWrapper 查询条件 + * @return 分页的用户信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + default Page selectPageUserList(Page page, Wrapper queryWrapper) { + return this.selectVoPage(page, queryWrapper); + } + + /** + * 查询用户列表,并进行数据权限控制 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + default List selectUserList(Wrapper queryWrapper) { + return this.selectVoList(queryWrapper); + } + + /** + * 根据条件分页查询用户列表 + * + * @param user 查询条件 + * @param deptIds 部门ID集合 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.create_by") + }) + default List selectUserExportList(SysUserBo user, List deptIds) { + MPJLambdaWrapper wrapper = QueryBuilder.lambdaJoin("u", SysUser.class) + .selectAll(SysUser.class) + .selectAs("u1", SysUser::getUserName, SysUserExportVo::getLeaderName) + .leftJoin(SysDept.class, "d", SysDept::getDeptId, SysUser::getDeptId) + .leftJoin(SysUser.class, "u1", SysUser::getUserId, SysDept::getLeader) + .likeIfText("u", SysUser::getUserName, user.getUserName()) + .likeIfText("u", SysUser::getNickName, user.getNickName()) + .eqIfText("u", SysUser::getStatus, user.getStatus()) + .likeIfText("u", SysUser::getPhoneNumber, user.getPhoneNumber()) + .betweenParams("u", SysUser::getCreateTime, user.getParams(), "beginTime", "endTime") + .inIfNotEmpty("u", SysUser::getDeptId, deptIds) + .orderByAsc("u", SysUser::getUserId) + .build(); + return this.selectJoinList(SysUserExportVo.class, wrapper); + } + + /** + * 根据条件分页查询已配用户角色列表 + * + * @param page 分页信息 + * @param user 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.create_by") + }) + default Page selectAllocatedList(Page page, SysUserBo user) { + MPJLambdaWrapper wrapper = this.buildUserRoleJoinWrapper(user) + .eq(user.getRoleId() != null, "r", SysRole::getRoleId, user.getRoleId()) + .orderByAsc("u", SysUser::getUserId); + return this.selectJoinPage(page, SysUserVo.class, wrapper); + } + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param page 分页信息 + * @param user 查询条件 + * @param userIds 未分配用户角色的用户ID列表 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.create_by") + }) + default Page selectUnallocatedList(Page page, SysUserBo user, List userIds) { + MPJLambdaWrapper wrapper = this.buildUserRoleJoinWrapper(user) + .notIn(userIds != null && !userIds.isEmpty(), "u", SysUser::getUserId, userIds) + .orderByAsc("u", SysUser::getUserId); + return this.selectJoinPage(page, SysUserVo.class, wrapper); + } + + /** + * 根据用户ID统计用户数量 + * + * @param userId 用户ID + * @return 用户数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + default long countUserById(Long userId) { + return lambda().eq(SysUser::getUserId, userId).count(); + } + + /** + * 根据条件更新用户数据 + * + * @param user 要更新的用户实体 + * @param updateWrapper 更新条件封装器 + * @return 更新操作影响的行数 + */ + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + int update(@Param(Constants.ENTITY) SysUser user, @Param(Constants.WRAPPER) Wrapper updateWrapper); + + /** + * 根据用户ID更新用户数据 + * + * @param user 要更新的用户实体 + * @return 更新操作影响的行数 + */ + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + int updateById(@Param(Constants.ENTITY) SysUser user); + + /** + * 构建用户与角色关联查询条件 + * + * @param user 查询条件 + * @return 用户角色关联查询包装器 + */ + default MPJLambdaWrapper buildUserRoleJoinWrapper(SysUserBo user) { + return QueryBuilder.lambdaJoin("u", SysUser.class) + .distinct() + .selectAll(SysUser.class) + .leftJoin(SysDept.class, "d", SysDept::getDeptId, SysUser::getDeptId) + .leftJoin(SysUserRole.class, "sur", SysUserRole::getUserId, SysUser::getUserId) + .leftJoin(SysRole.class, "r", SysRole::getRoleId, SysUserRole::getRoleId) + .likeIfText("u", SysUser::getUserName, user.getUserName()) + .eqIfText("u", SysUser::getStatus, user.getStatus()) + .likeIfText("u", SysUser::getPhoneNumber, user.getPhoneNumber()) + .build(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java new file mode 100644 index 000000000..07c137112 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUserPost; + +/** + * 用户与岗位关联表 数据层 + * + * @author Lion Li + */ +public interface SysUserPostMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java new file mode 100644 index 000000000..f5d048af2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,29 @@ +package org.dromara.system.mapper; + +import cn.hutool.core.convert.Convert; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUserRole; + +import java.util.List; + +/** + * 用户与角色关联表 数据层 + * + * @author Lion Li + */ +public interface SysUserRoleMapper extends BaseMapperPlus { + + /** + * 根据角色ID查询关联的用户ID列表 + * + * @param roleId 角色ID + * @return 关联到指定角色的用户ID列表 + */ + default List selectUserIdsByRoleId(Long roleId) { + return this.lambda() + .select(SysUserRole::getUserId) + .eq(SysUserRole::getRoleId, roleId) + .objs(Convert::toLong); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java new file mode 100644 index 000000000..9830b23cc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java @@ -0,0 +1,33 @@ +package org.dromara.system.runner; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.system.service.ISysOssConfigService; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * 初始化 system 模块对应业务数据 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class SystemApplicationRunner implements ApplicationRunner { + + private final ISysOssConfigService ossConfigService; + + /** + * 应用启动后初始化 OSS 配置缓存。 + * + * @param args 启动参数 + */ + @Override + public void run(ApplicationArguments args) throws Exception { + ossConfigService.init(); + log.info("初始化OSS配置成功"); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java new file mode 100644 index 000000000..b14d4f404 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java @@ -0,0 +1,66 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysClientBo; +import org.dromara.system.domain.vo.SysClientVo; + +import java.util.Collection; +import java.util.List; + +/** + * 客户端管理Service接口 + * + * @author Michelle.Chung + * @date 2023-06-18 + */ +public interface ISysClientService { + + /** + * 查询客户端管理 + */ + SysClientVo queryById(Long id); + + /** + * 查询客户端信息基于客户端id + */ + SysClientVo queryByClientId(String clientId); + + /** + * 查询客户端管理列表 + */ + PageResult queryPageList(SysClientBo bo, PageQuery pageQuery); + + /** + * 查询客户端管理列表 + */ + List queryList(SysClientBo bo); + + /** + * 新增客户端管理 + */ + Boolean insertByBo(SysClientBo bo); + + /** + * 修改客户端管理 + */ + Boolean updateByBo(SysClientBo bo); + + /** + * 修改状态 + */ + int updateClientStatus(String clientId, String status); + + /** + * 校验并批量删除客户端管理信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 校验客户端key是否唯一 + * + * @param client 客户端信息 + * @return 结果 + */ + boolean checkClickKeyUnique(SysClientBo client); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java new file mode 100644 index 000000000..e581407b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java @@ -0,0 +1,94 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; + +import java.util.Collection; +import java.util.List; + +/** + * 参数配置 服务层 + * + * @author Lion Li + */ +public interface ISysConfigService { + + /** + * 分页查询参数配置列表 + * + * @param config 查询条件 + * @param pageQuery 分页参数 + * @return 参数配置分页列表 + */ + PageResult selectPageConfigList(SysConfigBo config, PageQuery pageQuery); + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + SysConfigVo selectConfigById(Long configId); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数键值 + */ + String selectConfigByKey(String configKey); + + /** + * 获取注册开关 + * + * @return true开启,false关闭 + */ + boolean selectRegisterEnabled(); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + List selectConfigList(SysConfigBo config); + + /** + * 新增参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + String insertConfig(SysConfigBo bo); + + /** + * 修改参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + String updateConfig(SysConfigBo bo); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + void deleteConfigByIds(Collection configIds); + + /** + * 重置参数缓存数据 + */ + void resetConfigCache(); + + /** + * 校验参数键名是否唯一 + * + * @param config 参数信息 + * @return 结果 + */ + boolean checkConfigKeyUnique(SysConfigBo config); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java new file mode 100644 index 000000000..3f252f7e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java @@ -0,0 +1,26 @@ +package org.dromara.system.service; + +/** + * 通用 数据权限 服务 + * + * @author Lion Li + */ +public interface ISysDataScopeService { + + /** + * 获取角色自定义权限 + * + * @param roleId 角色id + * @return 部门id组 + */ + String getRoleCustom(Long roleId); + + /** + * 获取部门及以下权限 + * + * @param deptId 部门id + * @return 部门id组 + */ + String getDeptAndChild(Long deptId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java new file mode 100644 index 000000000..515ffa4e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java @@ -0,0 +1,138 @@ +package org.dromara.system.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; + +import java.util.Collection; +import java.util.List; + +/** + * 部门管理 服务层 + * + * @author Lion Li + */ +public interface ISysDeptService { + + /** + * 分页查询部门管理数据 + * + * @param dept 部门信息 + * @param pageQuery 分页对象 + * @return 部门信息集合 + */ + PageResult selectPageDeptList(SysDeptBo dept, PageQuery pageQuery); + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + List selectDeptList(SysDeptBo dept); + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + List> selectDeptTreeList(SysDeptBo dept); + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + List> buildDeptTreeSelect(List depts); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + List selectDeptListByRoleId(Long roleId); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + SysDeptVo selectDeptById(Long deptId); + + /** + * 通过部门ID串查询部门 + * + * @param deptIds 部门id串 + * @return 部门列表信息 + */ + List selectDeptByIds(Collection deptIds); + + /** + * 根据ID查询所有子部门数(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + long selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在部门子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + boolean hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + boolean checkDeptNameUnique(SysDeptBo dept); + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + void checkDeptDataScope(Long deptId); + + /** + * 新增保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + int insertDept(SysDeptBo bo); + + /** + * 修改保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + int updateDept(SysDeptBo bo); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + int deleteDeptById(Long deptId); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java new file mode 100644 index 000000000..540453ac4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java @@ -0,0 +1,83 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; + +import java.util.Collection; +import java.util.List; + +/** + * 字典 业务层 + * + * @author Lion Li + */ +public interface ISysDictDataService { + + /** + * 分页查询字典数据列表 + * + * @param dictData 查询条件 + * @param pageQuery 分页参数 + * @return 字典数据分页列表 + */ + PageResult selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery); + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + List selectDictDataList(SysDictDataBo dictData); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + String selectDictLabel(String dictType, String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + SysDictDataVo selectDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + void deleteDictDataByIds(Collection dictCodes); + + /** + * 新增保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + List insertDictData(SysDictDataBo bo); + + /** + * 修改保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + List updateDictData(SysDictDataBo bo); + + /** + * 校验字典键值是否唯一 + * + * @param dict 字典数据 + * @return 结果 + */ + boolean checkDictDataUnique(SysDictDataBo dict); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java new file mode 100644 index 000000000..6ad37691d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java @@ -0,0 +1,102 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysDictTypeVo; + +import java.util.Collection; +import java.util.List; + +/** + * 字典 业务层 + * + * @author Lion Li + */ +public interface ISysDictTypeService { + + /** + * 分页查询字典类型列表 + * + * @param dictType 查询条件 + * @param pageQuery 分页参数 + * @return 字典类型分页列表 + */ + PageResult selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery); + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + List selectDictTypeList(SysDictTypeBo dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + List selectDictTypeAll(); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + List selectDictDataByType(String dictType); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + SysDictTypeVo selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + SysDictTypeVo selectDictTypeByType(String dictType); + + /** + * 批量删除字典信息 + * + * @param dictIds 需要删除的字典ID + */ + void deleteDictTypeByIds(Collection dictIds); + + /** + * 重置字典缓存数据 + */ + void resetDictCache(); + + /** + * 新增保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + List insertDictType(SysDictTypeBo bo); + + /** + * 修改保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + List updateDictType(SysDictTypeBo bo); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + boolean checkDictTypeUnique(SysDictTypeBo dictType); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLoginInfoService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLoginInfoService.java new file mode 100644 index 000000000..ff0136a29 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLoginInfoService.java @@ -0,0 +1,53 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysLoginInfoBo; +import org.dromara.system.domain.vo.SysLoginInfoVo; + +import java.util.List; + +/** + * 系统访问日志情况信息 服务层 + * + * @author Lion Li + */ +public interface ISysLoginInfoService { + + /** + * 分页查询登录日志列表 + * + * @param loginInfo 查询条件 + * @param pageQuery 分页参数 + * @return 登录日志分页列表 + */ + PageResult selectPageLoginInfoList(SysLoginInfoBo loginInfo, PageQuery pageQuery); + + /** + * 新增系统登录日志 + * + * @param bo 访问日志对象 + */ + void insertLoginInfo(SysLoginInfoBo bo); + + /** + * 查询系统登录日志集合 + * + * @param loginInfo 访问日志对象 + * @return 登录记录集合 + */ + List selectLoginInfoList(SysLoginInfoBo loginInfo); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + int deleteLoginInfoByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + */ + void cleanLoginInfo(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java new file mode 100644 index 000000000..dd851d711 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java @@ -0,0 +1,173 @@ +package org.dromara.system.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 菜单 业务层 + * + * @author Lion Li + */ +public interface ISysMenuService { + + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuList(Long userId); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuList(SysMenuBo menu, Long userId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + Set selectMenuPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + Set selectMenuPermsByRoleId(Long roleId); + + /** + * 根据角色ID列表批量查询权限 + * + * @param roleIds 角色ID列表 + * @return 角色权限映射 + */ + Map> selectMenuPermsByRoleIds(Collection roleIds); + + /** + * 根据用户ID查询菜单树信息 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + List selectMenuListByRoleId(Long roleId); + + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + List buildMenus(List menus); + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + List> buildMenuTreeSelect(List menus); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + SysMenuVo selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + boolean hasChildByMenuId(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuIds 菜单ID列表 + * @return 结果 true 存在 false 不存在 + */ + boolean hasChildByMenuId(Collection menuIds); + + /** + * 查询菜单是否存在角色 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkMenuExistRole(Long menuId); + + /** + * 新增保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + int insertMenu(SysMenuBo bo); + + /** + * 修改保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + int updateMenu(SysMenuBo bo); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + int deleteMenuById(Long menuId); + + /** + * 批量删除菜单管理信息 + * + * @param menuIds 菜单ID列表 + */ + void deleteMenuById(Collection menuIds); + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + boolean checkMenuNameUnique(SysMenuBo menu); + + /** + * 校验路由组合是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + boolean checkRouteConfigUnique(SysMenuBo menu); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java new file mode 100644 index 000000000..f53d51807 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java @@ -0,0 +1,93 @@ +package org.dromara.system.service; + +import org.dromara.system.api.domain.PushPayloadDTO; +import org.dromara.system.domain.vo.SysMessageBoxVo; + +import java.util.List; + +/** + * 消息记录服务接口 + * + * @author Lion Li + */ +public interface ISysMessageService { + + /** + * 查询当前用户消息盒子数据 + * 按系统消息、通知公告、工作流消息分类返回 + * + * @param userId 用户ID + * @return 消息盒子数据 + */ + SysMessageBoxVo queryMessageBox(Long userId); + + /** + * 发送指定用户文本消息 + * + * @param userId 目标用户ID + * @param message 文本消息内容 + */ + void sendMessage(Long userId, String message); + + /** + * 全局广播文本消息 + * + * @param message 文本消息内容 + */ + void sendMessage(String message); + + /** + * 发送指定用户自定义消息体 + * + * @param userId 目标用户ID + * @param payload 消息推送体 + */ + void sendMessage(Long userId, PushPayloadDTO payload); + + /** + * 全局广播自定义消息体 + * + * @param payload 消息推送体 + */ + void sendMessage(PushPayloadDTO payload); + + /** + * 批量发布消息给指定用户列表 + * + * @param userIds 用户ID集合 + * @param payload 消息推送体 + */ + void publishMessage(List userIds, PushPayloadDTO payload); + + /** + * 发布全局广播文本消息 + * + * @param message 文本消息内容 + */ + void publishAll(String message); + + /** + * 发布全局广播自定义消息体 + * + * @param payload 消息推送体 + */ + void publishAll(PushPayloadDTO payload); + + /** + * 存储全局广播消息到数据库 + * + * @param payload 消息推送体 + * @return 回填消息ID后的消息体 + */ + PushPayloadDTO storeAll(PushPayloadDTO payload); + + /** + * 存储指定用户消息到数据库 + * + * @param userIds 用户ID集合 + * @param payload 消息推送体 + * @return 回填消息ID后的消息体 + */ + PushPayloadDTO storeUsers(List userIds, PushPayloadDTO payload); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java new file mode 100644 index 000000000..78de4bb5c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java @@ -0,0 +1,73 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; + +import java.util.List; + +/** + * 公告 服务层 + * + * @author Lion Li + */ +public interface ISysNoticeService { + + /** + * 分页查询通知公告列表 + * + * @param notice 查询条件 + * @param pageQuery 分页参数 + * @return 通知公告分页列表 + */ + PageResult selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery); + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + SysNoticeVo selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + List selectNoticeList(SysNoticeBo notice); + + /** + * 新增公告 + * + * @param bo 公告信息 + * @return 结果 + */ + int insertNotice(SysNoticeBo bo); + + /** + * 修改公告 + * + * @param bo 公告信息 + * @return 结果 + */ + int updateNotice(SysNoticeBo bo); + + /** + * 删除公告信息 + * + * @param noticeId 公告ID + * @return 结果 + */ + int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java new file mode 100644 index 000000000..7c3bf4dcf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java @@ -0,0 +1,61 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; + +import java.util.List; + +/** + * 操作日志 服务层 + * + * @author Lion Li + */ +public interface ISysOperLogService { + + /** + * 分页查询操作日志列表 + * + * @param operLog 查询条件 + * @param pageQuery 分页参数 + * @return 操作日志分页列表 + */ + PageResult selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery); + + /** + * 新增操作日志 + * + * @param bo 操作日志对象 + */ + void insertOperlog(SysOperLogBo bo); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + List selectOperLogList(SysOperLogBo operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + SysOperLogVo selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + void cleanOperLog(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java new file mode 100644 index 000000000..d7734e528 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java @@ -0,0 +1,64 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; + +import java.util.Collection; + +/** + * 对象存储配置Service接口 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +public interface ISysOssConfigService { + + /** + * 初始化OSS配置 + */ + void init(); + + /** + * 查询单个 + */ + SysOssConfigVo queryById(Long ossConfigId); + + /** + * 查询列表 + */ + PageResult queryPageList(SysOssConfigBo bo, PageQuery pageQuery); + + /** + * 根据新增业务对象插入对象存储配置 + * + * @param bo 对象存储配置新增业务对象 + * @return 结果 + */ + Boolean insertByBo(SysOssConfigBo bo); + + /** + * 根据编辑业务对象修改对象存储配置 + * + * @param bo 对象存储配置编辑业务对象 + * @return 结果 + */ + Boolean updateByBo(SysOssConfigBo bo); + + /** + * 校验并删除数据 + * + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return 结果 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 启用停用状态 + */ + int updateOssConfigStatus(SysOssConfigBo bo); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java new file mode 100644 index 000000000..074eee407 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java @@ -0,0 +1,81 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.SysOssExt; +import org.dromara.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssVo; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.util.Collection; +import java.util.List; + +/** + * 文件上传 服务层 + * + * @author Lion Li + */ +public interface ISysOssService { + + /** + * 查询OSS对象存储列表 + * + * @param sysOss OSS对象存储分页查询对象 + * @param pageQuery 分页查询实体类 + * @return 结果 + */ + PageResult queryPageList(SysOssBo sysOss, PageQuery pageQuery); + + /** + * 根据一组 ossIds 获取对应的 SysOssVo 列表 + * + * @param ossIds 一组文件在数据库中的唯一标识集合 + * @return 包含 SysOssVo 对象的列表 + */ + List listByIds(Collection ossIds); + + /** + * 根据 ossId 从缓存或数据库中获取 SysOssVo 对象 + * + * @param ossId 文件在数据库中的唯一标识 + * @return SysOssVo 对象,包含文件信息 + */ + SysOssVo getById(Long ossId); + + /** + * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @param ossExt 扩展信息 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssVo upload(MultipartFile file, SysOssExt ossExt); + + /** + * 上传文件到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的文件对象 + * @param ossExt 扩展信息 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssVo upload(File file, SysOssExt ossExt); + + /** + * 文件下载方法,支持一次性下载完整文件 + * + * @param ossId OSS对象ID + */ + ResponseEntity download(Long ossId); + + /** + * 删除OSS对象存储 + * + * @param ids OSS对象ID串 + * @param isValid 判断是否需要校验 + * @return 结果 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java new file mode 100644 index 000000000..ea63a14b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java @@ -0,0 +1,40 @@ +package org.dromara.system.service; + +import org.dromara.system.api.domain.RoleDTO; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 用户权限处理 + * + * @author Lion Li + */ +public interface ISysPermissionService { + + /** + * 获取角色数据权限 + * + * @param userId 用户id + * @return 角色权限信息 + */ + Set getRolePermission(Long userId); + + /** + * 获取菜单数据权限 + * + * @param userId 用户id + * @return 菜单权限信息 + */ + Set getMenuPermission(Long userId); + + /** + * 根据角色列表构建数据权限角色映射 + * + * @param roles 角色列表 + * @return key 为权限码 value 为命中的角色ID列表 + */ + Map> getDataScopeRoleMap(List roles); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java new file mode 100644 index 000000000..2662175a1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java @@ -0,0 +1,137 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.vo.SysPostVo; + +import java.util.Collection; +import java.util.List; + +/** + * 岗位信息 服务层 + * + * @author Lion Li + */ +public interface ISysPostService { + + /** + * 分页查询岗位列表 + * + * @param post 查询条件 + * @param pageQuery 分页参数 + * @return 岗位分页列表 + */ + PageResult selectPagePostList(SysPostBo post, PageQuery pageQuery); + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位列表 + */ + List selectPostList(SysPostBo post); + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 岗位列表 + */ + List selectPostsByUserId(Long userId); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + List selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 岗位信息 + */ + SysPostVo selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + List selectPostListByUserId(Long userId); + + /** + * 通过岗位ID串查询岗位 + * + * @param postIds 岗位id串 + * @return 岗位列表信息 + */ + List selectPostByIds(Collection postIds); + + /** + * 校验岗位名称 + * + * @param post 岗位信息 + * @return 是否唯一 + */ + boolean checkPostNameUnique(SysPostBo post); + + /** + * 校验岗位编码 + * + * @param post 岗位信息 + * @return 是否唯一 + */ + boolean checkPostCodeUnique(SysPostBo post); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 绑定用户数量 + */ + long countUserPostById(Long postId); + + /** + * 通过部门ID查询岗位使用数量 + * + * @param deptId 部门id + * @return 岗位数量 + */ + long countPostByDeptId(Long deptId); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 影响行数 + */ + int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 影响行数 + */ + int deletePostByIds(Collection postIds); + + /** + * 新增保存岗位信息 + * + * @param bo 岗位信息 + * @return 影响行数 + */ + int insertPost(SysPostBo bo); + + /** + * 修改保存岗位信息 + * + * @param bo 岗位信息 + * @return 影响行数 + */ + int updatePost(SysPostBo bo); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java new file mode 100644 index 000000000..207fd06de --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java @@ -0,0 +1,238 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.vo.SysRoleVo; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * 角色业务层 + * + * @author Lion Li + */ +public interface ISysRoleService { + + /** + * 分页查询角色列表 + * + * @param role 查询条件 + * @param pageQuery 分页参数 + * @return 角色分页列表 + */ + PageResult selectPageRoleList(SysRoleBo role, PageQuery pageQuery); + + /** + * 根据条件查询角色数据 + * + * @param role 角色信息 + * @return 角色列表 + */ + List selectRoleList(SysRoleBo role); + + /** + * 根据用户ID查询角色列表 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesByUserId(Long userId); + + /** + * 根据用户ID查询角色列表(包含被授权状态) + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesAuthByUserId(Long userId); + + /** + * 根据用户ID查询角色权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + Set selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + List selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + List selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + SysRoleVo selectRoleById(Long roleId); + + /** + * 通过角色ID串查询角色 + * + * @param roleIds 角色ID串 + * @return 角色列表信息 + */ + List selectRoleByIds(Collection roleIds); + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 是否唯一 + */ + boolean checkRoleNameUnique(SysRoleBo role); + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 是否唯一 + */ + boolean checkRoleKeyUnique(SysRoleBo role); + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + void checkRoleAllowed(SysRoleBo role); + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + void checkRoleDataScope(Long roleId); + + /** + * 校验角色是否有数据权限 + * + * @param roleIds 角色ID列表(支持传单个ID) + */ + void checkRoleDataScope(Collection roleIds); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 绑定用户数量 + */ + long countUserRoleByRoleId(Long roleId); + + /** + * 新增保存角色信息 + * + * @param bo 角色信息 + * @return 影响行数 + */ + int insertRole(SysRoleBo bo); + + /** + * 修改角色基础信息(不包含菜单/数据权限)。 + * + * @param bo 角色信息 + * @return 影响行数 + */ + int updateRoleBaseInfo(SysRoleBo bo); + + /** + * 修改角色权限信息(菜单权限 + 数据权限)。 + * + * @param bo 角色权限参数 + * @return 影响行数 + */ + int updateRolePermission(SysRoleBo bo); + + /** + * 修改角色状态 + * + * @param roleId 角色ID + * @param status 角色状态 + * @return 影响行数 + */ + int updateRoleStatus(Long roleId, String status); + + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 影响行数 + */ + int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 影响行数 + */ + int deleteRoleByIds(Collection roleIds); + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 影响行数 + */ + int deleteAuthUser(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 影响行数 + */ + int deleteAuthUsers(Long roleId, Collection userIds); + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 影响行数 + */ + int insertAuthUsers(Long roleId, Collection userIds); + + /** + * 根据角色ID清除该角色关联的所有在线用户的登录状态(踢出在线用户) + * + *

+ * 先判断角色是否绑定用户,若无绑定则直接返回 + * 然后遍历当前所有在线Token,查找拥有该角色的用户并强制登出 + * 注意:在线用户量过大时,操作可能导致 Redis 阻塞,需谨慎调用 + *

+ * + * @param roleId 角色ID + */ + void cleanOnlineUserByRole(Long roleId); + + /** + * 根据用户ID列表清除对应在线用户的登录状态(踢出指定用户) + * + *

+ * 遍历当前所有在线Token,匹配用户ID列表中的用户,强制登出 + * 注意:在线用户量过大时,操作可能导致 Redis 阻塞,需谨慎调用 + *

+ * + * @param userIds 需要清除的用户ID列表 + */ + void cleanOnlineUser(Collection userIds); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java new file mode 100644 index 000000000..cc7016e42 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java @@ -0,0 +1,53 @@ +package org.dromara.system.service; + +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.SysSocialVo; + +import java.util.List; + +/** + * 社会化关系Service接口 + * + * @author thiszhc + */ +public interface ISysSocialService { + + + /** + * 查询社会化关系 + */ + SysSocialVo queryById(String id); + + /** + * 查询社会化关系列表 + */ + List queryList(SysSocialBo bo); + + /** + * 查询社会化关系列表 + */ + List queryListByUserId(Long userId); + + /** + * 新增授权关系 + */ + Boolean insertByBo(SysSocialBo bo); + + /** + * 更新社会化关系 + */ + Boolean updateByBo(SysSocialBo bo); + + /** + * 删除社会化关系信息 + */ + Boolean deleteWithValidById(Long id); + + + /** + * 根据 authId 查询 + */ + List selectByAuthId(String authId); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java new file mode 100644 index 000000000..623374267 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java @@ -0,0 +1,223 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserExportVo; +import org.dromara.system.domain.vo.SysUserVo; + +import java.util.Collection; +import java.util.List; + +/** + * 用户 业务层 + * + * @author Lion Li + */ +public interface ISysUserService { + + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @param pageQuery 分页参数 + * @return 用户分页信息 + */ + PageResult selectPageUserList(SysUserBo user, PageQuery pageQuery); + + /** + * 导出用户列表 + * + * @param user 用户信息 + * @return 用户导出列表 + */ + List selectUserExportList(SysUserBo user); + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @param pageQuery 分页 + * @return 已分配角色的用户分页信息 + */ + PageResult selectAllocatedList(SysUserBo user, PageQuery pageQuery); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @param pageQuery 分页 + * @return 未分配角色的用户分页信息 + */ + PageResult selectUnallocatedList(SysUserBo user, PageQuery pageQuery); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + SysUserVo selectUserByUserName(String userName); + + /** + * 通过手机号查询用户 + * + * @param phoneNumber 手机号 + * @return 用户对象信息 + */ + SysUserVo selectUserByPhoneNumber(String phoneNumber); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + SysUserVo selectUserById(Long userId); + + /** + * 通过用户ID串查询用户 + * + * @param userIds 用户ID串 + * @param deptId 部门id + * @return 用户列表信息 + */ + List selectUserByIds(Collection userIds, Long deptId); + + /** + * 根据用户ID查询用户所属角色组 + * + * @param userId 用户ID + * @return 结果 + */ + String selectUserRoleGroup(Long userId); + + /** + * 根据用户ID查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + String selectUserPostGroup(Long userId); + + /** + * 校验用户账号是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkUserNameUnique(SysUserBo user); + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkPhoneUnique(SysUserBo user); + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkEmailUnique(SysUserBo user); + + /** + * 校验用户是否允许操作 + * + * @param userId 用户ID + */ + void checkUserAllowed(Long userId); + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + void checkUserDataScope(Long userId); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + int insertUser(SysUserBo user); + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 是否注册成功 + */ + boolean registerUser(SysUserBo user); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUser(SysUserBo user); + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + void insertUserAuth(Long userId, Long[] roleIds); + + /** + * 修改用户状态 + * + * @param userId 用户ID + * @param status 账号状态 + * @return 结果 + */ + int updateUserStatus(Long userId, String status); + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUserProfile(SysUserBo user); + + /** + * 重置用户密码 + * + * @param userId 用户ID + * @param password 密码 + * @return 结果 + */ + int resetUserPwd(Long userId, String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + int deleteUserByIds(Long[] userIds); + + /** + * 通过部门id查询当前部门所有用户 + * + * @param deptId 部门id + * @return 结果 + */ + List selectUserListByDept(Long deptId); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java new file mode 100644 index 000000000..16cdd6bc3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java @@ -0,0 +1,268 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.SecureUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.bo.SysClientBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.mapper.SysClientMapper; +import org.dromara.system.service.ISysClientService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.function.UnaryOperator; + +/** + * 客户端管理Service业务层处理 + * + * @author Michelle.Chung + * @date 2023-06-18 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysClientServiceImpl implements ISysClientService { + + private static final String CLIENT_RULE_SEPARATOR_REGEX = "[,;\\r\\n]+"; + + private final SysClientMapper clientMapper; + + /** + * 查询客户端管理 + * + * @param id 主键 + * @return 客户端详情 + */ + @Override + public SysClientVo queryById(Long id) { + SysClientVo vo = clientMapper.selectVoById(id); + fillClientRuleFields(vo); + return vo; + } + + /** + * 查询客户端管理 + * + * @param clientId 客户端标识 + * @return 客户端详情 + */ + @Cacheable(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId") + @Override + public SysClientVo queryByClientId(String clientId) { + SysClientVo vo = clientMapper.lambda().eq(SysClient::getClientId, clientId).voOne(); + fillClientRuleFields(vo); + return vo; + } + + /** + * 查询客户端管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 客户端分页列表 + */ + @Override + public PageResult queryPageList(SysClientBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = clientMapper.selectVoPage(pageQuery.build(), lqw); + result.getRecords().forEach(this::fillClientRuleFields); + return PageResult.build(result.getRecords(), result.getTotal()); + } + + /** + * 查询客户端管理列表 + * + * @param bo 查询条件 + * @return 客户端列表 + */ + @Override + public List queryList(SysClientBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List list = clientMapper.selectVoList(lqw); + list.forEach(this::fillClientRuleFields); + return list; + } + + /** + * 构造客户端列表查询条件。 + * + * @param bo 客户端筛选条件 + * @return 包含 clientId、clientKey、状态等条件的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysClientBo bo) { + return QueryBuilder.lambda(SysClient.class) + .eqIfText(SysClient::getClientId, bo.getClientId()) + .eqIfText(SysClient::getClientKey, bo.getClientKey()) + .eqIfText(SysClient::getClientSecret, bo.getClientSecret()) + .eqIfText(SysClient::getStatus, bo.getStatus()) + .orderByAsc(SysClient::getId) + .build(); + } + + /** + * 新增客户端管理 + * + * @param bo 客户端业务对象 + * @return 新增成功返回 {@code true} + */ + @Override + public Boolean insertByBo(SysClientBo bo) { + SysClient add = MapstructUtils.convert(bo, SysClient.class); + add.setGrantType(CollUtil.join(bo.getGrantTypeList(), StringUtils.SEPARATOR)); + add.setAccessPath(resolveRuleValue(bo.getAccessPath(), bo.getAccessPathList(), this::normalizeAccessPath)); + add.setIpWhitelist(resolveRuleValue(bo.getIpWhitelist(), bo.getIpWhitelistList(), UnaryOperator.identity())); + // 生成clientid + String clientKey = bo.getClientKey(); + String clientSecret = bo.getClientSecret(); + add.setClientId(SecureUtil.md5(clientKey + clientSecret)); + boolean flag = clientMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改客户端管理 + * + * @param bo 客户端业务对象 + * @return 修改成功返回 {@code true} + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#bo.clientId") + @Override + public Boolean updateByBo(SysClientBo bo) { + SysClient update = MapstructUtils.convert(bo, SysClient.class); + update.setGrantType(StringUtils.joinComma(bo.getGrantTypeList())); + update.setAccessPath(resolveRuleValue(bo.getAccessPath(), bo.getAccessPathList(), this::normalizeAccessPath)); + update.setIpWhitelist(resolveRuleValue(bo.getIpWhitelist(), bo.getIpWhitelistList(), UnaryOperator.identity())); + return clientMapper.updateById(update) > 0; + } + + /** + * 修改状态 + * + * @param clientId 客户端标识 + * @param status 状态值 + * @return 更新条数 + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId") + @Override + public int updateClientStatus(String clientId, String status) { + return clientMapper.lambda() + .set(SysClient::getStatus, status) + .eq(SysClient::getClientId, clientId) + .updateCount(); + } + + /** + * 批量删除客户端管理 + * + * @param ids 主键集合 + * @param isValid 是否执行业务校验 + * @return 删除成功返回 {@code true} + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, allEntries = true) + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + return clientMapper.deleteByIds(ids) > 0; + } + + /** + * 校验客户端key是否唯一 + * + * @param client 客户端信息 + * @return 结果 + */ + @Override + public boolean checkClickKeyUnique(SysClientBo client) { + boolean exist = clientMapper.lambda() + .eq(SysClient::getClientKey, client.getClientKey()) + .neIfPresent(SysClient::getId, client.getId()) + .exists(); + return !exist; + } + + /** + * 回填客户端扩展规则字段,便于前端直接展示和编辑。 + * + * @param vo 客户端视图对象 + */ + private void fillClientRuleFields(SysClientVo vo) { + if (ObjectUtil.isNull(vo)) { + return; + } + vo.setGrantTypeList(StringUtils.splitList(vo.getGrantType())); + vo.setAccessPathList(parseRuleList(vo.getAccessPath(), this::normalizeAccessPath)); + vo.setIpWhitelistList(parseRuleList(vo.getIpWhitelist(), UnaryOperator.identity())); + } + + /** + * 统一处理白名单与路径规则的入库格式。 + * + * @param rawValue 原始字符串 + * @param listValue 列表值 + * @param normalizer 单条规则归一化器 + * @return 逗号拼接后的规则串 + */ + private String resolveRuleValue(String rawValue, List listValue, UnaryOperator normalizer) { + List rules = rawValue != null + ? StringUtils.str2List(rawValue, CLIENT_RULE_SEPARATOR_REGEX, true, true) + : listValue; + if (CollUtil.isEmpty(rules)) { + return listValue != null || rawValue != null ? "" : null; + } + return CollUtil.join(rules.stream() + .map(normalizer) + .filter(StringUtils::isNotBlank) + .toList(), StringUtils.SEPARATOR); + } + + /** + * 将规则串转换为列表。 + * + * @param value 规则串 + * @param normalizer 单条规则归一化器 + * @return 规则列表 + */ + private List parseRuleList(String value, UnaryOperator normalizer) { + return StringUtils.str2List(value, CLIENT_RULE_SEPARATOR_REGEX, true, true).stream() + .map(normalizer) + .filter(StringUtils::isNotBlank) + .toList(); + } + + /** + * 统一补齐路径前导斜杠,避免配置成 app/** 时无法命中。 + * + * @param path 路径规则 + * @return 规范化后的路径规则 + */ + private String normalizeAccessPath(String path) { + if (StringUtils.isBlank(path)) { + return null; + } + String accessPath = StringUtils.trim(path); + if (StringUtils.isBlank(accessPath)) { + return null; + } + if (StringUtils.equals(accessPath, "*") || StringUtils.equals(accessPath, "/**")) { + return "/**"; + } + return accessPath.startsWith(StringUtils.SLASH) ? accessPath : StringUtils.SLASH + accessPath; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java new file mode 100644 index 000000000..cac34e329 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,270 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.system.api.ConfigService; +import org.dromara.system.domain.SysConfig; +import org.dromara.system.domain.bo.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; +import org.dromara.system.mapper.SysConfigMapper; +import org.dromara.system.service.ISysConfigService; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 参数配置 服务层实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysConfigServiceImpl implements ISysConfigService, ConfigService { + + private final SysConfigMapper configMapper; + + /** + * 分页查询参数配置列表 + * + * @param config 查询条件 + * @param pageQuery 分页参数 + * @return 参数配置分页列表 + */ + @Override + public PageResult selectPageConfigList(SysConfigBo config, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(config); + Page page = configMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + @Override + public SysConfigVo selectConfigById(Long configId) { + return configMapper.selectVoById(configId); + } + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数key + * @return 参数键值 + */ + @Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configKey") + @Override + public String selectConfigByKey(String configKey) { + SysConfig retConfig = configMapper.lambda().eq(SysConfig::getConfigKey, configKey).one(); + return ObjectUtils.notNullGetter(retConfig, SysConfig::getConfigValue, StringUtils.EMPTY); + } + + /** + * 获取注册开关 + * + * @return true开启,false关闭 + */ + @Override + public boolean selectRegisterEnabled() { + return Convert.toBool(this.getConfigValue("sys.account.registerUser")); + } + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + @Override + public List selectConfigList(SysConfigBo config) { + LambdaQueryWrapper lqw = buildQueryWrapper(config); + return configMapper.selectVoList(lqw); + } + + /** + * 构造参数配置列表查询条件。 + * + * @param bo 参数配置筛选条件 + * @return 包含名称、键名、类型与时间区间的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysConfigBo bo) { + Map params = bo.getParams(); + return QueryBuilder.lambda(SysConfig.class) + .likeIfText(SysConfig::getConfigName, bo.getConfigName()) + .eqIfText(SysConfig::getConfigType, bo.getConfigType()) + .likeIfText(SysConfig::getConfigKey, bo.getConfigKey()) + .betweenParams(SysConfig::getCreateTime, params, "beginTime", "endTime") + .orderByAsc(SysConfig::getConfigId) + .build(); + } + + /** + * 新增参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey") + @Override + public String insertConfig(SysConfigBo bo) { + SysConfig config = MapstructUtils.convert(bo, SysConfig.class); + int row = configMapper.insert(config); + if (row > 0) { + return config.getConfigValue(); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey") + @Override + public String updateConfig(SysConfigBo bo) { + int row; + SysConfig config = MapstructUtils.convert(bo, SysConfig.class); + if (config.getConfigId() != null) { + SysConfig temp = configMapper.selectById(config.getConfigId()); + if (ObjectUtil.isNotNull(temp) && !StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) { + CacheUtils.evict(CacheNames.SYS_CONFIG, temp.getConfigKey()); + } + row = configMapper.updateById(config); + } else { + CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey()); + row = configMapper.lambda() + .eq(SysConfig::getConfigKey, config.getConfigKey()) + .updateCount(config); + } + if (row > 0) { + return config.getConfigValue(); + } + throw new ServiceException("操作失败"); + } + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + @Override + public void deleteConfigByIds(Collection configIds) { + List list = configMapper.selectByIds(configIds); + list.forEach(config -> { + if (StringUtils.equals(SystemConstants.YES, config.getConfigType())) { + throw new ServiceException("内置参数【{}】不能删除", config.getConfigKey()); + } + CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey()); + }); + configMapper.deleteByIds(configIds); + } + + /** + * 重置参数缓存数据 + */ + @Override + public void resetConfigCache() { + CacheUtils.clear(CacheNames.SYS_CONFIG); + } + + /** + * 校验参数键名是否唯一 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public boolean checkConfigKeyUnique(SysConfigBo config) { + boolean exist = configMapper.lambda() + .eq(SysConfig::getConfigKey, config.getConfigKey()) + .neIfPresent(SysConfig::getConfigId, config.getConfigId()) + .exists(); + return !exist; + } + + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + @Override + public String getConfigValue(String configKey) { + return SpringUtils.getAopProxy(this).selectConfigByKey(configKey); + } + + /** + * 根据参数 key 获取 Map 类型的配置 + * + * @param configKey 参数 key + * @return Dict 对象,如果配置为空或无法解析则返回空 Dict + */ + @Override + public Dict getConfigMap(String configKey) { + String configValue = getConfigValue(configKey); + return JsonUtils.parseMap(configValue); + } + + /** + * 根据参数 key 获取 Map 类型的配置列表 + * + * @param configKey 参数 key + * @return Dict 列表,如果配置为空或无法解析则返回空列表 + */ + @Override + public List getConfigArrayMap(String configKey) { + String configValue = getConfigValue(configKey); + return JsonUtils.parseArrayMap(configValue); + } + + /** + * 根据参数 key 获取指定类型的配置对象 + * + * @param configKey 参数 key + * @param clazz 目标对象类型 + * @return 对象实例,如果配置为空或无法解析,返回 null + */ + @Override + public T getConfigObject(String configKey, Class clazz) { + String configValue = getConfigValue(configKey); + return JsonUtils.parseObject(configValue, clazz); + } + + /** + * 根据参数 key 获取指定类型的配置列表= + * + * @param configKey 参数 key + * @param clazz 目标元素类型 + * @return 指定类型列表,如果配置为空或无法解析,返回空列表 + */ + @Override + public List getConfigArray(String configKey, Class clazz) { + String configValue = getConfigValue(configKey); + return JsonUtils.parseArray(configValue, clazz); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java new file mode 100644 index 000000000..e94c5780c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java @@ -0,0 +1,72 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.system.domain.SysRoleDept; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysRoleDeptMapper; +import org.dromara.system.service.ISysDataScopeService; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 数据权限 实现 + *

+ * 注意: 此Service内不允许调用标注`数据权限`注解的方法 + * 例如: deptMapper.selectList 此 selectList 方法标注了`数据权限`注解 会出现循环解析的问题 + * 当前实现仅负责返回角色自定义部门范围以及部门树展开后的 id 串,供数据权限插件拼装 SQL 时使用。 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service("sdss") +public class SysDataScopeServiceImpl implements ISysDataScopeService { + + private final SysRoleDeptMapper roleDeptMapper; + private final SysDeptMapper deptMapper; + + /** + * 获取角色自定义权限 + * + * @param roleId 角色Id + * @return 逗号分隔的部门 id 字符串,未配置时返回 `-1` + */ + @Cacheable(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId", condition = "#roleId != null") + @Override + public String getRoleCustom(Long roleId) { + if (ObjectUtil.isNull(roleId)) { + return "-1"; + } + List list = roleDeptMapper.lambda() + .select(SysRoleDept::getDeptId) + .eq(SysRoleDept::getRoleId, roleId) + .list(); + if (CollUtil.isNotEmpty(list)) { + return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId())); + } + return "-1"; + } + + /** + * 获取部门及以下权限 + * + * @param deptId 部门Id + * @return 当前部门及其子部门的逗号分隔 id 字符串,未查询到时返回 `-1` + */ + @Cacheable(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId", condition = "#deptId != null") + @Override + public String getDeptAndChild(Long deptId) { + if (ObjectUtil.isNull(deptId)) { + return "-1"; + } + List deptIds = deptMapper.selectDeptAndChildById(deptId); + return CollUtil.isNotEmpty(deptIds) ? StreamUtils.join(deptIds, Convert::toStr) : "-1"; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java new file mode 100644 index 000000000..899cadb18 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,439 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.LambdaQueryBuilder; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.DeptService; +import org.dromara.system.api.domain.DeptDTO; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysDeptService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 部门管理 服务实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysDeptServiceImpl implements ISysDeptService, DeptService { + + private final SysDeptMapper deptMapper; + private final SysRoleMapper roleMapper; + private final SysUserMapper userMapper; + + /** + * 分页查询部门管理数据 + * + * @param dept 部门信息 + * @param pageQuery 分页对象 + * @return 部门信息集合 + */ + @Override + public PageResult selectPageDeptList(SysDeptBo dept, PageQuery pageQuery) { + Page page = deptMapper.selectPageDeptList(pageQuery.build(), buildQueryWrapper(dept)); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + @Override + public List selectDeptList(SysDeptBo dept) { + LambdaQueryWrapper lqw = buildQueryWrapper(dept); + return deptMapper.selectDeptList(lqw); + } + + /** + * 查询部门树结构信息 + * + * @param bo 部门信息 + * @return 部门树信息集合 + */ + @Override + public List> selectDeptTreeList(SysDeptBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List depts = deptMapper.selectDeptList(lqw); + return buildDeptTreeSelect(depts); + } + + /** + * 构造部门列表查询条件。 + * + * @param bo 部门筛选条件 + * @return 包含树级过滤、状态、分类和时间区间的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysDeptBo bo) { + Map params = bo.getParams(); + LambdaQueryBuilder builder = QueryBuilder.lambda(SysDept.class) + .eq(SysDept::getDelFlag, SystemConstants.NORMAL) + .eqIfPresent(SysDept::getDeptId, bo.getDeptId()) + .eqIfPresent(SysDept::getParentId, bo.getParentId()) + .likeIfText(SysDept::getDeptName, bo.getDeptName()) + .likeIfText(SysDept::getDeptCategory, bo.getDeptCategory()) + .eqIfText(SysDept::getStatus, bo.getStatus()) + .betweenParams(SysDept::getCreateTime, params, "beginTime", "endTime") + .orderByAsc(SysDept::getAncestors, SysDept::getParentId, SysDept::getOrderNum, SysDept::getDeptId); + if (ObjectUtil.isNotNull(bo.getBelongDeptId())) { + //部门树搜索 + builder.and(x -> { + List deptIds = deptMapper.selectDeptAndChildById(bo.getBelongDeptId()); + x.in(SysDept::getDeptId, deptIds); + }); + } + return builder.build(); + } + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildDeptTreeSelect(List depts) { + if (CollUtil.isEmpty(depts)) { + return CollUtil.newArrayList(); + } + return TreeBuildUtils.buildMultiRoot( + depts, + SysDeptVo::getDeptId, + SysDeptVo::getParentId, + (node, treeNode) -> treeNode + .setId(node.getDeptId()) + .setParentId(node.getParentId()) + .setName(node.getDeptName()) + .setWeight(node.getOrderNum()) + .putExtra("disabled", SystemConstants.DISABLE.equals(node.getStatus())) + ); + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + @Override + public List selectDeptListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + return deptMapper.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly()); + } + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_DEPT, key = "#deptId") + @Override + public SysDeptVo selectDeptById(Long deptId) { + SysDeptVo dept = deptMapper.selectVoById(deptId); + if (ObjectUtil.isNull(dept)) { + return null; + } + SysDeptVo parentDept = deptMapper.lambda() + .select(SysDept::getDeptName) + .eq(SysDept::getDeptId, dept.getParentId()) + .voOne(); + dept.setParentName(ObjectUtils.notNullGetter(parentDept, SysDeptVo::getDeptName)); + return dept; + } + + /** + * 按部门主键集合查询部门基础信息。 + * + * @param deptIds 部门主键集合 + * @return 部门基础信息列表 + */ + @Override + public List selectDeptByIds(Collection deptIds) { + return deptMapper.selectDeptList(deptMapper.lambda() + .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getLeader) + .eq(SysDept::getStatus, SystemConstants.NORMAL) + .in(CollUtil.isNotEmpty(deptIds), SysDept::getDeptId, deptIds) + .build()); + } + + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + @Override + public String selectDeptNameByIds(String deptIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(deptIds, Convert::toLong)) { + SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(id); + if (ObjectUtil.isNotNull(vo)) { + list.add(vo.getDeptName()); + } + } + return StringUtils.joinComma(list); + } + + /** + * 根据部门ID查询部门负责人 + * + * @param deptId 部门ID,用于指定需要查询的部门 + * @return 返回该部门的负责人ID + */ + @Override + public Long selectDeptLeaderById(Long deptId) { + SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(deptId); + return ObjectUtil.isNull(vo) ? null : vo.getLeader(); + } + + /** + * 查询部门 + * + * @return 部门列表 + */ + @Override + public List selectDeptsByList() { + List list = deptMapper.selectDeptList(deptMapper.lambda() + .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getParentId) + .eq(SysDept::getStatus, SystemConstants.NORMAL) + .build()); + return BeanUtil.copyToList(list, DeptDTO.class); + } + + /** + * 根据ID查询所有子部门数(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + @Override + public long selectNormalChildrenDeptById(Long deptId) { + return deptMapper.lambda() + .eq(SysDept::getStatus, SystemConstants.NORMAL) + .findInSet(deptId, SysDept::getAncestors) + .count(); + } + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public boolean hasChildByDeptId(Long deptId) { + return deptMapper.lambda().eq(SysDept::getParentId, deptId).exists(); + } + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkDeptExistUser(Long deptId) { + return userMapper.lambda().eq(SysUser::getDeptId, deptId).exists(); + } + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public boolean checkDeptNameUnique(SysDeptBo dept) { + boolean exist = deptMapper.lambda() + .eq(SysDept::getDeptName, dept.getDeptName()) + .eq(SysDept::getParentId, dept.getParentId()) + .neIfPresent(SysDept::getDeptId, dept.getDeptId()) + .exists(); + return !exist; + } + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + @Override + public void checkDeptDataScope(Long deptId) { + if (ObjectUtil.isNull(deptId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (deptMapper.countDeptById(deptId) == 0) { + throw new ServiceException("没有权限访问部门数据!"); + } + } + + /** + * 新增保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true) + @Override + public int insertDept(SysDeptBo bo) { + SysDept info = deptMapper.selectById(bo.getParentId()); + // 如果父节点不存在或不为正常状态,则不允许新增子节点 + if (ObjectUtil.isNull(info)) { + throw new ServiceException("父部门不存在"); + } + if (!SystemConstants.NORMAL.equals(info.getStatus())) { + throw new ServiceException("部门停用,不允许新增"); + } + SysDept dept = MapstructUtils.convert(bo, SysDept.class); + dept.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + dept.getParentId()); + return deptMapper.insert(dept); + } + + /** + * 修改保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + @Caching(evict = { + @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#bo.deptId"), + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true) + }) + @Override + @Transactional(rollbackFor = Exception.class) + public int updateDept(SysDeptBo bo) { + SysDept dept = MapstructUtils.convert(bo, SysDept.class); + SysDept oldDept = deptMapper.selectById(dept.getDeptId()); + if (ObjectUtil.isNull(oldDept)) { + throw new ServiceException("部门不存在,无法修改"); + } + if (!oldDept.getParentId().equals(dept.getParentId())) { + // 如果是新父部门 则校验是否具有新父部门权限 避免越权 + this.checkDeptDataScope(dept.getParentId()); + SysDept newParentDept = deptMapper.selectById(dept.getParentId()); + if (ObjectUtil.isNotNull(newParentDept)) { + String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId(); + String oldAncestors = oldDept.getAncestors(); + dept.setAncestors(newAncestors); + updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors); + } + } else { + dept.setAncestors(oldDept.getAncestors()); + } + int result = deptMapper.updateById(dept); + // 如果部门状态为启用,且部门祖级列表不为空,且部门祖级列表不等于根部门祖级列表(如果部门祖级列表不等于根部门祖级列表,则说明存在上级部门) + if (SystemConstants.NORMAL.equals(dept.getStatus()) + && StringUtils.isNotEmpty(dept.getAncestors()) + && !StringUtils.equals(SystemConstants.ROOT_DEPT_ANCESTORS, dept.getAncestors())) { + // 如果该部门是启用状态,则启用该部门的所有上级部门 + updateParentDeptStatusNormal(dept); + } + return result; + } + + /** + * 修改该部门的父级部门状态 + * + * @param dept 当前部门 + */ + private void updateParentDeptStatusNormal(SysDept dept) { + String ancestors = dept.getAncestors(); + Long[] deptIds = Convert.toLongArray(ancestors); + deptMapper.lambda() + .set(SysDept::getStatus, SystemConstants.NORMAL) + .in(SysDept::getDeptId, Arrays.asList(deptIds)) + .update(); + } + + /** + * 修改子元素关系 + * + * @param deptId 被修改的部门ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + private void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) { + List children = deptMapper.lambda().findInSet(deptId, SysDept::getAncestors).list(); + List list = new ArrayList<>(); + for (SysDept child : children) { + SysDept dept = new SysDept(); + dept.setDeptId(child.getDeptId()); + dept.setAncestors(StringUtils.replaceOnce(child.getAncestors(), oldAncestors, newAncestors)); + list.add(dept); + } + if (CollUtil.isNotEmpty(list)) { + if (deptMapper.updateBatchById(list)) { + list.forEach(dept -> CacheUtils.evict(CacheNames.SYS_DEPT, dept.getDeptId())); + } + } + } + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + @Caching(evict = { + @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId"), + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true) + }) + @Override + public int deleteDeptById(Long deptId) { + return deptMapper.deleteById(deptId); + } + + + /** + * 根据部门 ID 列表查询部门名称映射关系 + * + * @param deptIds 部门 ID 列表 + * @return Map,其中 key 为部门 ID,value 为对应的部门名称 + */ + @Override + public Map selectDeptNamesByIds(Collection deptIds) { + if (CollUtil.isEmpty(deptIds)) { + return Collections.emptyMap(); + } + List list = deptMapper.lambda() + .select(SysDept::getDeptId, SysDept::getDeptName) + .in(SysDept::getDeptId, deptIds) + .list(); + return StreamUtils.toMap(list, SysDept::getDeptId, SysDept::getDeptName); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java new file mode 100644 index 000000000..1dba696a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,166 @@ +package org.dromara.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.system.domain.SysDictData; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.mapper.SysDictDataMapper; +import org.dromara.system.service.ISysDictDataService; +import org.springframework.cache.annotation.CachePut; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; + +/** + * 字典 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysDictDataServiceImpl implements ISysDictDataService { + + private final SysDictDataMapper dictDataMapper; + + /** + * 分页查询字典数据列表 + * + * @param dictData 查询条件 + * @param pageQuery 分页参数 + * @return 字典数据分页列表 + */ + @Override + public PageResult selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictData); + Page page = dictDataMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataList(SysDictDataBo dictData) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictData); + return dictDataMapper.selectVoList(lqw); + } + + /** + * 构造字典数据列表查询条件。 + * + * @param bo 字典数据筛选条件 + * @return 包含排序号、标签和字典类型条件的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysDictDataBo bo) { + return QueryBuilder.lambda(SysDictData.class) + .eqIfPresent(SysDictData::getDictSort, bo.getDictSort()) + .likeIfText(SysDictData::getDictLabel, bo.getDictLabel()) + .eqIfText(SysDictData::getDictType, bo.getDictType()) + .orderByAsc(SysDictData::getDictSort, SysDictData::getDictCode) + .build(); + } + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + @Override + public String selectDictLabel(String dictType, String dictValue) { + return dictDataMapper.lambda() + .select(SysDictData::getDictLabel) + .eq(SysDictData::getDictType, dictType) + .eq(SysDictData::getDictValue, dictValue) + .one() + .getDictLabel(); + } + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + @Override + public SysDictDataVo selectDictDataById(Long dictCode) { + return dictDataMapper.selectVoById(dictCode); + } + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + @Override + public void deleteDictDataByIds(Collection dictCodes) { + List list = dictDataMapper.selectByIds(dictCodes); + dictDataMapper.deleteByIds(dictCodes); + list.forEach(x -> CacheUtils.evict(CacheNames.SYS_DICT, x.getDictType())); + } + + /** + * 新增保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List insertDictData(SysDictDataBo bo) { + SysDictData data = MapstructUtils.convert(bo, SysDictData.class); + int row = dictDataMapper.insert(data); + if (row > 0) { + return dictDataMapper.selectDictDataByType(data.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List updateDictData(SysDictDataBo bo) { + SysDictData data = MapstructUtils.convert(bo, SysDictData.class); + int row = dictDataMapper.updateById(data); + if (row > 0) { + return dictDataMapper.selectDictDataByType(data.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 校验字典键值是否唯一 + * + * @param dict 字典数据 + * @return 结果 + */ + @Override + public boolean checkDictDataUnique(SysDictDataBo dict) { + boolean exist = dictDataMapper.lambda() + .eq(SysDictData::getDictType, dict.getDictType()) + .eq(SysDictData::getDictValue, dict.getDictValue()) + .neIfPresent(SysDictData::getDictCode, dict.getDictCode()) + .exists(); + return !exist; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 000000000..7652efecd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,322 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.dto.DictDataDTO; +import org.dromara.common.core.domain.dto.DictTypeDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.system.domain.SysDictData; +import org.dromara.system.domain.SysDictType; +import org.dromara.system.domain.bo.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysDictTypeVo; +import org.dromara.system.mapper.SysDictDataMapper; +import org.dromara.system.mapper.SysDictTypeMapper; +import org.dromara.system.service.ISysDictTypeService; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 字典 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService { + + private final SysDictTypeMapper dictTypeMapper; + private final SysDictDataMapper dictDataMapper; + + /** + * 分页查询字典类型列表 + * + * @param dictType 查询条件 + * @param pageQuery 分页参数 + * @return 字典类型分页列表 + */ + @Override + public PageResult selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictType); + Page page = dictTypeMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeList(SysDictTypeBo dictType) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictType); + return dictTypeMapper.selectVoList(lqw); + } + + /** + * 构造字典类型列表查询条件。 + * + * @param bo 字典类型筛选条件 + * @return 包含名称、类型与创建时间区间的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysDictTypeBo bo) { + return QueryBuilder.lambda(SysDictType.class) + .likeIfText(SysDictType::getDictName, bo.getDictName()) + .likeIfText(SysDictType::getDictType, bo.getDictType()) + .orderByAsc(SysDictType::getDictId) + .build(); + } + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeAll() { + return dictTypeMapper.selectVoList(); + } + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType") + @Override + public List selectDictDataByType(String dictType) { + List dictDatas = dictDataMapper.selectDictDataByType(dictType); + return CollUtil.isNotEmpty(dictDatas) ? dictDatas : Collections.emptyList(); + } + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + @Override + public SysDictTypeVo selectDictTypeById(Long dictId) { + return dictTypeMapper.selectVoById(dictId); + } + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + @Cacheable(cacheNames = CacheNames.SYS_DICT_TYPE, key = "#dictType") + @Override + public SysDictTypeVo selectDictTypeByType(String dictType) { + return dictTypeMapper.lambda().eq(SysDictType::getDictType, dictType).voOne(); + } + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + */ + @Override + public void deleteDictTypeByIds(Collection dictIds) { + List list = dictTypeMapper.selectByIds(dictIds); + list.forEach(x -> { + boolean assigned = dictDataMapper.lambda().eq(SysDictData::getDictType, x.getDictType()).exists(); + if (assigned) { + throw new ServiceException("{}已分配,不能删除", x.getDictName()); + } + }); + dictTypeMapper.deleteByIds(dictIds); + list.forEach(x -> { + CacheUtils.evict(CacheNames.SYS_DICT, x.getDictType()); + CacheUtils.evict(CacheNames.SYS_DICT_TYPE, x.getDictType()); + }); + } + + /** + * 重置字典缓存数据 + */ + @Override + public void resetDictCache() { + CacheUtils.clear(CacheNames.SYS_DICT); + CacheUtils.clear(CacheNames.SYS_DICT_TYPE); + } + + /** + * 新增保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List insertDictType(SysDictTypeBo bo) { + SysDictType dict = MapstructUtils.convert(bo, SysDictType.class); + int row = dictTypeMapper.insert(dict); + if (row > 0) { + // 新增 type 下无 data 数据 返回空防止缓存穿透 + return new ArrayList<>(); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + @Transactional(rollbackFor = Exception.class) + public List updateDictType(SysDictTypeBo bo) { + SysDictType dict = MapstructUtils.convert(bo, SysDictType.class); + SysDictType oldDict = dictTypeMapper.selectById(dict.getDictId()); + dictDataMapper.lambda() + .set(SysDictData::getDictType, dict.getDictType()) + .eq(SysDictData::getDictType, oldDict.getDictType()) + .update(); + int row = dictTypeMapper.updateById(dict); + if (row > 0) { + CacheUtils.evict(CacheNames.SYS_DICT, oldDict.getDictType()); + CacheUtils.evict(CacheNames.SYS_DICT_TYPE, oldDict.getDictType()); + return dictDataMapper.selectDictDataByType(dict.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + @Override + public boolean checkDictTypeUnique(SysDictTypeBo dictType) { + boolean exist = dictTypeMapper.lambda() + .eq(SysDictType::getDictType, dictType.getDictType()) + .neIfPresent(SysDictType::getDictId, dictType.getDictId()) + .exists(); + return !exist; + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 转换后的字典标签,支持按分隔符批量转换 + */ + @Override + public String getDictLabel(String dictType, String dictValue, String separator) { + List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(datas)) { + return StringUtils.EMPTY; + } + Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); + if (StringUtils.containsAny(dictValue, separator)) { + return Arrays.stream(dictValue.split(separator)) + .map(v -> map.getOrDefault(v, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictValue, StringUtils.EMPTY); + } + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 转换后的字典值,支持按分隔符批量转换 + */ + @Override + public String getDictValue(String dictType, String dictLabel, String separator) { + List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(datas)) { + return StringUtils.EMPTY; + } + Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue); + if (StringUtils.containsAny(dictLabel, separator)) { + return Arrays.stream(dictLabel.split(separator)) + .map(l -> map.getOrDefault(l, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictLabel, StringUtils.EMPTY); + } + } + + /** + * 获取字典下所有的字典值与标签 + * + * @param dictType 字典类型 + * @return dictValue为key,dictLabel为值组成的Map + */ + @Override + public Map getAllDictByDictType(String dictType) { + List list = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(list)) { + return new HashMap<>(); + } + // 保证顺序 + LinkedHashMap map = new LinkedHashMap<>(); + for (SysDictDataVo vo : list) { + map.put(vo.getDictValue(), vo.getDictLabel()); + } + return map; + } + + /** + * 根据字典类型查询详细信息 + * + * @param dictType 字典类型 + * @return 字典类型详细信息 + */ + @Override + public DictTypeDTO getDictType(String dictType) { + SysDictTypeVo vo = SpringUtils.getAopProxy(this).selectDictTypeByType(dictType); + if (ObjectUtil.isNull(vo)) { + return null; + } + return BeanUtil.toBean(vo, DictTypeDTO.class); + } + + /** + * 根据字典类型查询字典数据列表 + * + * @param dictType 字典类型 + * @return 字典数据列表 + */ + @Override + public List getDictData(String dictType) { + List list = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(list)) { + return new ArrayList<>(); + } + return BeanUtil.copyToList(list, DictDataDTO.class); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLoginInfoServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLoginInfoServiceImpl.java new file mode 100644 index 000000000..30da11c97 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLoginInfoServiceImpl.java @@ -0,0 +1,185 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.LoginInfoEvent; +import org.dromara.common.mybatis.core.mapper.LambdaCrudChainWrapper; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.SysLoginInfo; +import org.dromara.system.domain.bo.SysLoginInfoBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysLoginInfoVo; +import org.dromara.system.mapper.SysLoginInfoMapper; +import org.dromara.system.service.ISysClientService; +import org.dromara.system.service.ISysLoginInfoService; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * 系统访问日志情况信息 服务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Slf4j +@Service +public class SysLoginInfoServiceImpl implements ISysLoginInfoService { + + private final SysLoginInfoMapper loginInfoMapper; + + private final ISysClientService clientService; + + /** + * 记录登录信息 + * + * @param loginInfoEvent 登录事件 + */ + @Async + @EventListener + public void recordLoginInfo(LoginInfoEvent loginInfoEvent) { + UserAgent userAgent = UserAgentUtil.parse(loginInfoEvent.getUserAgent()); + String ip = loginInfoEvent.getIp(); + // 客户端信息 + String clientId = loginInfoEvent.getClientId(); + SysClientVo client = null; + if (StringUtils.isNotBlank(clientId)) { + client = clientService.queryByClientId(clientId); + } + + String address = AddressUtils.getRealAddressByIP(ip); + String s = getBlock(ip) + + address + + getBlock(loginInfoEvent.getUsername()) + + getBlock(loginInfoEvent.getStatus()) + + getBlock(loginInfoEvent.getMessage()); + // 打印信息到日志 + log.info(s, loginInfoEvent.getArgs()); + // 获取客户端操作系统 + String os = userAgent.getOs().getName(); + // 获取客户端浏览器 + String browser = userAgent.getBrowser().getName(); + // 封装对象 + SysLoginInfoBo loginInfo = new SysLoginInfoBo(); + loginInfo.setUserName(loginInfoEvent.getUsername()); + if (ObjectUtil.isNotNull(client)) { + loginInfo.setClientKey(client.getClientKey()); + loginInfo.setDeviceType(client.getDeviceType()); + } + loginInfo.setIpaddr(ip); + loginInfo.setLoginLocation(address); + loginInfo.setBrowser(browser); + loginInfo.setOs(os); + loginInfo.setMsg(loginInfoEvent.getMessage()); + // 日志状态 + if (StringUtils.equalsAny(loginInfoEvent.getStatus(), Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) { + loginInfo.setStatus(Constants.SUCCESS); + } else if (Constants.LOGIN_FAIL.equals(loginInfoEvent.getStatus())) { + loginInfo.setStatus(Constants.FAIL); + } + // 插入数据 + insertLoginInfo(loginInfo); + } + + /** + * 将日志片段包装为统一的方括号格式。 + * + * @param msg 日志片段内容 + * @return 包装后的日志片段字符串 + */ + private String getBlock(Object msg) { + if (msg == null) { + msg = ""; + } + return "[" + msg + "]"; + } + + /** + * 分页查询登录日志列表 + * + * @param loginInfo 查询条件 + * @param pageQuery 分页参数 + * @return 登录日志分页列表 + */ + @Override + public PageResult selectPageLoginInfoList(SysLoginInfoBo loginInfo, PageQuery pageQuery) { + LambdaCrudChainWrapper lqw = buildQueryWrapper(loginInfo); + if (StringUtils.isBlank(pageQuery.getOrderByColumn())) { + lqw.orderByDesc(SysLoginInfo::getInfoId); + } + Page page = loginInfoMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 新增系统登录日志 + * + * @param bo 访问日志对象 + */ + @Override + public void insertLoginInfo(SysLoginInfoBo bo) { + SysLoginInfo loginInfo = MapstructUtils.convert(bo, SysLoginInfo.class); + loginInfo.setLoginTime(LocalDateTime.now()); + loginInfoMapper.insert(loginInfo); + } + + /** + * 查询系统登录日志集合 + * + * @param loginInfo 访问日志对象 + * @return 登录记录集合 + */ + @Override + public List selectLoginInfoList(SysLoginInfoBo loginInfo) { + return loginInfoMapper.selectVoList(buildQueryWrapper(loginInfo) + .orderByDesc(SysLoginInfo::getInfoId)); + } + + /** + * 构造登录日志列表查询条件。 + * + * @param loginInfo 登录日志筛选条件 + * @return 登录日志查询包装器 + */ + private LambdaCrudChainWrapper buildQueryWrapper(SysLoginInfoBo loginInfo) { + Map params = loginInfo.getParams(); + return loginInfoMapper.lambda() + .likeIfText(SysLoginInfo::getIpaddr, loginInfo.getIpaddr()) + .eqIfText(SysLoginInfo::getStatus, loginInfo.getStatus()) + .likeIfText(SysLoginInfo::getUserName, loginInfo.getUserName()) + .betweenParams(SysLoginInfo::getLoginTime, params, "beginTime", "endTime"); + } + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + @Override + public int deleteLoginInfoByIds(Long[] infoIds) { + return loginInfoMapper.deleteByIds(Arrays.asList(infoIds)); + } + + /** + * 清空系统登录日志 + */ + @Override + public void cleanLoginInfo() { + loginInfoMapper.lambda().delete(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 000000000..a1d4d7c22 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,393 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.TreeBuildUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysRoleMenu; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.MetaVo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; +import org.dromara.system.mapper.SysMenuMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysRoleMenuMapper; +import org.dromara.system.service.ISysMenuService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 菜单 业务层处理 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysMenuServiceImpl implements ISysMenuService { + + private final SysMenuMapper menuMapper; + private final SysRoleMapper roleMapper; + private final SysRoleMenuMapper roleMenuMapper; + + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + @Override + public List selectMenuList(Long userId) { + return selectMenuList(new SysMenuBo(), userId); + } + + /** + * 查询系统菜单列表 + * + * @param menu 菜单筛选条件 + * @param userId 当前查询的用户主键 + * @return 菜单列表 + */ + @Override + public List selectMenuList(SysMenuBo menu, Long userId) { + // 管理员显示所有菜单信息 不是管理员 按用户id过滤菜单 + if (LoginHelper.isSuperAdmin(userId)) { + return menuMapper.lambda() + .likeIfText(SysMenu::getMenuName, menu.getMenuName()) + .eqIfText(SysMenu::getVisible, menu.getVisible()) + .eqIfText(SysMenu::getStatus, menu.getStatus()) + .eqIfText(SysMenu::getMenuType, menu.getMenuType()) + .eqIfPresent(SysMenu::getParentId, menu.getParentId()) + .orderByAsc(SysMenu::getParentId) + .orderByAsc(SysMenu::getOrderNum) + .voList(); + } + return menuMapper.selectMenuListByUserId(menu, userId); + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByUserId(Long userId) { + return menuMapper.selectMenuPermsByUserId(userId); + } + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByRoleId(Long roleId) { + return menuMapper.selectMenuPermsByRoleId(roleId); + } + + /** + * 根据角色ID列表批量查询权限 + * + * @param roleIds 角色ID列表 + * @return 角色权限映射 + */ + @Override + public Map> selectMenuPermsByRoleIds(Collection roleIds) { + return menuMapper.selectMenuPermsByRoleIds(roleIds); + } + + /** + * 根据用户ID查询菜单树信息 + * + * @param userId 用户ID + * @return 按树结构组织的菜单列表 + */ + @Override + public List selectMenuTreeByUserId(Long userId) { + List menus; + if (LoginHelper.isSuperAdmin(userId)) { + menus = menuMapper.selectMenuTreeAll(); + } else { + menus = menuMapper.selectMenuTreeByUserId(userId); + } + if (CollUtil.isEmpty(menus)) { + return CollUtil.newArrayList(); + } + + List menuTree = TreeBuildUtils.build(menus, Constants.TOP_PARENT_ID, SysMenu::getParentId, (menu, nodeTreeMaps) -> { + // 将当前节点的菜单ID用作父节点ID + Long menuParentId = menu.getMenuId(); + // 从动态规划表中取出子节点列表 + // 如果不存在子节点,则返回一个空的列表,确保数据在进行JSON序列化时该字段的类型和结构是正确的 + List childMenus = nodeTreeMaps.getOrDefault(menuParentId, Collections.emptyList()); + // 设置子节点 + // 如果存在根节点指向尾节点的情况,则会出现环形依赖。但在菜单表中基本不会出现这种情况... + menu.setChildren(childMenus); + }); + return CollUtil.isEmpty(menuTree) ? CollUtil.newArrayList() : menuTree; + } + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + @Override + public List selectMenuListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + return menuMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly()); + } + + /** + * 构建前端路由所需要的菜单 + * 路由name命名规则 path首字母转大写 + id + * + * @param menus 菜单列表 + * @return 路由列表 + */ + @Override + public List buildMenus(List menus) { + if (CollUtil.isEmpty(menus)) { + return CollUtil.newArrayList(); + } + List routers = new LinkedList<>(); + for (SysMenu menu : menus) { + String name = menu.getRouteName() + menu.getMenuId(); + RouterVo router = new RouterVo(); + router.setHidden("1".equals(menu.getVisible())); + router.setName(name); + router.setPath(menu.getRouterPath()); + router.setComponent(menu.getComponentInfo()); + router.setQuery(menu.getQueryParam()); + router.setExt(menu.getExt()); + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals(SystemConstants.NO, menu.getIsCache()), menu.getPath(), menu.getActiveMenu())); + List cMenus = menu.getChildren(); + if (CollUtil.isNotEmpty(cMenus) && SystemConstants.TYPE_DIR.equals(menu.getMenuType())) { + router.setAlwaysShow(true); + router.setRedirect("noRedirect"); + router.setChildren(buildMenus(cMenus)); + } else if (menu.isMenuFrame()) { + String frameName = StringUtils.capitalize(menu.getPath()) + menu.getMenuId(); + router.setMeta(null); + List childrenList = new ArrayList<>(); + RouterVo children = new RouterVo(); + children.setPath(menu.getPath()); + children.setComponent(menu.getComponent()); + children.setName(frameName); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals(SystemConstants.NO, menu.getIsCache()), menu.getPath(), menu.getActiveMenu())); + children.setQuery(menu.getQueryParam()); + children.setExt(menu.getExt()); + childrenList.add(children); + router.setChildren(childrenList); + } else if (menu.getParentId().equals(Constants.TOP_PARENT_ID) && menu.isInnerLink()) { + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); + router.setPath("/"); + List childrenList = new ArrayList<>(); + RouterVo children = new RouterVo(); + String routerPath = SysMenu.innerLinkReplaceEach(menu.getPath()); + String innerLinkName = StringUtils.capitalize(routerPath) + menu.getMenuId(); + children.setPath(routerPath); + children.setComponent(SystemConstants.INNER_LINK); + children.setName(innerLinkName); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath())); + children.setExt(menu.getExt()); + childrenList.add(children); + router.setChildren(childrenList); + } + routers.add(router); + } + return routers; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildMenuTreeSelect(List menus) { + if (CollUtil.isEmpty(menus)) { + return CollUtil.newArrayList(); + } + return TreeBuildUtils.build(menus, (menu, tree) -> { + Tree menuTree = tree.setId(menu.getMenuId()) + .setParentId(menu.getParentId()) + .setName(menu.getMenuName()) + .setWeight(menu.getOrderNum()); + menuTree.put("menuType", menu.getMenuType()); + menuTree.put("icon", menu.getIcon()); + menuTree.put("visible", menu.getVisible()); + menuTree.put("status", menu.getStatus()); + }); + } + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + @Override + public SysMenuVo selectMenuById(Long menuId) { + return menuMapper.selectVoById(menuId); + } + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean hasChildByMenuId(Long menuId) { + return menuMapper.lambda().eq(SysMenu::getParentId, menuId).exists(); + } + + /** + * 是否存在菜单子节点 + * + * @param menuIds 菜单ID列表 + * @return 结果 + */ + @Override + public boolean hasChildByMenuId(Collection menuIds) { + return menuMapper.lambda() + .in(SysMenu::getParentId, menuIds) + .notIn(SysMenu::getMenuId, menuIds) + .exists(); + } + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean checkMenuExistRole(Long menuId) { + return roleMenuMapper.lambda().eq(SysRoleMenu::getMenuId, menuId).exists(); + } + + /** + * 新增保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + @Override + public int insertMenu(SysMenuBo bo) { + SysMenu menu = MapstructUtils.convert(bo, SysMenu.class); + return menuMapper.insert(menu); + } + + /** + * 修改保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + @Override + public int updateMenu(SysMenuBo bo) { + SysMenu menu = MapstructUtils.convert(bo, SysMenu.class); + return menuMapper.updateById(menu); + } + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int deleteMenuById(Long menuId) { + return menuMapper.deleteById(menuId); + } + + /** + * 批量删除菜单管理信息 + * + * @param menuIds 菜单ID串 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteMenuById(Collection menuIds) { + menuMapper.deleteByIds(menuIds); + roleMenuMapper.deleteByMenuIds(menuIds); + } + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public boolean checkMenuNameUnique(SysMenuBo menu) { + boolean exist = menuMapper.lambda() + .eq(SysMenu::getMenuName, menu.getMenuName()) + .eq(SysMenu::getParentId, menu.getParentId()) + .neIfPresent(SysMenu::getMenuId, menu.getMenuId()) + .exists(); + return !exist; + } + + /** + * 校验路由组合是否唯一 + * + * @param menuBo 菜单信息 + * @return 结果 + */ + @Override + public boolean checkRouteConfigUnique(SysMenuBo menuBo) { + SysMenu menu = MapstructUtils.convert(menuBo, SysMenu.class); + if (SystemConstants.TYPE_BUTTON.equals(menu.getMenuType())) { + return true; + } + long menuId = ObjectUtil.isNull(menu.getMenuId()) ? -1L : menu.getMenuId(); + Long parentId = menu.getParentId(); + String path = menu.getPath(); + String routeName = StringUtils.isEmpty(menu.getRouteName()) ? path : menu.getRouteName(); + List sysMenuList = menuMapper.lambda() + .in(SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU) + .and(w -> + w.eq(SysMenu::getPath, path).or().eq(SysMenu::getPath, routeName) + ).list(); + for (SysMenu sysMenu : sysMenuList) { + if (!sysMenu.getMenuId().equals(menuId)) { + Long dbParentId = sysMenu.getParentId(); + String dbPath = sysMenu.getPath(); + String dbRouteName = StringUtils.isEmpty(sysMenu.getRouteName()) ? dbPath : sysMenu.getRouteName(); + if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.equals(dbParentId)) { + log.warn("[同级路由冲突] 同级下已存在相同路由路径 '{}',冲突菜单:{}", dbPath, sysMenu.getMenuName()); + return false; + } else if (StringUtils.equalsAnyIgnoreCase(path, dbPath) + && Constants.TOP_PARENT_ID.equals(parentId) + && Constants.TOP_PARENT_ID.equals(dbParentId)) { + log.warn("[根目录路由冲突] 根目录下路由 '{}' 必须唯一,已被菜单 '{}' 占用", path, sysMenu.getMenuName()); + return false; + } else if (StringUtils.equalsAnyIgnoreCase(routeName, dbRouteName) + && sysMenu.getMenuType().equals(menu.getMenuType())) { + log.warn("[路由名称冲突] 路由名称 '{}' 需全局唯一,已被菜单 '{}' 使用", routeName, sysMenu.getMenuName()); + return false; + } + } + } + return true; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java new file mode 100644 index 000000000..f4e3567bd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java @@ -0,0 +1,345 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.enums.PushSourceEnum; +import org.dromara.common.core.enums.PushTypeEnum; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.utils.IdGeneratorUtil; +import org.dromara.common.push.helper.PushHelper; +import org.dromara.system.api.MessageService; +import org.dromara.system.api.domain.PushPayloadDTO; +import org.dromara.system.domain.SysMessage; +import org.dromara.system.domain.vo.SysMessageBoxVo; +import org.dromara.system.domain.vo.SysMessageVo; +import org.dromara.system.mapper.SysMessageMapper; +import org.dromara.system.service.ISysMessageService; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * 消息记录服务实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysMessageServiceImpl implements ISysMessageService, MessageService { + + /** + * 全局广播用户标识(所有用户可见) + */ + private static final String GLOBAL_USER_IDS = "0"; + + /** + * 消息分类:系统消息 + */ + private static final String CATEGORY_SYSTEM = "system"; + + /** + * 消息分类:通知公告 + */ + private static final String CATEGORY_NOTICE = "notice"; + + /** + * 消息分类:工作流 + */ + private static final String CATEGORY_WORKFLOW = "workflow"; + + /** + * 消息盒子每页展示最大条数 + */ + private static final int BOX_LIMIT = 100; + + /** + * 消息盒子展示消息天数(仅展示30天内) + */ + private static final long BOX_DAYS = 30L; + + private final SysMessageMapper messageMapper; + + /** + * 查询当前用户消息盒子数据 + * 按系统消息、通知公告、工作流消息分类返回 + * + * @param userId 用户ID + * @return 分类消息盒子数据 + */ + @Override + public SysMessageBoxVo queryMessageBox(Long userId) { + SysMessageBoxVo box = new SysMessageBoxVo(); + box.setSystemList(selectMessageList(CATEGORY_SYSTEM, userId)); + box.setNoticeList(selectMessageList(CATEGORY_NOTICE, userId)); + box.setWorkflowList(selectMessageList(CATEGORY_WORKFLOW, userId)); + return box; + } + + /** + * 发送指定用户文本消息 + * + * @param userId 目标用户ID + * @param message 文本消息内容 + */ + @Override + public void sendMessage(Long userId, String message) { + PushHelper.sendMessage(userId, buildDefaultMessage(message)); + } + + /** + * 全局广播文本消息 + * + * @param message 文本消息内容 + */ + @Override + public void sendMessage(String message) { + PushHelper.sendMessage(buildDefaultMessage(message)); + } + + /** + * 发送指定用户自定义消息体 + * + * @param userId 目标用户ID + * @param payload 消息推送体 + */ + @Override + public void sendMessage(Long userId, PushPayloadDTO payload) { + PushHelper.sendMessage(userId, payload); + } + + /** + * 全局广播自定义消息体 + * + * @param payload 消息推送体 + */ + @Override + public void sendMessage(PushPayloadDTO payload) { + PushHelper.sendMessage(payload); + } + + /** + * 批量发布消息给指定用户列表 + * + * @param userIds 用户ID集合 + * @param payload 消息推送体 + */ + @Override + public void publishMessage(List userIds, PushPayloadDTO payload) { + PushHelper.publishMessage(userIds, storeUsers(userIds, payload)); + } + + /** + * 发布全局广播文本消息 + * + * @param message 文本消息内容 + */ + @Override + public void publishAll(String message) { + publishAll(buildDefaultMessage(message)); + } + + /** + * 发布全局广播自定义消息体 + * + * @param payload 消息推送体 + */ + @Override + public void publishAll(PushPayloadDTO payload) { + PushHelper.publishAll(storeAll(payload)); + } + + /** + * 存储全局广播消息到数据库 + * + * @param payload 消息推送体 + * @return 回填消息ID后的消息体 + */ + @Override + public PushPayloadDTO storeAll(PushPayloadDTO payload) { + return storeMessage(null, payload); + } + + /** + * 存储指定用户消息到数据库 + * + * @param userIds 用户ID集合 + * @param payload 消息推送体 + * @return 回填消息ID后的消息体 + */ + @Override + public PushPayloadDTO storeUsers(List userIds, PushPayloadDTO payload) { + return storeMessage(userIds, payload); + } + + /** + * 统一消息存储逻辑 + * 判断是否需要存入消息盒子,需要则插入数据库 + * + * @param userIds 用户ID集合(为null则全局广播) + * @param payload 消息推送体 + * @return 回填消息ID后的消息体 + */ + private PushPayloadDTO storeMessage(List userIds, PushPayloadDTO payload) { + if (!supportsMessageBox(payload)) { + return payload; + } + SysMessage message = buildMessage(userIds, payload); + messageMapper.insert(message); + payload.setMessageId(message.getMessageId()); + return payload; + } + + /** + * 根据分类和用户ID查询消息列表 + * 仅查询30天内、最多100条、按时间倒序 + * + * @param category 消息分类 + * @param userId 用户ID + * @return 消息VO列表 + */ + private List selectMessageList(String category, Long userId) { + List list = messageMapper.lambda() + .eq(SysMessage::getCategory, category) + // 仅查询30天内消息 + .ge(SysMessage::getCreateTime, LocalDateTime.now().minusDays(BOX_DAYS)) + // 全局消息 或 当前用户在接收人范围内 + .and(wrapper -> + wrapper.eq(SysMessage::getSendUserIds, GLOBAL_USER_IDS) + .or() + .findInSet(userId, SysMessage::getSendUserIds) + ) + .orderByDesc(SysMessage::getCreateTime, SysMessage::getMessageId) + // 分页查询(只查第一页,最多100条) + .list(new Page<>(1, BOX_LIMIT, false)); + return list.stream().map(this::buildVo).toList(); + } + + /** + * 构建消息实体(用于数据库存储) + * + * @param userIds 接收用户ID集合 + * @param payload 消息推送体 + * @return 系统消息实体 + */ + private SysMessage buildMessage(List userIds, PushPayloadDTO payload) { + SysMessage message = new SysMessage(); + // 设置消息ID(无则自动生成) + message.setMessageId(payload.getMessageId() == null ? IdGeneratorUtil.nextLongId() : payload.getMessageId()); + message.setCategory(resolveCategory(payload)); + message.setType(payload.getType()); + message.setSource(payload.getSource()); + message.setTitle(resolveTitle(payload)); + message.setMessage(payload.getMessage()); + message.setContent(resolveContent(payload)); + message.setDataJson(JsonUtils.toJsonString(payload.getData())); + message.setPath(payload.getPath()); + // 设置接收人(无则为全局广播) + message.setSendUserIds(CollUtil.isEmpty(userIds) ? GLOBAL_USER_IDS : StringUtils.joinComma(userIds)); + return message; + } + + /** + * 消息实体转换为展示VO + * + * @param entity 消息实体 + * @return 消息展示VO + */ + private SysMessageVo buildVo(SysMessage entity) { + SysMessageVo vo = MapstructUtils.convert(entity, SysMessageVo.class); + vo.setData(parseData(entity.getDataJson())); + return vo; + } + + /** + * 判断消息是否需要存入消息盒子 + * 仅系统消息、通知消息需要存入 + * + * @param payload 消息推送体 + * @return 是否支持存入消息盒子 + */ + private boolean supportsMessageBox(PushPayloadDTO payload) { + if (payload == null) { + return false; + } + // 仅消息/通知类型需要存入,排除LLM大模型消息 + if (StringUtils.equalsAny(payload.getType(), PushTypeEnum.MESSAGE.getType(), PushTypeEnum.NOTICE.getType())) { + return !StringUtils.equalsAny(payload.getType(), PushTypeEnum.LLM.getType()) + && !StringUtils.equalsAny(payload.getSource(), PushSourceEnum.LLM.getSource()); + } + return false; + } + + /** + * 根据消息类型/来源自动解析消息分类 + * + * @param payload 消息推送体 + * @return 消息分类(system/notice/workflow) + */ + private String resolveCategory(PushPayloadDTO payload) { + if (StringUtils.equalsAny(payload.getType(), PushTypeEnum.NOTICE.getType()) + || StringUtils.equalsAny(payload.getSource(), PushSourceEnum.NOTICE.getSource())) { + return CATEGORY_NOTICE; + } + if (StringUtils.equalsAny(payload.getSource(), PushSourceEnum.WORKFLOW.getSource())) { + return CATEGORY_WORKFLOW; + } + return CATEGORY_SYSTEM; + } + + /** + * 根据消息分类自动生成消息标题 + * + * @param payload 消息推送体 + * @return 消息标题 + */ + private String resolveTitle(PushPayloadDTO payload) { + return switch (resolveCategory(payload)) { + case CATEGORY_NOTICE -> "通知公告消息"; + case CATEGORY_WORKFLOW -> "工作流消息"; + default -> "系统消息"; + }; + } + + /** + * 解析消息内容(从data中提取noticeContent) + * + * @param payload 消息推送体 + * @return 消息内容 + */ + private String resolveContent(PushPayloadDTO payload) { + Object data = payload.getData(); + if (data instanceof Map map) { + return Convert.toStr(map.get("noticeContent")); + } + return null; + } + + /** + * 解析JSON数据字符串为对象 + * + * @param dataJson JSON字符串 + * @return 解析后对象 + */ + private Object parseData(String dataJson) { + if (StringUtils.isBlank(dataJson)) { + return null; + } + return JsonUtils.parseObject(dataJson, Object.class); + } + + /** + * 构建默认格式的消息体 + * + * @param message 消息内容 + * @return 默认消息体 + */ + private PushPayloadDTO buildDefaultMessage(String message) { + return PushPayloadDTO.of(PushTypeEnum.MESSAGE, PushSourceEnum.BACKEND, message, null); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java new file mode 100644 index 000000000..f48eb566b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java @@ -0,0 +1,139 @@ +package org.dromara.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.LambdaQueryBuilder; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.system.domain.SysNotice; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysNoticeMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysNoticeService; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +/** + * 公告 服务层实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysNoticeServiceImpl implements ISysNoticeService { + + private final SysNoticeMapper noticeMapper; + private final SysUserMapper userMapper; + + /** + * 分页查询通知公告列表 + * + * @param notice 查询条件 + * @param pageQuery 分页参数 + * @return 通知公告分页列表 + */ + @Override + public PageResult selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(notice); + Page page = noticeMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + @Override + public SysNoticeVo selectNoticeById(Long noticeId) { + return noticeMapper.selectVoById(noticeId); + } + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + @Override + public List selectNoticeList(SysNoticeBo notice) { + LambdaQueryWrapper lqw = buildQueryWrapper(notice); + return noticeMapper.selectVoList(lqw); + } + + /** + * 构造公告列表查询条件。 + * + * @param bo 公告筛选条件 + * @return 包含标题、类型、创建人和排序条件的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysNoticeBo bo) { + LambdaQueryBuilder builder = QueryBuilder.lambda(SysNotice.class) + .likeIfText(SysNotice::getNoticeTitle, bo.getNoticeTitle()) + .eqIfText(SysNotice::getNoticeType, bo.getNoticeType()); + if (StringUtils.isNotBlank(bo.getCreateByName())) { + SysUserVo sysUser = userMapper.lambda().eq(SysUser::getUserName, bo.getCreateByName()).voOne(); + builder.eq(SysNotice::getCreateBy, ObjectUtils.notNullGetter(sysUser, SysUserVo::getUserId)); + } + return builder.orderByAsc(SysNotice::getNoticeId).build(); + } + + /** + * 新增公告 + * + * @param bo 公告信息 + * @return 结果 + */ + @Override + public int insertNotice(SysNoticeBo bo) { + SysNotice notice = MapstructUtils.convert(bo, SysNotice.class); + int rows = noticeMapper.insert(notice); + bo.setNoticeId(notice.getNoticeId()); + return rows; + } + + /** + * 修改公告 + * + * @param bo 公告信息 + * @return 结果 + */ + @Override + public int updateNotice(SysNoticeBo bo) { + SysNotice notice = MapstructUtils.convert(bo, SysNotice.class); + return noticeMapper.updateById(notice); + } + + /** + * 删除公告对象 + * + * @param noticeId 公告ID + * @return 结果 + */ + @Override + public int deleteNoticeById(Long noticeId) { + return noticeMapper.deleteById(noticeId); + } + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + @Override + public int deleteNoticeByIds(Long[] noticeIds) { + return noticeMapper.deleteByIds(Arrays.asList(noticeIds)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java new file mode 100644 index 000000000..153c5d997 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java @@ -0,0 +1,153 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ArrayUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.system.domain.SysOperLog; +import org.dromara.system.domain.bo.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; +import org.dromara.system.mapper.SysOperLogMapper; +import org.dromara.system.service.ISysOperLogService; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * 操作日志 服务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysOperLogServiceImpl implements ISysOperLogService { + + private final SysOperLogMapper operLogMapper; + + /** + * 操作日志记录 + * + * @param operLogEvent 操作日志事件 + */ + @Async + @EventListener + public void recordOper(OperLogEvent operLogEvent) { + SysOperLogBo operLog = MapstructUtils.convert(operLogEvent, SysOperLogBo.class); + // 远程查询操作地点 + operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); + insertOperlog(operLog); + } + + /** + * 分页查询操作日志列表 + * + * @param operLog 查询条件 + * @param pageQuery 分页参数 + * @return 操作日志分页列表 + */ + @Override + public PageResult selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(operLog); + if (StringUtils.isBlank(pageQuery.getOrderByColumn())) { + lqw.orderByDesc(SysOperLog::getOperId); + } + Page page = operLogMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 构造操作日志查询条件。 + * + * @param operLog 操作日志筛选条件 + * @return 包含业务类型、状态、操作人和时间区间的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysOperLogBo operLog) { + Map params = operLog.getParams(); + return QueryBuilder.lambda(SysOperLog.class) + .likeIfText(SysOperLog::getOperIp, operLog.getOperIp()) + .likeIfText(SysOperLog::getTitle, operLog.getTitle()) + .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0, + SysOperLog::getBusinessType, operLog.getBusinessType()) + .func(f -> { + if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) { + f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes())); + } + }) + .eqIfPresent(SysOperLog::getStatus, operLog.getStatus()) + .likeIfText(SysOperLog::getOperName, operLog.getOperName()) + .eqIfPresent(SysOperLog::getUserId, operLog.getUserId()) + .eqIfPresent(SysOperLog::getDeptId, operLog.getDeptId()) + .eqIfText(SysOperLog::getClientKey, operLog.getClientKey()) + .eqIfText(SysOperLog::getDeviceType, operLog.getDeviceType()) + .likeIfText(SysOperLog::getBrowser, operLog.getBrowser()) + .likeIfText(SysOperLog::getOs, operLog.getOs()) + .betweenParams(SysOperLog::getOperTime, params, "beginTime", "endTime") + .build(); + } + + /** + * 新增操作日志 + * + * @param bo 操作日志对象 + */ + @Override + public void insertOperlog(SysOperLogBo bo) { + SysOperLog operLog = MapstructUtils.convert(bo, SysOperLog.class); + operLog.setOperTime(LocalDateTime.now()); + operLogMapper.insert(operLog); + } + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + @Override + public List selectOperLogList(SysOperLogBo operLog) { + LambdaQueryWrapper lqw = buildQueryWrapper(operLog); + return operLogMapper.selectVoList(lqw.orderByDesc(SysOperLog::getOperId)); + } + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + @Override + public int deleteOperLogByIds(Long[] operIds) { + return operLogMapper.deleteByIds(Arrays.asList(operIds)); + } + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + @Override + public SysOperLogVo selectOperLogById(Long operId) { + return operLogMapper.selectVoById(operId); + } + + /** + * 清空操作日志 + */ + @Override + public void cleanOperLog() { + operLogMapper.lambda().delete(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java new file mode 100644 index 000000000..f5e74e3b8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java @@ -0,0 +1,239 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.oss.constant.OssConstant; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.system.domain.SysOssConfig; +import org.dromara.system.domain.bo.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; +import org.dromara.system.event.OssConfigChangeEvent; +import org.dromara.system.mapper.SysOssConfigMapper; +import org.dromara.system.service.ISysOssConfigService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 对象存储配置Service业务层处理 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysOssConfigServiceImpl implements ISysOssConfigService { + + private final SysOssConfigMapper ossConfigMapper; + + /** + * 项目启动时,初始化参数到缓存,加载配置类 + */ + @Override + public void init() { + List list = ossConfigMapper.selectList(); + // 加载OSS初始化配置 + for (SysOssConfig config : list) { + String configKey = config.getConfigKey(); + if (SystemConstants.YES.equals(config.getStatus())) { + RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey); + } + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); + } + } + + /** + * 查询对象存储配置详情。 + * + * @param ossConfigId 配置主键 + * @return 对象存储配置详情 + */ + @Override + public SysOssConfigVo queryById(Long ossConfigId) { + return ossConfigMapper.selectVoById(ossConfigId); + } + + /** + * 分页查询对象存储配置列表。 + * + * @param bo 配置筛选条件 + * @param pageQuery 分页参数 + * @return 配置分页结果 + */ + @Override + public PageResult queryPageList(SysOssConfigBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = ossConfigMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(result.getRecords(), result.getTotal()); + } + + + /** + * 构造对象存储配置列表查询条件。 + * + * @param bo 配置筛选条件 + * @return 包含配置标识、桶名称和状态条件的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysOssConfigBo bo) { + return QueryBuilder.lambda(SysOssConfig.class) + .eqIfText(SysOssConfig::getConfigKey, bo.getConfigKey()) + .likeIfText(SysOssConfig::getBucketName, bo.getBucketName()) + .eqIfText(SysOssConfig::getStatus, bo.getStatus()) + .orderByAsc(SysOssConfig::getOssConfigId) + .build(); + } + + /** + * 新增对象存储配置并刷新缓存。 + * + * @param bo 配置业务对象 + * @return 新增成功返回 {@code true} + */ + @Override + public Boolean insertByBo(SysOssConfigBo bo) { + SysOssConfig config = MapstructUtils.convert(bo, SysOssConfig.class); + validEntityBeforeSave(config); + boolean flag = ossConfigMapper.insert(config) > 0; + if (flag) { + // 从数据库查询完整的数据做缓存 + config = ossConfigMapper.selectById(config.getOssConfigId()); + publishOssConfigSaved(config, null); + } + return flag; + } + + /** + * 更新对象存储配置并刷新缓存。 + * + * @param bo 配置业务对象 + * @return 更新成功返回 {@code true} + */ + @Override + public Boolean updateByBo(SysOssConfigBo bo) { + SysOssConfig config = MapstructUtils.convert(bo, SysOssConfig.class); + validEntityBeforeSave(config); + SysOssConfig oldConfig = ossConfigMapper.selectById(config.getOssConfigId()); + boolean flag = ossConfigMapper.lambda() + .set(ObjectUtil.isNull(config.getPrefix()), SysOssConfig::getPrefix, "") + .set(ObjectUtil.isNull(config.getRegion()), SysOssConfig::getRegion, "") + .set(ObjectUtil.isNull(config.getExt1()), SysOssConfig::getExt1, "") + .set(ObjectUtil.isNull(config.getRemark()), SysOssConfig::getRemark, "") + .eq(SysOssConfig::getOssConfigId, config.getOssConfigId()) + .update(config); + if (flag) { + // 从数据库查询完整的数据做缓存 + config = ossConfigMapper.selectById(config.getOssConfigId()); + publishOssConfigSaved(config, ObjectUtils.notNullGetter(oldConfig, SysOssConfig::getConfigKey)); + } + return flag; + } + + /** + * 保存前的数据校验 + * + * @param entity 待保存的对象存储配置实体 + */ + private void validEntityBeforeSave(SysOssConfig entity) { + if (StringUtils.isNotEmpty(entity.getConfigKey()) + && !checkConfigKeyUnique(entity)) { + throw new ServiceException("操作配置'{}'失败, 配置key已存在!", entity.getConfigKey()); + } + } + + /** + * 删除对象存储配置并同步清理缓存。 + * + * @param ids 主键集合 + * @param isValid 是否执行业务校验 + * @return 删除成功返回 {@code true} + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + if (CollUtil.containsAny(ids, OssConstant.SYSTEM_DATA_IDS)) { + throw new ServiceException("系统内置, 不可删除!"); + } + } + List list = CollUtil.newArrayList(); + for (Long configId : ids) { + SysOssConfig config = ossConfigMapper.selectById(configId); + if (ObjectUtil.isNotNull(config)) { + list.add(config); + } + } + boolean flag = ossConfigMapper.deleteByIds(ids) > 0; + if (flag) { + list.forEach(sysOssConfig -> + SpringUtils.context().publishEvent(OssConfigChangeEvent.remove(sysOssConfig.getConfigKey()))); + } + return flag; + } + + /** + * 判断configKey是否唯一 + * + * @param sysOssConfig 对象存储配置实体 + * @return 唯一返回 {@code true} + */ + private boolean checkConfigKeyUnique(SysOssConfig sysOssConfig) { + long ossConfigId = ObjectUtils.notNull(sysOssConfig.getOssConfigId(), -1L); + SysOssConfig info = ossConfigMapper.lambda() + .select(SysOssConfig::getOssConfigId, SysOssConfig::getConfigKey) + .eq(SysOssConfig::getConfigKey, sysOssConfig.getConfigKey()) + .one(); + return ObjectUtil.isNull(info) || ObjectUtil.equals(info.getOssConfigId(), ossConfigId); + } + + /** + * 启用禁用状态 + * + * @param bo 配置业务对象 + * @return 更新条数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateOssConfigStatus(SysOssConfigBo bo) { + SysOssConfig sysOssConfig = MapstructUtils.convert(bo, SysOssConfig.class); + int row = ossConfigMapper.lambda().set(SysOssConfig::getStatus, SystemConstants.NO).updateCount(); + row += ossConfigMapper.updateById(sysOssConfig); + if (row > 0) { + SpringUtils.context().publishEvent(OssConfigChangeEvent.useDefault(sysOssConfig.getConfigKey())); + } + return row; + } + + /** + * 发布 OSS 配置保存事件。 + * + * @param config 当前配置 + * @param oldConfigKey 变更前配置 key + */ + private void publishOssConfigSaved(SysOssConfig config, String oldConfigKey) { + SpringUtils.context().publishEvent(OssConfigChangeEvent.save( + config.getConfigKey(), + oldConfigKey, + JsonUtils.toJsonString(config) + )); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java new file mode 100644 index 000000000..b4a7fb469 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java @@ -0,0 +1,332 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.oss.client.OssClient; +import org.dromara.common.oss.enums.AccessPolicy; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.oss.model.Options; +import org.dromara.common.oss.model.PutObjectResult; +import org.dromara.system.api.OssService; +import org.dromara.system.api.domain.OssDTO; +import org.dromara.system.domain.SysOss; +import org.dromara.system.domain.SysOssExt; +import org.dromara.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.mapper.SysOssMapper; +import org.dromara.system.service.ISysOssService; +import org.jetbrains.annotations.NotNull; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.time.Duration; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +/** + * 文件上传 服务层实现 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysOssServiceImpl implements ISysOssService, OssService { + + private final SysOssMapper ossMapper; + + /** + * 查询OSS对象存储列表 + * + * @param bo OSS对象存储分页查询对象 + * @param pageQuery 分页查询实体类 + * @return 结果 + */ + @Override + public PageResult queryPageList(SysOssBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = ossMapper.selectVoPage(pageQuery.build(), lqw); + List filterResult = StreamUtils.toList(result.getRecords(), this::matchingUrl); + result.setRecords(filterResult); + return PageResult.build(result.getRecords(), result.getTotal()); + } + + /** + * 根据一组 ossIds 获取对应的 SysOssVo 列表 + * + * @param ossIds 一组文件在数据库中的唯一标识集合 + * @return 包含 SysOssVo 对象的列表 + */ + @Override + public List listByIds(Collection ossIds) { + SysOssServiceImpl ossService = SpringUtils.getAopProxy(this); + List> suppliers = ossIds.stream().map(id -> (Supplier) () -> { + SysOssVo vo = ossService.getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + return this.matchingUrl(vo); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + return vo; + } + } + return null; + }).toList(); + List list = ThreadUtils.virtualSubmitAll(suppliers); + list.removeAll(Collections.singleton(null)); + return list; + } + + /** + * 根据一组 ossIds 获取对应文件的 URL 列表 + * + * @param ossIds 以逗号分隔的 ossId 字符串 + * @return 以逗号分隔的文件 URL 字符串 + */ + @Override + public String selectUrlByIds(String ossIds) { + List ids = StringUtils.splitTo(ossIds, Convert::toLong); + SysOssServiceImpl ossService = SpringUtils.getAopProxy(this); + List> suppliers = ids.stream().map(id -> (Supplier) () -> { + SysOssVo vo = ossService.getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + return this.matchingUrl(vo).getUrl(); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + return vo.getUrl(); + } + } + return null; + }).toList(); + List list = ThreadUtils.virtualSubmitAll(suppliers); + list.removeAll(Collections.singleton(null)); + return StringUtils.joinComma(list); + } + + /** + * 根据逗号分隔的文件主键列表查询文件传输对象集合。 + * + * @param ossIds 逗号分隔的文件主键字符串 + * @return 文件传输对象列表 + */ + @Override + public List selectByIds(String ossIds) { + List ids = StringUtils.splitTo(ossIds, Convert::toLong); + var ossService = SpringUtils.getAopProxy(this); + List> suppliers = ids.stream().map(id -> (Supplier) () -> { + SysOssVo vo = ossService.getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + vo.setUrl(this.matchingUrl(vo).getUrl()); + return BeanUtil.toBean(vo, OssDTO.class); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + return BeanUtil.toBean(vo, OssDTO.class); + } + } + return null; + }).toList(); + List list = ThreadUtils.virtualSubmitAll(suppliers); + list.removeAll(Collections.singleton(null)); + return list; + } + + /** + * 构造 OSS 文件列表查询条件。 + * + * @param bo 文件筛选条件 + * @return 包含文件名、后缀、归属服务和创建时间区间的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysOssBo bo) { + Map params = bo.getParams(); + return QueryBuilder.lambda(SysOss.class) + .likeIfText(SysOss::getFileName, bo.getFileName()) + .likeIfText(SysOss::getOriginalName, bo.getOriginalName()) + .eqIfText(SysOss::getFileSuffix, bo.getFileSuffix()) + .eqIfText(SysOss::getUrl, bo.getUrl()) + .betweenParams(SysOss::getCreateTime, params, "beginCreateTime", "endCreateTime") + .eqIfPresent(SysOss::getCreateBy, bo.getCreateBy()) + .eqIfText(SysOss::getService, bo.getService()) + .orderByAsc(SysOss::getOssId) + .build(); + } + + /** + * 根据 ossId 从缓存或数据库中获取 SysOssVo 对象 + * + * @param ossId 文件在数据库中的唯一标识 + * @return SysOssVo 对象,包含文件信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId") + @Override + public SysOssVo getById(Long ossId) { + return ossMapper.selectVoById(ossId); + } + + + /** + * 文件下载方法,支持一次性下载完整文件 + * + * @param ossId OSS对象ID + */ + @Override + public ResponseEntity download(Long ossId) { + SysOssVo sysOss = SpringUtils.getAopProxy(this).getById(ossId); + if (ObjectUtil.isNull(sysOss)) { + throw new ServiceException("文件数据不存在!"); + } + String percentEncodedFileName = FileUtils.percentEncode(sysOss.getOriginalName()); + return OssFactory.instance(sysOss.getService()) + .download(sysOss.getFileName(), (result, inputStream) -> { + // 尝试解析媒体类型,如果解析失败,则使用 application/octet-stream + MediaType mediaType; + try { + mediaType = MediaType.parseMediaType(result.contentType()); + } catch (Exception e) { + mediaType = MediaType.APPLICATION_OCTET_STREAM; + } + // 构建响应实体 + return ResponseEntity.ok() + .header(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "Content-Disposition,download-filename") + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=%s;filename*=utf-8''%s".formatted(percentEncodedFileName, percentEncodedFileName)) + .header("download-filename", percentEncodedFileName) + .contentType(mediaType) + .contentLength(result.size()) + .body(IoUtil.readBytes(inputStream)); + }); + + } + + /** + * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + * @throws ServiceException 如果上传过程中发生异常,则抛出 ServiceException 异常 + */ + @Override + public SysOssVo upload(MultipartFile file, SysOssExt ossExt) { + if (ObjectUtil.isNull(file) || file.isEmpty()) { + throw new ServiceException("上传文件不能为空"); + } + String originalfileName = file.getOriginalFilename(); + String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); + OssClient instance = OssFactory.instance(); + String pathKey = instance.buildPathKey(originalfileName); + try (InputStream inputStream = file.getInputStream()) { + PutObjectResult result = instance.upload(pathKey, inputStream, file.getSize(), Options.builder().setContentType(file.getContentType())); + ossExt = ossExt == null ? new SysOssExt() : ossExt; + ossExt.setFileSize(file.getSize()); + ossExt.setContentType(file.getContentType()); + // 保存文件信息 + return buildResultEntity(originalfileName, suffix, instance.clientId(), result, ossExt); + } catch (IOException e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 上传文件到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的文件对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + @Override + public SysOssVo upload(File file, SysOssExt ossExt) { + if (ObjectUtil.isNull(file) || !file.isFile() || file.length() <= 0) { + throw new ServiceException("上传文件不能为空"); + } + String originalfileName = file.getName(); + String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); + OssClient instance = OssFactory.instance(); + String pathKey = instance.buildPathKey(originalfileName); + PutObjectResult result = instance.upload(pathKey, file, Options.builder().setContentType(FileUtils.getMimeType(file.toPath()))); + SysOssExt ext1 = ossExt == null ? new SysOssExt() : ossExt; + ext1.setFileSize(result.size()); + // 保存文件信息 + return buildResultEntity(originalfileName, suffix, instance.clientId(), result, ext1); + } + + /** + * 组装上传结果并持久化文件元数据。 + * + * @param originalfileName 原始文件名 + * @param suffix 文件后缀 + * @param configKey 存储配置标识 + * @param result 上传结果 + * @param ext1 扩展属性对象 + * @return 持久化后的文件信息视图 + */ + @NotNull + private SysOssVo buildResultEntity(String originalfileName, String suffix, String configKey, PutObjectResult result, SysOssExt ext1) { + SysOss oss = new SysOss(); + oss.setUrl(result.url()); + oss.setFileSuffix(suffix); + oss.setFileName(result.key()); + oss.setOriginalName(originalfileName); + oss.setService(configKey); + oss.setExt1(JsonUtils.toJsonString(ext1)); + ossMapper.insert(oss); + SysOssVo sysOssVo = MapstructUtils.convert(oss, SysOssVo.class); + return this.matchingUrl(sysOssVo); + } + + /** + * 删除OSS对象存储 + * + * @param ids OSS对象ID串 + * @param isValid 判断是否需要校验 + * @return 结果 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + } + List list = ossMapper.selectByIds(ids); + for (SysOss sysOss : list) { + OssFactory.instance(sysOss.getService()).delete(sysOss.getFileName()); + } + return ossMapper.deleteByIds(ids) > 0; + } + + /** + * 桶类型为 private 的URL 修改为临时URL时长为120s + * + * @param oss OSS对象 + * @return oss 匹配Url的OSS对象 + */ + private SysOssVo matchingUrl(SysOssVo oss) { + OssClient instance = OssFactory.instance(oss.getService()); + // 仅修改桶类型为 private 的URL,临时URL时长为120s + if (instance.verifyConfig(config -> AccessPolicy.PRIVATE.equals(config.accessControlPolicyConfig().accessPolicy()))) { + oss.setUrl(instance.presignGetUrl(oss.getFileName(), Duration.ofSeconds(120))); + } + return oss; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java new file mode 100644 index 000000000..75cd2bd50 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java @@ -0,0 +1,86 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.service.PermissionService; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.domain.RoleDTO; +import org.dromara.system.service.ISysMenuService; +import org.dromara.system.service.ISysPermissionService; +import org.dromara.system.service.ISysRoleService; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 用户权限处理 + * + * @author ruoyi + */ +@RequiredArgsConstructor +@Service +public class SysPermissionServiceImpl implements ISysPermissionService, PermissionService { + + private final ISysRoleService roleService; + private final ISysMenuService menuService; + + /** + * 获取角色数据权限 + * + * @param userId 用户id + * @return 角色权限信息 + */ + @Override + public Set getRolePermission(Long userId) { + Set roles = new HashSet<>(); + // 管理员拥有所有权限 + if (LoginHelper.isSuperAdmin(userId)) { + roles.add(SystemConstants.SUPER_ADMIN_ROLE_KEY); + } else { + roles.addAll(roleService.selectRolePermissionByUserId(userId)); + } + return roles; + } + + /** + * 获取菜单数据权限 + * + * @param userId 用户id + * @return 菜单权限信息 + */ + @Override + public Set getMenuPermission(Long userId) { + Set perms = new HashSet<>(); + // 管理员拥有所有权限 + if (LoginHelper.isSuperAdmin(userId)) { + perms.add("*:*:*"); + } else { + perms.addAll(menuService.selectMenuPermsByUserId(userId)); + } + return perms; + } + + /** + * 按权限标识汇总具备数据权限的角色集合。 + * + * @param roles 角色传输对象列表 + * @return key 为权限标识、value 为拥有该权限的角色主键列表 + */ + @Override + public Map> getDataScopeRoleMap(List roles) { + if (CollUtil.isEmpty(roles)) { + return Map.of(); + } + List roleIds = StreamUtils.toList(roles, RoleDTO::getRoleId); + Map> permsRoleIds = menuService.selectMenuPermsByRoleIds(roleIds); + Map> rolePermsMap = new LinkedHashMap<>(); + permsRoleIds.forEach((roleId, perms) -> + perms.forEach(perm -> + rolePermsMap.computeIfAbsent(perm, key -> new ArrayList<>()).add(roleId) + ) + ); + return rolePermsMap; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java new file mode 100644 index 000000000..e811a798f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,277 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.api.PostService; +import org.dromara.system.domain.SysPost; +import org.dromara.system.domain.SysUserPost; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysPostMapper; +import org.dromara.system.mapper.SysUserPostMapper; +import org.dromara.system.service.ISysPostService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 岗位信息 服务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysPostServiceImpl implements ISysPostService, PostService { + + private final SysPostMapper postMapper; + private final SysDeptMapper deptMapper; + private final SysUserPostMapper userPostMapper; + + /** + * 分页查询岗位列表 + * + * @param post 查询条件 + * @param pageQuery 分页参数 + * @return 岗位分页列表 + */ + @Override + public PageResult selectPagePostList(SysPostBo post, PageQuery pageQuery) { + Page page = postMapper.selectPagePostList(pageQuery.build(), buildQueryWrapper(post)); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + @Override + public List selectPostList(SysPostBo post) { + return postMapper.selectVoList(buildQueryWrapper(post)); + } + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 岗位ID + */ + @Override + public List selectPostsByUserId(Long userId) { + return postMapper.selectPostsByUserId(userId); + } + + /** + * 根据查询条件构建查询包装器 + * + * @param bo 查询条件对象 + * @return 构建好的查询包装器 + */ + private Wrapper buildQueryWrapper(SysPostBo bo) { + Map params = bo.getParams(); + var wrapper = postMapper.lambda() + .likeIfText(SysPost::getPostCode, bo.getPostCode()) + .likeIfText(SysPost::getPostCategory, bo.getPostCategory()) + .likeIfText(SysPost::getPostName, bo.getPostName()) + .eqIfText(SysPost::getStatus, bo.getStatus()) + .betweenParams(SysPost::getCreateTime, params, "beginTime", "endTime") + .orderByAsc(SysPost::getPostSort); + if (ObjectUtil.isNotNull(bo.getDeptId())) { + //优先单部门搜索 + wrapper.eq(SysPost::getDeptId, bo.getDeptId()); + } else if (ObjectUtil.isNotNull(bo.getBelongDeptId())) { + //部门树搜索 + wrapper.and(x -> { + List deptIds = deptMapper.selectDeptAndChildById(bo.getBelongDeptId()); + x.in(SysPost::getDeptId, deptIds); + }); + } + return wrapper; + } + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + @Override + public List selectPostAll() { + return postMapper.lambda().voList(); + } + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + @Override + public SysPostVo selectPostById(Long postId) { + return postMapper.selectVoById(postId); + } + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + @Override + public List selectPostListByUserId(Long userId) { + List list = postMapper.selectPostsByUserId(userId); + return StreamUtils.toList(list, SysPostVo::getPostId); + } + + /** + * 通过岗位ID串查询岗位 + * + * @param postIds 岗位id串 + * @return 岗位列表信息 + */ + @Override + public List selectPostByIds(Collection postIds) { + return postMapper.lambda() + .select(SysPost::getPostId, SysPost::getPostName, SysPost::getPostCode) + .eq(SysPost::getStatus, SystemConstants.NORMAL) + .in(CollUtil.isNotEmpty(postIds), SysPost::getPostId, postIds) + .voList(); + } + + /** + * 校验岗位名称是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostNameUnique(SysPostBo post) { + boolean exist = postMapper.lambda() + .eq(SysPost::getPostName, post.getPostName()) + .eq(SysPost::getDeptId, post.getDeptId()) + .neIfPresent(SysPost::getPostId, post.getPostId()) + .exists(); + return !exist; + } + + /** + * 校验岗位编码是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostCodeUnique(SysPostBo post) { + boolean exist = postMapper.lambda() + .eq(SysPost::getPostCode, post.getPostCode()) + .neIfPresent(SysPost::getPostId, post.getPostId()) + .exists(); + return !exist; + } + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public long countUserPostById(Long postId) { + return userPostMapper.lambda().eq(SysUserPost::getPostId, postId).count(); + } + + /** + * 通过部门ID查询岗位使用数量 + * + * @param deptId 部门id + * @return 结果 + */ + @Override + public long countPostByDeptId(Long deptId) { + return postMapper.lambda().eq(SysPost::getDeptId, deptId).count(); + } + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int deletePostById(Long postId) { + return postMapper.deleteById(postId); + } + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + @Override + public int deletePostByIds(Collection postIds) { + List list = postMapper.selectByIds(postIds); + for (SysPost post : list) { + if (this.countUserPostById(post.getPostId()) > 0) { + throw new ServiceException("{}已分配,不能删除!", post.getPostName()); + } + } + return postMapper.deleteByIds(postIds); + } + + /** + * 新增保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + @Override + public int insertPost(SysPostBo bo) { + SysPost post = MapstructUtils.convert(bo, SysPost.class); + return postMapper.insert(post); + } + + /** + * 修改保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + @Override + public int updatePost(SysPostBo bo) { + SysPost post = MapstructUtils.convert(bo, SysPost.class); + return postMapper.updateById(post); + } + + /** + * 根据岗位 ID 列表查询岗位名称映射关系 + * + * @param postIds 岗位 ID 列表 + * @return Map,其中 key 为岗位 ID,value 为对应的岗位名称 + */ + @Override + public Map selectPostNamesByIds(Collection postIds) { + if (CollUtil.isEmpty(postIds)) { + return Collections.emptyMap(); + } + List list = postMapper.lambda() + .select(SysPost::getPostId, SysPost::getPostName) + .in(SysPost::getPostId, postIds) + .list(); + return StreamUtils.toMap(list, SysPost::getPostId, SysPost::getPostName); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 000000000..caa15c4a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,620 @@ +package org.dromara.system.service.impl; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.RoleService; +import org.dromara.system.api.model.LoginUser; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysRoleDept; +import org.dromara.system.domain.SysRoleMenu; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.event.OnlineUserCleanEvent; +import org.dromara.system.mapper.SysRoleDeptMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysRoleMenuMapper; +import org.dromara.system.mapper.SysUserRoleMapper; +import org.dromara.system.service.ISysRoleService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 角色 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysRoleServiceImpl implements ISysRoleService, RoleService { + + private final SysRoleMapper roleMapper; + private final SysRoleMenuMapper roleMenuMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysRoleDeptMapper roleDeptMapper; + + /** + * 分页查询角色列表 + * + * @param role 查询条件 + * @param pageQuery 分页参数 + * @return 角色分页列表 + */ + @Override + public PageResult selectPageRoleList(SysRoleBo role, PageQuery pageQuery) { + Page page = roleMapper.selectPageRoleList(pageQuery.build(), this.buildQueryWrapper(role)); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 根据条件查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + @Override + public List selectRoleList(SysRoleBo role) { + return roleMapper.selectRoleList(this.buildQueryWrapper(role)); + } + + /** + * 构造角色列表查询条件。 + * + * @param bo 角色筛选条件 + * @return 包含名称、权限字符、状态和创建时间区间的查询包装器 + */ + private Wrapper buildQueryWrapper(SysRoleBo bo) { + Map params = bo.getParams(); + return QueryBuilder.lambda(SysRole.class) + .eqIfPresent(SysRole::getRoleId, bo.getRoleId()) + .likeIfText(SysRole::getRoleName, bo.getRoleName()) + .eqIfText(SysRole::getStatus, bo.getStatus()) + .likeIfText(SysRole::getRoleKey, bo.getRoleKey()) + .betweenParams(SysRole::getCreateTime, params, "beginTime", "endTime") + .orderByAsc(SysRole::getRoleSort, SysRole::getCreateTime) + .build(); + } + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesByUserId(Long userId) { + return roleMapper.selectRolesByUserId(userId); + } + + /** + * 根据用户ID查询角色列表(包含被授权状态) + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesAuthByUserId(Long userId) { + List userRoles = roleMapper.selectRolesByUserId(userId); + List roles = selectRoleAll(); + // 使用HashSet提高查找效率 + Set userRoleIds = StreamUtils.toSet(userRoles, SysRoleVo::getRoleId); + for (SysRoleVo role : roles) { + if (userRoleIds.contains(role.getRoleId())) { + role.setFlag(true); + } + } + return roles; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectRolePermissionByUserId(Long userId) { + List perms = roleMapper.selectRolesByUserId(userId); + Set permsSet = new HashSet<>(); + for (SysRoleVo perm : perms) { + if (ObjectUtil.isNotNull(perm)) { + permsSet.addAll(StringUtils.splitList(perm.getRoleKey().trim())); + } + } + return permsSet; + } + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + @Override + public List selectRoleAll() { + return this.selectRoleList(new SysRoleBo()); + } + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + @Override + public List selectRoleListByUserId(Long userId) { + List list = roleMapper.selectRolesByUserId(userId); + return StreamUtils.toList(list, SysRoleVo::getRoleId); + } + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + @Override + public SysRoleVo selectRoleById(Long roleId) { + return roleMapper.selectRoleById(roleId); + } + + /** + * 通过角色ID串查询角色 + * + * @param roleIds 角色ID串 + * @return 角色列表信息 + */ + @Override + public List selectRoleByIds(Collection roleIds) { + return roleMapper.selectRoleList(roleMapper.lambda() + .eq(SysRole::getStatus, SystemConstants.NORMAL) + .inIfNotEmpty(SysRole::getRoleId, roleIds) + .build()); + } + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleNameUnique(SysRoleBo role) { + boolean exist = roleMapper.lambda() + .eq(SysRole::getRoleName, role.getRoleName()) + .neIfPresent(SysRole::getRoleId, role.getRoleId()) + .exists(); + return !exist; + } + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleKeyUnique(SysRoleBo role) { + boolean exist = roleMapper.lambda() + .eq(SysRole::getRoleKey, role.getRoleKey()) + .neIfPresent(SysRole::getRoleId, role.getRoleId()) + .exists(); + return !exist; + } + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + @Override + public void checkRoleAllowed(SysRoleBo role) { + if (ObjectUtil.isNotNull(role.getRoleId()) && SystemConstants.SUPER_ADMIN_ROLE_ID.equals(role.getRoleId())) { + throw new ServiceException("不允许操作超级管理员角色"); + } + String[] keys = new String[]{SystemConstants.SUPER_ADMIN_ROLE_KEY}; + // 新增不允许使用 管理员标识符 + if (ObjectUtil.isNull(role.getRoleId()) + && StringUtils.equalsAny(role.getRoleKey(), keys)) { + throw new ServiceException("不允许使用系统内置管理员角色标识符!"); + } + // 修改不允许修改 管理员标识符 + if (ObjectUtil.isNotNull(role.getRoleId())) { + SysRole sysRole = roleMapper.selectById(role.getRoleId()); + // 如果标识符不相等 判断为修改了管理员标识符 + if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())) { + if (StringUtils.equalsAny(sysRole.getRoleKey(), keys)) { + throw new ServiceException("不允许修改系统内置管理员角色标识符!"); + } else if (StringUtils.equalsAny(role.getRoleKey(), keys)) { + throw new ServiceException("不允许使用系统内置管理员角色标识符!"); + } + } + } + } + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + @Override + public void checkRoleDataScope(Long roleId) { + if (ObjectUtil.isNull(roleId)) { + return; + } + this.checkRoleDataScope(Collections.singletonList(roleId)); + } + + /** + * 校验角色是否有数据权限 + * + * @param roleIds 角色ID列表(支持传单个ID) + */ + @Override + public void checkRoleDataScope(Collection roleIds) { + if (CollUtil.isEmpty(roleIds) || LoginHelper.isSuperAdmin()) { + return; + } + long count = roleMapper.selectRoleCount(roleIds); + if (count != roleIds.size()) { + throw new ServiceException("没有权限访问部分角色数据!"); + } + } + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + public long countUserRoleByRoleId(Long roleId) { + return userRoleMapper.lambda().eq(SysUserRole::getRoleId, roleId).count(); + } + + /** + * 新增保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertRole(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + // 新增角色信息 + roleMapper.insert(role); + bo.setRoleId(role.getRoleId()); + return insertRoleMenu(bo); + } + + /** + * 修改角色基础信息(不更新菜单与数据权限)。 + * + * @param bo 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateRoleBaseInfo(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + + if (SystemConstants.DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) { + throw new ServiceException("角色已分配,不能禁用!"); + } + // 仅更新角色基础字段,避免影响权限分配。 + return roleMapper.updateById(role); + } + + /** + * 修改角色权限信息(菜单权限 + 数据权限)。 + * + * @param bo 角色权限参数 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#bo.roleId") + @Override + @Transactional(rollbackFor = Exception.class) + public int updateRolePermission(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + // 更新权限相关配置字段(数据范围、树联动)。 + roleMapper.updateById(role); + // 先清理旧菜单权限,再重建。 + roleMenuMapper.lambda().eq(SysRoleMenu::getRoleId, role.getRoleId()).delete(); + insertRoleMenu(bo); + // 先清理旧数据权限,再按当前配置重建。 + roleDeptMapper.lambda().eq(SysRoleDept::getRoleId, role.getRoleId()).delete(); + return insertRoleDept(bo); + } + + /** + * 修改角色状态 + * + * @param roleId 角色ID + * @param status 角色状态 + * @return 结果 + */ + @Override + public int updateRoleStatus(Long roleId, String status) { + if (SystemConstants.DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) { + throw new ServiceException("角色已分配,不能禁用!"); + } + return roleMapper.lambda() + .set(SysRole::getStatus, status) + .eq(SysRole::getRoleId, roleId) + .updateCount(); + } + + + /** + * 新增角色菜单信息 + * + * @param role 角色对象 + */ + private int insertRoleMenu(SysRoleBo role) { + int rows = 1; + // 新增用户与角色管理 + List list = new ArrayList<>(); + for (Long menuId : role.getMenuIds()) { + SysRoleMenu rm = new SysRoleMenu(); + rm.setRoleId(role.getRoleId()); + rm.setMenuId(menuId); + list.add(rm); + } + if (CollUtil.isNotEmpty(list)) { + rows = roleMenuMapper.insertBatch(list) ? list.size() : 0; + } + return rows; + } + + /** + * 新增角色部门信息(数据权限) + * + * @param role 角色对象 + */ + private int insertRoleDept(SysRoleBo role) { + int rows = 1; + // 新增角色与部门(数据权限)管理 + List list = new ArrayList<>(); + for (Long deptId : role.getDeptIds()) { + SysRoleDept rd = new SysRoleDept(); + rd.setRoleId(role.getRoleId()); + rd.setDeptId(deptId); + list.add(rd); + } + if (CollUtil.isNotEmpty(list)) { + rows = roleDeptMapper.insertBatch(list) ? list.size() : 0; + } + return rows; + } + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId") + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleById(Long roleId) { + // 删除角色与菜单关联 + roleMenuMapper.lambda().eq(SysRoleMenu::getRoleId, roleId).delete(); + // 删除角色与部门关联 + roleDeptMapper.lambda().eq(SysRoleDept::getRoleId, roleId).delete(); + return roleMapper.deleteById(roleId); + } + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, allEntries = true) + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleByIds(Collection roleIds) { + this.checkRoleDataScope(roleIds); + List roles = roleMapper.selectByIds(roleIds); + for (SysRole role : roles) { + checkRoleAllowed(BeanUtil.toBean(role, SysRoleBo.class)); + if (countUserRoleByRoleId(role.getRoleId()) > 0) { + throw new ServiceException(String.format("%1$s已分配,不能删除!", role.getRoleName())); + } + } + // 删除角色与菜单关联 + roleMenuMapper.lambda().in(SysRoleMenu::getRoleId, roleIds).delete(); + // 删除角色与部门关联 + roleDeptMapper.lambda().in(SysRoleDept::getRoleId, roleIds).delete(); + return roleMapper.deleteByIds(roleIds); + } + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + @Override + public int deleteAuthUser(SysUserRole userRole) { + if (LoginHelper.getUserId().equals(userRole.getUserId())) { + throw new ServiceException("不允许修改当前用户角色!"); + } + int rows = userRoleMapper.lambda() + .eq(SysUserRole::getRoleId, userRole.getRoleId()) + .eq(SysUserRole::getUserId, userRole.getUserId()) + .deleteCount(); + if (rows > 0) { + SpringUtils.context().publishEvent(OnlineUserCleanEvent.byUsers(List.of(userRole.getUserId()))); + } + return rows; + } + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + @Override + public int deleteAuthUsers(Long roleId, Collection userIds) { + if (userIds.contains(LoginHelper.getUserId())) { + throw new ServiceException("不允许修改当前用户角色!"); + } + int rows = userRoleMapper.lambda() + .eq(SysUserRole::getRoleId, roleId) + .in(SysUserRole::getUserId, userIds) + .deleteCount(); + if (rows > 0) { + SpringUtils.context().publishEvent(OnlineUserCleanEvent.byUsers(userIds)); + } + return rows; + } + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要授权的用户数据ID + * @return 结果 + */ + @Override + public int insertAuthUsers(Long roleId, Collection userIds) { + // 新增用户与角色管理 + int rows = 1; + if (userIds.contains(LoginHelper.getUserId())) { + throw new ServiceException("不允许修改当前用户角色!"); + } + List list = StreamUtils.toList(userIds, userId -> { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + return ur; + }); + if (CollUtil.isNotEmpty(list)) { + rows = userRoleMapper.insertBatch(list) ? list.size() : 0; + } + if (rows > 0) { + SpringUtils.context().publishEvent(OnlineUserCleanEvent.byUsers(userIds)); + } + return rows; + } + + /** + * 根据角色ID清除该角色关联的所有在线用户的登录状态(踢出在线用户) + * + *

+ * 先判断角色是否绑定用户,若无绑定则直接返回 + * 然后遍历当前所有在线Token,查找拥有该角色的用户并强制登出 + * 注意:在线用户量过大时,操作可能导致 Redis 阻塞,需谨慎调用 + *

+ * + * @param roleId 角色ID + */ + @Override + public void cleanOnlineUserByRole(Long roleId) { + // 如果角色未绑定用户 直接返回 + Long num = userRoleMapper.lambda().eq(SysUserRole::getRoleId, roleId).count(); + if (num == 0) { + return; + } + List keys = StpUtil.searchTokenValue("", 0, -1, false); + if (CollUtil.isEmpty(keys)) { + return; + } + // 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作 + keys.parallelStream().forEach(key -> { + String token = StringUtils.substringAfterLast(key, StringUtils.COLON); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return; + } + LoginUser loginUser = LoginHelper.getLoginUser(token); + if (ObjectUtil.isNull(loginUser) || CollUtil.isEmpty(loginUser.getRoles())) { + return; + } + if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) { + try { + StpUtil.logoutByTokenValue(token); + } catch (NotLoginException ignored) { + } + } + }); + } + + /** + * 根据用户ID列表清除对应在线用户的登录状态(踢出指定用户) + * + *

+ * 遍历当前所有在线Token,匹配用户ID列表中的用户,强制登出 + * 注意:在线用户量过大时,操作可能导致 Redis 阻塞,需谨慎调用 + *

+ * + * @param userIds 需要清除的用户ID列表 + */ + @Override + public void cleanOnlineUser(Collection userIds) { + List keys = StpUtil.searchTokenValue("", 0, -1, false); + if (CollUtil.isEmpty(keys)) { + return; + } + // 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作 + keys.parallelStream().forEach(key -> { + String token = StringUtils.substringAfterLast(key, StringUtils.COLON); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return; + } + LoginUser loginUser = LoginHelper.getLoginUser(token); + if (ObjectUtil.isNull(loginUser)) { + return; + } + if (userIds.contains(loginUser.getUserId())) { + try { + StpUtil.logoutByTokenValue(token); + } catch (NotLoginException ignored) { + } + } + }); + } + + /** + * 根据角色 ID 列表查询角色名称映射关系 + * + * @param roleIds 角色 ID 列表 + * @return Map,其中 key 为角色 ID,value 为对应的角色名称 + */ + @Override + public Map selectRoleNamesByIds(Collection roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return Collections.emptyMap(); + } + List list = roleMapper.lambda() + .select(SysRole::getRoleId, SysRole::getRoleName) + .in(SysRole::getRoleId, roleIds) + .list(); + return StreamUtils.toMap(list, SysRole::getRoleId, SysRole::getRoleName); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java new file mode 100644 index 000000000..869bb9d71 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java @@ -0,0 +1,47 @@ +package org.dromara.system.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ArrayUtil; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sensitive.core.SensitiveService; +import org.springframework.stereotype.Service; + +/** + * 脱敏服务 + * 默认管理员不过滤 + * 需自行根据业务重写实现 + * + * @author Lion Li + * @version 3.6.0 + */ +@Service +public class SysSensitiveServiceImpl implements SensitiveService { + + /** + * 是否脱敏 + * + * @param roleKey 允许查看原文的角色标识列表 + * @param perms 允许查看原文的权限标识列表 + * @return 需要脱敏返回 {@code true} + */ + @Override + public boolean isSensitive(String[] roleKey, String[] perms) { + if (!LoginHelper.isLogin()) { + return true; + } + boolean roleExist = ArrayUtil.isNotEmpty(roleKey); + boolean permsExist = ArrayUtil.isNotEmpty(perms); + if (roleExist && permsExist) { + if (StpUtil.hasRoleOr(roleKey) && StpUtil.hasPermissionOr(perms)) { + return false; + } + } else if (roleExist && StpUtil.hasRoleOr(roleKey)) { + return false; + } else if (permsExist && StpUtil.hasPermissionOr(perms)) { + return false; + } + + return !LoginHelper.isSuperAdmin(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java new file mode 100644 index 000000000..b03870f3e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java @@ -0,0 +1,132 @@ +package org.dromara.system.service.impl; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.system.domain.SysSocial; +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.mapper.SysSocialMapper; +import org.dromara.system.service.ISysSocialService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 社会化关系Service业务层处理 + * + * @author thiszhc + * @date 2023-06-12 + */ +@RequiredArgsConstructor +@Service +public class SysSocialServiceImpl implements ISysSocialService { + + private final SysSocialMapper socialMapper; + + + /** + * 查询社会化关系 + * + * @param id 主键 + * @return 社会化绑定详情 + */ + @Override + public SysSocialVo queryById(String id) { + return socialMapper.selectVoById(id); + } + + /** + * 授权列表 + * + * @param bo 查询条件 + * @return 社会化授权关系列表 + */ + @Override + public List queryList(SysSocialBo bo) { + return socialMapper.lambda() + .eqIfPresent(SysSocial::getUserId, bo.getUserId()) + .eqIfText(SysSocial::getAuthId, bo.getAuthId()) + .eqIfText(SysSocial::getSource, bo.getSource()) + .voList(); + } + + /** + * 按用户主键查询其绑定的社会化授权列表。 + * + * @param userId 用户主键 + * @return 用户已绑定的社会化授权列表 + */ + @Override + public List queryListByUserId(Long userId) { + return socialMapper.lambda().eq(SysSocial::getUserId, userId).voList(); + } + + + /** + * 新增社会化关系 + * + * @param bo 业务对象 + * @return 新增成功返回 {@code true} + */ + @Override + public Boolean insertByBo(SysSocialBo bo) { + SysSocial add = MapstructUtils.convert(bo, SysSocial.class); + validEntityBeforeSave(add); + boolean flag = socialMapper.insert(add) > 0; + if (flag) { + if (add != null) { + bo.setId(add.getId()); + } else { + return false; + } + } + return flag; + } + + /** + * 更新社会化关系 + * + * @param bo 业务对象 + * @return 更新成功返回 {@code true} + */ + @Override + public Boolean updateByBo(SysSocialBo bo) { + SysSocial update = MapstructUtils.convert(bo, SysSocial.class); + validEntityBeforeSave(update); + return socialMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + * + * @param entity 待保存的社会化关系实体 + */ + private void validEntityBeforeSave(SysSocial entity) { + //TODO 做一些数据校验,如唯一约束 + } + + + /** + * 删除社会化关系 + * + * @param id 主键 + * @return 删除成功返回 {@code true} + */ + @Override + public Boolean deleteWithValidById(Long id) { + return socialMapper.deleteById(id) > 0; + } + + + /** + * 根据 authId 查询用户信息 + * + * @param authId 认证id + * @return 授权信息 + */ + @Override + public List selectByAuthId(String authId) { + return socialMapper.lambda().eq(SysSocial::getAuthId, authId).voList(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java new file mode 100644 index 000000000..b9b89478d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java @@ -0,0 +1,138 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.api.TaskAssigneeService; +import org.dromara.system.api.domain.TaskAssigneeDTO; +import org.dromara.system.api.model.TaskAssigneeBody; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysPostService; +import org.dromara.system.service.ISysRoleService; +import org.dromara.system.service.ISysUserService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * 工作流设计器获取任务执行人 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysTaskAssigneeServiceImpl implements TaskAssigneeService { + + // 上级Service注入下级Service 其他Service永远不可能注入当前类 避免循环注入 + private final ISysPostService postService; + private final ISysDeptService deptService; + private final ISysUserService userService; + private final ISysRoleService roleService; + + /** + * 查询角色并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + SysRoleBo bo = new SysRoleBo(); + bo.setRoleKey(taskQuery.getHandlerCode()); + bo.setRoleName(taskQuery.getHandlerName()); + bo.setStatus(SystemConstants.NORMAL); + Map params = bo.getParams(); + params.put("beginTime", taskQuery.getBeginTime()); + params.put("endTime", taskQuery.getEndTime()); + PageResult page = roleService.selectPageRoleList(bo, pageQuery); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(), + item -> Convert.toStr(item.getRoleId()), SysRoleVo::getRoleKey, SysRoleVo::getRoleName, item -> "", SysRoleVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + /** + * 查询岗位并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + SysPostBo bo = new SysPostBo(); + bo.setPostCategory(taskQuery.getHandlerCode()); + bo.setPostName(taskQuery.getHandlerName()); + bo.setStatus(SystemConstants.NORMAL); + Map params = bo.getParams(); + params.put("beginTime", taskQuery.getBeginTime()); + params.put("endTime", taskQuery.getEndTime()); + bo.setBelongDeptId(Convert.toLong(taskQuery.getGroupId())); + PageResult page = postService.selectPagePostList(bo, pageQuery); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(), + item -> Convert.toStr(item.getPostId()), SysPostVo::getPostCategory, SysPostVo::getPostName, item -> Convert.toStr(item.getDeptId()), SysPostVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + /** + * 查询部门并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + SysDeptBo bo = new SysDeptBo(); + bo.setDeptCategory(taskQuery.getHandlerCode()); + bo.setDeptName(taskQuery.getHandlerName()); + bo.setStatus(SystemConstants.NORMAL); + Map params = bo.getParams(); + params.put("beginTime", taskQuery.getBeginTime()); + params.put("endTime", taskQuery.getEndTime()); + bo.setBelongDeptId(Convert.toLong(taskQuery.getGroupId())); + PageResult page = deptService.selectPageDeptList(bo, pageQuery); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(), + item -> Convert.toStr(item.getDeptId()), SysDeptVo::getDeptCategory, SysDeptVo::getDeptName, item -> Convert.toStr(item.getParentId()), SysDeptVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + /** + * 查询用户并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + SysUserBo bo = new SysUserBo(); + bo.setUserName(taskQuery.getHandlerCode()); + bo.setNickName(taskQuery.getHandlerName()); + bo.setStatus(SystemConstants.NORMAL); + Map params = bo.getParams(); + params.put("beginTime", taskQuery.getBeginTime()); + params.put("endTime", taskQuery.getEndTime()); + bo.setDeptId(Convert.toLong(taskQuery.getGroupId())); + PageResult page = userService.selectPageUserList(bo, pageQuery); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(), + item -> Convert.toStr(item.getUserId()), SysUserVo::getUserName, SysUserVo::getNickName, item -> Convert.toStr(item.getDeptId()), SysUserVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 000000000..770796762 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,777 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.UserService; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.SysUserPost; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserExportVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.*; +import org.dromara.system.service.ISysUserService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 用户 业务层处理 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysUserServiceImpl implements ISysUserService, UserService { + + private final SysUserMapper userMapper; + private final SysDeptMapper deptMapper; + private final SysRoleMapper roleMapper; + private final SysPostMapper postMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysUserPostMapper userPostMapper; + + /** + * 分页查询用户列表。 + * + * @param user 用户筛选条件 + * @param pageQuery 分页参数 + * @return 用户分页结果 + */ + @Override + public PageResult selectPageUserList(SysUserBo user, PageQuery pageQuery) { + Page page = userMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user)); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public List selectUserExportList(SysUserBo user) { + List deptIds = ObjectUtil.isNotNull(user.getDeptId()) ? deptMapper.selectDeptAndChildById(user.getDeptId()) : null; + return userMapper.selectUserExportList(user, deptIds); + } + + /** + * 构造用户列表查询条件。 + * + * @param user 用户筛选条件 + * @return 叠加部门、状态、时间区间等条件的查询包装器 + */ + private Wrapper buildQueryWrapper(SysUserBo user) { + Map params = user.getParams(); + LambdaQueryWrapper wrapper = QueryBuilder.lambda(SysUser.class) + .eq(SysUser::getDelFlag, SystemConstants.NORMAL) + .eqIfPresent(SysUser::getUserId, user.getUserId()) + .in(StringUtils.isNotBlank(user.getUserIds()), SysUser::getUserId, StringUtils.splitTo(user.getUserIds(), Convert::toLong)) + .likeIfText(SysUser::getUserName, user.getUserName()) + .likeIfText(SysUser::getNickName, user.getNickName()) + .eqIfText(SysUser::getStatus, user.getStatus()) + .likeIfText(SysUser::getPhoneNumber, user.getPhoneNumber()) + .betweenParams(SysUser::getCreateTime, params, "beginTime", "endTime") + .and(ObjectUtil.isNotNull(user.getDeptId()), w -> { + List ids = deptMapper.selectDeptAndChildById(user.getDeptId()); + w.in(SysUser::getDeptId, ids); + }) + .orderByAsc(SysUser::getUserId) + .build(); + if (StringUtils.isNotBlank(user.getExcludeUserIds())) { + wrapper.notIn(SysUser::getUserId, StringUtils.splitTo(user.getExcludeUserIds(), Convert::toLong)); + } + return wrapper; + } + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public PageResult selectAllocatedList(SysUserBo user, PageQuery pageQuery) { + Page page = userMapper.selectAllocatedList(pageQuery.build(), user); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public PageResult selectUnallocatedList(SysUserBo user, PageQuery pageQuery) { + List userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId()); + Page page = userMapper.selectUnallocatedList(pageQuery.build(), user, userIds); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserByUserName(String userName) { + return userMapper.lambda().eq(SysUser::getUserName, userName).voOne(); + } + + /** + * 通过手机号查询用户 + * + * @param phoneNumber 手机号 + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserByPhoneNumber(String phoneNumber) { + return userMapper.lambda().eq(SysUser::getPhoneNumber, phoneNumber).voOne(); + } + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserById(Long userId) { + SysUserVo user = userMapper.selectVoById(userId); + if (ObjectUtil.isNull(user)) { + return user; + } + user.setRoles(roleMapper.selectRolesByUserId(user.getUserId())); + return user; + } + + /** + * 通过用户ID串查询用户 + * + * @param userIds 用户ID串 + * @param deptId 部门id + * @return 用户列表信息 + */ + @Override + public List selectUserByIds(Collection userIds, Long deptId) { + return userMapper.selectUserList(userMapper.lambda() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .eqIfPresent(SysUser::getDeptId, deptId) + .inIfNotEmpty(SysUser::getUserId, userIds) + .build()); + } + + /** + * 查询用户所属角色组 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + public String selectUserRoleGroup(Long userId) { + List list = roleMapper.selectRolesByUserId(userId); + if (CollUtil.isEmpty(list)) { + return StringUtils.EMPTY; + } + return StreamUtils.join(list, SysRoleVo::getRoleName); + } + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + public String selectUserPostGroup(Long userId) { + List list = postMapper.selectPostsByUserId(userId); + if (CollUtil.isEmpty(list)) { + return StringUtils.EMPTY; + } + return StreamUtils.join(list, SysPostVo::getPostName); + } + + /** + * 校验用户账号是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean checkUserNameUnique(SysUserBo user) { + boolean exist = userMapper.lambda() + .eq(SysUser::getUserName, user.getUserName()) + .neIfPresent(SysUser::getUserId, user.getUserId()) + .exists(); + return !exist; + } + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + */ + @Override + public boolean checkPhoneUnique(SysUserBo user) { + boolean exist = userMapper.lambda() + .eq(SysUser::getPhoneNumber, user.getPhoneNumber()) + .neIfPresent(SysUser::getUserId, user.getUserId()) + .exists(); + return !exist; + } + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + */ + @Override + public boolean checkEmailUnique(SysUserBo user) { + boolean exist = userMapper.lambda() + .eq(SysUser::getEmail, user.getEmail()) + .neIfPresent(SysUser::getUserId, user.getUserId()) + .exists(); + return !exist; + } + + /** + * 校验用户是否允许操作 + * + * @param userId 用户ID + */ + @Override + public void checkUserAllowed(Long userId) { + if (ObjectUtil.isNotNull(userId) && LoginHelper.isSuperAdmin(userId)) { + throw new ServiceException("不允许操作超级管理员用户"); + } + } + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + @Override + public void checkUserDataScope(Long userId) { + if (ObjectUtil.isNull(userId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (userMapper.countUserById(userId) == 0) { + throw new ServiceException("没有权限访问用户数据!"); + } + } + + /** + * 新增保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertUser(SysUserBo user) { + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + // 新增用户信息 + int rows = userMapper.insert(sysUser); + user.setUserId(sysUser.getUserId()); + // 新增用户岗位关联 + insertUserPost(user, false); + // 新增用户与角色管理 + insertUserRole(user, false); + return rows; + } + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean registerUser(SysUserBo user) { + user.setCreateBy(0L); + user.setUpdateBy(0L); + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + return userMapper.insert(sysUser) > 0; + } + + /** + * 修改保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId") + @Transactional(rollbackFor = Exception.class) + public int updateUser(SysUserBo user) { + // 新增用户与角色管理 + insertUserRole(user, true); + // 新增用户与岗位管理 + insertUserPost(user, true); + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + // 防止错误更新后导致的数据误删除 + int flag = userMapper.updateById(sysUser); + if (flag < 1) { + throw new ServiceException("修改用户{}信息失败", user.getUserName()); + } + return flag; + } + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void insertUserAuth(Long userId, Long[] roleIds) { + insertUserRole(userId, roleIds, true); + } + + /** + * 修改用户状态 + * + * @param userId 用户ID + * @param status 账号状态 + * @return 结果 + */ + @Override + public int updateUserStatus(Long userId, String status) { + return userMapper.lambda() + .set(SysUser::getStatus, status) + .eq(SysUser::getUserId, userId) + .updateCount(); + } + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId") + @Override + public int updateUserProfile(SysUserBo user) { + return userMapper.lambda() + .setIfPresent(SysUser::getNickName, user.getNickName()) + .setIfPresent(SysUser::getAvatar, user.getAvatar()) + .setIfPresent(SysUser::getPhoneNumber, user.getPhoneNumber()) + .setIfPresent(SysUser::getEmail, user.getEmail()) + .setIfPresent(SysUser::getGender, user.getGender()) + .eq(SysUser::getUserId, user.getUserId()) + .updateCount(); + } + + /** + * 重置用户密码 + * + * @param userId 用户ID + * @param password 密码 + * @return 结果 + */ + @Override + public int resetUserPwd(Long userId, String password) { + return userMapper.lambda() + .set(SysUser::getPassword, password) + .eq(SysUser::getUserId, userId) + .updateCount(); + } + + /** + * 新增用户角色信息 + * + * @param user 用户对象 + * @param clear 清除已存在的关联数据 + */ + private void insertUserRole(SysUserBo user, boolean clear) { + this.insertUserRole(user.getUserId(), user.getRoleIds(), clear); + } + + /** + * 新增用户岗位信息 + * + * @param user 用户对象 + * @param clear 清除已存在的关联数据 + */ + private void insertUserPost(SysUserBo user, boolean clear) { + Long[] postIdArr = user.getPostIds(); + if (ArrayUtil.isEmpty(postIdArr)) { + return; + } + List postIds = Arrays.asList(postIdArr); + + // 校验是否有权限操作这些岗位(含数据权限控制) + if (postMapper.selectPostCount(postIds) != postIds.size()) { + throw new ServiceException("没有权限访问岗位的数据"); + } + + // 是否清除旧的用户岗位绑定 + if (clear) { + userPostMapper.lambda().eq(SysUserPost::getUserId, user.getUserId()).delete(); + } + + // 构建用户岗位关联列表并批量插入 + List list = StreamUtils.toList(postIds, + postId -> { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + return up; + }); + userPostMapper.insertBatch(list); + } + + /** + * 新增用户角色信息 + * + * @param userId 用户ID + * @param roleIds 角色组 + * @param clear 清除已存在的关联数据 + */ + private void insertUserRole(Long userId, Long[] roleIds, boolean clear) { + if (ArrayUtil.isEmpty(roleIds)) { + return; + } + + List roleList = new ArrayList<>(Arrays.asList(roleIds)); + + // 非超级管理员,禁止包含超级管理员角色 + if (!LoginHelper.isSuperAdmin(userId)) { + roleList.remove(SystemConstants.SUPER_ADMIN_ROLE_ID); + } + + // 移除超管角色后若无剩余角色,说明仅选了超管角色且不允许分配,显式报错 + if (roleList.isEmpty()) { + throw new ServiceException("不允许为普通用户分配超级管理员角色,请至少选择一个其他角色"); + } + + // 校验是否有权限访问这些角色(含数据权限控制) + if (roleMapper.selectRoleCount(roleList) != roleList.size()) { + throw new ServiceException("没有权限访问角色的数据"); + } + + // 是否清除原有绑定 + if (clear) { + userRoleMapper.lambda().eq(SysUserRole::getUserId, userId).delete(); + } + + // 批量插入用户-角色关联 + List list = StreamUtils.toList(roleList, + roleId -> { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + return ur; + }); + userRoleMapper.insertBatch(list); + } + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserById(Long userId) { + // 删除用户与角色关联 + userRoleMapper.lambda().eq(SysUserRole::getUserId, userId).delete(); + // 删除用户与岗位表 + userPostMapper.lambda().eq(SysUserPost::getUserId, userId).delete(); + // 防止更新失败导致的数据删除 + int flag = userMapper.deleteById(userId); + if (flag < 1) { + throw new ServiceException("删除用户失败!"); + } + return flag; + } + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserByIds(Long[] userIds) { + for (Long userId : userIds) { + checkUserAllowed(userId); + checkUserDataScope(userId); + } + List ids = List.of(userIds); + // 删除用户与角色关联 + userRoleMapper.lambda().in(SysUserRole::getUserId, ids).delete(); + // 删除用户与岗位表 + userPostMapper.lambda().in(SysUserPost::getUserId, ids).delete(); + // 防止更新失败导致的数据删除 + int flag = userMapper.deleteByIds(ids); + if (flag < 1) { + throw new ServiceException("删除用户失败!"); + } + return flag; + } + + /** + * 通过部门id查询当前部门所有用户 + * + * @param deptId 部门ID + * @return 用户信息集合信息 + */ + @Override + public List selectUserListByDept(Long deptId) { + return userMapper.lambda() + .eq(SysUser::getDeptId, deptId) + .orderByAsc(SysUser::getUserId) + .voList(); + } + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId") + @Override + public String selectUserNameById(Long userId) { + SysUser sysUser = userMapper.lambda() + .select(SysUser::getUserName) + .eq(SysUser::getUserId, userId) + .one(); + return ObjectUtils.notNullGetter(sysUser, SysUser::getUserName); + } + + /** + * 通过用户ID查询用户昵称 + * + * @param userId 用户ID + * @return 用户昵称 + */ + @Override + @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId") + public String selectNicknameById(Long userId) { + SysUser sysUser = userMapper.lambda() + .select(SysUser::getNickName) + .eq(SysUser::getUserId, userId) + .one(); + return ObjectUtils.notNullGetter(sysUser, SysUser::getNickName); + } + + /** + * 通过用户ID查询用户昵称 + * + * @param userIds 用户ID 多个用逗号隔开 + * @return 用户昵称 + */ + @Override + public String selectNicknameByIds(String userIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(userIds, Convert::toLong)) { + String nickname = SpringUtils.getAopProxy(this).selectNicknameById(id); + if (StringUtils.isNotBlank(nickname)) { + list.add(nickname); + } + } + return StringUtils.joinComma(list); + } + + /** + * 通过用户ID查询用户手机号 + * + * @param userId 用户id + * @return 用户手机号 + */ + @Override + public String selectPhonenumberById(Long userId) { + SysUser sysUser = userMapper.lambda() + .select(SysUser::getPhoneNumber) + .eq(SysUser::getUserId, userId) + .one(); + return ObjectUtils.notNullGetter(sysUser, SysUser::getPhoneNumber); + } + + /** + * 通过用户ID查询用户邮箱 + * + * @param userId 用户id + * @return 用户邮箱 + */ + @Override + public String selectEmailById(Long userId) { + SysUser sysUser = userMapper.lambda() + .select(SysUser::getEmail) + .eq(SysUser::getUserId, userId) + .one(); + return ObjectUtils.notNullGetter(sysUser, SysUser::getEmail); + } + + /** + * 通过用户ID查询用户 + * + * @param userId 用户id + * @return 用户列表 + */ + @Override + public UserDTO selectById(Long userId) { + SysUserVo vo = userMapper.lambda() + .select(SysUser::getUserId, SysUser::getDeptId, SysUser::getUserName, + SysUser::getNickName, SysUser::getUserType, SysUser::getEmail, + SysUser::getPhoneNumber, SysUser::getGender, SysUser::getStatus, + SysUser::getCreateTime) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .eq(SysUser::getUserId, userId) + .voOne(); + return BeanUtil.copyProperties(vo, UserDTO.class); + } + + /** + * 通过用户ID查询用户列表 + * + * @param userIds 用户ids + * @return 用户列表 + */ + @Override + public List selectListByIds(Collection userIds) { + if (CollUtil.isEmpty(userIds)) { + return List.of(); + } + List list = userMapper.lambda() + .select(SysUser::getUserId, SysUser::getDeptId, SysUser::getUserName, + SysUser::getNickName, SysUser::getUserType, SysUser::getEmail, + SysUser::getPhoneNumber, SysUser::getGender, SysUser::getStatus, + SysUser::getCreateTime) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .in(SysUser::getUserId, userIds) + .voList(); + return BeanUtil.copyToList(list, UserDTO.class); + } + + /** + * 通过角色ID查询用户ID + * + * @param roleIds 角色ids + * @return 用户ids + */ + @Override + public List selectUserIdsByRoleIds(Collection roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return List.of(); + } + List userRoles = userRoleMapper.lambda().in(SysUserRole::getRoleId, roleIds).list(); + return StreamUtils.toList(userRoles, SysUserRole::getUserId); + } + + /** + * 通过角色ID查询用户 + * + * @param roleIds 角色ids + * @return 用户 + */ + @Override + public List selectUsersByRoleIds(Collection roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return List.of(); + } + + // 通过角色ID获取用户角色信息 + List userRoles = userRoleMapper.lambda().in(SysUserRole::getRoleId, roleIds).list(); + + // 获取用户ID列表 + Set userIds = StreamUtils.toSet(userRoles, SysUserRole::getUserId); + + return this.selectListByIds(new ArrayList<>(userIds)); + } + + /** + * 通过部门ID查询用户 + * + * @param deptIds 部门ids + * @return 用户 + */ + @Override + public List selectUsersByDeptIds(Collection deptIds) { + if (CollUtil.isEmpty(deptIds)) { + return List.of(); + } + List list = userMapper.lambda() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhoneNumber) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .in(SysUser::getDeptId, deptIds) + .voList(); + return BeanUtil.copyToList(list, UserDTO.class); + } + + /** + * 通过岗位ID查询用户 + * + * @param postIds 岗位ids + * @return 用户 + */ + @Override + public List selectUsersByPostIds(Collection postIds) { + if (CollUtil.isEmpty(postIds)) { + return List.of(); + } + + // 通过岗位ID获取用户岗位信息 + List userPosts = userPostMapper.lambda().in(SysUserPost::getPostId, postIds).list(); + + // 获取用户ID列表 + Set userIds = StreamUtils.toSet(userPosts, SysUserPost::getUserId); + + return this.selectListByIds(new ArrayList<>(userIds)); + } + + /** + * 根据用户 ID 列表查询用户昵称映射关系 + * + * @param userIds 用户 ID 列表 + * @return Map,其中 key 为用户 ID,value 为对应的用户昵称 + */ + @Override + public Map selectUserNicksByIds(Collection userIds) { + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyMap(); + } + List list = userMapper.lambda() + .select(SysUser::getUserId, SysUser::getNickName) + .in(SysUser::getUserId, userIds) + .list(); + return StreamUtils.toMap(list, SysUser::getUserId, SysUser::getNickName); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md new file mode 100644 index 000000000..c938b1e50 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml new file mode 100644 index 000000000..fd150ad12 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml new file mode 100644 index 000000000..e542a1031 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml new file mode 100644 index 000000000..928ad2738 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml new file mode 100644 index 000000000..6bcce514d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml new file mode 100644 index 000000000..6975da471 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLoginInfoMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLoginInfoMapper.xml new file mode 100644 index 000000000..f218640ff --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLoginInfoMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml new file mode 100644 index 000000000..9e78302f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageMapper.xml new file mode 100644 index 000000000..9e468e343 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml new file mode 100644 index 000000000..43f494db1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml new file mode 100644 index 000000000..5ef14eee9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml new file mode 100644 index 000000000..8c2c0808c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml new file mode 100644 index 000000000..d9b25bd5e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml new file mode 100644 index 000000000..a75350072 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml new file mode 100644 index 000000000..1705bb259 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml new file mode 100644 index 000000000..7f69e0101 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml new file mode 100644 index 000000000..f01dc5e8f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml new file mode 100644 index 000000000..baa4b5946 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml new file mode 100644 index 000000000..7f0df4a2c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml new file mode 100644 index 000000000..e9f2496fb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml new file mode 100644 index 000000000..6f7cedfee --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/pom.xml b/ruoyi-modules/ruoyi-workflow/pom.xml new file mode 100644 index 000000000..066eecadf --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/pom.xml @@ -0,0 +1,107 @@ + + + + org.dromara + ruoyi-modules + ${revision} + ../pom.xml + + 4.0.0 + + ruoyi-workflow + + + 工作流模块 + + + + + + + org.dromara + ruoyi-common-push + + + + + org.dromara + ruoyi-common-doc + + + + + org.dromara + ruoyi-common-mail + + + + + org.dromara + ruoyi-common-sms + + + + + org.dromara + ruoyi-common-mybatis + + + + + org.dromara + ruoyi-common-web + + + + + org.dromara + ruoyi-common-log + + + + + org.dromara + ruoyi-common-excel + + + + + org.dromara + ruoyi-common-translation + + + + + org.dromara + ruoyi-common-security + + + + + org.dromara + ruoyi-api + + + + + org.dromara.warm + warm-flow-mybatis-plus-sb3-starter + + + + + org.dromara.warm + warm-flow-plugin-ui-sb-web + + + + + org.dromara + ruoyi-common-liteflow + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java new file mode 100644 index 000000000..225bc9cb9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java @@ -0,0 +1,29 @@ +package org.dromara.workflow.common; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义条件注解,用于基于配置启用或禁用特定功能 + *

+ * 该注解只会在配置文件中 `warm-flow.enabled=true` 时,标注了此注解的类或方法才会被 Spring 容器加载 + *

+ * 示例配置: + *

+ * warm-flow:
+ *   enabled: true  # 设置为 true 时,启用工作流功能
+ * 
+ *

+ * 使用此注解时,可以动态控制工作流功能是否启用,而不需要修改代码逻辑 + * + * @author Lion Li + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@ConditionalOnProperty(value = "warm-flow.enabled", havingValue = "true") +public @interface ConditionalOnEnable { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java new file mode 100644 index 000000000..512a1348f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java @@ -0,0 +1,111 @@ +package org.dromara.workflow.common.constant; + + +/** + * 工作流常量 + * + * @author may + */ +public interface FlowConstant { + + /** + * 流程发起人 + */ + String INITIATOR = "initiator"; + + /** + * 业务id + */ + String BUSINESS_ID = "businessId"; + + /** + * 部门id + */ + String INITIATOR_DEPT_ID = "initiatorDeptId"; + + /** + * 流程分类 ID 转名称的翻译标识。 + */ + String CATEGORY_ID_TO_NAME = "category_id_to_name"; + + /** + * 流程分类名称缓存键。 + */ + String FLOW_CATEGORY_NAME = "flow_category_name#30d"; + + /** + * 默认租户 OA 申请分类 ID。 + */ + Long FLOW_CATEGORY_ID = 100L; + + /** + * 申请人提交动作标识。 + */ + String SUBMIT = "submit"; + + /** + * 抄送列表流程变量名。 + */ + String FLOW_COPY_LIST = "flowCopyList"; + + /** + * 消息类型流程变量名。 + */ + String MESSAGE_TYPE = "messageType"; + + /** + * 消息通知内容流程变量名。 + */ + String MESSAGE_NOTICE = "messageNotice"; + + /** + * 我的发起页面路径。 + */ + String PATH_MY_DOCUMENT = "/task/myDocument"; + + /** + * 我的待办页面路径。 + */ + String PATH_TASK_WAITING = "/task/taskWaiting"; + + /** + * 我的已办页面路径。 + */ + String PATH_TASK_FINISH = "/task/taskFinish"; + + /** + * 我的抄送页面路径。 + */ + String PATH_TASK_COPY = "/task/taskCopyList"; + + /** + * 任务状态字典类型编码。 + */ + String WF_TASK_STATUS = "wf_task_status"; + + /** + * 自动通过变量标识。 + */ + String AUTO_PASS = "autoPass"; + + /** + * 业务编码流程变量名。 + */ + String BUSINESS_CODE = "businessCode"; + + /** + * 忽略-办理权限校验(true:忽略,false:不忽略) + */ + String VAR_IGNORE = "ignore"; + + /** + * 忽略-委派处理(true:忽略,false:不忽略) + */ + String VAR_IGNORE_DEPUTE = "ignoreDepute"; + + /** + * 忽略-会签票签处理(true:忽略,false:不忽略) + */ + String VAR_IGNORE_COOPERATE = "ignoreCooperate"; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java new file mode 100644 index 000000000..32e668bc2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java @@ -0,0 +1,76 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 按钮权限枚举 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum ButtonPermissionEnum implements NodeExtEnum { + + /** + * 是否弹窗选人 + */ + POP("是否弹窗选人", "pop", false), + + /** + * 是否能委托 + */ + TRUST("是否能委托", "trust", false), + + /** + * 是否能转办 + */ + TRANSFER("是否能转办", "transfer", false), + + /** + * 是否能抄送 + */ + COPY("是否能抄送", "copy", true), + + /** + * 是否显示退回 + */ + BACK("是否显示退回", "back", true), + + /** + * 是否能加签 + */ + ADD_SIGN("是否能加签", "addSign", false), + + /** + * 是否能减签 + */ + SUB_SIGN("是否能减签", "subSign", false), + + /** + * 是否能终止 + */ + TERMINATION("是否能终止", "termination", true), + + /** + * 是否能上传附件 + */ + FILE("是否能上传附件", "file", true); + + /** + * 按钮展示名称。 + */ + private final String label; + + /** + * 按钮权限值。 + */ + private final String value; + + /** + * 是否默认开启。 + */ + private final boolean selected; + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/CopySettingEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/CopySettingEnum.java new file mode 100644 index 000000000..5512eb9ec --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/CopySettingEnum.java @@ -0,0 +1,32 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 抄送设置枚举 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum CopySettingEnum implements NodeExtEnum { + ; + + /** + * 展示名称。 + */ + private final String label; + + /** + * 配置值。 + */ + private final String value; + + /** + * 是否默认选中。 + */ + private final boolean selected; + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java new file mode 100644 index 000000000..8848f876b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java @@ -0,0 +1,61 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 消息类型枚举,定义流程通知支持的消息通道。 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum MessageTypeEnum { + + /** + * 站内信 + */ + SYSTEM_MESSAGE("1", "站内信"), + + /** + * 邮箱 + */ + EMAIL_MESSAGE("2", "邮箱"), + + /** + * 短信 + */ + SMS_MESSAGE("3", "短信"); + + /** + * 消息类型编码。 + */ + private final String code; + + /** + * 消息类型描述。 + */ + private final String desc; + + /** + * 消息类型编码缓存。 + */ + private static final Map MESSAGE_TYPE_ENUM_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(MessageTypeEnum::getCode, Function.identity())); + + /** + * 根据消息类型编码获取枚举实例。 + * + * @param code 消息类型code + * @return MessageTypeEnum + */ + public static MessageTypeEnum getByCode(String code) { + return MESSAGE_TYPE_ENUM_MAP.getOrDefault(code, null); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/NodeExtEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/NodeExtEnum.java new file mode 100644 index 000000000..3501f1dfa --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/NodeExtEnum.java @@ -0,0 +1,32 @@ +package org.dromara.workflow.common.enums; + +/** + * 节点扩展属性枚举通用接口,约束扩展选项的展示名、值和默认勾选状态。 + * + * @author AprilWind + */ +public interface NodeExtEnum { + + /** + * 获取选项展示名称。 + * + * @return 选项label + */ + String getLabel(); + + /** + * 获取选项值。 + * + * @return 选项值 + */ + String getValue(); + + /** + * 是否默认选中。 + * + * @return 是否默认选中 + */ + boolean isSelected(); + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java new file mode 100644 index 000000000..8e68fdbcf --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java @@ -0,0 +1,141 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 任务分配人枚举 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum TaskAssigneeEnum { + + /** + * 用户 + */ + USER("用户", ""), + + /** + * 角色 + */ + ROLE("角色", "role:"), + + /** + * 部门 + */ + DEPT("部门", "dept:"), + + /** + * 岗位 + */ + POST("岗位", "post:"), + + /** + * SPEL表达式 + */ + SPEL("SpEL表达式", ""); + + /** + * 类型描述。 + */ + private final String desc; + + /** + * 类型编码前缀。 + */ + private final String code; + + /** + * 根据描述获取对应的枚举类型 + *

+ * 通过传入描述,查找并返回匹配的枚举项。如果未找到匹配项,会抛出 {@link ServiceException}。 + *

+ * + * @param desc 描述,用于匹配对应的枚举项 + * @return TaskAssigneeEnum 返回对应的枚举类型 + * @throws ServiceException 如果未找到匹配的枚举项 + */ + public static TaskAssigneeEnum fromDesc(String desc) { + for (TaskAssigneeEnum type : values()) { + if (type.getDesc().equals(desc)) { + return type; + } + } + throw new ServiceException("未知的办理人类型: " + desc); + } + + /** + * 根据代码获取对应的枚举类型 + *

+ * 通过传入代码,查找并返回匹配的枚举项。如果未找到匹配项,会抛出 {@link ServiceException}。 + *

+ * + * @param code 代码,用于匹配对应的枚举项 + * @return TaskAssigneeEnum 返回对应的枚举类型 + * @throws IllegalArgumentException 如果未找到匹配的枚举项 + */ + public static TaskAssigneeEnum fromCode(String code) { + for (TaskAssigneeEnum type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + throw new ServiceException("未知的办理人类型代码: " + code); + } + + /** + * 获取所有办理人类型的描述列表,通常用于前端展示选择项。 + * + * @return List 返回所有办理人类型的描述列表 + */ + public static List getAssigneeTypeList() { + return Arrays.stream(values()) + .map(TaskAssigneeEnum::getDesc) + .collect(Collectors.toList()); + } + + /** + * 获取所有办理人类型的代码列表,通常用于程序内部逻辑判断。 + * + * @return List 返回所有办理人类型的代码列表 + */ + public static List getAssigneeCodeList() { + return Arrays.stream(values()) + .map(TaskAssigneeEnum::getCode) + .collect(Collectors.toList()); + } + + /** + * 判断当前办理人类型是否需要调用部门服务。 + * + * @return 如果类型是 USER、DEPT 或 POST,则返回 true;否则返回 false + */ + public boolean needsDeptService() { + return this == USER || this == DEPT || this == POST; + } + + /** + * 判断给定字符串是否符合 SPEL 表达式格式(以 $ 或 # 开头) + * + * @param value 待判断字符串 + * @return 是否为 SPEL 表达式 + */ + public static boolean isSpelExpression(String value) { + if (value == null) { + return false; + } + // $前缀表示默认办理人变量策略 + // #前缀表示spel办理人变量策略 + return StringUtils.startsWith(value, "$") || StringUtils.startsWith(value, "#"); + } + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java new file mode 100644 index 000000000..eed1b91fb --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 人员类型 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum TaskAssigneeType { + + /** + * 待办任务的审批人权限 + *

该权限表示用户是待办任务的审批人,负责审核任务的执行情况。

+ */ + APPROVER("1", "待办任务的审批人权限"), + + /** + * 待办任务的转办人权限 + *

该权限表示用户是待办任务的转办人,负责将任务分配给其他人员。

+ */ + TRANSFER("2", "待办任务的转办人权限"), + + /** + * 待办任务的委托人权限 + *

该权限表示用户是待办任务的委托人,能够委托其他人代为处理任务。

+ */ + DELEGATE("3", "待办任务的委托人权限"), + + /** + * 待办任务的抄送人权限 + *

该权限表示用户是待办任务的抄送人,仅接收任务信息的通知,不参与任务的审批或处理。

+ */ + COPY("4", "待办任务的抄送人权限"); + + /** + * 类型 + */ + private final String code; + + /** + * 描述 + */ + private final String description; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java new file mode 100644 index 000000000..a3f1afbf5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java @@ -0,0 +1,66 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 任务操作类型枚举,定义流程任务支持的运行时操作。 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum TaskOperationEnum { + + /** + * 委派 + */ + DELEGATE_TASK("delegateTask", "委派"), + + /** + * 转办 + */ + TRANSFER_TASK("transferTask", "转办"), + + /** + * 加签 + */ + ADD_SIGNATURE("addSignature", "加签"), + + /** + * 减签 + */ + REDUCTION_SIGNATURE("reductionSignature", "减签"); + + /** + * 操作编码,供接口与前端交互使用。 + */ + private final String code; + + /** + * 操作描述。 + */ + private final String desc; + + /** + * 操作编码缓存。 + */ + private static final Map CODE_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(TaskOperationEnum::getCode, Function.identity())); + + /** + * 根据 code 获取枚举实例。 + * + * @param code 操作编码 + * @return 对应的枚举实例 + */ + public static TaskOperationEnum getByCode(String code) { + return CODE_MAP.get(code); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java new file mode 100644 index 000000000..19807dd96 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java @@ -0,0 +1,115 @@ +package org.dromara.workflow.common.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 任务状态枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum TaskStatusEnum { + + /** + * 撤销 + */ + CANCEL("cancel", "撤销"), + + /** + * 通过 + */ + PASS("pass", "通过"), + + /** + * 待审核 + */ + WAITING("waiting", "待审核"), + + /** + * 作废 + */ + INVALID("invalid", "作废"), + + /** + * 退回 + */ + BACK("back", "退回"), + + /** + * 终止 + */ + TERMINATION("termination", "终止"), + + /** + * 转办 + */ + TRANSFER("transfer", "转办"), + + /** + * 委托 + */ + DEPUTE("depute", "委托"), + + /** + * 抄送 + */ + COPY("copy", "抄送"), + + /** + * 加签 + */ + SIGN("sign", "加签"), + + /** + * 减签 + */ + SIGN_OFF("sign_off", "减签"), + + /** + * 超时 + */ + TIMEOUT("timeout", "超时"); + + /** + * 状态编码与描述缓存。 + */ + private static final Map STATUS_DESC_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(TaskStatusEnum::getStatus, TaskStatusEnum::getDesc)); + /** + * 状态 + */ + private final String status; + /** + * 状态描述。 + */ + private final String desc; + + /** + * 根据状态编码获取任务业务状态描述。 + * + * @param status 状态 + * @return 状态描述 + */ + public static String findByStatus(String status) { + // 从缓存中直接获取描述 + return STATUS_DESC_MAP.getOrDefault(status, StrUtil.EMPTY); + } + + /** + * 判断状态是否为通过或退回 + * + * @param status 状态值 + * @return true 表示是通过或退回状态 + */ + public static boolean isPassOrBack(String status) { + return PASS.getStatus().equals(status) || BACK.getStatus().equals(status); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/VariablesEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/VariablesEnum.java new file mode 100644 index 000000000..cadc15287 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/VariablesEnum.java @@ -0,0 +1,32 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 节点扩展变量枚举,占位用于后续补充可配置变量定义。 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum VariablesEnum implements NodeExtEnum { + ; + + /** + * 展示名称。 + */ + private final String label; + + /** + * 变量值。 + */ + private final String value; + + /** + * 是否选中。 + */ + private final boolean selected; + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java new file mode 100644 index 000000000..46dc97124 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java @@ -0,0 +1,16 @@ +package org.dromara.workflow.config; + +import org.dromara.workflow.common.ConditionalOnEnable; +import org.springframework.context.annotation.Configuration; + +/** + * WarmFlow 工作流配置入口,在工作流开关开启时注册相关组件。 + * + * @author may + */ +@ConditionalOnEnable +@Configuration +public class WarmFlowConfig { + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java new file mode 100644 index 000000000..c37be9372 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java @@ -0,0 +1,149 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 流程分类 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/category") +public class FlwCategoryController extends BaseController { + + private final IFlwCategoryService flwCategoryService; + + /** + * 查询流程分类列表。 + * + * @param bo 查询条件 + * @return 流程分类列表 + */ + @SaCheckPermission("workflow:category:list") + @GetMapping("/list") + public R> list(FlowCategoryBo bo) { + List list = flwCategoryService.queryList(bo); + return R.ok(list); + } + + /** + * 导出流程分类列表。 + * + * @param bo 查询条件 + * @param response 响应流 + */ + @SaCheckPermission("workflow:category:export") + @Log(title = "流程分类", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FlowCategoryBo bo, HttpServletResponse response) { + List list = flwCategoryService.queryList(bo); + ExcelBuilder.of(list, FlowCategoryVo.class).sheetName("流程分类").toResponse(response); + } + + /** + * 获取单个流程分类详情。 + * + * @param categoryId 主键 + * @return 流程分类详情 + */ + @SaCheckPermission("workflow:category:query") + @GetMapping("/{categoryId}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long categoryId) { + return R.ok(flwCategoryService.queryById(categoryId)); + } + + /** + * 新增流程分类,并校验分类名称唯一性。 + * + * @param category 分类信息 + * @return 操作结果 + */ + @SaCheckPermission("workflow:category:add") + @Log(title = "流程分类", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FlowCategoryBo category) { + if (!flwCategoryService.checkCategoryNameUnique(category)) { + return R.fail("新增流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在"); + } + return toAjax(flwCategoryService.insertByBo(category)); + } + + /** + * 修改流程分类,并校验名称唯一及父子关系合法性。 + * + * @param category 分类信息 + * @return 操作结果 + */ + @SaCheckPermission("workflow:category:edit") + @Log(title = "流程分类", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo category) { + Long categoryId = category.getCategoryId(); + if (!flwCategoryService.checkCategoryNameUnique(category)) { + return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在"); + } else if (category.getParentId().equals(categoryId)) { + return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,上级流程分类不能是自己"); + } + return toAjax(flwCategoryService.updateByBo(category)); + } + + /** + * 删除流程分类,删除前校验默认分类、子节点和绑定流程定义。 + * + * @param categoryId 主键 + * @return 操作结果 + */ + @SaCheckPermission("workflow:category:remove") + @Log(title = "流程分类", businessType = BusinessType.DELETE) + @DeleteMapping("/{categoryId}") + public R remove(@PathVariable Long categoryId) { + if (FlowConstant.FLOW_CATEGORY_ID.equals(categoryId)) { + return R.warn("默认流程分类,不允许删除"); + } + if (flwCategoryService.hasChildByCategoryId(categoryId)) { + return R.warn("存在下级流程分类,不允许删除"); + } + if (flwCategoryService.checkCategoryExistDefinition(categoryId)) { + return R.warn("流程分类存在流程定义,不允许删除"); + } + return toAjax(flwCategoryService.deleteWithValidById(categoryId)); + } + + /** + * 获取流程分类树列表,用于流程定义选择分类节点。 + * + * @param categoryBo 流程分类 + * @return 流程分类树 + */ + @GetMapping("/categoryTree") + public R>> categoryTree(FlowCategoryBo categoryBo) { + return R.ok(flwCategoryService.selectCategoryTreeList(categoryBo)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java new file mode 100644 index 000000000..cf41a1ad0 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java @@ -0,0 +1,223 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * 流程定义管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/definition") +public class FlwDefinitionController extends BaseController { + + private final DefService defService; + private final IFlwDefinitionService flwDefinitionService; + + /** + * 分页查询流程定义列表。 + * + * @param flowDefinition 查询条件 + * @param pageQuery 分页参数 + * @return 流程定义分页数据 + */ + @GetMapping("/list") + @SaCheckPermission("workflow:definition:list") + public R> list(FlowDefinition flowDefinition, PageQuery pageQuery) { + return R.ok(flwDefinitionService.queryList(flowDefinition, pageQuery)); + } + + /** + * 分页查询未发布的流程定义列表。 + * + * @param flowDefinition 查询条件 + * @param pageQuery 分页参数 + * @return 未发布流程定义分页数据 + */ + @GetMapping("/unPublishList") + @SaCheckPermission("workflow:definition:list") + public R> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) { + return R.ok(flwDefinitionService.unPublishList(flowDefinition, pageQuery)); + } + + /** + * 获取流程定义详细信息。 + * + * @param id 流程定义id + * @return 流程定义详情 + */ + @GetMapping(value = "/{id}") + @SaCheckPermission("workflow:definition:query") + public R getInfo(@PathVariable Long id) { + return R.ok(defService.getById(id)); + } + + /** + * 新增流程定义并执行格式校验。 + * + * @param flowDefinition 流程定义信息 + * @return 操作结果 + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PostMapping + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + @SaCheckPermission("workflow:definition:add") + public R add(@RequestBody FlowDefinition flowDefinition) { + return R.ok(defService.checkAndSave(flowDefinition)); + } + + /** + * 修改流程定义。 + * + * @param flowDefinition 流程定义信息 + * @return 操作结果 + */ + @Log(title = "流程定义", businessType = BusinessType.UPDATE) + @PutMapping + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + @SaCheckPermission("workflow:definition:edit") + public R edit(@RequestBody FlowDefinition flowDefinition) { + return R.ok(defService.updateById(flowDefinition)); + } + + /** + * 发布流程定义,使其进入可用状态。 + * + * @param id 流程定义id + * @return 发布结果 + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PutMapping("/publish/{id}") + @RepeatSubmit() + @SaCheckPermission("workflow:definition:publish") + public R publish(@PathVariable Long id) { + return R.ok(flwDefinitionService.publish(id)); + } + + /** + * 取消发布流程定义。 + * + * @param id 流程定义id + * @return 操作结果 + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PutMapping("/unPublish/{id}") + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + @SaCheckPermission("workflow:definition:publish") + public R unPublish(@PathVariable Long id) { + return R.ok(defService.unPublish(id)); + } + + /** + * 批量删除流程定义。 + * + * @param ids 流程定义ID集合 + * @return 操作结果 + */ + @Log(title = "流程定义", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + @SaCheckPermission("workflow:definition:remove") + public R remove(@PathVariable List ids) { + return toAjax(flwDefinitionService.removeDef(ids)); + } + + /** + * 复制一份流程定义,便于快速创建相似流程。 + * + * @param id 流程定义id + * @return 复制结果 + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PostMapping("/copy/{id}") + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + @SaCheckPermission("workflow:definition:copy") + public R copy(@PathVariable Long id) { + return R.ok(defService.copyDef(id)); + } + + /** + * 通过文件导入流程定义。 + * + * @param file 文件 + * @param category 分类 + * @return 导入结果 + */ + @Log(title = "流程定义", businessType = BusinessType.IMPORT) + @PostMapping("/importDef") + @SaCheckPermission("workflow:definition:import") + public R importDef(MultipartFile file, String category) { + return R.ok(flwDefinitionService.importJson(file, category)); + } + + /** + * 导出流程定义文件。 + * + * @param id 流程定义id + * @param response 响应 + * @throws IOException 异常 + */ + @Log(title = "流程定义", businessType = BusinessType.EXPORT) + @PostMapping("/exportDef/{id}") + @SaCheckPermission("workflow:definition:export") + public void exportDef(@PathVariable Long id, HttpServletResponse response) throws IOException { + flwDefinitionService.exportDef(id, response); + } + + /** + * 获取流程定义 JSON 字符串。 + * + * @param id 流程定义id + * @return 流程定义 JSON + */ + @GetMapping("/xmlString/{id}") + @SaCheckPermission("workflow:definition:query") + public R xmlString(@PathVariable Long id) { + return R.data(defService.exportJson(id)); + } + + /** + * 激活或挂起流程定义。 + * + * @param id 流程定义id + * @param active 激活/挂起 + * @return 处理结果 + */ + @RepeatSubmit() + @PutMapping("/active/{id}") + @Transactional(rollbackFor = Exception.class) + @Log(title = "流程定义", businessType = BusinessType.UPDATE) + @SaCheckPermission("workflow:definition:active") + public R active(@PathVariable Long id, @RequestParam boolean active) { + return R.ok(active ? defService.active(id) : defService.unActive(id)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java new file mode 100644 index 000000000..389597560 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java @@ -0,0 +1,214 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.bo.FlowVariableBo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; +import org.dromara.workflow.service.IFlwInstanceService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 流程实例管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/instance") +public class FlwInstanceController extends BaseController { + + private final InsService insService; + private final IFlwInstanceService flwInstanceService; + + /** + * 分页查询正在运行的流程实例。 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 正在运行的流程实例分页数据 + */ + @GetMapping("/pageByRunning") + @SaCheckPermission("workflow:instance:list") + public R> selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return R.ok(flwInstanceService.selectRunningInstanceList(flowInstanceBo, pageQuery)); + } + + /** + * 分页查询已结束的流程实例。 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 已结束的流程实例分页数据 + */ + @GetMapping("/pageByFinish") + @SaCheckPermission("workflow:instance:list") + public R> selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return R.ok(flwInstanceService.selectFinishInstanceList(flowInstanceBo, pageQuery)); + } + + /** + * 根据业务 id 查询流程实例详细信息。 + * + * @param businessId 业务id + * @return 流程实例详情 + */ + @GetMapping("/getInfo/{businessId}") + @SaCheckPermission("workflow:instance:query") + public R getInfo(@PathVariable Long businessId) { + return R.ok(flwInstanceService.queryByBusinessId(businessId)); + } + + /** + * 按业务 id 批量删除流程实例。 + * + * @param businessIds 业务id + * @return 操作结果 + */ + @DeleteMapping("/deleteByBusinessIds/{businessIds}") + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @SaCheckPermission("workflow:instance:remove") + public R deleteByBusinessIds(@PathVariable List businessIds) { + return toAjax(flwInstanceService.deleteByBusinessIds(StreamUtils.toList(businessIds, Convert::toStr))); + } + + /** + * 按实例 id 批量删除流程实例。 + * + * @param instanceIds 实例id + * @return 操作结果 + */ + @DeleteMapping("/deleteByInstanceIds/{instanceIds}") + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @SaCheckPermission("workflow:instance:remove") + public R deleteByInstanceIds(@PathVariable List instanceIds) { + return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds)); + } + + /** + * 按实例 id 批量删除已完成的流程实例。 + * + * @param instanceIds 实例id + * @return 操作结果 + */ + @DeleteMapping("/deleteHisByInstanceIds/{instanceIds}") + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @SaCheckPermission("workflow:instance:remove") + public R deleteHisByInstanceIds(@PathVariable List instanceIds) { + return toAjax(flwInstanceService.deleteHisByInstanceIds(instanceIds)); + } + + /** + * 撤销当前申请人发起的流程。 + * + * @param bo 参数 + * @return 操作结果 + */ + @RepeatSubmit() + @PutMapping("/cancelProcessApply") + @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) + @SaCheckPermission("workflow:instance:cancel") + public R cancelProcessApply(@RequestBody FlowCancelBo bo) { + return toAjax(flwInstanceService.cancelProcessApply(bo)); + } + + /** + * 激活或挂起流程实例。 + * + * @param id 流程实例id + * @param active 激活/挂起 + * @return 处理结果 + */ + @RepeatSubmit() + @PutMapping("/active/{id}") + @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) + @SaCheckPermission("workflow:instance:active") + public R active(@PathVariable Long id, @RequestParam boolean active) { + return R.ok(active ? insService.active(id) : insService.unActive(id)); + } + + /** + * 获取当前登录人发起的流程实例列表。 + * + * @param flowInstanceBo 参数 + * @param pageQuery 分页 + * @return 当前用户发起的流程实例分页数据 + */ + @GetMapping("/pageByCurrent") + @SaCheckPermission("workflow:instance:currentList") + public R> selectCurrentInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return R.ok(flwInstanceService.selectCurrentInstanceList(flowInstanceBo, pageQuery)); + } + + /** + * 获取流程图和流程记录,用于展示实例流转轨迹。 + * + * @param businessId 业务id + * @return 流程图与历史节点信息 + */ + @GetMapping("/flowHisTaskList/{businessId}") + @SaCheckPermission("workflow:instance:query") + public R> flowHisTaskList(@PathVariable String businessId) { + return R.ok(flwInstanceService.flowHisTaskList(businessId)); + } + + /** + * 获取流程变量。 + * + * @param instanceId 流程实例id + * @return 流程变量 + */ + @GetMapping("/instanceVariable/{instanceId}") + @SaCheckPermission("workflow:instance:variableQuery") + public R> instanceVariable(@PathVariable Long instanceId) { + return R.ok(flwInstanceService.instanceVariable(instanceId)); + } + + /** + * 修改流程变量。 + * + * @param bo 参数 + * @return 操作结果 + */ + @RepeatSubmit() + @PutMapping("/updateVariable") + @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) + @SaCheckPermission("workflow:instance:variable") + public R updateVariable(@Validated @RequestBody FlowVariableBo bo) { + return toAjax(flwInstanceService.updateVariable(bo)); + } + + /** + * 作废流程实例。 + * + * @param bo 参数 + * @return 处理结果 + */ + @Log(title = "流程实例管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/invalid") + @SaCheckPermission("workflow:instance:invalid") + public R invalid(@Validated @RequestBody FlowInvalidBo bo) { + return R.ok(flwInstanceService.processInvalid(bo)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwSpelController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwSpelController.java new file mode 100644 index 000000000..54bfb8a27 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwSpelController.java @@ -0,0 +1,105 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.FlowSpelBo; +import org.dromara.workflow.domain.vo.FlowSpelVo; +import org.dromara.workflow.service.IFlwSpelService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 流程 SpEL 表达式定义控制器,负责表达式规则的增删改查。 + * + * @author Michelle.Chung + * @date 2025-07-04 + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/spel") +public class FlwSpelController extends BaseController { + + private final IFlwSpelService flwSpelService; + + /** + * 分页查询流程 SpEL 表达式定义列表。 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 表达式分页数据 + */ + @SaCheckPermission("workflow:spel:list") + @GetMapping("/list") + public R> list(FlowSpelBo bo, PageQuery pageQuery) { + return R.ok(flwSpelService.queryPageList(bo, pageQuery)); + } + + /** + * 获取流程 SpEL 表达式定义详情。 + * + * @param id 主键 + * @return 表达式详情 + */ + @SaCheckPermission("workflow:spel:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { + return R.ok(flwSpelService.queryById(id)); + } + + /** + * 新增流程 SpEL 表达式定义。 + * + * @param bo 表达式信息 + * @return 操作结果 + */ + @SaCheckPermission("workflow:spel:add") + @Log(title = "流程spel表达式定义", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FlowSpelBo bo) { + return toAjax(flwSpelService.insertByBo(bo)); + } + + /** + * 修改流程 SpEL 表达式定义。 + * + * @param bo 表达式信息 + * @return 操作结果 + */ + @SaCheckPermission("workflow:spel:edit") + @Log(title = "流程spel表达式定义", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FlowSpelBo bo) { + return toAjax(flwSpelService.updateByBo(bo)); + } + + /** + * 批量删除流程 SpEL 表达式定义。 + * + * @param ids 主键串 + * @return 操作结果 + */ + @SaCheckPermission("workflow:spel:remove") + @Log(title = "流程spel表达式定义", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { + return toAjax(flwSpelService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java new file mode 100644 index 000000000..d992f1e30 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java @@ -0,0 +1,242 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.workflow.api.domain.StartProcessReturnDTO; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 任务管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/task") +public class FlwTaskController extends BaseController { + + private final IFlwTaskService flwTaskService; + + /** + * 启动流程任务。 + * + * @param startProcessBo 启动流程参数 + * @return 启动结果及后续流程信息 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/startWorkFlow") + public R startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) { + StartProcessReturnDTO startProcessReturn = flwTaskService.startWorkFlow(startProcessBo); + return R.ok("提交成功", startProcessReturn); + } + + /** + * 办理当前任务节点。 + * + * @param completeTaskBo 办理任务参数 + * @return 操作结果 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/completeTask") + public R completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) { + return toAjax(flwTaskService.completeTask(completeTaskBo)); + } + + /** + * 查询当前用户的待办任务。 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 待办任务分页数据 + */ + @GetMapping("/pageByTaskWait") + public R> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return R.ok(flwTaskService.pageByTaskWait(flowTaskBo, pageQuery)); + } + + /** + * 查询当前用户的已办任务。 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 已办任务分页数据 + */ + @GetMapping("/pageByTaskFinish") + public R> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return R.ok(flwTaskService.pageByTaskFinish(flowTaskBo, pageQuery)); + } + + /** + * 查询全部待办任务。 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 待办任务分页数据 + */ + @SaCheckPermission("workflow:task:list") + @GetMapping("/pageByAllTaskWait") + public R> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return R.ok(flwTaskService.pageByAllTaskWait(flowTaskBo, pageQuery)); + } + + /** + * 查询全部已办任务。 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 已办任务分页数据 + */ + @SaCheckPermission("workflow:task:list") + @GetMapping("/pageByAllTaskFinish") + public R> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return R.ok(flwTaskService.pageByAllTaskFinish(flowTaskBo, pageQuery)); + } + + /** + * 查询当前用户收到的抄送任务。 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 抄送任务分页数据 + */ + @GetMapping("/pageByTaskCopy") + public R> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return R.ok(flwTaskService.pageByTaskCopy(flowTaskBo, pageQuery)); + } + + /** + * 根据任务 id 查询任务详情。 + * + * @param taskId 任务id + * @return 任务详情 + */ + @GetMapping("/getTask/{taskId}") + public R getTask(@PathVariable Long taskId) { + return R.ok(flwTaskService.selectById(taskId)); + } + + /** + * 获取流程下一节点信息。 + * + * @param bo 参数 + * @return 下一节点列表 + */ + @PostMapping("/getNextNodeList") + public R> getNextNodeList(@RequestBody FlowNextNodeBo bo) { + return R.ok(flwTaskService.getNextNodeList(bo)); + } + + /** + * 终止流程任务。 + * + * @param bo 参数 + * @return 处理结果 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/terminationTask") + public R terminationTask(@RequestBody FlowTerminationBo bo) { + return R.ok(flwTaskService.terminationTask(bo)); + } + + /** + * 执行任务操作,例如委派、转办、加签或减签。 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + * @return 操作结果 + */ + @Log(title = "任务管理", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PostMapping("/taskOperation/{taskOperation}") + public R taskOperation(@Validated @RequestBody TaskOperationBo bo, @PathVariable String taskOperation) { + return toAjax(flwTaskService.taskOperation(bo, taskOperation)); + } + + /** + * 批量修改任务办理人。 + * + * @param taskIdList 任务id + * @param userId 办理人id + * @return 操作结果 + */ + @Log(title = "任务管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @SaCheckPermission("workflow:task:edit") + @PutMapping("/updateAssignee/{userId}") + public R updateAssignee(@RequestBody List taskIdList, @PathVariable String userId) { + return toAjax(flwTaskService.updateAssignee(taskIdList, userId)); + } + + /** + * 驳回审批到前置节点。 + * + * @param bo 参数 + * @return 操作结果 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/backProcess") + public R backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo bo) { + return toAjax(flwTaskService.backProcess(bo)); + } + + /** + * 获取当前任务可驳回的前置节点。 + * + * @param taskId 任务id + * @param nowNodeCode 当前节点 + * @return 可驳回节点列表 + */ + @GetMapping("/getBackTaskNode/{taskId}/{nowNodeCode}") + public R> getBackTaskNode(@PathVariable Long taskId, @PathVariable String nowNodeCode) { + return R.ok(flwTaskService.getBackTaskNode(taskId, nowNodeCode)); + } + + /** + * 获取当前任务的所有办理人。 + * + * @param taskId 任务id + * @return 办理人列表 + */ + @GetMapping("/currentTaskAllUser/{taskId}") + public R> currentTaskAllUser(@PathVariable Long taskId) { + return R.ok(flwTaskService.currentTaskAllUser(List.of(taskId))); + } + + /** + * 催办任务。 + * + * @param bo 参数 + * @return 结果 + */ + @PostMapping("/urgeTask") + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @SaCheckPermission("workflow:task:edit") + public R urgeTask(@RequestBody FlowUrgeTaskBo bo) { + return toAjax(flwTaskService.urgeTask(bo)); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java new file mode 100644 index 000000000..24159fcad --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java @@ -0,0 +1,137 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelBuilder; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.redis.annotation.RepeatSubmit; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; +import org.dromara.workflow.service.ITestLeaveService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 请假示例控制器,演示业务单据与流程引擎联动的典型用法。 + * + * @author may + * @date 2023-07-21 + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/leave") +public class TestLeaveController extends BaseController { + + private final ITestLeaveService testLeaveService; + + /** + * 分页查询请假列表。 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 请假分页数据 + */ + @SaCheckPermission("workflow:leave:list") + @GetMapping("/list") + public R> list(TestLeaveBo bo, PageQuery pageQuery) { + return R.ok(testLeaveService.queryPageList(bo, pageQuery)); + } + + /** + * 导出请假列表。 + * + * @param bo 查询条件 + * @param response 响应流 + */ + @SaCheckPermission("workflow:leave:export") + @Log(title = "请假", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TestLeaveBo bo, HttpServletResponse response) { + List list = testLeaveService.queryList(bo); + ExcelBuilder.of(list, TestLeaveVo.class).sheetName("请假").toResponse(response); + } + + /** + * 获取请假单详情。 + * + * @param id 主键 + * @return 请假详情 + */ + @SaCheckPermission("workflow:leave:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(testLeaveService.queryById(id)); + } + + /** + * 新增请假单。 + * + * @param bo 请假信息 + * @return 新增后的请假单 + */ + @SaCheckPermission("workflow:leave:add") + @Log(title = "请假", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.insertByBo(bo)); + } + + /** + * 提交请假单并同步发起流程。 + * + * @param bo 请假信息 + * @return 提交后的请假单 + */ + @SaCheckPermission("workflow:leave:add") + @Log(title = "请假", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/submitAndFlowStart") + public R submitAndFlowStart(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.submitAndFlowStart(bo)); + } + + /** + * 修改请假单。 + * + * @param bo 请假信息 + * @return 修改后的请假单 + */ + @SaCheckPermission("workflow:leave:edit") + @Log(title = "请假", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.updateByBo(bo)); + } + + /** + * 批量删除请假单。 + * + * @param ids 主键串 + * @return 操作结果 + */ + @SaCheckPermission("workflow:leave:remove") + @Log(title = "请假", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(testLeaveService.deleteWithValidByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java new file mode 100644 index 000000000..5247efee9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java @@ -0,0 +1,67 @@ +package org.dromara.workflow.domain; + +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.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.ArrayList; +import java.util.List; + +/** + * 流程分类对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("flow_category") +public class FlowCategory extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程分类ID + */ + @TableId(value = "category_id") + private Long categoryId; + + /** + * 父流程分类id + */ + private Long parentId; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 流程分类名称 + */ + private String categoryName; + + /** + * 显示顺序 + */ + private Long orderNum; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 子菜单 + */ + @TableField(exist = false) + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowInstanceBizExt.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowInstanceBizExt.java new file mode 100644 index 000000000..fc62210c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowInstanceBizExt.java @@ -0,0 +1,59 @@ +package org.dromara.workflow.domain; + +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.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 流程实例业务扩展对象 flow_instance_biz_ext + * + * @author may + * @date 2025-08-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("flow_instance_biz_ext") +public class FlowInstanceBizExt extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 流程实例ID + */ + private Long instanceId; + + /** + * 业务ID + */ + private String businessId; + + /** + * 业务编码 + */ + private String businessCode; + + /** + * 业务标题 + */ + private String businessTitle; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowSpel.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowSpel.java new file mode 100644 index 000000000..89a7ae9fb --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowSpel.java @@ -0,0 +1,69 @@ +package org.dromara.workflow.domain; + +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.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 流程spel表达式定义对象 flow_spel + * + * @author Michelle.Chung + * @date 2025-07-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("flow_spel") +public class FlowSpel extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 组件名称 + */ + private String componentName; + + /** + * 方法名 + */ + private String methodName; + + /** + * 参数 + */ + private String methodParams; + + /** + * 预览spel表达式 + */ + private String viewSpel; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 删除标志 + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java new file mode 100644 index 000000000..8c45642b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java @@ -0,0 +1,68 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.time.LocalDateTime; + +/** + * 请假对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_leave") +public class TestLeave extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 申请编号 + */ + private String applyCode; + + /** + * 请假类型 + */ + private String leaveType; + + /** + * 开始时间 + */ + private LocalDateTime startDate; + + /** + * 结束时间 + */ + private LocalDateTime endDate; + + /** + * 请假天数 + */ + private Integer leaveDays; + + /** + * 请假原因 + */ + private String remark; + + /** + * 状态 + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java new file mode 100644 index 000000000..a9674b0b3 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + + +/** + * 驳回参数请求 + * + * @author may + */ +@Data +public class BackProcessBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + @NotNull(message = "任务ID不能为空", groups = AddGroup.class) + private Long taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 驳回的节点id(目前未使用,直接驳回到申请人) + */ + private String nodeCode; + + /** + * 办理意见 + */ + private String message; + + /** + * 通知 + */ + private String notice; + + /** + * 流程变量 + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + variables = new HashMap<>(16); + return variables; + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java new file mode 100644 index 000000000..e24629352 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java @@ -0,0 +1,85 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 办理任务请求对象 + * + * @author may + */ +@Data +public class CompleteTaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotNull(message = "任务id不能为空", groups = {AddGroup.class}) + private Long taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 抄送人员 + */ + private List flowCopyList; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 办理意见 + */ + private String message; + + /** + * 消息通知 + */ + private String notice; + + /** + * 办理人(可不填 用于覆盖当前节点办理人) + */ + private String handler; + + /** + * 流程变量 + */ + private Map variables; + + /** + * 弹窗选择的办理人 + */ + private Map assigneeMap; + + /** + * 扩展变量(此处为逗号分隔的ossId) + */ + private String ext; + + public Map getVariables() { + if (variables == null) { + variables = new HashMap<>(16); + return variables; + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java new file mode 100644 index 000000000..24241fe91 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java @@ -0,0 +1,18 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import org.dromara.common.core.validate.AddGroup; + +/** + * 撤销流程请求对象。 + * + * @param businessId 业务 ID + * @param message 撤销说明 + * @author may + */ +public record FlowCancelBo( + @NotBlank(message = "业务ID不能为空", groups = AddGroup.class) + String businessId, + String message +) { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java new file mode 100644 index 000000000..a86b835bf --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java @@ -0,0 +1,50 @@ +package org.dromara.workflow.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.workflow.domain.FlowCategory; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程分类业务对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@AutoMapper(target = FlowCategory.class, reverseConvertGenerate = false) +public class FlowCategoryBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程分类ID + */ + @NotNull(message = "流程分类ID不能为空", groups = {EditGroup.class}) + private Long categoryId; + + /** + * 父流程分类id + */ + @NotNull(message = "父流程分类id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long parentId; + + /** + * 流程分类名称 + */ + @NotBlank(message = "流程分类名称不能为空", groups = {AddGroup.class, EditGroup.class}) + private String categoryName; + + /** + * 显示顺序 + */ + private Long orderNum; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java new file mode 100644 index 000000000..e3267f8ab --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java @@ -0,0 +1,30 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 流程抄送请求对象。 + * + * @author may + */ +@Data +public class FlowCopyBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户昵称 + */ + private String nickName; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java new file mode 100644 index 000000000..b997631a7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java @@ -0,0 +1,55 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 流程实例查询条件对象。 + * + * @author may + */ +@Data +public class FlowInstanceBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 任务发起人 + */ + private String startUserId; + + /** + * 业务id + */ + private String businessId; + + /** + * 流程分类id + */ + private String category; + + /** + * 任务名称 + */ + private String nodeName; + + /** + * 申请人Ids + */ + private List createByIds; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java new file mode 100644 index 000000000..c2d857267 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java @@ -0,0 +1,18 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.validate.AddGroup; + +/** + * 作废流程请求对象。 + * + * @param id 流程实例 ID + * @param comment 作废意见 + * @author may + */ +public record FlowInvalidBo( + @NotNull(message = "流程实例id为空", groups = AddGroup.class) + Long id, + String comment +) { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java new file mode 100644 index 000000000..4d2ac5557 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java @@ -0,0 +1,44 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 查询下一节点信息的请求对象。 + * + * @author may + */ +@Data +public class FlowNextNodeBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + /** + * 任务id + */ + private Long taskId; + + /** + * 流程变量 + */ + private Map variables; + + /** + * 获取流程变量并自动剔除空值。 + * + * @return 流程变量 + */ + public Map getVariables() { + if (variables == null) { + variables = new HashMap<>(16); + return variables; + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowSpelBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowSpelBo.java new file mode 100644 index 000000000..d51378c42 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowSpelBo.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.workflow.domain.FlowSpel; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 流程spel表达式定义业务对象 flow_spel + * + * @author Michelle.Chung + * @date 2025-07-04 + */ +@Data +@AutoMapper(target = FlowSpel.class, reverseConvertGenerate = false) +public class FlowSpelBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 组件名称 + */ + private String componentName; + + /** + * 方法名 + */ + private String methodName; + + /** + * 参数 + */ + private String methodParams; + + /** + * 预览spel值 + */ + @NotBlank(message = "预览spel值不能为空", groups = {AddGroup.class, EditGroup.class}) + private String viewSpel; + + /** + * 状态(0正常 1停用) + */ + @NotBlank(message = "状态(0正常 1停用)不能为空", groups = {AddGroup.class, EditGroup.class}) + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java new file mode 100644 index 000000000..75405647f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java @@ -0,0 +1,69 @@ +package org.dromara.workflow.domain.bo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 任务请求对象 + * + * @author may + */ +@Data +public class FlowTaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务名称 + */ + private String nodeName; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程实例id + */ + private Long instanceId; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 权限列表 + */ + private List permissionList; + + /** + * 申请人Ids + */ + private List createByIds; + + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java new file mode 100644 index 000000000..b6c3d0a20 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java @@ -0,0 +1,18 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.validate.AddGroup; + +/** + * 终止任务请求对象 + * + * @param taskId 任务 ID + * @param comment 终止意见 + * @author may + */ +public record FlowTerminationBo( + @NotNull(message = "任务id为空", groups = AddGroup.class) + Long taskId, + String comment +) { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowUrgeTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowUrgeTaskBo.java new file mode 100644 index 000000000..8e51b12e5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowUrgeTaskBo.java @@ -0,0 +1,38 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 流程变量参数 + * + * @author may + */ +@Data +public class FlowUrgeTaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotNull(message = "任务id为空", groups = AddGroup.class) + private List taskIdList; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 催办内容 + */ + @NotNull(message = "催办内容为空", groups = AddGroup.class) + private String message; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowVariableBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowVariableBo.java new file mode 100644 index 000000000..0e64851a8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowVariableBo.java @@ -0,0 +1,22 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.validate.AddGroup; + +/** + * 流程变量参数 + * + * @param instanceId 流程实例 ID + * @param key 变量键 + * @param value 变量值 + * @author may + */ +public record FlowVariableBo( + @NotNull(message = "流程实例id为空", groups = AddGroup.class) + Long instanceId, + @NotNull(message = "流程变量key为空", groups = AddGroup.class) + String key, + @NotNull(message = "流程变量value为空", groups = AddGroup.class) + String value +) { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java new file mode 100644 index 000000000..98f33a007 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java @@ -0,0 +1,69 @@ +package org.dromara.workflow.domain.bo; + + +import cn.hutool.core.util.ObjectUtil; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.workflow.domain.FlowInstanceBizExt; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 启动流程对象 + * + * @author may + */ +@Data +public class StartProcessBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 业务唯一值id + */ + @NotBlank(message = "业务ID不能为空", groups = {AddGroup.class}) + private String businessId; + + /** + * 流程定义编码 + */ + @NotBlank(message = "流程定义编码不能为空", groups = {AddGroup.class}) + private String flowCode; + + /** + * 办理人(可不填 用于覆盖当前节点办理人) + */ + private String handler; + + /** + * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} + */ + private Map variables; + + /** + * 流程业务扩展信息 + */ + private FlowInstanceBizExt bizExt; + + public Map getVariables() { + if (variables == null) { + variables = new HashMap<>(16); + return variables; + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } + + public FlowInstanceBizExt getBizExt() { + if (ObjectUtil.isNull(bizExt)) { + bizExt = new FlowInstanceBizExt(); + } + return bizExt; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java new file mode 100644 index 000000000..0846e73b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java @@ -0,0 +1,53 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 任务操作业务对象,用于描述任务委派、转办、加签等操作的必要参数 + * 包含了用户ID、任务ID、任务相关的消息、以及加签/减签的用户ID + * + * @author AprilWind + */ +@Data +public class TaskOperationBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 委派/转办人的用户ID(必填,准对委派/转办人操作) + */ + @NotNull(message = "委派/转办人id不能为空", groups = {AddGroup.class}) + private String userId; + + /** + * 加签/减签人的用户ID列表(必填,针对加签/减签操作) + */ + @NotNull(message = "加签/减签id不能为空", groups = {EditGroup.class}) + private List userIds; + + /** + * 任务ID(必填) + */ + @NotNull(message = "任务id不能为空") + private Long taskId; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 意见或备注信息(可选) + */ + private String message; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java new file mode 100644 index 000000000..84669b4c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java @@ -0,0 +1,100 @@ +package org.dromara.workflow.domain.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.workflow.domain.TestLeave; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 请假业务对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@AutoMapper(target = TestLeave.class, reverseConvertGenerate = false) +public class TestLeaveBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 流程code + */ + private String flowCode; + + /** + * 申请编号 + */ + private String applyCode; + + /** + * 请假类型 + */ + @NotBlank(message = "请假类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String leaveType; + + /** + * 开始时间 + */ + @NotNull(message = "开始时间不能为空", groups = {AddGroup.class, EditGroup.class}) + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDateTime startDate; + + /** + * 结束时间 + */ + @NotNull(message = "结束时间不能为空", groups = {AddGroup.class, EditGroup.class}) + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDateTime endDate; + + /** + * 请假天数 + */ + private Integer leaveDays; + + /** + * 开始时间 + */ + private Integer startLeaveDays; + + /** + * 结束时间 + */ + private Integer endLeaveDays; + + /** + * 请假原因 + */ + private String remark; + + /** + * 状态 + */ + private String status; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/CompleteTaskContext.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/CompleteTaskContext.java new file mode 100644 index 000000000..c6f56a003 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/CompleteTaskContext.java @@ -0,0 +1,44 @@ +package org.dromara.workflow.domain.context; + +import lombok.Data; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.domain.bo.CompleteTaskBo; + +/** + * 办理任务 LiteFlow 上下文。 + *

+ * 链路内各节点通过该对象传递任务、实例、办理参数等中间结果,避免组件之间重复查询。 + * + * @author may + */ +@Data +public class CompleteTaskContext { + + /** + * 办理任务入参。 + */ + private final CompleteTaskBo completeTaskBo; + + /** + * 当前待办理的运行任务,由校验节点加载。 + */ + private FlowTask flowTask; + + /** + * 当前任务所属流程实例,由校验节点加载。 + */ + private Instance instance; + + /** + * Warm-Flow 办理参数,由参数构建节点生成并供执行、自动审批节点复用。 + */ + private FlowParams flowParams; + + /** + * 流程实例是否开启自动审批,由参数构建节点从实例变量中解析。 + */ + private Boolean autoPass; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/InstanceDeleteContext.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/InstanceDeleteContext.java new file mode 100644 index 000000000..86a7a530c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/InstanceDeleteContext.java @@ -0,0 +1,59 @@ +package org.dromara.workflow.domain.context; + +import lombok.Data; +import org.dromara.warm.flow.orm.entity.FlowInstance; + +import java.util.Collection; +import java.util.List; + +/** + * 删除流程实例 LiteFlow 上下文。 + * + * @author may + */ +@Data +public class InstanceDeleteContext { + + /** + * 按业务 id 删除时的业务 id 集合。 + */ + private final List businessIds; + + /** + * 按实例 id 删除时的实例 id 集合。 + */ + private final Collection instanceIds; + + /** + * 是否删除历史实例及其历史任务数据。 + */ + private final boolean history; + + /** + * 待删除流程实例。 + */ + private List flowInstances; + + /** + * 实际执行删除的实例 id。 + */ + private List deleteInstanceIds; + + /** + * 删除结果。 + */ + private boolean result; + + public static InstanceDeleteContext byBusinessIds(List businessIds) { + return new InstanceDeleteContext(businessIds, null, false); + } + + public static InstanceDeleteContext byInstanceIds(Collection instanceIds) { + return new InstanceDeleteContext(null, instanceIds, false); + } + + public static InstanceDeleteContext byHistoryInstanceIds(Collection instanceIds) { + return new InstanceDeleteContext(null, instanceIds, true); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/StartProcessContext.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/StartProcessContext.java new file mode 100644 index 000000000..9a8ae610e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/StartProcessContext.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.domain.context; + +import lombok.Data; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.api.domain.StartProcessReturnDTO; +import org.dromara.workflow.domain.FlowInstanceBizExt; +import org.dromara.workflow.domain.bo.StartProcessBo; + +import java.util.List; +import java.util.Map; + +/** + * 启动流程 LiteFlow 上下文。 + *

+ * 链路内保存启动参数、流程定义、流程实例和首个任务等中间结果。 + * + * @author may + */ +@Data +public class StartProcessContext { + + /** + * 启动流程入参。 + */ + private final StartProcessBo startProcessBo; + + /** + * 业务唯一标识。 + */ + private String businessId; + + /** + * 流程变量。 + */ + private Map variables; + + /** + * 流程实例业务扩展信息。 + */ + private FlowInstanceBizExt bizExt; + + /** + * 已存在的流程实例,非空时走续提交逻辑。 + */ + private FlowInstance existingInstance; + + /** + * 已发布的流程定义。 + */ + private Definition definition; + + /** + * 新启动的流程实例。 + */ + private Instance instance; + + /** + * 当前流程实例下生成的任务列表。 + */ + private List taskList; + + /** + * 启动流程返回结果。 + */ + private StartProcessReturnDTO startProcessReturn; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/TaskOperationContext.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/TaskOperationContext.java new file mode 100644 index 000000000..73fa2de4c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/context/TaskOperationContext.java @@ -0,0 +1,55 @@ +package org.dromara.workflow.domain.context; + +import lombok.Data; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.workflow.common.enums.TaskOperationEnum; +import org.dromara.workflow.domain.bo.TaskOperationBo; + +/** + * 任务操作 LiteFlow 上下文。 + *

+ * 用于在委派、转办、加签、减签链路中传递操作类型、任务、节点和办理参数。 + * + * @author may + */ +@Data +public class TaskOperationContext { + + /** + * 任务操作入参。 + */ + private final TaskOperationBo taskOperationBo; + + /** + * 操作类型编码。 + */ + private final String taskOperation; + + /** + * 解析后的操作枚举。 + */ + private TaskOperationEnum operation; + + /** + * Warm-Flow 操作参数。 + */ + private FlowParams flowParams; + + /** + * 当前任务。 + */ + private Task task; + + /** + * 当前任务对应的流程节点。 + */ + private FlowNode flowNode; + + /** + * 操作执行结果。 + */ + private boolean result; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ButtonPermissionVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ButtonPermissionVo.java new file mode 100644 index 000000000..37cee08da --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ButtonPermissionVo.java @@ -0,0 +1,52 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 按钮权限视图对象。 + * + * @author may + * @date 2025-02-28 + */ +@Data +public class ButtonPermissionVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 唯一编码 + */ + private String code; + + /** + * 选项值 + */ + private String value; + + /** + * 是否显示 + */ + private Boolean show; + + /** + * 无参构造方法。 + */ + public ButtonPermissionVo() { + } + + /** + * 使用按钮编码和显示状态构造按钮权限对象。 + * + * @param code 按钮编码 + * @param show 是否显示 + */ + public ButtonPermissionVo(String code, Boolean show) { + this.code = code; + this.show = show; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java new file mode 100644 index 000000000..8b85f9ce6 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java @@ -0,0 +1,69 @@ +package org.dromara.workflow.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.FlowCategory; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 流程分类视图对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FlowCategory.class) +public class FlowCategoryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程分类ID + */ + @ExcelProperty(value = "流程分类ID") + private Long categoryId; + + /** + * 父级分类id + */ + private Long parentId; + + /** + * 父级分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "parentId") + private String parentName; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 流程分类名称 + */ + @ExcelProperty(value = "流程分类名称") + private String categoryName; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "显示顺序") + private Long orderNum; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java new file mode 100644 index 000000000..db21858be --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java @@ -0,0 +1,41 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程抄送视图对象。 + * + * @author AprilWind + */ +@Data +public class FlowCopyVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户昵称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "userId") + private String nickName; + + /** + * 使用用户 ID 构造抄送对象。 + * + * @param userId 用户ID + */ + public FlowCopyVo(Long userId) { + this.userId = userId; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java new file mode 100644 index 000000000..ae28d722a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java @@ -0,0 +1,102 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 流程定义视图 + * + * @author may + */ +@Data +public class FlowDefinitionVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程定义主键 + */ + private Long id; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 流程版本 + */ + private String version; + + /** + * 是否发布(0未发布 1已发布 9失效) + */ + private Integer isPublish; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 流程激活状态(0挂起 1激活) + */ + private Integer activityStatus; + + /** + * 监听器类型 + */ + private String listenerType; + + /** + * 监听器路径 + */ + private String listenerPath; + + /** + * 扩展字段,预留给业务系统使用 + */ + private String ext; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java new file mode 100644 index 000000000..1733a701c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java @@ -0,0 +1,254 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.warm.flow.core.enums.CooperateType; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 历史任务视图 + * + * @author may + */ +@Data +public class FlowHisTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 历史任务主键 + */ + private Long id; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程实例表id + */ + private Long instanceId; + + /** + * 任务表id + */ + private Long taskId; + + /** + * 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签) + */ + private Integer cooperateType; + + /** + * 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签) + */ + private String cooperateTypeName; + + /** + * 业务id + */ + private String businessId; + + /** + * 开始节点编码 + */ + private String nodeCode; + + /** + * 开始节点名称 + */ + private String nodeName; + + /** + * 开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 目标节点编码 + */ + private String targetNodeCode; + + /** + * 结束节点名称 + */ + private String targetNodeName; + + /** + * 审批者 + */ + private String approver; + + /** + * 审批者 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "approver") + private String approverName; + + /** + * 协作人(只有转办、会签、票签、委派) + */ + private String collaborator; + + /** + * 权限标识 permissionFlag的list形式 + */ + private List permissionList; + + /** + * 跳转类型(PASS通过 REJECT退回 NONE无动作) + */ + private String skipType; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 任务状态 + */ + private String flowTaskStatus; + + /** + * 流程状态 + */ + private String flowStatusName; + + /** + * 审批意见 + */ + private String message; + + /** + * 业务详情 存业务类的json + */ + private String ext; + + /** + * 创建者 + */ + private String createBy; + + /** + * 申请人 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程版本号 + */ + private String version; + + /** + * 运行时长 + */ + private String runDuration; + + //业务扩展信息开始 + /** + * 业务编码 + */ + private String businessCode; + + /** + * 业务标题 + */ + private String businessTitle; + //业务扩展信息结束 + + /** + * 设置创建时间并计算任务运行时长 + * + * @param createTime 创建时间 + */ + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + updateRunDuration(); + } + + /** + * 设置更新时间并计算任务运行时长 + * + * @param updateTime 更新时间 + */ + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + updateRunDuration(); + } + + /** + * 更新运行时长 + */ + private void updateRunDuration() { + // 如果创建时间和更新时间均不为空,计算它们之间的时长 + if (this.updateTime != null && this.createTime != null) { + this.runDuration = DateUtils.formatBetweenBySecond(this.updateTime, this.createTime); + } + } + + /** + * 设置协作方式,并通过协作方式获取名称 + */ + public void setCooperateType(Integer cooperateType) { + this.cooperateType = cooperateType; + this.cooperateTypeName = CooperateType.getValueByKey(cooperateType); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java new file mode 100644 index 000000000..f0bd6d1e5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java @@ -0,0 +1,147 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.time.LocalDateTime; + +/** + * 流程实例视图对象。 + * + * @author may + */ +@Data +public class FlowInstanceVo { + + /** + * 流程实例ID。 + */ + private Long id; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 业务id + */ + private String businessId; + + /** + * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 流程节点编码 每个流程的nodeCode是唯一的,即definitionId+nodeCode唯一,在数据库层面做了控制 + */ + private String nodeCode; + + /** + * 流程节点名称 + */ + private String nodeName; + + /** + * 流程变量 + */ + private String variable; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 流程状态 + */ + private String flowStatusName; + + /** + * 流程激活状态(0挂起 1激活) + */ + private Integer activityStatus; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 扩展字段,预留给业务系统使用 + */ + private String ext; + + /** + * 流程定义版本 + */ + private String version; + + /** + * 创建者 + */ + private String createBy; + + /** + * 申请人 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + //业务扩展信息开始 + /** + * 业务编码 + */ + private String businessCode; + + /** + * 业务标题 + */ + private String businessTitle; + //业务扩展信息结束 + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowSpelVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowSpelVo.java new file mode 100644 index 000000000..63eedaf07 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowSpelVo.java @@ -0,0 +1,79 @@ +package org.dromara.workflow.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.workflow.domain.FlowSpel; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 流程spel表达式定义视图对象 flow_spel + * + * @author Michelle.Chung + * @date 2025-07-04 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FlowSpel.class) +public class FlowSpelVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 组件名称 + */ + @ExcelProperty(value = "组件名称") + private String componentName; + + /** + * 方法名 + */ + @ExcelProperty(value = "方法名") + private String methodName; + + /** + * 参数 + */ + @ExcelProperty(value = "参数") + private String methodParams; + + /** + * 预览spel值 + */ + @ExcelProperty(value = "预览spel值") + private String viewSpel; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java new file mode 100644 index 000000000..c4aefbf56 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java @@ -0,0 +1,212 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.warm.flow.core.entity.User; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * 流程任务视图对象。 + * + * @author may + */ +@Data +public class FlowTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID。 + */ + private Long id; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程实例表id + */ + private Long instanceId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 业务id + */ + private String businessId; + + /** + * 节点编码 + */ + private String nodeCode; + + /** + * 节点名称 + */ + private String nodeName; + + /** + * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 权限标识 permissionFlag的list形式 + */ + private List permissionList; + + /** + * 流程用户列表 + */ + private List userList; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单 + */ + private String formPath; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程版本号 + */ + private String version; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 流程状态 + */ + @Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "flowStatus", other = "wf_business_status") + private String flowStatusName; + + /** + * 办理人类型 + */ + private String type; + + /** + * 办理人ids + */ + private String assigneeIds; + + /** + * 办理人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assigneeIds") + private String assigneeNames; + + /** + * 抄送人id + */ + private String processedBy; + + /** + * 抄送人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "processedBy") + private String processedByName; + + /** + * 流程签署比例值 大于0为票签,会签 + */ + private String nodeRatio; + + /** + * 申请人id + */ + private String createBy; + + /** + * 申请人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 是否为申请人节点 + */ + private Boolean applyNode; + + /** + * 按钮权限 + */ + private List buttonList; + + /** + * 抄送对象 ID 集合 + *

+ * 根据扩展属性中 CopySettingEnum 类型的数据生成,存储需要抄送的对象 ID + */ + private List copyList; + + /** + * 自定义参数 Map + *

+ * 根据扩展属性中 VariablesEnum 类型的数据生成,存储 key=value 格式的自定义参数 + */ + private Map varList; + + //业务扩展信息开始 + /** + * 业务编码 + */ + private String businessCode; + + /** + * 业务标题 + */ + private String businessTitle; + //业务扩展信息结束 + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/NodeExtVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/NodeExtVo.java new file mode 100644 index 000000000..5fb3380b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/NodeExtVo.java @@ -0,0 +1,45 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Node 扩展属性解析结果 VO + *

+ * 用于封装从扩展属性 JSON 中解析出的各类信息,包括按钮权限、抄送对象和自定义参数。 + * + * @author AprilWind + */ +@Data +public class NodeExtVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 按钮权限列表 + *

+ * 根据扩展属性中 ButtonPermissionEnum 类型的数据生成,每个元素表示一个按钮及其是否勾选。 + */ + private List buttonPermissions; + + /** + * 抄送对象 ID 集合 + *

+ * 根据扩展属性中 CopySettingEnum 类型的数据生成,存储需要抄送的对象 ID + */ + private Set copySettings; + + /** + * 自定义参数 Map + *

+ * 根据扩展属性中 VariablesEnum 类型的数据生成,存储 key=value 格式的自定义参数 + */ + private Map variables; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java new file mode 100644 index 000000000..b66c25279 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java @@ -0,0 +1,76 @@ +package org.dromara.workflow.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.dromara.workflow.domain.TestLeave; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + + +/** + * 请假视图对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TestLeave.class) +public class TestLeaveVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 申请编号 + */ + @ExcelProperty(value = "申请编号") + private String applyCode; + + /** + * 请假类型 + */ + @ExcelProperty(value = "请假类型") + private String leaveType; + + /** + * 开始时间 + */ + @ExcelProperty(value = "开始时间") + private LocalDateTime startDate; + + /** + * 结束时间 + */ + @ExcelProperty(value = "结束时间") + private LocalDateTime endDate; + + /** + * 请假天数 + */ + @ExcelProperty(value = "请假天数") + private Integer leaveDays; + + /** + * 备注 + */ + @ExcelProperty(value = "请假原因") + private String remark; + + /** + * 状态 + */ + @ExcelProperty(value = "状态") + private String status; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowCopyEvent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowCopyEvent.java new file mode 100644 index 000000000..06336313e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowCopyEvent.java @@ -0,0 +1,23 @@ +package org.dromara.workflow.event; + +import cn.hutool.core.collection.CollUtil; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.workflow.domain.bo.FlowCopyBo; + +import java.util.List; + +/** + * 工作流抄送事件。 + * + * @param task 当前任务 + * @param flowCopyList 抄送人列表 + */ +public record WorkflowCopyEvent(Task task, List flowCopyList) { + + public WorkflowCopyEvent { + if (CollUtil.isNotEmpty(flowCopyList)) { + flowCopyList = List.copyOf(flowCopyList); + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowResultMessageEvent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowResultMessageEvent.java new file mode 100644 index 000000000..58a37db10 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowResultMessageEvent.java @@ -0,0 +1,23 @@ +package org.dromara.workflow.event; + +import cn.hutool.core.collection.CollUtil; + +import java.util.List; + +/** + * 工作流结果消息事件。 + * + * @param flowName 流程名称 + * @param status 流程状态 + * @param createBy 发起人用户 ID + * @param messageType 消息类型 + */ +public record WorkflowResultMessageEvent(String flowName, String status, String createBy, List messageType) { + + public WorkflowResultMessageEvent { + if (CollUtil.isNotEmpty(messageType)) { + messageType = List.copyOf(messageType); + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowTaskMessageEvent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowTaskMessageEvent.java new file mode 100644 index 000000000..68c221a1b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/event/WorkflowTaskMessageEvent.java @@ -0,0 +1,23 @@ +package org.dromara.workflow.event; + +import cn.hutool.core.collection.CollUtil; + +import java.util.List; + +/** + * 工作流待办消息事件。 + * + * @param flowName 流程名称 + * @param instanceId 流程实例 ID + * @param messageType 消息类型 + * @param notice 通知内容 + */ +public record WorkflowTaskMessageEvent(String flowName, Long instanceId, List messageType, String notice) { + + public WorkflowTaskMessageEvent { + if (CollUtil.isNotEmpty(messageType)) { + messageType = List.copyOf(messageType); + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowExceptionHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowExceptionHandler.java new file mode 100644 index 000000000..837298704 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowExceptionHandler.java @@ -0,0 +1,33 @@ +package org.dromara.workflow.handler; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.dromara.warm.flow.core.exception.FlowException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * 工作流失败异常 + * + * @author Lion Li + */ +@Slf4j +@RestControllerAdvice +public class FlowExceptionHandler { + + /** + * 工作流失败异常。 + * + * @param e 异常信息 + * @param request 当前请求 + * @return 统一失败响应 + */ + @ExceptionHandler(FlowException.class) + public R handleFlowException(FlowException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}'", requestURI, e); + return R.fail(e.getMessage()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java new file mode 100644 index 000000000..d61d685cf --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java @@ -0,0 +1,89 @@ +package org.dromara.workflow.handler; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.workflow.api.event.ProcessDeleteEvent; +import org.dromara.workflow.api.event.ProcessEvent; +import org.dromara.workflow.api.event.ProcessTaskEvent; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 流程监听服务 + * + * @author may + * @date 2024-06-02 + */ +@ConditionalOnEnable +@Slf4j +@Component +public class FlowProcessEventHandler { + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等) + * + * @param flowCode 流程定义编码 + * @param instance 实例数据 + * @param status 流程状态 + * @param params 办理参数 + * @param submit 当为true时为申请人节点办理 + */ + public void processHandler(String flowCode, Instance instance, String status, Map params, boolean submit) { + log.info("【流程事件发布】流程编码: {}, 业务ID: {}, 流程状态: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 是否申请人节点: {}, 参数: {}", + flowCode, instance.getBusinessId(), status, instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), submit, params); + ProcessEvent processEvent = new ProcessEvent(); + processEvent.setFlowCode(flowCode); + processEvent.setInstanceId(instance.getId()); + processEvent.setBusinessId(instance.getBusinessId()); + processEvent.setNodeType(instance.getNodeType()); + processEvent.setNodeCode(instance.getNodeCode()); + processEvent.setNodeName(instance.getNodeName()); + processEvent.setStatus(status); + processEvent.setParams(params); + processEvent.setSubmit(submit); + SpringUtils.context().publishEvent(processEvent); + } + + /** + * 执行创建任务监听 + * + * @param flowCode 流程定义编码 + * @param instance 实例数据 + * @param nextTask 任务 + * @param params 上一个任务的办理参数 + */ + public void processTaskHandler(String flowCode, Instance instance, Task nextTask, Map params) { + log.info("【流程任务事件发布】流程编码: {}, 业务ID: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 任务ID: {}", + flowCode, instance.getBusinessId(), nextTask.getNodeType(), nextTask.getNodeCode(), nextTask.getNodeName(), nextTask.getId()); + ProcessTaskEvent processTaskEvent = new ProcessTaskEvent(); + processTaskEvent.setFlowCode(flowCode); + processTaskEvent.setInstanceId(instance.getId()); + processTaskEvent.setBusinessId(instance.getBusinessId()); + processTaskEvent.setNodeType(nextTask.getNodeType()); + processTaskEvent.setNodeCode(nextTask.getNodeCode()); + processTaskEvent.setNodeName(nextTask.getNodeName()); + processTaskEvent.setTaskId(nextTask.getId()); + processTaskEvent.setStatus(instance.getFlowStatus()); + processTaskEvent.setParams(params); + SpringUtils.context().publishEvent(processTaskEvent); + } + + /** + * 删除流程监听 + * + * @param flowCode 流程定义编码 + * @param businessId 业务ID + */ + public void processDeleteHandler(String flowCode, String businessId) { + log.info("【流程删除事件发布】流程编码: {}, 业务ID: {}", flowCode, businessId); + ProcessDeleteEvent processDeleteEvent = new ProcessDeleteEvent(); + processDeleteEvent.setFlowCode(flowCode); + processDeleteEvent.setBusinessId(businessId); + SpringUtils.context().publishEvent(processDeleteEvent); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java new file mode 100644 index 000000000..bebd4740c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.handler.PermissionHandler; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +/** + * 办理人权限处理器 + * + * @author AprilWind + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Component +@Slf4j +public class WorkflowPermissionHandler implements PermissionHandler { + + private final IFlwTaskAssigneeService flwTaskAssigneeService; + + /** + * 办理人权限标识,比如用户,角色,部门等,用于校验是否有权限办理任务 + * 后续在{@link FlowParams#getPermissionFlag} 中获取 + * 返回当前用户权限集合 + * + * @return 当前用户权限集合 + */ + @Override + public List permissions() { + return Collections.singletonList(LoginHelper.getUserIdStr()); + } + + /** + * 获取当前办理人 + * + * @return 当前办理人 + */ + @Override + public String getHandler() { + return LoginHelper.getUserIdStr(); + } + + /** + * 将预设办理人转换为实际用户 ID 列表。 + * + * @param permissions 预设权限标识列表 + * @return 用户 ID 列表 + */ + @Override + public List convertPermissions(List permissions) { + if (CollUtil.isEmpty(permissions)) { + return permissions; + } + String storageIds = CollUtil.join(permissions, StringUtils.SEPARATOR); + List users = flwTaskAssigneeService.fetchUsersByStorageIds(storageIds); + return StreamUtils.toList(users, userDTO -> Convert.toStr(userDTO.getUserId())); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java new file mode 100644 index 000000000..bd081bf7d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java @@ -0,0 +1,328 @@ +package org.dromara.workflow.listener; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.TypeReference; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.api.UserService; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.listener.GlobalListener; +import org.dromara.warm.flow.core.listener.ListenerVariable; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.FlowCopyBo; +import org.dromara.workflow.domain.vo.NodeExtVo; +import org.dromara.workflow.event.WorkflowCopyEvent; +import org.dromara.workflow.event.WorkflowResultMessageEvent; +import org.dromara.workflow.event.WorkflowTaskMessageEvent; +import org.dromara.workflow.handler.FlowProcessEventHandler; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwNodeExtService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 工作流全局监听器,处理任务流转中的扩展变量、消息和事件发布。 + * + * @author may + */ +@ConditionalOnEnable +@Component +@Slf4j +@RequiredArgsConstructor +public class WorkflowGlobalListener implements GlobalListener { + + private final IFlwTaskService flwTaskService; + private final IFlwInstanceService flwInstanceService; + private final FlowProcessEventHandler flowProcessEventHandler; + private final IFlwCommonService flwCommonService; + private final IFlwNodeExtService nodeExtService; + private final UserService userService; + + /** + * 任务创建回调,当前预留扩展。 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void create(ListenerVariable listenerVariable) { + + } + + /** + * 任务开始办理时解析节点扩展配置。 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void start(ListenerVariable listenerVariable) { + String ext = listenerVariable.getNode().getExt(); + if (StringUtils.isNotBlank(ext)) { + Map variable = listenerVariable.getVariable(); + if (CollUtil.isEmpty(variable)) { + variable = new HashMap<>(); + } + NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable); + Set copyList = nodeExt.getCopySettings(); + if (CollUtil.isNotEmpty(copyList)) { + List userIds = StreamUtils.toList(copyList, Convert::toLong); + Map nickNameMap = userService.selectUserNicksByIds(userIds); + List list = StreamUtils.toList(copyList, x -> { + FlowCopyBo bo = new FlowCopyBo(); + Long id = Convert.toLong(x); + bo.setUserId(id); + bo.setNickName(nickNameMap.getOrDefault(id, StringUtils.EMPTY)); + return bo; + }); + variable.put(FlowConstant.FLOW_COPY_LIST, list); + } + if (CollUtil.isNotEmpty(nodeExt.getVariables())) { + variable.putAll(nodeExt.getVariables()); + } + } + } + + /** + * 任务分派时动态调整办理权限。 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void assignment(ListenerVariable listenerVariable) { + Map variable = listenerVariable.getVariable(); + List nextTasks = listenerVariable.getNextTasks(); + FlowParams flowParams = listenerVariable.getFlowParams(); + Definition definition = listenerVariable.getDefinition(); + Instance instance = listenerVariable.getInstance(); + String applyNodeCode = flwCommonService.applyNodeCode(definition.getId()); + String hisStatus = flowParams != null ? flowParams.getHisStatus() : null; + + for (Task flowTask : nextTasks) { + String nodeCode = flowTask.getNodeCode(); + + // 处理办理或退回时指定办理人的情况 + if (TaskStatusEnum.PASS.getStatus().equals(hisStatus)) { + processTaskPermission(variable, flowTask, hisStatus); + } else if (TaskStatusEnum.BACK.getStatus().equals(hisStatus)) { + processTaskPermission(variable, flowTask, hisStatus); + } + + // 如果是申请节点,则把启动人添加到办理人 + if (nodeCode.equals(applyNodeCode) && StringUtils.isNotBlank(instance.getCreateBy())) { + flowTask.setPermissionList(List.of(instance.getCreateBy())); + } + } + } + + /** + * 处理任务权限设置 + * + * @param variable 变量集合 + * @param flowTask 流程任务 + * @param taskStatus 任务状态 + */ + private void processTaskPermission(Map variable, Task flowTask, String taskStatus) { + String nodeKey = taskStatus + StringUtils.COLON + flowTask.getNodeCode(); + + // 检查是否存在状态相关的变量 + if (!variable.containsKey(nodeKey)) { + return; + } + + // 获取用户ID字符串 + Object userIdsObj = variable.get(nodeKey); + if (userIdsObj == null) { + return; + } + + String userIds = userIdsObj.toString(); + if (StringUtils.isBlank(userIds)) { + return; + } + + // 分割用户ID并设置权限列表 + List userIdList = StringUtils.str2List(userIds, StringUtils.SEPARATOR, true, true); + if (CollUtil.isNotEmpty(userIdList)) { + flowTask.setPermissionList(userIdList); + if (TaskStatusEnum.PASS.getStatus().equals(taskStatus)) { + // 办理指定人变量只消费一次;驳回指定人变量需要保留给后续重复驳回。 + variable.remove(nodeKey); + FlowEngine.insService().removeVariables(flowTask.getInstanceId(), nodeKey); + } + } + } + + /** + * 任务完成后发布流程事件并处理抄送和通知。 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void finish(ListenerVariable listenerVariable) { + Instance instance = listenerVariable.getInstance(); + Definition definition = listenerVariable.getDefinition(); + Task task = listenerVariable.getTask(); + List nextTasks = listenerVariable.getNextTasks(); + Map params = new HashMap<>(); + FlowParams flowParams = listenerVariable.getFlowParams(); + Map variable = new HashMap<>(); + if (ObjectUtil.isNotNull(flowParams)) { + // 历史任务扩展(通常为附件) + params.put("hisTaskExt", flowParams.getHisTaskExt()); + // 办理人 + params.put("handler", flowParams.getHandler()); + // 办理意见 + params.put("message", flowParams.getMessage()); + variable = flowParams.getVariable(); + } + //申请人提交事件 + Boolean submit = MapUtil.getBool(variable, FlowConstant.SUBMIT); + if (submit != null && submit) { + String status = determineFlowStatus(instance); + flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, variable, true); + } else { + // 判断流程状态(发布:撤销,退回,作废,终止,已完成事件) + String status = determineFlowStatus(instance); + if (StringUtils.isNotBlank(status)) { + flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, params, false); + notifyInitiatorIfNeeded(definition, instance, status, variable); + } + if (!BusinessStatusEnum.initialState(instance.getFlowStatus())) { + if (task != null && CollUtil.isNotEmpty(nextTasks) && nextTasks.size() == 1 + && flwCommonService.applyNodeCode(definition.getId()).equals(nextTasks.getFirst().getNodeCode())) { + // 如果为画线指定驳回 线条指定为驳回 驳回得节点为申请人节点 则修改流程状态为退回 + flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, BusinessStatusEnum.BACK.getStatus(), params, false); + notifyInitiatorIfNeeded(definition, instance, BusinessStatusEnum.BACK.getStatus(), variable); + // 修改流程实例状态 + instance.setFlowStatus(BusinessStatusEnum.BACK.getStatus()); + FlowEngine.insService().updateById(instance); + } + } + } + //发布任务事件 + if (CollUtil.isNotEmpty(nextTasks)) { + for (Task nextTask : nextTasks) { + flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, nextTask, params); + } + } + if (ObjectUtil.isNull(flowParams)) { + return; + } + // 只有办理或者退回的时候才执行消息通知和抄送 + if (!TaskStatusEnum.isPassOrBack(flowParams.getHisStatus())) { + return; + } + if (ObjectUtil.isNull(variable)) { + return; + } + + if (variable.containsKey(FlowConstant.FLOW_COPY_LIST)) { + List flowCopyList = MapUtil.get(variable, FlowConstant.FLOW_COPY_LIST, new TypeReference<>() { + }); + // 添加抄送人 + SpringUtils.context().publishEvent(new WorkflowCopyEvent(task, flowCopyList)); + } + if (variable.containsKey(FlowConstant.MESSAGE_TYPE)) { + List messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() { + }); + String notice = MapUtil.getStr(variable, FlowConstant.MESSAGE_NOTICE); + // 退回到申请人时只保留“已退回”结果消息,避免再追加一条“新的待办”形成重复提醒。 + if (shouldSendTaskMessage(flowParams, definition, nextTasks)) { + SpringUtils.context().publishEvent(new WorkflowTaskMessageEvent(definition.getFlowName(), instance.getId(), messageType, notice)); + } + } + FlowEngine.insService().removeVariables(instance.getId(), + FlowConstant.FLOW_COPY_LIST, + FlowConstant.MESSAGE_TYPE, + FlowConstant.MESSAGE_NOTICE, + FlowConstant.SUBMIT + ); + } + + /** + * 判断是否需要发送后续待办消息。 + * + * @param flowParams 流程参数 + * @param definition 流程定义 + * @param nextTasks 后续任务列表 + * @return 是否发送待办消息 + */ + private boolean shouldSendTaskMessage(FlowParams flowParams, Definition definition, List nextTasks) { + if (flowParams == null || !TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus())) { + return true; + } + if (CollUtil.isEmpty(nextTasks) || nextTasks.size() != 1) { + return true; + } + // 只有“退回到申请人”场景需要拦截待办提醒,其余退回/流转仍然保留待办消息。 + String applyNodeCode = flwCommonService.applyNodeCode(definition.getId()); + return !StringUtils.equals(applyNodeCode, nextTasks.getFirst().getNodeCode()); + } + + /** + * 在流程完成或退回时通知发起人。 + * + * @param definition 流程定义 + * @param instance 流程实例 + * @param status 业务状态 + * @param variable 流程变量 + */ + private void notifyInitiatorIfNeeded(Definition definition, Instance instance, String status, Map variable) { + if (!StringUtils.equalsAny(status, BusinessStatusEnum.FINISH.getStatus(), BusinessStatusEnum.BACK.getStatus())) { + return; + } + if (StringUtils.isBlank(instance.getCreateBy())) { + return; + } + // 已完成、已退回这类结果消息只发给发起人,不再混入处理人待办消息。 + List messageType = null; + if (MapUtil.isNotEmpty(variable) && variable.containsKey(FlowConstant.MESSAGE_TYPE)) { + messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() { + }); + } + SpringUtils.context().publishEvent(new WorkflowResultMessageEvent(definition.getFlowName(), status, instance.getCreateBy(), messageType)); + } + + /** + * 根据流程实例确定最终状态 + * + * @param instance 流程实例 + * @return 流程最终状态 + */ + private String determineFlowStatus(Instance instance) { + String flowStatus = instance.getFlowStatus(); + if (StringUtils.isNotBlank(flowStatus) && BusinessStatusEnum.initialState(flowStatus)) { + log.info("流程实例当前状态: {}", flowStatus); + return flowStatus; + } else { + Long instanceId = instance.getId(); + if (flwTaskService.isTaskEnd(instanceId)) { + String status = BusinessStatusEnum.FINISH.getStatus(); + // 更新流程状态为已完成 + flwInstanceService.updateStatus(instanceId, status); + log.info("流程已结束,状态更新为: {}", status); + return status; + } + return null; + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowSideEffectListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowSideEffectListener.java new file mode 100644 index 000000000..315646810 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowSideEffectListener.java @@ -0,0 +1,85 @@ +package org.dromara.workflow.listener; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.api.UserService; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.MessageTypeEnum; +import org.dromara.workflow.event.WorkflowCopyEvent; +import org.dromara.workflow.event.WorkflowResultMessageEvent; +import org.dromara.workflow.event.WorkflowTaskMessageEvent; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +/** + * 工作流副作用事件监听器。 + * + * @author may + */ +@ConditionalOnEnable +@Component +@RequiredArgsConstructor +public class WorkflowSideEffectListener { + + private final IFlwTaskService flwTaskService; + private final IFlwCommonService flwCommonService; + private final UserService userService; + + /** + * 保存工作流抄送记录。 + * + * @param event 工作流抄送事件 + */ + @EventListener + public void handleCopy(WorkflowCopyEvent event) { + flwTaskService.setCopy(event.task(), event.flowCopyList()); + } + + /** + * 发送工作流待办消息。 + * + * @param event 工作流待办消息事件 + */ + @EventListener + public void handleTaskMessage(WorkflowTaskMessageEvent event) { + flwCommonService.sendMessage(event.flowName(), event.instanceId(), event.messageType(), event.notice()); + } + + /** + * 发送工作流结果消息。 + * + * @param event 工作流结果消息事件 + */ + @EventListener + public void handleResultMessage(WorkflowResultMessageEvent event) { + if (!StringUtils.equalsAny(event.status(), BusinessStatusEnum.FINISH.getStatus(), BusinessStatusEnum.BACK.getStatus())) { + return; + } + Long createBy = Convert.toLong(event.createBy(), null); + if (createBy == null) { + return; + } + BusinessStatusEnum status = BusinessStatusEnum.getByStatus(event.status()); + if (status == null) { + return; + } + UserDTO initiator = userService.selectById(createBy); + if (initiator == null || initiator.getUserId() == null) { + return; + } + List messageType = CollUtil.isNotEmpty(event.messageType()) + ? event.messageType() + : Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode()); + flwCommonService.sendResultMessage(event.flowName(), status, messageType, Collections.singletonList(initiator)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteAutoPassComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteAutoPassComponent.java new file mode 100644 index 000000000..cb21570f0 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteAutoPassComponent.java @@ -0,0 +1,95 @@ +package org.dromara.workflow.liteflow.complete; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.User; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.context.CompleteTaskContext; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 执行当前处理人的后续自动审批。 + *

+ * 仅当流程实例开启自动审批时生效,用于连续跳过同一登录人负责的后续待办任务。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("completeAutoPass") +public class CompleteAutoPassComponent extends NodeComponent { + + private final TaskService taskService; + private final FlowTaskMapper flowTaskMapper; + + @Override + public void process() { + CompleteTaskContext context = getContextBean(CompleteTaskContext.class); + FlowTask flowTask = context.getFlowTask(); + autoPass(flowTask.getId(), context.getFlowParams(), flowTask.getInstanceId()); + } + + /** + * 递归跳过当前处理人的后续任务。 + * + * @param taskId 本轮已处理任务 id,用于避免重复跳过同一任务 + * @param flowParams 当前办理参数,会在自动审批时覆盖为自动审批消息和空抄送变量 + * @param instanceId 流程实例 id + */ + private void autoPass(Long taskId, FlowParams flowParams, Long instanceId) { + List flowTaskList = selectByInstId(instanceId); + if (CollUtil.isEmpty(flowTaskList)) { + return; + } + List userList = FlowEngine.userService() + .getByAssociateds(StreamUtils.toList(flowTaskList, FlowTask::getId)); + if (CollUtil.isEmpty(userList)) { + return; + } + for (FlowTask task : flowTaskList) { + if (task.getId().equals(taskId)) { + continue; + } + // 自动审批只处理当前登录人仍是办理人的后续任务,避免替其他候选人或并行分支误审批。 + List users = StreamUtils.filter(userList, + e -> ObjectUtil.equals(task.getId(), e.getAssociated()) && ObjectUtil.equal(e.getProcessedBy(), LoginHelper.getUserIdStr())); + if (CollUtil.isEmpty(users)) { + continue; + } + // 自动审批不继承人工办理时的抄送和消息通知,避免重复发送业务消息。 + flowParams + .message("流程引擎自动审批!") + .variable(Map.of( + SUBMIT, false, + FLOW_COPY_LIST, Collections.emptyList(), + MESSAGE_NOTICE, StringUtils.EMPTY)); + taskService.skip(task.getId(), flowParams); + // 跳过后可能生成新的后续任务,继续扫描直到当前登录人不再有可自动办理任务。 + autoPass(task.getId(), flowParams, instanceId); + } + } + + private List selectByInstId(Long instanceId) { + return flowTaskMapper.selectList(QueryBuilder.lambda(FlowTask.class) + .eq(FlowTask::getInstanceId, instanceId) + .build()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteExecuteComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteExecuteComponent.java new file mode 100644 index 000000000..a6cd00dd3 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteExecuteComponent.java @@ -0,0 +1,54 @@ +package org.dromara.workflow.liteflow.complete; + +import cn.hutool.core.convert.Convert; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.enums.SkipType; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.CompleteTaskBo; +import org.dromara.workflow.domain.context.CompleteTaskContext; + +import java.util.Map; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 构建办理参数并执行当前任务跳转。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("completeExecute") +public class CompleteExecuteComponent extends NodeComponent { + + private final TaskService taskService; + + @Override + public void process() { + CompleteTaskContext context = getContextBean(CompleteTaskContext.class); + CompleteTaskBo completeTaskBo = context.getCompleteTaskBo(); + Map variables = completeTaskBo.getVariables(); + FlowParams flowParams = FlowParams.build() + .handler(completeTaskBo.getHandler()) + .variable(variables) + .ignore(Convert.toBool(variables.getOrDefault(VAR_IGNORE, false))) + .ignoreDepute(Convert.toBool(variables.getOrDefault(VAR_IGNORE_DEPUTE, false))) + .ignoreCooperate(Convert.toBool(variables.getOrDefault(VAR_IGNORE_COOPERATE, false))) + .skipType(SkipType.PASS.getKey()) + .message(completeTaskBo.getMessage()) + .flowStatus(BusinessStatusEnum.WAITING.getStatus()) + .hisStatus(TaskStatusEnum.PASS.getStatus()) + .hisTaskExt(completeTaskBo.getFileId()); + + context.setFlowParams(flowParams); + context.setAutoPass(Convert.toBool(context.getInstance().getVariableMap().getOrDefault(AUTO_PASS, false))); + taskService.skip(context.getFlowTask().getId(), flowParams); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteNeedAutoPassComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteNeedAutoPassComponent.java new file mode 100644 index 000000000..d74646c7d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompleteNeedAutoPassComponent.java @@ -0,0 +1,23 @@ +package org.dromara.workflow.liteflow.complete; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBooleanComponent; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.context.CompleteTaskContext; + +/** + * 判断办理任务后是否进入自动审批分支。 + * + * @author may + */ +@ConditionalOnEnable +@LiteflowComponent("completeNeedAutoPass") +public class CompleteNeedAutoPassComponent extends NodeBooleanComponent { + + @Override + public boolean processBoolean() { + CompleteTaskContext context = getContextBean(CompleteTaskContext.class); + return Boolean.TRUE.equals(context.getAutoPass()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompletePrepareComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompletePrepareComponent.java new file mode 100644 index 000000000..ad3bb56e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/complete/CompletePrepareComponent.java @@ -0,0 +1,100 @@ +package org.dromara.workflow.liteflow.complete; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.CompleteTaskBo; +import org.dromara.workflow.domain.context.CompleteTaskContext; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 准备任务办理上下文。 + *

+ * 负责加载任务实例、补齐流程变量,并解析弹窗选择的后续办理人。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("completePrepare") +public class CompletePrepareComponent extends NodeComponent { + + private final FlowTaskMapper flowTaskMapper; + private final InsService insService; + + @Override + public void process() { + CompleteTaskContext context = getContextBean(CompleteTaskContext.class); + CompleteTaskBo completeTaskBo = context.getCompleteTaskBo(); + FlowTask flowTask = flowTaskMapper.selectById(completeTaskBo.getTaskId()); + if (ObjectUtil.isNull(flowTask)) { + throw new ServiceException("流程任务不存在或任务已审批!"); + } + Instance instance = insService.getById(flowTask.getInstanceId()); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException("流程实例不存在"); + } + context.setFlowTask(flowTask); + context.setInstance(instance); + + Map variables = completeTaskBo.getVariables(); + variables.put(FLOW_COPY_LIST, completeTaskBo.getFlowCopyList()); + variables.put(MESSAGE_TYPE, completeTaskBo.getMessageType()); + variables.put(MESSAGE_NOTICE, completeTaskBo.getNotice()); + if (BusinessStatusEnum.isDraftOrCancelOrBack(instance.getFlowStatus())) { + // 草稿、撤销、驳回状态再次办理时等同于重新提交,条件表达式通过 SUBMIT 识别提交分支。 + variables.put(SUBMIT, true); + } + Map assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), instance.getVariableMap()); + if (CollUtil.isNotEmpty(assigneeMap)) { + variables.putAll(assigneeMap); + } + } + + /** + * 将弹窗处理人映射成通过/退回状态下的办理人变量。 + */ + private Map setPopAssigneeMap(Map assigneeMap, Map variablesMap) { + Map map = new HashMap<>(); + if (CollUtil.isEmpty(assigneeMap)) { + return map; + } + for (Map.Entry entry : assigneeMap.entrySet()) { + if (variablesMap.containsKey(entry.getKey())) { + String userIds = variablesMap.get(entry.getKey()).toString(); + if (StringUtils.isNotBlank(userIds)) { + Set hashSet = CollUtil.newHashSet(); + List popUserIds = StringUtils.str2List(entry.getValue().toString(), StringUtils.SEPARATOR, true, true); + List variableUserIds = StringUtils.str2List(userIds, StringUtils.SEPARATOR, true, true); + hashSet.addAll(popUserIds); + hashSet.addAll(variableUserIds); + // Warm-Flow 会按“状态:变量名”读取办理人,正向和退回都写入同一批候选人。 + map.put(TaskStatusEnum.PASS.getStatus() + StringUtils.COLON + entry.getKey(), StringUtils.joinComma(hashSet)); + map.put(TaskStatusEnum.BACK.getStatus() + StringUtils.COLON + entry.getKey(), StringUtils.joinComma(hashSet)); + } + } else { + map.put(TaskStatusEnum.PASS.getStatus() + StringUtils.COLON + entry.getKey(), entry.getValue()); + map.put(TaskStatusEnum.BACK.getStatus() + StringUtils.COLON + entry.getKey(), entry.getValue()); + } + } + return map; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteEventComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteEventComponent.java new file mode 100644 index 000000000..8924b84ba --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteEventComponent.java @@ -0,0 +1,60 @@ +package org.dromara.workflow.liteflow.instance; + +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.context.InstanceDeleteContext; +import org.dromara.workflow.handler.FlowProcessEventHandler; + +import java.util.Map; +import java.util.function.Function; + +/** + * 校验实例删除权限并发布业务删除事件。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Slf4j +@LiteflowComponent("instanceDeleteEvent") +public class InstanceDeleteEventComponent extends NodeComponent { + + private final DefService defService; + private final FlowProcessEventHandler flowProcessEventHandler; + + @Override + public void process() { + InstanceDeleteContext context = getContextBean(InstanceDeleteContext.class); + String userId = LoginHelper.getUserIdStr(); + context.getFlowInstances().forEach(flowInstance -> { + if (!LoginHelper.isSuperAdmin() && !flowInstance.getCreateBy().equals(userId)) { + throw new ServiceException("权限不足,无法删除流程实例信息!"); + } + }); + + Map definitionMap = StreamUtils.toMap( + defService.getByIds(StreamUtils.toList(context.getFlowInstances(), Instance::getDefinitionId)), + Definition::getId, + Function.identity() + ); + context.getFlowInstances().forEach(instance -> { + Definition definition = definitionMap.get(instance.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId()); + return; + } + flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId()); + }); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteExecuteComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteExecuteComponent.java new file mode 100644 index 000000000..8e27a47e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteExecuteComponent.java @@ -0,0 +1,79 @@ +package org.dromara.workflow.liteflow.instance; + +import cn.hutool.core.collection.CollUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.context.InstanceDeleteContext; + +import java.util.List; +import java.util.Objects; + +/** + * 执行流程实例删除。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("instanceDeleteExecute") +public class InstanceDeleteExecuteComponent extends NodeComponent { + + private final InsService insService; + private final FlowHisTaskMapper flowHisTaskMapper; + private final FlowTaskMapper flowTaskMapper; + + @Override + public void process() { + InstanceDeleteContext context = getContextBean(InstanceDeleteContext.class); + deleteCopyUsers(context.getDeleteInstanceIds()); + if (!context.isHistory()) { + context.setResult(insService.remove(context.getDeleteInstanceIds())); + return; + } + List flowTaskList = flowTaskMapper.selectList(QueryBuilder.lambda(FlowTask.class) + .in(FlowTask::getInstanceId, context.getDeleteInstanceIds()) + .build()); + if (CollUtil.isNotEmpty(flowTaskList)) { + FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTaskList, FlowTask::getId)); + } + FlowEngine.taskService().deleteByInsIds(context.getDeleteInstanceIds()); + FlowEngine.hisTaskService().deleteByInsIds(context.getDeleteInstanceIds()); + FlowEngine.insService().removeByIds(context.getDeleteInstanceIds()); + context.setResult(true); + } + + /** + * 删除流程实例产生的抄送人员关联。 + * + * @param instanceIds 流程实例 ID 集合 + */ + private void deleteCopyUsers(List instanceIds) { + List copyTasks = flowHisTaskMapper.selectList(QueryBuilder.lambda(FlowHisTask.class) + .in(FlowHisTask::getInstanceId, instanceIds) + .eq(FlowHisTask::getFlowStatus, TaskStatusEnum.COPY.getStatus()) + .build()); + if (CollUtil.isEmpty(copyTasks)) { + return; + } + List copyTaskIds = copyTasks.stream() + .map(FlowHisTask::getTaskId) + .filter(Objects::nonNull) + .distinct() + .toList(); + if (CollUtil.isNotEmpty(copyTaskIds)) { + FlowEngine.userService().deleteByTaskIds(copyTaskIds); + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteExistsComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteExistsComponent.java new file mode 100644 index 000000000..5b49657ba --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteExistsComponent.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.liteflow.instance; + +import cn.hutool.core.collection.CollUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBooleanComponent; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.context.InstanceDeleteContext; + +/** + * 判断删除流程实例时是否存在可执行删除的数据。 + * + * @author may + */ +@ConditionalOnEnable +@LiteflowComponent("instanceDeleteExists") +public class InstanceDeleteExistsComponent extends NodeBooleanComponent { + + @Override + public boolean processBoolean() { + InstanceDeleteContext context = getContextBean(InstanceDeleteContext.class); + return CollUtil.isNotEmpty(context.getFlowInstances()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteLoadComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteLoadComponent.java new file mode 100644 index 000000000..376996b6d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/instance/InstanceDeleteLoadComponent.java @@ -0,0 +1,52 @@ +package org.dromara.workflow.liteflow.instance; + +import cn.hutool.core.collection.CollUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.context.InstanceDeleteContext; + +import java.util.ArrayList; +import java.util.List; + +/** + * 加载待删除流程实例。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Slf4j +@LiteflowComponent("instanceDeleteLoad") +public class InstanceDeleteLoadComponent extends NodeComponent { + + private final FlowInstanceMapper flowInstanceMapper; + + @Override + public void process() { + InstanceDeleteContext context = getContextBean(InstanceDeleteContext.class); + List flowInstances; + if (CollUtil.isNotEmpty(context.getBusinessIds())) { + flowInstances = flowInstanceMapper.selectList(QueryBuilder.lambda(FlowInstance.class) + .in(FlowInstance::getBusinessId, context.getBusinessIds()) + .build()); + context.setDeleteInstanceIds(StreamUtils.toList(flowInstances, FlowInstance::getId)); + } else { + flowInstances = flowInstanceMapper.selectByIds(context.getInstanceIds()); + context.setDeleteInstanceIds(new ArrayList<>(context.getInstanceIds())); + } + if (CollUtil.isEmpty(flowInstances)) { + log.warn("未找到对应的流程实例信息,无法执行删除操作。"); + context.setResult(false); + return; + } + context.setFlowInstances(flowInstances); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpExecuteComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpExecuteComponent.java new file mode 100644 index 000000000..dc2b77825 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpExecuteComponent.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.liteflow.operation; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.context.TaskOperationContext; + +/** + * 执行委派、转办、加签或减签。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("taskOpExecute") +public class TaskOpExecuteComponent extends NodeComponent { + + private final TaskService taskService; + + @Override + public void process() { + TaskOperationContext context = getContextBean(TaskOperationContext.class); + Long taskId = context.getTaskOperationBo().getTaskId(); + boolean result = false; + switch (context.getOperation()) { + case DELEGATE_TASK -> { + context.getFlowParams().hisStatus(TaskStatusEnum.DEPUTE.getStatus()); + result = taskService.depute(taskId, context.getFlowParams()); + } + case TRANSFER_TASK -> { + context.getFlowParams().hisStatus(TaskStatusEnum.TRANSFER.getStatus()); + result = taskService.transfer(taskId, context.getFlowParams()); + } + case ADD_SIGNATURE -> { + context.getFlowParams().hisStatus(TaskStatusEnum.SIGN.getStatus()); + result = taskService.addSignature(taskId, context.getFlowParams()); + } + case REDUCTION_SIGNATURE -> { + context.getFlowParams().hisStatus(TaskStatusEnum.SIGN_OFF.getStatus()); + result = taskService.reductionSignature(taskId, context.getFlowParams()); + } + } + context.setResult(result); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpLoadComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpLoadComponent.java new file mode 100644 index 000000000..226d771b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpLoadComponent.java @@ -0,0 +1,53 @@ +package org.dromara.workflow.liteflow.operation; + +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.enums.CooperateType; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskOperationEnum; +import org.dromara.workflow.domain.context.TaskOperationContext; + +/** + * 加载任务节点并校验操作约束。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("taskOpLoad") +public class TaskOpLoadComponent extends NodeComponent { + + private final TaskService taskService; + private final FlowNodeMapper flowNodeMapper; + + @Override + public void process() { + TaskOperationContext context = getContextBean(TaskOperationContext.class); + Task task = taskService.getById(context.getTaskOperationBo().getTaskId()); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } + FlowNode flowNode = flowNodeMapper.selectOne(QueryBuilder.lambda(FlowNode.class) + .eq(FlowNode::getNodeCode, task.getNodeCode()) + .eq(FlowNode::getDefinitionId, task.getDefinitionId()) + .build()); + if (ObjectUtil.isNull(flowNode)) { + throw new ServiceException("流程节点不存在"); + } + if ((context.getOperation() == TaskOperationEnum.ADD_SIGNATURE || context.getOperation() == TaskOperationEnum.REDUCTION_SIGNATURE) + && CooperateType.isOrSign(flowNode.getNodeRatio())) { + throw new ServiceException(task.getNodeName() + "不是会签或票签节点!"); + } + context.setTask(task); + context.setFlowNode(flowNode); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpNeedNotifyComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpNeedNotifyComponent.java new file mode 100644 index 000000000..b5c8c7d95 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpNeedNotifyComponent.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.liteflow.operation; + +import cn.hutool.core.collection.CollUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBooleanComponent; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.context.TaskOperationContext; + +/** + * 判断任务操作后是否进入消息通知分支。 + * + * @author may + */ +@ConditionalOnEnable +@LiteflowComponent("taskOpNeedNotify") +public class TaskOpNeedNotifyComponent extends NodeBooleanComponent { + + @Override + public boolean processBoolean() { + TaskOperationContext context = getContextBean(TaskOperationContext.class); + return context.isResult() && CollUtil.isNotEmpty(context.getTaskOperationBo().getMessageType()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpNotifyComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpNotifyComponent.java new file mode 100644 index 000000000..b58a2430d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpNotifyComponent.java @@ -0,0 +1,57 @@ +package org.dromara.workflow.liteflow.operation; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.api.UserService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.TaskOperationBo; +import org.dromara.workflow.domain.context.TaskOperationContext; +import org.dromara.workflow.service.IFlwCommonService; + +import java.util.ArrayList; +import java.util.List; + +import static org.dromara.workflow.common.constant.FlowConstant.PATH_TASK_WAITING; + +/** + * 任务操作成功后发送待办消息。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("taskOpNotify") +public class TaskOpNotifyComponent extends NodeComponent { + + private final IFlwCommonService flwCommonService; + private final UserService userService; + + @Override + public void process() { + TaskOperationContext context = getContextBean(TaskOperationContext.class); + TaskOperationBo bo = context.getTaskOperationBo(); + List userIdList = new ArrayList<>(); + if (StringUtils.isNotBlank(bo.getUserId())) { + userIdList.add(Convert.toLong(bo.getUserId())); + } + if (CollUtil.isNotEmpty(bo.getUserIds())) { + userIdList.addAll(bo.getUserIds().stream().map(Convert::toLong).toList()); + } + if (CollUtil.isEmpty(userIdList)) { + return; + } + // 转办、委托、加减签等运行时操作,消息接收人统一从“我的待办”进入处理。 + flwCommonService.sendMessage( + bo.getMessageType(), + StringUtils.isNotBlank(bo.getMessage()) ? bo.getMessage() : "单据「" + context.getOperation().getDesc() + "」通知", + "单据「" + context.getOperation().getDesc() + "」提醒", + userService.selectListByIds(userIdList), + PATH_TASK_WAITING + ); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpPrepareComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpPrepareComponent.java new file mode 100644 index 000000000..4cfc0d6a2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/operation/TaskOpPrepareComponent.java @@ -0,0 +1,57 @@ +package org.dromara.workflow.liteflow.operation; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskOperationEnum; +import org.dromara.workflow.domain.bo.TaskOperationBo; +import org.dromara.workflow.domain.context.TaskOperationContext; + +import java.util.Collections; + +/** + * 准备任务操作参数。 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@LiteflowComponent("taskOpPrepare") +public class TaskOpPrepareComponent extends NodeComponent { + + @Override + public void process() { + TaskOperationContext context = getContextBean(TaskOperationContext.class); + TaskOperationEnum op = TaskOperationEnum.getByCode(context.getTaskOperation()); + if (op == null) { + log.error("Invalid operation type:{} ", context.getTaskOperation()); + throw new ServiceException("Invalid operation type " + context.getTaskOperation()); + } + context.setOperation(op); + + TaskOperationBo bo = context.getTaskOperationBo(); + switch (op) { + case DELEGATE_TASK, TRANSFER_TASK -> ValidatorUtils.validate(bo, AddGroup.class); + case ADD_SIGNATURE, REDUCTION_SIGNATURE -> ValidatorUtils.validate(bo, EditGroup.class); + } + + FlowParams flowParams = FlowParams.build().message(bo.getMessage()); + if (LoginHelper.isSuperAdmin()) { + flowParams.ignore(true); + } + switch (op) { + case DELEGATE_TASK, TRANSFER_TASK -> flowParams.addHandlers(Collections.singletonList(bo.getUserId())); + case ADD_SIGNATURE -> flowParams.addHandlers(bo.getUserIds()); + case REDUCTION_SIGNATURE -> flowParams.reductionHandlers(bo.getUserIds()); + } + context.setFlowParams(flowParams); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartExecuteComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartExecuteComponent.java new file mode 100644 index 000000000..eacbcee8b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartExecuteComponent.java @@ -0,0 +1,67 @@ +package org.dromara.workflow.liteflow.start; + +import cn.hutool.core.collection.CollUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.api.domain.StartProcessReturnDTO; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.FlowInstanceBizExt; +import org.dromara.workflow.domain.context.StartProcessContext; +import org.dromara.workflow.mapper.FlwInstanceBizExtMapper; + +import java.util.List; + +/** + * 启动流程实例并构建返回结果。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("startExecute") +public class StartExecuteComponent extends NodeComponent { + + private final InsService insService; + private final TaskService taskService; + private final FlwInstanceBizExtMapper flwInstanceBizExtMapper; + + @Override + public void process() { + StartProcessContext context = getContextBean(StartProcessContext.class); + FlowParams flowParams = FlowParams.build() + .handler(context.getStartProcessBo().getHandler()) + .flowCode(context.getStartProcessBo().getFlowCode()) + .variable(context.getVariables()) + .flowStatus(BusinessStatusEnum.DRAFT.getStatus()); + Instance instance = insService.start(context.getBusinessId(), flowParams); + context.setInstance(instance); + saveBizExt(context, instance); + + List taskList = taskService.list(new FlowTask().setInstanceId(instance.getId())); + if (CollUtil.isEmpty(taskList)) { + throw new ServiceException("流程启动失败,未生成任务"); + } + if (taskList.size() > 1) { + throw new ServiceException("请检查流程第一个环节是否为申请人!"); + } + context.setTaskList(taskList); + context.setStartProcessReturn(new StartProcessReturnDTO(instance.getId(), taskList.getFirst().getId())); + } + + private void saveBizExt(StartProcessContext context, Instance instance) { + FlowInstanceBizExt bizExt = context.getBizExt(); + bizExt.setInstanceId(instance.getId()); + bizExt.setBusinessId(instance.getBusinessId()); + flwInstanceBizExtMapper.saveOrUpdateByInstanceId(bizExt); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartExistsComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartExistsComponent.java new file mode 100644 index 000000000..5986f3730 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartExistsComponent.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.liteflow.start; + +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBooleanComponent; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.context.StartProcessContext; + +/** + * 判断启动流程时是否走已有实例续提交分支。 + * + * @author may + */ +@ConditionalOnEnable +@LiteflowComponent("startExists") +public class StartExistsComponent extends NodeBooleanComponent { + + @Override + public boolean processBoolean() { + StartProcessContext context = getContextBean(StartProcessContext.class); + return ObjectUtil.isNotNull(context.getExistingInstance()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartPrepareInstanceComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartPrepareInstanceComponent.java new file mode 100644 index 000000000..fc3cfa753 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartPrepareInstanceComponent.java @@ -0,0 +1,55 @@ +package org.dromara.workflow.liteflow.start; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.FlowInstanceBizExt; +import org.dromara.workflow.domain.context.StartProcessContext; + +import java.util.Map; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 加载流程定义并补齐启动变量。 + * + * @author may + */ +@ConditionalOnEnable +@LiteflowComponent("startPrepareInstance") +public class StartPrepareInstanceComponent extends NodeComponent { + + @Override + public void process() { + StartProcessContext context = getContextBean(StartProcessContext.class); + Definition definition = FlowEngine.defService().getPublishByFlowCode(context.getStartProcessBo().getFlowCode()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException("流程【" + context.getStartProcessBo().getFlowCode() + "】未发布,请先在流程设计器中发布流程定义"); + } + context.setDefinition(definition); + + Map variables = context.getVariables(); + Dict dict = JsonUtils.parseMap(definition.getExt()); + boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(AUTO_PASS); + variables.put(AUTO_PASS, autoPass); + variables.put(BUSINESS_CODE, generateBusinessCode(context.getBizExt())); + } + + private String generateBusinessCode(FlowInstanceBizExt bizExt) { + if (ObjectUtil.isNull(bizExt.getBusinessCode()) || bizExt.getBusinessCode().isBlank()) { + // TODO: 按照自己业务规则生成编号 + String businessCode = Convert.toStr(System.currentTimeMillis()); + bizExt.setBusinessCode(businessCode); + return businessCode; + } + return bizExt.getBusinessCode(); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartPrepareRequestComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartPrepareRequestComponent.java new file mode 100644 index 000000000..a848c78a4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartPrepareRequestComponent.java @@ -0,0 +1,53 @@ +package org.dromara.workflow.liteflow.start; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.context.StartProcessContext; + +import java.util.Map; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 准备流程启动请求。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("startPrepareRequest") +public class StartPrepareRequestComponent extends NodeComponent { + + private final FlowInstanceMapper flowInstanceMapper; + + @Override + public void process() { + StartProcessContext context = getContextBean(StartProcessContext.class); + String businessId = context.getStartProcessBo().getBusinessId(); + if (StringUtils.isBlank(businessId)) { + throw new ServiceException("启动工作流时必须包含业务ID"); + } + context.setBusinessId(businessId); + context.setVariables(context.getStartProcessBo().getVariables()); + context.setBizExt(context.getStartProcessBo().getBizExt()); + + Map variables = context.getVariables(); + variables.put(INITIATOR, LoginHelper.getUserIdStr()); + variables.put(INITIATOR_DEPT_ID, LoginHelper.getDeptId()); + variables.put(BUSINESS_ID, businessId); + + FlowInstance flowInstance = flowInstanceMapper.selectOne(QueryBuilder.lambda(FlowInstance.class) + .eq(FlowInstance::getBusinessId, businessId) + .build()); + context.setExistingInstance(flowInstance); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartResumeComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartResumeComponent.java new file mode 100644 index 000000000..71b885042 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/liteflow/start/StartResumeComponent.java @@ -0,0 +1,56 @@ +package org.dromara.workflow.liteflow.start; + +import cn.hutool.core.collection.CollUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.api.domain.StartProcessReturnDTO; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.FlowInstanceBizExt; +import org.dromara.workflow.domain.context.StartProcessContext; +import org.dromara.workflow.mapper.FlwInstanceBizExtMapper; + +import java.util.List; + +/** + * 已存在流程实例时执行续提交。 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@LiteflowComponent("startResume") +public class StartResumeComponent extends NodeComponent { + + private final TaskService taskService; + private final InsService insService; + private final FlwInstanceBizExtMapper flwInstanceBizExtMapper; + + @Override + public void process() { + StartProcessContext context = getContextBean(StartProcessContext.class); + BusinessStatusEnum.checkStartStatus(context.getExistingInstance().getFlowStatus()); + List taskList = taskService.list(new FlowTask().setInstanceId(context.getExistingInstance().getId())); + if (CollUtil.isEmpty(taskList)) { + throw new ServiceException("流程实例缺少任务,请检查流程定义配置"); + } + taskService.mergeVariable(context.getExistingInstance(), context.getVariables()); + insService.updateById(context.getExistingInstance()); + saveBizExt(context); + context.setStartProcessReturn(new StartProcessReturnDTO(taskList.getFirst().getInstanceId(), taskList.getFirst().getId())); + } + + private void saveBizExt(StartProcessContext context) { + FlowInstanceBizExt bizExt = context.getBizExt(); + bizExt.setInstanceId(context.getExistingInstance().getId()); + bizExt.setBusinessId(context.getExistingInstance().getBusinessId()); + flwInstanceBizExtMapper.saveOrUpdateByInstanceId(bizExt); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java new file mode 100644 index 000000000..d618fafea --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java @@ -0,0 +1,46 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.vo.FlowCategoryVo; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 流程分类Mapper接口 + * + * @author may + * @date 2023-06-27 + */ +public interface FlwCategoryMapper extends BaseMapperPlus { + + /** + * 根据父流程分类ID查询其所有子流程分类的列表 + * + * @param parentId 父流程分类ID + * @return 包含子流程分类的列表 + */ + default List selectListByParentId(Long parentId) { + return this.lambda() + .select(FlowCategory::getCategoryId) + .findInSet(parentId, FlowCategory::getAncestors) + .list(); + } + + /** + * 根据父流程分类ID查询包括父ID及其所有子流程分类ID的列表 + * + * @param parentId 父流程分类ID + * @return 包含父ID和子流程分类ID的列表 + */ + default List selectCategoryIdsByParentId(Long parentId) { + return Stream.concat( + this.selectListByParentId(parentId).stream() + .map(FlowCategory::getCategoryId), + Stream.of(parentId) + ).collect(Collectors.toList()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwHisTaskMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwHisTaskMapper.java new file mode 100644 index 000000000..5cc2e8c9d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwHisTaskMapper.java @@ -0,0 +1,69 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.base.MPJBaseMapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.FlowInstanceBizExt; +import org.dromara.workflow.domain.bo.FlowTaskBo; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; + +import java.util.List; +import java.util.Map; + +/** + * 任务信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +public interface FlwHisTaskMapper extends BaseMapperPlus, MPJBaseMapper { + + /** + * 分页查询已办任务列表。 + * + * @param page 分页对象 + * @param bo 查询条件 + * @param categoryIds 流程分类 ID 集合 + * @param userId 当前用户 ID + * @return 已办任务分页结果 + */ + default Page getListFinishTask(Page page, FlowTaskBo bo, List categoryIds, String userId) { + Map params = bo.getParams(); + return QueryBuilder.lambdaJoin("a", FlowHisTask.class) + .select(FlowHisTask::getId, FlowHisTask::getNodeCode, FlowHisTask::getNodeName, + FlowHisTask::getCooperateType, FlowHisTask::getApprover, FlowHisTask::getCollaborator, + FlowHisTask::getNodeType, FlowHisTask::getTargetNodeCode, FlowHisTask::getTargetNodeName, + FlowHisTask::getDefinitionId, FlowHisTask::getInstanceId) + .selectAs(FlowHisTask::getFlowStatus, FlowHisTaskVo::getFlowTaskStatus) + .select(FlowHisTask::getMessage, FlowHisTask::getExt, FlowHisTask::getCreateTime, + FlowHisTask::getUpdateTime, FlowHisTask::getFormCustom, FlowHisTask::getFormPath) + .select("b", FlowInstance::getFlowStatus, FlowInstance::getBusinessId, FlowInstance::getCreateBy) + .select("c", FlowDefinition::getFlowName, FlowDefinition::getFlowCode, FlowDefinition::getCategory, + FlowDefinition::getVersion) + .select("biz", FlowInstanceBizExt::getBusinessCode, FlowInstanceBizExt::getBusinessTitle) + .leftJoin(FlowInstance.class, "b", FlowInstance::getId, FlowHisTask::getInstanceId) + .leftJoin(FlowDefinition.class, "c", FlowDefinition::getId, FlowHisTask::getDefinitionId) + .leftJoin(FlowInstanceBizExt.class, "biz", FlowInstanceBizExt::getInstanceId, FlowInstance::getId) + .in("a", FlowHisTask::getNodeType, List.of(1, 3, 4)) + .ne("a", FlowHisTask::getFlowStatus, TaskStatusEnum.COPY.getStatus()) + .likeIfText("a", FlowHisTask::getNodeName, bo.getNodeName()) + .likeIfText("c", FlowDefinition::getFlowName, bo.getFlowName()) + .likeIfText("c", FlowDefinition::getFlowCode, bo.getFlowCode()) + .likeIfText("b", FlowInstance::getFlowStatus, bo.getFlowStatus()) + .inIfNotEmpty("b", FlowInstance::getCreateBy, bo.getCreateByIds()) + .inIfNotEmpty("c", FlowDefinition::getCategory, categoryIds) + .betweenParams("a", FlowHisTask::getCreateTime, params, "beginTime", "endTime") + .eq(userId != null && !userId.isBlank(), "a", FlowHisTask::getNodeType, NodeType.BETWEEN.getKey()) + .eqIfText("a", FlowHisTask::getApprover, userId) + .orderByDesc("a", FlowHisTask::getCreateTime) + .orderByDesc("a", FlowHisTask::getUpdateTime) + .page(page, FlowHisTaskVo.class); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceBizExtMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceBizExtMapper.java new file mode 100644 index 000000000..a895f57e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceBizExtMapper.java @@ -0,0 +1,59 @@ +package org.dromara.workflow.mapper; + +import cn.hutool.core.util.ObjectUtil; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.FlowInstanceBizExt; + +import java.util.Collection; + +/** + * 流程实例业务扩展Mapper接口 + * + * @author may + * @date 2025-08-05 + */ +public interface FlwInstanceBizExtMapper extends BaseMapperPlus { + + /** + * 根据 instanceId 保存或更新流程实例业务扩展 + * + * @param entity 流程实例业务扩展实体 + * @return 操作是否成功 + */ + default int saveOrUpdateByInstanceId(FlowInstanceBizExt entity) { + // 查询是否存在 + FlowInstanceBizExt exist = this.lambda() + .eq(FlowInstanceBizExt::getInstanceId, entity.getInstanceId()) + .one(); + + if (ObjectUtil.isNotNull(exist)) { + // 存在就带上主键更新 + entity.setId(exist.getId()); + return updateById(entity); + } else { + // 不存在就插入 + return insert(entity); + } + } + + /** + * 按照流程实例ID删除单个流程实例业务扩展 + * + * @param instanceId 流程实例ID + * @return 删除的行数 + */ + default int deleteByInstId(Long instanceId) { + return this.lambda().eq(FlowInstanceBizExt::getInstanceId, instanceId).deleteCount(); + } + + /** + * 按照流程实例ID批量删除流程实例业务扩展 + * + * @param instanceIds 流程实例ID列表 + * @return 删除的行数 + */ + default int deleteByInstIds(Collection instanceIds) { + return this.lambda().in(FlowInstanceBizExt::getInstanceId, instanceIds).deleteCount(); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java new file mode 100644 index 000000000..d87a18767 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java @@ -0,0 +1,28 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.base.MPJBaseMapper; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.domain.vo.FlowInstanceVo; + +/** + * 实例信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +public interface FlwInstanceMapper extends MPJBaseMapper { + + /** + * 流程实例信息 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + default Page selectInstanceList(Page page, MPJLambdaWrapper queryWrapper) { + return this.selectJoinPage(page, FlowInstanceVo.class, queryWrapper); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwSpelMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwSpelMapper.java new file mode 100644 index 000000000..24dd70a4a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwSpelMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.FlowSpel; +import org.dromara.workflow.domain.vo.FlowSpelVo; + +/** + * 流程spel表达式定义Mapper接口 + * + * @author Michelle.Chung + * @date 2025-07-04 + */ +public interface FlwSpelMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java new file mode 100644 index 000000000..25bb30293 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java @@ -0,0 +1,103 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.base.MPJBaseMapper; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.orm.entity.*; +import org.dromara.workflow.domain.FlowInstanceBizExt; +import org.dromara.workflow.domain.bo.FlowTaskBo; +import org.dromara.workflow.domain.vo.FlowTaskVo; + +import java.util.List; +import java.util.Map; + +/** + * 任务信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +public interface FlwTaskMapper extends BaseMapperPlus, MPJBaseMapper { + + /** + * 分页查询运行中的待办任务。 + * + * @param page 分页对象 + * @param bo 查询条件 + * @param categoryIds 流程分类 id 列表 + * @param userId 当前用户 id + * @return 待办任务分页结果 + */ + default Page getListRunTask(Page page, FlowTaskBo bo, List categoryIds, String userId) { + Map params = bo.getParams(); + return QueryBuilder.lambdaJoin("t", FlowTask.class) + .distinct() + .select(FlowTask::getId, FlowTask::getNodeCode, FlowTask::getNodeName, FlowTask::getNodeType, + FlowTask::getDefinitionId, FlowTask::getInstanceId, FlowTask::getCreateTime, FlowTask::getUpdateTime) + .select("i", FlowInstance::getBusinessId, FlowInstance::getFlowStatus, FlowInstance::getCreateBy) + .select("d", FlowDefinition::getFlowName, FlowDefinition::getFlowCode, FlowDefinition::getFormCustom, + FlowDefinition::getCategory, FlowDefinition::getVersion) + .select("uu", FlowUser::getProcessedBy, FlowUser::getType) + .select("biz", FlowInstanceBizExt::getBusinessCode, FlowInstanceBizExt::getBusinessTitle) + .selectAs("COALESCE(NULLIF(TRIM(t.form_path), ''), NULLIF(TRIM(d.form_path), ''))", FlowTaskVo::getFormPath) + .leftJoin(FlowUser.class, "uu", FlowUser::getAssociated, FlowTask::getId) + .leftJoin(FlowDefinition.class, "d", FlowDefinition::getId, FlowTask::getDefinitionId) + .leftJoin(FlowInstance.class, "i", FlowInstance::getId, FlowTask::getInstanceId) + .leftJoin(FlowInstanceBizExt.class, "biz", FlowInstanceBizExt::getInstanceId, FlowInstance::getId) + .eq("t", FlowTask::getNodeType, NodeType.BETWEEN.getKey()) + .in("uu", FlowUser::getType, List.of("1", "2", "3")) + .likeIfText("t", FlowTask::getNodeName, bo.getNodeName()) + .likeIfText("d", FlowDefinition::getFlowName, bo.getFlowName()) + .likeIfText("d", FlowDefinition::getFlowCode, bo.getFlowCode()) + .likeIfText("i", FlowInstance::getFlowStatus, bo.getFlowStatus()) + .inIfNotEmpty("i", FlowInstance::getCreateBy, bo.getCreateByIds()) + .inIfNotEmpty("d", FlowDefinition::getCategory, categoryIds) + .betweenParams("t", FlowTask::getCreateTime, params, "beginTime", "endTime") + .eqIfText("uu", FlowUser::getProcessedBy, userId) + .eq(userId != null && !userId.isBlank(), "i", FlowInstance::getFlowStatus, BusinessStatusEnum.WAITING.getStatus()) + .orderByDesc("t", FlowTask::getCreateTime) + .orderByDesc("t", FlowTask::getUpdateTime) + .page(page, FlowTaskVo.class); + } + + /** + * 分页查询抄送任务。 + * + * @param page 分页对象 + * @param bo 查询条件 + * @param categoryIds 流程分类 id 列表 + * @param userId 当前用户 id + * @return 抄送任务分页结果 + */ + default Page getTaskCopyByPage(Page page, FlowTaskBo bo, List categoryIds, String userId) { + Map params = bo.getParams(); + return QueryBuilder.lambdaJoin("a", FlowUser.class) + .select(FlowUser::getProcessedBy, FlowUser::getCreateTime) + .select("b", FlowHisTask::getId, FlowHisTask::getUpdateTime, FlowHisTask::getFormCustom, + FlowHisTask::getFormPath, FlowHisTask::getNodeName, FlowHisTask::getNodeCode) + .select("c", FlowInstance::getBusinessId, FlowInstance::getFlowStatus, FlowInstance::getCreateBy) + .select("d", FlowDefinition::getFlowName, FlowDefinition::getFlowCode, FlowDefinition::getCategory, + FlowDefinition::getVersion) + .select("biz", FlowInstanceBizExt::getBusinessCode, FlowInstanceBizExt::getBusinessTitle) + .leftJoin(FlowHisTask.class, "b", FlowHisTask::getTaskId, FlowUser::getAssociated) + .leftJoin(FlowInstance.class, "c", FlowInstance::getId, FlowHisTask::getInstanceId) + .leftJoin(FlowDefinition.class, "d", FlowDefinition::getId, FlowInstance::getDefinitionId) + .leftJoin(FlowInstanceBizExt.class, "biz", FlowInstanceBizExt::getInstanceId, FlowInstance::getId) + .eq("a", FlowUser::getType, "4") + .likeIfText("b", FlowHisTask::getNodeName, bo.getNodeName()) + .likeIfText("d", FlowDefinition::getFlowName, bo.getFlowName()) + .likeIfText("d", FlowDefinition::getFlowCode, bo.getFlowCode()) + .likeIfText("c", FlowInstance::getFlowStatus, bo.getFlowStatus()) + .inIfNotEmpty("c", FlowInstance::getCreateBy, bo.getCreateByIds()) + .inIfNotEmpty("d", FlowDefinition::getCategory, categoryIds) + .betweenParams("a", FlowUser::getCreateTime, params, "beginTime", "endTime") + .eqIfText("a", FlowUser::getProcessedBy, userId) + .orderByDesc("a", FlowUser::getCreateTime) + .orderByDesc("b", FlowHisTask::getUpdateTime) + .page(page, FlowTaskVo.class); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwUserMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwUserMapper.java new file mode 100644 index 000000000..f30d2c6b3 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwUserMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import com.github.yulichang.base.MPJBaseMapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.warm.flow.orm.entity.FlowUser; + +/** + * 任务信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +public interface FlwUserMapper extends BaseMapperPlus, MPJBaseMapper { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java new file mode 100644 index 000000000..cd1edba89 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.vo.TestLeaveVo; + +/** + * 请假Mapper接口 + * + * @author may + * @date 2023-07-21 + */ +public interface TestLeaveMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/rule/SpelRuleComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/rule/SpelRuleComponent.java new file mode 100644 index 000000000..ef89fdcfc --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/rule/SpelRuleComponent.java @@ -0,0 +1,41 @@ +package org.dromara.workflow.rule; + +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.system.api.DeptService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.springframework.stereotype.Component; + +/** + * spel表达式规则组件 + *

+ * 通过该组件统一管理流程定义中的spel表达式 + *

+ * + * @author Michelle.Chung + */ +@ConditionalOnEnable +@Slf4j +@Component +@RequiredArgsConstructor +public class SpelRuleComponent { + + private final DeptService deptService; + + /** + * 通过发起人部门 ID 获取部门负责人。 + * + * @param initiatorDeptId 发起人部门 ID + * @return 部门负责人用户 ID + */ + public Long selectDeptLeaderById(Long initiatorDeptId) { + Long leaderId = deptService.selectDeptLeaderById(initiatorDeptId); + if (ObjectUtil.isNull(leaderId)) { + throw new ServiceException("当前部门未设置负责人,请联系管理员操作。"); + } + return leaderId; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java new file mode 100644 index 000000000..b3e5024bd --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java @@ -0,0 +1,105 @@ +package org.dromara.workflow.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 流程分类Service接口 + * + * @author may + */ +public interface IFlwCategoryService { + + /** + * 查询流程分类 + * + * @param categoryId 主键 + * @return 流程分类 + */ + FlowCategoryVo queryById(Long categoryId); + + /** + * 根据流程分类ID查询流程分类名称 + * + * @param categoryId 流程分类ID + * @return 流程分类名称 + */ + String selectCategoryNameById(Long categoryId); + + /** + * 根据流程分类ID查询流程分类名称 + * + * @param categoryIds 流程分类ID + * @return 流程分类名称 + */ + Map selectCategoryNameByIds(Set categoryIds); + + /** + * 查询符合条件的流程分类列表 + * + * @param bo 查询条件 + * @return 流程分类列表 + */ + List queryList(FlowCategoryBo bo); + + /** + * 查询流程分类树结构信息 + * + * @param category 流程分类信息 + * @return 流程分类树信息集合 + */ + List> selectCategoryTreeList(FlowCategoryBo category); + + /** + * 校验流程分类名称是否唯一 + * + * @param category 流程分类信息 + * @return 结果 + */ + boolean checkCategoryNameUnique(FlowCategoryBo category); + + /** + * 查询流程分类是否存在流程定义 + * + * @param categoryId 流程分类ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkCategoryExistDefinition(Long categoryId); + + /** + * 是否存在流程分类子节点 + * + * @param categoryId 流程分类ID + * @return 结果 + */ + boolean hasChildByCategoryId(Long categoryId); + + /** + * 新增流程分类 + * + * @param bo 流程分类 + * @return 是否新增成功 + */ + int insertByBo(FlowCategoryBo bo); + + /** + * 修改流程分类 + * + * @param bo 流程分类 + * @return 是否修改成功 + */ + int updateByBo(FlowCategoryBo bo); + + /** + * 删除流程分类信息 + * + * @param categoryId 主键 + * @return 是否删除成功 + */ + int deleteWithValidById(Long categoryId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java new file mode 100644 index 000000000..2883d4869 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java @@ -0,0 +1,63 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.system.api.domain.UserDTO; + +import java.util.List; + +/** + * 通用 工作流服务 + * + * @author LionLi + */ +public interface IFlwCommonService { + + /** + * 发送消息 + * + * @param flowName 流程定义名称 + * @param instId 实例id + * @param messageType 消息类型 + * @param message 消息内容,为空则发送默认配置的消息内容 + */ + void sendMessage(String flowName, Long instId, List messageType, String message); + + /** + * 发送消息 + * + * @param messageType 消息类型 + * @param message 消息内容 + * @param subject 邮件标题 + * @param userList 接收用户 + */ + void sendMessage(List messageType, String message, String subject, List userList); + + /** + * 发送带跳转路径的消息。 + * + * @param messageType 消息类型 + * @param message 消息内容 + * @param subject 邮件标题 + * @param userList 接收用户 + * @param path 前端跳转路径 + */ + void sendMessage(List messageType, String message, String subject, List userList, String path); + + /** + * 发送工作流结果消息给指定用户。 + * + * @param flowName 流程名称 + * @param status 流程状态 + * @param messageType 消息类型 + * @param userList 接收用户 + */ + void sendResultMessage(String flowName, BusinessStatusEnum status, List messageType, List userList); + + /** + * 申请人节点编码 + * + * @param definitionId 流程定义id + * @return 申请人节点编码 + */ + String applyNodeCode(Long definitionId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java new file mode 100644 index 000000000..e86c99cac --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java @@ -0,0 +1,72 @@ +package org.dromara.workflow.service; + +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Collection; + +/** + * 流程定义 服务层 + * + * @author may + */ +public interface IFlwDefinitionService { + + /** + * 查询流程定义列表 + * + * @param flowDefinition 参数 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + PageResult queryList(FlowDefinition flowDefinition, PageQuery pageQuery); + + /** + * 查询未发布的流程定义列表 + * + * @param flowDefinition 参数 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + PageResult unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery); + + /** + * 发布流程定义 + * + * @param id 流程定义id + * @return 是否发布成功 + */ + boolean publish(Long id); + + /** + * 导出流程定义 + * + * @param id 流程定义id + * @param response 响应 + * @throws IOException 异常 + */ + void exportDef(Long id, HttpServletResponse response) throws IOException; + + /** + * 导入流程定义 + * + * @param file 文件 + * @param category 分类 + * @return 是否导入成功 + */ + boolean importJson(MultipartFile file, String category); + + /** + * 删除流程定义 + * + * @param ids 流程定义id + * @return 是否删除成功 + */ + boolean removeDef(Collection ids); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java new file mode 100644 index 000000000..38b50e08e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java @@ -0,0 +1,169 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.bo.FlowVariableBo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 流程实例 服务层 + * + * @author may + */ +public interface IFlwInstanceService { + + /** + * 分页查询正在运行的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + PageResult selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery); + + /** + * 分页查询已结束的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + PageResult selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery); + + /** + * 根据业务 id 查询流程实例详情,返回业务侧展示所需信息。 + * + * @param businessId 业务id + * @return 结果 + */ + FlowInstanceVo queryByBusinessId(Long businessId); + + /** + * 按业务 id 查询底层流程实例实体。 + * + * @param businessId 业务id + * @return 结果 + */ + FlowInstance selectInstByBusinessId(String businessId); + + /** + * 按实例 id 查询单个流程实例实体。 + * + * @param instanceId 实例id + * @return 结果 + */ + FlowInstance selectInstById(Long instanceId); + + /** + * 按实例 id 集合批量查询流程实例。 + * + * @param instanceIds 实例id + * @return 结果 + */ + List selectInstListByIdList(Collection instanceIds); + + /** + * 按照业务id删除流程实例 + * + * @param businessIds 业务id + * @return 结果 + */ + boolean deleteByBusinessIds(List businessIds); + + /** + * 按照实例id删除流程实例 + * + * @param instanceIds 实例id + * @return 结果 + */ + boolean deleteByInstanceIds(Collection instanceIds); + + /** + * 按照实例id删除已完成得流程实例 + * + * @param instanceIds 删除的实例id + * @return 删除结果 + */ + boolean deleteHisByInstanceIds(Collection instanceIds); + + /** + * 撤销流程 + * + * @param bo 参数 + * @return 结果 + */ + boolean cancelProcessApply(FlowCancelBo bo); + + /** + * 获取当前登陆人发起的流程实例 + * + * @param instanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + PageResult selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery); + + /** + * 获取流程图及历史办理记录,供前端展示流转轨迹。 + * + * @param businessId 业务id + * @return 结果 + */ + Map flowHisTaskList(String businessId); + + /** + * 按照实例id更新状态 + * + * @param instanceId 实例id + * @param status 状态 + */ + void updateStatus(Long instanceId, String status); + + /** + * 获取指定实例当前持有的流程变量。 + * + * @param instanceId 实例id + * @return 结果 + */ + Map instanceVariable(Long instanceId); + + /** + * 更新流程变量,支持在运行中修正流程上下文数据。 + * + * @param bo 参数 + * @return 结果 + */ + boolean updateVariable(FlowVariableBo bo); + + /** + * 为指定流程实例设置变量集合。 + * + * @param instanceId 实例id + * @param variable 流程变量 + */ + void setVariable(Long instanceId, Map variable); + + /** + * 按任务 id 反查所属流程实例。 + * + * @param taskId 任务id + * @return 结果 + */ + FlowInstance selectByTaskId(Long taskId); + + /** + * 作废流程 + * + * @param bo 流程实例 + * @return 结果 + */ + boolean processInvalid(FlowInvalidBo bo); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java new file mode 100644 index 000000000..a94a225ac --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java @@ -0,0 +1,35 @@ +package org.dromara.workflow.service; + +import org.dromara.workflow.domain.vo.NodeExtVo; + +import java.util.Map; + +/** + * 流程节点扩展属性 服务层 + * + * @author AprilWind + */ +public interface IFlwNodeExtService { + + /** + * 解析扩展属性 JSON 并构建 Node 扩展属性对象 + *

+ * 根据传入的 JSON 字符串,将扩展属性分为三类: + * 1. ButtonPermissionEnum:解析为按钮权限列表,标记每个按钮是否勾选 + * 2. CopySettingEnum:解析为抄送对象 ID 集合 + * 3. VariablesEnum:解析为自定义参数 Map + * + *

示例 JSON: + * [ + * {"code": "ButtonPermissionEnum", "value": "back,termination"}, + * {"code": "CopySettingEnum", "value": "1"}, + * {"code": "VariablesEnum", "value": "key1=value1,key2=value2"} + * ] + * + * @param ext 扩展属性 JSON 字符串 + * @param variable 流程变量 + * @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map + */ + NodeExtVo parseNodeExt(String ext, Map variable); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwSpelService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwSpelService.java new file mode 100644 index 000000000..14b77a812 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwSpelService.java @@ -0,0 +1,88 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.api.domain.TaskAssigneeDTO; +import org.dromara.system.api.model.TaskAssigneeBody; +import org.dromara.workflow.domain.bo.FlowSpelBo; +import org.dromara.workflow.domain.vo.FlowSpelVo; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 流程 SpEL 表达式定义服务接口,负责表达式规则管理与动态指派解析。 + * + * @author Michelle.Chung + * @date 2025-07-04 + */ +public interface IFlwSpelService { + + /** + * 根据主键查询流程 SpEL 表达式定义。 + * + * @param id 主键 + * @return 流程spel表达式定义 + */ + FlowSpelVo queryById(Long id); + + /** + * 分页查询流程spel表达式定义列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 流程spel表达式定义分页列表 + */ + PageResult queryPageList(FlowSpelBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的流程 SpEL 表达式定义列表。 + * + * @param bo 查询条件 + * @return 流程spel表达式定义列表 + */ + List queryList(FlowSpelBo bo); + + /** + * 新增流程 SpEL 表达式定义。 + * + * @param bo 流程spel表达式定义 + * @return 是否新增成功 + */ + Boolean insertByBo(FlowSpelBo bo); + + /** + * 修改流程 SpEL 表达式定义。 + * + * @param bo 流程spel表达式定义 + * @return 是否修改成功 + */ + Boolean updateByBo(FlowSpelBo bo); + + /** + * 校验并批量删除流程spel表达式定义信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 按任务指派条件解析 SpEL,并返回可用办理人列表。 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectSpelByTaskAssigneeList(TaskAssigneeBody taskQuery); + + /** + * 根据视图 SpEL 表达式列表,查询对应的备注信息 + * + * @param viewSpels SpEL 表达式列表 + * @return 映射表:key 为 SpEL 表达式,value 为对应备注;若为空则返回空 Map + */ + Map selectRemarksBySpels(List viewSpels); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java new file mode 100644 index 000000000..d427b546d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.service; + +import org.dromara.system.api.domain.UserDTO; + +import java.util.List; + +/** + * 流程设计器-获取办理人 + * + * @author AprilWind + */ +public interface IFlwTaskAssigneeService { + + /** + * 批量解析多个存储标识符(storageIds),按类型分类并合并查询用户列表 + * 输入格式支持多个以逗号分隔的标识(如 "user:123,role:456,789") + * 会自动去重返回结果,非法格式的标识将被忽略 + * + * @param storageIds 多个存储标识符字符串(逗号分隔) + * @return 合并后的用户列表,去重后返回,非法格式的标识将被跳过 + */ + List fetchUsersByStorageIds(String storageIds); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java new file mode 100644 index 000000000..b45f88817 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java @@ -0,0 +1,218 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.api.domain.StartProcessReturnDTO; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; + +import java.util.Collection; +import java.util.List; + +/** + * 任务 服务层 + * + * @author may + */ +public interface IFlwTaskService { + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + * @return 结果 + */ + StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo); + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + * @return 结果 + */ + boolean completeTask(CompleteTaskBo completeTaskBo); + + /** + * 添加抄送人 + * + * @param task 任务信息 + * @param flowCopyList 抄送人 + */ + void setCopy(Task task, List flowCopyList); + + /** + * 查询当前用户的待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 当前用户待办任务分页结果 + */ + PageResult pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询当前租户所有待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 当前用户已办任务分页结果 + */ + PageResult pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 当前租户待办任务分页结果 + */ + PageResult pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 当前租户已办任务分页结果 + */ + PageResult pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询当前用户的抄送 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 当前用户抄送分页结果 + */ + PageResult pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 修改任务办理人 + * + * @param taskIdList 任务id + * @param userId 用户id + * @return 结果 + */ + boolean updateAssignee(Collection taskIdList, String userId); + + /** + * 驳回审批 + * + * @param bo 参数 + * @return 结果 + */ + boolean backProcess(BackProcessBo bo); + + /** + * 获取可驳回的前置节点 + * + * @param taskId 任务id + * @param nowNodeCode 当前节点 + * @return 结果 + */ + List getBackTaskNode(Long taskId, String nowNodeCode); + + /** + * 终止任务 + * + * @param bo 参数 + * @return 结果 + */ + boolean terminationTask(FlowTerminationBo bo); + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + * @return 任务列表 + */ + List selectByIdList(Collection taskIdList); + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 任务详情 + */ + FlowTaskVo selectById(Long taskId); + + /** + * 获取下一节点信息 + * + * @param bo 参数 + * @return 下一节点列表 + */ + List getNextNodeList(FlowNextNodeBo bo); + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 历史任务详情 + */ + FlowHisTask selectHisTaskById(Long taskId); + + /** + * 按照实例id查询任务 + * + * @param instanceId 流程实例id + * @return 任务列表 + */ + List selectByInstId(Long instanceId); + + /** + * 按照实例id查询任务 + * + * @param instanceIds 列表 + * @return 任务列表 + */ + List selectByInstIds(Collection instanceIds); + + /** + * 判断流程是否已结束(即该流程实例下是否还有未完成的任务) + * + * @param instanceId 流程实例ID + * @return true 表示任务已全部结束;false 表示仍有任务存在 + */ + boolean isTaskEnd(Long instanceId); + + /** + * 任务操作 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + * @return 结果 + */ + boolean taskOperation(TaskOperationBo bo, String taskOperation); + + /** + * 获取当前任务的所有办理人 + * + * @param taskIds 任务id + * @return 办理人列表 + */ + List currentTaskAllUser(List taskIds); + + /** + * 按照节点编码查询节点 + * + * @param nodeCode 节点编码 + * @param definitionId 流程定义id + * @return 节点 + */ + FlowNode getByNodeCode(String nodeCode, Long definitionId); + + /** + * 催办任务 + * + * @param bo 参数 + * @return 是否催办成功 + */ + boolean urgeTask(FlowUrgeTaskBo bo); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java new file mode 100644 index 000000000..c67fcbca2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java @@ -0,0 +1,75 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; + +import java.util.Collection; +import java.util.List; + +/** + * 请假示例服务接口,定义请假单查询、维护与流程发起能力。 + * + * @author may + * @date 2023-07-21 + */ +public interface ITestLeaveService { + + /** + * 根据主键查询请假单。 + * + * @param id 主键 + * @return 请假详情 + */ + TestLeaveVo queryById(Long id); + + /** + * 分页查询请假列表。 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 请假分页数据 + */ + PageResult queryPageList(TestLeaveBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的请假列表。 + * + * @param bo 查询条件 + * @return 请假列表 + */ + List queryList(TestLeaveBo bo); + + /** + * 新增请假单。 + * + * @param bo 请假信息 + * @return 新增结果 + */ + TestLeaveVo insertByBo(TestLeaveBo bo); + + /** + * 提交请假单并发起审批流程。 + * + * @param bo 请假信息 + * @return 提交结果 + */ + TestLeaveVo submitAndFlowStart(TestLeaveBo bo); + + /** + * 修改请假单。 + * + * @param bo 请假信息 + * @return 修改结果 + */ + TestLeaveVo updateByBo(TestLeaveBo bo); + + /** + * 校验并批量删除请假信息。 + * + * @param ids 主键集合 + * @return 删除结果 + */ + Boolean deleteWithValidByIds(Collection ids); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java new file mode 100644 index 000000000..6f902a9ef --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java @@ -0,0 +1,78 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.translation.annotation.TranslationType; +import org.dromara.common.translation.core.TranslationInterface; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.stereotype.Service; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +/** + * 流程分类名称翻译实现 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +@TranslationType(type = FlowConstant.CATEGORY_ID_TO_NAME) +public class CategoryNameTranslationImpl implements TranslationInterface { + + private final IFlwCategoryService flwCategoryService; + + /** + * 将流程分类 ID 翻译为分类名称。 + * + * @param key 流程分类 ID + * @param other 额外参数 + * @return 流程分类名称 + */ + @Override + public String translation(Object key, String other) { + return flwCategoryService.selectCategoryNameById(Convert.toLong(key)); + } + + /** + * 批量将流程分类 ID 翻译为分类名称。 + * + * @param keys 流程分类 ID 集合 + * @param other 额外参数 + * @return 流程分类 ID 与分类名称映射 + */ + @Override + public Map translationBatch(Set keys, String other) { + Set categoryIds = collectLongIds(keys); + if (categoryIds.isEmpty()) { + return Map.of(); + } + Map categoryNames = flwCategoryService.selectCategoryNameByIds(categoryIds); + Map result = new LinkedHashMap<>(keys.size()); + for (Object key : keys) { + result.put(key, buildValue(key, categoryNames)); + } + return result; + } + + /** + * 根据原始键构建流程分类名称翻译值。 + * + * @param source 原始键 + * @param categoryNames 流程分类 ID 与分类名称映射 + * @return 流程分类名称 + */ + private String buildValue(Object source, Map categoryNames) { + if (source instanceof String ids) { + return joinMappedValues(ids, categoryNames::get); + } + return source == null ? null : categoryNames.get(Convert.toLong(source)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java new file mode 100644 index 000000000..13d182ea1 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java @@ -0,0 +1,286 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.warm.flow.ui.service.CategoryService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 流程分类Service业务层处理 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +public class FlwCategoryServiceImpl implements IFlwCategoryService, CategoryService { + + private final DefService defService; + private final FlwCategoryMapper categoryMapper; + + /** + * 查询流程分类 + * + * @param categoryId 主键 + * @return 流程分类 + */ + @Override + public FlowCategoryVo queryById(Long categoryId) { + return categoryMapper.selectVoById(categoryId); + } + + /** + * 根据流程分类ID查询流程分类名称 + * + * @param categoryId 流程分类ID + * @return 流程分类名称 + */ + @Cacheable(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId") + @Override + public String selectCategoryNameById(Long categoryId) { + if (ObjectUtil.isNull(categoryId)) { + return null; + } + FlowCategory category = categoryMapper.lambda() + .select(FlowCategory::getCategoryName) + .eq(FlowCategory::getCategoryId, categoryId) + .one(); + return ObjectUtils.notNullGetter(category, FlowCategory::getCategoryName); + } + + /** + * 根据流程分类ID查询流程分类名称 + * + * @param categoryIds 流程分类ID + * @return 流程分类名称 + */ + @Override + public Map selectCategoryNameByIds(Set categoryIds) { + if (CollUtil.isEmpty(categoryIds)) { + return Collections.emptyMap(); + } + List list = categoryMapper.lambda() + .select(FlowCategory::getCategoryId, FlowCategory::getCategoryName) + .in(FlowCategory::getCategoryId, categoryIds) + .list(); + return StreamUtils.toMap(list, FlowCategory::getCategoryId, FlowCategory::getCategoryName); + } + + /** + * 查询符合条件的流程分类列表 + * + * @param bo 查询条件 + * @return 流程分类列表 + */ + @Override + public List queryList(FlowCategoryBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return categoryMapper.selectVoList(lqw); + } + + /** + * 查询流程分类树结构信息 + * + * @param category 流程分类信息 + * @return 流程分类树信息集合 + */ + @Override + public List> selectCategoryTreeList(FlowCategoryBo category) { + List categoryList = this.queryList(category); + if (CollUtil.isEmpty(categoryList)) { + return CollUtil.newArrayList(); + } + return TreeBuildUtils.buildMultiRoot( + categoryList, + node -> Convert.toStr(node.getCategoryId()), + node -> Convert.toStr(node.getParentId()), + (node, treeNode) -> treeNode + .setId(Convert.toStr(node.getCategoryId())) + .setParentId(Convert.toStr(node.getParentId())) + .setName(node.getCategoryName()) + .setWeight(node.getOrderNum()) + ); + } + + /** + * 工作流查询分类 + * + * @return 分类树结构列表 + */ + @Override + public List queryCategory() { + List list = this.queryList(new FlowCategoryBo()); + return StreamUtils.toList(list, category -> new org.dromara.warm.flow.core.dto.Tree() + .setId(Convert.toStr(category.getCategoryId())) + .setName(category.getCategoryName()) + .setParentId(Convert.toStr(category.getParentId())) + ); + } + + /** + * 校验流程分类名称是否唯一 + * + * @param category 流程分类信息 + * @return 结果 + */ + @Override + public boolean checkCategoryNameUnique(FlowCategoryBo category) { + boolean exist = categoryMapper.lambda() + .eq(FlowCategory::getCategoryName, category.getCategoryName()) + .eq(FlowCategory::getParentId, category.getParentId()) + .neIfPresent(FlowCategory::getCategoryId, category.getCategoryId()) + .exists(); + return !exist; + } + + /** + * 查询流程分类是否存在流程定义 + * + * @param categoryId 流程分类ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkCategoryExistDefinition(Long categoryId) { + FlowDefinition definition = new FlowDefinition(); + definition.setCategory(categoryId.toString()); + return defService.exists(definition); + } + + /** + * 是否存在流程分类子节点 + * + * @param categoryId 流程分类ID + * @return 结果 + */ + @Override + public boolean hasChildByCategoryId(Long categoryId) { + return categoryMapper.lambda().eq(FlowCategory::getParentId, categoryId).exists(); + } + + /** + * 构建流程分类查询条件。 + * + * @param bo 查询条件 + * @return 查询条件包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(FlowCategoryBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(FlowCategory::getDelFlag, SystemConstants.NORMAL); + lqw.eq(ObjectUtil.isNotNull(bo.getCategoryId()), FlowCategory::getCategoryId, bo.getCategoryId()); + lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), FlowCategory::getParentId, bo.getParentId()); + lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), FlowCategory::getCategoryName, bo.getCategoryName()); + lqw.orderByAsc(FlowCategory::getAncestors); + lqw.orderByAsc(FlowCategory::getParentId); + lqw.orderByAsc(FlowCategory::getOrderNum); + lqw.orderByAsc(FlowCategory::getCategoryId); + return lqw; + } + + /** + * 新增流程分类 + * + * @param bo 流程分类 + * @return 是否新增成功 + */ + @Override + public int insertByBo(FlowCategoryBo bo) { + FlowCategory info = categoryMapper.selectById(bo.getParentId()); + if (ObjectUtil.isNull(info)) { + throw new ServiceException("父级流程分类不存在!"); + } + FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class); + category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId()); + return categoryMapper.insert(category); + } + + /** + * 修改流程分类 + * + * @param bo 流程分类 + * @return 是否修改成功 + */ + @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#bo.categoryId") + @Override + @Transactional(rollbackFor = Exception.class) + public int updateByBo(FlowCategoryBo bo) { + FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class); + FlowCategory oldCategory = categoryMapper.selectById(category.getCategoryId()); + if (ObjectUtil.isNull(oldCategory)) { + throw new ServiceException("流程分类不存在,无法修改"); + } + if (oldCategory.getParentId() == 0L && category.getParentId() != 0L) { + throw new ServiceException("不允许修改顶级分类的父级节点"); + } + if (!oldCategory.getParentId().equals(category.getParentId())) { + FlowCategory newParentCategory = categoryMapper.selectById(category.getParentId()); + if (ObjectUtil.isNotNull(newParentCategory)) { + String newAncestors = newParentCategory.getAncestors() + StringUtils.SEPARATOR + newParentCategory.getCategoryId(); + String oldAncestors = oldCategory.getAncestors(); + category.setAncestors(newAncestors); + updateCategoryChildren(category.getCategoryId(), newAncestors, oldAncestors); + } else { + throw new ServiceException("父级流程分类不存在!"); + } + } else { + category.setAncestors(oldCategory.getAncestors()); + } + return categoryMapper.updateById(category); + } + + /** + * 修改子元素关系 + * + * @param categoryId 被修改的流程分类ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + private void updateCategoryChildren(Long categoryId, String newAncestors, String oldAncestors) { + List children = categoryMapper.lambda() + .findInSet(categoryId, FlowCategory::getAncestors) + .list(); + List list = new ArrayList<>(); + for (FlowCategory child : children) { + FlowCategory category = new FlowCategory(); + category.setCategoryId(child.getCategoryId()); + category.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + list.add(category); + } + if (CollUtil.isNotEmpty(list)) { + categoryMapper.updateBatchById(list); + } + } + + /** + * 删除流程分类信息 + * + * @param categoryId 主键 + * @return 是否删除成功 + */ + @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId") + @Override + public int deleteWithValidById(Long categoryId) { + return categoryMapper.deleteById(categoryId); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwChartExtServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwChartExtServiceImpl.java new file mode 100644 index 000000000..7c9cd1747 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwChartExtServiceImpl.java @@ -0,0 +1,273 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.api.DeptService; +import org.dromara.system.api.UserService; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.warm.flow.core.dto.DefJson; +import org.dromara.warm.flow.core.dto.NodeJson; +import org.dromara.warm.flow.core.dto.PromptContent; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.utils.MapUtil; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.ui.service.ChartExtService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 流程图提示信息 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwChartExtServiceImpl implements ChartExtService { + + private final UserService userService; + private final DeptService deptService; + private final FlowHisTaskMapper flowHisTaskMapper; + private final DictService dictService; + @Value("${warm-flow.node-tooltip:true}") + private boolean nodeTooltip; + + /** + * 设置流程图提示信息 + * + * @param defJson 流程定义json对象 + */ + @Override + public void execute(DefJson defJson) { + // 配置关闭,直接返回,不渲染悬浮窗 + if (!nodeTooltip) { + return; + } + + // 根据流程实例ID查询所有相关的历史任务列表 + List flowHisTasks = this.getHisTaskGroupedByNode(defJson.getInstance().getId()); + if (CollUtil.isEmpty(flowHisTasks)) { + return; + } + + // 按节点编号(nodeCode)对历史任务进行分组 + Map> groupedByNode = StreamUtils.groupByKey(flowHisTasks, FlowHisTask::getNodeCode); + + // 批量查询所有审批人的用户信息 + List userDTOList = userService.selectListByIds(StreamUtils.toSet(flowHisTasks, e -> Convert.toLong(e.getApprover()))); + + // 将查询到的用户列表转换为以用户ID为key的映射 + Map userMap = StreamUtils.toIdentityMap(userDTOList, UserDTO::getUserId); + Set deptIds = StreamUtils.toSet(userDTOList, UserDTO::getDeptId); + Map deptNameMap = deptService.selectDeptNamesByIds(deptIds); + + Map dictType = dictService.getAllDictByDictType(FlowConstant.WF_TASK_STATUS); + + for (NodeJson nodeJson : defJson.getNodeList()) { + List taskList = groupedByNode.get(nodeJson.getNodeCode()); + if (CollUtil.isEmpty(taskList)) { + continue; + } + + // 按审批人分组去重,保留最新处理记录,最终转换成 List + List latestPerApprover = taskList.stream() + .collect(Collectors.collectingAndThen( + Collectors.toMap( + FlowHisTask::getApprover, + Function.identity(), + (oldTask, newTask) -> newTask.getUpdateTime().after(oldTask.getUpdateTime()) ? newTask : oldTask, + LinkedHashMap::new + ), + map -> new ArrayList<>(map.values()) + )); + + // 处理当前节点的扩展信息 + this.processNodeExtInfo(nodeJson, latestPerApprover, userMap, deptNameMap, dictType); + } + } + + /** + * 初始化流程图提示信息 + * + * @param defJson 流程定义json对象 + */ + @Override + public void initPromptContent(DefJson defJson) { + // 配置关闭,直接返回,不渲染悬浮窗 + if (!nodeTooltip) { + return; + } + + defJson.setTopText("流程名称: " + defJson.getFlowName()); + defJson.getNodeList().forEach(nodeJson -> { + nodeJson.setPromptContent( + new PromptContent() + // 提示信息 + .setInfo( + CollUtil.newArrayList( + new PromptContent.InfoItem() + .setPrefix("任务名称: ") + .setContent(nodeJson.getNodeName()) + .setContentStyle(Map.of( + "border", "1px solid #d1e9ff", + "backgroundColor", "#e8f4ff", + "padding", "4px 8px", + "borderRadius", "4px" + )) + .setRowStyle(Map.of( + "fontWeight", "bold", + "margin", "0 0 6px 0", + "padding", "0 0 8px 0", + "borderBottom", "1px solid #ccc" + )) + ) + ) + // 弹窗样式 + .setDialogStyle(MapUtil.mergeAll( + "position", "absolute", + "backgroundColor", "#fff", + "border", "1px solid #ccc", + "borderRadius", "4px", + "boxShadow", "0 2px 8px rgba(0, 0, 0, 0.15)", + "padding", "8px 12px", + "fontSize", "14px", + "zIndex", "1000", + "maxWidth", "500px", + "maxHeight", "300px", + "overflowY", "auto", + "overflowX", "hidden", + "color", "#333", + "pointerEvents", "auto", + "scrollbarWidth", "thin" + )) + ); + }); + } + + /** + * 处理节点的扩展信息,构建用于流程图悬浮提示的内容 + * + * @param nodeJson 当前流程节点对象,包含节点基础信息和提示内容容器 + * @param taskList 当前节点关联的历史审批任务列表,用于生成提示信息 + * @param userMap 用户信息映射表,key 为用户ID,value 为用户DTO对象,用于获取审批人信息 + * @param deptNameMap 部门名称映射表,key 为部门ID,value 为部门名称 + * @param dictType 数据字典映射表,key 为字典项编码,value 为对应显示值,用于翻译审批状态等 + */ + private void processNodeExtInfo(NodeJson nodeJson, List taskList, Map userMap, + Map deptNameMap, Map dictType) { + + // 获取节点提示内容对象中的 info 列表,用于追加提示项 + List info = nodeJson.getPromptContent().getInfo(); + + // 遍历所有任务记录,构建提示内容 + for (FlowHisTask task : taskList) { + UserDTO userDTO = userMap.get(Convert.toLong(task.getApprover())); + if (ObjectUtil.isEmpty(userDTO)) { + continue; + } + + String deptName = deptNameMap.getOrDefault(userDTO.getDeptId(), StringUtils.EMPTY); + + // 添加标题项,如:👤 张三(市场部) + info.add(new PromptContent.InfoItem() + .setPrefix(StringUtils.format("👥 {}({})", userDTO.getNickName(), deptName)) + .setPrefixStyle(Map.of( + "fontWeight", "bold", + "fontSize", "15px", + "color", "#333" + )) + .setRowStyle(Map.of( + "margin", "8px 0", + "borderBottom", "1px dashed #ccc" + )) + ); + + // 添加具体信息项:账号、耗时、时间 + info.add(buildInfoItem("用户账号", userDTO.getUserName())); + info.add(buildInfoItem("审批状态", dictType.get(task.getFlowStatus()))); + info.add(buildInfoItem("审批耗时", DateUtils.formatBetweenBySecond(task.getUpdateTime(), task.getCreateTime()))); + info.add(buildInfoItem("办理时间", DateUtils.formatDateTime(task.getUpdateTime()))); + } + } + + /** + * 构建单条提示内容对象 InfoItem,用于悬浮窗显示(key: value) + * + * @param key 字段名(作为前缀) + * @param value 字段值 + * @return 提示项对象 + */ + private PromptContent.InfoItem buildInfoItem(String key, String value) { + return new PromptContent.InfoItem() + // 前缀 + .setPrefix(key + ": ") + // 前缀样式 + .setPrefixStyle(Map.of( + "textAlign", "right", + "color", "#444", + "userSelect", "none", + "display", "inline-block", + "width", "100px", + "paddingRight", "8px", + "fontWeight", "500", + "fontSize", "14px", + "lineHeight", "24px", + "verticalAlign", "middle" + )) + // 内容 + .setContent(value) + // 内容样式 + .setContentStyle(Map.of( + "backgroundColor", "#f7faff", + "color", "#005cbf", + "padding", "4px 8px", + "fontSize", "14px", + "borderRadius", "4px", + "whiteSpace", "normal", + "border", "1px solid #d0e5ff", + "userSelect", "text", + "lineHeight", "20px" + )) + // 行样式 + .setRowStyle(Map.of( + "color", "#222", + "alignItems", "center", + "display", "flex", + "marginBottom", "6px", + "fontWeight", "400", + "fontSize", "14px" + )); + } + + /** + * 根据流程实例ID获取历史任务列表 + * + * @param instanceId 流程实例ID + * @return 按更新时间倒序排列的审批历史任务列表 + */ + public List getHisTaskGroupedByNode(Long instanceId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(FlowHisTask::getInstanceId, instanceId) + .eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey()) + .orderByDesc(FlowHisTask::getUpdateTime); + return flowHisTaskMapper.selectList(wrapper); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java new file mode 100644 index 000000000..4afee8142 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java @@ -0,0 +1,194 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.enums.PushSourceEnum; +import org.dromara.common.core.enums.PushTypeEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ThreadUtils; +import org.dromara.common.mail.core.MailBuilder; +import org.dromara.system.api.MessageService; +import org.dromara.system.api.domain.PushPayloadDTO; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.MessageTypeEnum; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import static org.dromara.workflow.common.constant.FlowConstant.PATH_MY_DOCUMENT; +import static org.dromara.workflow.common.constant.FlowConstant.PATH_TASK_WAITING; + +/** + * 工作流工具 + * + * @author LionLi + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwCommonServiceImpl implements IFlwCommonService { + + private static final String DEFAULT_SUBJECT = "单据审批提醒"; + private final MessageService messageService; + + /** + * 根据流程实例发送消息给当前处理人 + * + * @param flowName 流程定义名称 + * @param instId 流程实例ID + * @param messageType 消息类型列表 + * @param message 消息内容,为空则使用默认消息 + */ + @Override + public void sendMessage(String flowName, Long instId, List messageType, String message) { + if (CollUtil.isEmpty(messageType)) { + return; + } + IFlwTaskService flwTaskService = SpringUtils.getBean(IFlwTaskService.class); + List list = flwTaskService.selectByInstId(instId); + if (CollUtil.isEmpty(list)) { + return; + } + if (StringUtils.isBlank(message)) { + message = "有新的【" + flowName + "】单据已经提交至您,请您及时处理。"; + } + List userList = flwTaskService.currentTaskAllUser(StreamUtils.toList(list, FlowTask::getId)); + if (CollUtil.isEmpty(userList)) { + return; + } + // 发给当前处理人的工作流消息统一进入“我的待办”。 + sendMessage(messageType, message, DEFAULT_SUBJECT, userList, PATH_TASK_WAITING); + } + + /** + * 发送消息给指定用户列表 + * + * @param messageType 消息类型列表 + * @param message 消息内容 + * @param subject 邮件标题 + * @param userList 接收用户列表 + */ + @Override + public void sendMessage(List messageType, String message, String subject, List userList) { + sendMessage(messageType, message, subject, userList, null); + } + + /** + * 发送流程结果通知。 + * + * @param flowName 流程名称 + * @param status 业务状态 + * @param messageType 消息类型列表 + * @param userList 接收用户列表 + */ + @Override + public void sendResultMessage(String flowName, BusinessStatusEnum status, List messageType, List userList) { + if (status == null || CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) { + return; + } + // 审批结果类消息面向发起人查看,统一跳转到“我发起的”。 + String message = "您发起的【" + flowName + "】单据审批已" + status.getDesc() + "。"; + sendMessage(messageType, message, DEFAULT_SUBJECT, userList, PATH_MY_DOCUMENT); + } + + /** + * 发送消息给指定用户列表。 + * + * @param messageType 消息类型列表 + * @param message 消息内容 + * @param subject 邮件标题 + * @param userList 接收用户列表 + * @param path 前端跳转路径 + */ + @Override + public void sendMessage(List messageType, String message, String subject, List userList, String path) { + if (CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) { + return; + } + List userIds = new ArrayList<>(StreamUtils.toSet(userList, UserDTO::getUserId)); + Set emails = StreamUtils.toSet(userList, UserDTO::getEmail); + emails.removeIf(StringUtils::isBlank); + + Runnable[] sendTasks = messageType.stream() + .map(code -> (Runnable) () -> sendMessageByType(code, message, subject, path, userIds, emails, userList.size())) + .toArray(Runnable[]::new); + ThreadUtils.virtualInvokeAll(sendTasks); + } + + /** + * 按消息类型执行具体发送逻辑。 + * + * @param code 消息类型编码 + * @param message 消息内容 + * @param subject 邮件标题 + * @param path 前端跳转路径 + * @param userIds 接收用户 id 列表 + * @param emails 接收邮箱集合 + * @param userCount 接收用户数量 + */ + private void sendMessageByType(String code, String message, String subject, String path, List userIds, Set emails, int userCount) { + MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code); + if (ObjectUtil.isEmpty(messageTypeEnum)) { + return; + } + try { + switch (messageTypeEnum) { + case SYSTEM_MESSAGE -> { + // 站内消息直接携带前端路由,消息盒子点击后可按路径分流。 + messageService.publishMessage(userIds, PushPayloadDTO.of( + PushTypeEnum.MESSAGE, + PushSourceEnum.WORKFLOW, + message, null, path + )); + } + case EMAIL_MESSAGE -> MailBuilder.of().to(emails).subject(subject).text(message).send(); + case SMS_MESSAGE -> { +// LinkedHashMap map = new LinkedHashMap<>(1); +// // 根据具体短信服务商参数用法传参 +// map.put("code", "1234"); +// // 自动获取一个短信服务商 +// SmsBlend smsBlend = SmsFactory.getSmsBlend(); +// // 指定获取一个短信服务商 configKey +// SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); +// SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map); + log.info("【短信发送 - TODO】用户数量={} 内容={}", userCount, message); + } + default -> log.warn("【消息发送】未处理的消息类型:{}", messageTypeEnum); + } + } catch (Exception ex) { + // 记录错误但不抛出,确保主逻辑不受影响 + log.error("【消息发送失败】类型={},原因={}", messageTypeEnum, ex.getMessage(), ex); + } + } + + /** + * 申请人节点编码 + * + * @param definitionId 流程定义id + * @return 申请人节点编码 + */ + @Override + public String applyNodeCode(Long definitionId) { + List firstBetweenNode = FlowEngine.nodeService().getFirstBetweenNode(definitionId, new HashMap<>()); + if (CollUtil.isEmpty(firstBetweenNode)) { + throw new ServiceException("流程定义缺少申请人节点,请检查流程定义配置"); + } + return firstBetweenNode.getFirst().getNodeCode(); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java new file mode 100644 index 000000000..3f9d167cd --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java @@ -0,0 +1,209 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.warm.flow.core.dto.DefJson; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.PublishStatus; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.mapper.FlowDefinitionMapper; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * 流程定义 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwDefinitionServiceImpl implements IFlwDefinitionService { + + private final DefService defService; + private final FlowDefinitionMapper flowDefinitionMapper; + private final FlowHisTaskMapper flowHisTaskMapper; + private final FlowNodeMapper flowNodeMapper; + private final FlwCategoryMapper flwCategoryMapper; + private final IFlwCommonService flwCommonService; + + /** + * 查询流程定义列表 + * + * @param flowDefinition 流程定义信息 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + @Override + public PageResult queryList(FlowDefinition flowDefinition, PageQuery pageQuery) { + LambdaQueryWrapper wrapper = buildQueryWrapper(flowDefinition); + wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey()); + Page page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper); + List list = BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class); + return PageResult.build(list, page.getTotal()); + } + + /** + * 查询未发布的流程定义列表 + * + * @param flowDefinition 流程定义信息 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + @Override + public PageResult unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) { + LambdaQueryWrapper wrapper = buildQueryWrapper(flowDefinition); + wrapper.in(FlowDefinition::getIsPublish, Arrays.asList(PublishStatus.UNPUBLISHED.getKey(), PublishStatus.EXPIRED.getKey())); + Page page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper); + List list = BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class); + return PageResult.build(list, page.getTotal()); + } + + /** + * 构造流程定义分页查询条件。 + * + * @param flowDefinition 页面传入的流程定义筛选条件 + * @return 叠加流程编码、名称、分类以及排序条件后的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(FlowDefinition flowDefinition) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowCode()), FlowDefinition::getFlowCode, flowDefinition.getFlowCode()); + wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowName()), FlowDefinition::getFlowName, flowDefinition.getFlowName()); + if (StringUtils.isNotBlank(flowDefinition.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinition.getCategory())); + wrapper.in(FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr)); + } + wrapper.orderByDesc(FlowDefinition::getCreateTime); + return wrapper; + } + + /** + * 发布流程定义 + * + * @param id 流程定义id + * @return 发布成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean publish(Long id) { + List flowNodes = flowNodeMapper.selectList( + QueryBuilder.lambda(FlowNode.class).eq(FlowNode::getDefinitionId, id).build()); + List errorMsg = new ArrayList<>(); + if (CollUtil.isNotEmpty(flowNodes)) { + String applyNodeCode = flwCommonService.applyNodeCode(id); + for (FlowNode flowNode : flowNodes) { + if (StringUtils.isBlank(flowNode.getPermissionFlag()) && !applyNodeCode.equals(flowNode.getNodeCode()) && NodeType.BETWEEN.getKey().equals(flowNode.getNodeType())) { + errorMsg.add(flowNode.getNodeName()); + } + } + if (CollUtil.isNotEmpty(errorMsg)) { + throw new ServiceException("节点【{}】未配置办理人!", StringUtils.joinComma(errorMsg)); + } + } + return defService.publish(id); + } + + /** + * 导入流程定义 + * + * @param file 流程定义 Json 文件 + * @param category 导入后绑定的流程分类 + * @return 导入成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean importJson(MultipartFile file, String category) { + try { + DefJson defJson = JsonUtils.parseObject(file.getBytes(), DefJson.class); + defJson.setCategory(category); + defService.importDef(defJson); + } catch (IOException e) { + log.error("读取文件流错误: {}", e.getMessage(), e); + throw new IllegalStateException("文件读取失败,请检查文件内容", e); + } + return true; + } + + /** + * 导出流程定义 + * + * @param id 流程定义id + * @param response HTTP 响应对象,用于输出定义 Json 内容 + * @throws IOException 异常 + */ + @Override + public void exportDef(Long id, HttpServletResponse response) throws IOException { + byte[] data = defService.exportJson(id).getBytes(StandardCharsets.UTF_8); + // 设置响应头和内容类型 + response.reset(); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setContentType("application/text"); + response.setHeader("Content-Disposition", "attachment;"); + response.addHeader("Content-Length", "" + data.length); + IoUtil.write(response.getOutputStream(), false, data); + } + + /** + * 删除流程定义 + * + * @param ids 流程定义id + * @return 删除成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeDef(Collection ids) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.in(FlowHisTask::getDefinitionId, ids); + List flowHisTasks = flowHisTaskMapper.selectList(wrapper); + if (CollUtil.isNotEmpty(flowHisTasks)) { + List flowDefinitions = flowDefinitionMapper.selectByIds(StreamUtils.toList(flowHisTasks, FlowHisTask::getDefinitionId)); + if (CollUtil.isNotEmpty(flowDefinitions)) { + String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode); + log.info("流程定义【{}】已被使用不可被删除!", join); + throw new ServiceException("流程定义【{}】已被使用不可被删除!", join); + } + } + try { + defService.removeDef((List) ids); + } catch (Exception e) { + log.error("Error removing flow definitions: {}", e.getMessage(), e); + throw new RuntimeException("Failed to remove flow definitions", e); + } + return true; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java new file mode 100644 index 000000000..8a6972e70 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java @@ -0,0 +1,463 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.liteflow.utils.LiteFlowUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.LambdaJoinQueryBuilder; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.constant.ExceptionCons; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.entity.User; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.FlowInstanceBizExt; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.bo.FlowVariableBo; +import org.dromara.workflow.domain.context.InstanceDeleteContext; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.mapper.FlwInstanceMapper; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 流程实例 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwInstanceServiceImpl implements IFlwInstanceService { + + private static final String DELETE_INSTANCE_CHAIN = "deleteInstanceChain"; + + private final InsService insService; + private final DefService defService; + private final TaskService taskService; + private final FlowHisTaskMapper flowHisTaskMapper; + private final FlowInstanceMapper flowInstanceMapper; + private final IFlwTaskService flwTaskService; + private final FlwInstanceMapper flwInstanceMapper; + private final FlwCategoryMapper flwCategoryMapper; + + /** + * 分页查询正在运行的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 当前符合条件的运行中流程实例分页结果 + */ + @Override + public PageResult selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + MPJLambdaWrapper queryWrapper = buildQueryWrapper(flowInstanceBo); + queryWrapper.in("fi", FlowInstance::getFlowStatus, BusinessStatusEnum.runningStatus()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 分页查询已结束的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 当前符合条件的已结束流程实例分页结果 + */ + @Override + public PageResult selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + MPJLambdaWrapper queryWrapper = buildQueryWrapper(flowInstanceBo); + queryWrapper.in("fi", FlowInstance::getFlowStatus, BusinessStatusEnum.finishStatus()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 根据业务id查询流程实例详细信息 + * + * @param businessId 业务id + * @return 结果 + */ + @Override + public FlowInstanceVo queryByBusinessId(Long businessId) { + FlowInstance instance = this.selectInstByBusinessId(Convert.toStr(businessId)); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class); + Definition definition = defService.getById(instanceVo.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); + } + instanceVo.setFlowName(definition.getFlowName()); + instanceVo.setFlowCode(definition.getFlowCode()); + instanceVo.setVersion(definition.getVersion()); + instanceVo.setFormCustom(definition.getFormCustom()); + instanceVo.setFormPath(definition.getFormPath()); + instanceVo.setCategory(definition.getCategory()); + return instanceVo; + } + + /** + * 通用查询条件 + * + * @param flowInstanceBo 查询条件 + * @return 查询条件构造方法 + */ + private MPJLambdaWrapper buildQueryWrapper(FlowInstanceBo flowInstanceBo) { + LambdaJoinQueryBuilder queryBuilder = QueryBuilder.lambdaJoin("fi", FlowInstance.class) + .select(FlowInstance::getId, FlowInstance::getCreateTime, FlowInstance::getUpdateTime, + FlowInstance::getDelFlag, FlowInstance::getDefinitionId, FlowInstance::getBusinessId, + FlowInstance::getNodeType, FlowInstance::getNodeCode, FlowInstance::getNodeName, + FlowInstance::getVariable, FlowInstance::getFlowStatus, FlowInstance::getActivityStatus, + FlowInstance::getCreateBy, FlowInstance::getExt) + .select("fd", org.dromara.warm.flow.orm.entity.FlowDefinition::getFlowName, + org.dromara.warm.flow.orm.entity.FlowDefinition::getFlowCode, + org.dromara.warm.flow.orm.entity.FlowDefinition::getVersion, + org.dromara.warm.flow.orm.entity.FlowDefinition::getFormCustom, + org.dromara.warm.flow.orm.entity.FlowDefinition::getFormPath, + org.dromara.warm.flow.orm.entity.FlowDefinition::getCategory) + .select("biz", FlowInstanceBizExt::getBusinessCode, FlowInstanceBizExt::getBusinessTitle) + .leftJoin(org.dromara.warm.flow.orm.entity.FlowDefinition.class, "fd", org.dromara.warm.flow.orm.entity.FlowDefinition::getId, FlowInstance::getDefinitionId) + .leftJoin(FlowInstanceBizExt.class, "biz", FlowInstanceBizExt::getInstanceId, FlowInstance::getId); + queryBuilder.likeIfText("fi", FlowInstance::getNodeName, flowInstanceBo.getNodeName()); + queryBuilder.likeIfText("fd", org.dromara.warm.flow.orm.entity.FlowDefinition::getFlowName, flowInstanceBo.getFlowName()); + queryBuilder.likeIfText("fd", org.dromara.warm.flow.orm.entity.FlowDefinition::getFlowCode, flowInstanceBo.getFlowCode()); + if (StringUtils.isNotBlank(flowInstanceBo.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowInstanceBo.getCategory())); + queryBuilder.inIfNotEmpty("fd", org.dromara.warm.flow.orm.entity.FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr)); + } + queryBuilder.eqIfText("fi", FlowInstance::getBusinessId, flowInstanceBo.getBusinessId()); + queryBuilder.inIfNotEmpty("fi", FlowInstance::getCreateBy, flowInstanceBo.getCreateByIds()); + queryBuilder.orderByDesc("fi", FlowInstance::getCreateTime); + return queryBuilder.build(); + } + + /** + * 根据业务id查询流程实例 + * + * @param businessId 业务id + * @return 对应的流程实例,不存在时返回 {@code null} + */ + @Override + public FlowInstance selectInstByBusinessId(String businessId) { + return flowInstanceMapper.selectOne( + QueryBuilder.lambda(FlowInstance.class) + .eq(FlowInstance::getBusinessId, businessId) + .build()); + } + + /** + * 按照实例id查询流程实例 + * + * @param instanceId 实例id + * @return 实例详情,不存在时返回 {@code null} + */ + @Override + public FlowInstance selectInstById(Long instanceId) { + return flowInstanceMapper.selectById(instanceId); + } + + /** + * 按照实例id查询流程实例 + * + * @param instanceIds 实例id + * @return 实例列表 + */ + @Override + public List selectInstListByIdList(Collection instanceIds) { + return flowInstanceMapper.selectByIds(instanceIds); + } + + /** + * 按照业务id删除流程实例 + * + * @param businessIds 业务id + * @return 删除成功返回 {@code true},未找到实例时返回 {@code false} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteByBusinessIds(List businessIds) { + InstanceDeleteContext context = InstanceDeleteContext.byBusinessIds(businessIds); + LiteFlowUtils.execute(DELETE_INSTANCE_CHAIN, context); + return context.isResult(); + } + + /** + * 按照实例id删除流程实例 + * + * @param instanceIds 实例id + * @return 删除成功返回 {@code true},未找到实例时返回 {@code false} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteByInstanceIds(Collection instanceIds) { + InstanceDeleteContext context = InstanceDeleteContext.byInstanceIds(instanceIds); + LiteFlowUtils.execute(DELETE_INSTANCE_CHAIN, context); + return context.isResult(); + } + + /** + * 按照实例id删除已完成的流程实例 + * + * @param instanceIds 实例id + * @return 删除成功返回 {@code true},未找到实例时返回 {@code false} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteHisByInstanceIds(Collection instanceIds) { + InstanceDeleteContext context = InstanceDeleteContext.byHistoryInstanceIds(instanceIds); + LiteFlowUtils.execute(DELETE_INSTANCE_CHAIN, context); + return context.isResult(); + } + + /** + * 撤销流程 + * + * @param bo 参数 + * @return 撤销成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelProcessApply(FlowCancelBo bo) { + Instance instance = selectInstByBusinessId(bo.businessId()); + if (instance == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + Definition definition = defService.getById(instance.getDefinitionId()); + if (definition == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); + } + String userIdStr = LoginHelper.getUserIdStr(); + if (!LoginHelper.isSuperAdmin() && !instance.getCreateBy().equals(userIdStr)) { + throw new ServiceException("权限不足,无法撤销流程!"); + } + BusinessStatusEnum.checkCancelStatus(instance.getFlowStatus()); + FlowParams flowParams = FlowParams.build() + .message(bo.message()) + .flowStatus(BusinessStatusEnum.CANCEL.getStatus()) + .hisStatus(BusinessStatusEnum.CANCEL.getStatus()) + .handler(userIdStr) + .ignore(true); + taskService.revoke(instance.getId(), flowParams); + return true; + } + + /** + * 获取当前登陆人发起的流程实例 + * + * @param instanceBo 流程实例 + * @param pageQuery 分页 + * @return 当前登录人发起的流程实例分页结果 + */ + @Override + public PageResult selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery) { + MPJLambdaWrapper queryWrapper = buildQueryWrapper(instanceBo); + queryWrapper.eq("fi", FlowInstance::getCreateBy, LoginHelper.getUserIdStr()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 获取流程图,流程记录 + * + * @param businessId 业务id + * @return 包含流程记录列表和实例 id 的结果集 + */ + @Override + public Map flowHisTaskList(String businessId) { + FlowInstance flowInstance = this.selectInstByBusinessId(businessId); + if (ObjectUtil.isNull(flowInstance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + Long instanceId = flowInstance.getId(); + + // 先组装待审批任务(运行中的任务) + List runningTaskVos = new ArrayList<>(); + List runningTasks = flwTaskService.selectByInstId(instanceId); + if (CollUtil.isNotEmpty(runningTasks)) { + runningTaskVos = BeanUtil.copyToList(runningTasks, FlowHisTaskVo.class); + + List associatedUsers = FlowEngine.userService() + .getByAssociateds(StreamUtils.toList(runningTasks, FlowTask::getId)); + Map> taskUserMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated); + + for (FlowHisTaskVo vo : runningTaskVos) { + vo.setFlowStatus(TaskStatusEnum.WAITING.getStatus()); + vo.setUpdateTime(null); + vo.setRunDuration(null); + + List users = taskUserMap.get(vo.getId()); + if (CollUtil.isNotEmpty(users)) { + vo.setApprover(StreamUtils.join(users, User::getProcessedBy)); + } + } + } + + // 再组装历史任务(已处理任务) + List hisTaskVos = new ArrayList<>(); + List hisTasks = flowHisTaskMapper.selectList( + QueryBuilder.lambda(FlowHisTask.class) + .eq(FlowHisTask::getInstanceId, instanceId) + .eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey()) + .orderByDesc(FlowHisTask::getUpdateTime) + .build() + ); + if (CollUtil.isNotEmpty(hisTasks)) { + hisTaskVos = BeanUtil.copyToList(hisTasks, FlowHisTaskVo.class); + } + + // 结果列表,待审批任务在前,历史任务在后 + List combinedList = new ArrayList<>(); + combinedList.addAll(runningTaskVos); + combinedList.addAll(hisTaskVos); + + return Map.of("list", combinedList, "instanceId", instanceId); + } + + /** + * 按照实例id更新状态 + * + * @param instanceId 实例id + * @param status 状态 + */ + @Override + public void updateStatus(Long instanceId, String status) { + flowInstanceMapper.update(Wrappers.lambdaUpdate(FlowInstance.class) + .set(FlowInstance::getFlowStatus, status) + .eq(FlowInstance::getId, instanceId)); + } + + /** + * 获取流程变量 + * + * @param instanceId 实例id + * @return 变量明细列表及原始变量字符串 + */ + @Override + public Map instanceVariable(Long instanceId) { + FlowInstance flowInstance = flowInstanceMapper.selectById(instanceId); + if (ObjectUtil.isNull(flowInstance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + Map variableMap = Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap()); + List> variableList = variableMap.entrySet().stream() + .map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue())) + .toList(); + return Map.of("variableList", variableList, "variable", flowInstance.getVariable()); + } + + /** + * 设置流程变量 + * + * @param bo 参数 + * @return 更新成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateVariable(FlowVariableBo bo) { + FlowInstance flowInstance = flowInstanceMapper.selectById(bo.instanceId()); + if (flowInstance == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + Map variableMap = new HashMap<>(Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap())); + if (!variableMap.containsKey(bo.key())) { + log.error("变量不存在: {}", bo.key()); + return false; + } + variableMap.put(bo.key(), bo.value()); + flowInstance.setVariable(FlowEngine.jsonConvert.objToStr(variableMap)); + return flowInstanceMapper.updateById(flowInstance) > 0; + } + + /** + * 设置流程变量 + * + * @param instanceId 实例id + * @param variable 流程变量 + */ + @Override + public void setVariable(Long instanceId, Map variable) { + Instance instance = insService.getById(instanceId); + if (instance != null) { + taskService.mergeVariable(instance, variable); + insService.updateById(instance); + } + } + + /** + * 按任务id查询实例 + * + * @param taskId 任务id + * @return 任务关联的流程实例,运行中任务不存在时回退查询历史任务 + */ + @Override + public FlowInstance selectByTaskId(Long taskId) { + Task task = taskService.getById(taskId); + if (task == null) { + FlowHisTask flowHisTask = flwTaskService.selectHisTaskById(taskId); + if (flowHisTask != null) { + return this.selectInstById(flowHisTask.getInstanceId()); + } + } else { + return this.selectInstById(task.getInstanceId()); + } + return null; + } + + /** + * 作废流程 + * + * @param bo 参数 + * @return 作废成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean processInvalid(FlowInvalidBo bo) { + Instance instance = insService.getById(bo.id()); + if (instance != null) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); + } + FlowParams flowParams = FlowParams.build() + .message(bo.comment()) + .flowStatus(BusinessStatusEnum.INVALID.getStatus()) + .hisStatus(TaskStatusEnum.INVALID.getStatus()) + .ignore(true); + taskService.terminationByInsId(bo.id(), flowParams); + return true; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java new file mode 100644 index 000000000..5a9dab190 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java @@ -0,0 +1,365 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.DictTypeDTO; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.utils.CollUtil; +import org.dromara.warm.flow.core.utils.ExpressionUtil; +import org.dromara.warm.flow.ui.service.NodeExtService; +import org.dromara.warm.flow.ui.vo.NodeExt; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.ButtonPermissionEnum; +import org.dromara.workflow.common.enums.CopySettingEnum; +import org.dromara.workflow.common.enums.NodeExtEnum; +import org.dromara.workflow.common.enums.VariablesEnum; +import org.dromara.workflow.domain.vo.ButtonPermissionVo; +import org.dromara.workflow.domain.vo.NodeExtVo; +import org.dromara.workflow.service.IFlwNodeExtService; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 流程设计器-节点扩展属性 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService { + + /** + * 存储不同 dictType 对应的配置信息 + */ + private static final Map> CHILD_NODE_MAP; + + static { + CHILD_NODE_MAP = Map.of( + CopySettingEnum.class.getSimpleName(), + Map.of( + "label", "抄送对象", + "type", 5, + "must", false, + "multiple", false, + "desc", "设置该节点的抄送办理人" + ), + VariablesEnum.class.getSimpleName(), + Map.of( + "label", "自定义参数", + "type", 2, + "must", false, + "multiple", false, + "desc", "节点执行时可设置自定义参数,多个参数以逗号分隔,如:key1=value1,key2=value2" + ), + ButtonPermissionEnum.class.getSimpleName(), + Map.of( + "label", "权限按钮", + "type", 4, + "must", false, + "multiple", true, + "desc", "控制该节点的按钮权限" + ) + ); + } + + private final DictService dictService; + + /** + * 获取节点扩展属性 + * + * @return 节点扩展属性列表 + */ + @Override + public List getNodeExt() { + List nodeExtList = new ArrayList<>(); + // 构建基础设置页面 + nodeExtList.add(buildNodeExt("wf_basic_tab", "基础设置", 1, + List.of(CopySettingEnum.class, VariablesEnum.class))); + // 构建按钮权限页面 + nodeExtList.add(buildNodeExt("wf_button_tab", "权限", 2, + List.of(ButtonPermissionEnum.class))); + // 自定义构建 规则参考 NodeExt 与 warm-flow文档说明 + // nodeExtList.add(buildNodeExt("xxx_xxx", "xxx", 1, List); + return nodeExtList; + } + + /** + * 构建一个 `NodeExt` 对象 + * + * @param code 唯一编码 + * @param name 名称(新页签时,作为页签名称) + * @param type 节点类型(1: 基础设置,2: 新页签) + * @param sources 数据来源(枚举类或字典类型) + * @return 构建的 `NodeExt` 对象 + */ + @SuppressWarnings("unchecked") + private NodeExt buildNodeExt(String code, String name, int type, List sources) { + NodeExt nodeExt = new NodeExt(); + nodeExt.setCode(code); + nodeExt.setType(type); + nodeExt.setName(name); + nodeExt.setChilds(sources.stream() + .map(source -> { + if (source instanceof Class clazz && NodeExtEnum.class.isAssignableFrom(clazz)) { + return buildChildNode((Class) clazz); + } else if (source instanceof String dictType) { + return buildChildNode(dictType); + } + return null; + }) + .filter(ObjectUtil::isNotNull) + .toList() + ); + return nodeExt; + } + + /** + * 根据枚举类型构建一个 `ChildNode` 对象 + * + * @param enumClass 枚举类,必须实现 `NodeExtEnum` 接口 + * @return 构建的 `ChildNode` 对象 + */ + private NodeExt.ChildNode buildChildNode(Class enumClass) { + if (!enumClass.isEnum()) { + return null; + } + String simpleName = enumClass.getSimpleName(); + NodeExt.ChildNode childNode = new NodeExt.ChildNode(); + Map map = CHILD_NODE_MAP.get(simpleName); + // 编码,此json中唯 + childNode.setCode(simpleName); + // label名称 + childNode.setLabel(Convert.toStr(map.get("label"))); + // 1:输入框 2:文本域 3:下拉框 4:选择框 5:用户选择器 + childNode.setType(Convert.toInt(map.get("type"), 1)); + // 是否必填 + childNode.setMust(Convert.toBool(map.get("must"), false)); + // 是否多选 + childNode.setMultiple(Convert.toBool(map.get("multiple"), true)); + // 描述 + childNode.setDesc(Convert.toStr(map.get("desc"), null)); + // 字典,下拉框和复选框时用到 + childNode.setDict(Arrays.stream(enumClass.getEnumConstants()) + .map(NodeExtEnum.class::cast) + .map(x -> + new NodeExt.DictItem(x.getLabel(), x.getValue(), x.isSelected()) + ).toList()); + return childNode; + } + + /** + * 根据字典类型构建 `ChildNode` 对象 + * + * @param dictType 字典类型 + * @return 构建的 `ChildNode` 对象 + */ + private NodeExt.ChildNode buildChildNode(String dictType) { + DictTypeDTO dictTypeDTO = dictService.getDictType(dictType); + if (ObjectUtil.isNull(dictTypeDTO)) { + return null; + } + NodeExt.ChildNode childNode = new NodeExt.ChildNode(); + // 编码,此json中唯一 + childNode.setCode(dictType); + // label名称 + childNode.setLabel(dictTypeDTO.getDictName()); + // 1:输入框 2:文本域 3:下拉框 4:选择框 5:用户选择器 + childNode.setType(3); + // 是否必填 + childNode.setMust(false); + // 是否多选 + childNode.setMultiple(true); + // 描述 (可根据描述参数解析更多配置,如type,must,multiple等) + childNode.setDesc(dictTypeDTO.getRemark()); + // 字典,下拉框和复选框时用到 + childNode.setDict(dictService.getDictData(dictType) + .stream().map(x -> + new NodeExt.DictItem(x.getDictLabel(), x.getDictValue(), Convert.toBool(x.getIsDefault(), false)) + ).toList()); + return childNode; + } + + /** + * 解析扩展属性 JSON 并构建 Node 扩展属性对象 + *

+ * 根据传入的 JSON 字符串,将扩展属性分为三类: + * 1. ButtonPermissionEnum:解析为按钮权限列表,标记每个按钮是否勾选 + * 2. CopySettingEnum:解析为抄送对象 ID 集合 + * 3. VariablesEnum:解析为自定义参数 Map + * + *

示例 JSON: + * [ + * {"code": "ButtonPermissionEnum", "value": "back,termination"}, + * {"code": "CopySettingEnum", "value": "1,3,4,#{@spelRuleComponent.selectDeptLeaderById(#deptId", "#roleId)}"}, + * {"code": "VariablesEnum", "value": "key1=value1,key2=value2"} + * ] + * + * @param ext 扩展属性 JSON 字符串 + * @param variable 流程变量 + * @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map + */ + @Override + public NodeExtVo parseNodeExt(String ext, Map variable) { + NodeExtVo nodeExtVo = new NodeExtVo(); + + // 解析 JSON 为 Dict 列表 + List nodeExtMap = JsonUtils.parseArrayMap(ext); + if (ObjectUtil.isEmpty(nodeExtMap)) { + return nodeExtVo; + } + + for (Dict nodeExt : nodeExtMap) { + String code = nodeExt.getStr("code"); + String value = nodeExt.getStr("value"); + + if (ButtonPermissionEnum.class.getSimpleName().equals(code)) { + // 解析按钮权限 + // 将 value 拆分为 Set,便于精确匹配 + Set buttonSet = StringUtils.str2Set(value, StringUtils.SEPARATOR); + + // 获取按钮字典配置 + NodeExt.ChildNode childNode = buildChildNode(ButtonPermissionEnum.class); + + // 构建 ButtonPermissionVo 列表 + List buttonList = Optional.ofNullable(childNode) + .map(NodeExt.ChildNode::getDict) + .orElse(List.of()) + .stream() + .map(dict -> new ButtonPermissionVo(dict.getValue(), buttonSet.contains(dict.getValue()))) + .toList(); + + nodeExtVo.setButtonPermissions(buttonList); + + } else if (CopySettingEnum.class.getSimpleName().equals(code)) { + List permissions = spelSmartSplit(value).stream() + .map(s -> { + List result = ExpressionUtil.evalVariable(s, variable); + if (CollUtil.isNotEmpty(result)) { + return result; + } + return Collections.singletonList(s); + }).filter(Objects::nonNull) + .flatMap(List::stream) + .distinct() + .collect(Collectors.toList()); + List copySettings = FlowEngine.permissionHandler().convertPermissions(permissions); + // 解析抄送对象 ID 集合 + nodeExtVo.setCopySettings(new HashSet<>(copySettings)); + + } else if (VariablesEnum.class.getSimpleName().equals(code)) { + // 解析自定义参数 + // 将 key=value 字符串拆分为 Map + Map variables = StringUtils.str2List(value, StringUtils.SEPARATOR, true, true).stream() + .map(s -> StringUtils.split(s, "=")) + .filter(arr -> arr.length == 2) + .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1])); + + nodeExtVo.setVariables(variables); + } else { + // 未知扩展类型,记录日志 + log.warn("未知扩展类型:code={}, value={}", code, value); + } + } + return nodeExtVo; + } + + /** + * 按逗号分割字符串,但保留 #{...} 表达式和字符串常量中的逗号 + * + * @param str 原始配置字符串 + * @return 智能分割后的片段列表 + */ + private static List spelSmartSplit(String str) { + List result = new ArrayList<>(); + if (str == null || str.trim().isEmpty()) { + return result; + } + + StringBuilder token = new StringBuilder(); + // #{...} 的嵌套深度 + int depth = 0; + // 是否在字符串常量中(" 或 ') + boolean inString = false; + // 当前字符串引号类型 + char stringQuote = 0; + + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + + // 检测进入 SpEL 表达式 #{...} + if (!inString && c == '#' && depth == 0 && checkNext(str, i, '{')) { + depth++; + token.append("#{"); + // 跳过 { + i++; + continue; + } + + // 在表达式中遇到 { 或 } 改变嵌套深度 + if (!inString && depth > 0) { + if (c == '{') { + depth++; + } else if (c == '}') { + depth--; + } + token.append(c); + continue; + } + + // 检测字符串开始/结束 + if (depth > 0 && (c == '"' || c == '\'')) { + if (!inString) { + inString = true; + stringQuote = c; + } else if (stringQuote == c) { + inString = false; + } + token.append(c); + continue; + } + + // 外层逗号才分割 + if (c == ',' && depth == 0 && !inString) { + String part = token.toString().trim(); + if (!part.isEmpty()) { + result.add(part); + } + token.setLength(0); + continue; + } + + token.append(c); + } + + // 添加最后一个 + String part = token.toString().trim(); + if (!part.isEmpty()) { + result.add(part); + } + + return result; + } + + /** + * 判断指定位置的下一个字符是否匹配预期字符。 + * + * @param str 原始字符串 + * @param index 当前索引 + * @param expected 期望匹配的字符 + * @return 匹配成功返回 {@code true} + */ + private static boolean checkNext(String str, int index, char expected) { + return index + 1 < str.length() && str.charAt(index + 1) == expected; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java new file mode 100644 index 000000000..fcb08f692 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java @@ -0,0 +1,205 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.api.domain.TaskAssigneeDTO; +import org.dromara.system.api.model.TaskAssigneeBody; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.FlowSpel; +import org.dromara.workflow.domain.bo.FlowSpelBo; +import org.dromara.workflow.domain.vo.FlowSpelVo; +import org.dromara.workflow.mapper.FlwSpelMapper; +import org.dromara.workflow.service.IFlwSpelService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 流程spel表达式定义Service业务层处理 + * + * @author Michelle.Chung + * @date 2025-07-04 + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwSpelServiceImpl implements IFlwSpelService { + + private final FlwSpelMapper spelMapper; + + /** + * 查询流程spel表达式定义 + * + * @param id 主键 + * @return 流程spel表达式定义 + */ + @Override + public FlowSpelVo queryById(Long id) { + return spelMapper.selectVoById(id); + } + + /** + * 分页查询流程spel表达式定义列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 流程spel表达式定义分页列表 + */ + @Override + public PageResult queryPageList(FlowSpelBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = spelMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(result.getRecords(), result.getTotal()); + } + + /** + * 查询符合条件的流程spel表达式定义列表 + * + * @param bo 查询条件 + * @return 流程spel表达式定义列表 + */ + @Override + public List queryList(FlowSpelBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return spelMapper.selectVoList(lqw); + } + + /** + * 组装 SpEL 表达式列表查询条件。 + * + * @param bo 页面筛选参数 + * @return 包含排序和筛选条件的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(FlowSpelBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(FlowSpel::getId); + lqw.like(StringUtils.isNotBlank(bo.getComponentName()), FlowSpel::getComponentName, bo.getComponentName()); + lqw.like(StringUtils.isNotBlank(bo.getMethodName()), FlowSpel::getMethodName, bo.getMethodName()); + lqw.eq(StringUtils.isNotBlank(bo.getMethodParams()), FlowSpel::getMethodParams, bo.getMethodParams()); + lqw.eq(StringUtils.isNotBlank(bo.getViewSpel()), FlowSpel::getViewSpel, bo.getViewSpel()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), FlowSpel::getStatus, bo.getStatus()); + lqw.like(StringUtils.isNotBlank(bo.getRemark()), FlowSpel::getRemark, bo.getRemark()); + return lqw; + } + + /** + * 新增流程spel表达式定义 + * + * @param bo 流程spel表达式定义 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(FlowSpelBo bo) { + FlowSpel add = MapstructUtils.convert(bo, FlowSpel.class); + validEntityBeforeSave(add); + boolean flag = spelMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改流程spel表达式定义 + * + * @param bo 流程spel表达式定义 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(FlowSpelBo bo) { + FlowSpel update = MapstructUtils.convert(bo, FlowSpel.class); + validEntityBeforeSave(update); + return spelMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + * + * @param entity 待保存的 SpEL 表达式实体 + */ + private void validEntityBeforeSave(FlowSpel entity) { + if (StringUtils.isNotBlank(entity.getViewSpel())) { + boolean exists = spelMapper.lambda() + .eq(FlowSpel::getViewSpel, entity.getViewSpel()) + .neIfPresent(FlowSpel::getId, entity.getId()) + .exists(); + if (exists) { + throw new ServiceException("SpEL表达式已存在,请勿重复添加"); + } + } + } + + /** + * 校验并批量删除流程spel表达式定义信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return spelMapper.deleteByIds(ids) > 0; + } + + /** + * 查询spel并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectSpelByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + FlowSpelBo bo = new FlowSpelBo(); + bo.setViewSpel(taskQuery.getHandlerCode()); + bo.setRemark(taskQuery.getHandlerName()); + bo.setStatus(SystemConstants.NORMAL); + Map params = bo.getParams(); + params.put("beginTime", taskQuery.getBeginTime()); + params.put("endTime", taskQuery.getEndTime()); + PageResult page = this.queryPageList(bo, pageQuery); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(), + FlowSpelVo::getViewSpel, item -> "", FlowSpelVo::getRemark, item -> "", FlowSpelVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + /** + * 根据视图 SpEL 表达式列表,查询对应的备注信息 + * + * @param viewSpels SpEL 表达式列表 + * @return 映射表:key 为 SpEL 表达式,value 为对应备注;若为空则返回空 Map + */ + @Override + public Map selectRemarksBySpels(List viewSpels) { + if (CollUtil.isEmpty(viewSpels)) { + return Collections.emptyMap(); + } + List list = spelMapper.lambda() + .select(FlowSpel::getViewSpel, FlowSpel::getRemark) + .in(FlowSpel::getViewSpel, viewSpels) + .list(); + return StreamUtils.toMap(list, FlowSpel::getViewSpel, x -> + StringUtils.isEmpty(x.getRemark()) ? "" : x.getRemark() + ); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java new file mode 100644 index 000000000..8b6d9612d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java @@ -0,0 +1,328 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Pair; +import cn.hutool.core.map.MapUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.api.*; +import org.dromara.system.api.domain.DeptDTO; +import org.dromara.system.api.domain.TaskAssigneeDTO; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.system.api.model.TaskAssigneeBody; +import org.dromara.warm.flow.ui.dto.HandlerFunDto; +import org.dromara.warm.flow.ui.dto.HandlerQuery; +import org.dromara.warm.flow.ui.dto.TreeFunDto; +import org.dromara.warm.flow.ui.service.HandlerSelectService; +import org.dromara.warm.flow.ui.vo.HandlerFeedBackVo; +import org.dromara.warm.flow.ui.vo.HandlerSelectVo; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskAssigneeEnum; +import org.dromara.workflow.service.IFlwSpelService; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 流程设计器-获取办理人权限设置列表 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, HandlerSelectService { + + private static final String DEFAULT_GROUP_NAME = "默认分组"; + + private final TaskAssigneeService taskAssigneeService; + private final UserService userService; + private final DeptService deptService; + private final RoleService roleService; + private final PostService postService; + private final IFlwSpelService spelService; + + /** + * 获取办理人权限设置列表tabs页签 + * + * @return tabs页签 + */ + @Override + public List getHandlerType() { + return TaskAssigneeEnum.getAssigneeTypeList(); + } + + /** + * 获取办理列表, 同时构建左侧部门树状结构 + * + * @param query 查询条件 + * @return HandlerSelectVo + */ + @Override + public HandlerSelectVo getHandlerSelect(HandlerQuery query) { + // 获取任务办理类型 + TaskAssigneeEnum type = TaskAssigneeEnum.fromDesc(query.getHandlerType()); + // 转换查询条件为 TaskAssigneeBody + TaskAssigneeBody taskQuery = BeanUtil.toBean(query, TaskAssigneeBody.class); + + // 统一查询并构建业务数据 + TaskAssigneeDTO dto = fetchTaskAssigneeData(type, taskQuery); + List depts = fetchDeptData(type); + + return getHandlerSelectVo(buildHandlerData(dto, type), buildDeptTree(depts)); + } + + /** + * 办理人权限名称回显 + * + * @param storageIds 入库主键集合 + * @return 结果 + */ + @Override + public List handlerFeedback(List storageIds) { + if (CollUtil.isEmpty(storageIds)) { + return Collections.emptyList(); + } + // 解析并归类 ID,同时记录原始顺序和对应解析结果 + Map> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class); + Map> parsedMap = new LinkedHashMap<>(); + for (String storageId : storageIds) { + Pair parsed = this.parseStorageId(storageId); + parsedMap.put(storageId, parsed); + if (parsed != null) { + typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue()); + } + } + + // 查询所有类型对应的 ID 名称映射 + Map> nameMap = this.getNamesByTypes(typeIdMap); + // 组装返回结果,保持原始顺序 + return parsedMap.entrySet().stream() + .map(entry -> { + String storageId = entry.getKey(); + Pair parsed = entry.getValue(); + String handlerName = (parsed == null) ? null + : nameMap.getOrDefault(parsed.getKey(), Collections.emptyMap()) + .get(parsed.getValue()); + return new HandlerFeedBackVo(storageId, handlerName); + }).toList(); + } + + /** + * 根据办理人类型查询右侧候选数据。 + * + * @param type 办理人类型 + * @param taskQuery 查询条件 + * @return 办理人数据 + */ + private TaskAssigneeDTO fetchTaskAssigneeData(TaskAssigneeEnum type, TaskAssigneeBody taskQuery) { + return switch (type) { + case USER -> taskAssigneeService.selectUsersByTaskAssigneeList(taskQuery); + case ROLE -> taskAssigneeService.selectRolesByTaskAssigneeList(taskQuery); + case DEPT -> taskAssigneeService.selectDeptsByTaskAssigneeList(taskQuery); + case POST -> taskAssigneeService.selectPostsByTaskAssigneeList(taskQuery); + case SPEL -> spelService.selectSpelByTaskAssigneeList(taskQuery); + }; + } + + /** + * 根据办理人类型获取部门树数据源。 + * + * @param type 办理人类型 + * @return 部门列表 + */ + private List fetchDeptData(TaskAssigneeEnum type) { + if (type.needsDeptService()) { + return deptService.selectDeptsByList(); + } + return new ArrayList<>(); + } + + /** + * 获取权限分组名称 + * + * @param type 任务分配人枚举 + * @param groupName 权限分组 + * @return 权限分组名称 + */ + private String getGroupName(TaskAssigneeEnum type, String groupName) { + if (StringUtils.isEmpty(groupName)) { + return DEFAULT_GROUP_NAME; + } + if (type.needsDeptService()) { + return deptService.selectDeptNameByIds(groupName); + } + return DEFAULT_GROUP_NAME; + } + + /** + * 构建设计器左侧部门树。 + * + * @param depts 部门列表 + * @return 部门树构建器 + */ + private TreeFunDto buildDeptTree(List depts) { + return new TreeFunDto<>(depts) + .setId(dept -> Convert.toStr(dept.getDeptId())) + .setName(DeptDTO::getDeptName) + .setParentId(dept -> Convert.toStr(dept.getParentId())); + } + + /** + * 构建设计器右侧办理人列表数据。 + * + * @param dto 办理人数据 + * @param type 办理人类型 + * @return 办理人列表构建器 + */ + private HandlerFunDto buildHandlerData(TaskAssigneeDTO dto, TaskAssigneeEnum type) { + return new HandlerFunDto<>(dto.getList(), dto.getTotal()) + .setStorageId(assignee -> type.getCode() + assignee.getStorageId()) + .setHandlerCode(assignee -> StringUtils.blankToDefault(assignee.getHandlerCode(), "无")) + .setHandlerName(assignee -> StringUtils.blankToDefault(assignee.getHandlerName(), "无")) + .setGroupName(assignee -> this.getGroupName(type, assignee.getGroupName())) + .setCreateTime(assignee -> DateUtils.formatLocalDateTime(assignee.getCreateTime())); + } + + /** + * 批量解析多个存储标识符(storageIds),按类型分类并合并查询用户列表 + * 输入格式支持多个以逗号分隔的标识(如 "user:123,role:456,789") + * 会自动去重返回结果,非法格式的标识将被忽略 + * + * @param storageIds 多个存储标识符字符串(逗号分隔) + * @return 合并后的用户列表,去重后返回,非法格式的标识将被跳过 + */ + @Override + public List fetchUsersByStorageIds(String storageIds) { + if (StringUtils.isEmpty(storageIds)) { + return List.of(); + } + Map> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class); + for (String storageId : StringUtils.str2List(storageIds, StringUtils.SEPARATOR, true, true)) { + Pair parsed = this.parseStorageId(storageId); + if (parsed != null) { + typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue()); + } + } + return this.getUsersByTypes(typeIdMap).stream() + .distinct() + .toList(); + } + + /** + * 按任务分配类型批量查询用户。 + * + * @param typeIdMap 任务分配类型与 id 列表映射 + * @return 用户列表 + */ + private List getUsersByTypes(Map> typeIdMap) { + return typeIdMap.entrySet().stream() + .map(entry -> this.getUsersByType(entry.getKey(), entry.getValue())) + .filter(CollUtil::isNotEmpty) + .flatMap(Collection::stream) + .toList(); + } + + /** + * 按任务分配类型批量查询名称映射。 + * + * @param typeIdMap 任务分配类型与 id 列表映射 + * @return 任务分配类型与名称映射 + */ + private Map> getNamesByTypes(Map> typeIdMap) { + Map> nameMap = new EnumMap<>(TaskAssigneeEnum.class); + typeIdMap.forEach((type, ids) -> nameMap.put(type, this.getNamesByType(type, ids))); + return nameMap; + } + + /** + * 根据指定的任务分配类型(TaskAssigneeEnum)和 ID 列表,获取对应的用户信息列表 + * + * @param type 任务分配类型,表示用户、角色、部门或其他(TaskAssigneeEnum 枚举值) + * @param ids 与指定分配类型关联的 ID 列表(例如用户ID、角色ID、部门ID等) + * @return 返回包含用户信息的列表。如果类型为用户(USER),则通过用户ID列表查询; + * 如果类型为角色(ROLE),则通过角色ID列表查询; + * 如果类型为部门(DEPT),则通过部门ID列表查询; + * 如果类型为岗位(POST)或无法识别的类型,则返回空列表 + */ + private List getUsersByType(TaskAssigneeEnum type, List ids) { + if (type == TaskAssigneeEnum.SPEL) { + return new ArrayList<>(); + } + List longIds = StreamUtils.toList(ids, Convert::toLong); + return switch (type) { + case USER -> userService.selectListByIds(longIds); + case ROLE -> userService.selectUsersByRoleIds(longIds); + case DEPT -> userService.selectUsersByDeptIds(longIds); + case POST -> userService.selectUsersByPostIds(longIds); + default -> new ArrayList<>(); + }; + } + + /** + * 根据任务分配类型和对应 ID 列表,批量查询名称映射关系 + * + * @param type 分配类型(用户、角色、部门、岗位) + * @param ids ID 列表(如用户ID、角色ID等) + * @return 返回 Map,其中 key 为 ID,value 为对应的名称 + */ + private Map getNamesByType(TaskAssigneeEnum type, List ids) { + if (type == TaskAssigneeEnum.SPEL) { + return spelService.selectRemarksBySpels(ids); + } + + List longIds = StreamUtils.toList(ids, Convert::toLong); + Map rawMap = switch (type) { + case USER -> userService.selectUserNicksByIds(longIds); + case ROLE -> roleService.selectRoleNamesByIds(longIds); + case DEPT -> deptService.selectDeptNamesByIds(longIds); + case POST -> postService.selectPostNamesByIds(longIds); + default -> Collections.emptyMap(); + }; + if (MapUtil.isEmpty(rawMap)) { + return Collections.emptyMap(); + } + return rawMap.entrySet() + .stream() + .collect(Collectors.toMap( + e -> Convert.toStr(e.getKey()), + Map.Entry::getValue + )); + } + + /** + * 解析 storageId 字符串,返回类型和ID的组合 + * + * @param storageId 例如 "user:123" 或 "456" + * @return Pair(TaskAssigneeEnum, Long),如果格式非法返回 null + */ + private Pair parseStorageId(String storageId) { + if (StringUtils.isBlank(storageId)) { + return null; + } + if (TaskAssigneeEnum.isSpelExpression(storageId)) { + return Pair.of(TaskAssigneeEnum.SPEL, storageId); + } + try { + String[] parts = storageId.split(StringUtils.COLON, 2); + if (parts.length < 2) { + return Pair.of(TaskAssigneeEnum.USER, parts[0]); + } else { + TaskAssigneeEnum type = TaskAssigneeEnum.fromCode(parts[0] + StringUtils.COLON); + return Pair.of(type, parts[1]); + } + } catch (Exception e) { + log.warn("解析 storageId 失败,格式非法:{},错误信息:{}", storageId, e.getMessage()); + return null; + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java new file mode 100644 index 000000000..70a2065a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -0,0 +1,742 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.lock.annotation.Lock4j; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.liteflow.utils.LiteFlowUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.query.QueryBuilder; +import org.dromara.common.mybatis.utils.IdGeneratorUtil; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.api.UserService; +import org.dromara.system.api.domain.UserDTO; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.constant.ExceptionCons; +import org.dromara.warm.flow.core.dto.FlowCombine; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.*; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.SkipType; +import org.dromara.warm.flow.core.enums.UserType; +import org.dromara.warm.flow.core.exception.FlowException; +import org.dromara.warm.flow.core.service.*; +import org.dromara.warm.flow.core.utils.ExpressionUtil; +import org.dromara.warm.flow.core.utils.MapUtil; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.entity.FlowUser; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; +import org.dromara.workflow.api.domain.StartProcessReturnDTO; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskAssigneeType; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.context.CompleteTaskContext; +import org.dromara.workflow.domain.context.StartProcessContext; +import org.dromara.workflow.domain.context.TaskOperationContext; +import org.dromara.workflow.domain.vo.FlowCopyVo; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; +import org.dromara.workflow.domain.vo.NodeExtVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.mapper.FlwHisTaskMapper; +import org.dromara.workflow.mapper.FlwTaskMapper; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwNodeExtService; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 任务 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwTaskServiceImpl implements IFlwTaskService { + + private static final String START_PROCESS_CHAIN = "startProcessChain"; + private static final String COMPLETE_TASK_CHAIN = "completeTaskChain"; + private static final String TASK_OPERATION_CHAIN = "taskOperationChain"; + + private final TaskService taskService; + private final InsService insService; + private final DefService defService; + private final HisTaskService hisTaskService; + private final NodeService nodeService; + private final FlowTaskMapper flowTaskMapper; + private final FlowHisTaskMapper flowHisTaskMapper; + private final UserService userService; + private final FlwTaskMapper flwTaskMapper; + private final FlwHisTaskMapper flwHisTaskMapper; + private final FlwCategoryMapper flwCategoryMapper; + private final FlowNodeMapper flowNodeMapper; + private final IFlwTaskAssigneeService flwTaskAssigneeService; + private final IFlwCommonService flwCommonService; + private final IFlwNodeExtService flwNodeExtService; + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + * @return 启动后的流程实例标识与首个任务标识 + */ + @Override + @Transactional(rollbackFor = Exception.class) + @Lock4j(keys = {"#startProcessBo.flowCode + #startProcessBo.businessId"}) + public StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo) { + StartProcessContext context = new StartProcessContext(startProcessBo); + LiteFlowUtils.execute(START_PROCESS_CHAIN, context); + return context.getStartProcessReturn(); + } + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + * @return 办理成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + @Lock4j(keys = {"#completeTaskBo.taskId"}) + public boolean completeTask(CompleteTaskBo completeTaskBo) { + // 办理任务的业务编排交给 LiteFlow 链路,当前方法只保留事务、锁和异常透传边界。 + LiteFlowUtils.execute(COMPLETE_TASK_CHAIN, new CompleteTaskContext(completeTaskBo)); + return true; + } + + /** + * 添加抄送人 + * + * @param task 任务信息 + * @param flowCopyList 抄送人 + */ + @Override + public void setCopy(Task task, List flowCopyList) { + if (CollUtil.isEmpty(flowCopyList)) { + return; + } + // 添加抄送人记录 + List flowHisTasks = flowHisTaskMapper.selectList( + QueryBuilder.lambda(FlowHisTask.class) + .eq(FlowHisTask::getTaskId, task.getId()) + .build()); + if (CollUtil.isEmpty(flowHisTasks)) { + throw new ServiceException("流程历史任务不存在,无法添加抄送记录"); + } + FlowHisTask flowHisTask = flowHisTasks.getFirst(); + FlowNode flowNode = new FlowNode(); + flowNode.setNodeCode(flowHisTask.getTargetNodeCode()); + flowNode.setNodeName(flowHisTask.getTargetNodeName()); + //生成新的任务id + long taskId = IdGeneratorUtil.nextLongId(); + task.setId(taskId); + task.setNodeName("【抄送】" + task.getNodeName()); + Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000); + FlowParams flowParams = FlowParams.build() + .skipType(SkipType.NONE.getKey()) + .hisStatus(TaskStatusEnum.COPY.getStatus()) + .message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getNickName)); + HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams); + hisTask.setCreateTime(updateTime); + hisTask.setUpdateTime(updateTime); + hisTaskService.save(hisTask); + List userList = StreamUtils.toList(flowCopyList, x -> + new FlowUser() + .setType(TaskAssigneeType.COPY.getCode()) + .setProcessedBy(Convert.toStr(x.getUserId())) + .setAssociated(taskId)); + // 批量保存抄送人员 + FlowEngine.userService().saveBatch(userList); + // 抄送消息进入“我的抄送”,不和待办列表混用。 + flwCommonService.sendMessage( + List.of(org.dromara.workflow.common.enums.MessageTypeEnum.SYSTEM_MESSAGE.getCode()), + "您收到一条新的流程抄送,请及时查看。", + "单据抄送提醒", + userService.selectListByIds(StreamUtils.toList(flowCopyList, FlowCopyBo::getUserId)), + PATH_TASK_COPY + ); + } + + /** + * 查询当前用户的待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 当前登录人的待办任务分页结果 + */ + @Override + public PageResult pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + Page page = flwTaskMapper.getListRunTask(pageQuery.build(), flowTaskBo, categoryIds(flowTaskBo), LoginHelper.getUserIdStr()); + this.wrapAssigneeInfo(page.getRecords()); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 查询当前用户的已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 当前登录人的已办任务分页结果 + */ + @Override + public PageResult pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + Page page = flwHisTaskMapper.getListFinishTask(pageQuery.build(), flowTaskBo, categoryIds(flowTaskBo), LoginHelper.getUserIdStr()); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 查询待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 全部待办任务分页结果 + */ + @Override + public PageResult pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + Page page = flwTaskMapper.getListRunTask(pageQuery.build(), flowTaskBo, categoryIds(flowTaskBo), null); + this.wrapAssigneeInfo(page.getRecords()); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 为流程任务列表封装处理人 ID(assigneeIds) + * + * @param taskList 流程任务列表 + */ + private void wrapAssigneeInfo(List taskList) { + if (CollUtil.isEmpty(taskList)) { + return; + } + List associatedUsers = FlowEngine.userService().getByAssociateds(StreamUtils.toList(taskList, FlowTaskVo::getId)); + Map> taskUserMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated); + // 组装用户数据回任务列表 + for (FlowTaskVo task : taskList) { + List users = taskUserMap.get(task.getId()); + task.setAssigneeIds(StreamUtils.join(users, User::getProcessedBy)); + } + } + + /** + * 查询已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 全部已办任务分页结果 + */ + @Override + public PageResult pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + Page page = flwHisTaskMapper.getListFinishTask(pageQuery.build(), flowTaskBo, categoryIds(flowTaskBo), null); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 查询当前用户的抄送 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 当前登录人收到的抄送分页结果 + */ + @Override + public PageResult pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + Page page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), flowTaskBo, categoryIds(flowTaskBo), LoginHelper.getUserIdStr()); + return PageResult.build(page.getRecords(), page.getTotal()); + } + + /** + * 解析查询条件中的分类及其子分类编码集合。 + * + * @param flowTaskBo 任务筛选条件 + * @return 分类 id 字符串集合,未指定分类时返回 {@code null} + */ + private List categoryIds(FlowTaskBo flowTaskBo) { + if (StringUtils.isNotBlank(flowTaskBo.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory())); + return StreamUtils.toList(categoryIds, Convert::toStr); + } + return null; + } + + /** + * 驳回任务 + * + * @param bo 参数 + * @return 驳回成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean backProcess(BackProcessBo bo) { + Long taskId = bo.getTaskId(); + String notice = bo.getNotice(); + List messageType = bo.getMessageType(); + String message = bo.getMessage(); + FlowTask task = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } + Instance inst = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(inst)) { + throw new ServiceException("流程实例不存在"); + } + BusinessStatusEnum.checkBackStatus(inst.getFlowStatus()); + Long definitionId = task.getDefinitionId(); + String applyNodeCode = flwCommonService.applyNodeCode(definitionId); + + Map variable = new HashMap<>(); + variable.put(MESSAGE_TYPE, messageType); + variable.put(MESSAGE_NOTICE, notice); + + FlowParams flowParams = FlowParams.build() + .nodeCode(bo.getNodeCode()) + .variable(variable) + .message(message) + .skipType(SkipType.REJECT.getKey()) + .flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus()) + .hisStatus(TaskStatusEnum.BACK.getStatus()) + .hisTaskExt(bo.getFileId()); + taskService.skip(task.getId(), flowParams); + return true; + } + + /** + * 获取可驳回的前置节点 + * + * @param taskId 任务id + * @param nowNodeCode 当前节点 + * @return 当前任务允许驳回的节点列表 + */ + @Override + public List getBackTaskNode(Long taskId, String nowNodeCode) { + FlowTask task = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } + List nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), task.getDefinitionId()); + if (!CollUtil.isNotEmpty(nodeCodes)) { + return nodeCodes; + } + List userList = FlowEngine.userService() + .getByAssociateds(Collections.singletonList(task.getId()), UserType.DEPUTE.getKey()); + if (CollUtil.isNotEmpty(userList)) { + return nodeCodes; + } + //判断是否配置了固定驳回节点 + Node node = nodeCodes.getFirst(); + if (StringUtils.isNotBlank(node.getAnyNodeSkip())) { + return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), task.getDefinitionId()); + } + //获取可驳回的前置节点 + Long definitionId = task.getDefinitionId(); + FlowCombine flowCombine = defService.getFlowCombineNoDef(definitionId); + Map nodeMap = getPreviousNodeMap(nowNodeCode, flowCombine); + List hisTaskList = hisTaskService.getByInsId(task.getInstanceId()); + + Set reachableNodeCodes = new HashSet<>(); + if (CollUtil.isNotEmpty(hisTaskList)) { + Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException("流程实例不存在"); + } + collectReachableNodeCodes(reachableNodeCodes, instance, flowCombine); + if (!reachableNodeCodes.contains(nowNodeCode)) { + reachableNodeCodes.clear(); + } + } + + Set added = new HashSet<>(); + List backNodeList = new ArrayList<>(); + for (HisTask hisTask : hisTaskList) { + Node nodeValue = nodeMap.get(hisTask.getNodeCode()); + if (nodeValue != null + && NodeType.BETWEEN.getKey().equals(nodeValue.getNodeType()) + && (CollUtil.isEmpty(reachableNodeCodes) || reachableNodeCodes.contains(nodeValue.getNodeCode())) + && added.add(nodeValue.getNodeCode())) { + backNodeList.add(nodeValue); + } + } + if (CollUtil.isNotEmpty(backNodeList)) { + Collections.reverse(backNodeList); + return backNodeList; + } + if (CollUtil.isNotEmpty(hisTaskList)) { + return Collections.emptyList(); + } + return StreamUtils.filter(nodeMap.values(), e -> NodeType.BETWEEN.getKey().equals(e.getNodeType())); + } + + private Map getPreviousNodeMap(String nodeCode, FlowCombine flowCombine) { + if (ObjectUtil.isNull(flowCombine) || CollUtil.isEmpty(flowCombine.getAllNodes()) || CollUtil.isEmpty(flowCombine.getAllSkips())) { + return Collections.emptyMap(); + } + Map allNodeMap = StreamUtils.toIdentityMap(flowCombine.getAllNodes(), Node::getNodeCode); + Map> previousSkipMap = new HashMap<>(); + for (Skip skip : flowCombine.getAllSkips()) { + previousSkipMap.computeIfAbsent(skip.getNextNodeCode(), k -> new ArrayList<>()).add(skip); + } + + Map previousNodeMap = new LinkedHashMap<>(); + Set visitedNodeCodes = new HashSet<>(); + Deque nodeQueue = new ArrayDeque<>(); + visitedNodeCodes.add(nodeCode); + nodeQueue.add(nodeCode); + while (CollUtil.isNotEmpty(nodeQueue)) { + String currentNodeCode = nodeQueue.poll(); + List previousSkips = previousSkipMap.get(currentNodeCode); + if (CollUtil.isEmpty(previousSkips)) { + continue; + } + for (Skip previousSkip : previousSkips) { + String previousNodeCode = previousSkip.getNowNodeCode(); + if (!visitedNodeCodes.add(previousNodeCode)) { + continue; + } + Node previousNode = allNodeMap.get(previousNodeCode); + if (ObjectUtil.isNull(previousNode)) { + continue; + } + previousNodeMap.put(previousNodeCode, previousNode); + nodeQueue.add(previousNodeCode); + } + } + return previousNodeMap; + } + + private void collectReachableNodeCodes(Set nodeCodes, Instance instance, FlowCombine flowCombine) { + if (ObjectUtil.isNull(flowCombine) || CollUtil.isEmpty(flowCombine.getAllNodes())) { + return; + } + Deque nodeQueue = new ArrayDeque<>(); + flowCombine.getAllNodes().stream() + .filter(e -> NodeType.START.getKey().equals(e.getNodeType())) + .findFirst() + .ifPresent(nodeQueue::add); + + while (CollUtil.isNotEmpty(nodeQueue)) { + Node currentNode = nodeQueue.poll(); + if (ObjectUtil.isNull(currentNode) || !nodeCodes.add(currentNode.getNodeCode())) { + continue; + } + + try { + List nextNodes = nodeService.getNextNodeList(currentNode, null, SkipType.PASS.getKey(), + instance.getVariableMap(), null, flowCombine); + if (CollUtil.isNotEmpty(nextNodes)) { + nodeQueue.addAll(nextNodes); + } + } catch (FlowException e) { + // 条件变量缺失时跳过当前分支,其他引擎异常继续抛出。 + if (!StringUtils.containsAny(e.getMessage(), ExceptionCons.NULL_CONDITION_VALUE, ExceptionCons.NULL_SKIP_TYPE)) { + throw e; + } + } + } + } + + /** + * 终止任务 + * + * @param bo 参数 + * @return 终止成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean terminationTask(FlowTerminationBo bo) { + Long taskId = bo.taskId(); + Task task = taskService.getById(taskId); + if (task == null) { + throw new ServiceException("任务不存在!"); + } + Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNotNull(instance)) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); + } + FlowParams flowParams = FlowParams.build() + .message(bo.comment()) + .flowStatus(BusinessStatusEnum.TERMINATION.getStatus()) + .hisStatus(TaskStatusEnum.TERMINATION.getStatus()); + taskService.termination(taskId, flowParams); + return true; + } + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + * @return 任务列表 + */ + @Override + public List selectByIdList(Collection taskIdList) { + return flowTaskMapper.selectList(QueryBuilder.lambda(FlowTask.class) + .in(FlowTask::getId, taskIdList) + .build()); + } + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 任务详情视图,不存在时返回 {@code null} + */ + @Override + public FlowTaskVo selectById(Long taskId) { + Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + return null; + } + FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class); + Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException("流程实例不存在"); + } + Definition definition = defService.getById(task.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException("流程定义不存在"); + } + flowTaskVo.setFlowStatus(instance.getFlowStatus()); + flowTaskVo.setVersion(definition.getVersion()); + flowTaskVo.setFlowCode(definition.getFlowCode()); + flowTaskVo.setFlowName(definition.getFlowName()); + flowTaskVo.setBusinessId(instance.getBusinessId()); + FlowNode flowNode = this.getByNodeCode(flowTaskVo.getNodeCode(), instance.getDefinitionId()); + if (ObjectUtil.isNull(flowNode)) { + throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在"); + } + NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt(), instance.getVariableMap()); + //设置按钮权限 + if (CollUtil.isNotEmpty(nodeExtVo.getButtonPermissions())) { + flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions()); + } else { + flowTaskVo.setButtonList(new ArrayList<>()); + } + if (CollUtil.isNotEmpty(nodeExtVo.getCopySettings())) { + List list = StreamUtils.toList(nodeExtVo.getCopySettings(), x -> new FlowCopyVo(Convert.toLong(x))); + flowTaskVo.setCopyList(list); + } else { + flowTaskVo.setCopyList(new ArrayList<>()); + } + if (CollUtil.isNotEmpty(nodeExtVo.getVariables())) { + flowTaskVo.setVarList(nodeExtVo.getVariables()); + } else { + flowTaskVo.setVarList(new HashMap<>()); + } + flowTaskVo.setNodeRatio(flowNode.getNodeRatio()); + flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId()))); + return flowTaskVo; + } + + /** + * 获取下一节点信息 + * + * @param bo 参数 + * @return 当前任务在给定变量下可流转到的下一审批节点列表 + */ + @Override + public List getNextNodeList(FlowNextNodeBo bo) { + Long taskId = bo.getTaskId(); + Map variables = bo.getVariables(); + Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } + Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException("流程实例不存在"); + } + Definition definition = defService.getById(task.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException("流程定义不存在"); + } + Map mergeVariable = MapUtil.mergeAll(instance.getVariableMap(), variables); + // 获取下一节点列表 + List nextNodeList = nodeService.getNextNodeList(task.getDefinitionId(), task.getNodeCode(), null, SkipType.PASS.getKey(), mergeVariable); + if (CollUtil.isEmpty(nextNodeList)) { + return new ArrayList<>(); + } + List nextFlowNodes = BeanUtil.copyToList(nextNodeList, FlowNode.class); + // 只获取中间节点 + nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType())); + if (CollUtil.isNotEmpty(nextNodeList)) { + //构建以下节点数据 + List buildNextTaskList = StreamUtils.toList(nextNodeList, node -> taskService.addTask(node, instance, definition, FlowParams.build())); + //办理人变量替换 + ExpressionUtil.evalVariable(buildNextTaskList, FlowParams.build().variable(mergeVariable)); + for (FlowNode flowNode : nextFlowNodes) { + StreamUtils.findFirst(buildNextTaskList, t -> t.getNodeCode().equals(flowNode.getNodeCode())) + .ifPresent(first -> { + List users; + if (CollUtil.isNotEmpty(first.getPermissionList()) + && CollUtil.isNotEmpty(users = flwTaskAssigneeService.fetchUsersByStorageIds(StringUtils.joinComma(first.getPermissionList())))) { + flowNode.setPermissionFlag(StreamUtils.join(users, e -> Convert.toStr(e.getUserId()))); + } + }); + } + } + return nextFlowNodes; + } + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 结果 + */ + @Override + public FlowHisTask selectHisTaskById(Long taskId) { + return flowHisTaskMapper.selectOne(QueryBuilder.lambda(FlowHisTask.class) + .eq(FlowHisTask::getId, taskId) + .build()); + } + + /** + * 按照实例id查询任务 + * + * @param instanceId 流程实例id + * @return 运行中的任务列表 + */ + @Override + public List selectByInstId(Long instanceId) { + return flowTaskMapper.selectList(QueryBuilder.lambda(FlowTask.class) + .eq(FlowTask::getInstanceId, instanceId) + .build()); + } + + /** + * 按照实例id查询任务 + * + * @param instanceIds 流程实例id + * @return 运行中的任务列表 + */ + @Override + public List selectByInstIds(Collection instanceIds) { + return flowTaskMapper.selectList(QueryBuilder.lambda(FlowTask.class) + .in(FlowTask::getInstanceId, instanceIds) + .build()); + } + + /** + * 判断流程是否已结束(即该流程实例下是否还有未完成的任务) + * + * @param instanceId 流程实例ID + * @return true 表示任务已全部结束;false 表示仍有任务存在 + */ + @Override + public boolean isTaskEnd(Long instanceId) { + boolean exists = flowTaskMapper.exists(QueryBuilder.lambda(FlowTask.class) + .eq(FlowTask::getInstanceId, instanceId) + .build()); + return !exists; + } + + /** + * 任务操作 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + * @return 操作成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean taskOperation(TaskOperationBo bo, String taskOperation) { + TaskOperationContext context = new TaskOperationContext(bo, taskOperation); + LiteFlowUtils.execute(TASK_OPERATION_CHAIN, context); + return context.isResult(); + } + + /** + * 修改任务办理人(此方法将会批量修改所有任务的办理人) + * + * @param taskIdList 任务id + * @param userId 用户id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateAssignee(Collection taskIdList, String userId) { + if (CollUtil.isEmpty(taskIdList)) { + return false; + } + List flowTasks = this.selectByIdList(taskIdList); + // 批量删除现有任务的办理人记录 + if (CollUtil.isNotEmpty(flowTasks)) { + FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); + List userList = StreamUtils.toList(flowTasks, flowTask -> + new FlowUser() + .setType(TaskAssigneeType.APPROVER.getCode()) + .setProcessedBy(userId) + .setAssociated(flowTask.getId())); + if (CollUtil.isNotEmpty(userList)) { + FlowEngine.userService().saveBatch(userList); + } + } + return true; + } + + /** + * 获取当前任务的所有办理人 + * + * @param taskIds 任务id + */ + @Override + public List currentTaskAllUser(List taskIds) { + // 获取与当前任务关联的用户列表 + List userList = FlowEngine.userService().getByAssociateds(taskIds); + if (CollUtil.isEmpty(userList)) { + return Collections.emptyList(); + } + return userService.selectListByIds(StreamUtils.toSet(userList, e -> Convert.toLong(e.getProcessedBy()))); + } + + /** + * 按照节点编码查询节点 + * + * @param nodeCode 节点编码 + * @param definitionId 流程定义id + */ + @Override + public FlowNode getByNodeCode(String nodeCode, Long definitionId) { + return flowNodeMapper.selectOne(QueryBuilder.lambda(FlowNode.class) + .eq(FlowNode::getNodeCode, nodeCode) + .eq(FlowNode::getDefinitionId, definitionId) + .build()); + } + + /** + * 催办任务 + * + * @param bo 参数 + */ + @Override + public boolean urgeTask(FlowUrgeTaskBo bo) { + if (CollUtil.isEmpty(bo.getTaskIdList())) { + return false; + } + List userList = this.currentTaskAllUser(bo.getTaskIdList()); + if (CollUtil.isEmpty(userList)) { + return false; + } + List messageType = bo.getMessageType(); + String message = bo.getMessage(); + flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList, PATH_TASK_WAITING); + return true; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java new file mode 100644 index 000000000..add317aaa --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java @@ -0,0 +1,272 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.PageResult; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.workflow.api.WorkflowService; +import org.dromara.workflow.api.domain.StartProcessDTO; +import org.dromara.workflow.api.event.ProcessDeleteEvent; +import org.dromara.workflow.api.event.ProcessEvent; +import org.dromara.workflow.api.event.ProcessTaskEvent; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; +import org.dromara.workflow.mapper.TestLeaveMapper; +import org.dromara.workflow.service.ITestLeaveService; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.temporal.ChronoUnit; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 请假Service业务层处理 + * + * @author may + * @date 2023-07-21 + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +@Slf4j +public class TestLeaveServiceImpl implements ITestLeaveService { + + private final TestLeaveMapper leaveMapper; + private final WorkflowService workflowService; + + /** + * spel条件表达:判断小于2 + * + * @param leaveDays 待判断的变量(可不传自行返回true或false) + * @return boolean + */ + public boolean eval(Integer leaveDays) { + return leaveDays <= 2; + } + + /** + * 查询请假 + * + * @param id 主键 + * @return 请假详情 + */ + @Override + public TestLeaveVo queryById(Long id) { + return leaveMapper.selectVoById(id); + } + + /** + * 查询请假列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 请假分页列表 + */ + @Override + public PageResult queryPageList(TestLeaveBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = leaveMapper.selectVoPage(pageQuery.build(), lqw); + return PageResult.build(result.getRecords(), result.getTotal()); + } + + /** + * 查询请假列表 + * + * @param bo 查询条件 + * @return 请假列表 + */ + @Override + public List queryList(TestLeaveBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return leaveMapper.selectVoList(lqw); + } + + /** + * 构造请假列表查询条件。 + * + * @param bo 查询参数 + * @return 包含请假类型、天数区间和排序条件的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(TestLeaveBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getLeaveType()), TestLeave::getLeaveType, bo.getLeaveType()); + lqw.ge(bo.getStartLeaveDays() != null, TestLeave::getLeaveDays, bo.getStartLeaveDays()); + lqw.le(bo.getEndLeaveDays() != null, TestLeave::getLeaveDays, bo.getEndLeaveDays()); + lqw.orderByDesc(BaseEntity::getCreateTime); + return lqw; + } + + /** + * 新增请假 + * + * @param bo 请假业务对象 + * @return 新增后的请假详情 + */ + @Override + public TestLeaveVo insertByBo(TestLeaveBo bo) { + long day = ChronoUnit.DAYS.between(bo.getStartDate(), bo.getEndDate()); + // 截止日期也算一天 + bo.setLeaveDays((int) day + 1); + bo.setApplyCode(System.currentTimeMillis() + StrUtil.EMPTY); + TestLeave add = MapstructUtils.convert(bo, TestLeave.class); + if (StringUtils.isBlank(add.getStatus())) { + add.setStatus(BusinessStatusEnum.DRAFT.getStatus()); + } + boolean flag = leaveMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return MapstructUtils.convert(add, TestLeaveVo.class); + } + + /** + * 提交请假并同步发起审批流程。 + * + * @param bo 请假业务对象 + * @return 已落库并完成流程提交的请假详情 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public TestLeaveVo submitAndFlowStart(TestLeaveBo bo) { + long day = ChronoUnit.DAYS.between(bo.getStartDate(), bo.getEndDate()); + // 截止日期也算一天 + bo.setLeaveDays((int) day + 1); + if (ObjectUtil.isNull(bo.getId())) { + bo.setApplyCode(System.currentTimeMillis() + StrUtil.EMPTY); + } + TestLeave leave = MapstructUtils.convert(bo, TestLeave.class); + boolean flag = leaveMapper.insertOrUpdate(leave); + if (flag) { + bo.setId(leave.getId()); + // 后端发起需要忽略权限 + bo.getParams().put("ignore", true); + + StartProcessDTO startProcess = new StartProcessDTO(); + startProcess.setBusinessId(leave.getId().toString()); + startProcess.setFlowCode(StringUtils.isEmpty(bo.getFlowCode()) ? "leave1" : bo.getFlowCode()); + startProcess.setVariables(bo.getParams()); + // 后端发起 如果没有登录用户 比如定时任务 可以手动设置一个处理人id + // startProcess.setHandler("0"); + + boolean flag1 = workflowService.startCompleteTask(startProcess); + if (!flag1) { + throw new ServiceException("流程发起异常"); + } + } + return MapstructUtils.convert(leave, TestLeaveVo.class); + } + + /** + * 修改请假 + * + * @param bo 请假业务对象 + * @return 更新后的请假详情 + */ + @Override + public TestLeaveVo updateByBo(TestLeaveBo bo) { + TestLeave update = MapstructUtils.convert(bo, TestLeave.class); + leaveMapper.updateById(update); + return MapstructUtils.convert(update, TestLeaveVo.class); + } + + /** + * 批量删除请假 + * + * @param ids 主键集合 + * @return 删除成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids) { + boolean deleted = leaveMapper.deleteByIds(ids) > 0; + workflowService.deleteInstance(StreamUtils.toList(ids, Convert::toStr)); + return deleted; + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode.startsWith('leave')") + public void processHandler(ProcessEvent processEvent) { + log.info("当前任务执行了{}", processEvent.toString()); + TestLeave testLeave = leaveMapper.selectById(Convert.toLong(processEvent.getBusinessId())); + testLeave.setStatus(processEvent.getStatus()); + // 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程 + Map params = processEvent.getParams(); + if (MapUtil.isNotEmpty(params)) { + // 历史任务扩展(通常为附件) + String hisTaskExt = Convert.toStr(params.get("hisTaskExt")); + // 办理人 + String handler = Convert.toStr(params.get("handler")); + // 办理意见 + String message = Convert.toStr(params.get("message")); + } + if (processEvent.getSubmit()) { + if (StringUtils.isBlank(testLeave.getApplyCode())) { + String businessCode = MapUtil.getStr(params, FlowConstant.BUSINESS_CODE, StrUtil.EMPTY); + testLeave.setApplyCode(businessCode); + } + testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus()); + log.info("申请人提交"); + } + String status = BusinessStatusEnum.findByStatus(processEvent.getStatus()); + log.info("当前流程状态为{}", status); + leaveMapper.updateById(testLeave); + } + + /** + * 执行任务创建监听(也代表上一条任务完成事件) + * 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.startsWith('leave')") + public void processTaskHandler(ProcessTaskEvent processTaskEvent) { + log.info("当前任务创建了{}", processTaskEvent.toString()); + } + + /** + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @EventListener(condition = "#processDeleteEvent.flowCode.startsWith('leave')") + public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString()); + TestLeave testLeave = leaveMapper.selectById(Convert.toLong(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(testLeave)) { + return; + } + leaveMapper.deleteById(testLeave.getId()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java new file mode 100644 index 000000000..3955d163a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java @@ -0,0 +1,173 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.api.WorkflowService; +import org.dromara.workflow.api.domain.CompleteTaskDTO; +import org.dromara.workflow.api.domain.StartProcessDTO; +import org.dromara.workflow.api.domain.StartProcessReturnDTO; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.MessageTypeEnum; +import org.dromara.workflow.domain.FlowInstanceBizExt; +import org.dromara.workflow.domain.bo.CompleteTaskBo; +import org.dromara.workflow.domain.bo.StartProcessBo; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 通用 工作流服务实现 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +public class WorkflowServiceImpl implements WorkflowService { + + private final IFlwInstanceService flwInstanceService; + private final IFlwTaskService flwTaskService; + + /** + * 删除流程实例 + * + * @param businessIds 业务id + * @return 结果 + */ + @Override + public boolean deleteInstance(List businessIds) { + return flwInstanceService.deleteByBusinessIds(businessIds); + } + + /** + * 获取当前流程状态 + * + * @param taskId 任务id + * @return 任务关联流程实例的业务状态,未查询到时返回空字符串 + */ + @Override + public String getBusinessStatusByTaskId(Long taskId) { + FlowInstance flowInstance = flwInstanceService.selectByTaskId(taskId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY; + } + + /** + * 获取当前流程状态 + * + * @param businessId 业务id + * @return 业务单据对应的流程状态,未查询到时返回空字符串 + */ + @Override + public String getBusinessStatus(String businessId) { + FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY; + } + + /** + * 设置流程变量 + * + * @param instanceId 流程实例id + * @param variables 流程变量 + */ + @Override + public void setVariable(Long instanceId, Map variables) { + flwInstanceService.setVariable(instanceId, variables); + } + + /** + * 获取流程变量 + * + * @param instanceId 流程实例id + * @return 实例变量信息 + */ + @Override + public Map instanceVariable(Long instanceId) { + return flwInstanceService.instanceVariable(instanceId); + } + + /** + * 按照业务id查询流程实例id + * + * @param businessId 业务id + * @return 结果 + */ + @Override + public Long getInstanceIdByBusinessId(String businessId) { + FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getId() : null; + } + + /** + * 启动流程 + * + * @param startProcess 参数 + * @return 启动后的流程实例和首个任务信息 + */ + @Override + public StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess) { + return flwTaskService.startWorkFlow(BeanUtil.toBean(startProcess, StartProcessBo.class)); + } + + /** + * 办理任务 + * 系统后台发起审批 无用户信息 需要忽略权限 + * completeTask.getVariables().put("ignore", true); + * + * @param completeTask 参数 + * @return 办理成功返回 {@code true} + */ + @Override + public boolean completeTask(CompleteTaskDTO completeTask) { + return flwTaskService.completeTask(BeanUtil.toBean(completeTask, CompleteTaskBo.class)); + } + + /** + * 办理任务 + * + * @param taskId 任务ID + * @param message 办理意见 + * @return 办理成功返回 {@code true} + */ + @Override + public boolean completeTask(Long taskId, String message) { + CompleteTaskBo completeTask = new CompleteTaskBo(); + completeTask.setTaskId(taskId); + completeTask.setMessage(message); + // 忽略权限(系统后台发起审批 无用户信息 需要忽略权限) + completeTask.getVariables().put("ignore", true); + return flwTaskService.completeTask(completeTask); + } + + /** + * 启动流程并办理第一个任务 + * + * @param startProcess 参数 + * @return 首节点办理成功返回 {@code true} + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean startCompleteTask(StartProcessDTO startProcess) { + StartProcessBo processBo = new StartProcessBo(); + processBo.setBusinessId(startProcess.getBusinessId()); + processBo.setFlowCode(startProcess.getFlowCode()); + processBo.setVariables(startProcess.getVariables()); + processBo.setHandler(startProcess.getHandler()); + processBo.setBizExt(BeanUtil.toBean(startProcess.getBizExt(), FlowInstanceBizExt.class)); + + StartProcessReturnDTO result = flwTaskService.startWorkFlow(processBo); + CompleteTaskBo taskBo = new CompleteTaskBo(); + taskBo.setTaskId(result.taskId()); + taskBo.setMessageType(Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode())); + taskBo.setVariables(startProcess.getVariables()); + taskBo.setHandler(startProcess.getHandler()); + return flwTaskService.completeTask(taskBo); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/liteflow/instance-chain.el.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/liteflow/instance-chain.el.xml new file mode 100644 index 000000000..c37beb7d8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/liteflow/instance-chain.el.xml @@ -0,0 +1,22 @@ + + + + + THEN( + instanceDeleteLoad, + IF( + instanceDeleteExists, + THEN( + instanceDeleteEvent, + instanceDeleteExecute + ), + noop + ) + ); + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/liteflow/task-chain.el.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/liteflow/task-chain.el.xml new file mode 100644 index 000000000..772243388 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/liteflow/task-chain.el.xml @@ -0,0 +1,61 @@ + + + + + THEN( + startPrepareRequest, + IF( + startExists, + startResume, + THEN( + startPrepareInstance, + startExecute + ) + ) + ); + + + + + THEN( + completePrepare, + completeExecute, + IF( + completeNeedAutoPass, + completeAutoPass, + noop + ) + ); + + + + + THEN( + taskOpPrepare, + taskOpLoad, + taskOpExecute, + IF( + taskOpNeedNotify, + taskOpNotify, + noop + ) + ); + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md new file mode 100644 index 000000000..c938b1e50 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml new file mode 100644 index 000000000..10c948d85 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwHisTaskMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwHisTaskMapper.xml new file mode 100644 index 000000000..420e4f9a1 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwHisTaskMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceBizExtMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceBizExtMapper.xml new file mode 100644 index 000000000..c2cc9c7c6 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceBizExtMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml new file mode 100644 index 000000000..c86c5844c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwSpelMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwSpelMapper.xml new file mode 100644 index 000000000..03355f6a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwSpelMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml new file mode 100644 index 000000000..3e9bdc881 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwUserMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwUserMapper.xml new file mode 100644 index 000000000..6c6389da9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwUserMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml new file mode 100644 index 000000000..d52f6b037 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/script/bin/ry.bat b/script/bin/ry.bat new file mode 100644 index 000000000..ea98cbed0 --- /dev/null +++ b/script/bin/ry.bat @@ -0,0 +1,68 @@ +rem 使用者应根据自身平台编码自行转换 防止乱码 例如 win使用gbk编码 +@echo off + +rem jar平级目录 +set AppName=ruoyi-admin.jar + +rem JVM参数 +set JVM_OPTS="-Dname=%AppName% -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC" + + +ECHO. + ECHO. [1] 启动%AppName% + ECHO. [2] 关闭%AppName% + ECHO. [3] 重启%AppName% + ECHO. [4] 启动状态 %AppName% + ECHO. [5] 退 出 +ECHO. + +ECHO.请输入选择项目的序号: +set /p ID= + IF "%id%"=="1" GOTO start + IF "%id%"=="2" GOTO stop + IF "%id%"=="3" GOTO restart + IF "%id%"=="4" GOTO status + IF "%id%"=="5" EXIT +PAUSE +:start + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if defined pid ( + echo %%is running + PAUSE + ) + +start javaw %JVM_OPTS% -jar %AppName% + +echo starting…… +echo Start %AppName% success... +goto:eof + +rem 函数stop通过jps命令查找pid并结束进程 +:stop + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% does not exists) else ( + echo prepare to kill %image_name% + echo start kill %pid% ... + rem 根据进程ID,kill进程 + taskkill /f /pid %pid% + ) +goto:eof +:restart + call :stop + call :start +goto:eof +:status + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% is dead ) else ( + echo %image_name% is running + ) +goto:eof diff --git a/script/bin/ry.sh b/script/bin/ry.sh new file mode 100644 index 000000000..a6f5d9cba --- /dev/null +++ b/script/bin/ry.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# ./ry.sh start 启动 stop 停止 restart 重启 status 状态 +AppName=ruoyi-admin.jar + +# JVM参数 +JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC" +APP_HOME=`pwd` +LOG_PATH=$APP_HOME/logs/$AppName.log + +if [ "$1" = "" ]; +then + echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m" + exit 1 +fi + +if [ "$AppName" = "" ]; +then + echo -e "\033[0;31m 未输入应用名 \033[0m" + exit 1 +fi + +function start() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + + if [ x"$PID" != x"" ]; then + echo "$AppName is running..." + else + nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 & + echo "Start $AppName success..." + fi +} + +function stop() +{ + echo "Stop $AppName" + + PID="" + query(){ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + } + + query + if [ x"$PID" != x"" ]; then + kill -TERM $PID + echo "$AppName (pid:$PID) exiting..." + while [ x"$PID" != x"" ] + do + sleep 1 + query + done + echo "$AppName exited." + else + echo "$AppName already stopped." + fi +} + +function restart() +{ + stop + sleep 2 + start +} + +function status() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l` + if [ $PID != 0 ];then + echo "$AppName is running..." + else + echo "$AppName is not running..." + fi +} + +case $1 in + start) + start;; + stop) + stop;; + restart) + restart;; + status) + status;; + *) + +esac diff --git a/script/docker/database.yml b/script/docker/database.yml new file mode 100644 index 000000000..6034b39c4 --- /dev/null +++ b/script/docker/database.yml @@ -0,0 +1,59 @@ +services: + # 此镜像仅用于测试 正式环境需自行安装数据库 + # SID: XE user: system password: oracle + oracle: + image: tekintian/oracle12c:latest + container_name: oracle + environment: + # 时区上海 + TZ: Asia/Shanghai + DBCA_TOTAL_MEMORY: 16192 + ports: + - "18080:8080" + - "1521:1521" + volumes: + # 数据挂载 + - "/docker/oracle/data:/u01/app/oracle" + network_mode: "host" + + # 此镜像仅用于测试 正式环境需自行安装数据库 + sqlserver: + image: mcr.microsoft.com/mssql/server:2017-latest + container_name: sqlserver + environment: + # 时区上海 + TZ: Asia/Shanghai + ACCEPT_EULA: "Y" + SA_PASSWORD: "Ruoyi@123" + ports: + - "1433:1433" + volumes: + # 数据挂载 + - "/docker/sqlserver/data:/var/opt/mssql" + network_mode: "host" + + postgres: + image: postgres:14.2 + container_name: postgres + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: postgres + ports: + - "5432:5432" + volumes: + - /docker/postgres/data:/var/lib/postgresql/data + network_mode: "host" + + postgres13: + image: postgres:13.6 + container_name: postgres13 + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: postgres + ports: + - "5433:5432" + volumes: + - /docker/postgres13/data:/var/lib/postgresql/data + network_mode: "host" diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml new file mode 100644 index 000000000..9a293c389 --- /dev/null +++ b/script/docker/docker-compose.yml @@ -0,0 +1,176 @@ +services: + mysql: + image: mysql:8.4.9 + container_name: mysql + environment: + # 时区上海 + TZ: Asia/Shanghai + # root 密码 + MYSQL_ROOT_PASSWORD: root + # 初始化数据库(后续的初始化sql会在这个库执行) + MYSQL_DATABASE: ry-vue + ports: + - "3306:3306" + volumes: + # 数据挂载 + - /docker/mysql/data/:/var/lib/mysql/ + # 配置挂载 + - /docker/mysql/conf/:/etc/mysql/conf.d/ + command: + --character-set-server=utf8mb4 + --collation-server=utf8mb4_general_ci + --explicit_defaults_for_timestamp=true + --lower_case_table_names=1 + privileged: true + network_mode: "host" + + nginx-web: + image: nginx:1.31.1 + container_name: nginx-web + environment: + # 时区上海 + TZ: Asia/Shanghai + ports: + - "80:80" + - "443:443" + volumes: + # 证书映射 + - /docker/nginx/cert:/etc/nginx/cert + # 配置文件映射 + - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf + # 页面目录 + - /docker/nginx/html:/usr/share/nginx/html + # 日志目录 + - /docker/nginx/log:/var/log/nginx + privileged: true + network_mode: "host" + + redis: + image: redis:8.6.3 + container_name: redis + ports: + - "6379:6379" + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/redis/conf:/redis/config:rw + # 数据文件 + - /docker/redis/data/:/redis/data/:rw + command: "redis-server /redis/config/redis.conf" + privileged: true + network_mode: "host" + + minio: + # pgsty 开源社区 fork 重新维护的最新版 minio + image: pgsty/minio:RELEASE.2026-04-17T00-00-00Z + container_name: minio + ports: + # api 端口 + - "9000:9000" + # 控制台端口 + - "9001:9001" + environment: + # 时区上海 + TZ: Asia/Shanghai + # 管理后台用户名 + MINIO_ROOT_USER: ruoyi + # 管理后台密码,最小8个字符 + MINIO_ROOT_PASSWORD: ruoyi123 + # https需要指定域名 + #MINIO_SERVER_URL: "https://xxx.com:9000" + #MINIO_BROWSER_REDIRECT_URL: "https://xxx.com:9001" + # 开启压缩 on 开启 off 关闭 + MINIO_COMPRESS: "off" + # 扩展名 .pdf,.doc 为空 所有类型均压缩 + MINIO_COMPRESS_EXTENSIONS: "" + # mime 类型 application/pdf 为空 所有类型均压缩 + MINIO_COMPRESS_MIME_TYPES: "" + volumes: + # 映射当前目录下的data目录至容器内/data目录 + - /docker/minio/data:/data + # 映射配置目录 + - /docker/minio/config:/root/.minio/ + command: server --address ':9000' --console-address ':9001' /data # 指定容器中的目录 /data + privileged: true + network_mode: "host" + + ruoyi-server1: + image: ruoyi/ruoyi-server:6.0.0 + container_name: ruoyi-server1 + environment: + # 时区上海 + TZ: Asia/Shanghai + SERVER_PORT: 8080 + SNAIL_JOB_PORT: 28080 + SNAIL_AI_PORT: 38080 + volumes: + # 配置文件 + - /docker/server1/logs/:/ruoyi/server/logs/ + # skywalking 探针 +# - /docker/skywalking/agent/:/ruoyi/skywalking/agent + privileged: true + network_mode: "host" + + ruoyi-server2: + image: ruoyi/ruoyi-server:6.0.0 + container_name: ruoyi-server2 + environment: + # 时区上海 + TZ: Asia/Shanghai + SERVER_PORT: 8081 + SNAIL_JOB_PORT: 28081 + SNAIL_AI_PORT: 38081 + volumes: + # 配置文件 + - /docker/server2/logs/:/ruoyi/server/logs/ + # skywalking 探针 +# - /docker/skywalking/agent/:/ruoyi/skywalking/agent + privileged: true + network_mode: "host" + + ruoyi-monitor-admin: + image: ruoyi/ruoyi-monitor-admin:6.0.0 + container_name: ruoyi-monitor-admin + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/monitor/logs/:/ruoyi/monitor/logs + privileged: true + network_mode: "host" + + ruoyi-snailjob-server: + image: ruoyi/ruoyi-snailjob-server:6.0.0 + container_name: ruoyi-snailjob-server + environment: + # 时区上海 + TZ: Asia/Shanghai + ports: + - "8800:8800" + - "17888:17888" + volumes: + - /docker/snailjob/logs/:/ruoyi/snailjob/logs + privileged: true + network_mode: "host" + + ruoyi-snailai-server: + image: ruoyi/ruoyi-snailai-server:6.0.0 + container_name: ruoyi-snailai-server + environment: + # 时区上海 + TZ: Asia/Shanghai + # Docling 与 PaddleOCR 服务需单独部署;host 网络模式下默认通过宿主机端口访问 + SNAIL_AI_RAG_DOCLING_ENABLED: ${SNAIL_AI_RAG_DOCLING_ENABLED:-true} + SNAIL_AI_RAG_DOCLING_URL: ${SNAIL_AI_RAG_DOCLING_URL:-http://127.0.0.1:5100} + SNAIL_AI_RAG_DOCLING_PADDLE_OCR_ENABLED: ${SNAIL_AI_RAG_DOCLING_PADDLE_OCR_ENABLED:-true} + SNAIL_AI_RAG_DOCLING_PADDLE_OCR_URL: ${SNAIL_AI_RAG_DOCLING_PADDLE_OCR_URL:-http://127.0.0.1:8866/ocr} + ports: + - "8900:8900" + - "18888:18888" + volumes: + - /docker/snailai/logs/:/ruoyi/snailai/logs + privileged: true + network_mode: "host" diff --git a/script/docker/nginx/conf/nginx.conf b/script/docker/nginx/conf/nginx.conf new file mode 100644 index 000000000..ad70f5642 --- /dev/null +++ b/script/docker/nginx/conf/nginx.conf @@ -0,0 +1,181 @@ +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + # 可以根据业务并发量适当调高 + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + # 高效传输文件 + sendfile on; + # 长连接超时时间 + keepalive_timeout 65; + # 单连接最大请求数,提高长连接复用率 + keepalive_requests 100000; + # 限制body大小 + client_max_body_size 100m; + client_header_buffer_size 32k; + client_body_buffer_size 512k; + # 开启静态资源压缩 + gzip_static on; + # 连接数限制 (防御类配置) 10m 一般够用了,能存储上万 IP 的计数 + limit_conn_zone $binary_remote_addr zone=perip:10m; + limit_conn_zone $server_name zone=perserver:10m; + # 隐藏 nginx 版本号,防止暴露版本信息 + server_tokens off; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + upstream server { + ip_hash; + server 127.0.0.1:8080; + server 127.0.0.1:8081; + } + + upstream monitor-admin { + server 127.0.0.1:9090; + } + + upstream snailjob-server { + server 127.0.0.1:8800; + } + + upstream snailai-server { + server 127.0.0.1:8900; + } + + server { + listen 80; + server_name localhost; + + # https配置参考 start + #listen 443 ssl; + + # 证书直接存放 /docker/nginx/cert/ 目录下即可 更改证书名称即可 无需更改证书路径 + #ssl_certificate /etc/nginx/cert/xxx.local.crt; # /etc/nginx/cert/ 为docker映射路径 不允许更改 + #ssl_certificate_key /etc/nginx/cert/xxx.local.key; # /etc/nginx/cert/ 为docker映射路径 不允许更改 + #ssl_session_timeout 5m; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; + #ssl_protocols TLSv1.3 TLSv1.2; + #ssl_prefer_server_ciphers on; + # https配置参考 end + + # 演示环境配置 拦截除 GET POST 之外的所有请求 + # if ($request_method !~* GET|POST) { + # rewrite ^/(.*)$ /403; + # } + + # location = /403 { + # default_type application/json; + # return 200 '{"msg":"演示模式,不允许操作","code":500}'; + # } + + # 限制外网访问内网 actuator 相关路径 + location ~ ^(/[^/]*)?/actuator.*(/.*)?$ { + return 403; + } + + location / { + root /usr/share/nginx/html; # docker映射路径 不允许更改 + try_files $uri $uri/ /index.html; + index index.html index.htm; + } + + location /prod-api/ { + # 设置客户端请求头中的 Host 信息(保持原始 Host) + proxy_set_header Host $http_host; + # 获取客户端真实 IP + proxy_set_header X-Real-IP $remote_addr; + # 自定义头 REMOTE-HOST,记录客户端 IP + proxy_set_header REMOTE-HOST $remote_addr; + # 获取完整的客户端 IP 链(经过多级代理时) + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # 设置后端响应超时时间(这里是 24 小时,适合长连接/SSE) + proxy_read_timeout 86400s; + # SSE (Server-Sent Events) 与 WebSocket 支持参数 + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + # 禁用代理缓冲,数据直接传给客户端 + proxy_buffering off; + # 禁用代理缓存 + proxy_cache off; + proxy_pass http://server/; + } + + # https 会拦截内链所有的 http 请求 造成功能无法使用 + # 解决方案1 将 admin 服务 也配置成 https + # 解决方案2 将菜单配置为外链访问 走独立页面 http 访问 + location /admin/ { + # 设置客户端请求头中的 Host 信息(保持原始 Host) + proxy_set_header Host $http_host; + # 获取客户端真实 IP + proxy_set_header X-Real-IP $remote_addr; + # 自定义头 REMOTE-HOST,记录客户端 IP + proxy_set_header REMOTE-HOST $remote_addr; + # 获取完整的客户端 IP 链(经过多级代理时) + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # 禁用代理缓冲,数据直接传给客户端 + proxy_buffering off; + # 禁用代理缓存 + proxy_cache off; + proxy_pass http://monitor-admin/admin/; + } + + location /snail-job/ { + # 设置客户端请求头中的 Host 信息(保持原始 Host) + proxy_set_header Host $http_host; + # 获取客户端真实 IP + proxy_set_header X-Real-IP $remote_addr; + # 自定义头 REMOTE-HOST,记录客户端 IP + proxy_set_header REMOTE-HOST $remote_addr; + # 获取完整的客户端 IP 链(经过多级代理时) + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # SSE (Server-Sent Events) 与 WebSocket 支持参数 + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + # 禁用代理缓冲,直接传输给客户端 + proxy_buffering off; + # 禁用代理缓存 + proxy_cache off; + proxy_pass http://snailjob-server/snail-job/; + } + + location /snail-ai/ { + # 设置客户端请求头中的 Host 信息(保持原始 Host) + proxy_set_header Host $http_host; + # 获取客户端真实 IP + proxy_set_header X-Real-IP $remote_addr; + # 自定义头 REMOTE-HOST,记录客户端 IP + proxy_set_header REMOTE-HOST $remote_addr; + # 获取完整的客户端 IP 链(经过多级代理时) + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # 设置后端响应超时时间(这里是 24 小时,适合长连接/SSE) + proxy_read_timeout 86400s; + # SSE (Server-Sent Events) 与 WebSocket 支持参数 + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + # 禁用代理缓冲,直接传输给客户端 + proxy_buffering off; + # 禁用代理缓存 + proxy_cache off; + proxy_pass http://snailai-server/snail-ai/; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } +} diff --git a/script/docker/redis/conf/redis.conf b/script/docker/redis/conf/redis.conf new file mode 100644 index 000000000..72255c617 --- /dev/null +++ b/script/docker/redis/conf/redis.conf @@ -0,0 +1,28 @@ +# redis 密码 +requirepass ruoyi123 + +# key 监听器配置 +# notify-keyspace-events Ex + +# 配置持久化文件存储路径 +dir /redis/data +# 配置rdb +# 15分钟内有至少1个key被更改则进行快照 +save 900 1 +# 5分钟内有至少10个key被更改则进行快照 +save 300 10 +# 1分钟内有至少10000个key被更改则进行快照 +save 60 10000 +# 开启压缩 +rdbcompression yes +# rdb文件名 用默认的即可 +dbfilename dump.rdb + +# 开启aof +appendonly yes +# 文件名 +appendfilename "appendonly.aof" +# 持久化策略,no:不同步,everysec:每秒一次,always:总是同步,速度比较慢 +# appendfsync always +appendfsync everysec +# appendfsync no diff --git a/script/docker/redis/data/README.md b/script/docker/redis/data/README.md new file mode 100644 index 000000000..fbc5474bc --- /dev/null +++ b/script/docker/redis/data/README.md @@ -0,0 +1 @@ +数据目录 请执行 `chmod 777 /docker/redis/data` 赋予读写权限 否则将无法写入数据 \ No newline at end of file diff --git a/script/leave/leave1.json b/script/leave/leave1.json new file mode 100644 index 000000000..9abf1c7d7 --- /dev/null +++ b/script/leave/leave1.json @@ -0,0 +1,129 @@ +{ + "nodeList": [ + { + "nodeType": "0", + "nodeCode": "d5ee3ddf-3968-4379-a86f-9ceabde5faac", + "nodeName": "开始", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "200,200|200,200", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "d5ee3ddf-3968-4379-a86f-9ceabde5faac", + "nextNodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42", + "coordinate": "220,200;310,200" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42", + "nodeName": "申请人", + "permissionFlag": "${initiator}", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,copy\"}]", + "coordinate": "360,200|360,200", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42", + "nextNodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf", + "coordinate": "410,200;490,200" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf", + "nodeName": "组长", + "permissionFlag": "role:1761300000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,copy,transfer,trust,file\"}]", + "coordinate": "540,200|540,200", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf", + "nextNodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "coordinate": "590,200;670,200" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "nodeName": "部门主管", + "permissionFlag": "role:1761300000000000003@@role:1761300000000000004", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,copy,transfer,trust,file\"}]", + "coordinate": "720,200|720,200", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "nextNodeCode": "8b82b7d7-8660-455e-b880-d6d22ea3eb6d", + "coordinate": "770,200;880,200" + } + ] + }, + { + "nodeType": "2", + "nodeCode": "8b82b7d7-8660-455e-b880-d6d22ea3eb6d", + "nodeName": "结束", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "900,200|900,200", + "version": "1", + "skipList": [] + } + ], + "flowCode": "leave1", + "flowName": "请假申请-普通", + "modelValue": "CLASSICS", + "category": "1762300000000000103", + "version": "1", + "formCustom": "N", + "formPath": "/workflow/leaveEdit/index", + "listenerType": null, + "listenerPath": null +} diff --git a/script/leave/leave2.json b/script/leave/leave2.json new file mode 100644 index 000000000..262697cb8 --- /dev/null +++ b/script/leave/leave2.json @@ -0,0 +1,187 @@ +{ + "nodeList": [ + { + "nodeType": "0", + "nodeCode": "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a", + "nodeName": "开始", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "300,240|300,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a", + "nextNodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd", + "coordinate": "320,240;390,240" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd", + "nodeName": "申请人", + "permissionFlag": "${initiator}", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]", + "coordinate": "440,240|440,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd", + "nextNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "coordinate": "490,240;535,240" + } + ] + }, + { + "nodeType": "3", + "nodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "560,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": "le@@leaveDays|2", + "skipName": null, + "nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "nextNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "coordinate": "560,265;560,320;670,320" + }, + { + "skipType": "PASS", + "skipCondition": "gt@@leaveDays|2", + "skipName": "大于两天", + "nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "nextNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605", + "coordinate": "560,215;560,160;670,160|560,187" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "nodeName": "组长", + "permissionFlag": "1761100000000000003@@1761100000000000004", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]", + "coordinate": "720,320|720,320", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "nextNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "coordinate": "770,320;860,320;860,280" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "nodeName": "总经理", + "permissionFlag": "role:1761300000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]", + "coordinate": "860,240|860,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "nextNodeCode": "40aa65fd-0712-4d23-b6f7-d0432b920fd1", + "coordinate": "910,240;980,240" + } + ] + }, + { + "nodeType": "2", + "nodeCode": "40aa65fd-0712-4d23-b6f7-d0432b920fd1", + "nodeName": "结束", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "1000,240|1000,240", + "version": "1", + "skipList": [] + }, + { + "nodeType": "1", + "nodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605", + "nodeName": "部门领导", + "permissionFlag": "role:1761300000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]", + "coordinate": "720,160|720,160", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605", + "nextNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "nextNodeType": "1", + "coordinate": "770,160;860,160;860,200" + } + ] + } + ], + "flowCode": "leave2", + "flowName": "请假申请-排他网关", + "modelValue": "CLASSICS", + "category": "1762300000000000103", + "version": "1", + "formCustom": "N", + "formPath": "/workflow/leaveEdit/index", + "listenerType": null, + "listenerPath": null +} diff --git a/script/leave/leave3.json b/script/leave/leave3.json new file mode 100644 index 000000000..1ac01e2bb --- /dev/null +++ b/script/leave/leave3.json @@ -0,0 +1,211 @@ +{ + "nodeList": [ + { + "nodeType": "0", + "nodeCode": "a80ecf9f-f465-4ae5-a429-e30ec5d0f957", + "nodeName": "开始", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "380,220|380,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "a80ecf9f-f465-4ae5-a429-e30ec5d0f957", + "nextNodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99", + "coordinate": "400,220;470,220" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99", + "nodeName": "申请人", + "permissionFlag": "${initiator}", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]", + "coordinate": "520,220|520,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99", + "nextNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "coordinate": "570,220;655,220" + } + ] + }, + { + "nodeType": "4", + "nodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "680,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "nextNodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "coordinate": "680,195;680,140;750,140" + }, + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "nextNodeCode": "762cb975-37d8-4276-b6db-79a4c3606394", + "coordinate": "680,245;680,300;750,300" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "nodeName": "市场部", + "permissionFlag": "role:1761300000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]", + "coordinate": "800,140|800,140", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "nextNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "coordinate": "850,140;920,140;920,195" + } + ] + }, + { + "nodeType": "4", + "nodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "920,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "nextNodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6", + "coordinate": "945,220;975,220;975,220;960,220;960,220;990,220" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6", + "nodeName": "CEO", + "permissionFlag": "1761100000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]", + "coordinate": "1040,220|1040,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6", + "nextNodeCode": "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1", + "coordinate": "1090,220;1140,220" + } + ] + }, + { + "nodeType": "2", + "nodeCode": "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1", + "nodeName": "结束", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "1160,220|1160,220", + "version": "1", + "skipList": [] + }, + { + "nodeType": "1", + "nodeCode": "762cb975-37d8-4276-b6db-79a4c3606394", + "nodeName": "综合部", + "permissionFlag": "role:1761300000000000003@@role:1761300000000000004", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]", + "coordinate": "800,300|800,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "762cb975-37d8-4276-b6db-79a4c3606394", + "nextNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "nextNodeType": "4", + "coordinate": "850,300;920,300;920,245" + } + ] + } + ], + "flowCode": "leave3", + "flowName": "请假申请-并行网关", + "modelValue": "CLASSICS", + "category": "1762300000000000103", + "version": "1", + "formCustom": "N", + "formPath": "/workflow/leaveEdit/index", + "listenerType": null, + "listenerPath": null +} diff --git a/script/leave/leave4.json b/script/leave/leave4.json new file mode 100644 index 000000000..7e2f57820 --- /dev/null +++ b/script/leave/leave4.json @@ -0,0 +1,154 @@ +{ + "nodeList": [ + { + "nodeType": "0", + "nodeCode": "9ce8bf00-f25b-4fc6-91b8-827082fc4876", + "nodeName": "开始", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "320,240|320,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "9ce8bf00-f25b-4fc6-91b8-827082fc4876", + "nextNodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "coordinate": "340,240;410,240" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "nodeName": "申请人", + "permissionFlag": "${initiator}", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]", + "coordinate": "460,240|460,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "nextNodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "coordinate": "510,240;590,240" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "nodeName": "百分之60通过", + "permissionFlag": "${userList}", + "nodeRatio": "60.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]", + "coordinate": "640,240|640,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "nextNodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "coordinate": "690,240;770,240" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "nodeName": "全部审批通过", + "permissionFlag": "role:1761300000000000001@@role:1761300000000000003", + "nodeRatio": "100.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]", + "coordinate": "820,240|820,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "nextNodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "coordinate": "870,240;950,240" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "nodeName": "CEO", + "permissionFlag": "1761100000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]", + "coordinate": "1000,240|1000,240", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "nextNodeCode": "b62b88c3-8d8d-4969-911e-2aaea219e7fc", + "coordinate": "1050,240;1080,240;1080,240;1070,240;1070,240;1100,240" + } + ] + }, + { + "nodeType": "2", + "nodeCode": "b62b88c3-8d8d-4969-911e-2aaea219e7fc", + "nodeName": "结束", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "1120,240|1120,240", + "version": "1", + "skipList": [] + } + ], + "flowCode": "leave4", + "flowName": "请假申请-会签", + "modelValue": "CLASSICS", + "category": "1762300000000000103", + "version": "1", + "formCustom": "N", + "formPath": "/workflow/leaveEdit/index", + "listenerType": null, + "listenerPath": null +} diff --git a/script/leave/leave5.json b/script/leave/leave5.json new file mode 100644 index 000000000..2cd24a00d --- /dev/null +++ b/script/leave/leave5.json @@ -0,0 +1,211 @@ +{ + "nodeList": [ + { + "nodeType": "0", + "nodeCode": "ebebaf26-9cb6-497e-8119-4c9fed4c597c", + "nodeName": "开始", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "300,220|300,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "ebebaf26-9cb6-497e-8119-4c9fed4c597c", + "nextNodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374", + "coordinate": "320,220;350,220;350,220;340,220;340,220;370,220" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374", + "nodeName": "申请人", + "permissionFlag": "${initiator}", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]", + "coordinate": "420,220|420,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374", + "nextNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "coordinate": "470,220;535,220" + } + ] + }, + { + "nodeType": "4", + "nodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "560,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "nextNodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "coordinate": "560,245;560,320;650,320" + }, + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "nextNodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "coordinate": "560,195;560,120;650,120" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "nodeName": "会签", + "permissionFlag": "role:1761300000000000001@@role:1761300000000000003", + "nodeRatio": "100.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]", + "coordinate": "700,320|700,320", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "nextNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b", + "coordinate": "750,320;860,320;860,245" + } + ] + }, + { + "nodeType": "4", + "nodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "860,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b", + "nextNodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9", + "coordinate": "885,220;950,220" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9", + "nodeName": "CEO", + "permissionFlag": "1761100000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]", + "coordinate": "1000,220|1000,220", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9", + "nextNodeCode": "03c4d2bc-58b5-4408-a2e4-65afb046f169", + "coordinate": "1050,220;1120,220" + } + ] + }, + { + "nodeType": "2", + "nodeCode": "03c4d2bc-58b5-4408-a2e4-65afb046f169", + "nodeName": "结束", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "1140,220|1140,220", + "version": "1", + "skipList": [] + }, + { + "nodeType": "1", + "nodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "nodeName": "百分之60票签", + "permissionFlag": "${userList}", + "nodeRatio": "60.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]", + "coordinate": "700,120|700,120", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "nextNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b", + "nextNodeType": "4", + "coordinate": "750,120;860,120;860,195" + } + ] + } + ], + "flowCode": "leave5", + "flowName": "请假申请-并行会签网关", + "modelValue": "CLASSICS", + "category": "1762300000000000103", + "version": "1", + "formCustom": "N", + "formPath": "/workflow/leaveEdit/index", + "listenerType": null, + "listenerPath": null +} diff --git a/script/leave/leave6.json b/script/leave/leave6.json new file mode 100644 index 000000000..348eb5c54 --- /dev/null +++ b/script/leave/leave6.json @@ -0,0 +1,368 @@ +{ + "nodeList": [ + { + "nodeType": "0", + "nodeCode": "122b89a5-7c6f-40a3-aa09-7a263f902054", + "nodeName": "开始", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "240,300|240,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "122b89a5-7c6f-40a3-aa09-7a263f902054", + "nextNodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd", + "coordinate": "260,300;350,300" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd", + "nodeName": "申请人", + "permissionFlag": "${initiator}", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]", + "coordinate": "400,300|400,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd", + "nextNodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742", + "coordinate": "450,300;510,300" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9", + "nodeName": "副经理", + "permissionFlag": "role:1761300000000000001@@role:1761300000000000003@@role:1761300000000000004", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "coordinate": "860,200|860,200", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9", + "nextNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32", + "coordinate": "910,200;1000,200;1000,275" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60", + "nodeName": "组长", + "permissionFlag": "1761100000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "coordinate": "860,400|860,400", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60", + "nextNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32", + "coordinate": "910,400;1000,400;1000,325" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742", + "nodeName": "副组长", + "permissionFlag": "1761100000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,transfer,copy,pop\"}]", + "coordinate": "560,300|560,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742", + "nextNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13", + "coordinate": "610,300;675,300" + } + ] + }, + { + "nodeType": "3", + "nodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "700,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": "default@@${leaveDays > 2}", + "skipName": "大于两天", + "nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13", + "nextNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9", + "nextNodeType": "1", + "coordinate": "700,275;700,200;810,200|700,237" + }, + { + "skipType": "PASS", + "skipCondition": "spel@@#{@testLeaveServiceImpl.eval(#leaveDays)}", + "skipName": null, + "nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13", + "nextNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60", + "nextNodeType": "1", + "coordinate": "700,325;700,400;810,400" + } + ] + }, + { + "nodeType": "3", + "nodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "1000,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32", + "nextNodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496", + "coordinate": "1025,300;1130,300" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496", + "nodeName": "经理会签", + "permissionFlag": "1761100000000000001@@1761100000000000003", + "nodeRatio": "100.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,pop,addSign,subSign\"}]", + "coordinate": "1180,300|1180,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496", + "nextNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992", + "coordinate": "1230,300;1315,300" + } + ] + }, + { + "nodeType": "4", + "nodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "1340,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992", + "nextNodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5", + "coordinate": "1340,325;1340,400;1430,400" + }, + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992", + "nextNodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4", + "coordinate": "1340,275;1340,200;1430,200" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4", + "nodeName": "总经理", + "permissionFlag": "1761100000000000001@@1761100000000000003", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "coordinate": "1480,200|1480,200", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4", + "nextNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519", + "coordinate": "1530,200;1640,200;1640,275" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5", + "nodeName": "副总经理", + "permissionFlag": "1761100000000000001@@1761100000000000003", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "coordinate": "1480,400|1480,400", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5", + "nextNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519", + "coordinate": "1530,400;1640,400;1640,325" + } + ] + }, + { + "nodeType": "4", + "nodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "1640,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519", + "nextNodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828", + "coordinate": "1665,300;1770,300" + } + ] + }, + { + "nodeType": "1", + "nodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828", + "nodeName": "董事", + "permissionFlag": "1761100000000000001", + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": "", + "listenerPath": "", + "formCustom": "N", + "formPath": null, + "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "coordinate": "1820,300|1820,300", + "version": "1", + "skipList": [ + { + "skipType": "PASS", + "skipCondition": null, + "skipName": null, + "nowNodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828", + "nextNodeCode": "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31", + "coordinate": "1870,300;1960,300" + } + ] + }, + { + "nodeType": "2", + "nodeCode": "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31", + "nodeName": "结束", + "permissionFlag": null, + "nodeRatio": "0.000", + "anyNodeSkip": null, + "listenerType": null, + "listenerPath": null, + "formCustom": "N", + "formPath": null, + "ext": "[]", + "coordinate": "1980,300|1980,300", + "version": "1", + "skipList": [] + } + ], + "flowCode": "leave6", + "flowName": "请假申请-排他并行会签", + "modelValue": "CLASSICS", + "category": "1762300000000000103", + "version": "1", + "formCustom": "N", + "formPath": "/workflow/leaveEdit/index", + "listenerType": null, + "listenerPath": null +} diff --git a/script/sql/oracle/oracle_ry_job.sql b/script/sql/oracle/oracle_ry_job.sql new file mode 100644 index 000000000..e3a7c6f83 --- /dev/null +++ b/script/sql/oracle/oracle_ry_job.sql @@ -0,0 +1,946 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : Oracle + Date: 2025-06-21 23:33:11 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id number GENERATED ALWAYS AS IDENTITY, + name varchar2(64) NULL, + unique_id varchar2(64) NULL, + description varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_namespace + ADD CONSTRAINT pk_sj_namespace PRIMARY KEY (id); + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name); + +COMMENT ON COLUMN sj_namespace.id IS '主键'; +COMMENT ON COLUMN sj_namespace.name IS '名称'; +COMMENT ON COLUMN sj_namespace.unique_id IS '唯一id'; +COMMENT ON COLUMN sj_namespace.description IS '描述'; +COMMENT ON COLUMN sj_namespace.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_namespace.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_namespace.update_dt IS '修改时间'; +COMMENT ON TABLE sj_namespace IS '命名空间'; + +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES ('Development', 'dev', '', 0, sysdate, sysdate); +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES ('Production', 'prod', '', 0, sysdate, sysdate); + +-- sj_group_config +CREATE TABLE sj_group_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + description varchar2(256) DEFAULT '' NULL, + token varchar2(64) DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' NULL, + group_status smallint DEFAULT 0 NOT NULL, + version number NOT NULL, + group_partition number NOT NULL, + id_generator_mode smallint DEFAULT 1 NOT NULL, + init_scene smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_group_config + ADD CONSTRAINT pk_sj_group_config PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_group_config.id IS '主键'; +COMMENT ON COLUMN sj_group_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_group_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_group_config.description IS '组描述'; +COMMENT ON COLUMN sj_group_config.token IS 'token'; +COMMENT ON COLUMN sj_group_config.group_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_group_config.version IS '版本号'; +COMMENT ON COLUMN sj_group_config.group_partition IS '分区'; +COMMENT ON COLUMN sj_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式'; +COMMENT ON COLUMN sj_group_config.init_scene IS '是否初始化场景 0:否 1:是'; +COMMENT ON COLUMN sj_group_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_group_config IS '组配置'; + +INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, sysdate, sysdate); +INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, create_dt, update_dt) VALUES ('prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, sysdate, sysdate); + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + notify_name varchar2(64) DEFAULT '' NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + notify_status smallint DEFAULT 0 NOT NULL, + recipient_ids varchar2(128) NULL, + notify_threshold number DEFAULT 0 NOT NULL, + notify_scene smallint DEFAULT 0 NOT NULL, + rate_limiter_status smallint DEFAULT 0 NOT NULL, + rate_limiter_threshold number DEFAULT 0 NOT NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_notify_config + ADD CONSTRAINT pk_sj_notify_config PRIMARY KEY (id); + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_notify_config.id IS '主键'; +COMMENT ON COLUMN sj_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_notify_config.notify_name IS '通知名称'; +COMMENT ON COLUMN sj_notify_config.system_task_type IS '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.recipient_ids IS '接收人id列表'; +COMMENT ON COLUMN sj_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN sj_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN sj_notify_config.description IS '描述'; +COMMENT ON COLUMN sj_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_config IS '通知配置'; + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + recipient_name varchar2(64) NULL, + notify_type smallint DEFAULT 0 NOT NULL, + notify_attribute varchar2(512) NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_notify_recipient + ADD CONSTRAINT pk_sj_notify_recipient PRIMARY KEY (id); + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id); + +COMMENT ON COLUMN sj_notify_recipient.id IS '主键'; +COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称'; +COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook'; +COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性'; +COMMENT ON COLUMN sj_notify_recipient.description IS '描述'; +COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_recipient.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_recipient IS '告警通知接收人'; + +-- sj_retry_dead_letter +CREATE TABLE sj_retry_dead_letter +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + group_id number NOT NULL, + scene_name varchar2(64) NULL, + scene_id number NOT NULL, + idempotent_id varchar2(64) NULL, + biz_no varchar2(64) DEFAULT '' NULL, + executor_name varchar2(512) DEFAULT '' NULL, + serializer_name varchar2(32) DEFAULT 'jackson' NULL, + args_str clob NULL, + ext_attrs clob NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_dead_letter + ADD CONSTRAINT pk_sj_retry_dead_letter PRIMARY KEY (id); + +CREATE INDEX idx_sj_retry_dead_letter_01 ON sj_retry_dead_letter (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_dead_letter_02 ON sj_retry_dead_letter (idempotent_id); +CREATE INDEX idx_sj_retry_dead_letter_03 ON sj_retry_dead_letter (biz_no); +CREATE INDEX idx_sj_retry_dead_letter_04 ON sj_retry_dead_letter (create_dt); + +COMMENT ON COLUMN sj_retry_dead_letter.id IS '主键'; +COMMENT ON COLUMN sj_retry_dead_letter.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_dead_letter.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_dead_letter.group_id IS '组Id'; +COMMENT ON COLUMN sj_retry_dead_letter.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_dead_letter.scene_id IS '场景ID'; +COMMENT ON COLUMN sj_retry_dead_letter.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_dead_letter.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_dead_letter.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_dead_letter.serializer_name IS '执行方法参数序列化器名称'; +COMMENT ON COLUMN sj_retry_dead_letter.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_dead_letter.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_dead_letter.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_dead_letter IS '死信队列表'; + +-- sj_retry +CREATE TABLE sj_retry +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + group_id number NOT NULL, + scene_name varchar2(64) NULL, + scene_id number NOT NULL, + idempotent_id varchar2(64) NULL, + biz_no varchar2(64) DEFAULT '' NULL, + executor_name varchar2(512) DEFAULT '' NULL, + args_str clob NULL, + ext_attrs clob NULL, + serializer_name varchar2(32) DEFAULT 'jackson' NULL, + next_trigger_at number NOT NULL, + retry_count number DEFAULT 0 NOT NULL, + retry_status smallint DEFAULT 0 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + bucket_index number DEFAULT 0 NOT NULL, + parent_id number DEFAULT 0 NOT NULL, + deleted number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry + ADD CONSTRAINT pk_sj_retry PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_01 ON sj_retry (scene_id, task_type, idempotent_id, deleted); + +CREATE INDEX idx_sj_retry_01 ON sj_retry (biz_no); +CREATE INDEX idx_sj_retry_02 ON sj_retry (idempotent_id); +CREATE INDEX idx_sj_retry_03 ON sj_retry (retry_status, bucket_index); +CREATE INDEX idx_sj_retry_04 ON sj_retry (parent_id); +CREATE INDEX idx_sj_retry_05 ON sj_retry (create_dt); + +COMMENT ON COLUMN sj_retry.id IS '主键'; +COMMENT ON COLUMN sj_retry.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry.group_id IS '组Id'; +COMMENT ON COLUMN sj_retry.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry.scene_id IS '场景ID'; +COMMENT ON COLUMN sj_retry.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry.serializer_name IS '执行方法参数序列化器名称'; +COMMENT ON COLUMN sj_retry.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_retry.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_retry.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数'; +COMMENT ON COLUMN sj_retry.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_retry.parent_id IS '父节点id'; +COMMENT ON COLUMN sj_retry.deleted IS '逻辑删除'; +COMMENT ON COLUMN sj_retry.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry IS '重试信息表'; + +-- sj_retry_task +CREATE TABLE sj_retry_task +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + scene_name varchar2(64) NULL, + retry_id number NOT NULL, + ext_attrs clob NULL, + task_status smallint DEFAULT 1 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + operation_reason smallint DEFAULT 0 NOT NULL, + client_info varchar2(128) DEFAULT NULL NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_task + ADD CONSTRAINT pk_sj_retry_task PRIMARY KEY (id); + +CREATE INDEX idx_sj_retry_task_01 ON sj_retry_task (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_02 ON sj_retry_task (task_status); +CREATE INDEX idx_sj_retry_task_03 ON sj_retry_task (create_dt); +CREATE INDEX idx_sj_retry_task_04 ON sj_retry_task (retry_id); + +COMMENT ON COLUMN sj_retry_task.id IS '主键'; +COMMENT ON COLUMN sj_retry_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task.retry_id IS '重试信息Id'; +COMMENT ON COLUMN sj_retry_task.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task.task_status IS '重试状态'; +COMMENT ON COLUMN sj_retry_task.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_retry_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_retry_task.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task IS '重试任务表'; + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + retry_id number NOT NULL, + retry_task_id number NOT NULL, + message clob NULL, + log_num number DEFAULT 1 NOT NULL, + real_time number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_task_log_message + ADD CONSTRAINT pk_sj_retry_task_log_message PRIMARY KEY (id); + +CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, retry_task_id); +CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt); + +COMMENT ON COLUMN sj_retry_task_log_message.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log_message.retry_id IS '重试信息Id'; +COMMENT ON COLUMN sj_retry_task_log_message.retry_task_id IS '重试任务Id'; +COMMENT ON COLUMN sj_retry_task_log_message.message IS '异常信息'; +COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_task_log_message IS '任务调度日志信息记录表'; + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + scene_name varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_status smallint DEFAULT 0 NOT NULL, + max_retry_count number DEFAULT 5 NOT NULL, + back_off smallint DEFAULT 1 NOT NULL, + trigger_interval varchar2(16) DEFAULT '' NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + deadline_request number DEFAULT 60000 NOT NULL, + executor_timeout number DEFAULT 5 NOT NULL, + route_key smallint DEFAULT 4 NOT NULL, + block_strategy smallint DEFAULT 1 NOT NULL, + cb_status smallint DEFAULT 0 NOT NULL, + cb_trigger_type smallint DEFAULT 1 NOT NULL, + cb_max_count number DEFAULT 16 NOT NULL, + cb_trigger_interval varchar2(16) DEFAULT '' NULL, + owner_id number DEFAULT NULL NULL, + labels varchar2(512) DEFAULT '' NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_scene_config + ADD CONSTRAINT pk_sj_retry_scene_config PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name); + +COMMENT ON COLUMN sj_retry_scene_config.id IS '主键'; +COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_scene_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '最大重试次数'; +COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒'; +COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_retry_scene_config.route_key IS '路由策略'; +COMMENT ON COLUMN sj_retry_scene_config.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_retry_scene_config.cb_status IS '回调状态 0、不开启 1、开启'; +COMMENT ON COLUMN sj_retry_scene_config.cb_trigger_type IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN sj_retry_scene_config.cb_max_count IS '回调的最大执行次数'; +COMMENT ON COLUMN sj_retry_scene_config.cb_trigger_interval IS '回调的最大执行次数'; +COMMENT ON COLUMN sj_retry_scene_config.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_retry_scene_config.labels IS '标签'; +COMMENT ON COLUMN sj_retry_scene_config.description IS '描述'; +COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_scene_config IS '场景配置'; + +-- sj_server_node +CREATE TABLE sj_server_node +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + host_id varchar2(64) NULL, + host_ip varchar2(64) NULL, + host_port number NOT NULL, + expire_at date NOT NULL, + node_type smallint NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + labels varchar2(512) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_server_node + ADD CONSTRAINT pk_sj_server_node PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip); + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name); +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type); + +COMMENT ON COLUMN sj_server_node.id IS '主键'; +COMMENT ON COLUMN sj_server_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_server_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_server_node.host_id IS '主机id'; +COMMENT ON COLUMN sj_server_node.host_ip IS '机器ip'; +COMMENT ON COLUMN sj_server_node.host_port IS '机器端口'; +COMMENT ON COLUMN sj_server_node.expire_at IS '过期时间'; +COMMENT ON COLUMN sj_server_node.node_type IS '节点类型 1、客户端 2、是服务端'; +COMMENT ON COLUMN sj_server_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_server_node.labels IS '标签'; +COMMENT ON COLUMN sj_server_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_server_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_server_node IS '服务器节点'; + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name varchar2(64) NOT NULL, + lock_until timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL, + locked_at timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL, + locked_by varchar2(255) NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_distributed_lock + ADD CONSTRAINT pk_sj_distributed_lock PRIMARY KEY (name); + +COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称'; +COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长'; +COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间'; +COMMENT ON COLUMN sj_distributed_lock.locked_by IS '锁定者'; +COMMENT ON COLUMN sj_distributed_lock.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_distributed_lock.update_dt IS '修改时间'; +COMMENT ON TABLE sj_distributed_lock IS '锁定表'; + +-- sj_system_user +CREATE TABLE sj_system_user +( + id number GENERATED ALWAYS AS IDENTITY, + username varchar2(64) NULL, + password varchar2(128) NULL, + role smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_system_user + ADD CONSTRAINT pk_sj_system_user PRIMARY KEY (id); + +COMMENT ON COLUMN sj_system_user.id IS '主键'; +COMMENT ON COLUMN sj_system_user.username IS '账号'; +COMMENT ON COLUMN sj_system_user.password IS '密码'; +COMMENT ON COLUMN sj_system_user.role IS '角色:1-普通用户、2-管理员'; +COMMENT ON COLUMN sj_system_user.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user IS '系统用户表'; + +INSERT INTO sj_system_user (username, password, role) +VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2); + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id number GENERATED ALWAYS AS IDENTITY, + group_name varchar2(64) NULL, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + system_user_id number NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_system_user_permission + ADD CONSTRAINT pk_sj_system_user_permission PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id); + +COMMENT ON COLUMN sj_system_user_permission.id IS '主键'; +COMMENT ON COLUMN sj_system_user_permission.group_name IS '组名称'; +COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '系统用户id'; +COMMENT ON COLUMN sj_system_user_permission.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user_permission.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user_permission IS '系统用户权限表'; + +-- sj_job +CREATE TABLE sj_job +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + biz_id varchar2(64) NOT NULL, + group_name varchar2(64) NULL, + job_name varchar2(64) NULL, + args_str clob DEFAULT NULL NULL, + args_type smallint DEFAULT 1 NOT NULL, + next_trigger_at number NOT NULL, + job_status smallint DEFAULT 1 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + route_key smallint DEFAULT 4 NOT NULL, + executor_type smallint DEFAULT 1 NOT NULL, + executor_info varchar2(255) DEFAULT NULL NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar2(255) NULL, + block_strategy smallint DEFAULT 1 NOT NULL, + executor_timeout number DEFAULT 0 NOT NULL, + max_retry_times number DEFAULT 0 NOT NULL, + parallel_num number DEFAULT 1 NOT NULL, + retry_interval number DEFAULT 0 NOT NULL, + bucket_index number DEFAULT 0 NOT NULL, + resident smallint DEFAULT 0 NOT NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + owner_id number DEFAULT NULL NULL, + labels varchar2(512) DEFAULT '' NULL, + description varchar2(256) DEFAULT '' NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job + ADD CONSTRAINT pk_sj_job PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name); +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index); +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt); +CREATE UNIQUE INDEX uk_sj_job_01 ON sj_job (namespace_id, biz_id); + +COMMENT ON COLUMN sj_job.id IS '主键'; +COMMENT ON COLUMN sj_job.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job.biz_id IS '业务ID'; +COMMENT ON COLUMN sj_job.group_name IS '组名称'; +COMMENT ON COLUMN sj_job.job_name IS '名称'; +COMMENT ON COLUMN sj_job.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_job.job_status IS '任务状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_job.task_type IS '任务类型 1、集群 2、广播 3、切片'; +COMMENT ON COLUMN sj_job.route_key IS '路由策略'; +COMMENT ON COLUMN sj_job.executor_type IS '执行器类型'; +COMMENT ON COLUMN sj_job.executor_info IS '执行器名称'; +COMMENT ON COLUMN sj_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_job.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行 4、恢复'; +COMMENT ON COLUMN sj_job.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_job.max_retry_times IS '最大重试次数'; +COMMENT ON COLUMN sj_job.parallel_num IS '并行数'; +COMMENT ON COLUMN sj_job.retry_interval IS '重试间隔 ( s)'; +COMMENT ON COLUMN sj_job.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_job.resident IS '是否是常驻任务'; +COMMENT ON COLUMN sj_job.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_job.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_job.labels IS '标签'; +COMMENT ON COLUMN sj_job.description IS '描述'; +COMMENT ON COLUMN sj_job.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job IS '任务信息'; + +INSERT INTO sj_job(namespace_id, biz_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, notify_ids, owner_id, labels, description, ext_attrs, deleted, create_dt, update_dt) VALUES ('dev', 'demo-job', 'ruoyi_group', 'demo-job', NULL, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1, '','', '', 0, sysdate, sysdate); + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + task_batch_id number NOT NULL, + task_id number NOT NULL, + message clob NULL, + log_num number DEFAULT 1 NOT NULL, + real_time number DEFAULT 0 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_log_message + ADD CONSTRAINT pk_sj_job_log_message PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id); +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt); +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_log_message.id IS '主键'; +COMMENT ON COLUMN sj_job_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_log_message.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN sj_job_log_message.task_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_log_message.message IS '调度信息'; +COMMENT ON COLUMN sj_job_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_job_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_job_log_message IS '调度日志'; + +-- sj_job_task +CREATE TABLE sj_job_task +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + task_batch_id number NOT NULL, + parent_id number DEFAULT 0 NOT NULL, + task_status smallint DEFAULT 0 NOT NULL, + retry_count number DEFAULT 0 NOT NULL, + mr_stage smallint DEFAULT NULL NULL, + leaf smallint DEFAULT '1' NOT NULL, + task_name varchar2(255) DEFAULT '' NULL, + client_info varchar2(128) DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + result_message clob NULL, + args_str clob DEFAULT NULL NULL, + args_type smallint DEFAULT 1 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_task + ADD CONSTRAINT pk_sj_job_task PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status); +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt); +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_task.id IS '主键'; +COMMENT ON COLUMN sj_job_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id'; +COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce'; +COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点'; +COMMENT ON COLUMN sj_job_task.task_name IS '任务名称'; +COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文'; +COMMENT ON COLUMN sj_job_task.result_message IS '执行结果'; +COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job_task.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task IS '任务实例'; + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + workflow_node_id number DEFAULT 0 NOT NULL, + parent_workflow_node_id number DEFAULT 0 NOT NULL, + workflow_task_batch_id number DEFAULT 0 NOT NULL, + task_batch_status smallint DEFAULT 0 NOT NULL, + operation_reason smallint DEFAULT 0 NOT NULL, + execution_at number DEFAULT 0 NOT NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + parent_id varchar2(64) DEFAULT '' NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_task_batch + ADD CONSTRAINT pk_sj_job_task_batch PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status); +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt); +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name); +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id); + +COMMENT ON COLUMN sj_job_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task_batch.job_id IS '任务id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '工作流节点id'; +COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '工作流任务父批次id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '工作流任务批次id'; +COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_job_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_task_batch.parent_id IS '父节点'; +COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task_batch IS '任务批次'; + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + business_id number NOT NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + trigger_at date DEFAULT CURRENT_TIMESTAMP NOT NULL, + success_num number DEFAULT 0 NOT NULL, + fail_num number DEFAULT 0 NOT NULL, + fail_reason varchar2(512) DEFAULT '' NULL, + stop_num number DEFAULT 0 NOT NULL, + stop_reason varchar2(512) DEFAULT '' NULL, + cancel_num number DEFAULT 0 NOT NULL, + cancel_reason varchar2(512) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_summary + ADD CONSTRAINT pk_sj_job_summary PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id); + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id); + +COMMENT ON COLUMN sj_job_summary.id IS '主键'; +COMMENT ON COLUMN sj_job_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_summary.business_id IS '业务id ( job_id或workflow_id)'; +COMMENT ON COLUMN sj_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_job_summary.success_num IS '执行成功-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.stop_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.stop_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.cancel_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.cancel_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job'; + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + scene_name varchar2(64) DEFAULT '' NULL, + trigger_at date DEFAULT CURRENT_TIMESTAMP NOT NULL, + running_num number DEFAULT 0 NOT NULL, + finish_num number DEFAULT 0 NOT NULL, + max_count_num number DEFAULT 0 NOT NULL, + suspend_num number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_summary + ADD CONSTRAINT pk_sj_retry_summary PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at); + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at); + +COMMENT ON COLUMN sj_retry_summary.id IS '主键'; +COMMENT ON COLUMN sj_retry_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_summary.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_retry_summary.running_num IS '重试中-日志数量'; +COMMENT ON COLUMN sj_retry_summary.finish_num IS '重试完成-日志数量'; +COMMENT ON COLUMN sj_retry_summary.max_count_num IS '重试到达最大次数-日志数量'; +COMMENT ON COLUMN sj_retry_summary.suspend_num IS '暂停重试-日志数量'; +COMMENT ON COLUMN sj_retry_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry'; + +-- sj_workflow +CREATE TABLE sj_workflow +( + id number GENERATED ALWAYS AS IDENTITY, + workflow_name varchar2(64) NULL, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + biz_id varchar2(64) NOT NULL, + group_name varchar2(64) NULL, + workflow_status smallint DEFAULT 1 NOT NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar2(255) NULL, + next_trigger_at number NOT NULL, + block_strategy smallint DEFAULT 1 NOT NULL, + executor_timeout number DEFAULT 0 NOT NULL, + description varchar2(256) DEFAULT '' NULL, + flow_info clob DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + bucket_index number DEFAULT 0 NOT NULL, + version number NOT NULL, + owner_id number DEFAULT NULL NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow + ADD CONSTRAINT pk_sj_workflow PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt); +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name); +CREATE UNIQUE INDEX uk_sj_workflow_01 ON sj_workflow (namespace_id, biz_id); + +COMMENT ON COLUMN sj_workflow.id IS '主键'; +COMMENT ON COLUMN sj_workflow.workflow_name IS '工作流名称'; +COMMENT ON COLUMN sj_workflow.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow.biz_id IS '业务ID'; +COMMENT ON COLUMN sj_workflow.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow.workflow_status IS '工作流状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_workflow.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_workflow.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_workflow.description IS '描述'; +COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow.wf_context IS '上下文'; +COMMENT ON COLUMN sj_workflow.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_workflow.version IS '版本号'; +COMMENT ON COLUMN sj_workflow.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow IS '工作流'; + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + node_name varchar2(64) NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + workflow_id number NOT NULL, + node_type smallint DEFAULT 1 NOT NULL, + expression_type smallint DEFAULT 0 NOT NULL, + fail_strategy smallint DEFAULT 1 NOT NULL, + workflow_node_status smallint DEFAULT 1 NOT NULL, + priority_level number DEFAULT 1 NOT NULL, + node_info clob DEFAULT NULL NULL, + version number NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow_node + ADD CONSTRAINT pk_sj_workflow_node PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt); +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_node.id IS '主键'; +COMMENT ON COLUMN sj_workflow_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_node.node_name IS '节点名称'; +COMMENT ON COLUMN sj_workflow_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_node.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_workflow_node.workflow_id IS '工作流ID'; +COMMENT ON COLUMN sj_workflow_node.node_type IS '1、任务节点 2、条件节点'; +COMMENT ON COLUMN sj_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL'; +COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞'; +COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow_node.priority_level IS '优先级'; +COMMENT ON COLUMN sj_workflow_node.node_info IS '节点信息 '; +COMMENT ON COLUMN sj_workflow_node.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_node.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_node IS '工作流节点'; + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + workflow_id number NOT NULL, + task_batch_status smallint DEFAULT 0 NOT NULL, + operation_reason smallint DEFAULT 0 NOT NULL, + flow_info clob DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + execution_at number DEFAULT 0 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + version number DEFAULT 1 NOT NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow_task_batch + ADD CONSTRAINT pk_sj_workflow_task_batch PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status); +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt); +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id'; +COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文'; +COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_task_batch IS '工作流批次'; + +-- sj_job_executor +CREATE TABLE sj_job_executor +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + executor_info varchar2(256) NULL, + executor_type varchar2(3) NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_executor + ADD CONSTRAINT pk_sj_job_executor PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_executor_01 ON sj_job_executor (namespace_id, group_name); +CREATE INDEX idx_sj_job_executor_02 ON sj_job_executor (create_dt); + +COMMENT ON COLUMN sj_job_executor.id IS '主键'; +COMMENT ON COLUMN sj_job_executor.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_executor.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_executor.executor_info IS '任务执行器名称'; +COMMENT ON COLUMN sj_job_executor.executor_type IS '1:java 2:python 3:go'; +COMMENT ON COLUMN sj_job_executor.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_executor.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_executor IS '任务执行器信息'; diff --git a/script/sql/oracle/oracle_ry_vue.sql b/script/sql/oracle/oracle_ry_vue.sql new file mode 100644 index 000000000..b911b1435 --- /dev/null +++ b/script/sql/oracle/oracle_ry_vue.sql @@ -0,0 +1,1353 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id number(20) not null, + user_id number(20) not null, + auth_id varchar2(255) not null, + source varchar2(255) not null, + open_id varchar2(255) default null, + user_name varchar2(30) not null, + nick_name varchar2(30) default '', + email varchar2(255) default '', + avatar varchar2(500) default '', + access_token varchar2(2000) not null, + expire_in number(20) default null, + refresh_token varchar2(2000) default null, + access_code varchar2(255) default null, + union_id varchar2(255) default null, + scope varchar2(255) default null, + token_type varchar2(255) default null, + id_token varchar2(2000) default null, + mac_algorithm varchar2(255) default null, + mac_key varchar2(255) default null, + code varchar2(255) default null, + oauth_token varchar2(255) default null, + oauth_token_secret varchar2(255) default null, + create_dept number(20), + create_by number(20), + create_time date, + update_by number(20), + update_time date, + del_flag char(1) default '0' +); + +alter table sys_social add constraint pk_sys_social primary key (id); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 1代表删除)'; + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table sys_dept ( + dept_id number(20) not null, + parent_id number(20) default 0, + ancestors varchar2(500) default '', + dept_name varchar2(30) default '', + dept_category varchar2(100) default null, + order_num number(4) default 0, + leader number(20) default null, + phone varchar2(11) default null, + email varchar2(50) default null, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_dept add constraint pk_sys_dept primary key (dept_id); + +create index idx_sys_dept_parent_id on sys_dept (parent_id); + +comment on table sys_dept is '部门表'; +comment on column sys_dept.dept_id is '部门id'; +comment on column sys_dept.parent_id is '父部门id'; +comment on column sys_dept.ancestors is '祖级列表'; +comment on column sys_dept.dept_name is '部门名称'; +comment on column sys_dept.dept_category is '部门类别编码'; +comment on column sys_dept.order_num is '显示顺序'; +comment on column sys_dept.leader is '负责人'; +comment on column sys_dept.phone is '联系电话'; +comment on column sys_dept.email is '邮箱'; +comment on column sys_dept.status is '部门状态(0正常 1停用)'; +comment on column sys_dept.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_dept.create_dept is '创建部门'; +comment on column sys_dept.create_by is '创建者'; +comment on column sys_dept.create_time is '创建时间'; +comment on column sys_dept.update_by is '更新者'; +comment on column sys_dept.update_time is '更新时间'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- + +insert into sys_dept values(1761000000000000100, 0, '0', 'XXX科技', null, 0, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000101, 1761000000000000100, '0,1761000000000000100', '深圳总公司', null, 1, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000102, 1761000000000000100, '0,1761000000000000100', '长沙分公司', null, 2, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000103, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '研发部门', null, 1, 1761100000000000001, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000104, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '市场部门', null, 2, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000105, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '测试部门', null, 3, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000106, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '财务部门', null, 4, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000107, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '运维部门', null, 5, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000108, 1761000000000000102, '0,1761000000000000100,1761000000000000102', '市场部门', null, 1, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); +insert into sys_dept values(1761000000000000109, 1761000000000000102, '0,1761000000000000100,1761000000000000102', '财务部门', null, 2, NULL, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table sys_user ( + user_id number(20) not null, + dept_id number(20) default null, + user_name varchar2(40) not null, + nick_name varchar2(40) not null, + user_type varchar2(10) default 'sys_user', + email varchar2(50) default '', + phone_number varchar2(11) default '', + gender char(1) default '0', + avatar number(20) default null, + password varchar2(100) default '', + status char(1) default '0', + del_flag char(1) default '0', + login_ip varchar2(128) default '', + login_date date, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default '' +); + +alter table sys_user add constraint pk_sys_user primary key (user_id); + +create index idx_sys_user_dept_id on sys_user (dept_id); +create index idx_sys_user_create_by on sys_user (create_by); +create index idx_sys_user_user_name on sys_user (user_name); +create index idx_sys_user_phone on sys_user (phone_number); + +comment on table sys_user is '用户信息表'; +comment on column sys_user.user_id is '用户ID'; +comment on column sys_user.dept_id is '部门ID'; +comment on column sys_user.user_name is '用户账号'; +comment on column sys_user.nick_name is '用户昵称'; +comment on column sys_user.user_type is '用户类型(sys_user系统用户)'; +comment on column sys_user.email is '用户邮箱'; +comment on column sys_user.phone_number is '手机号码'; +comment on column sys_user.gender is '用户性别(0男 1女 2未知)'; +comment on column sys_user.avatar is '头像路径'; +comment on column sys_user.password is '密码'; +comment on column sys_user.status is '账号状态(0正常 1停用)'; +comment on column sys_user.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_user.login_ip is '最后登录IP'; +comment on column sys_user.login_date is '最后登录时间'; +comment on column sys_user.create_dept is '创建部门'; +comment on column sys_user.create_by is '创建者'; +comment on column sys_user.create_time is '创建时间'; +comment on column sys_user.update_by is '更新者'; +comment on column sys_user.update_time is '更新时间'; +comment on column sys_user.remark is '备注'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1761100000000000001, 1761000000000000103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '管理员'); +insert into sys_user values(1761100000000000003, 1761000000000000108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 1761000000000000103, 1761100000000000001, sysdate, NULL, null, ''); +insert into sys_user values(1761100000000000004, 1761000000000000102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 1761000000000000103, 1761100000000000001, sysdate, NULL, null, ''); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table sys_post ( + post_id number(20) not null, + dept_id number(20) not null, + post_code varchar2(64) not null, + post_category varchar2(64) default null, + post_name varchar2(50) not null, + post_sort number(4) not null, + status char(1) not null, + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) +); + +alter table sys_post add constraint pk_sys_post primary key (post_id); + +create index idx_sys_post_dept_id on sys_post (dept_id); + +comment on table sys_post is '岗位信息表'; +comment on column sys_post.post_id is '岗位ID'; +comment on column sys_post.dept_id is '部门id'; +comment on column sys_post.post_code is '岗位编码'; +comment on column sys_post.post_category is '岗位类别编码'; +comment on column sys_post.post_name is '岗位名称'; +comment on column sys_post.post_sort is '显示顺序'; +comment on column sys_post.status is '状态(0正常 1停用)'; +comment on column sys_post.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_post.create_dept is '创建部门'; +comment on column sys_post.create_by is '创建者'; +comment on column sys_post.create_time is '创建时间'; +comment on column sys_post.update_by is '更新者'; +comment on column sys_post.update_time is '更新时间'; +comment on column sys_post.remark is '备注'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1761200000000000001, 1761000000000000103, 'ceo', null, '董事长', 1, '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, ''); +insert into sys_post values(1761200000000000002, 1761000000000000100, 'se', null, '项目经理', 2, '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, ''); +insert into sys_post values(1761200000000000003, 1761000000000000100, 'hr', null, '人力资源', 3, '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, ''); +insert into sys_post values(1761200000000000004, 1761000000000000100, 'user', null, '普通员工', 4, '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table sys_role ( + role_id number(20) not null, + role_name varchar2(30) not null, + role_key varchar2(100) not null, + role_sort number(4) not null, + data_scope char(1) default '1', + menu_check_strictly number(1) default 1, + dept_check_strictly number(1) default 1, + status char(1) not null, + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_role add constraint pk_sys_role primary key (role_id); + +create index idx_sys_role_create_dept on sys_role (create_dept); +create index idx_sys_role_create_by on sys_role (create_by); + +comment on table sys_role is '角色信息表'; +comment on column sys_role.role_id is '角色ID'; +comment on column sys_role.role_name is '角色名称'; +comment on column sys_role.role_key is '角色权限字符串'; +comment on column sys_role.role_sort is '显示顺序'; +comment on column sys_role.data_scope is '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限)'; +comment on column sys_role.menu_check_strictly is '菜单树选择项是否关联显示'; +comment on column sys_role.dept_check_strictly is '部门树选择项是否关联显示'; +comment on column sys_role.status is '角色状态(0正常 1停用)'; +comment on column sys_role.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_role.create_dept is '创建部门'; +comment on column sys_role.create_by is '创建者'; +comment on column sys_role.create_time is '创建时间'; +comment on column sys_role.update_by is '更新者'; +comment on column sys_role.update_time is '更新时间'; +comment on column sys_role.remark is '备注'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values(1761300000000000001, '超级管理员', 'superadmin', 1, 1, 1, 1, '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '超级管理员'); +insert into sys_role values(1761300000000000003, '本部门及以下', 'test1', 3, 4, 1, 1, '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, null); +insert into sys_role values(1761300000000000004, '仅本人', 'test2', 4, 5, 1, 1, '0', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, null); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table sys_menu ( + menu_id number(20) not null, + menu_name varchar2(50) not null, + parent_id number(20) default 0, + order_num number(4) default 0, + path varchar2(200) default '', + component varchar2(255) default null, + query_param varchar2(255) default null, + is_frame char(1) default 'N', + is_cache char(1) default 'Y', + menu_type char(1) default '', + visible char(1) default 0, + status char(1) default 0, + perms varchar2(100) default null, + icon varchar2(100) default '#', + active_menu varchar2(255) default '', + ext varchar2(2000) default '', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date , + remark varchar2(500) default '' +); + +alter table sys_menu add constraint pk_sys_menu primary key (menu_id); + +comment on table sys_menu is '菜单权限表'; +comment on column sys_menu.menu_id is '菜单ID'; +comment on column sys_menu.menu_name is '菜单名称'; +comment on column sys_menu.parent_id is '父菜单ID'; +comment on column sys_menu.order_num is '显示顺序'; +comment on column sys_menu.path is '请求地址'; +comment on column sys_menu.component is '路由地址'; +comment on column sys_menu.query_param is '路由参数'; +comment on column sys_menu.is_frame is '是否为外链(Y是 N否)'; +comment on column sys_menu.is_cache is '是否缓存(Y缓存 N不缓存)'; +comment on column sys_menu.menu_type is '菜单类型(M目录 C菜单 F按钮)'; +comment on column sys_menu.visible is '显示状态(0显示 1隐藏)'; +comment on column sys_menu.status is '菜单状态(0正常 1停用)'; +comment on column sys_menu.perms is '权限标识'; +comment on column sys_menu.icon is '菜单图标'; +comment on column sys_menu.create_dept is '创建部门'; +comment on column sys_menu.create_by is '创建者'; +comment on column sys_menu.create_time is '创建时间'; +comment on column sys_menu.update_by is '更新者'; +comment on column sys_menu.update_time is '更新时间'; +comment on column sys_menu.active_menu is '激活菜单路径'; +comment on column sys_menu.ext is '扩展字段'; +comment on column sys_menu.remark is '备注'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values(1761400000000000001, '系统管理', 0, 1, 'system', null, '', 'N', 'Y', 'M', '0', '0', '', 'system', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '系统管理目录'); +insert into sys_menu values(1761400000000000002, '系统监控', 0, 3, 'monitor', null, '', 'N', 'Y', 'M', '0', '0', '', 'monitor', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '系统监控目录'); +insert into sys_menu values(1761400000000000003, '系统工具', 0, 4, 'tool', null, '', 'N', 'Y', 'M', '0', '0', '', 'tool', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '系统工具目录'); +insert into sys_menu values(1761400000000000005, '测试菜单', 0, 5, 'demo', null, '', 'N', 'Y', 'M', '0', '0', null, 'star', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000000006, 'AI会话', 0, 8, 'aichat', 'ai/chat/index', '', 'N', 'Y', 'C', '0', '0', '', 'checkbox', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, 'AI聊天菜单'); +insert into sys_menu values(1761400000000000004, 'PLUS官网', 0, 9, 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 'Y', 'Y', 'M', '0', '0', '', 'guide', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, 'RuoYi-Vue-Plus官网地址'); +-- 二级菜单 +insert into sys_menu values(1761400000000000100, '用户管理', 1761400000000000001, 1, 'user', 'system/user/index', '', 'N', 'Y', 'C', '0', '0', 'system:user:list', 'user', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '用户管理菜单'); +insert into sys_menu values(1761400000000000101, '角色管理', 1761400000000000001, 2, 'role', 'system/role/index', '', 'N', 'Y', 'C', '0', '0', 'system:role:list', 'peoples', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '角色管理菜单'); +insert into sys_menu values(1761400000000000102, '菜单管理', 1761400000000000001, 3, 'menu', 'system/menu/index', '', 'N', 'Y', 'C', '0', '0', 'system:menu:list', 'tree-table', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '菜单管理菜单'); +insert into sys_menu values(1761400000000000103, '部门管理', 1761400000000000001, 4, 'dept', 'system/dept/index', '', 'N', 'Y', 'C', '0', '0', 'system:dept:list', 'tree', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '部门管理菜单'); +insert into sys_menu values(1761400000000000104, '岗位管理', 1761400000000000001, 5, 'post', 'system/post/index', '', 'N', 'Y', 'C', '0', '0', 'system:post:list', 'post', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '岗位管理菜单'); +insert into sys_menu values(1761400000000000105, '字典管理', 1761400000000000001, 6, 'dict', 'system/dict/index', '', 'N', 'Y', 'C', '0', '0', 'system:dict:list', 'dict', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '字典管理菜单'); +insert into sys_menu values(1761400000000000106, '参数设置', 1761400000000000001, 7, 'config', 'system/config/index', '', 'N', 'Y', 'C', '0', '0', 'system:config:list', 'edit', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '参数设置菜单'); +insert into sys_menu values(1761400000000000107, '通知公告', 1761400000000000001, 8, 'notice', 'system/notice/index', '', 'N', 'Y', 'C', '0', '0', 'system:notice:list', 'message', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '通知公告菜单'); +insert into sys_menu values(1761400000000000108, '日志管理', 1761400000000000001, 9, 'log', '', '', 'N', 'Y', 'M', '0', '0', '', 'log', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '日志管理菜单'); +insert into sys_menu values(1761400000000000109, '在线用户', 1761400000000000002, 1, 'online', 'monitor/online/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:online:list', 'online', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '在线用户菜单'); +insert into sys_menu values(1761400000000000113, '缓存监控', 1761400000000000002, 5, 'cache', 'monitor/cache/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:cache:list', 'redis', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '缓存监控菜单'); +insert into sys_menu values(1761400000000000115, '代码生成', 1761400000000000003, 2, 'gen', 'tool/gen/index', '', 'N', 'Y', 'C', '0', '0', 'tool:gen:list', 'code', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '代码生成菜单'); +insert into sys_menu values(1761400000000000123, '客户端管理', 1761400000000000001, 11, 'client', 'system/client/index', '', 'N', 'Y', 'C', '0', '0', 'system:client:list', 'international', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '客户端管理菜单'); +insert into sys_menu values(1761400000000000116, '修改生成配置', 1761400000000000003, 2, 'gen-edit/index/:tableId', 'tool/gen/editTable', '', 'N', 'N', 'C', '1', '0', 'tool:gen:edit', '#', '/tool/gen', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000000130, '分配用户', 1761400000000000001, 2, 'role-auth/user/:roleId', 'system/role/authUser', '', 'N', 'N', 'C', '1', '0', 'system:role:edit', '#', '/system/role', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000000131, '分配角色', 1761400000000000001, 1, 'user-auth/role/:userId', 'system/user/authRole', '', 'N', 'N', 'C', '1', '0', 'system:user:edit', '#', '/system/user', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000000133, '文件配置管理', 1761400000000000001, 10, 'oss-config/index', 'system/oss/config', '', 'N', 'N', 'C', '1', '0', 'system:ossConfig:list', '#', '/system/oss', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); + +-- springboot-admin监控 +insert into sys_menu values(1761400000000000117, 'Admin监控', 1761400000000000002, 5, 'Admin', 'monitor/admin/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:admin:list', 'dashboard', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values(1761400000000000118, '文件管理', 1761400000000000001, 10, 'oss', 'system/oss/index', '', 'N', 'Y', 'C', '0', '0', 'system:oss:list', 'upload', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values(1761400000000000120, '任务调度中心', 1761400000000000002, 5, 'snailjob', 'monitor/snailjob/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:snailjob:list', 'job', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, 'snailjob控制台菜单'); +-- snail-ai server控制台 +insert into sys_menu values(1761400000000000121, 'AI控制台', 1761400000000000002, 7, 'snailai', 'monitor/snailai/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:snailai:list', 'checkbox', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, 'AI控制台菜单'); + +-- 三级菜单 +insert into sys_menu values(1761400000000000500, '操作日志', 1761400000000000108, 1, 'operlog', 'monitor/operlog/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:operlog:list', 'form', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '操作日志菜单'); +insert into sys_menu values(1761400000000000501, '登录日志', 1761400000000000108, 2, 'logininfo', 'monitor/logininfo/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:logininfo:list', 'logininfo', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values(1761400000000001001, '用户查询', 1761400000000000100, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001002, '用户新增', 1761400000000000100, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001003, '用户修改', 1761400000000000100, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001004, '用户删除', 1761400000000000100, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001005, '用户导出', 1761400000000000100, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001006, '用户导入', 1761400000000000100, 6, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:import', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001007, '重置密码', 1761400000000000100, 7, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:resetPwd', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 角色管理按钮 +insert into sys_menu values(1761400000000001008, '角色查询', 1761400000000000101, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001009, '角色新增', 1761400000000000101, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001010, '角色修改', 1761400000000000101, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001011, '角色删除', 1761400000000000101, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001012, '角色导出', 1761400000000000101, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values(1761400000000001013, '菜单查询', 1761400000000000102, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001014, '菜单新增', 1761400000000000102, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001015, '菜单修改', 1761400000000000102, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001016, '菜单删除', 1761400000000000102, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 部门管理按钮 +insert into sys_menu values(1761400000000001017, '部门查询', 1761400000000000103, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001018, '部门新增', 1761400000000000103, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001019, '部门修改', 1761400000000000103, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001020, '部门删除', 1761400000000000103, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values(1761400000000001021, '岗位查询', 1761400000000000104, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001022, '岗位新增', 1761400000000000104, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001023, '岗位修改', 1761400000000000104, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001024, '岗位删除', 1761400000000000104, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001025, '岗位导出', 1761400000000000104, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 字典管理按钮 +insert into sys_menu values(1761400000000001026, '字典查询', 1761400000000000105, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001027, '字典新增', 1761400000000000105, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001028, '字典修改', 1761400000000000105, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001029, '字典删除', 1761400000000000105, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001030, '字典导出', 1761400000000000105, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 参数设置按钮 +insert into sys_menu values(1761400000000001031, '参数查询', 1761400000000000106, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001032, '参数新增', 1761400000000000106, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001033, '参数修改', 1761400000000000106, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001034, '参数删除', 1761400000000000106, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001035, '参数导出', 1761400000000000106, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 通知公告按钮 +insert into sys_menu values(1761400000000001036, '公告查询', 1761400000000000107, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001037, '公告新增', 1761400000000000107, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001038, '公告修改', 1761400000000000107, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001039, '公告删除', 1761400000000000107, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 操作日志按钮 +insert into sys_menu values(1761400000000001040, '操作查询', 1761400000000000500, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001041, '操作删除', 1761400000000000500, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001042, '日志导出', 1761400000000000500, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 登录日志按钮 +insert into sys_menu values(1761400000000001043, '登录查询', 1761400000000000501, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001044, '登录删除', 1761400000000000501, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001045, '日志导出', 1761400000000000501, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001050, '账户解锁', 1761400000000000501, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:unlock', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 在线用户按钮 +insert into sys_menu values(1761400000000001046, '在线查询', 1761400000000000109, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001047, '批量强退', 1761400000000000109, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:batchLogout', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001048, '单条强退', 1761400000000000109, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:forceLogout', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 代码生成按钮 +insert into sys_menu values(1761400000000001055, '生成查询', 1761400000000000115, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001056, '生成修改', 1761400000000000115, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001057, '生成删除', 1761400000000000115, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001058, '导入代码', 1761400000000000115, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:import', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001059, '预览代码', 1761400000000000115, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:preview', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001060, '生成代码', 1761400000000000115, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:code', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- oss相关按钮 +insert into sys_menu values(1761400000000001600, '文件查询', 1761400000000000118, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001601, '文件上传', 1761400000000000118, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:upload', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001602, '文件下载', 1761400000000000118, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:download', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001603, '文件删除', 1761400000000000118, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001620, '配置列表', 1761400000000000118, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:list', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001621, '配置添加', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001622, '配置编辑', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001623, '配置删除', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 客户端管理按钮 +insert into sys_menu values(1761400000000001061, '客户端管理查询', 1761400000000000123, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001062, '客户端管理新增', 1761400000000000123, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001063, '客户端管理修改', 1761400000000000123, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001064, '客户端管理删除', 1761400000000000123, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001065, '客户端管理导出', 1761400000000000123, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +-- 测试菜单 +insert into sys_menu values(1761400000000001500, '测试单表', 1761400000000000005, 1, 'demo', 'demo/demo/index', '', 'N', 'Y', 'C', '0', '0', 'demo:demo:list', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '测试单表菜单'); +insert into sys_menu values(1761400000000001501, '测试单表查询', 1761400000000001500, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001502, '测试单表新增', 1761400000000001500, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001503, '测试单表修改', 1761400000000001500, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001504, '测试单表删除', 1761400000000001500, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001505, '测试单表导出', 1761400000000001500, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001506, '测试树表', 1761400000000000005, 1, 'tree', 'demo/tree/index', '', 'N', 'Y', 'C', '0', '0', 'demo:tree:list', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, '测试树表菜单'); +insert into sys_menu values(1761400000000001507, '测试树表查询', 1761400000000001506, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001508, '测试树表新增', 1761400000000001506, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001509, '测试树表修改', 1761400000000001506, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001510, '测试树表删除', 1761400000000001506, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); +insert into sys_menu values(1761400000000001511, '测试树表导出', 1761400000000001506, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate, null, null, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table sys_user_role ( + user_id number(20) not null, + role_id number(20) not null +); + +alter table sys_user_role add constraint pk_sys_user_role primary key (user_id, role_id); + +create index idx_sys_user_role_rid on sys_user_role (role_id); + +comment on table sys_user_role is '用户和角色关联表'; +comment on column sys_user_role.user_id is '用户ID'; +comment on column sys_user_role.role_id is '角色ID'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values (1761100000000000001, 1761300000000000001); +insert into sys_user_role values (1761100000000000003, 1761300000000000003); +insert into sys_user_role values (1761100000000000004, 1761300000000000004); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table sys_role_menu ( + role_id number(20) not null, + menu_id number(20) not null +); + +alter table sys_role_menu add constraint pk_sys_role_menu primary key (role_id, menu_id); + +comment on table sys_role_menu is '角色和菜单关联表'; +comment on column sys_role_menu.role_id is '角色ID'; +comment on column sys_role_menu.menu_id is '菜单ID'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values (1761300000000000003, 1761400000000000001); +insert into sys_role_menu values (1761300000000000003, 1761400000000000005); +insert into sys_role_menu values (1761300000000000003, 1761400000000000100); +insert into sys_role_menu values (1761300000000000003, 1761400000000000101); +insert into sys_role_menu values (1761300000000000003, 1761400000000000102); +insert into sys_role_menu values (1761300000000000003, 1761400000000000103); +insert into sys_role_menu values (1761300000000000003, 1761400000000000104); +insert into sys_role_menu values (1761300000000000003, 1761400000000000105); +insert into sys_role_menu values (1761300000000000003, 1761400000000000106); +insert into sys_role_menu values (1761300000000000003, 1761400000000000107); +insert into sys_role_menu values (1761300000000000003, 1761400000000000108); +insert into sys_role_menu values (1761300000000000003, 1761400000000000118); +insert into sys_role_menu values (1761300000000000003, 1761400000000000123); +insert into sys_role_menu values (1761300000000000003, 1761400000000000130); +insert into sys_role_menu values (1761300000000000003, 1761400000000000131); +insert into sys_role_menu values (1761300000000000003, 1761400000000000133); +insert into sys_role_menu values (1761300000000000003, 1761400000000000500); +insert into sys_role_menu values (1761300000000000003, 1761400000000000501); +insert into sys_role_menu values (1761300000000000003, 1761400000000001001); +insert into sys_role_menu values (1761300000000000003, 1761400000000001002); +insert into sys_role_menu values (1761300000000000003, 1761400000000001003); +insert into sys_role_menu values (1761300000000000003, 1761400000000001004); +insert into sys_role_menu values (1761300000000000003, 1761400000000001005); +insert into sys_role_menu values (1761300000000000003, 1761400000000001006); +insert into sys_role_menu values (1761300000000000003, 1761400000000001007); +insert into sys_role_menu values (1761300000000000003, 1761400000000001008); +insert into sys_role_menu values (1761300000000000003, 1761400000000001009); +insert into sys_role_menu values (1761300000000000003, 1761400000000001010); +insert into sys_role_menu values (1761300000000000003, 1761400000000001011); +insert into sys_role_menu values (1761300000000000003, 1761400000000001012); +insert into sys_role_menu values (1761300000000000003, 1761400000000001013); +insert into sys_role_menu values (1761300000000000003, 1761400000000001014); +insert into sys_role_menu values (1761300000000000003, 1761400000000001015); +insert into sys_role_menu values (1761300000000000003, 1761400000000001016); +insert into sys_role_menu values (1761300000000000003, 1761400000000001017); +insert into sys_role_menu values (1761300000000000003, 1761400000000001018); +insert into sys_role_menu values (1761300000000000003, 1761400000000001019); +insert into sys_role_menu values (1761300000000000003, 1761400000000001020); +insert into sys_role_menu values (1761300000000000003, 1761400000000001021); +insert into sys_role_menu values (1761300000000000003, 1761400000000001022); +insert into sys_role_menu values (1761300000000000003, 1761400000000001023); +insert into sys_role_menu values (1761300000000000003, 1761400000000001024); +insert into sys_role_menu values (1761300000000000003, 1761400000000001025); +insert into sys_role_menu values (1761300000000000003, 1761400000000001026); +insert into sys_role_menu values (1761300000000000003, 1761400000000001027); +insert into sys_role_menu values (1761300000000000003, 1761400000000001028); +insert into sys_role_menu values (1761300000000000003, 1761400000000001029); +insert into sys_role_menu values (1761300000000000003, 1761400000000001030); +insert into sys_role_menu values (1761300000000000003, 1761400000000001031); +insert into sys_role_menu values (1761300000000000003, 1761400000000001032); +insert into sys_role_menu values (1761300000000000003, 1761400000000001033); +insert into sys_role_menu values (1761300000000000003, 1761400000000001034); +insert into sys_role_menu values (1761300000000000003, 1761400000000001035); +insert into sys_role_menu values (1761300000000000003, 1761400000000001036); +insert into sys_role_menu values (1761300000000000003, 1761400000000001037); +insert into sys_role_menu values (1761300000000000003, 1761400000000001038); +insert into sys_role_menu values (1761300000000000003, 1761400000000001039); +insert into sys_role_menu values (1761300000000000003, 1761400000000001040); +insert into sys_role_menu values (1761300000000000003, 1761400000000001041); +insert into sys_role_menu values (1761300000000000003, 1761400000000001042); +insert into sys_role_menu values (1761300000000000003, 1761400000000001043); +insert into sys_role_menu values (1761300000000000003, 1761400000000001044); +insert into sys_role_menu values (1761300000000000003, 1761400000000001045); +insert into sys_role_menu values (1761300000000000003, 1761400000000001050); +insert into sys_role_menu values (1761300000000000003, 1761400000000001061); +insert into sys_role_menu values (1761300000000000003, 1761400000000001062); +insert into sys_role_menu values (1761300000000000003, 1761400000000001063); +insert into sys_role_menu values (1761300000000000003, 1761400000000001064); +insert into sys_role_menu values (1761300000000000003, 1761400000000001065); +insert into sys_role_menu values (1761300000000000003, 1761400000000001500); +insert into sys_role_menu values (1761300000000000003, 1761400000000001501); +insert into sys_role_menu values (1761300000000000003, 1761400000000001502); +insert into sys_role_menu values (1761300000000000003, 1761400000000001503); +insert into sys_role_menu values (1761300000000000003, 1761400000000001504); +insert into sys_role_menu values (1761300000000000003, 1761400000000001505); +insert into sys_role_menu values (1761300000000000003, 1761400000000001506); +insert into sys_role_menu values (1761300000000000003, 1761400000000001507); +insert into sys_role_menu values (1761300000000000003, 1761400000000001508); +insert into sys_role_menu values (1761300000000000003, 1761400000000001509); +insert into sys_role_menu values (1761300000000000003, 1761400000000001510); +insert into sys_role_menu values (1761300000000000003, 1761400000000001511); +insert into sys_role_menu values (1761300000000000003, 1761400000000001600); +insert into sys_role_menu values (1761300000000000003, 1761400000000001601); +insert into sys_role_menu values (1761300000000000003, 1761400000000001602); +insert into sys_role_menu values (1761300000000000003, 1761400000000001603); +insert into sys_role_menu values (1761300000000000003, 1761400000000001620); +insert into sys_role_menu values (1761300000000000003, 1761400000000001621); +insert into sys_role_menu values (1761300000000000003, 1761400000000001622); +insert into sys_role_menu values (1761300000000000003, 1761400000000001623); +insert into sys_role_menu values (1761300000000000003, 1761400000000011616); +insert into sys_role_menu values (1761300000000000003, 1761400000000011618); +insert into sys_role_menu values (1761300000000000003, 1761400000000011619); +insert into sys_role_menu values (1761300000000000003, 1761400000000011622); +insert into sys_role_menu values (1761300000000000003, 1761400000000011623); +insert into sys_role_menu values (1761300000000000003, 1761400000000011629); +insert into sys_role_menu values (1761300000000000003, 1761400000000011632); +insert into sys_role_menu values (1761300000000000003, 1761400000000011633); +insert into sys_role_menu values (1761300000000000003, 1761400000000011638); +insert into sys_role_menu values (1761300000000000003, 1761400000000011639); +insert into sys_role_menu values (1761300000000000003, 1761400000000011640); +insert into sys_role_menu values (1761300000000000003, 1761400000000011641); +insert into sys_role_menu values (1761300000000000003, 1761400000000011642); +insert into sys_role_menu values (1761300000000000003, 1761400000000011643); +insert into sys_role_menu values (1761300000000000003, 1761400000000011701); +insert into sys_role_menu values (1761300000000000004, 1761400000000000005); +insert into sys_role_menu values (1761300000000000004, 1761400000000001500); +insert into sys_role_menu values (1761300000000000004, 1761400000000001501); +insert into sys_role_menu values (1761300000000000004, 1761400000000001502); +insert into sys_role_menu values (1761300000000000004, 1761400000000001503); +insert into sys_role_menu values (1761300000000000004, 1761400000000001504); +insert into sys_role_menu values (1761300000000000004, 1761400000000001505); +insert into sys_role_menu values (1761300000000000004, 1761400000000001506); +insert into sys_role_menu values (1761300000000000004, 1761400000000001507); +insert into sys_role_menu values (1761300000000000004, 1761400000000001508); +insert into sys_role_menu values (1761300000000000004, 1761400000000001509); +insert into sys_role_menu values (1761300000000000004, 1761400000000001510); +insert into sys_role_menu values (1761300000000000004, 1761400000000001511); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table sys_role_dept ( + role_id number(20) not null, + dept_id number(20) not null +); + +alter table sys_role_dept add constraint pk_sys_role_dept primary key (role_id, dept_id); + +comment on table sys_role_dept is '角色和部门关联表'; +comment on column sys_role_dept.role_id is '角色ID'; +comment on column sys_role_dept.dept_id is '部门ID'; + + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table sys_user_post ( + user_id number(20) not null, + post_id number(20) not null +); + +alter table sys_user_post add constraint pk_sys_user_post primary key (user_id, post_id); + +comment on table sys_user_post is '用户与岗位关联表'; +comment on column sys_user_post.user_id is '用户ID'; +comment on column sys_user_post.post_id is '岗位ID'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values (1761100000000000001, 1761200000000000001); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table sys_oper_log ( + oper_id number(20) not null, + title varchar2(50) default '', + business_type number(2) default 0, + method varchar2(100) default '', + request_method varchar2(10) default '', + operator_type number(1) default 0, + oper_name varchar2(50) default '', + user_id number(20) default null, + dept_id number(20) default null, + dept_name varchar2(50) default '', + client_key varchar2(32) default '', + device_type varchar2(32) default '', + browser varchar2(50) default '', + os varchar2(50) default '', + oper_url varchar2(255) default '', + oper_ip varchar2(128) default '', + oper_location varchar2(255) default '', + oper_param varchar2(4000) default '', + json_result varchar2(4000) default '', + status number(1) default 0, + error_msg varchar2(4000) default '', + oper_time date, + cost_time number(20) default 0 +); + +alter table sys_oper_log add constraint pk_sys_oper_log primary key (oper_id); +create index idx_sys_oper_log_bt on sys_oper_log (business_type); +create index idx_sys_oper_log_uid on sys_oper_log (user_id); +create index idx_sys_oper_log_s on sys_oper_log (status); +create index idx_sys_oper_log_ot on sys_oper_log (oper_time); + +comment on table sys_oper_log is '操作日志记录'; +comment on column sys_oper_log.oper_id is '日志主键'; +comment on column sys_oper_log.title is '模块标题'; +comment on column sys_oper_log.business_type is '业务类型(0其它 1新增 2修改 3删除)'; +comment on column sys_oper_log.method is '方法名称'; +comment on column sys_oper_log.request_method is '请求方式'; +comment on column sys_oper_log.operator_type is '操作类别(0其它 1后台用户 2手机端用户)'; +comment on column sys_oper_log.oper_name is '操作人员'; +comment on column sys_oper_log.user_id is '操作用户ID'; +comment on column sys_oper_log.dept_id is '操作部门ID'; +comment on column sys_oper_log.dept_name is '部门名称'; +comment on column sys_oper_log.client_key is '客户端'; +comment on column sys_oper_log.device_type is '设备类型'; +comment on column sys_oper_log.browser is '浏览器类型'; +comment on column sys_oper_log.os is '操作系统'; +comment on column sys_oper_log.oper_url is '请求URL'; +comment on column sys_oper_log.oper_ip is '主机地址'; +comment on column sys_oper_log.oper_location is '操作地点'; +comment on column sys_oper_log.oper_param is '请求参数'; +comment on column sys_oper_log.json_result is '返回参数'; +comment on column sys_oper_log.status is '操作状态(0正常 1异常)'; +comment on column sys_oper_log.error_msg is '错误消息'; +comment on column sys_oper_log.oper_time is '操作时间'; +comment on column sys_oper_log.cost_time is '消耗时间'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table sys_dict_type ( + dict_id number(20) not null, + dict_name varchar2(100) default '', + dict_type varchar2(100) default '', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_dict_type add constraint pk_sys_dict_type primary key (dict_id); +create unique index sys_dict_type_index1 on sys_dict_type (dict_type); + +comment on table sys_dict_type is '字典类型表'; +comment on column sys_dict_type.dict_id is '字典主键'; +comment on column sys_dict_type.dict_name is '字典名称'; +comment on column sys_dict_type.dict_type is '字典类型'; +comment on column sys_dict_type.create_dept is '创建部门'; +comment on column sys_dict_type.create_by is '创建者'; +comment on column sys_dict_type.create_time is '创建时间'; +comment on column sys_dict_type.update_by is '更新者'; +comment on column sys_dict_type.update_time is '更新时间'; +comment on column sys_dict_type.remark is '备注'; + +insert into sys_dict_type values(1761500000000000001, '用户性别', 'sys_user_gender', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '用户性别列表'); +insert into sys_dict_type values(1761500000000000002, '菜单状态', 'sys_show_hide', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '菜单状态列表'); +insert into sys_dict_type values(1761500000000000003, '系统开关', 'sys_normal_disable', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '系统开关列表'); +insert into sys_dict_type values(1761500000000000006, '系统是否', 'sys_yes_no', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '系统是否列表'); +insert into sys_dict_type values(1761500000000000007, '通知类型', 'sys_notice_type', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '通知类型列表'); +insert into sys_dict_type values(1761500000000000008, '通知状态', 'sys_notice_status', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '通知状态列表'); +insert into sys_dict_type values(1761500000000000009, '操作类型', 'sys_oper_type', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '操作类型列表'); +insert into sys_dict_type values(1761500000000000010, '系统状态', 'sys_common_status', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '登录状态列表'); +insert into sys_dict_type values(1761500000000000011, '授权类型', 'sys_grant_type', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '认证授权类型'); +insert into sys_dict_type values(1761500000000000012, '设备类型', 'sys_device_type', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '客户端设备类型'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table sys_dict_data ( + dict_code number(20) not null, + dict_sort number(4) default 0, + dict_label varchar2(100) default '', + dict_value varchar2(100) default '', + dict_type varchar2(100) default '', + css_class varchar2(100) default null, + list_class varchar2(100) default null, + is_default char(1) default 'N', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_dict_data add constraint pk_sys_dict_data primary key (dict_code); + +create index idx_sys_dict_data_type on sys_dict_data (dict_type); + +comment on table sys_dict_data is '字典数据表'; +comment on column sys_dict_data.dict_code is '字典主键'; +comment on column sys_dict_data.dict_sort is '字典排序'; +comment on column sys_dict_data.dict_label is '字典标签'; +comment on column sys_dict_data.dict_value is '字典键值'; +comment on column sys_dict_data.dict_type is '字典类型'; +comment on column sys_dict_data.css_class is '样式属性(其他样式扩展)'; +comment on column sys_dict_data.list_class is '表格回显样式'; +comment on column sys_dict_data.is_default is '是否默认(Y是 N否)'; +comment on column sys_dict_data.create_dept is '创建部门'; +comment on column sys_dict_data.create_by is '创建者'; +comment on column sys_dict_data.create_time is '创建时间'; +comment on column sys_dict_data.update_by is '更新者'; +comment on column sys_dict_data.update_time is '更新时间'; +comment on column sys_dict_data.remark is '备注'; + +insert into sys_dict_data values(1761600000000000001, 1, '男', '0', 'sys_user_gender', '', '', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '性别男'); +insert into sys_dict_data values(1761600000000000002, 2, '女', '1', 'sys_user_gender', '', '', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '性别女'); +insert into sys_dict_data values(1761600000000000003, 3, '未知', '2', 'sys_user_gender', '', '', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '性别未知'); +insert into sys_dict_data values(1761600000000000004, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '显示菜单'); +insert into sys_dict_data values(1761600000000000005, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '隐藏菜单'); +insert into sys_dict_data values(1761600000000000006, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '正常状态'); +insert into sys_dict_data values(1761600000000000007, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '停用状态'); +insert into sys_dict_data values(1761600000000000012, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '系统默认是'); +insert into sys_dict_data values(1761600000000000013, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '系统默认否'); +insert into sys_dict_data values(1761600000000000014, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '通知'); +insert into sys_dict_data values(1761600000000000015, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '公告'); +insert into sys_dict_data values(1761600000000000016, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '正常状态'); +insert into sys_dict_data values(1761600000000000017, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '关闭状态'); +insert into sys_dict_data values(1761600000000000029, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '其他操作'); +insert into sys_dict_data values(1761600000000000018, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '新增操作'); +insert into sys_dict_data values(1761600000000000019, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '修改操作'); +insert into sys_dict_data values(1761600000000000020, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '删除操作'); +insert into sys_dict_data values(1761600000000000021, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '授权操作'); +insert into sys_dict_data values(1761600000000000022, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '导出操作'); +insert into sys_dict_data values(1761600000000000023, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '导入操作'); +insert into sys_dict_data values(1761600000000000024, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '强退操作'); +insert into sys_dict_data values(1761600000000000025, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '生成操作'); +insert into sys_dict_data values(1761600000000000026, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '清空操作'); +insert into sys_dict_data values(1761600000000000027, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '正常状态'); +insert into sys_dict_data values(1761600000000000028, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '停用状态'); +insert into sys_dict_data values(1761600000000000030, 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '密码认证'); +insert into sys_dict_data values(1761600000000000031, 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '短信认证'); +insert into sys_dict_data values(1761600000000000032, 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '邮件认证'); +insert into sys_dict_data values(1761600000000000033, 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '小程序认证'); +insert into sys_dict_data values(1761600000000000034, 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '三方登录认证'); +insert into sys_dict_data values(1761600000000000035, 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, 'PC'); +insert into sys_dict_data values(1761600000000000036, 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '安卓'); +insert into sys_dict_data values(1761600000000000037, 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, 'iOS'); +insert into sys_dict_data values(1761600000000000038, 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table sys_config ( + config_id number(20) not null, + config_name varchar2(100) default '', + config_key varchar2(100) default '', + config_value varchar2(100) default '', + config_type char(1) default 'N', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); +alter table sys_config add constraint pk_sys_config primary key (config_id); + +comment on table sys_config is '参数配置表'; +comment on column sys_config.config_id is '参数主键'; +comment on column sys_config.config_name is '参数名称'; +comment on column sys_config.config_key is '参数键名'; +comment on column sys_config.config_value is '参数键值'; +comment on column sys_config.config_type is '系统内置(Y是 N否)'; +comment on column sys_config.create_dept is '创建部门'; +comment on column sys_config.create_by is '创建者'; +comment on column sys_config.create_time is '创建时间'; +comment on column sys_config.update_by is '更新者'; +comment on column sys_config.update_time is '更新时间'; +comment on column sys_config.remark is '备注'; + +insert into sys_config values(1761700000000000001, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '初始化密码 123456'); +insert into sys_config values(1761700000000000002, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(1761700000000000003, 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table sys_login_info ( + info_id number(20) not null, + user_name varchar2(50) default '', + client_key varchar2(32) default '', + device_type varchar2(32) default '', + ipaddr varchar2(128) default '', + login_location varchar2(255) default '', + browser varchar2(50) default '', + os varchar2(50) default '', + status char(1) default '0', + msg varchar2(255) default '', + login_time date +); + +alter table sys_login_info add constraint pk_sys_login_info primary key (info_id); +create index idx_sys_login_info_s on sys_login_info (status); +create index idx_sys_login_info_lt on sys_login_info (login_time); + +comment on table sys_login_info is '系统访问记录'; +comment on column sys_login_info.info_id is '访问ID'; +comment on column sys_login_info.user_name is '登录账号'; +comment on column sys_login_info.client_key is '客户端'; +comment on column sys_login_info.device_type is '设备类型'; +comment on column sys_login_info.ipaddr is '登录IP地址'; +comment on column sys_login_info.login_location is '登录地点'; +comment on column sys_login_info.browser is '浏览器类型'; +comment on column sys_login_info.os is '操作系统'; +comment on column sys_login_info.status is '登录状态(0正常 1异常)'; +comment on column sys_login_info.msg is '提示消息'; +comment on column sys_login_info.login_time is '访问时间'; + + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table sys_notice ( + notice_id number(20) not null, + notice_title varchar2(50) not null, + notice_type char(1) not null, + notice_content clob default null, + status char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(255) default null +); + +alter table sys_notice add constraint pk_sys_notice primary key (notice_id); + +comment on table sys_notice is '通知公告表'; +comment on column sys_notice.notice_id is '公告主键'; +comment on column sys_notice.notice_title is '公告标题'; +comment on column sys_notice.notice_type is '公告类型(1通知 2公告)'; +comment on column sys_notice.notice_content is '公告内容'; +comment on column sys_notice.status is '公告状态(0正常 1关闭)'; +comment on column sys_notice.create_dept is '创建部门'; +comment on column sys_notice.create_by is '创建者'; +comment on column sys_notice.create_time is '创建时间'; +comment on column sys_notice.update_by is '更新者'; +comment on column sys_notice.update_time is '更新时间'; +comment on column sys_notice.remark is '备注'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values(1761800000000000001, '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '管理员'); +insert into sys_notice values(1761800000000000002, '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 1761000000000000103, 1761100000000000001, sysdate, NULL, null, '管理员'); + + +-- ---------------------------- +-- 18、消息记录表 +-- ---------------------------- +create table sys_message ( + message_id number(20) not null, + category varchar2(20) not null, + type varchar2(20) not null, + source varchar2(20) not null, + title varchar2(100) default '', + message varchar2(500) default '', + content clob default null, + data_json clob default null, + path varchar2(500) default null, + send_user_ids varchar2(2000) default '0' not null, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_message add constraint pk_sys_message primary key (message_id); + +create index idx_sys_message_category_time on sys_message(category, create_time); + +comment on table sys_message is '消息记录表'; +comment on column sys_message.message_id is '消息ID'; +comment on column sys_message.category is '消息分组(system/notice/workflow)'; +comment on column sys_message.type is '消息类型'; +comment on column sys_message.source is '消息来源'; +comment on column sys_message.title is '标题'; +comment on column sys_message.message is '摘要消息'; +comment on column sys_message.content is '详细内容'; +comment on column sys_message.data_json is '扩展数据JSON'; +comment on column sys_message.path is '前端跳转路径'; +comment on column sys_message.send_user_ids is '目标用户ID串,0表示全局'; +comment on column sys_message.create_dept is '创建部门'; +comment on column sys_message.create_by is '创建者'; +comment on column sys_message.create_time is '创建时间'; +comment on column sys_message.update_by is '更新者'; +comment on column sys_message.update_time is '更新时间'; + + +-- ---------------------------- +-- 19、代码生成业务表 +-- ---------------------------- +create table gen_table ( + table_id number(20) not null, + data_name varchar2(200) default '', + table_name varchar2(200) default '', + table_comment varchar2(500) default '', + class_name varchar2(100) default '', + tpl_category varchar2(200) default 'crud', + frontend_type varchar2(50) default 'vue', + package_name varchar2(100), + module_name varchar2(30), + business_name varchar2(30), + function_name varchar2(50), + function_author varchar2(50), + gen_type char(1) default '0', + gen_path varchar2(200) default '/', + options varchar2(1000), + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table gen_table add constraint pk_gen_table primary key (table_id); + +comment on table gen_table is '代码生成业务表'; +comment on column gen_table.table_id is '编号'; +comment on column gen_table.data_name is '数据源名称'; +comment on column gen_table.table_name is '表名称'; +comment on column gen_table.table_comment is '表描述'; +comment on column gen_table.class_name is '实体类名称'; +comment on column gen_table.tpl_category is '使用的模板(crud单表操作 tree树表操作)'; +comment on column gen_table.frontend_type is '前端模板类型,对应 vm 下的模板目录'; +comment on column gen_table.package_name is '生成包路径'; +comment on column gen_table.module_name is '生成模块名'; +comment on column gen_table.business_name is '生成业务名'; +comment on column gen_table.function_name is '生成功能名'; +comment on column gen_table.function_author is '生成功能作者'; +comment on column gen_table.gen_type is '生成代码方式(0zip压缩包 1自定义路径)'; +comment on column gen_table.gen_path is '生成路径(不填默认项目路径)'; +comment on column gen_table.options is '其它生成选项'; +comment on column gen_table.create_dept is '创建部门'; +comment on column gen_table.create_by is '创建者'; +comment on column gen_table.create_time is '创建时间'; +comment on column gen_table.update_by is '更新者'; +comment on column gen_table.update_time is '更新时间'; +comment on column gen_table.remark is '备注'; + + +-- ---------------------------- +-- 20、代码生成业务表字段 +-- ---------------------------- +create table gen_table_column ( + column_id number(20) not null, + table_id number(20), + column_name varchar2(200), + column_comment varchar2(500), + column_type varchar2(100), + java_type varchar2(500), + java_field varchar2(200), + is_pk char(1), + is_increment char(1), + is_required char(1), + is_insert char(1), + is_edit char(1), + is_list char(1), + is_query char(1), + query_type varchar2(200) default 'EQ', + html_type varchar2(200), + dict_type varchar2(200) default '', + sort number(4), + create_dept number(20) default null, + create_by number(20) default null, + create_time date , + update_by number(20) default null, + update_time date +); + +alter table gen_table_column add constraint pk_gen_table_column primary key (column_id); + +comment on table gen_table_column is '代码生成业务表字段'; +comment on column gen_table_column.column_id is '编号'; +comment on column gen_table_column.table_id is '归属表编号'; +comment on column gen_table_column.column_name is '列名称'; +comment on column gen_table_column.column_comment is '列描述'; +comment on column gen_table_column.column_type is '列类型'; +comment on column gen_table_column.java_type is 'JAVA类型'; +comment on column gen_table_column.java_field is 'JAVA字段名'; +comment on column gen_table_column.is_pk is '是否主键(1是)'; +comment on column gen_table_column.is_increment is '是否自增(1是)'; +comment on column gen_table_column.is_required is '是否必填(1是)'; +comment on column gen_table_column.is_insert is '是否为插入字段(1是)'; +comment on column gen_table_column.is_edit is '是否编辑字段(1是)'; +comment on column gen_table_column.is_list is '是否列表字段(1是)'; +comment on column gen_table_column.is_query is '是否查询字段(1是)'; +comment on column gen_table_column.query_type is '查询方式(等于、不等于、大于、小于、范围)'; +comment on column gen_table_column.html_type is '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)'; +comment on column gen_table_column.dict_type is '字典类型'; +comment on column gen_table_column.sort is '排序'; +comment on column gen_table_column.create_dept is '创建部门'; +comment on column gen_table_column.create_by is '创建者'; +comment on column gen_table_column.create_time is '创建时间'; +comment on column gen_table_column.update_by is '更新者'; +comment on column gen_table_column.update_time is '更新时间'; + + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table sys_oss ( + oss_id number(20) not null, + file_name varchar2(255) not null, + original_name varchar2(255) not null, + file_suffix varchar2(10) not null, + url varchar2(500) not null, + service varchar2(20) default 'minio' not null, + ext1 varchar2(500) default '', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_oss add constraint pk_sys_oss primary key (oss_id); + +comment on table sys_oss is 'OSS对象存储表'; +comment on column sys_oss.oss_id is '对象存储主键'; +comment on column sys_oss.file_name is '文件名'; +comment on column sys_oss.original_name is '原名'; +comment on column sys_oss.file_suffix is '文件后缀名'; +comment on column sys_oss.url is 'URL地址'; +comment on column sys_oss.service is '服务商'; +comment on column sys_oss.ext1 is '扩展字段'; +comment on column sys_oss.create_dept is '创建部门'; +comment on column sys_oss.create_time is '创建时间'; +comment on column sys_oss.create_by is '上传者'; +comment on column sys_oss.update_time is '更新时间'; +comment on column sys_oss.update_by is '更新者'; + + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table sys_oss_config ( + oss_config_id number(20) not null, + config_key varchar2(20) not null, + access_key varchar2(255) default '', + secret_key varchar2(255) default '', + bucket_name varchar2(255) default '', + prefix varchar2(255) default '', + endpoint varchar2(255) default '', + domain_url varchar2(255) default '', + is_https char(1) default 'N', + region varchar2(255) default '', + access_policy char(1) default '1' not null, + status char(1) default 'N', + ext1 varchar2(255) default '', + remark varchar2(500) default null, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_oss_config add constraint pk_sys_oss_config primary key (oss_config_id); + +comment on table sys_oss_config is '对象存储配置表'; +comment on column sys_oss_config.oss_config_id is '主键'; +comment on column sys_oss_config.config_key is '配置key'; +comment on column sys_oss_config.access_key is 'accesskey'; +comment on column sys_oss_config.secret_key is '秘钥'; +comment on column sys_oss_config.bucket_name is '桶名称'; +comment on column sys_oss_config.prefix is '前缀'; +comment on column sys_oss_config.endpoint is '访问站点'; +comment on column sys_oss_config.domain_url is '自定义域名'; +comment on column sys_oss_config.is_https is '是否https(Y=是,N=否)'; +comment on column sys_oss_config.region is '域'; +comment on column sys_oss_config.access_policy is '桶权限类型(0=private 1=public 2=custom)'; +comment on column sys_oss_config.status is '是否默认(Y=是,N=否)'; +comment on column sys_oss_config.ext1 is '扩展字段'; +comment on column sys_oss_config.remark is '备注'; +comment on column sys_oss_config.create_dept is '创建部门'; +comment on column sys_oss_config.create_by is '创建者'; +comment on column sys_oss_config.create_time is '创建时间'; +comment on column sys_oss_config.update_by is '更新者'; +comment on column sys_oss_config.update_time is '更新时间'; + +insert into sys_oss_config values (1761900000000000001, 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '', 'N', '', '1', 'Y', '', NULL, 1761000000000000103, 1761100000000000001, sysdate, 1761100000000000001, sysdate); +insert into sys_oss_config values (1761900000000000002, 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '', 'N', '', '1', 'N', '', NULL, 1761000000000000103, 1761100000000000001, sysdate, 1761100000000000001, sysdate); +insert into sys_oss_config values (1761900000000000003, 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '', 'N', '', '1', 'N', '', NULL, 1761000000000000103, 1761100000000000001, sysdate, 1761100000000000001, sysdate); +insert into sys_oss_config values (1761900000000000004, 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1250000000', '', 'cos.ap-beijing.myqcloud.com', '', 'N', 'ap-beijing', '1', 'N', '', NULL, 1761000000000000103, 1761100000000000001, sysdate, 1761100000000000001, sysdate); +insert into sys_oss_config values (1761900000000000005, 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '', 'N', '', '1', 'N', '', NULL, 1761000000000000103, 1761100000000000001, sysdate, 1761100000000000001, sysdate); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id number(20) not null, + client_id varchar2(64) default null, + client_key varchar2(32) default null, + client_secret varchar2(255) default null, + grant_type varchar2(255) default null, + device_type varchar2(32) default null, + access_path varchar2(2000) default null, + ip_whitelist varchar2(1000) default null, + active_timeout number(11) default 1800, + timeout number(11) default 604800, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_client add constraint pk_sys_client primary key (id); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.access_path is '允许访问路径'; +comment on column sys_client.ip_whitelist is 'IP白名单'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1762000000000000001, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', null, null, 1800, 604800, 0, 0, 1761000000000000103, 1761100000000000001, sysdate, 1761100000000000001, sysdate); +insert into sys_client values (1762000000000000002, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', '/app/**', null, 1800, 604800, 0, 0, 1761000000000000103, 1761100000000000001, sysdate, 1761100000000000001, sysdate); + +create table test_demo ( + id number(20) not null, + dept_id number(20) default null, + user_id number(20) default null, + order_num number(10) default 0, + test_key varchar2(255) default null, + value varchar2(255) default null, + version number(10) default 0, + create_dept number(20) default null, + create_time date, + create_by number(20) default null, + update_time date, + update_by number(20) default null, + del_flag number(2) default 0 +); + +alter table test_demo add constraint pk_test_demo primary key (id); + +comment on table test_demo is '测试单表'; +comment on column test_demo.id is '主键'; +comment on column test_demo.dept_id is '部门id'; +comment on column test_demo.user_id is '用户id'; +comment on column test_demo.order_num is '排序号'; +comment on column test_demo.test_key is 'key键'; +comment on column test_demo.value is '值'; +comment on column test_demo.version is '版本'; +comment on column test_demo.create_dept is '创建部门'; +comment on column test_demo.create_time is '创建时间'; +comment on column test_demo.create_by is '创建人'; +comment on column test_demo.update_time is '更新时间'; +comment on column test_demo.update_by is '更新人'; +comment on column test_demo.del_flag is '删除标志'; + +create table test_tree ( + id number(20) not null, + parent_id number(20) default 0, + dept_id number(20) default null, + user_id number(20) default null, + tree_name varchar2(255) default null, + version number(10) default 0, + create_dept number(20) default null, + create_time date, + create_by number(20) default null, + update_time date, + update_by number(20) default null, + del_flag number(2) default 0 +); + +alter table test_tree add constraint pk_test_tree primary key (id); + +comment on table test_tree is '测试树表'; +comment on column test_tree.id is '主键'; +comment on column test_tree.parent_id is '父id'; +comment on column test_tree.dept_id is '部门id'; +comment on column test_tree.user_id is '用户id'; +comment on column test_tree.tree_name is '值'; +comment on column test_tree.version is '版本'; +comment on column test_tree.create_dept is '创建部门'; +comment on column test_tree.create_time is '创建时间'; +comment on column test_tree.create_by is '创建人'; +comment on column test_tree.update_time is '更新时间'; +comment on column test_tree.update_by is '更新人'; +comment on column test_tree.del_flag is '删除标志'; + +insert into test_demo values (1762100000000000001, 1761000000000000102, 1761100000000000004, 1, '测试数据权限', '测试', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000002, 1761000000000000102, 1761100000000000003, 2, '子节点1', '111', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000003, 1761000000000000102, 1761100000000000003, 3, '子节点2', '222', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000004, 1761000000000000108, 1761100000000000004, 4, '测试数据', 'demo', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000005, 1761000000000000108, 1761100000000000003, 13, '子节点11', '1111', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000006, 1761000000000000108, 1761100000000000003, 12, '子节点22', '2222', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000007, 1761000000000000108, 1761100000000000003, 11, '子节点33', '3333', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000008, 1761000000000000108, 1761100000000000003, 10, '子节点44', '4444', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000009, 1761000000000000108, 1761100000000000003, 9, '子节点55', '5555', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000010, 1761000000000000108, 1761100000000000003, 8, '子节点66', '6666', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000011, 1761000000000000108, 1761100000000000003, 7, '子节点77', '7777', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000012, 1761000000000000108, 1761100000000000003, 6, '子节点88', '8888', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_demo values (1762100000000000013, 1761000000000000108, 1761100000000000003, 5, '子节点99', '9999', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); + +insert into test_tree values (1762200000000000001, NULL, 1761000000000000102, 1761100000000000004, '测试数据权限', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000002, 1762200000000000001, 1761000000000000102, 1761100000000000003, '子节点1', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000003, 1762200000000000002, 1761000000000000102, 1761100000000000003, '子节点2', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000004, NULL, 1761000000000000108, 1761100000000000004, '测试树1', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000005, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点11', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000006, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点22', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000007, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点33', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000008, 1762200000000000005, 1761000000000000108, 1761100000000000003, '子节点44', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000009, 1762200000000000006, 1761000000000000108, 1761100000000000003, '子节点55', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000010, 1762200000000000007, 1761000000000000108, 1761100000000000003, '子节点66', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000011, 1762200000000000007, 1761000000000000108, 1761100000000000003, '子节点77', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000012, 1762200000000000010, 1761000000000000108, 1761100000000000003, '子节点88', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); +insert into test_tree values (1762200000000000013, 1762200000000000010, 1761000000000000108, 1761100000000000003, '子节点99', 0, 1761000000000000103, sysdate, 1761100000000000001, null, NULL, 0); + + +-- ---------------------------- +-- 钩子 ,用于session连接之后 自动设置默认的date类型格式化 简化时间查询 +-- 如需设置其它配置 可在此钩子内任意增加处理语句 +-- 例如: SELECT * FROM sys_user WHERE create_time BETWEEN '2022-03-01 00:00:00' AND '2022-04-01 00:00:00' +-- ---------------------------- +create or replace trigger login_trg +after logon on database +begin +execute immediate 'alter session set nls_date_format=''YYYY-MM-DD HH24:MI:SS'''; +end; + diff --git a/script/sql/oracle/oracle_ry_workflow.sql b/script/sql/oracle/oracle_ry_workflow.sql new file mode 100644 index 000000000..11df353c2 --- /dev/null +++ b/script/sql/oracle/oracle_ry_workflow.sql @@ -0,0 +1,549 @@ +-- ---------------------------- +-- 0、warm-flow-all.sql,地址:https://gitee.com/dromara/warm-flow/blob/master/sql/oracle/oracle-wram-flow-all.sql +-- ---------------------------- +create table FLOW_DEFINITION +( + ID NUMBER(20) not null, + FLOW_CODE VARCHAR2(40) not null, + FLOW_NAME VARCHAR2(100) not null, + MODEL_VALUE VARCHAR2(40) default 'CLASSICS' not null, + CATEGORY VARCHAR2(100), + VERSION VARCHAR2(20) not null, + IS_PUBLISH NUMBER(1) default 0 not null, + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + ACTIVITY_STATUS NUMBER(1) default 1, + LISTENER_TYPE VARCHAR2(100), + LISTENER_PATH VARCHAR2(500), + EXT VARCHAR2(500), + CREATE_TIME DATE, + CREATE_BY VARCHAR2(64) default '', + UPDATE_TIME DATE, + UPDATE_BY VARCHAR2(64) default '', + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_DEFINITION + add constraint PK_FLOW_DEFINITION primary key (ID); + +comment on table FLOW_DEFINITION is '流程定义表'; +comment on column FLOW_DEFINITION.ID is '主键id'; +comment on column FLOW_DEFINITION.FLOW_CODE is '流程编码'; +comment on column FLOW_DEFINITION.FLOW_NAME is '流程名称'; +comment on column FLOW_DEFINITION.MODEL_VALUE is '设计器模型(CLASSICS经典模型 MIMIC仿钉钉模型)'; +comment on column FLOW_DEFINITION.CATEGORY is '流程类别'; +comment on column FLOW_DEFINITION.VERSION is '流程版本'; +comment on column FLOW_DEFINITION.IS_PUBLISH is '是否发布 (0未发布 1已发布 9失效)'; +comment on column FLOW_DEFINITION.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_DEFINITION.FORM_PATH is '审批表单路径'; +comment on column FLOW_DEFINITION.ACTIVITY_STATUS is '流程激活状态(0挂起 1激活)'; +comment on column FLOW_DEFINITION.LISTENER_TYPE is '监听器类型'; +comment on column FLOW_DEFINITION.LISTENER_PATH is '监听器路径'; +comment on column FLOW_DEFINITION.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_DEFINITION.CREATE_TIME is '创建时间'; +comment on column FLOW_DEFINITION.CREATE_BY is '创建人'; +comment on column FLOW_DEFINITION.UPDATE_TIME is '更新时间'; +comment on column FLOW_DEFINITION.UPDATE_BY is '更新人'; +comment on column FLOW_DEFINITION.DEL_FLAG is '删除标志'; +comment on column FLOW_DEFINITION.TENANT_ID is '租户id'; + +create table FLOW_NODE +( + ID NUMBER(20) not null, + NODE_TYPE NUMBER(1) not null, + DEFINITION_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100) not null, + NODE_NAME VARCHAR2(100), + PERMISSION_FLAG VARCHAR2(200), + NODE_RATIO VARCHAR2(200), + COORDINATE VARCHAR2(100), + ANY_NODE_SKIP VARCHAR2(100), + LISTENER_TYPE VARCHAR2(100), + LISTENER_PATH VARCHAR2(500), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + VERSION VARCHAR2(20), + CREATE_TIME DATE, + CREATE_BY VARCHAR2(64) default '', + UPDATE_TIME DATE, + UPDATE_BY VARCHAR2(64) default '', + EXT CLOB, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_NODE + add constraint PK_FLOW_NODE primary key (ID); + +comment on table FLOW_NODE is '流程节点表'; +comment on column FLOW_NODE.ID is '主键id'; +comment on column FLOW_NODE.NODE_TYPE is '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_NODE.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_NODE.NODE_CODE is '流程节点编码'; +comment on column FLOW_NODE.NODE_NAME is '流程节点名称'; +comment on column FLOW_NODE.NODE_RATIO is '流程签署比例值'; +comment on column FLOW_NODE.COORDINATE is '坐标'; +comment on column FLOW_NODE.ANY_NODE_SKIP is '任意结点跳转'; +comment on column FLOW_NODE.LISTENER_TYPE is '监听器类型'; +comment on column FLOW_NODE.LISTENER_PATH is '监听器路径'; +comment on column FLOW_NODE.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_NODE.FORM_PATH is '审批表单路径'; +comment on column FLOW_NODE.VERSION is '版本'; +comment on column FLOW_NODE.CREATE_TIME is '创建时间'; +comment on column FLOW_NODE.CREATE_BY is '创建人'; +comment on column FLOW_NODE.UPDATE_TIME is '更新时间'; +comment on column FLOW_NODE.UPDATE_BY is '更新人'; +comment on column FLOW_NODE.EXT is '节点扩展属性'; +comment on column FLOW_NODE.DEL_FLAG is '删除标志'; +comment on column FLOW_NODE.TENANT_ID is '租户id'; +comment on column FLOW_NODE.PERMISSION_FLAG is '权限标识(权限类型:权限标识,可以多个,用@@隔开)'; + +create table FLOW_SKIP +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + NOW_NODE_CODE VARCHAR2(100) not null, + NOW_NODE_TYPE NUMBER(1), + NEXT_NODE_CODE VARCHAR2(100) not null, + NEXT_NODE_TYPE NUMBER(1), + SKIP_NAME VARCHAR2(100), + SKIP_TYPE VARCHAR2(40), + SKIP_CONDITION VARCHAR2(200), + COORDINATE VARCHAR2(100), + CREATE_TIME DATE, + CREATE_BY VARCHAR2(64) default '', + UPDATE_TIME DATE, + UPDATE_BY VARCHAR2(64) default '', + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_SKIP + add constraint PK_FLOW_SKIP primary key (ID); + +comment on table FLOW_SKIP is '节点跳转关联表'; +comment on column FLOW_SKIP.ID is '主键id'; +comment on column FLOW_SKIP.DEFINITION_ID is '流程定义id'; +comment on column FLOW_SKIP.NOW_NODE_CODE is '当前流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.NOW_NODE_TYPE is '下一个流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.NEXT_NODE_CODE is '下一个流程节点编码'; +comment on column FLOW_SKIP.NEXT_NODE_TYPE is '下一个流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.SKIP_NAME is '跳转名称'; +comment on column FLOW_SKIP.SKIP_TYPE is '跳转类型 (PASS审批通过 REJECT退回)'; +comment on column FLOW_SKIP.SKIP_CONDITION is '跳转条件'; +comment on column FLOW_SKIP.COORDINATE is '坐标'; +comment on column FLOW_SKIP.CREATE_TIME is '创建时间'; +comment on column FLOW_SKIP.CREATE_BY is '创建人'; +comment on column FLOW_SKIP.UPDATE_TIME is '更新时间'; +comment on column FLOW_SKIP.UPDATE_BY is '更新人'; +comment on column FLOW_SKIP.DEL_FLAG is '删除标志'; +comment on column FLOW_SKIP.TENANT_ID is '租户id'; + +create table FLOW_INSTANCE +( + ID NUMBER not null, + DEFINITION_ID NUMBER not null, + BUSINESS_ID VARCHAR2(40) not null, + NODE_TYPE NUMBER(1), + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + VARIABLE CLOB, + FLOW_STATUS VARCHAR2(20), + ACTIVITY_STATUS NUMBER(1) default 1, + DEF_JSON CLOB, + CREATE_TIME DATE, + CREATE_BY VARCHAR2(64) default '', + UPDATE_TIME DATE, + UPDATE_BY VARCHAR2(64) default '', + EXT VARCHAR2(500), + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_INSTANCE + add constraint PK_FLOW_INSTANCE primary key (ID); + +comment on table FLOW_INSTANCE is '流程实例表'; +comment on column FLOW_INSTANCE.ID is '主键id'; +comment on column FLOW_INSTANCE.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_INSTANCE.BUSINESS_ID is '业务id'; +comment on column FLOW_INSTANCE.NODE_TYPE is '开始节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_INSTANCE.NODE_CODE is '开始节点编码'; +comment on column FLOW_INSTANCE.NODE_NAME is '开始节点名称'; +comment on column FLOW_INSTANCE.VARIABLE is '任务变量'; +comment on column FLOW_INSTANCE.FLOW_STATUS is '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)'; +comment on column FLOW_INSTANCE.ACTIVITY_STATUS is '流程激活状态(0挂起 1激活)'; +comment on column FLOW_INSTANCE.DEF_JSON is '流程定义json'; +comment on column FLOW_INSTANCE.CREATE_TIME is '创建时间'; +comment on column FLOW_INSTANCE.CREATE_BY is '创建人'; +comment on column FLOW_INSTANCE.UPDATE_TIME is '更新时间'; +comment on column FLOW_INSTANCE.UPDATE_BY is '更新人'; +comment on column FLOW_INSTANCE.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_INSTANCE.DEL_FLAG is '删除标志'; +comment on column FLOW_INSTANCE.TENANT_ID is '租户id'; + +create table FLOW_TASK +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + INSTANCE_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + NODE_TYPE NUMBER(1), + FLOW_STATUS VARCHAR2(20), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + CREATE_TIME DATE, + CREATE_BY VARCHAR2(64) default '', + UPDATE_TIME DATE, + UPDATE_BY VARCHAR2(64) default '', + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_TASK + add constraint PK_FLOW_TASK primary key (ID); + +comment on table FLOW_TASK is '待办任务表'; +comment on column FLOW_TASK.ID is '主键id'; +comment on column FLOW_TASK.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_TASK.INSTANCE_ID is '对应flow_instance表的id'; +comment on column FLOW_TASK.NODE_CODE is '节点编码'; +comment on column FLOW_TASK.NODE_NAME is '节点名称'; +comment on column FLOW_TASK.NODE_TYPE is '节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_TASK.FLOW_STATUS is '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)'; +comment on column FLOW_TASK.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_TASK.FORM_PATH is '审批表单路径'; +comment on column FLOW_TASK.CREATE_TIME is '创建时间'; +comment on column FLOW_TASK.CREATE_BY is '创建人'; +comment on column FLOW_TASK.UPDATE_TIME is '更新时间'; +comment on column FLOW_TASK.UPDATE_BY is '更新人'; +comment on column FLOW_TASK.DEL_FLAG is '删除标志'; +comment on column FLOW_TASK.TENANT_ID is '租户id'; + +create table FLOW_HIS_TASK +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + INSTANCE_ID NUMBER(20) not null, + TASK_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + NODE_TYPE NUMBER(1), + TARGET_NODE_CODE VARCHAR2(200), + TARGET_NODE_NAME VARCHAR2(200), + APPROVER VARCHAR2(40), + COOPERATE_TYPE NUMBER(1) default 0, + COLLABORATOR VARCHAR2(500), + SKIP_TYPE VARCHAR2(10), + FLOW_STATUS VARCHAR2(20), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + MESSAGE VARCHAR2(500), + VARIABLE CLOB, + EXT CLOB, + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) + +); + +alter table FLOW_HIS_TASK + add constraint PK_FLOW_HIS_TASK primary key (ID); + +comment on table FLOW_HIS_TASK is '历史任务记录表'; +comment on column FLOW_HIS_TASK.ID is '主键id'; +comment on column FLOW_HIS_TASK.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_HIS_TASK.INSTANCE_ID is '对应flow_instance表的id'; +comment on column FLOW_HIS_TASK.TASK_ID is '对应flow_task表的id'; +comment on column FLOW_HIS_TASK.NODE_CODE is '开始节点编码'; +comment on column FLOW_HIS_TASK.NODE_NAME is '开始节点名称'; +comment on column FLOW_HIS_TASK.NODE_TYPE is '开始节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_HIS_TASK.TARGET_NODE_CODE is '目标节点编码'; +comment on column FLOW_HIS_TASK.TARGET_NODE_NAME is '目标节点名称'; +comment on column FLOW_HIS_TASK.SKIP_TYPE is '流转类型(PASS通过 REJECT退回 NONE无动作)'; +comment on column FLOW_HIS_TASK.FLOW_STATUS is '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)'; +comment on column FLOW_HIS_TASK.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_HIS_TASK.FORM_PATH is '审批表单路径'; +comment on column FLOW_HIS_TASK.MESSAGE is '审批意见'; +comment on column FLOW_HIS_TASK.VARIABLE is '任务变量'; +comment on column FLOW_HIS_TASK.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_HIS_TASK.CREATE_TIME is '任务开始时间'; +comment on column FLOW_HIS_TASK.UPDATE_TIME is '审批完成时间'; +comment on column FLOW_HIS_TASK.DEL_FLAG is '删除标志'; +comment on column FLOW_HIS_TASK.TENANT_ID is '租户id'; +comment on column FLOW_HIS_TASK.APPROVER is '审批者'; +comment on column FLOW_HIS_TASK.COOPERATE_TYPE is '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)'; +comment on column FLOW_HIS_TASK.COLLABORATOR is '协作人'; + +create table FLOW_USER +( + ID NUMBER(20) not null, + TYPE VARCHAR2(1) not null, + PROCESSED_BY VARCHAR2(80), + ASSOCIATED NUMBER(20) not null, + CREATE_TIME DATE, + CREATE_BY VARCHAR2(64) default '', + UPDATE_TIME DATE, + UPDATE_BY VARCHAR2(64) default '', + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_USER + add constraint PK_FLOW_USER primary key (ID); + +comment on table FLOW_USER is '待办任务表'; +comment on column FLOW_USER.ID is '主键id'; +comment on column FLOW_USER.TYPE is '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)'; +comment on column FLOW_USER.PROCESSED_BY is '权限人)'; +comment on column FLOW_USER.ASSOCIATED is '任务表id'; +comment on column FLOW_USER.CREATE_TIME is '创建时间'; +comment on column FLOW_USER.CREATE_BY is '创建人'; +comment on column FLOW_USER.UPDATE_TIME is '更新时间'; +comment on column FLOW_USER.UPDATE_BY is '更新人'; +comment on column FLOW_USER.DEL_FLAG is '删除标志'; +comment on column FLOW_USER.TENANT_ID is '租户id'; + +create index USER_PROCESSED_TYPE on FLOW_USER (PROCESSED_BY, TYPE); +create index USER_ASSOCIATED_IDX on FLOW_USER (ASSOCIATED); + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +CREATE TABLE flow_category +( + category_id NUMBER(20) NOT NULL, + tenant_id VARCHAR2(20) DEFAULT '000000', + parent_id NUMBER(20) DEFAULT 0, + ancestors VARCHAR2(500) DEFAULT '', + category_name VARCHAR2(30) NOT NULL, + order_num NUMBER(4) DEFAULT 0, + del_flag CHAR(1) DEFAULT '0', + create_dept NUMBER(20), + create_by NUMBER(20), + create_time DATE, + update_by NUMBER(20), + update_time DATE +); + +alter table flow_category add constraint pk_flow_category primary key (category_id); + +COMMENT ON TABLE flow_category IS '流程分类'; +COMMENT ON COLUMN flow_category.category_id IS '流程分类ID'; +COMMENT ON COLUMN flow_category.tenant_id IS '租户编号'; +COMMENT ON COLUMN flow_category.parent_id IS '父流程分类id'; +COMMENT ON COLUMN flow_category.ancestors IS '祖级列表'; +COMMENT ON COLUMN flow_category.category_name IS '流程分类名称'; +COMMENT ON COLUMN flow_category.order_num IS '显示顺序'; +COMMENT ON COLUMN flow_category.del_flag IS '删除标志(0代表存在 1代表删除)'; +COMMENT ON COLUMN flow_category.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_category.create_by IS '创建者'; +COMMENT ON COLUMN flow_category.create_time IS '创建时间'; +COMMENT ON COLUMN flow_category.update_by IS '更新者'; +COMMENT ON COLUMN flow_category.update_time IS '更新时间'; + +INSERT INTO flow_category VALUES (1762300000000000100, 0, '0', 'OA审批', 0, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000101, 1762300000000000100, '0,1762300000000000100', '假勤管理', 0, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000102, 1762300000000000100, '0,1762300000000000100', '人事管理', 1, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000103, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '请假', 0, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000104, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '出差', 1, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000105, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '加班', 2, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000106, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '换班', 3, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000107, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '外出', 4, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000108, 1762300000000000102, '0,1762300000000000100,1762300000000000102', '转正', 1, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000109, 1762300000000000102, '0,1762300000000000100,1762300000000000102', '离职', 2, '0', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL); + +-- ---------------------------- +-- 流程spel表达式定义表 +-- ---------------------------- +CREATE TABLE flow_spel ( + id NUMBER(20) NOT NULL, + component_name VARCHAR2(255), + method_name VARCHAR2(255), + method_params VARCHAR2(255), + view_spel VARCHAR2(255), + remark VARCHAR2(255), + status CHAR(1) DEFAULT '0', + del_flag CHAR(1) DEFAULT '0', + create_dept NUMBER(20), + create_by NUMBER(20), + create_time DATE, + update_by NUMBER(20), + update_time DATE +); + +alter table flow_spel add constraint pk_flow_spel primary key (id); + +COMMENT ON TABLE flow_spel IS '流程spel表达式定义表'; +COMMENT ON COLUMN flow_spel.id IS '主键id'; +COMMENT ON COLUMN flow_spel.component_name IS '组件名称'; +COMMENT ON COLUMN flow_spel.method_name IS '方法名'; +COMMENT ON COLUMN flow_spel.method_params IS '参数'; +COMMENT ON COLUMN flow_spel.view_spel IS '预览spel表达式'; +COMMENT ON COLUMN flow_spel.remark IS '备注'; +COMMENT ON COLUMN flow_spel.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN flow_spel.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_spel.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_spel.create_by IS '创建者'; +COMMENT ON COLUMN flow_spel.create_time IS '创建时间'; +COMMENT ON COLUMN flow_spel.update_by IS '更新者'; +COMMENT ON COLUMN flow_spel.update_time IS '更新时间'; + +INSERT INTO flow_spel VALUES (1762400000000000001, 'spelRuleComponent', 'selectDeptLeaderById', 'initiatorDeptId', '#{@spelRuleComponent.selectDeptLeaderById(#initiatorDeptId)}', '根据部门id获取部门负责人', '0', '0', 1761000000000000103, 1761100000000000001, SYSDATE, 1761100000000000001, SYSDATE); +INSERT INTO flow_spel VALUES (1762400000000000002, NULL, NULL, 'initiator', '${initiator}', '流程发起人', '0', '0', 1761000000000000103, 1761100000000000001, SYSDATE, 1761100000000000001, SYSDATE); + +-- ---------------------------- +-- 流程实例业务扩展表 +-- ---------------------------- +CREATE TABLE flow_instance_biz_ext ( + id NUMBER(20), + tenant_id VARCHAR2(20) DEFAULT '000000', + create_dept NUMBER(20), + create_by NUMBER(20), + create_time TIMESTAMP, + update_by NUMBER(20), + update_time TIMESTAMP, + business_code VARCHAR2(255), + business_title VARCHAR2(1000), + del_flag CHAR(1) DEFAULT '0', + instance_id NUMBER(20), + business_id VARCHAR2(255) +); + +alter table flow_instance_biz_ext add constraint pk_fi_biz_ext primary key (id); + +COMMENT ON TABLE flow_instance_biz_ext IS '流程实例业务扩展表'; +COMMENT ON COLUMN flow_instance_biz_ext.id IS '主键id'; +COMMENT ON COLUMN flow_instance_biz_ext.tenant_id IS '租户编号'; +COMMENT ON COLUMN flow_instance_biz_ext.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_instance_biz_ext.create_by IS '创建者'; +COMMENT ON COLUMN flow_instance_biz_ext.create_time IS '创建时间'; +COMMENT ON COLUMN flow_instance_biz_ext.update_by IS '更新者'; +COMMENT ON COLUMN flow_instance_biz_ext.update_time IS '更新时间'; +COMMENT ON COLUMN flow_instance_biz_ext.business_code IS '业务编码'; +COMMENT ON COLUMN flow_instance_biz_ext.business_title IS '业务标题'; +COMMENT ON COLUMN flow_instance_biz_ext.del_flag IS '删除标志(0代表存在 1代表删除)'; +COMMENT ON COLUMN flow_instance_biz_ext.instance_id IS '流程实例Id'; +COMMENT ON COLUMN flow_instance_biz_ext.business_id IS '业务Id'; + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- +CREATE TABLE test_leave +( + id NUMBER (20) NOT NULL, + tenant_id VARCHAR2 (20) DEFAULT '000000', + apply_code VARCHAR2 (50) NOT NULL, + leave_type VARCHAR2 (255) NOT NULL, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + leave_days NUMBER (10) NOT NULL, + remark VARCHAR2 (255), + status VARCHAR2 (255), + create_dept NUMBER (20), + create_by NUMBER (20), + create_time DATE, + update_by NUMBER (20), + update_time DATE +); + +alter table test_leave add constraint pk_test_leave primary key (id); + +COMMENT ON TABLE test_leave IS '请假申请表'; +COMMENT ON COLUMN test_leave.id IS 'ID'; +COMMENT ON COLUMN test_leave.tenant_id IS '租户编号'; +COMMENT ON COLUMN test_leave.apply_code IS '申请编号'; +COMMENT ON COLUMN test_leave.leave_type IS '请假类型'; +COMMENT ON COLUMN test_leave.start_date IS '开始时间'; +COMMENT ON COLUMN test_leave.end_date IS '结束时间'; +COMMENT ON COLUMN test_leave.leave_days IS '请假天数'; +COMMENT ON COLUMN test_leave.remark IS '请假原因'; +COMMENT ON COLUMN test_leave.status IS '状态'; +COMMENT ON COLUMN test_leave.create_dept IS '创建部门'; +COMMENT ON COLUMN test_leave.create_by IS '创建者'; +COMMENT ON COLUMN test_leave.create_time IS '创建时间'; +COMMENT ON COLUMN test_leave.update_by IS '更新者'; +COMMENT ON COLUMN test_leave.update_time IS '更新时间'; + +INSERT INTO sys_menu VALUES (1761400000000011616, '工作流', 0, 6, 'workflow', '', '', 'N', 'Y', 'M', '0', '0', '', 'workflow', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011618, '我的任务', 0, 7, 'task', '', '', 'N', 'Y', 'M', '0', '0', '', 'my-task', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011619, '我的待办', 1761400000000011618, 2, 'taskWaiting', 'workflow/task/taskWaiting', '', 'N', 'N', 'C', '0', '0', '', 'waiting', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011632, '我的已办', 1761400000000011618, 3, 'taskFinish', 'workflow/task/taskFinish', '', 'N', 'N', 'C', '0', '0', '', 'finish', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011633, '我的抄送', 1761400000000011618, 4, 'taskCopyList', 'workflow/task/taskCopyList', '', 'N', 'N', 'C', '0', '0', '', 'my-copy', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011620, '流程定义', 1761400000000011616, 3, 'processDefinition', 'workflow/processDefinition/index', '', 'N', 'N', 'C', '0', '0', 'workflow:definition:list', 'process-definition', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011621, '流程实例', 1761400000000011630, 1, 'processInstance', 'workflow/processInstance/index', '', 'N', 'N', 'C', '0', '0', 'workflow:instance:list', 'tree-table', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011622, '流程分类', 1761400000000011616, 1, 'category', 'workflow/category/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:category:list', 'category', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011629, '我发起的', 1761400000000011618, 1, 'myDocument', 'workflow/task/myDocument', '', 'N', 'N', 'C', '0', '0', 'workflow:instance:currentList', 'guide', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011630, '流程监控', 1761400000000011616, 4, 'processMonitor', '', '', 'N', 'Y', 'M', '0', '0', '', 'monitor', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011631, '待办任务', 1761400000000011630, 2, 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', 'N', 'N', 'C', '0', '0', 'workflow:task:list', 'waiting', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011660, '待办任务修改', 1761400000000011631, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:task:edit', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011700, '流程设计', 1761400000000011616, 5, 'design/index', 'workflow/processDefinition/design', '', 'N', 'N', 'C', '1', '0', 'workflow:leave:edit', '#', '/workflow/processDefinition', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011701, '请假申请', 1761400000000011616, 6, 'leaveEdit/index', 'workflow/leave/leaveEdit', '', 'N', 'N', 'C', '1', '0', 'workflow:leave:edit', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_menu VALUES (1761400000000011623, '流程分类查询', 1761400000000011622, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:query', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011624, '流程分类新增', 1761400000000011622, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:add', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011625, '流程分类修改', 1761400000000011622, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:edit', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011626, '流程分类删除', 1761400000000011622, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:remove', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011627, '流程分类导出', 1761400000000011622, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:export', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); + +-- 流程实例管理相关按钮 +INSERT INTO sys_menu VALUES (1761400000000011653, '流程实例查询', 1761400000000011621, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:query', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011654, '流程变量查询', 1761400000000011621, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variableQuery', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011655, '流程变量修改', 1761400000000011621, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variable', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011656, '流程实例激活/挂起', 1761400000000011621, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:active', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011657, '流程实例删除', 1761400000000011621, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:remove', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011658, '流程实例作废', 1761400000000011621, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:invalid', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011659, '流程实例撤销', 1761400000000011621, 7, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:cancel', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); + +-- 流程定义管理相关按钮 +INSERT INTO sys_menu VALUES (1761400000000011644, '流程定义查询', 1761400000000011620, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:query', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011645, '流程定义新增', 1761400000000011620, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:add', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011646, '流程定义修改', 1761400000000011620, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:edit', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011647, '流程定义删除', 1761400000000011620, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:remove', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011648, '流程定义导出', 1761400000000011620, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:export', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011649, '流程定义导入', 1761400000000011620, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:import', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011650, '流程定义发布/取消发布', 1761400000000011620, 7, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:publish', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011651, '流程定义复制', 1761400000000011620, 8, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:copy', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011652, '流程定义激活/挂起', 1761400000000011620, 9, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:active', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_menu VALUES (1761400000000011801, '流程表达式', 1761400000000011616, 2, 'spel', 'workflow/spel/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:spel:list', 'input', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, 1761100000000000001, SYSDATE, '流程达式定义菜单'); +INSERT INTO sys_menu VALUES (1761400000000011802, '流程spel表达式定义查询', 1761400000000011801, 1, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:query', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011803, '流程spel表达式定义新增', 1761400000000011801, 2, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:add', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011804, '流程spel表达式定义修改', 1761400000000011801, 3, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:edit', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011805, '流程spel表达式定义删除', 1761400000000011801, 4, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:remove', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011806, '流程spel表达式定义导出', 1761400000000011801, 5, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:export', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_menu VALUES (1761400000000011638, '请假申请', 1761400000000000005, 1, 'leave', 'workflow/leave/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:leave:list', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu VALUES (1761400000000011639, '请假申请查询', 1761400000000011638, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:query', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011640, '请假申请新增', 1761400000000011638, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:add', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011641, '请假申请修改', 1761400000000011638, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:edit', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011642, '请假申请删除', 1761400000000011638, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:remove', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011643, '请假申请导出', 1761400000000011638, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:export', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (1761500000000000013, '业务状态', 'wf_business_status', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (1761500000000000014, '表单类型', 'wf_form_type', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (1761500000000000015, '任务状态', 'wf_task_status', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (1761600000000000039, 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data VALUES (1761600000000000040, 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (1761600000000000041, 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (1761600000000000042, 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '已完成'); +INSERT INTO sys_dict_data VALUES (1761600000000000043, 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '已作废'); +INSERT INTO sys_dict_data VALUES (1761600000000000044, 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '已退回'); +INSERT INTO sys_dict_data VALUES (1761600000000000045, 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (1761600000000000046, 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data VALUES (1761600000000000047, 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '动态表单'); +INSERT INTO sys_dict_data VALUES (1761600000000000048, 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (1761600000000000049, 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (1761600000000000050, 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (1761600000000000051, 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (1761600000000000052, 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (1761600000000000053, 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (1761600000000000054, 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (1761600000000000055, 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (1761600000000000056, 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (1761600000000000057, 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (1761600000000000058, 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (1761600000000000059, 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '超时'); diff --git a/script/sql/postgres/postgres_ry_ai.sql b/script/sql/postgres/postgres_ry_ai.sql new file mode 100644 index 000000000..8d45a4d2f --- /dev/null +++ b/script/sql/postgres/postgres_ry_ai.sql @@ -0,0 +1,861 @@ +-- ============================================================ +-- Snail AI PostgreSQL 全量建表脚本(仅 CREATE,无 ALTER) +-- 使用:psql -U user -d snail_ai -f postgres_ry_ai.sql +-- 结构来源:snail_ai_schema.sql +-- ============================================================ + +-- ============================================================ +-- 公共触发器函数:模拟 MySQL ON UPDATE CURRENT_TIMESTAMP +-- ============================================================ +CREATE OR REPLACE FUNCTION update_timestamp() +RETURNS TRIGGER AS $$ +BEGIN + NEW.update_dt = CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION update_timestamp_updated() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_dt = CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION update_timestamp_updated_at() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- ============================================================ +-- 一、用户与权限 +-- ============================================================ + +-- 1.1 用户表 +CREATE TABLE sai_user +( + id BIGSERIAL PRIMARY KEY, + role INT, + totals INT, + username VARCHAR(255), + nickname VARCHAR(128) DEFAULT NULL, + email VARCHAR(64), + password VARCHAR(255) NOT NULL, + resource_id BIGINT DEFAULT NULL, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_username UNIQUE (username) +); + +COMMENT ON COLUMN sai_user.nickname IS '用户昵称'; +COMMENT ON COLUMN sai_user.resource_id IS '头像资源ID,关联 sai_resource.id'; + +CREATE TRIGGER trigger_sai_user_update + BEFORE UPDATE ON sai_user + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +-- 1.2 OpenAPI 外部用户映射表 +CREATE TABLE sai_openapi_user +( + id BIGSERIAL PRIMARY KEY, + app_id VARCHAR(128) NOT NULL, + open_id VARCHAR(64) NOT NULL, + platform_user_id BIGINT NOT NULL, + external_id VARCHAR(256) DEFAULT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_app_open UNIQUE (app_id, open_id), + CONSTRAINT uk_app_external UNIQUE (app_id, external_id) +); + +COMMENT ON TABLE sai_openapi_user IS 'OpenAPI 外部用户映射表'; +COMMENT ON COLUMN sai_openapi_user.app_id IS '关联 sai_app.app_id'; +COMMENT ON COLUMN sai_openapi_user.open_id IS '平台分配的唯一标识(UUID)'; +COMMENT ON COLUMN sai_openapi_user.platform_user_id IS '关联 sai_user.id,注册时自动创建'; +COMMENT ON COLUMN sai_openapi_user.external_id IS '外部系统的用户标识(可选,幂等用)'; + +CREATE TRIGGER trigger_sai_openapi_user_update + BEFORE UPDATE ON sai_openapi_user + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_open_id ON sai_openapi_user (open_id); +CREATE INDEX idx_platform_user ON sai_openapi_user (platform_user_id); + +-- ============================================================ +-- 二、AI 模型管理 +-- ============================================================ + +-- 2.1 AI 模型提供商表 +CREATE TABLE IF NOT EXISTS sai_model_provider +( + id BIGSERIAL PRIMARY KEY, + provider_name VARCHAR(255) NOT NULL, + provider_key VARCHAR(50) NOT NULL, + description TEXT, + icon_url VARCHAR(500), + is_enabled BOOLEAN DEFAULT TRUE, + created_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_provider_name UNIQUE (provider_name), + CONSTRAINT uk_provider_key UNIQUE (provider_key) +); + +COMMENT ON TABLE sai_model_provider IS 'AI模型提供商表'; +COMMENT ON COLUMN sai_model_provider.provider_name IS '提供商名称'; +COMMENT ON COLUMN sai_model_provider.provider_key IS '提供商标识符'; +COMMENT ON COLUMN sai_model_provider.description IS '提供商描述'; +COMMENT ON COLUMN sai_model_provider.icon_url IS 'LOGO图标URL'; +COMMENT ON COLUMN sai_model_provider.is_enabled IS '是否启用'; +COMMENT ON COLUMN sai_model_provider.created_dt IS '创建时间'; +COMMENT ON COLUMN sai_model_provider.updated_dt IS '更新时间'; + +CREATE TRIGGER trigger_sai_model_provider_update + BEFORE UPDATE ON sai_model_provider + FOR EACH ROW + EXECUTE FUNCTION update_timestamp_updated(); + +CREATE INDEX idx_provider_key ON sai_model_provider (provider_key); +CREATE INDEX idx_is_enabled ON sai_model_provider (is_enabled); + +-- 2.2 AI模型配置表 +CREATE TABLE IF NOT EXISTS sai_model_config +( + id BIGSERIAL PRIMARY KEY, + provider_id BIGINT NOT NULL, + model_name VARCHAR(255) NOT NULL, + model_key VARCHAR(100) NOT NULL, + model_type VARCHAR(50) NOT NULL, + adapter_key VARCHAR(100), + description VARCHAR(1000), + api_key VARCHAR(1000), + api_endpoint VARCHAR(500), + config_json TEXT, + owner_id BIGINT, + scope VARCHAR(20) NOT NULL DEFAULT 'GLOBAL', + is_default BOOLEAN DEFAULT FALSE, + is_enabled BOOLEAN DEFAULT TRUE, + created_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON TABLE sai_model_config IS 'AI模型配置表'; +COMMENT ON COLUMN sai_model_config.provider_id IS '提供商ID'; +COMMENT ON COLUMN sai_model_config.model_name IS '模型名称'; +COMMENT ON COLUMN sai_model_config.model_key IS '模型标识符'; +COMMENT ON COLUMN sai_model_config.model_type IS '模型类型(CHAT/EMBEDDING/RERANKER/IMAGE/SPEECH)'; +COMMENT ON COLUMN sai_model_config.adapter_key IS '底层协议适配器标识(openai-compatible/http等)'; +COMMENT ON COLUMN sai_model_config.description IS '模型描述'; +COMMENT ON COLUMN sai_model_config.api_key IS 'API密钥(加密存储)'; +COMMENT ON COLUMN sai_model_config.api_endpoint IS 'API端点URL'; +COMMENT ON COLUMN sai_model_config.config_json IS '模型参数配置(JSON格式)'; +COMMENT ON COLUMN sai_model_config.owner_id IS '所有者ID(NULL=全局,具体值=用户ID)'; +COMMENT ON COLUMN sai_model_config.scope IS '作用域(GLOBAL/PERSONAL)'; +COMMENT ON COLUMN sai_model_config.is_default IS '是否为默认模型'; +COMMENT ON COLUMN sai_model_config.is_enabled IS '是否启用'; +COMMENT ON COLUMN sai_model_config.created_dt IS '创建时间'; +COMMENT ON COLUMN sai_model_config.updated_dt IS '更新时间'; + +CREATE TRIGGER trigger_sai_model_config_update + BEFORE UPDATE ON sai_model_config + FOR EACH ROW + EXECUTE FUNCTION update_timestamp_updated(); + +CREATE INDEX fk_provider_id ON sai_model_config (provider_id); + +CREATE INDEX idx_provider_model_type ON sai_model_config (provider_id, model_type); +CREATE INDEX idx_model_type_enabled ON sai_model_config (model_type, is_enabled); +CREATE INDEX idx_owner_id ON sai_model_config (owner_id); +CREATE INDEX idx_is_default ON sai_model_config (is_default); +CREATE INDEX idx_scope ON sai_model_config (scope); +CREATE INDEX idx_model_key ON sai_model_config (model_key); + +-- 2.3 模型使用统计表 +CREATE TABLE IF NOT EXISTS sai_model_usage_stat +( + id BIGSERIAL PRIMARY KEY, + model_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + total_calls BIGINT DEFAULT 0, + success_calls BIGINT DEFAULT 0, + failed_calls BIGINT DEFAULT 0, + total_tokens_used BIGINT DEFAULT 0, + total_cost DECIMAL(18, 8) DEFAULT 0, + avg_response_time BIGINT DEFAULT 0, + last_used_dt TIMESTAMP NULL DEFAULT NULL, + created_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT unique_model_user UNIQUE (model_id, user_id) +); + +COMMENT ON TABLE sai_model_usage_stat IS '模型使用统计表'; +COMMENT ON COLUMN sai_model_usage_stat.model_id IS '模型ID'; +COMMENT ON COLUMN sai_model_usage_stat.user_id IS '用户ID'; +COMMENT ON COLUMN sai_model_usage_stat.total_calls IS '总调用次数'; +COMMENT ON COLUMN sai_model_usage_stat.success_calls IS '成功调用次数'; +COMMENT ON COLUMN sai_model_usage_stat.failed_calls IS '失败调用次数'; +COMMENT ON COLUMN sai_model_usage_stat.total_tokens_used IS '总Token使用量'; +COMMENT ON COLUMN sai_model_usage_stat.total_cost IS '总费用'; +COMMENT ON COLUMN sai_model_usage_stat.avg_response_time IS '平均响应时间(毫秒)'; +COMMENT ON COLUMN sai_model_usage_stat.last_used_dt IS '最后使用时间'; +COMMENT ON COLUMN sai_model_usage_stat.created_dt IS '创建时间'; +COMMENT ON COLUMN sai_model_usage_stat.updated_dt IS '更新时间'; + +CREATE TRIGGER trigger_sai_model_usage_stat_update + BEFORE UPDATE ON sai_model_usage_stat + FOR EACH ROW + EXECUTE FUNCTION update_timestamp_updated(); + +CREATE INDEX fk_stat_model_id ON sai_model_usage_stat (model_id); + +CREATE INDEX idx_model_id ON sai_model_usage_stat (model_id); +CREATE INDEX idx_user_id ON sai_model_usage_stat (user_id); +CREATE INDEX idx_last_used_dt ON sai_model_usage_stat (last_used_dt); + +-- ============================================================ +-- 三、智能体(Agent) +-- ============================================================ + +-- 3.1 智能体主表 +CREATE TABLE IF NOT EXISTS sai_agent +( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description TEXT, + avatar VARCHAR(512), + instruction TEXT, + greeting TEXT, + preset_questions TEXT, + chat_model_id BIGINT, + memory_enabled BOOLEAN DEFAULT FALSE, + mcp_enabled BOOLEAN DEFAULT FALSE, + skill_enabled BOOLEAN DEFAULT FALSE, + web_search_enabled BOOLEAN DEFAULT FALSE, + rag_enabled BOOLEAN DEFAULT FALSE, + rag_ids VARCHAR(64) NULL, + rag_call_mode SMALLINT DEFAULT 1, + short_term_memory_size INT DEFAULT 20, + creator_id BIGINT, + is_featured BOOLEAN DEFAULT FALSE, + view_count INT DEFAULT 0, + status SMALLINT DEFAULT 1, + config TEXT, + app_id VARCHAR(128) NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON TABLE sai_agent IS '智能体表'; +COMMENT ON COLUMN sai_agent.name IS '智能体名称'; +COMMENT ON COLUMN sai_agent.description IS '智能体描述'; +COMMENT ON COLUMN sai_agent.avatar IS '头像URL'; +COMMENT ON COLUMN sai_agent.instruction IS '系统指令(System Prompt)'; +COMMENT ON COLUMN sai_agent.greeting IS '欢迎语'; +COMMENT ON COLUMN sai_agent.preset_questions IS '预设问题列表(JSON数组字符串)'; +COMMENT ON COLUMN sai_agent.chat_model_id IS '关联的对话模型ID'; +COMMENT ON COLUMN sai_agent.memory_enabled IS '是否启用记忆库'; +COMMENT ON COLUMN sai_agent.mcp_enabled IS '是否启用MCP'; +COMMENT ON COLUMN sai_agent.skill_enabled IS '是否启用Skill'; +COMMENT ON COLUMN sai_agent.web_search_enabled IS '是否启用联网搜索'; +COMMENT ON COLUMN sai_agent.rag_enabled IS '是否启用RAG'; +COMMENT ON COLUMN sai_agent.rag_ids IS '绑定的RAG ID列表,逗号分隔,最多5个'; +COMMENT ON COLUMN sai_agent.rag_call_mode IS 'RAG调用方式: 1=智能调用 2=强制调用'; +COMMENT ON COLUMN sai_agent.short_term_memory_size IS '短期记忆滑动窗口保留条数'; +COMMENT ON COLUMN sai_agent.creator_id IS '创建者用户ID'; +COMMENT ON COLUMN sai_agent.is_featured IS '是否精选'; +COMMENT ON COLUMN sai_agent.view_count IS '浏览次数'; +COMMENT ON COLUMN sai_agent.status IS '状态: 1-活跃 2-非活跃 3-已废弃 4-已禁用'; +COMMENT ON COLUMN sai_agent.config IS '扩展配置(预留)'; +COMMENT ON COLUMN sai_agent.app_id IS '关联应用ID(NULL=本地执行)'; + +CREATE TRIGGER trigger_sai_agent_update + BEFORE UPDATE ON sai_agent + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_agent_creator ON sai_agent (creator_id); +CREATE INDEX idx_agent_featured ON sai_agent (is_featured); + +-- 3.2 智能体对话表 +CREATE TABLE IF NOT EXISTS sai_agent_conversation +( + id BIGSERIAL PRIMARY KEY, + agent_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + conversation_id VARCHAR(64) NOT NULL, + title VARCHAR(255), + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_conv_id UNIQUE (conversation_id) +); + +COMMENT ON TABLE sai_agent_conversation IS '智能体对话表'; +COMMENT ON COLUMN sai_agent_conversation.agent_id IS '智能体ID'; +COMMENT ON COLUMN sai_agent_conversation.user_id IS '用户ID'; +COMMENT ON COLUMN sai_agent_conversation.conversation_id IS '对话ID(UUID)'; +COMMENT ON COLUMN sai_agent_conversation.title IS '对话标题'; + +CREATE TRIGGER trigger_sai_agent_conversation_update + BEFORE UPDATE ON sai_agent_conversation + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_agent_conv_agent ON sai_agent_conversation (agent_id); +CREATE INDEX idx_agent_conv_user ON sai_agent_conversation (user_id); + +-- 3.3 智能体对话消息记录表 +CREATE TABLE IF NOT EXISTS sai_agent_conversation_record +( + id BIGSERIAL PRIMARY KEY, + agent_id BIGINT NOT NULL, + conversation_id VARCHAR(64) NOT NULL, + user_id BIGINT NOT NULL, + role VARCHAR(16) DEFAULT 'user', + content TEXT, + thinking TEXT, + metadata TEXT DEFAULT NULL, + status INT DEFAULT 1, + input_tokens INT DEFAULT 0, + output_tokens INT DEFAULT 0, + cache_tokens INT DEFAULT 0, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON TABLE sai_agent_conversation_record IS '智能体对话消息记录'; +COMMENT ON COLUMN sai_agent_conversation_record.agent_id IS '智能体ID'; +COMMENT ON COLUMN sai_agent_conversation_record.conversation_id IS '对话ID'; +COMMENT ON COLUMN sai_agent_conversation_record.user_id IS '用户ID'; +COMMENT ON COLUMN sai_agent_conversation_record.role IS 'user/assistant'; +COMMENT ON COLUMN sai_agent_conversation_record.content IS '消息内容'; +COMMENT ON COLUMN sai_agent_conversation_record.thinking IS '思考过程(仅assistant)'; +COMMENT ON COLUMN sai_agent_conversation_record.metadata IS '消息扩展元数据JSON'; +COMMENT ON COLUMN sai_agent_conversation_record.status IS '1=成功,2=失败,3=进行中'; +COMMENT ON COLUMN sai_agent_conversation_record.input_tokens IS '输入Token数(prompt)'; +COMMENT ON COLUMN sai_agent_conversation_record.output_tokens IS '输出Token数(completion)'; +COMMENT ON COLUMN sai_agent_conversation_record.cache_tokens IS '缓存命中Token数'; + +CREATE INDEX idx_agent_rec_conv ON sai_agent_conversation_record (conversation_id); + +-- 3.4 智能体使用统计表 +CREATE TABLE IF NOT EXISTS sai_agent_usage_stat +( + id BIGSERIAL PRIMARY KEY, + agent_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + message_count INT DEFAULT 0, + conversation_count INT DEFAULT 0, + stat_date DATE NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_agent_user_date UNIQUE (agent_id, user_id, stat_date) +); + +COMMENT ON TABLE sai_agent_usage_stat IS '智能体使用统计'; +COMMENT ON COLUMN sai_agent_usage_stat.agent_id IS '智能体ID'; +COMMENT ON COLUMN sai_agent_usage_stat.user_id IS '用户ID'; +COMMENT ON COLUMN sai_agent_usage_stat.message_count IS '消息条数'; +COMMENT ON COLUMN sai_agent_usage_stat.conversation_count IS '对话轮次'; +COMMENT ON COLUMN sai_agent_usage_stat.stat_date IS '统计日期'; + +CREATE TRIGGER trigger_sai_agent_usage_stat_update + BEFORE UPDATE ON sai_agent_usage_stat + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_usage_agent ON sai_agent_usage_stat (agent_id); +CREATE INDEX idx_usage_date ON sai_agent_usage_stat (stat_date); + +-- 3.5 用户订阅的智能体(多对多) +CREATE TABLE IF NOT EXISTS sai_user_agent +( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT NOT NULL, + agent_id BIGINT NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_user_agent UNIQUE (user_id, agent_id) +); + +COMMENT ON TABLE sai_user_agent IS '用户订阅的智能体'; +COMMENT ON COLUMN sai_user_agent.user_id IS '用户ID'; +COMMENT ON COLUMN sai_user_agent.agent_id IS '智能体ID'; + +CREATE INDEX idx_user_agent_user ON sai_user_agent (user_id); + +-- ============================================================ +-- 四、RAG 知识库 +-- ============================================================ + +-- 4.1 知识库主表 +CREATE TABLE sai_rag +( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description TEXT, + icon VARCHAR(512), + embedding_model_id BIGINT NOT NULL, + dimension_of_vector_model INT NOT NULL, + rerank_model_id BIGINT, + search_engine_instance_id BIGINT, + vector_store_instance_id BIGINT, + search_engine_enable BOOLEAN DEFAULT FALSE, + delimiter VARCHAR(32) DEFAULT E'\n\n', + rag_enhancement TEXT, + config TEXT DEFAULT NULL, + dedup_strategy SMALLINT NOT NULL DEFAULT 2, + dedup_action SMALLINT NOT NULL DEFAULT 0, + upload_confirm BOOLEAN NOT NULL DEFAULT TRUE, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sai_rag.dimension_of_vector_model IS '向量维度'; +COMMENT ON COLUMN sai_rag.config IS 'RAG检索和问答的页面配置参数'; +COMMENT ON COLUMN sai_rag.dedup_strategy IS '去重策略: 0=NONE 1=BY_NAME 2=BY_CONTENT 3=BY_NAME_OR_CONTENT'; +COMMENT ON COLUMN sai_rag.dedup_action IS '冲突动作: 0=REJECT 1=SKIP 2=OVERWRITE'; +COMMENT ON COLUMN sai_rag.upload_confirm IS '上传前二次确认: 0-关 1-开'; + +CREATE TRIGGER trigger_sai_rag_update + BEFORE UPDATE ON sai_rag + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +-- 4.2 RAG 文档表 +CREATE TABLE sai_rag_document +( + id BIGSERIAL PRIMARY KEY, + rag_id BIGINT NOT NULL, + name VARCHAR(255), + file_type VARCHAR(32), + source_type VARCHAR(32), + source_path VARCHAR(1024), + storage_path VARCHAR(1024), + storage_type VARCHAR(32) DEFAULT 'LOCAL', + file_size BIGINT DEFAULT 0, + content TEXT, + status SMALLINT DEFAULT 0, + error_msg TEXT, + chunk_count INT DEFAULT 0, + page_count INT DEFAULT 0, + element_count INT DEFAULT 0, + table_count INT DEFAULT 0, + image_count INT DEFAULT 0, + parse_time INT DEFAULT 0, + md_content TEXT DEFAULT NULL, + doc_metadata TEXT DEFAULT NULL, + content_hash VARCHAR(64) DEFAULT NULL, + resource_id BIGINT DEFAULT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sai_rag_document.status IS '状态: 0-待处理 1-解析中 2-处理中 3-处理完成 4-处理失败'; +COMMENT ON COLUMN sai_rag_document.content_hash IS '文件内容SHA-256哈希,用于去重'; +COMMENT ON COLUMN sai_rag_document.resource_id IS '关联资源库 sai_resource.id'; + +CREATE TRIGGER trigger_sai_rag_document_update + BEFORE UPDATE ON sai_rag_document + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_rag_doc_rag ON sai_rag_document (rag_id); +CREATE INDEX idx_rag_content_hash ON sai_rag_document (rag_id, content_hash); +CREATE INDEX idx_rag_name ON sai_rag_document (rag_id, name); +CREATE INDEX idx_rag_doc_resource ON sai_rag_document (resource_id); + +CREATE TABLE sai_rag_document_image +( + id BIGSERIAL PRIMARY KEY, + rag_id BIGINT NOT NULL, + document_id BIGINT NOT NULL, + chunk_id BIGINT DEFAULT NULL, + resource_id BIGINT DEFAULT NULL, + image_index INT, + image_url VARCHAR(1024), + caption TEXT, + figure_no VARCHAR(64), + figure_title VARCHAR(512), + section_title VARCHAR(512), + source_page INT, + document_name VARCHAR(255), + ocr_text TEXT, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON TABLE sai_rag_document_image IS 'RAG document parsed image table'; +COMMENT ON COLUMN sai_rag_document_image.resource_id IS 'Linked resource id in sai_resource'; + +CREATE TRIGGER trigger_sai_rag_document_image_update + BEFORE UPDATE ON sai_rag_document_image + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_rag_doc_image_rag ON sai_rag_document_image (rag_id); +CREATE INDEX idx_rag_doc_image_document ON sai_rag_document_image (document_id); +CREATE INDEX idx_rag_doc_image_chunk ON sai_rag_document_image (chunk_id); +CREATE INDEX idx_rag_doc_image_resource ON sai_rag_document_image (resource_id); + +-- 4.3 RAG 分块表 +CREATE TABLE sai_rag_chunk +( + id BIGSERIAL PRIMARY KEY, + rag_id BIGINT NOT NULL, + document_id BIGINT NOT NULL, + paragraph_index INT, + chunk_index INT, + content TEXT, + token_count INT, + vector_id VARCHAR(128), + content_hash VARCHAR(64) DEFAULT NULL, + source_type VARCHAR(20) NOT NULL DEFAULT 'TEXT', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sai_rag_chunk.content_hash IS 'chunk内容SHA-256,用于向量去重'; +COMMENT ON COLUMN sai_rag_chunk.source_type IS 'chunk来源类型:TEXT文本、IMAGE图片'; + +CREATE TRIGGER trigger_sai_rag_chunk_update + BEFORE UPDATE ON sai_rag_chunk + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_rag_chunk_rag ON sai_rag_chunk (rag_id); +CREATE INDEX idx_rag_chunk_document ON sai_rag_chunk (document_id); +CREATE INDEX idx_chunk_rag_hash ON sai_rag_chunk (rag_id, content_hash); +CREATE INDEX idx_chunk_rag_source_type ON sai_rag_chunk (rag_id, source_type); + +-- ============================================================ +-- 五、MCP 服务管理 +-- ============================================================ + +-- 5.1 MCP 服务配置表 +CREATE TABLE IF NOT EXISTS sai_mcp_server +( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description TEXT, + transport_type SMALLINT DEFAULT 1, + base_uri VARCHAR(1024), + endpoint VARCHAR(1024), + command VARCHAR(1024), + args TEXT, + env_vars TEXT, + timeout BIGINT DEFAULT 60000, + headers TEXT, + last_connect_dt TIMESTAMP NULL, + creator_id BIGINT, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON TABLE sai_mcp_server IS 'MCP服务配置表'; +COMMENT ON COLUMN sai_mcp_server.name IS 'MCP服务名称'; +COMMENT ON COLUMN sai_mcp_server.description IS 'MCP服务描述'; +COMMENT ON COLUMN sai_mcp_server.transport_type IS '传输类型: 1-SSE 2-Streamable HTTP 3-Stdio'; +COMMENT ON COLUMN sai_mcp_server.base_uri IS '服务基础地址(SSE/Streamable HTTP时使用)'; +COMMENT ON COLUMN sai_mcp_server.endpoint IS '端点路径(SSE/Streamable HTTP时可选)'; +COMMENT ON COLUMN sai_mcp_server.command IS 'Stdio命令(Stdio时必填)'; +COMMENT ON COLUMN sai_mcp_server.args IS 'Stdio命令参数(JSON数组)'; +COMMENT ON COLUMN sai_mcp_server.env_vars IS 'Stdio环境变量(JSON对象)'; +COMMENT ON COLUMN sai_mcp_server.timeout IS '超时时间(毫秒)'; +COMMENT ON COLUMN sai_mcp_server.headers IS '请求头(JSON对象)'; +COMMENT ON COLUMN sai_mcp_server.last_connect_dt IS '最后连接时间'; +COMMENT ON COLUMN sai_mcp_server.creator_id IS '创建者用户ID'; + +CREATE TRIGGER trigger_sai_mcp_server_update + BEFORE UPDATE ON sai_mcp_server + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_mcp_server_creator ON sai_mcp_server (creator_id); + +-- 5.2 智能体与MCP服务关联表(多对多) +CREATE TABLE IF NOT EXISTS sai_agent_mcp_server +( + id BIGSERIAL PRIMARY KEY, + agent_id BIGINT NOT NULL, + mcp_server_id BIGINT NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_agent_mcp UNIQUE (agent_id, mcp_server_id) +); + +COMMENT ON TABLE sai_agent_mcp_server IS '智能体MCP服务关联表'; +COMMENT ON COLUMN sai_agent_mcp_server.agent_id IS '智能体ID'; +COMMENT ON COLUMN sai_agent_mcp_server.mcp_server_id IS 'MCP服务ID'; + +CREATE INDEX idx_agent_mcp_agent ON sai_agent_mcp_server (agent_id); +CREATE INDEX idx_agent_mcp_server ON sai_agent_mcp_server (mcp_server_id); + +-- ============================================================ +-- 六、Skill 技能包管理 +-- ============================================================ + +-- 6.1 Skill 技能包表 +CREATE TABLE IF NOT EXISTS sai_skill +( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description TEXT, + file_name VARCHAR(255), + file_path VARCHAR(1024), + file_size BIGINT DEFAULT 0, + skill_content TEXT, + storage_path VARCHAR(500) DEFAULT NULL, + version BIGINT DEFAULT 0, + has_files BOOLEAN DEFAULT FALSE, + creator_id BIGINT, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON TABLE sai_skill IS 'Skill技能包表'; +COMMENT ON COLUMN sai_skill.name IS 'Skill名称(从SKILL.md解析)'; +COMMENT ON COLUMN sai_skill.description IS 'Skill描述(从SKILL.md解析)'; +COMMENT ON COLUMN sai_skill.file_name IS '上传的zip文件名'; +COMMENT ON COLUMN sai_skill.file_path IS '解压后存储路径'; +COMMENT ON COLUMN sai_skill.file_size IS '文件大小(字节)'; +COMMENT ON COLUMN sai_skill.skill_content IS 'SKILL.md正文内容(去除frontmatter)'; +COMMENT ON COLUMN sai_skill.storage_path IS '对象存储相对路径前缀(如 skills/123/)'; +COMMENT ON COLUMN sai_skill.version IS '版本号,文件变更时自增,用于缓存一致性校验'; +COMMENT ON COLUMN sai_skill.has_files IS '是否包含支撑文件(0=仅SKILL.md,1=有scripts/references等)'; +COMMENT ON COLUMN sai_skill.creator_id IS '创建者用户ID'; + +CREATE TRIGGER trigger_sai_skill_update + BEFORE UPDATE ON sai_skill + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_skill_creator ON sai_skill (creator_id); + +-- 6.2 Skill 支撑文件内容表 +CREATE TABLE IF NOT EXISTS sai_skill_file +( + id BIGSERIAL PRIMARY KEY, + skill_id BIGINT NOT NULL, + file_path VARCHAR(255) NOT NULL, + content TEXT NOT NULL, + file_size INT NOT NULL, + encoding VARCHAR(50) DEFAULT 'utf-8', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_skill_path UNIQUE (skill_id, file_path) +); + +COMMENT ON TABLE sai_skill_file IS 'Skill支撑文件内容表'; +COMMENT ON COLUMN sai_skill_file.skill_id IS 'Skill ID'; +COMMENT ON COLUMN sai_skill_file.file_path IS '文件相对路径'; +COMMENT ON COLUMN sai_skill_file.content IS '文件内容'; +COMMENT ON COLUMN sai_skill_file.file_size IS '文件大小(字节)'; +COMMENT ON COLUMN sai_skill_file.encoding IS '编码方式'; +COMMENT ON COLUMN sai_skill_file.created_at IS '创建时间'; +COMMENT ON COLUMN sai_skill_file.updated_at IS '更新时间'; + +CREATE TRIGGER trigger_sai_skill_file_update + BEFORE UPDATE ON sai_skill_file + FOR EACH ROW + EXECUTE FUNCTION update_timestamp_updated_at(); + +CREATE INDEX idx_skill_id ON sai_skill_file (skill_id); + +-- 6.3 智能体与Skill关联表(多对多) +CREATE TABLE IF NOT EXISTS sai_agent_skill +( + id BIGSERIAL PRIMARY KEY, + agent_id BIGINT NOT NULL, + skill_id BIGINT NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_agent_skill UNIQUE (agent_id, skill_id) +); + +COMMENT ON TABLE sai_agent_skill IS '智能体Skill关联表'; +COMMENT ON COLUMN sai_agent_skill.agent_id IS '智能体ID'; +COMMENT ON COLUMN sai_agent_skill.skill_id IS 'Skill ID'; + +CREATE INDEX idx_agent_skill_agent ON sai_agent_skill (agent_id); +CREATE INDEX idx_agent_skill_skill ON sai_agent_skill (skill_id); + +-- ============================================================ +-- 七、客户端应用与节点 +-- ============================================================ + +-- 7.1 客户端应用 +CREATE TABLE IF NOT EXISTS sai_app +( + id BIGSERIAL PRIMARY KEY, + app_id VARCHAR(128) NOT NULL, + app_name VARCHAR(255) NOT NULL, + description VARCHAR(512), + token VARCHAR(128) NOT NULL, + route_strategy VARCHAR(32) DEFAULT 'LEAST_LOAD', + status SMALLINT DEFAULT 1, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_app_id UNIQUE (app_id) +); + +COMMENT ON TABLE sai_app IS '客户端应用'; +COMMENT ON COLUMN sai_app.app_id IS '应用唯一标识'; +COMMENT ON COLUMN sai_app.app_name IS '应用名称'; +COMMENT ON COLUMN sai_app.description IS '应用描述'; +COMMENT ON COLUMN sai_app.token IS '通信认证令牌'; +COMMENT ON COLUMN sai_app.route_strategy IS '路由策略'; +COMMENT ON COLUMN sai_app.status IS '1=启用, 0=停用'; + +CREATE TRIGGER trigger_sai_app_update + BEFORE UPDATE ON sai_app + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +-- 7.2 AI客户端实例节点 +CREATE TABLE IF NOT EXISTS sai_client_node +( + id BIGSERIAL PRIMARY KEY, + app_id VARCHAR(128) NOT NULL, + host_id VARCHAR(128) NOT NULL, + host_ip VARCHAR(64) NOT NULL, + grpc_port INT NOT NULL, + max_concurrent INT DEFAULT 10, + active_chats INT DEFAULT 0, + supported_providers TEXT, + labels TEXT, + expire_dt TIMESTAMP NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_client_node UNIQUE (app_id, host_id) +); + +COMMENT ON TABLE sai_client_node IS 'AI客户端实例节点'; +COMMENT ON COLUMN sai_client_node.app_id IS '所属应用ID'; +COMMENT ON COLUMN sai_client_node.host_id IS '客户端实例唯一标识'; +COMMENT ON COLUMN sai_client_node.host_ip IS '客户端IP'; +COMMENT ON COLUMN sai_client_node.grpc_port IS '客户端gRPC端口'; +COMMENT ON COLUMN sai_client_node.max_concurrent IS '最大并发对话数'; +COMMENT ON COLUMN sai_client_node.active_chats IS '当前活跃对话数'; +COMMENT ON COLUMN sai_client_node.supported_providers IS '支持的模型提供商(JSON数组)'; +COMMENT ON COLUMN sai_client_node.labels IS '路由标签'; +COMMENT ON COLUMN sai_client_node.expire_dt IS '过期时间(心跳更新)'; + +CREATE TRIGGER trigger_sai_client_node_update + BEFORE UPDATE ON sai_client_node + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_app_expire ON sai_client_node (app_id, expire_dt); + +-- ============================================================ +-- 八、存储与资源 +-- ============================================================ + +-- 8.1 存储实例 +CREATE TABLE IF NOT EXISTS sai_store_instance +( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(128) NOT NULL, + category SMALLINT NOT NULL, + type SMALLINT NOT NULL, + config TEXT DEFAULT NULL, + status SMALLINT DEFAULT 1, + is_default BOOLEAN DEFAULT FALSE, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON TABLE sai_store_instance IS '存储实例'; +COMMENT ON COLUMN sai_store_instance.name IS '实例名称'; +COMMENT ON COLUMN sai_store_instance.category IS '分类: 1-向量库 2-搜索引擎'; +COMMENT ON COLUMN sai_store_instance.type IS '类型: 1-PG_VECTOR 2-MILVUS 3-ELASTICSEARCH 4-PG_FULLTEXT'; +COMMENT ON COLUMN sai_store_instance.config IS '连接参数 JSON'; +COMMENT ON COLUMN sai_store_instance.status IS '状态: 0-停用 1-启用'; +COMMENT ON COLUMN sai_store_instance.is_default IS '是否为该 category 下默认实例'; + +CREATE TRIGGER trigger_sai_store_instance_update + BEFORE UPDATE ON sai_store_instance + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_store_instance_category ON sai_store_instance (category); +CREATE INDEX idx_store_instance_type ON sai_store_instance (type); + +-- 8.2 通用资源存储 +CREATE TABLE IF NOT EXISTS sai_resource +( + id BIGSERIAL PRIMARY KEY, + storage_key VARCHAR(512) NOT NULL, + original_name VARCHAR(255) NOT NULL, + file_size BIGINT DEFAULT 0, + mime_type VARCHAR(128), + storage_type VARCHAR(32) NOT NULL DEFAULT 'LOCAL', + access_url VARCHAR(1024), + biz_type VARCHAR(64) NOT NULL DEFAULT 'GENERAL', + biz_id BIGINT, + creator_id BIGINT, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_storage_key UNIQUE (storage_key) +); + +COMMENT ON TABLE sai_resource IS '通用资源存储'; +COMMENT ON COLUMN sai_resource.storage_key IS '存储键(相对路径或对象Key)'; +COMMENT ON COLUMN sai_resource.original_name IS '原始文件名'; +COMMENT ON COLUMN sai_resource.file_size IS '文件大小(bytes)'; +COMMENT ON COLUMN sai_resource.mime_type IS 'MIME类型'; +COMMENT ON COLUMN sai_resource.storage_type IS '存储类型: LOCAL/MINIO'; +COMMENT ON COLUMN sai_resource.access_url IS '访问URL'; +COMMENT ON COLUMN sai_resource.biz_type IS '业务类型: AVATAR/ATTACHMENT/DOCUMENT/GENERAL'; +COMMENT ON COLUMN sai_resource.biz_id IS '关联业务ID'; +COMMENT ON COLUMN sai_resource.creator_id IS '上传者ID'; + +CREATE TRIGGER trigger_sai_resource_update + BEFORE UPDATE ON sai_resource + FOR EACH ROW + EXECUTE FUNCTION update_timestamp(); + +CREATE INDEX idx_biz ON sai_resource (biz_type, biz_id); +CREATE INDEX idx_creator ON sai_resource (creator_id); + +-- ============================================================ +-- 九、初始化数据 +-- ============================================================ + +-- 默认管理员:admin / admin123 +INSERT INTO sai_user VALUES (1, 2, NULL, 'admin', 'admin', '', 'pbkdf2$120000$c25haWwtYWktYWRtaW4tMQ==$kakglT/wYKOgv/77Ah1stie58d/JbY2nGgq5DwgUBw4=', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (id) DO NOTHING; + +SELECT setval(pg_get_serial_sequence('sai_user', 'id'), COALESCE((SELECT MAX(id) FROM sai_user), 1), TRUE); + +-- 插入常见的AI提供商 +INSERT INTO sai_model_provider (provider_name, provider_key, description, is_enabled) +VALUES ('OpenAI', 'openai', 'OpenAI官方模型 (GPT-4, GPT-3.5等)', TRUE), + ('Claude', 'claude', 'Anthropic Claude模型', TRUE), + ('Ollama', 'ollama', '本地开源模型 (Llama, Mistral等)', TRUE), + ('Google Gemini', 'gemini', 'Google Gemini模型', TRUE), + ('阿里云百炼', 'qwen', '阿里云百炼 OpenAI 兼容模型 (Qwen等)', TRUE), + ('DeepSeek', 'deepseek', 'DeepSeek OpenAI 兼容模型', TRUE), + ('智谱AI', 'zhipu', '智谱AI OpenAI 兼容模型 (GLM等)', TRUE) +ON CONFLICT (provider_key) DO NOTHING; + +INSERT INTO sai_model_config VALUES (1, 5, 'glm-5.1', 'glm-5.1', 'CHAT', 'openai-compatible', '', '', 'https://dashscope.aliyuncs.com/compatible-mode/v1', '{"frequencyPenalty":0.0,"maxTokens":20000,"presencePenalty":0.0,"stopSequences":[],"stream":true,"temperature":0.7,"timeoutMs":300000,"topK":1,"topP":1.0}', NULL, 'GLOBAL', TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (id) DO NOTHING; + +SELECT setval(pg_get_serial_sequence('sai_model_config', 'id'), COALESCE((SELECT MAX(id) FROM sai_model_config), 1), TRUE); + +INSERT INTO sai_agent VALUES (1, '智测先锋专家', '智测先锋专家是一款专注于软件测试与质量保障领域的智能助手。它能够高效生成覆盖全面的测试用例,深度分析Bug根因并提供修复建议,支持编写自动化测试脚本,以及解读复杂的测试报告。适用于软件开发周期的各个QA阶段,包括单元测试、接口测试、UI自动化及回归测试规划。其核心特点是逻辑严密、注重边界与异常场景,帮助团队大幅提升测试效率与软件质量。', NULL, '你是一位资深的软件测试与质量保障(QA)专家,名为“智测先锋专家”。\n\n【角色定位】你是开发团队的最后一道防线,致力于保障软件产品的卓越质量。\n\n【专业领域】精通黑盒与白盒测试、自动化测试框架(如Selenium、Pytest)、接口与性能测试、安全测试及CI/CD持续集成流程。\n\n【回答风格】逻辑严密、条理清晰、客观专业。善于使用结构化排版(如Markdown列表、代码块、表格)呈现测试用例和步骤,语言精炼,直击痛点。\n\n【行为指南】\n1. 生成测试用例:必须覆盖正常流、异常流、边界值和兼容性等方面,确保测试的全面性与无遗漏。\n2. 分析Bug根因:从代码逻辑、数据状态、环境配置等多维度推导,不仅给出修复建议,更要提供预防性的测试策略。\n3. 编写自动化脚本:确保代码规范、包含必要注释与断言(Assert),并明确说明运行依赖与环境配置。\n4. 需求澄清:若用户提问模糊,主动追问业务背景、技术栈等关键细节,拒绝给出宽泛且无实操价值的答案。\n5. 风险预警:始终秉持质量第一理念,在解答中适时提示潜在的测试盲区与质量风险。', '你好!我是智测先锋专家,你的专属软件测试与质量保障顾问。无论是编写用例还是排查Bug,我都能为你提供专业支持!', '["如何为一个用户登录接口设计全面的测试用例?","帮我分析这个空指针异常Bug的可能根因及修复建议。","请提供一段Python的Pytest接口自动化测试脚本示例。","怎样制定一个高效的回归测试策略?"]', 2, FALSE, FALSE, FALSE, FALSE, FALSE, NULL, 1, 20, 1, FALSE, 1, 1, NULL, '1', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (id) DO NOTHING; + +SELECT setval(pg_get_serial_sequence('sai_agent', 'id'), COALESCE((SELECT MAX(id) FROM sai_agent), 1), TRUE); + +INSERT INTO sai_app VALUES (1, '1', '测试', '', 'SAI_566a6bfbc26e4998b4841cc927d50c5d', 'LEAST_LOAD', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (id) DO NOTHING; + +SELECT setval(pg_get_serial_sequence('sai_app', 'id'), COALESCE((SELECT MAX(id) FROM sai_app), 1), TRUE); + +INSERT INTO sai_openapi_user VALUES (1, '1', '46ed53c6a20044c7bbd870848e80f92f', 1, '1', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (id) DO NOTHING; + +SELECT setval(pg_get_serial_sequence('sai_openapi_user', 'id'), COALESCE((SELECT MAX(id) FROM sai_openapi_user), 1), TRUE); diff --git a/script/sql/postgres/postgres_ry_job.sql b/script/sql/postgres/postgres_ry_job.sql new file mode 100644 index 000000000..9b19c0663 --- /dev/null +++ b/script/sql/postgres/postgres_ry_job.sql @@ -0,0 +1,877 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : PostgreSQL + Date: 2025-06-21 23:23:10 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id bigserial PRIMARY KEY, + name varchar(64) NOT NULL, + unique_id varchar(64) NOT NULL, + description varchar(256) NOT NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name); + +COMMENT ON COLUMN sj_namespace.id IS '主键'; +COMMENT ON COLUMN sj_namespace.name IS '名称'; +COMMENT ON COLUMN sj_namespace.unique_id IS '唯一id'; +COMMENT ON COLUMN sj_namespace.description IS '描述'; +COMMENT ON COLUMN sj_namespace.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_namespace.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_namespace.update_dt IS '修改时间'; +COMMENT ON TABLE sj_namespace IS '命名空间'; + +INSERT INTO sj_namespace VALUES (1, 'Development', 'dev', '', 0, now(), now()); +INSERT INTO sj_namespace VALUES (2, 'Production', 'prod', '', 0, now(), now()); + +-- sj_group_config +CREATE TABLE sj_group_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + description varchar(256) NOT NULL DEFAULT '', + token varchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status smallint NOT NULL DEFAULT 0, + version int NOT NULL, + group_partition int NOT NULL, + id_generator_mode smallint NOT NULL DEFAULT 1, + init_scene smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_group_config.id IS '主键'; +COMMENT ON COLUMN sj_group_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_group_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_group_config.description IS '组描述'; +COMMENT ON COLUMN sj_group_config.token IS 'token'; +COMMENT ON COLUMN sj_group_config.group_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_group_config.version IS '版本号'; +COMMENT ON COLUMN sj_group_config.group_partition IS '分区'; +COMMENT ON COLUMN sj_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式'; +COMMENT ON COLUMN sj_group_config.init_scene IS '是否初始化场景 0:否 1:是'; +COMMENT ON COLUMN sj_group_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_group_config IS '组配置'; + +INSERT INTO sj_group_config VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, now(), now()); +INSERT INTO sj_group_config VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, now(), now()); + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + notify_name varchar(64) NOT NULL DEFAULT '', + system_task_type smallint NOT NULL DEFAULT 3, + notify_status smallint NOT NULL DEFAULT 0, + recipient_ids varchar(128) NOT NULL, + notify_threshold int NOT NULL DEFAULT 0, + notify_scene smallint NOT NULL DEFAULT 0, + rate_limiter_status smallint NOT NULL DEFAULT 0, + rate_limiter_threshold int NOT NULL DEFAULT 0, + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_notify_config.id IS '主键'; +COMMENT ON COLUMN sj_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_notify_config.notify_name IS '通知名称'; +COMMENT ON COLUMN sj_notify_config.system_task_type IS '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.recipient_ids IS '接收人id列表'; +COMMENT ON COLUMN sj_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN sj_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN sj_notify_config.description IS '描述'; +COMMENT ON COLUMN sj_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_config IS '通知配置'; + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + recipient_name varchar(64) NOT NULL, + notify_type smallint NOT NULL DEFAULT 0, + notify_attribute varchar(512) NOT NULL, + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id); + +COMMENT ON COLUMN sj_notify_recipient.id IS '主键'; +COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称'; +COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook'; +COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性'; +COMMENT ON COLUMN sj_notify_recipient.description IS '描述'; +COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_recipient.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_recipient IS '告警通知接收人'; + +-- sj_retry_dead_letter +CREATE TABLE sj_retry_dead_letter +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + group_id bigint NOT NULL, + scene_name varchar(64) NOT NULL, + scene_id bigint NOT NULL, + idempotent_id varchar(64) NOT NULL, + biz_no varchar(64) NOT NULL DEFAULT '', + executor_name varchar(512) NOT NULL DEFAULT '', + serializer_name varchar(32) NOT NULL DEFAULT 'jackson', + args_str text NOT NULL, + ext_attrs text NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_retry_dead_letter_01 ON sj_retry_dead_letter (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_dead_letter_02 ON sj_retry_dead_letter (idempotent_id); +CREATE INDEX idx_sj_retry_dead_letter_03 ON sj_retry_dead_letter (biz_no); +CREATE INDEX idx_sj_retry_dead_letter_04 ON sj_retry_dead_letter (create_dt); + +COMMENT ON COLUMN sj_retry_dead_letter.id IS '主键'; +COMMENT ON COLUMN sj_retry_dead_letter.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_dead_letter.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_dead_letter.group_id IS '组Id'; +COMMENT ON COLUMN sj_retry_dead_letter.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_dead_letter.scene_id IS '场景ID'; +COMMENT ON COLUMN sj_retry_dead_letter.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_dead_letter.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_dead_letter.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_dead_letter.serializer_name IS '执行方法参数序列化器名称'; +COMMENT ON COLUMN sj_retry_dead_letter.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_dead_letter.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_dead_letter.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_dead_letter IS '死信队列表'; + +-- sj_retry +CREATE TABLE sj_retry +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + group_id bigint NOT NULL, + scene_name varchar(64) NOT NULL, + scene_id bigint NOT NULL, + idempotent_id varchar(64) NOT NULL, + biz_no varchar(64) NOT NULL DEFAULT '', + executor_name varchar(512) NOT NULL DEFAULT '', + args_str text NOT NULL, + ext_attrs text NOT NULL, + serializer_name varchar(32) NOT NULL DEFAULT 'jackson', + next_trigger_at bigint NOT NULL, + retry_count int NOT NULL DEFAULT 0, + retry_status smallint NOT NULL DEFAULT 0, + task_type smallint NOT NULL DEFAULT 1, + bucket_index int NOT NULL DEFAULT 0, + parent_id bigint NOT NULL DEFAULT 0, + deleted bigint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_01 ON sj_retry (scene_id, task_type, idempotent_id, deleted); + +CREATE INDEX idx_sj_retry_01 ON sj_retry (biz_no); +CREATE INDEX idx_sj_retry_02 ON sj_retry (idempotent_id); +CREATE INDEX idx_sj_retry_03 ON sj_retry (retry_status, bucket_index); +CREATE INDEX idx_sj_retry_04 ON sj_retry (parent_id); +CREATE INDEX idx_sj_retry_05 ON sj_retry (create_dt); + +COMMENT ON COLUMN sj_retry.id IS '主键'; +COMMENT ON COLUMN sj_retry.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry.group_id IS '组Id'; +COMMENT ON COLUMN sj_retry.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry.scene_id IS '场景ID'; +COMMENT ON COLUMN sj_retry.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry.serializer_name IS '执行方法参数序列化器名称'; +COMMENT ON COLUMN sj_retry.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_retry.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_retry.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数'; +COMMENT ON COLUMN sj_retry.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_retry.parent_id IS '父节点id'; +COMMENT ON COLUMN sj_retry.deleted IS '逻辑删除'; +COMMENT ON COLUMN sj_retry.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry IS '重试信息表'; + +-- sj_retry_task +CREATE TABLE sj_retry_task +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + scene_name varchar(64) NOT NULL, + retry_id bigint NOT NULL, + ext_attrs text NOT NULL, + task_status smallint NOT NULL DEFAULT 1, + task_type smallint NOT NULL DEFAULT 1, + operation_reason smallint NOT NULL DEFAULT 0, + client_info varchar(128) NULL DEFAULT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_retry_task_01 ON sj_retry_task (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_02 ON sj_retry_task (task_status); +CREATE INDEX idx_sj_retry_task_03 ON sj_retry_task (create_dt); +CREATE INDEX idx_sj_retry_task_04 ON sj_retry_task (retry_id); + +COMMENT ON COLUMN sj_retry_task.id IS '主键'; +COMMENT ON COLUMN sj_retry_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task.retry_id IS '重试信息Id'; +COMMENT ON COLUMN sj_retry_task.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task.task_status IS '重试状态'; +COMMENT ON COLUMN sj_retry_task.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_retry_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_retry_task.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task IS '重试任务表'; + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + retry_id bigint NOT NULL, + retry_task_id bigint NOT NULL, + message text NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, retry_task_id); +CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt); + +COMMENT ON COLUMN sj_retry_task_log_message.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log_message.retry_id IS '重试信息Id'; +COMMENT ON COLUMN sj_retry_task_log_message.retry_task_id IS '重试任务Id'; +COMMENT ON COLUMN sj_retry_task_log_message.message IS '异常信息'; +COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_task_log_message IS '任务调度日志信息记录表'; + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_status smallint NOT NULL DEFAULT 0, + max_retry_count int NOT NULL DEFAULT 5, + back_off smallint NOT NULL DEFAULT 1, + trigger_interval varchar(16) NOT NULL DEFAULT '', + notify_ids varchar(128) NOT NULL DEFAULT '', + deadline_request bigint NOT NULL DEFAULT 60000, + executor_timeout int NOT NULL DEFAULT 5, + route_key smallint NOT NULL DEFAULT 4, + block_strategy smallint NOT NULL DEFAULT 1, + cb_status smallint NOT NULL DEFAULT 0, + cb_trigger_type smallint NOT NULL DEFAULT 1, + cb_max_count int NOT NULL DEFAULT 16, + cb_trigger_interval varchar(16) NOT NULL DEFAULT '', + owner_id bigint NULL DEFAULT NULL, + labels varchar(512) NULL DEFAULT '', + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name); + +COMMENT ON COLUMN sj_retry_scene_config.id IS '主键'; +COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_scene_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '最大重试次数'; +COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒'; +COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_retry_scene_config.route_key IS '路由策略'; +COMMENT ON COLUMN sj_retry_scene_config.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_retry_scene_config.cb_status IS '回调状态 0、不开启 1、开启'; +COMMENT ON COLUMN sj_retry_scene_config.cb_trigger_type IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN sj_retry_scene_config.cb_max_count IS '回调的最大执行次数'; +COMMENT ON COLUMN sj_retry_scene_config.cb_trigger_interval IS '回调的最大执行次数'; +COMMENT ON COLUMN sj_retry_scene_config.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_retry_scene_config.labels IS '标签'; +COMMENT ON COLUMN sj_retry_scene_config.description IS '描述'; +COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_scene_config IS '场景配置'; + +-- sj_server_node +CREATE TABLE sj_server_node +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + host_id varchar(64) NOT NULL, + host_ip varchar(64) NOT NULL, + host_port int NOT NULL, + expire_at timestamp NOT NULL, + node_type smallint NOT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + labels varchar(512) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip); + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name); +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type); + +COMMENT ON COLUMN sj_server_node.id IS '主键'; +COMMENT ON COLUMN sj_server_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_server_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_server_node.host_id IS '主机id'; +COMMENT ON COLUMN sj_server_node.host_ip IS '机器ip'; +COMMENT ON COLUMN sj_server_node.host_port IS '机器端口'; +COMMENT ON COLUMN sj_server_node.expire_at IS '过期时间'; +COMMENT ON COLUMN sj_server_node.node_type IS '节点类型 1、客户端 2、是服务端'; +COMMENT ON COLUMN sj_server_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_server_node.labels IS '标签'; +COMMENT ON COLUMN sj_server_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_server_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_server_node IS '服务器节点'; + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name varchar(64) NOT NULL PRIMARY KEY, + lock_until timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + locked_at timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + locked_by varchar(255) NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称'; +COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长'; +COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间'; +COMMENT ON COLUMN sj_distributed_lock.locked_by IS '锁定者'; +COMMENT ON COLUMN sj_distributed_lock.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_distributed_lock.update_dt IS '修改时间'; +COMMENT ON TABLE sj_distributed_lock IS '锁定表'; + +-- sj_system_user +CREATE TABLE sj_system_user +( + id bigserial PRIMARY KEY, + username varchar(64) NOT NULL, + password varchar(128) NOT NULL, + role smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sj_system_user.id IS '主键'; +COMMENT ON COLUMN sj_system_user.username IS '账号'; +COMMENT ON COLUMN sj_system_user.password IS '密码'; +COMMENT ON COLUMN sj_system_user.role IS '角色:1-普通用户、2-管理员'; +COMMENT ON COLUMN sj_system_user.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user IS '系统用户表'; + +INSERT INTO sj_system_user (username, password, role) +VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2); + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id bigserial PRIMARY KEY, + group_name varchar(64) NOT NULL, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + system_user_id bigint NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id); + +COMMENT ON COLUMN sj_system_user_permission.id IS '主键'; +COMMENT ON COLUMN sj_system_user_permission.group_name IS '组名称'; +COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '系统用户id'; +COMMENT ON COLUMN sj_system_user_permission.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user_permission.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user_permission IS '系统用户权限表'; + +-- sj_job +CREATE TABLE sj_job +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + biz_id varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + job_name varchar(64) NOT NULL, + args_str text NULL DEFAULT NULL, + args_type smallint NOT NULL DEFAULT 1, + next_trigger_at bigint NOT NULL, + job_status smallint NOT NULL DEFAULT 1, + task_type smallint NOT NULL DEFAULT 1, + route_key smallint NOT NULL DEFAULT 4, + executor_type smallint NOT NULL DEFAULT 1, + executor_info varchar(255) NULL DEFAULT NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar(255) NOT NULL, + block_strategy smallint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + max_retry_times int NOT NULL DEFAULT 0, + parallel_num int NOT NULL DEFAULT 1, + retry_interval int NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + resident smallint NOT NULL DEFAULT 0, + notify_ids varchar(128) NOT NULL DEFAULT '', + owner_id bigint NULL DEFAULT NULL, + labels varchar(512) NULL DEFAULT '', + description varchar(256) NOT NULL DEFAULT '', + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name); +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index); +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt); +CREATE UNIQUE INDEX uk_sj_job_01 ON sj_job (namespace_id, biz_id); + +COMMENT ON COLUMN sj_job.id IS '主键'; +COMMENT ON COLUMN sj_job.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job.biz_id IS '业务ID'; +COMMENT ON COLUMN sj_job.group_name IS '组名称'; +COMMENT ON COLUMN sj_job.job_name IS '名称'; +COMMENT ON COLUMN sj_job.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_job.job_status IS '任务状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_job.task_type IS '任务类型 1、集群 2、广播 3、切片'; +COMMENT ON COLUMN sj_job.route_key IS '路由策略'; +COMMENT ON COLUMN sj_job.executor_type IS '执行器类型'; +COMMENT ON COLUMN sj_job.executor_info IS '执行器名称'; +COMMENT ON COLUMN sj_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_job.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行 4、恢复'; +COMMENT ON COLUMN sj_job.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_job.max_retry_times IS '最大重试次数'; +COMMENT ON COLUMN sj_job.parallel_num IS '并行数'; +COMMENT ON COLUMN sj_job.retry_interval IS '重试间隔 ( s)'; +COMMENT ON COLUMN sj_job.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_job.resident IS '是否是常驻任务'; +COMMENT ON COLUMN sj_job.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_job.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_job.labels IS '标签'; +COMMENT ON COLUMN sj_job.description IS '描述'; +COMMENT ON COLUMN sj_job.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job IS '任务信息'; + +INSERT INTO sj_job VALUES (1, 'dev', 'demo-job', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1, '', '', '', 0, now(), now()); + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + task_id bigint NOT NULL, + message text NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + ext_attrs varchar(256) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id); +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt); +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_log_message.id IS '主键'; +COMMENT ON COLUMN sj_job_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_log_message.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN sj_job_log_message.task_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_log_message.message IS '调度信息'; +COMMENT ON COLUMN sj_job_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_job_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_job_log_message IS '调度日志'; + +-- sj_job_task +CREATE TABLE sj_job_task +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + parent_id bigint NOT NULL DEFAULT 0, + task_status smallint NOT NULL DEFAULT 0, + retry_count int NOT NULL DEFAULT 0, + mr_stage smallint NULL DEFAULT NULL, + leaf smallint NOT NULL DEFAULT '1', + task_name varchar(255) NOT NULL DEFAULT '', + client_info varchar(128) NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + result_message text NOT NULL, + args_str text NULL DEFAULT NULL, + args_type smallint NOT NULL DEFAULT 1, + ext_attrs varchar(256) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status); +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt); +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_task.id IS '主键'; +COMMENT ON COLUMN sj_job_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id'; +COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce'; +COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点'; +COMMENT ON COLUMN sj_job_task.task_name IS '任务名称'; +COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文'; +COMMENT ON COLUMN sj_job_task.result_message IS '执行结果'; +COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job_task.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task IS '任务实例'; + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_node_id bigint NOT NULL DEFAULT 0, + parent_workflow_node_id bigint NOT NULL DEFAULT 0, + workflow_task_batch_id bigint NOT NULL DEFAULT 0, + task_batch_status smallint NOT NULL DEFAULT 0, + operation_reason smallint NOT NULL DEFAULT 0, + execution_at bigint NOT NULL DEFAULT 0, + system_task_type smallint NOT NULL DEFAULT 3, + parent_id varchar(64) NOT NULL DEFAULT '', + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status); +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt); +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name); +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id); + +COMMENT ON COLUMN sj_job_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task_batch.job_id IS '任务id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '工作流节点id'; +COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '工作流任务父批次id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '工作流任务批次id'; +COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_job_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_task_batch.parent_id IS '父节点'; +COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task_batch IS '任务批次'; + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + business_id bigint NOT NULL, + system_task_type smallint NOT NULL DEFAULT 3, + trigger_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + success_num int NOT NULL DEFAULT 0, + fail_num int NOT NULL DEFAULT 0, + fail_reason varchar(512) NOT NULL DEFAULT '', + stop_num int NOT NULL DEFAULT 0, + stop_reason varchar(512) NOT NULL DEFAULT '', + cancel_num int NOT NULL DEFAULT 0, + cancel_reason varchar(512) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id); + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id); + +COMMENT ON COLUMN sj_job_summary.id IS '主键'; +COMMENT ON COLUMN sj_job_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_summary.business_id IS '业务id ( job_id或workflow_id)'; +COMMENT ON COLUMN sj_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_job_summary.success_num IS '执行成功-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.stop_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.stop_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.cancel_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.cancel_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job'; + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + scene_name varchar(64) NOT NULL DEFAULT '', + trigger_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + running_num int NOT NULL DEFAULT 0, + finish_num int NOT NULL DEFAULT 0, + max_count_num int NOT NULL DEFAULT 0, + suspend_num int NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at); + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at); + +COMMENT ON COLUMN sj_retry_summary.id IS '主键'; +COMMENT ON COLUMN sj_retry_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_summary.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_retry_summary.running_num IS '重试中-日志数量'; +COMMENT ON COLUMN sj_retry_summary.finish_num IS '重试完成-日志数量'; +COMMENT ON COLUMN sj_retry_summary.max_count_num IS '重试到达最大次数-日志数量'; +COMMENT ON COLUMN sj_retry_summary.suspend_num IS '暂停重试-日志数量'; +COMMENT ON COLUMN sj_retry_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry'; + +-- sj_workflow +CREATE TABLE sj_workflow +( + id bigserial PRIMARY KEY, + workflow_name varchar(64) NOT NULL, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + biz_id varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + workflow_status smallint NOT NULL DEFAULT 1, + trigger_type smallint NOT NULL, + trigger_interval varchar(255) NOT NULL, + next_trigger_at bigint NOT NULL, + block_strategy smallint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + description varchar(256) NOT NULL DEFAULT '', + flow_info text NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + notify_ids varchar(128) NOT NULL DEFAULT '', + bucket_index int NOT NULL DEFAULT 0, + version int NOT NULL, + owner_id bigint NULL DEFAULT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt); +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name); +CREATE UNIQUE INDEX uk_sj_workflow_01 ON sj_workflow (namespace_id, biz_id); + +COMMENT ON COLUMN sj_workflow.id IS '主键'; +COMMENT ON COLUMN sj_workflow.workflow_name IS '工作流名称'; +COMMENT ON COLUMN sj_workflow.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow.biz_id IS '业务ID'; +COMMENT ON COLUMN sj_workflow.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow.workflow_status IS '工作流状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_workflow.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_workflow.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_workflow.description IS '描述'; +COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow.wf_context IS '上下文'; +COMMENT ON COLUMN sj_workflow.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_workflow.version IS '版本号'; +COMMENT ON COLUMN sj_workflow.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow IS '工作流'; + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_id bigint NOT NULL, + node_type smallint NOT NULL DEFAULT 1, + expression_type smallint NOT NULL DEFAULT 0, + fail_strategy smallint NOT NULL DEFAULT 1, + workflow_node_status smallint NOT NULL DEFAULT 1, + priority_level int NOT NULL DEFAULT 1, + node_info text NULL DEFAULT NULL, + version int NOT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt); +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_node.id IS '主键'; +COMMENT ON COLUMN sj_workflow_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_node.node_name IS '节点名称'; +COMMENT ON COLUMN sj_workflow_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_node.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_workflow_node.workflow_id IS '工作流ID'; +COMMENT ON COLUMN sj_workflow_node.node_type IS '1、任务节点 2、条件节点'; +COMMENT ON COLUMN sj_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL'; +COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞'; +COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow_node.priority_level IS '优先级'; +COMMENT ON COLUMN sj_workflow_node.node_info IS '节点信息 '; +COMMENT ON COLUMN sj_workflow_node.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_node.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_node IS '工作流节点'; + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + workflow_id bigint NOT NULL, + task_batch_status smallint NOT NULL DEFAULT 0, + operation_reason smallint NOT NULL DEFAULT 0, + flow_info text NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + execution_at bigint NOT NULL DEFAULT 0, + ext_attrs varchar(256) NULL DEFAULT '', + version int NOT NULL DEFAULT 1, + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status); +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt); +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id'; +COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文'; +COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_task_batch IS '工作流批次'; + +-- sj_job_executor +CREATE TABLE sj_job_executor +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + executor_info varchar(256) NOT NULL, + executor_type varchar(3) NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_executor_01 ON sj_job_executor (namespace_id, group_name); +CREATE INDEX idx_sj_job_executor_02 ON sj_job_executor (create_dt); + +COMMENT ON COLUMN sj_job_executor.id IS '主键'; +COMMENT ON COLUMN sj_job_executor.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_executor.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_executor.executor_info IS '任务执行器名称'; +COMMENT ON COLUMN sj_job_executor.executor_type IS '1:java 2:python 3:go'; +COMMENT ON COLUMN sj_job_executor.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_executor.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_executor IS '任务执行器信息'; diff --git a/script/sql/postgres/postgres_ry_vue.sql b/script/sql/postgres/postgres_ry_vue.sql new file mode 100644 index 000000000..f9d6a28ee --- /dev/null +++ b/script/sql/postgres/postgres_ry_vue.sql @@ -0,0 +1,1340 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id int8 not null, + user_id int8 not null, + auth_id varchar(255) not null, + source varchar(255) not null, + open_id varchar(255) default null::varchar, + user_name varchar(30) not null, + nick_name varchar(30) default ''::varchar, + email varchar(255) default ''::varchar, + avatar varchar(500) default ''::varchar, + access_token varchar(2000) not null, + expire_in int8 default null, + refresh_token varchar(2000) default null::varchar, + access_code varchar(255) default null::varchar, + union_id varchar(255) default null::varchar, + scope varchar(255) default null::varchar, + token_type varchar(255) default null::varchar, + id_token varchar(2000) default null::varchar, + mac_algorithm varchar(255) default null::varchar, + mac_key varchar(255) default null::varchar, + code varchar(255) default null::varchar, + oauth_token varchar(255) default null::varchar, + oauth_token_secret varchar(255) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + del_flag char default '0'::bpchar, + constraint "pk_sys_social" primary key (id) +); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 1代表删除)'; + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table if not exists sys_dept +( + dept_id int8, + parent_id int8 default 0, + ancestors varchar(500)default ''::varchar, + dept_name varchar(30) default ''::varchar, + dept_category varchar(100) default null::varchar, + order_num int4 default 0, + leader int8 default null, + phone varchar(11) default null::varchar, + email varchar(50) default null::varchar, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint "sys_dept_pk" primary key (dept_id) +); + +create index idx_sys_dept_parent_id ON sys_dept (parent_id); + +comment on table sys_dept is '部门表'; +comment on column sys_dept.dept_id is '部门ID'; +comment on column sys_dept.parent_id is '父部门ID'; +comment on column sys_dept.ancestors is '祖级列表'; +comment on column sys_dept.dept_name is '部门名称'; +comment on column sys_dept.dept_category is '部门类别编码'; +comment on column sys_dept.order_num is '显示顺序'; +comment on column sys_dept.leader is '负责人'; +comment on column sys_dept.phone is '联系电话'; +comment on column sys_dept.email is '邮箱'; +comment on column sys_dept.status is '部门状态(0正常 1停用)'; +comment on column sys_dept.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_dept.create_dept is '创建部门'; +comment on column sys_dept.create_by is '创建者'; +comment on column sys_dept.create_time is '创建时间'; +comment on column sys_dept.update_by is '更新者'; +comment on column sys_dept.update_time is '更新时间'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- +insert into sys_dept values(1761000000000000100, 0, '0', 'XXX科技', null, 0, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000101, 1761000000000000100, '0,1761000000000000100', '深圳总公司', null, 1, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000102, 1761000000000000100, '0,1761000000000000100', '长沙分公司', null, 2, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000103, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '研发部门', null, 1, 1761100000000000001, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000104, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '市场部门', null, 2, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000105, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '测试部门', null, 3, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000106, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '财务部门', null, 4, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000107, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '运维部门', null, 5, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000108, 1761000000000000102, '0,1761000000000000100,1761000000000000102', '市场部门', null, 1, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); +insert into sys_dept values(1761000000000000109, 1761000000000000102, '0,1761000000000000100,1761000000000000102', '财务部门', null, 2, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null); + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table if not exists sys_user +( + user_id int8, + dept_id int8, + user_name varchar(30) not null, + nick_name varchar(30) not null, + user_type varchar(10) default 'sys_user'::varchar, + email varchar(50) default ''::varchar, + phone_number varchar(11) default ''::varchar, + gender char default '0'::bpchar, + avatar int8, + password varchar(100) default ''::varchar, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + login_ip varchar(128) default ''::varchar, + login_date timestamp, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_user_pk" primary key (user_id) +); + +create index idx_sys_user_dept_id ON sys_user (dept_id); +create index idx_sys_user_create_by ON sys_user (create_by); +create index idx_sys_user_user_name ON sys_user (user_name); +create index idx_sys_user_phone ON sys_user (phone_number); + +comment on table sys_user is '用户信息表'; +comment on column sys_user.user_id is '用户ID'; +comment on column sys_user.dept_id is '部门ID'; +comment on column sys_user.user_name is '用户账号'; +comment on column sys_user.nick_name is '用户昵称'; +comment on column sys_user.user_type is '用户类型(sys_user系统用户)'; +comment on column sys_user.email is '用户邮箱'; +comment on column sys_user.phone_number is '手机号码'; +comment on column sys_user.gender is '用户性别(0男 1女 2未知)'; +comment on column sys_user.avatar is '头像地址'; +comment on column sys_user.password is '密码'; +comment on column sys_user.status is '账号状态(0正常 1停用)'; +comment on column sys_user.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_user.login_ip is '最后登陆IP'; +comment on column sys_user.login_date is '最后登陆时间'; +comment on column sys_user.create_dept is '创建部门'; +comment on column sys_user.create_by is '创建者'; +comment on column sys_user.create_time is '创建时间'; +comment on column sys_user.update_by is '更新者'; +comment on column sys_user.update_time is '更新时间'; +comment on column sys_user.remark is '备注'; + +-- ---------------------------- + +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1761100000000000001, 1761000000000000103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 1761000000000000103, 1761100000000000001, now(), null, null, '管理员'); +insert into sys_user VALUES(1761100000000000003, 1761000000000000108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 1761000000000000103, 1761100000000000001, now(), 1761100000000000003, now(), NULL); +insert into sys_user VALUES(1761100000000000004, 1761000000000000102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 1761000000000000103, 1761100000000000001, now(), 1761100000000000004, now(), NULL); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table if not exists sys_post +( + post_id int8, + dept_id int8, + post_code varchar(64) not null, + post_category varchar(100) default null, + post_name varchar(50) not null, + post_sort int4 not null, + status char not null, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_post_pk" primary key (post_id) +); + +create index idx_sys_post_dept_id ON sys_post (dept_id); + +comment on table sys_post is '岗位信息表'; +comment on column sys_post.post_id is '岗位ID'; +comment on column sys_post.dept_id is '部门id'; +comment on column sys_post.post_code is '岗位编码'; +comment on column sys_post.post_category is '岗位类别编码'; +comment on column sys_post.post_name is '岗位名称'; +comment on column sys_post.post_sort is '显示顺序'; +comment on column sys_post.status is '状态(0正常 1停用)'; +comment on column sys_post.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_post.create_dept is '创建部门'; +comment on column sys_post.create_by is '创建者'; +comment on column sys_post.create_time is '创建时间'; +comment on column sys_post.update_by is '更新者'; +comment on column sys_post.update_time is '更新时间'; +comment on column sys_post.remark is '备注'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1761200000000000001, 1761000000000000103, 'ceo', null, '董事长', 1, '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_post values(1761200000000000002, 1761000000000000100, 'se', null, '项目经理', 2, '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_post values(1761200000000000003, 1761000000000000100, 'hr', null, '人力资源', 3, '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_post values(1761200000000000004, 1761000000000000100, 'user', null, '普通员工', 4, '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null, ''); + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table if not exists sys_role +( + role_id int8, + role_name varchar(30) not null, + role_key varchar(100) not null, + role_sort int4 not null, + data_scope char default '1'::bpchar, + menu_check_strictly bool default true, + dept_check_strictly bool default true, + status char not null, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_role_pk" primary key (role_id) +); + +create index idx_sys_role_create_dept ON sys_role (create_dept); +create index idx_sys_role_create_by ON sys_role (create_by); + +comment on table sys_role is '角色信息表'; +comment on column sys_role.role_id is '角色ID'; +comment on column sys_role.role_name is '角色名称'; +comment on column sys_role.role_key is '角色权限字符串'; +comment on column sys_role.role_sort is '显示顺序'; +comment on column sys_role.data_scope is '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限)'; +comment on column sys_role.menu_check_strictly is '菜单树选择项是否关联显示'; +comment on column sys_role.dept_check_strictly is '部门树选择项是否关联显示'; +comment on column sys_role.status is '角色状态(0正常 1停用)'; +comment on column sys_role.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_role.create_dept is '创建部门'; +comment on column sys_role.create_by is '创建者'; +comment on column sys_role.create_time is '创建时间'; +comment on column sys_role.update_by is '更新者'; +comment on column sys_role.update_time is '更新时间'; +comment on column sys_role.remark is '备注'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values(1761300000000000001, '超级管理员', 'superadmin', 1, '1', 't', 't', '0', '0', 1761000000000000103, 1761100000000000001, now(), null, null, '超级管理员'); +insert into sys_role values(1761300000000000003, '本部门及以下', 'test1', 3, '4', 't', 't', '0', '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_role values(1761300000000000004, '仅本人', 'test2', 4, '5', 't', 't', '0', '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table if not exists sys_menu +( + menu_id int8, + menu_name varchar(50) not null, + parent_id int8 default 0, + order_num int4 default 0, + path varchar(200) default ''::varchar, + component varchar(255) default null::varchar, + query_param varchar(255) default null::varchar, + is_frame char default 'N'::bpchar, + is_cache char default 'Y'::bpchar, + menu_type char default ''::bpchar, + visible char default '0'::bpchar, + status char default '0'::bpchar, + perms varchar(100) default null::varchar, + icon varchar(100) default '#'::varchar, + active_menu varchar(255) default ''::varchar, + ext varchar(2000) default ''::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default ''::varchar, + constraint "sys_menu_pk" primary key (menu_id) +); + +comment on table sys_menu is '菜单权限表'; +comment on column sys_menu.menu_id is '菜单ID'; +comment on column sys_menu.menu_name is '菜单名称'; +comment on column sys_menu.parent_id is '父菜单ID'; +comment on column sys_menu.order_num is '显示顺序'; +comment on column sys_menu.path is '路由地址'; +comment on column sys_menu.component is '组件路径'; +comment on column sys_menu.query_param is '路由参数'; +comment on column sys_menu.is_frame is '是否为外链(Y是 N否)'; +comment on column sys_menu.is_cache is '是否缓存(Y缓存 N不缓存)'; +comment on column sys_menu.menu_type is '菜单类型(M目录 C菜单 F按钮)'; +comment on column sys_menu.visible is '显示状态(0显示 1隐藏)'; +comment on column sys_menu.status is '菜单状态(0正常 1停用)'; +comment on column sys_menu.perms is '权限标识'; +comment on column sys_menu.icon is '菜单图标'; +comment on column sys_menu.create_dept is '创建部门'; +comment on column sys_menu.create_by is '创建者'; +comment on column sys_menu.create_time is '创建时间'; +comment on column sys_menu.update_by is '更新者'; +comment on column sys_menu.update_time is '更新时间'; +comment on column sys_menu.active_menu is '激活菜单路径'; +comment on column sys_menu.ext is '扩展字段'; +comment on column sys_menu.remark is '备注'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values(1761400000000000001, '系统管理', 0, 1, 'system', null, '', 'N', 'Y', 'M', '0', '0', '', 'system', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '系统管理目录'); +insert into sys_menu values(1761400000000000002, '系统监控', 0, 3, 'monitor', null, '', 'N', 'Y', 'M', '0', '0', '', 'monitor', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '系统监控目录'); +insert into sys_menu values(1761400000000000003, '系统工具', 0, 4, 'tool', null, '', 'N', 'Y', 'M', '0', '0', '', 'tool', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '系统工具目录'); +insert into sys_menu values(1761400000000000005, '测试菜单', 0, 5, 'demo', null, '', 'N', 'Y', 'M', '0', '0', null, 'star', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '测试菜单'); +insert into sys_menu values(1761400000000000006, 'AI会话', 0, 8, 'aichat', 'ai/chat/index', '', 'N', 'Y', 'C', '0', '0', '', 'checkbox', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, 'AI聊天菜单'); +insert into sys_menu values(1761400000000000004, 'PLUS官网', 0, 9, 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 'Y', 'Y', 'M', '0', '0', '', 'guide', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, 'RuoYi-Vue-Plus官网地址'); +-- 二级菜单 +insert into sys_menu values(1761400000000000100, '用户管理', 1761400000000000001, 1, 'user', 'system/user/index', '', 'N', 'Y', 'C', '0', '0', 'system:user:list', 'user', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '用户管理菜单'); +insert into sys_menu values(1761400000000000101, '角色管理', 1761400000000000001, 2, 'role', 'system/role/index', '', 'N', 'Y', 'C', '0', '0', 'system:role:list', 'peoples', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '角色管理菜单'); +insert into sys_menu values(1761400000000000102, '菜单管理', 1761400000000000001, 3, 'menu', 'system/menu/index', '', 'N', 'Y', 'C', '0', '0', 'system:menu:list', 'tree-table', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '菜单管理菜单'); +insert into sys_menu values(1761400000000000103, '部门管理', 1761400000000000001, 4, 'dept', 'system/dept/index', '', 'N', 'Y', 'C', '0', '0', 'system:dept:list', 'tree', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '部门管理菜单'); +insert into sys_menu values(1761400000000000104, '岗位管理', 1761400000000000001, 5, 'post', 'system/post/index', '', 'N', 'Y', 'C', '0', '0', 'system:post:list', 'post', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '岗位管理菜单'); +insert into sys_menu values(1761400000000000105, '字典管理', 1761400000000000001, 6, 'dict', 'system/dict/index', '', 'N', 'Y', 'C', '0', '0', 'system:dict:list', 'dict', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '字典管理菜单'); +insert into sys_menu values(1761400000000000106, '参数设置', 1761400000000000001, 7, 'config', 'system/config/index', '', 'N', 'Y', 'C', '0', '0', 'system:config:list', 'edit', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '参数设置菜单'); +insert into sys_menu values(1761400000000000107, '通知公告', 1761400000000000001, 8, 'notice', 'system/notice/index', '', 'N', 'Y', 'C', '0', '0', 'system:notice:list', 'message', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '通知公告菜单'); +insert into sys_menu values(1761400000000000108, '日志管理', 1761400000000000001, 9, 'log', '', '', 'N', 'Y', 'M', '0', '0', '', 'log', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '日志管理菜单'); +insert into sys_menu values(1761400000000000109, '在线用户', 1761400000000000002, 1, 'online', 'monitor/online/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:online:list', 'online', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '在线用户菜单'); +insert into sys_menu values(1761400000000000113, '缓存监控', 1761400000000000002, 5, 'cache', 'monitor/cache/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:cache:list', 'redis', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '缓存监控菜单'); +insert into sys_menu values(1761400000000000115, '代码生成', 1761400000000000003, 2, 'gen', 'tool/gen/index', '', 'N', 'Y', 'C', '0', '0', 'tool:gen:list', 'code', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '代码生成菜单'); +insert into sys_menu values(1761400000000000123, '客户端管理', 1761400000000000001, 11, 'client', 'system/client/index', '', 'N', 'Y', 'C', '0', '0', 'system:client:list', 'international', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '客户端管理菜单'); +insert into sys_menu values(1761400000000000116, '修改生成配置', 1761400000000000003, 2, 'gen-edit/index/:tableId', 'tool/gen/editTable', '', 'N', 'N', 'C', '1', '0', 'tool:gen:edit', '#', '/tool/gen', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000000130, '分配用户', 1761400000000000001, 2, 'role-auth/user/:roleId', 'system/role/authUser', '', 'N', 'N', 'C', '1', '0', 'system:role:edit', '#', '/system/role', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000000131, '分配角色', 1761400000000000001, 1, 'user-auth/role/:userId', 'system/user/authRole', '', 'N', 'N', 'C', '1', '0', 'system:user:edit', '#', '/system/user', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000000133, '文件配置管理', 1761400000000000001, 10, 'oss-config/index', 'system/oss/config', '', 'N', 'N', 'C', '1', '0', 'system:ossConfig:list', '#', '/system/oss', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); + +-- springboot-admin监控 +insert into sys_menu values(1761400000000000117, 'Admin监控', 1761400000000000002, 5, 'Admin', 'monitor/admin/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:admin:list', 'dashboard', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values(1761400000000000118, '文件管理', 1761400000000000001, 10, 'oss', 'system/oss/index', '', 'N', 'Y', 'C', '0', '0', 'system:oss:list', 'upload', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values(1761400000000000120, '任务调度中心', 1761400000000000002, 6, 'snailjob', 'monitor/snailjob/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:snailjob:list', 'job', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, 'SnailJob控制台菜单'); +-- snail-ai server控制台 +insert into sys_menu values(1761400000000000121, 'AI控制台', 1761400000000000002, 7, 'snailai', 'monitor/snailai/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:snailai:list', 'checkbox', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, 'AI控制台菜单'); + +-- 三级菜单 +insert into sys_menu values(1761400000000000500, '操作日志', 1761400000000000108, 1, 'operlog', 'monitor/operlog/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:operlog:list', 'form', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '操作日志菜单'); +insert into sys_menu values(1761400000000000501, '登录日志', 1761400000000000108, 2, 'logininfo', 'monitor/logininfo/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:logininfo:list', 'logininfo', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values(1761400000000001001, '用户查询', 1761400000000000100, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001002, '用户新增', 1761400000000000100, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001003, '用户修改', 1761400000000000100, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001004, '用户删除', 1761400000000000100, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001005, '用户导出', 1761400000000000100, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001006, '用户导入', 1761400000000000100, 6, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:import', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001007, '重置密码', 1761400000000000100, 7, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:resetPwd', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 角色管理按钮 +insert into sys_menu values(1761400000000001008, '角色查询', 1761400000000000101, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001009, '角色新增', 1761400000000000101, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001010, '角色修改', 1761400000000000101, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001011, '角色删除', 1761400000000000101, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001012, '角色导出', 1761400000000000101, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values(1761400000000001013, '菜单查询', 1761400000000000102, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001014, '菜单新增', 1761400000000000102, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001015, '菜单修改', 1761400000000000102, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001016, '菜单删除', 1761400000000000102, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 部门管理按钮 +insert into sys_menu values(1761400000000001017, '部门查询', 1761400000000000103, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001018, '部门新增', 1761400000000000103, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001019, '部门修改', 1761400000000000103, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001020, '部门删除', 1761400000000000103, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values(1761400000000001021, '岗位查询', 1761400000000000104, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001022, '岗位新增', 1761400000000000104, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001023, '岗位修改', 1761400000000000104, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001024, '岗位删除', 1761400000000000104, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001025, '岗位导出', 1761400000000000104, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 字典管理按钮 +insert into sys_menu values(1761400000000001026, '字典查询', 1761400000000000105, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001027, '字典新增', 1761400000000000105, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001028, '字典修改', 1761400000000000105, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001029, '字典删除', 1761400000000000105, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001030, '字典导出', 1761400000000000105, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 参数设置按钮 +insert into sys_menu values(1761400000000001031, '参数查询', 1761400000000000106, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001032, '参数新增', 1761400000000000106, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001033, '参数修改', 1761400000000000106, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001034, '参数删除', 1761400000000000106, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001035, '参数导出', 1761400000000000106, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 通知公告按钮 +insert into sys_menu values(1761400000000001036, '公告查询', 1761400000000000107, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001037, '公告新增', 1761400000000000107, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001038, '公告修改', 1761400000000000107, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001039, '公告删除', 1761400000000000107, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 操作日志按钮 +insert into sys_menu values(1761400000000001040, '操作查询', 1761400000000000500, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001041, '操作删除', 1761400000000000500, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001042, '日志导出', 1761400000000000500, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 登录日志按钮 +insert into sys_menu values(1761400000000001043, '登录查询', 1761400000000000501, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001044, '登录删除', 1761400000000000501, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001045, '日志导出', 1761400000000000501, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001050, '账户解锁', 1761400000000000501, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:unlock', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 在线用户按钮 +insert into sys_menu values(1761400000000001046, '在线查询', 1761400000000000109, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001047, '批量强退', 1761400000000000109, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:batchLogout', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001048, '单条强退', 1761400000000000109, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:forceLogout', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 代码生成按钮 +insert into sys_menu values(1761400000000001055, '生成查询', 1761400000000000115, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001056, '生成修改', 1761400000000000115, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001057, '生成删除', 1761400000000000115, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001058, '导入代码', 1761400000000000115, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:import', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001059, '预览代码', 1761400000000000115, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:preview', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001060, '生成代码', 1761400000000000115, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:code', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- oss相关按钮 +insert into sys_menu values(1761400000000001600, '文件查询', 1761400000000000118, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001601, '文件上传', 1761400000000000118, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:upload', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001602, '文件下载', 1761400000000000118, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:download', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001603, '文件删除', 1761400000000000118, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001620, '配置列表', 1761400000000000118, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:list', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001621, '配置添加', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001622, '配置编辑', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001623, '配置删除', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 客户端管理按钮 +insert into sys_menu values(1761400000000001061, '客户端管理查询', 1761400000000000123, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001062, '客户端管理新增', 1761400000000000123, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001063, '客户端管理修改', 1761400000000000123, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001064, '客户端管理删除', 1761400000000000123, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +insert into sys_menu values(1761400000000001065, '客户端管理导出', 1761400000000000123, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), null, null, ''); +-- 测试菜单 +insert into sys_menu values(1761400000000001500, '测试单表', 1761400000000000005, 1, 'demo', 'demo/demo/index', '', 'N', 'Y', 'C', '0', '0', 'demo:demo:list', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '测试单表菜单'); +insert into sys_menu values(1761400000000001501, '测试单表查询', 1761400000000001500, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001502, '测试单表新增', 1761400000000001500, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001503, '测试单表修改', 1761400000000001500, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001504, '测试单表删除', 1761400000000001500, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001505, '测试单表导出', 1761400000000001500, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001506, '测试树表', 1761400000000000005, 1, 'tree', 'demo/tree/index', '', 'N', 'Y', 'C', '0', '0', 'demo:tree:list', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '测试树表菜单'); +insert into sys_menu values(1761400000000001507, '测试树表查询', 1761400000000001506, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001508, '测试树表新增', 1761400000000001506, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001509, '测试树表修改', 1761400000000001506, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001510, '测试树表删除', 1761400000000001506, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +insert into sys_menu values(1761400000000001511, '测试树表导出', 1761400000000001506, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table if not exists sys_user_role +( + user_id int8 not null, + role_id int8 not null, + constraint sys_user_role_pk primary key (user_id, role_id) +); + +create index idx_sys_user_role_rid ON sys_user_role (role_id); + +comment on table sys_user_role is '用户和角色关联表'; +comment on column sys_user_role.user_id is '用户ID'; +comment on column sys_user_role.role_id is '角色ID'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values (1761100000000000001, 1761300000000000001); +insert into sys_user_role values (1761100000000000003, 1761300000000000003); +insert into sys_user_role values (1761100000000000004, 1761300000000000004); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table if not exists sys_role_menu +( + role_id int8 not null, + menu_id int8 not null, + constraint sys_role_menu_pk primary key (role_id, menu_id) +); + +comment on table sys_role_menu is '角色和菜单关联表'; +comment on column sys_role_menu.role_id is '角色ID'; +comment on column sys_role_menu.menu_id is '菜单ID'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values (1761300000000000003, 1761400000000000001); +insert into sys_role_menu values (1761300000000000003, 1761400000000000005); +insert into sys_role_menu values (1761300000000000003, 1761400000000000100); +insert into sys_role_menu values (1761300000000000003, 1761400000000000101); +insert into sys_role_menu values (1761300000000000003, 1761400000000000102); +insert into sys_role_menu values (1761300000000000003, 1761400000000000103); +insert into sys_role_menu values (1761300000000000003, 1761400000000000104); +insert into sys_role_menu values (1761300000000000003, 1761400000000000105); +insert into sys_role_menu values (1761300000000000003, 1761400000000000106); +insert into sys_role_menu values (1761300000000000003, 1761400000000000107); +insert into sys_role_menu values (1761300000000000003, 1761400000000000108); +insert into sys_role_menu values (1761300000000000003, 1761400000000000118); +insert into sys_role_menu values (1761300000000000003, 1761400000000000123); +insert into sys_role_menu values (1761300000000000003, 1761400000000000130); +insert into sys_role_menu values (1761300000000000003, 1761400000000000131); +insert into sys_role_menu values (1761300000000000003, 1761400000000000133); +insert into sys_role_menu values (1761300000000000003, 1761400000000000500); +insert into sys_role_menu values (1761300000000000003, 1761400000000000501); +insert into sys_role_menu values (1761300000000000003, 1761400000000001001); +insert into sys_role_menu values (1761300000000000003, 1761400000000001002); +insert into sys_role_menu values (1761300000000000003, 1761400000000001003); +insert into sys_role_menu values (1761300000000000003, 1761400000000001004); +insert into sys_role_menu values (1761300000000000003, 1761400000000001005); +insert into sys_role_menu values (1761300000000000003, 1761400000000001006); +insert into sys_role_menu values (1761300000000000003, 1761400000000001007); +insert into sys_role_menu values (1761300000000000003, 1761400000000001008); +insert into sys_role_menu values (1761300000000000003, 1761400000000001009); +insert into sys_role_menu values (1761300000000000003, 1761400000000001010); +insert into sys_role_menu values (1761300000000000003, 1761400000000001011); +insert into sys_role_menu values (1761300000000000003, 1761400000000001012); +insert into sys_role_menu values (1761300000000000003, 1761400000000001013); +insert into sys_role_menu values (1761300000000000003, 1761400000000001014); +insert into sys_role_menu values (1761300000000000003, 1761400000000001015); +insert into sys_role_menu values (1761300000000000003, 1761400000000001016); +insert into sys_role_menu values (1761300000000000003, 1761400000000001017); +insert into sys_role_menu values (1761300000000000003, 1761400000000001018); +insert into sys_role_menu values (1761300000000000003, 1761400000000001019); +insert into sys_role_menu values (1761300000000000003, 1761400000000001020); +insert into sys_role_menu values (1761300000000000003, 1761400000000001021); +insert into sys_role_menu values (1761300000000000003, 1761400000000001022); +insert into sys_role_menu values (1761300000000000003, 1761400000000001023); +insert into sys_role_menu values (1761300000000000003, 1761400000000001024); +insert into sys_role_menu values (1761300000000000003, 1761400000000001025); +insert into sys_role_menu values (1761300000000000003, 1761400000000001026); +insert into sys_role_menu values (1761300000000000003, 1761400000000001027); +insert into sys_role_menu values (1761300000000000003, 1761400000000001028); +insert into sys_role_menu values (1761300000000000003, 1761400000000001029); +insert into sys_role_menu values (1761300000000000003, 1761400000000001030); +insert into sys_role_menu values (1761300000000000003, 1761400000000001031); +insert into sys_role_menu values (1761300000000000003, 1761400000000001032); +insert into sys_role_menu values (1761300000000000003, 1761400000000001033); +insert into sys_role_menu values (1761300000000000003, 1761400000000001034); +insert into sys_role_menu values (1761300000000000003, 1761400000000001035); +insert into sys_role_menu values (1761300000000000003, 1761400000000001036); +insert into sys_role_menu values (1761300000000000003, 1761400000000001037); +insert into sys_role_menu values (1761300000000000003, 1761400000000001038); +insert into sys_role_menu values (1761300000000000003, 1761400000000001039); +insert into sys_role_menu values (1761300000000000003, 1761400000000001040); +insert into sys_role_menu values (1761300000000000003, 1761400000000001041); +insert into sys_role_menu values (1761300000000000003, 1761400000000001042); +insert into sys_role_menu values (1761300000000000003, 1761400000000001043); +insert into sys_role_menu values (1761300000000000003, 1761400000000001044); +insert into sys_role_menu values (1761300000000000003, 1761400000000001045); +insert into sys_role_menu values (1761300000000000003, 1761400000000001050); +insert into sys_role_menu values (1761300000000000003, 1761400000000001061); +insert into sys_role_menu values (1761300000000000003, 1761400000000001062); +insert into sys_role_menu values (1761300000000000003, 1761400000000001063); +insert into sys_role_menu values (1761300000000000003, 1761400000000001064); +insert into sys_role_menu values (1761300000000000003, 1761400000000001065); +insert into sys_role_menu values (1761300000000000003, 1761400000000001500); +insert into sys_role_menu values (1761300000000000003, 1761400000000001501); +insert into sys_role_menu values (1761300000000000003, 1761400000000001502); +insert into sys_role_menu values (1761300000000000003, 1761400000000001503); +insert into sys_role_menu values (1761300000000000003, 1761400000000001504); +insert into sys_role_menu values (1761300000000000003, 1761400000000001505); +insert into sys_role_menu values (1761300000000000003, 1761400000000001506); +insert into sys_role_menu values (1761300000000000003, 1761400000000001507); +insert into sys_role_menu values (1761300000000000003, 1761400000000001508); +insert into sys_role_menu values (1761300000000000003, 1761400000000001509); +insert into sys_role_menu values (1761300000000000003, 1761400000000001510); +insert into sys_role_menu values (1761300000000000003, 1761400000000001511); +insert into sys_role_menu values (1761300000000000003, 1761400000000001600); +insert into sys_role_menu values (1761300000000000003, 1761400000000001601); +insert into sys_role_menu values (1761300000000000003, 1761400000000001602); +insert into sys_role_menu values (1761300000000000003, 1761400000000001603); +insert into sys_role_menu values (1761300000000000003, 1761400000000001620); +insert into sys_role_menu values (1761300000000000003, 1761400000000001621); +insert into sys_role_menu values (1761300000000000003, 1761400000000001622); +insert into sys_role_menu values (1761300000000000003, 1761400000000001623); +insert into sys_role_menu values (1761300000000000003, 1761400000000011616); +insert into sys_role_menu values (1761300000000000003, 1761400000000011618); +insert into sys_role_menu values (1761300000000000003, 1761400000000011619); +insert into sys_role_menu values (1761300000000000003, 1761400000000011622); +insert into sys_role_menu values (1761300000000000003, 1761400000000011623); +insert into sys_role_menu values (1761300000000000003, 1761400000000011629); +insert into sys_role_menu values (1761300000000000003, 1761400000000011632); +insert into sys_role_menu values (1761300000000000003, 1761400000000011633); +insert into sys_role_menu values (1761300000000000003, 1761400000000011638); +insert into sys_role_menu values (1761300000000000003, 1761400000000011639); +insert into sys_role_menu values (1761300000000000003, 1761400000000011640); +insert into sys_role_menu values (1761300000000000003, 1761400000000011641); +insert into sys_role_menu values (1761300000000000003, 1761400000000011642); +insert into sys_role_menu values (1761300000000000003, 1761400000000011643); +insert into sys_role_menu values (1761300000000000003, 1761400000000011701); +insert into sys_role_menu values (1761300000000000004, 1761400000000000005); +insert into sys_role_menu values (1761300000000000004, 1761400000000001500); +insert into sys_role_menu values (1761300000000000004, 1761400000000001501); +insert into sys_role_menu values (1761300000000000004, 1761400000000001502); +insert into sys_role_menu values (1761300000000000004, 1761400000000001503); +insert into sys_role_menu values (1761300000000000004, 1761400000000001504); +insert into sys_role_menu values (1761300000000000004, 1761400000000001505); +insert into sys_role_menu values (1761300000000000004, 1761400000000001506); +insert into sys_role_menu values (1761300000000000004, 1761400000000001507); +insert into sys_role_menu values (1761300000000000004, 1761400000000001508); +insert into sys_role_menu values (1761300000000000004, 1761400000000001509); +insert into sys_role_menu values (1761300000000000004, 1761400000000001510); +insert into sys_role_menu values (1761300000000000004, 1761400000000001511); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table if not exists sys_role_dept +( + role_id int8 not null, + dept_id int8 not null, + constraint sys_role_dept_pk primary key (role_id, dept_id) +); + +comment on table sys_role_dept is '角色和部门关联表'; +comment on column sys_role_dept.role_id is '角色ID'; +comment on column sys_role_dept.dept_id is '部门ID'; + + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table if not exists sys_user_post +( + user_id int8 not null, + post_id int8 not null, + constraint sys_user_post_pk primary key (user_id, post_id) +); + +comment on table sys_user_post is '用户与岗位关联表'; +comment on column sys_user_post.user_id is '用户ID'; +comment on column sys_user_post.post_id is '岗位ID'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values (1761100000000000001, 1761200000000000001); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table if not exists sys_oper_log +( + oper_id int8, + title varchar(50) default ''::varchar, + business_type int4 default 0, + method varchar(100) default ''::varchar, + request_method varchar(10) default ''::varchar, + operator_type int4 default 0, + oper_name varchar(50) default ''::varchar, + user_id int8, + dept_id int8, + dept_name varchar(50) default ''::varchar, + client_key varchar(32) default ''::varchar, + device_type varchar(32) default ''::varchar, + browser varchar(50) default ''::varchar, + os varchar(50) default ''::varchar, + oper_url varchar(255) default ''::varchar, + oper_ip varchar(128) default ''::varchar, + oper_location varchar(255) default ''::varchar, + oper_param varchar(4000) default ''::varchar, + json_result varchar(4000) default ''::varchar, + status int4 default 0, + error_msg varchar(4000) default ''::varchar, + oper_time timestamp, + cost_time int8 default 0, + constraint sys_oper_log_pk primary key (oper_id) +); + +create index idx_sys_oper_log_bt ON sys_oper_log (business_type); +create index idx_sys_oper_log_uid ON sys_oper_log (user_id); +create index idx_sys_oper_log_s ON sys_oper_log (status); +create index idx_sys_oper_log_ot ON sys_oper_log (oper_time); + +comment on table sys_oper_log is '操作日志记录'; +comment on column sys_oper_log.oper_id is '日志主键'; +comment on column sys_oper_log.title is '模块标题'; +comment on column sys_oper_log.business_type is '业务类型(0其它 1新增 2修改 3删除)'; +comment on column sys_oper_log.method is '方法名称'; +comment on column sys_oper_log.request_method is '请求方式'; +comment on column sys_oper_log.operator_type is '操作类别(0其它 1后台用户 2手机端用户)'; +comment on column sys_oper_log.oper_name is '操作人员'; +comment on column sys_oper_log.user_id is '操作用户ID'; +comment on column sys_oper_log.dept_id is '操作部门ID'; +comment on column sys_oper_log.dept_name is '部门名称'; +comment on column sys_oper_log.client_key is '客户端'; +comment on column sys_oper_log.device_type is '设备类型'; +comment on column sys_oper_log.browser is '浏览器类型'; +comment on column sys_oper_log.os is '操作系统'; +comment on column sys_oper_log.oper_url is '请求URL'; +comment on column sys_oper_log.oper_ip is '主机地址'; +comment on column sys_oper_log.oper_location is '操作地点'; +comment on column sys_oper_log.oper_param is '请求参数'; +comment on column sys_oper_log.json_result is '返回参数'; +comment on column sys_oper_log.status is '操作状态(0正常 1异常)'; +comment on column sys_oper_log.error_msg is '错误消息'; +comment on column sys_oper_log.oper_time is '操作时间'; +comment on column sys_oper_log.cost_time is '消耗时间'; + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table if not exists sys_dict_type +( + dict_id int8, + dict_name varchar(100) default ''::varchar, + dict_type varchar(100) default ''::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_dict_type_pk primary key (dict_id) +); + +create unique index sys_dict_type_index1 ON sys_dict_type (dict_type); + +comment on table sys_dict_type is '字典类型表'; +comment on column sys_dict_type.dict_id is '字典主键'; +comment on column sys_dict_type.dict_name is '字典名称'; +comment on column sys_dict_type.dict_type is '字典类型'; +comment on column sys_dict_type.create_dept is '创建部门'; +comment on column sys_dict_type.create_by is '创建者'; +comment on column sys_dict_type.create_time is '创建时间'; +comment on column sys_dict_type.update_by is '更新者'; +comment on column sys_dict_type.update_time is '更新时间'; +comment on column sys_dict_type.remark is '备注'; + +insert into sys_dict_type values(1761500000000000001, '用户性别', 'sys_user_gender', 1761000000000000103, 1761100000000000001, now(), null, null, '用户性别列表'); +insert into sys_dict_type values(1761500000000000002, '菜单状态', 'sys_show_hide', 1761000000000000103, 1761100000000000001, now(), null, null, '菜单状态列表'); +insert into sys_dict_type values(1761500000000000003, '系统开关', 'sys_normal_disable', 1761000000000000103, 1761100000000000001, now(), null, null, '系统开关列表'); +insert into sys_dict_type values(1761500000000000006, '系统是否', 'sys_yes_no', 1761000000000000103, 1761100000000000001, now(), null, null, '系统是否列表'); +insert into sys_dict_type values(1761500000000000007, '通知类型', 'sys_notice_type', 1761000000000000103, 1761100000000000001, now(), null, null, '通知类型列表'); +insert into sys_dict_type values(1761500000000000008, '通知状态', 'sys_notice_status', 1761000000000000103, 1761100000000000001, now(), null, null, '通知状态列表'); +insert into sys_dict_type values(1761500000000000009, '操作类型', 'sys_oper_type', 1761000000000000103, 1761100000000000001, now(), null, null, '操作类型列表'); +insert into sys_dict_type values(1761500000000000010, '系统状态', 'sys_common_status', 1761000000000000103, 1761100000000000001, now(), null, null, '登录状态列表'); +insert into sys_dict_type values(1761500000000000011, '授权类型', 'sys_grant_type', 1761000000000000103, 1761100000000000001, now(), null, null, '认证授权类型'); +insert into sys_dict_type values(1761500000000000012, '设备类型', 'sys_device_type', 1761000000000000103, 1761100000000000001, now(), null, null, '客户端设备类型'); + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table if not exists sys_dict_data +( + dict_code int8, + dict_sort int4 default 0, + dict_label varchar(100) default ''::varchar, + dict_value varchar(100) default ''::varchar, + dict_type varchar(100) default ''::varchar, + css_class varchar(100) default null::varchar, + list_class varchar(100) default null::varchar, + is_default char default 'N'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_dict_data_pk primary key (dict_code) +); + +create index idx_sys_dict_data_type ON sys_dict_data (dict_type); + +comment on table sys_dict_data is '字典数据表'; +comment on column sys_dict_data.dict_code is '字典编码'; +comment on column sys_dict_data.dict_sort is '字典排序'; +comment on column sys_dict_data.dict_label is '字典标签'; +comment on column sys_dict_data.dict_value is '字典键值'; +comment on column sys_dict_data.dict_type is '字典类型'; +comment on column sys_dict_data.css_class is '样式属性(其他样式扩展)'; +comment on column sys_dict_data.list_class is '表格回显样式'; +comment on column sys_dict_data.is_default is '是否默认(Y是 N否)'; +comment on column sys_dict_data.create_dept is '创建部门'; +comment on column sys_dict_data.create_by is '创建者'; +comment on column sys_dict_data.create_time is '创建时间'; +comment on column sys_dict_data.update_by is '更新者'; +comment on column sys_dict_data.update_time is '更新时间'; +comment on column sys_dict_data.remark is '备注'; + +insert into sys_dict_data values(1761600000000000001, 1, '男', '0', 'sys_user_gender', '', '', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, '性别男'); +insert into sys_dict_data values(1761600000000000002, 2, '女', '1', 'sys_user_gender', '', '', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '性别女'); +insert into sys_dict_data values(1761600000000000003, 3, '未知', '2', 'sys_user_gender', '', '', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '性别未知'); +insert into sys_dict_data values(1761600000000000004, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, '显示菜单'); +insert into sys_dict_data values(1761600000000000005, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '隐藏菜单'); +insert into sys_dict_data values(1761600000000000006, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, '正常状态'); +insert into sys_dict_data values(1761600000000000007, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '停用状态'); +insert into sys_dict_data values(1761600000000000012, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, '系统默认是'); +insert into sys_dict_data values(1761600000000000013, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '系统默认否'); +insert into sys_dict_data values(1761600000000000014, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, '通知'); +insert into sys_dict_data values(1761600000000000015, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '公告'); +insert into sys_dict_data values(1761600000000000016, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, '正常状态'); +insert into sys_dict_data values(1761600000000000017, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '关闭状态'); +insert into sys_dict_data values(1761600000000000029, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '其他操作'); +insert into sys_dict_data values(1761600000000000018, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '新增操作'); +insert into sys_dict_data values(1761600000000000019, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '修改操作'); +insert into sys_dict_data values(1761600000000000020, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '删除操作'); +insert into sys_dict_data values(1761600000000000021, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '授权操作'); +insert into sys_dict_data values(1761600000000000022, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '导出操作'); +insert into sys_dict_data values(1761600000000000023, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '导入操作'); +insert into sys_dict_data values(1761600000000000024, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '强退操作'); +insert into sys_dict_data values(1761600000000000025, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '生成操作'); +insert into sys_dict_data values(1761600000000000026, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '清空操作'); +insert into sys_dict_data values(1761600000000000027, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '正常状态'); +insert into sys_dict_data values(1761600000000000028, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '停用状态'); +insert into sys_dict_data values(1761600000000000030, 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '密码认证'); +insert into sys_dict_data values(1761600000000000031, 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '短信认证'); +insert into sys_dict_data values(1761600000000000032, 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '邮件认证'); +insert into sys_dict_data values(1761600000000000033, 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '小程序认证'); +insert into sys_dict_data values(1761600000000000034, 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '三方登录认证'); +insert into sys_dict_data values(1761600000000000035, 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, 'PC'); +insert into sys_dict_data values(1761600000000000036, 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '安卓'); +insert into sys_dict_data values(1761600000000000037, 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, 'iOS'); +insert into sys_dict_data values(1761600000000000038, 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, now(), null, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table if not exists sys_config +( + config_id int8, + config_name varchar(100) default ''::varchar, + config_key varchar(100) default ''::varchar, + config_value varchar(500) default ''::varchar, + config_type char default 'N'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_config_pk primary key (config_id) +); + +comment on table sys_config is '参数配置表'; +comment on column sys_config.config_id is '参数主键'; +comment on column sys_config.config_name is '参数名称'; +comment on column sys_config.config_key is '参数键名'; +comment on column sys_config.config_value is '参数键值'; +comment on column sys_config.config_type is '系统内置(Y是 N否)'; +comment on column sys_config.create_dept is '创建部门'; +comment on column sys_config.create_by is '创建者'; +comment on column sys_config.create_time is '创建时间'; +comment on column sys_config.update_by is '更新者'; +comment on column sys_config.update_time is '更新时间'; +comment on column sys_config.remark is '备注'; + +insert into sys_config values(1761700000000000001, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, '初始化密码 123456'); +insert into sys_config values(1761700000000000002, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(1761700000000000003, 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 1761000000000000103, 1761100000000000001, now(), null, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table if not exists sys_login_info +( + info_id int8, + user_name varchar(50) default ''::varchar, + client_key varchar(32) default ''::varchar, + device_type varchar(32) default ''::varchar, + ipaddr varchar(128) default ''::varchar, + login_location varchar(255) default ''::varchar, + browser varchar(50) default ''::varchar, + os varchar(50) default ''::varchar, + status char default '0'::bpchar, + msg varchar(255) default ''::varchar, + login_time timestamp, + constraint sys_login_info_pk primary key (info_id) +); + +create index idx_sys_login_info_s ON sys_login_info (status); +create index idx_sys_login_info_lt ON sys_login_info (login_time); + +comment on table sys_login_info is '系统访问记录'; +comment on column sys_login_info.info_id is '访问ID'; +comment on column sys_login_info.user_name is '用户账号'; +comment on column sys_login_info.client_key is '客户端'; +comment on column sys_login_info.device_type is '设备类型'; +comment on column sys_login_info.ipaddr is '登录IP地址'; +comment on column sys_login_info.login_location is '登录地点'; +comment on column sys_login_info.browser is '浏览器类型'; +comment on column sys_login_info.os is '操作系统'; +comment on column sys_login_info.status is '登录状态(0正常 1异常)'; +comment on column sys_login_info.msg is '提示消息'; +comment on column sys_login_info.login_time is '访问时间'; + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table if not exists sys_notice +( + notice_id int8, + notice_title varchar(50) not null, + notice_type char not null, + notice_content text, + status char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(255) default null::varchar, + constraint sys_notice_pk primary key (notice_id) +); + +comment on table sys_notice is '通知公告表'; +comment on column sys_notice.notice_id is '公告ID'; +comment on column sys_notice.notice_title is '公告标题'; +comment on column sys_notice.notice_type is '公告类型(1通知 2公告)'; +comment on column sys_notice.notice_content is '公告内容'; +comment on column sys_notice.status is '公告状态(0正常 1关闭)'; +comment on column sys_notice.create_dept is '创建部门'; +comment on column sys_notice.create_by is '创建者'; +comment on column sys_notice.create_time is '创建时间'; +comment on column sys_notice.update_by is '更新者'; +comment on column sys_notice.update_time is '更新时间'; +comment on column sys_notice.remark is '备注'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values(1761800000000000001, '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 1761000000000000103, 1761100000000000001, now(), null, null, '管理员'); +insert into sys_notice values(1761800000000000002, '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 1761000000000000103, 1761100000000000001, now(), null, null, '管理员'); + + +-- ---------------------------- +-- 18、消息记录表 +-- ---------------------------- +create table if not exists sys_message +( + message_id int8, + category varchar(20) not null, + type varchar(20) not null, + source varchar(20) not null, + title varchar(100) default ''::varchar, + message varchar(500) default ''::varchar, + content text, + data_json text, + path varchar(500) default null::varchar, + send_user_ids varchar(2000) not null default '0'::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint sys_message_pk primary key (message_id) +); + +create index if not exists idx_sys_message_category_time on sys_message (category, create_time); + +comment on table sys_message is '消息记录表'; +comment on column sys_message.message_id is '消息ID'; +comment on column sys_message.category is '消息分组(system/notice/workflow)'; +comment on column sys_message.type is '消息类型'; +comment on column sys_message.source is '消息来源'; +comment on column sys_message.title is '标题'; +comment on column sys_message.message is '摘要消息'; +comment on column sys_message.content is '详细内容'; +comment on column sys_message.data_json is '扩展数据JSON'; +comment on column sys_message.path is '前端跳转路径'; +comment on column sys_message.send_user_ids is '目标用户ID串,0表示全局'; +comment on column sys_message.create_dept is '创建部门'; +comment on column sys_message.create_by is '创建者'; +comment on column sys_message.create_time is '创建时间'; +comment on column sys_message.update_by is '更新者'; +comment on column sys_message.update_time is '更新时间'; + + +-- ---------------------------- +-- 19、代码生成业务表 +-- ---------------------------- +create table if not exists gen_table +( + table_id int8, + data_name varchar(200) default ''::varchar, + table_name varchar(200) default ''::varchar, + table_comment varchar(500) default ''::varchar, + class_name varchar(100) default ''::varchar, + tpl_category varchar(200) default 'crud'::varchar, + frontend_type varchar(50) default 'vue'::varchar, + package_name varchar(100) default null::varchar, + module_name varchar(30) default null::varchar, + business_name varchar(30) default null::varchar, + function_name varchar(50) default null::varchar, + function_author varchar(50) default null::varchar, + gen_type char default '0'::bpchar not null, + gen_path varchar(200) default '/'::varchar, + options varchar(1000) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint gen_table_pk primary key (table_id) +); + +comment on table gen_table is '代码生成业务表'; +comment on column gen_table.table_id is '编号'; +comment on column gen_table.data_name is '数据源名称'; +comment on column gen_table.table_name is '表名称'; +comment on column gen_table.table_comment is '表描述'; +comment on column gen_table.class_name is '实体类名称'; +comment on column gen_table.tpl_category is '使用的模板(CRUD单表操作 TREE树表操作)'; +comment on column gen_table.frontend_type is '前端模板类型,对应 vm 下的模板目录'; +comment on column gen_table.package_name is '生成包路径'; +comment on column gen_table.module_name is '生成模块名'; +comment on column gen_table.business_name is '生成业务名'; +comment on column gen_table.function_name is '生成功能名'; +comment on column gen_table.function_author is '生成功能作者'; +comment on column gen_table.gen_type is '生成代码方式(0zip压缩包 1自定义路径)'; +comment on column gen_table.gen_path is '生成路径(不填默认项目路径)'; +comment on column gen_table.options is '其它生成选项'; +comment on column gen_table.create_dept is '创建部门'; +comment on column gen_table.create_by is '创建者'; +comment on column gen_table.create_time is '创建时间'; +comment on column gen_table.update_by is '更新者'; +comment on column gen_table.update_time is '更新时间'; +comment on column gen_table.remark is '备注'; + +-- ---------------------------- +-- 20、代码生成业务表字段 +-- ---------------------------- +create table if not exists gen_table_column +( + column_id int8, + table_id int8, + column_name varchar(200) default null::varchar, + column_comment varchar(500) default null::varchar, + column_type varchar(100) default null::varchar, + java_type varchar(500) default null::varchar, + java_field varchar(200) default null::varchar, + is_pk char default null::bpchar, + is_increment char default null::bpchar, + is_required char default null::bpchar, + is_insert char default null::bpchar, + is_edit char default null::bpchar, + is_list char default null::bpchar, + is_query char default null::bpchar, + query_type varchar(200) default 'EQ'::varchar, + html_type varchar(200) default null::varchar, + dict_type varchar(200) default ''::varchar, + sort int4, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint gen_table_column_pk primary key (column_id) +); + +comment on table gen_table_column is '代码生成业务表字段'; +comment on column gen_table_column.column_id is '编号'; +comment on column gen_table_column.table_id is '归属表编号'; +comment on column gen_table_column.column_name is '列名称'; +comment on column gen_table_column.column_comment is '列描述'; +comment on column gen_table_column.column_type is '列类型'; +comment on column gen_table_column.java_type is 'JAVA类型'; +comment on column gen_table_column.java_field is 'JAVA字段名'; +comment on column gen_table_column.is_pk is '是否主键(1是)'; +comment on column gen_table_column.is_increment is '是否自增(1是)'; +comment on column gen_table_column.is_required is '是否必填(1是)'; +comment on column gen_table_column.is_insert is '是否为插入字段(1是)'; +comment on column gen_table_column.is_edit is '是否编辑字段(1是)'; +comment on column gen_table_column.is_list is '是否列表字段(1是)'; +comment on column gen_table_column.is_query is '是否查询字段(1是)'; +comment on column gen_table_column.query_type is '查询方式(等于、不等于、大于、小于、范围)'; +comment on column gen_table_column.html_type is '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)'; +comment on column gen_table_column.dict_type is '字典类型'; +comment on column gen_table_column.sort is '排序'; +comment on column gen_table_column.create_dept is '创建部门'; +comment on column gen_table_column.create_by is '创建者'; +comment on column gen_table_column.create_time is '创建时间'; +comment on column gen_table_column.update_by is '更新者'; +comment on column gen_table_column.update_time is '更新时间'; + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table if not exists sys_oss +( + oss_id int8, + file_name varchar(255) default ''::varchar not null, + original_name varchar(255) default ''::varchar not null, + file_suffix varchar(10) default ''::varchar not null, + url varchar(500) default ''::varchar not null, + ext1 varchar(500) default ''::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + service varchar(20) default 'minio'::varchar, + constraint sys_oss_pk primary key (oss_id) +); + +comment on table sys_oss is 'OSS对象存储表'; +comment on column sys_oss.oss_id is '对象存储主键'; +comment on column sys_oss.file_name is '文件名'; +comment on column sys_oss.original_name is '原名'; +comment on column sys_oss.file_suffix is '文件后缀名'; +comment on column sys_oss.url is 'URL地址'; +comment on column sys_oss.ext1 is '扩展字段'; +comment on column sys_oss.create_by is '上传人'; +comment on column sys_oss.create_dept is '创建部门'; +comment on column sys_oss.create_time is '创建时间'; +comment on column sys_oss.update_by is '更新者'; +comment on column sys_oss.update_time is '更新时间'; +comment on column sys_oss.service is '服务商'; + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table if not exists sys_oss_config +( + oss_config_id int8, + config_key varchar(20) default ''::varchar not null, + access_key varchar(255) default ''::varchar, + secret_key varchar(255) default ''::varchar, + bucket_name varchar(255) default ''::varchar, + prefix varchar(255) default ''::varchar, + endpoint varchar(255) default ''::varchar, + domain_url varchar(255) default ''::varchar, + is_https char default 'N'::bpchar, + region varchar(255) default ''::varchar, + access_policy char(1) default '1'::bpchar not null, + status char default 'N'::bpchar, + ext1 varchar(255) default ''::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default ''::varchar, + constraint sys_oss_config_pk primary key (oss_config_id) +); + +comment on table sys_oss_config is '对象存储配置表'; +comment on column sys_oss_config.oss_config_id is '主键'; +comment on column sys_oss_config.config_key is '配置key'; +comment on column sys_oss_config.access_key is 'accessKey'; +comment on column sys_oss_config.secret_key is '秘钥'; +comment on column sys_oss_config.bucket_name is '桶名称'; +comment on column sys_oss_config.prefix is '前缀'; +comment on column sys_oss_config.endpoint is '访问站点'; +comment on column sys_oss_config.domain_url is '自定义域名'; +comment on column sys_oss_config.is_https is '是否https(Y=是,N=否)'; +comment on column sys_oss_config.region is '域'; +comment on column sys_oss_config.access_policy is '桶权限类型(0=private 1=public 2=custom)'; +comment on column sys_oss_config.status is '是否默认(Y=是,N=否)'; +comment on column sys_oss_config.ext1 is '扩展字段'; +comment on column sys_oss_config.create_dept is '创建部门'; +comment on column sys_oss_config.create_by is '创建者'; +comment on column sys_oss_config.create_time is '创建时间'; +comment on column sys_oss_config.update_by is '更新者'; +comment on column sys_oss_config.update_time is '更新时间'; +comment on column sys_oss_config.remark is '备注'; + +insert into sys_oss_config values (1761900000000000001, 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '', 'N', '', '1', 'Y', '', 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now(), null); +insert into sys_oss_config values (1761900000000000002, 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '', 'N', '', '1', 'N', '', 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now(), null); +insert into sys_oss_config values (1761900000000000003, 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '', 'N', '', '1', 'N', '', 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now(), null); +insert into sys_oss_config values (1761900000000000004, 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1240000000', '', 'cos.ap-beijing.myqcloud.com', '', 'N', 'ap-beijing', '1', 'N', '', 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now(), null); +insert into sys_oss_config values (1761900000000000005, 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '', 'N', '', '1', 'N', '', 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now(), NULL); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id int8, + client_id varchar(64) default ''::varchar, + client_key varchar(32) default ''::varchar, + client_secret varchar(255) default ''::varchar, + grant_type varchar(255) default ''::varchar, + device_type varchar(32) default ''::varchar, + access_path varchar(2000) default ''::varchar, + ip_whitelist varchar(1000) default ''::varchar, + active_timeout int4 default 1800, + timeout int4 default 604800, + status char(1) default '0'::bpchar, + del_flag char(1) default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint sys_client_pk primary key (id) +); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.access_path is '允许访问路径'; +comment on column sys_client.ip_whitelist is 'IP白名单'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1762000000000000001, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', '', '', 1800, 604800, 0, 0, 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now()); +insert into sys_client values (1762000000000000002, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', '/app/**', '', 1800, 604800, 0, 0, 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now()); + +create table if not exists test_demo +( + id int8, + dept_id int8, + user_id int8, + order_num int4 default 0, + test_key varchar(255), + value varchar(255), + version int4 default 0, + create_dept int8, + create_time timestamp, + create_by int8, + update_time timestamp, + update_by int8, + del_flag int4 default 0 +); + +comment on table test_demo is '测试单表'; +comment on column test_demo.id is '主键'; +comment on column test_demo.dept_id is '部门id'; +comment on column test_demo.user_id is '用户id'; +comment on column test_demo.order_num is '排序号'; +comment on column test_demo.test_key is 'key键'; +comment on column test_demo.value is '值'; +comment on column test_demo.version is '版本'; +comment on column test_demo.create_dept is '创建部门'; +comment on column test_demo.create_time is '创建时间'; +comment on column test_demo.create_by is '创建人'; +comment on column test_demo.update_time is '更新时间'; +comment on column test_demo.update_by is '更新人'; +comment on column test_demo.del_flag is '删除标志'; + +create table if not exists test_tree +( + id int8, + parent_id int8 default 0, + dept_id int8, + user_id int8, + tree_name varchar(255), + version int4 default 0, + create_dept int8, + create_time timestamp, + create_by int8, + update_time timestamp, + update_by int8, + del_flag integer default 0 +); + +comment on table test_tree is '测试树表'; +comment on column test_tree.id is '主键'; +comment on column test_tree.parent_id is '父id'; +comment on column test_tree.dept_id is '部门id'; +comment on column test_tree.user_id is '用户id'; +comment on column test_tree.tree_name is '值'; +comment on column test_tree.version is '版本'; +comment on column test_tree.create_dept is '创建部门'; +comment on column test_tree.create_time is '创建时间'; +comment on column test_tree.create_by is '创建人'; +comment on column test_tree.update_time is '更新时间'; +comment on column test_tree.update_by is '更新人'; +comment on column test_tree.del_flag is '删除标志'; + +INSERT INTO test_demo VALUES (1762100000000000001, 1761000000000000102, 1761100000000000004, 1, '测试数据权限', '测试', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000002, 1761000000000000102, 1761100000000000003, 2, '子节点1', '111', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000003, 1761000000000000102, 1761100000000000003, 3, '子节点2', '222', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000004, 1761000000000000108, 1761100000000000004, 4, '测试数据', 'demo', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000005, 1761000000000000108, 1761100000000000003, 13, '子节点11', '1111', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000006, 1761000000000000108, 1761100000000000003, 12, '子节点22', '2222', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000007, 1761000000000000108, 1761100000000000003, 11, '子节点33', '3333', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000008, 1761000000000000108, 1761100000000000003, 10, '子节点44', '4444', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000009, 1761000000000000108, 1761100000000000003, 9, '子节点55', '5555', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000010, 1761000000000000108, 1761100000000000003, 8, '子节点66', '6666', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000011, 1761000000000000108, 1761100000000000003, 7, '子节点77', '7777', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000012, 1761000000000000108, 1761100000000000003, 6, '子节点88', '8888', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000013, 1761000000000000108, 1761100000000000003, 5, '子节点99', '9999', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); + +INSERT INTO test_tree VALUES (1762200000000000001, 0, 1761000000000000102, 1761100000000000004, '测试数据权限', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000002, 1762200000000000001, 1761000000000000102, 1761100000000000003, '子节点1', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000003, 1762200000000000002, 1761000000000000102, 1761100000000000003, '子节点2', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000004, 0, 1761000000000000108, 1761100000000000004, '测试树1', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000005, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点11', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000006, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点22', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000007, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点33', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000008, 1762200000000000005, 1761000000000000108, 1761100000000000003, '子节点44', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000009, 1762200000000000006, 1761000000000000108, 1761100000000000003, '子节点55', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000010, 1762200000000000007, 1761000000000000108, 1761100000000000003, '子节点66', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000011, 1762200000000000007, 1761000000000000108, 1761100000000000003, '子节点77', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000012, 1762200000000000010, 1761000000000000108, 1761100000000000003, '子节点88', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000013, 1762200000000000010, 1761000000000000108, 1761100000000000003, '子节点99', 0, 1761000000000000103, now(), 1761100000000000001, NULL, NULL, 0); + +-- 字符串自动转时间 避免框架时间查询报错问题 +create or replace function cast_varchar_to_timestamp(varchar) returns timestamptz as $$ +select to_timestamp($1, 'yyyy-mm-dd hh24:mi:ss'); +$$ language sql strict ; + +create cast (varchar as timestamptz) with function cast_varchar_to_timestamp as IMPLICIT; + diff --git a/script/sql/postgres/postgres_ry_workflow.sql b/script/sql/postgres/postgres_ry_workflow.sql new file mode 100644 index 000000000..61012fe0e --- /dev/null +++ b/script/sql/postgres/postgres_ry_workflow.sql @@ -0,0 +1,522 @@ +CREATE TABLE flow_definition +( + id int8 NOT NULL, + flow_code varchar(40) NOT NULL, + flow_name varchar(100) NOT NULL, + model_value varchar(40) NOT NULL DEFAULT 'CLASSICS', + category varchar(100) NULL, + "version" varchar(20) NOT NULL, + is_publish int2 NOT NULL DEFAULT 0, + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, + form_path varchar(100) NULL, + activity_status int2 NOT NULL DEFAULT 1, + listener_type varchar(100) NULL, + listener_path varchar(400) NULL, + ext varchar(500) NULL, + create_time timestamp NULL, + create_by varchar(64) NULL DEFAULT '':: character varying, + update_time timestamp NULL, + update_by varchar(64) NULL DEFAULT '':: character varying, + del_flag bpchar(1) NULL DEFAULT '0':: character varying, + tenant_id varchar(40) NULL, + CONSTRAINT flow_definition_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_definition IS '流程定义表'; + +COMMENT ON COLUMN flow_definition.id IS '主键id'; +COMMENT ON COLUMN flow_definition.flow_code IS '流程编码'; +COMMENT ON COLUMN flow_definition.flow_name IS '流程名称'; +COMMENT ON COLUMN flow_definition.model_value IS '设计器模型(CLASSICS经典模型 MIMIC仿钉钉模型)'; +COMMENT ON COLUMN flow_definition.category IS '流程类别'; +COMMENT ON COLUMN flow_definition."version" IS '流程版本'; +COMMENT ON COLUMN flow_definition.is_publish IS '是否发布(0未发布 1已发布 9失效)'; +COMMENT ON COLUMN flow_definition.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_definition.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_definition.activity_status IS '流程激活状态(0挂起 1激活)'; +COMMENT ON COLUMN flow_definition.listener_type IS '监听器类型'; +COMMENT ON COLUMN flow_definition.listener_path IS '监听器路径'; +COMMENT ON COLUMN flow_definition.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_definition.create_time IS '创建时间'; +COMMENT ON COLUMN flow_definition.create_by IS '创建人'; +COMMENT ON COLUMN flow_definition.update_time IS '更新时间'; +COMMENT ON COLUMN flow_definition.update_by IS '更新人'; +COMMENT ON COLUMN flow_definition.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_definition.tenant_id IS '租户id'; + +CREATE TABLE flow_node +( + id int8 NOT NULL, + node_type int2 NOT NULL, + definition_id int8 NOT NULL, + node_code varchar(100) NOT NULL, + node_name varchar(100) NULL, + permission_flag varchar(200) NULL, + node_ratio varchar(200) NULL, + coordinate varchar(100) NULL, + any_node_skip varchar(100) NULL, + listener_type varchar(100) NULL, + listener_path varchar(400) NULL, + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, + form_path varchar(100) NULL, + "version" varchar(20) NOT NULL, + create_time timestamp NULL, + create_by varchar(64) NULL DEFAULT '':: character varying, + update_time timestamp NULL, + update_by varchar(64) NULL DEFAULT '':: character varying, + ext text NULL, + del_flag bpchar(1) NULL DEFAULT '0':: character varying, + tenant_id varchar(40) NULL, + CONSTRAINT flow_node_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_node IS '流程节点表'; + +COMMENT ON COLUMN flow_node.id IS '主键id'; +COMMENT ON COLUMN flow_node.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_node.definition_id IS '流程定义id'; +COMMENT ON COLUMN flow_node.node_code IS '流程节点编码'; +COMMENT ON COLUMN flow_node.node_name IS '流程节点名称'; +COMMENT ON COLUMN flow_node.permission_flag IS '权限标识(权限类型:权限标识,可以多个,用@@隔开)'; +COMMENT ON COLUMN flow_node.node_ratio IS '流程签署比例值'; +COMMENT ON COLUMN flow_node.coordinate IS '坐标'; +COMMENT ON COLUMN flow_node.any_node_skip IS '任意结点跳转'; +COMMENT ON COLUMN flow_node.listener_type IS '监听器类型'; +COMMENT ON COLUMN flow_node.listener_path IS '监听器路径'; +COMMENT ON COLUMN flow_node.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_node.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_node."version" IS '版本'; +COMMENT ON COLUMN flow_node.create_time IS '创建时间'; +COMMENT ON COLUMN flow_node.create_by IS '创建人'; +COMMENT ON COLUMN flow_node.update_time IS '更新时间'; +COMMENT ON COLUMN flow_node.update_by IS '更新人'; +COMMENT ON COLUMN flow_node.ext IS '节点扩展属性'; +COMMENT ON COLUMN flow_node.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_node.tenant_id IS '租户id'; + + +CREATE TABLE flow_skip +( + id int8 NOT NULL, + definition_id int8 NOT NULL, + now_node_code varchar(100) NOT NULL, + now_node_type int2 NULL, + next_node_code varchar(100) NOT NULL, + next_node_type int2 NULL, + skip_name varchar(100) NULL, + skip_type varchar(40) NULL, + skip_condition varchar(200) NULL, + coordinate varchar(100) NULL, + create_time timestamp NULL, + create_by varchar(64) NULL DEFAULT '':: character varying, + update_time timestamp NULL, + update_by varchar(64) NULL DEFAULT '':: character varying, + del_flag bpchar(1) NULL DEFAULT '0':: character varying, + tenant_id varchar(40) NULL, + CONSTRAINT flow_skip_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_skip IS '节点跳转关联表'; + +COMMENT ON COLUMN flow_skip.id IS '主键id'; +COMMENT ON COLUMN flow_skip.definition_id IS '流程定义id'; +COMMENT ON COLUMN flow_skip.now_node_code IS '当前流程节点的编码'; +COMMENT ON COLUMN flow_skip.now_node_type IS '当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_skip.next_node_code IS '下一个流程节点的编码'; +COMMENT ON COLUMN flow_skip.next_node_type IS '下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_skip.skip_name IS '跳转名称'; +COMMENT ON COLUMN flow_skip.skip_type IS '跳转类型(PASS审批通过 REJECT退回)'; +COMMENT ON COLUMN flow_skip.skip_condition IS '跳转条件'; +COMMENT ON COLUMN flow_skip.coordinate IS '坐标'; +COMMENT ON COLUMN flow_skip.create_time IS '创建时间'; +COMMENT ON COLUMN flow_skip.create_by IS '创建人'; +COMMENT ON COLUMN flow_skip.update_time IS '更新时间'; +COMMENT ON COLUMN flow_skip.update_by IS '更新人'; +COMMENT ON COLUMN flow_skip.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_skip.tenant_id IS '租户id'; + +CREATE TABLE flow_instance +( + id int8 NOT NULL, + definition_id int8 NOT NULL, + business_id varchar(40) NOT NULL, + node_type int2 NOT NULL, + node_code varchar(40) NOT NULL, + node_name varchar(100) NULL, + variable text NULL, + flow_status varchar(20) NOT NULL, + activity_status int2 NOT NULL DEFAULT 1, + def_json text NULL, + create_time timestamp NULL, + create_by varchar(64) NULL DEFAULT '':: character varying, + update_time timestamp NULL, + update_by varchar(64) NULL DEFAULT '':: character varying, + ext varchar(500) NULL, + del_flag bpchar(1) NULL DEFAULT '0':: character varying, + tenant_id varchar(40) NULL, + CONSTRAINT flow_instance_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_instance IS '流程实例表'; + +COMMENT ON COLUMN flow_instance.id IS '主键id'; +COMMENT ON COLUMN flow_instance.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_instance.business_id IS '业务id'; +COMMENT ON COLUMN flow_instance.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_instance.node_code IS '流程节点编码'; +COMMENT ON COLUMN flow_instance.node_name IS '流程节点名称'; +COMMENT ON COLUMN flow_instance.variable IS '任务变量'; +COMMENT ON COLUMN flow_instance.flow_status IS '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)'; +COMMENT ON COLUMN flow_instance.activity_status IS '流程激活状态(0挂起 1激活)'; +COMMENT ON COLUMN flow_instance.def_json IS '流程定义json'; +COMMENT ON COLUMN flow_instance.create_time IS '创建时间'; +COMMENT ON COLUMN flow_instance.create_by IS '创建人'; +COMMENT ON COLUMN flow_instance.update_time IS '更新时间'; +COMMENT ON COLUMN flow_instance.update_by IS '更新人'; +COMMENT ON COLUMN flow_instance.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_instance.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_instance.tenant_id IS '租户id'; + +CREATE TABLE flow_task +( + id int8 NOT NULL, + definition_id int8 NOT NULL, + instance_id int8 NOT NULL, + node_code varchar(100) NOT NULL, + node_name varchar(100) NULL, + node_type int2 NOT NULL, + flow_status varchar(20) NOT NULL, + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, + form_path varchar(100) NULL, + create_time timestamp NULL, + create_by varchar(64) NULL DEFAULT '':: character varying, + update_time timestamp NULL, + update_by varchar(64) NULL DEFAULT '':: character varying, + del_flag bpchar(1) NULL DEFAULT '0':: character varying, + tenant_id varchar(40) NULL, + CONSTRAINT flow_task_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_task IS '待办任务表'; + +COMMENT ON COLUMN flow_task.id IS '主键id'; +COMMENT ON COLUMN flow_task.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_task.instance_id IS '对应flow_instance表的id'; +COMMENT ON COLUMN flow_task.node_code IS '节点编码'; +COMMENT ON COLUMN flow_task.node_name IS '节点名称'; +COMMENT ON COLUMN flow_task.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_task.flow_status IS '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)'; +COMMENT ON COLUMN flow_task.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_task.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_task.create_time IS '创建时间'; +COMMENT ON COLUMN flow_task.create_by IS '创建人'; +COMMENT ON COLUMN flow_task.update_time IS '更新时间'; +COMMENT ON COLUMN flow_task.update_by IS '更新人'; +COMMENT ON COLUMN flow_task.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_task.tenant_id IS '租户id'; + +CREATE TABLE flow_his_task +( + id int8 NOT NULL, + definition_id int8 NOT NULL, + instance_id int8 NOT NULL, + task_id int8 NOT NULL, + node_code varchar(100) NULL, + node_name varchar(100) NULL, + node_type int2 NULL, + target_node_code varchar(200) NULL, + target_node_name varchar(200) NULL, + approver varchar(40) NULL, + cooperate_type int2 NOT NULL DEFAULT 0, + collaborator varchar(500) NULL, + skip_type varchar(10) NULL, + flow_status varchar(20) NOT NULL, + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, + form_path varchar(100) NULL, + ext text NULL, + message varchar(500) NULL, + variable text NULL, + create_time timestamp NULL, + update_time timestamp NULL, + del_flag bpchar(1) NULL DEFAULT '0':: character varying, + tenant_id varchar(40) NULL, + CONSTRAINT flow_his_task_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_his_task IS '历史任务记录表'; + +COMMENT ON COLUMN flow_his_task.id IS '主键id'; +COMMENT ON COLUMN flow_his_task.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_his_task.instance_id IS '对应flow_instance表的id'; +COMMENT ON COLUMN flow_his_task.task_id IS '对应flow_task表的id'; +COMMENT ON COLUMN flow_his_task.node_code IS '开始节点编码'; +COMMENT ON COLUMN flow_his_task.node_name IS '开始节点名称'; +COMMENT ON COLUMN flow_his_task.node_type IS '开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_his_task.target_node_code IS '目标节点编码'; +COMMENT ON COLUMN flow_his_task.target_node_name IS '结束节点名称'; +COMMENT ON COLUMN flow_his_task.approver IS '审批者'; +COMMENT ON COLUMN flow_his_task.cooperate_type IS '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)'; +COMMENT ON COLUMN flow_his_task.collaborator IS '协作人'; +COMMENT ON COLUMN flow_his_task.skip_type IS '流转类型(PASS通过 REJECT退回 NONE无动作)'; +COMMENT ON COLUMN flow_his_task.flow_status IS '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)'; +COMMENT ON COLUMN flow_his_task.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_his_task.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_his_task.message IS '审批意见'; +COMMENT ON COLUMN flow_his_task.variable IS '任务变量'; +COMMENT ON COLUMN flow_his_task.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_his_task.create_time IS '任务开始时间'; +COMMENT ON COLUMN flow_his_task.update_time IS '审批完成时间'; +COMMENT ON COLUMN flow_his_task.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_his_task.tenant_id IS '租户id'; + +CREATE TABLE flow_user +( + id int8 NOT NULL, + "type" bpchar(1) NOT NULL, + processed_by varchar(80) NULL, + associated int8 NOT NULL, + create_time timestamp NULL, + create_by varchar(64) NULL DEFAULT '':: character varying, + update_time timestamp NULL, + update_by varchar(64) NULL DEFAULT '':: character varying, + del_flag bpchar(1) NULL DEFAULT '0':: character varying, + tenant_id varchar(40) NULL, + CONSTRAINT flow_user_pk PRIMARY KEY (id) +); +CREATE INDEX user_processed_type ON flow_user USING btree (processed_by, type); +CREATE INDEX user_associated_idx ON FLOW_USER USING btree (associated); +COMMENT ON TABLE flow_user IS '流程用户表'; + +COMMENT ON COLUMN flow_user.id IS '主键id'; +COMMENT ON COLUMN flow_user."type" IS '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)'; +COMMENT ON COLUMN flow_user.processed_by IS '权限人'; +COMMENT ON COLUMN flow_user.associated IS '任务表id'; +COMMENT ON COLUMN flow_user.create_time IS '创建时间'; +COMMENT ON COLUMN flow_user.create_by IS '创建人'; +COMMENT ON COLUMN flow_user.update_time IS '更新时间'; +COMMENT ON COLUMN flow_user.update_by IS '更新人'; +COMMENT ON COLUMN flow_user.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_user.tenant_id IS '租户id'; + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +CREATE TABLE flow_category +( + category_id int8 NOT NULL, + parent_id int8 DEFAULT 0, + ancestors VARCHAR(500) DEFAULT ''::varchar, + category_name VARCHAR(30) NOT NULL, + order_num INT DEFAULT 0, + del_flag CHAR DEFAULT '0'::bpchar, + create_dept int8, + create_by int8, + create_time TIMESTAMP, + update_by int8, + update_time TIMESTAMP, + PRIMARY KEY (category_id) +); + +COMMENT ON TABLE flow_category IS '流程分类'; +COMMENT ON COLUMN flow_category.category_id IS '流程分类ID'; +COMMENT ON COLUMN flow_category.parent_id IS '父流程分类id'; +COMMENT ON COLUMN flow_category.ancestors IS '祖级列表'; +COMMENT ON COLUMN flow_category.category_name IS '流程分类名称'; +COMMENT ON COLUMN flow_category.order_num IS '显示顺序'; +COMMENT ON COLUMN flow_category.del_flag IS '删除标志(0代表存在 1代表删除)'; +COMMENT ON COLUMN flow_category.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_category.create_by IS '创建者'; +COMMENT ON COLUMN flow_category.create_time IS '创建时间'; +COMMENT ON COLUMN flow_category.update_by IS '更新者'; +COMMENT ON COLUMN flow_category.update_time IS '更新时间'; + +INSERT INTO flow_category VALUES (1762300000000000100, 0, '0', 'OA审批', 0, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000101, 1762300000000000100, '0,1762300000000000100', '假勤管理', 0, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000102, 1762300000000000100, '0,1762300000000000100', '人事管理', 1, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000103, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '请假', 0, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000104, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '出差', 1, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000105, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '加班', 2, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000106, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '换班', 3, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000107, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '外出', 4, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000108, 1762300000000000102, '0,1762300000000000100,1762300000000000102', '转正', 1, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); +INSERT INTO flow_category VALUES (1762300000000000109, 1762300000000000102, '0,1762300000000000100,1762300000000000102', '离职', 2, '0', 1761000000000000103, 1761100000000000001, now(), NULL, NULL); + +-- ---------------------------- +-- 流程spel表达式定义表 +-- ---------------------------- +CREATE TABLE flow_spel ( + id int8 NOT NULL, + component_name VARCHAR(255), + method_name VARCHAR(255), + method_params VARCHAR(255), + view_spel VARCHAR(255), + remark VARCHAR(255), + status CHAR(1) DEFAULT '0', + del_flag CHAR(1) DEFAULT '0', + create_dept int8, + create_by int8, + create_time TIMESTAMP, + update_by int8, + update_time TIMESTAMP, + PRIMARY KEY (id) +); + +COMMENT ON TABLE flow_spel IS '流程spel表达式定义表'; +COMMENT ON COLUMN flow_spel.id IS '主键id'; +COMMENT ON COLUMN flow_spel.component_name IS '组件名称'; +COMMENT ON COLUMN flow_spel.method_name IS '方法名'; +COMMENT ON COLUMN flow_spel.method_params IS '参数'; +COMMENT ON COLUMN flow_spel.view_spel IS '预览spel表达式'; +COMMENT ON COLUMN flow_spel.remark IS '备注'; +COMMENT ON COLUMN flow_spel.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN flow_spel.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_spel.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_spel.create_by IS '创建者'; +COMMENT ON COLUMN flow_spel.create_time IS '创建时间'; +COMMENT ON COLUMN flow_spel.update_by IS '更新者'; +COMMENT ON COLUMN flow_spel.update_time IS '更新时间'; + +INSERT INTO flow_spel VALUES (1762400000000000001, 'spelRuleComponent', 'selectDeptLeaderById', 'initiatorDeptId', '#{@spelRuleComponent.selectDeptLeaderById(#initiatorDeptId)}', '根据部门id获取部门负责人', '0', '0', 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now()); +INSERT INTO flow_spel VALUES (1762400000000000002, NULL, NULL, 'initiator', '${initiator}', '流程发起人', '0', '0', 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now()); + +-- ---------------------------- +-- 流程实例业务扩展表 +-- ---------------------------- +CREATE TABLE flow_instance_biz_ext ( + id int8, + create_dept int8, + create_by int8, + create_time TIMESTAMP, + update_by int8, + update_time TIMESTAMP, + business_code VARCHAR(255), + business_title VARCHAR(1000), + del_flag CHAR(1) DEFAULT '0', + instance_id int8, + business_id VARCHAR(255), + PRIMARY KEY (id) +); + +COMMENT ON TABLE flow_instance_biz_ext IS '流程实例业务扩展表'; +COMMENT ON COLUMN flow_instance_biz_ext.id IS '主键id'; +COMMENT ON COLUMN flow_instance_biz_ext.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_instance_biz_ext.create_by IS '创建者'; +COMMENT ON COLUMN flow_instance_biz_ext.create_time IS '创建时间'; +COMMENT ON COLUMN flow_instance_biz_ext.update_by IS '更新者'; +COMMENT ON COLUMN flow_instance_biz_ext.update_time IS '更新时间'; +COMMENT ON COLUMN flow_instance_biz_ext.business_code IS '业务编码'; +COMMENT ON COLUMN flow_instance_biz_ext.business_title IS '业务标题'; +COMMENT ON COLUMN flow_instance_biz_ext.del_flag IS '删除标志(0代表存在 1代表删除)'; +COMMENT ON COLUMN flow_instance_biz_ext.instance_id IS '流程实例Id'; +COMMENT ON COLUMN flow_instance_biz_ext.business_id IS '业务Id'; + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- +CREATE TABLE test_leave +( + id int8 NOT NULL, + apply_code VARCHAR(50) NOT NULL, + leave_type VARCHAR(255) NOT NULL, + start_date TIMESTAMP NOT NULL, + end_date TIMESTAMP NOT NULL, + leave_days int2 NOT NULL, + remark VARCHAR(255), + status VARCHAR(255), + create_dept int8, + create_by int8, + create_time TIMESTAMP, + update_by int8, + update_time TIMESTAMP, + PRIMARY KEY (id) +); + +COMMENT ON TABLE test_leave IS '请假申请表'; +COMMENT ON COLUMN test_leave.id IS 'id'; +COMMENT ON COLUMN test_leave.apply_code IS '申请编号'; +COMMENT ON COLUMN test_leave.leave_type IS '请假类型'; +COMMENT ON COLUMN test_leave.start_date IS '开始时间'; +COMMENT ON COLUMN test_leave.end_date IS '结束时间'; +COMMENT ON COLUMN test_leave.leave_days IS '请假天数'; +COMMENT ON COLUMN test_leave.remark IS '请假原因'; +COMMENT ON COLUMN test_leave.status IS '状态'; +COMMENT ON COLUMN test_leave.create_dept IS '创建部门'; +COMMENT ON COLUMN test_leave.create_by IS '创建者'; +COMMENT ON COLUMN test_leave.create_time IS '创建时间'; +COMMENT ON COLUMN test_leave.update_by IS '更新者'; +COMMENT ON COLUMN test_leave.update_time IS '更新时间'; + +INSERT INTO sys_menu VALUES (1761400000000011616, '工作流', 0, 6, 'workflow', '', '', 'N', 'Y', 'M', '0', '0', '', 'workflow', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011618, '我的任务', 0, 7, 'task', '', '', 'N', 'Y', 'M', '0', '0', '', 'my-task', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011619, '我的待办', 1761400000000011618, 2, 'taskWaiting', 'workflow/task/taskWaiting', '', 'N', 'N', 'C', '0', '0', '', 'waiting', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011632, '我的已办', 1761400000000011618, 3, 'taskFinish', 'workflow/task/taskFinish', '', 'N', 'N', 'C', '0', '0', '', 'finish', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011633, '我的抄送', 1761400000000011618, 4, 'taskCopyList', 'workflow/task/taskCopyList', '', 'N', 'N', 'C', '0', '0', '', 'my-copy', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011620, '流程定义', 1761400000000011616, 3, 'processDefinition', 'workflow/processDefinition/index', '', 'N', 'N', 'C', '0', '0', 'workflow:definition:list', 'process-definition', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011621, '流程实例', 1761400000000011630, 1, 'processInstance', 'workflow/processInstance/index', '', 'N', 'N', 'C', '0', '0', 'workflow:instance:list', 'tree-table', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011622, '流程分类', 1761400000000011616, 1, 'category', 'workflow/category/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:category:list', 'category', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011629, '我发起的', 1761400000000011618, 1, 'myDocument', 'workflow/task/myDocument', '', 'N', 'N', 'C', '0', '0', 'workflow:instance:currentList', 'guide', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011630, '流程监控', 1761400000000011616, 4, 'processMonitor', '', '', 'N', 'Y', 'M', '0', '0', '', 'monitor', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011631, '待办任务', 1761400000000011630, 2, 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', 'N', 'N', 'C', '0', '0', 'workflow:task:list', 'waiting', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011660, '待办任务修改', 1761400000000011631, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:task:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011700, '流程设计', 1761400000000011616, 5, 'design/index', 'workflow/processDefinition/design', '', 'N', 'N', 'C', '1', '0', 'workflow:leave:edit', '#', '/workflow/processDefinition', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011701, '请假申请', 1761400000000011616, 6, 'leaveEdit/index', 'workflow/leave/leaveEdit', '', 'N', 'N', 'C', '1', '0', 'workflow:leave:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); + +INSERT INTO sys_menu VALUES (1761400000000011623, '流程分类查询', 1761400000000011622, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011624, '流程分类新增', 1761400000000011622, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011625, '流程分类修改', 1761400000000011622, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011626, '流程分类删除', 1761400000000011622, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011627, '流程分类导出', 1761400000000011622, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); + +-- 流程实例管理相关按钮 +INSERT INTO sys_menu VALUES (1761400000000011653, '流程实例查询', 1761400000000011621, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011654, '流程变量查询', 1761400000000011621, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variableQuery', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011655, '流程变量修改', 1761400000000011621, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variable', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011656, '流程实例激活/挂起', 1761400000000011621, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:active', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011657, '流程实例删除', 1761400000000011621, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011658, '流程实例作废', 1761400000000011621, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:invalid', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011659, '流程实例撤销', 1761400000000011621, 7, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:cancel', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); + +-- 流程定义管理相关按钮 +INSERT INTO sys_menu VALUES (1761400000000011644, '流程定义查询', 1761400000000011620, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011645, '流程定义新增', 1761400000000011620, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011646, '流程定义修改', 1761400000000011620, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011647, '流程定义删除', 1761400000000011620, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011648, '流程定义导出', 1761400000000011620, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011649, '流程定义导入', 1761400000000011620, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:import', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011650, '流程定义发布/取消发布', 1761400000000011620, 7, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:publish', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011651, '流程定义复制', 1761400000000011620, 8, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:copy', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011652, '流程定义激活/挂起', 1761400000000011620, 9, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:active', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); + +INSERT INTO sys_menu VALUES (1761400000000011801, '流程表达式', 1761400000000011616, 2, 'spel', 'workflow/spel/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:spel:list', 'input', '', '', 1761000000000000103, 1761100000000000001, now(), 1761100000000000001, now(), '流程达式定义菜单'); +INSERT INTO sys_menu VALUES (1761400000000011802, '流程spel表达式定义查询', 1761400000000011801, 1, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011803, '流程spel表达式定义新增', 1761400000000011801, 2, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011804, '流程spel表达式定义修改', 1761400000000011801, 3, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011805, '流程spel表达式定义删除', 1761400000000011801, 4, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011806, '流程spel表达式定义导出', 1761400000000011801, 5, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); + +INSERT INTO sys_menu VALUES (1761400000000011638, '请假申请', 1761400000000000005, 1, 'leave', 'workflow/leave/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:leave:list', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu VALUES (1761400000000011639, '请假申请查询', 1761400000000011638, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011640, '请假申请新增', 1761400000000011638, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011641, '请假申请修改', 1761400000000011638, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:edit', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011642, '请假申请删除', 1761400000000011638, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011643, '请假申请导出', 1761400000000011638, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (1761500000000000013, '业务状态', 'wf_business_status', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (1761500000000000014, '表单类型', 'wf_form_type', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (1761500000000000015, '任务状态', 'wf_task_status', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (1761600000000000039, 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data VALUES (1761600000000000040, 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (1761600000000000041, 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (1761600000000000042, 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '已完成'); +INSERT INTO sys_dict_data VALUES (1761600000000000043, 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '已作废'); +INSERT INTO sys_dict_data VALUES (1761600000000000044, 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '已退回'); +INSERT INTO sys_dict_data VALUES (1761600000000000045, 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (1761600000000000046, 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data VALUES (1761600000000000047, 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '动态表单'); +INSERT INTO sys_dict_data VALUES (1761600000000000048, 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (1761600000000000049, 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (1761600000000000050, 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (1761600000000000051, 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (1761600000000000052, 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (1761600000000000053, 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (1761600000000000054, 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (1761600000000000055, 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (1761600000000000056, 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (1761600000000000057, 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (1761600000000000058, 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (1761600000000000059, 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '超时'); + diff --git a/script/sql/ry_ai.sql b/script/sql/ry_ai.sql new file mode 100644 index 000000000..2249d115e --- /dev/null +++ b/script/sql/ry_ai.sql @@ -0,0 +1,571 @@ +-- ============================================================ +-- Snail AI MySQL 全量建表脚本(仅 CREATE,无 ALTER) +-- 使用:mysql -u user -p database < ry_ai.sql +-- ============================================================ + + +-- ============================================================ +-- 一、用户与权限 +-- ============================================================ + +-- 1.1 用户表 +CREATE TABLE sai_user +( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + role INT, + totals INT, + username VARCHAR(255), + nickname VARCHAR(128) DEFAULT NULL COMMENT '用户昵称', + email VARCHAR(64), + password VARCHAR(255) NOT NULL, + resource_id BIGINT DEFAULT NULL COMMENT '头像资源ID,关联 sai_resource.id', + create_dt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_username (username) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4; + +-- 1.2 OpenAPI 外部用户映射表 +CREATE TABLE sai_openapi_user +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + app_id VARCHAR(128) NOT NULL COMMENT '关联 sai_app.app_id', + open_id VARCHAR(64) NOT NULL COMMENT '平台分配的唯一标识(UUID)', + platform_user_id BIGINT NOT NULL COMMENT '关联 sai_user.id,注册时自动创建', + external_id VARCHAR(256) DEFAULT NULL COMMENT '外部系统的用户标识(可选,幂等用)', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_app_open (app_id, open_id), + UNIQUE KEY uk_app_external (app_id, external_id), + INDEX idx_open_id (open_id), + INDEX idx_platform_user (platform_user_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci + COMMENT='OpenAPI 外部用户映射表'; + + +-- ============================================================ +-- 二、AI 模型管理 +-- ============================================================ + +-- 2.1 AI 模型提供商表 +CREATE TABLE IF NOT EXISTS sai_model_provider +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + provider_name VARCHAR(255) NOT NULL COMMENT '提供商名称', + provider_key VARCHAR(50) NOT NULL COMMENT '提供商标识符', + description TEXT COMMENT '提供商描述', + icon_url VARCHAR(500) COMMENT 'LOGO图标URL', + is_enabled TINYINT(1) DEFAULT 1 COMMENT '是否启用', + created_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + updated_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + UNIQUE KEY uk_provider_name (provider_name), + UNIQUE KEY uk_provider_key (provider_key) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = 'AI模型提供商表'; + +CREATE INDEX idx_provider_key ON sai_model_provider (provider_key); +CREATE INDEX idx_is_enabled ON sai_model_provider (is_enabled); + +-- 2.2 AI模型配置表 +CREATE TABLE IF NOT EXISTS sai_model_config +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + provider_id BIGINT NOT NULL COMMENT '提供商ID', + model_name VARCHAR(255) NOT NULL COMMENT '模型名称', + model_key VARCHAR(100) NOT NULL COMMENT '模型标识符', + model_type VARCHAR(50) NOT NULL COMMENT '模型类型(CHAT/EMBEDDING/RERANKER/IMAGE/SPEECH)', + adapter_key VARCHAR(100) COMMENT '底层协议适配器标识(openai-compatible/http等)', + description VARCHAR(1000) COMMENT '模型描述', + api_key VARCHAR(1000) COMMENT 'API密钥(加密存储)', + api_endpoint VARCHAR(500) COMMENT 'API端点URL', + config_json TEXT COMMENT '模型参数配置(JSON格式)', + owner_id BIGINT COMMENT '所有者ID(NULL=全局,具体值=用户ID)', + scope VARCHAR(20) NOT NULL DEFAULT 'GLOBAL' COMMENT '作用域(GLOBAL/PERSONAL)', + is_default TINYINT(1) DEFAULT 0 COMMENT '是否为默认模型', + is_enabled TINYINT(1) DEFAULT 1 COMMENT '是否启用', + created_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + updated_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + KEY fk_provider_id (provider_id) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = 'AI模型配置表'; + +CREATE INDEX idx_provider_model_type ON sai_model_config (provider_id, model_type); +CREATE INDEX idx_model_type_enabled ON sai_model_config (model_type, is_enabled); +CREATE INDEX idx_owner_id ON sai_model_config (owner_id); +CREATE INDEX idx_is_default ON sai_model_config (is_default); +CREATE INDEX idx_scope ON sai_model_config (scope); +CREATE INDEX idx_model_key ON sai_model_config (model_key); + +-- 2.3 模型使用统计表 +CREATE TABLE IF NOT EXISTS sai_model_usage_stat +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + model_id BIGINT NOT NULL COMMENT '模型ID', + user_id BIGINT NOT NULL COMMENT '用户ID', + total_calls BIGINT DEFAULT 0 COMMENT '总调用次数', + success_calls BIGINT DEFAULT 0 COMMENT '成功调用次数', + failed_calls BIGINT DEFAULT 0 COMMENT '失败调用次数', + total_tokens_used BIGINT DEFAULT 0 COMMENT '总Token使用量', + total_cost DECIMAL(18, 8) DEFAULT 0 COMMENT '总费用', + avg_response_time BIGINT DEFAULT 0 COMMENT '平均响应时间(毫秒)', + last_used_dt TIMESTAMP NULL DEFAULT NULL COMMENT '最后使用时间', + created_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + updated_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + UNIQUE KEY unique_model_user (model_id, user_id), + KEY fk_stat_model_id (model_id) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '模型使用统计表'; + +CREATE INDEX idx_model_id ON sai_model_usage_stat (model_id); +CREATE INDEX idx_user_id ON sai_model_usage_stat (user_id); +CREATE INDEX idx_last_used_dt ON sai_model_usage_stat (last_used_dt); + + +-- ============================================================ +-- 三、智能体(Agent) +-- ============================================================ + +-- 3.1 智能体主表 +CREATE TABLE IF NOT EXISTS sai_agent +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL COMMENT '智能体名称', + description TEXT COMMENT '智能体描述', + avatar VARCHAR(512) COMMENT '头像URL', + instruction TEXT COMMENT '系统指令(System Prompt)', + greeting TEXT COMMENT '欢迎语', + preset_questions TEXT COMMENT '预设问题列表(JSON数组字符串)', + chat_model_id BIGINT COMMENT '关联的对话模型ID', + memory_enabled TINYINT(1) DEFAULT 0 COMMENT '是否启用记忆库', + mcp_enabled TINYINT(1) DEFAULT 0 COMMENT '是否启用MCP', + skill_enabled TINYINT(1) DEFAULT 0 COMMENT '是否启用Skill', + web_search_enabled TINYINT(1) DEFAULT 0 COMMENT '是否启用联网搜索', + rag_enabled TINYINT(1) DEFAULT 0 COMMENT '是否启用RAG', + rag_ids VARCHAR(64) NULL COMMENT '绑定的RAG ID列表,逗号分隔,最多5个', + rag_call_mode TINYINT DEFAULT 1 COMMENT 'RAG调用方式: 1=智能调用 2=强制调用', + short_term_memory_size INT DEFAULT 20 COMMENT '短期记忆滑动窗口保留条数', + creator_id BIGINT COMMENT '创建者用户ID', + is_featured TINYINT(1) DEFAULT 0 COMMENT '是否精选', + view_count INT DEFAULT 0 COMMENT '浏览次数', + status TINYINT DEFAULT 1 COMMENT '状态: 1-活跃 2-非活跃 3-已废弃 4-已禁用', + config TEXT COMMENT '扩展配置(预留)', + app_id VARCHAR(128) NULL COMMENT '关联应用ID(NULL=本地执行)', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '智能体表'; + +CREATE INDEX idx_agent_creator ON sai_agent (creator_id); +CREATE INDEX idx_agent_featured ON sai_agent (is_featured); + +-- 3.2 智能体对话表 +CREATE TABLE IF NOT EXISTS sai_agent_conversation +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + agent_id BIGINT NOT NULL COMMENT '智能体ID', + user_id BIGINT NOT NULL COMMENT '用户ID', + conversation_id VARCHAR(64) NOT NULL COMMENT '对话ID(UUID)', + title VARCHAR(255) COMMENT '对话标题', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_conv_id (conversation_id) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '智能体对话表'; + +CREATE INDEX idx_agent_conv_agent ON sai_agent_conversation (agent_id); +CREATE INDEX idx_agent_conv_user ON sai_agent_conversation (user_id); + +-- 3.3 智能体对话消息记录表 +CREATE TABLE IF NOT EXISTS sai_agent_conversation_record +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + agent_id BIGINT NOT NULL COMMENT '智能体ID', + conversation_id VARCHAR(64) NOT NULL COMMENT '对话ID', + user_id BIGINT NOT NULL COMMENT '用户ID', + role VARCHAR(16) DEFAULT 'user' COMMENT 'user/assistant', + content TEXT COMMENT '消息内容', + thinking TEXT COMMENT '思考过程(仅assistant)', + metadata LONGTEXT DEFAULT NULL COMMENT '消息扩展元数据JSON', + status INT DEFAULT 1 COMMENT '1=成功,2=失败,3=进行中', + input_tokens INT DEFAULT 0 COMMENT '输入Token数(prompt)', + output_tokens INT DEFAULT 0 COMMENT '输出Token数(completion)', + cache_tokens INT DEFAULT 0 COMMENT '缓存命中Token数', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '智能体对话消息记录'; + +CREATE INDEX idx_agent_rec_conv ON sai_agent_conversation_record (conversation_id); + +-- 3.4 智能体使用统计表 +CREATE TABLE IF NOT EXISTS sai_agent_usage_stat +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + agent_id BIGINT NOT NULL COMMENT '智能体ID', + user_id BIGINT NOT NULL COMMENT '用户ID', + message_count INT DEFAULT 0 COMMENT '消息条数', + conversation_count INT DEFAULT 0 COMMENT '对话轮次', + stat_date DATE NOT NULL COMMENT '统计日期', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_agent_user_date (agent_id, user_id, stat_date) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '智能体使用统计'; + +CREATE INDEX idx_usage_agent ON sai_agent_usage_stat (agent_id); +CREATE INDEX idx_usage_date ON sai_agent_usage_stat (stat_date); + +-- 3.5 用户订阅的智能体(多对多) +CREATE TABLE IF NOT EXISTS sai_user_agent +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT NOT NULL COMMENT '用户ID', + agent_id BIGINT NOT NULL COMMENT '智能体ID', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY uk_user_agent (user_id, agent_id) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '用户订阅的智能体'; + +CREATE INDEX idx_user_agent_user ON sai_user_agent (user_id); + + +-- ============================================================ +-- 四、RAG 知识库 +-- ============================================================ + +-- 4.1 知识库主表 +CREATE TABLE sai_rag +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description TEXT, + icon VARCHAR(512), + embedding_model_id BIGINT(128) NOT NULL, + dimension_of_vector_model INT NOT NULL COMMENT '向量维度', + rerank_model_id BIGINT(128), + search_engine_instance_id BIGINT(128), + vector_store_instance_id BIGINT(128), + search_engine_enable TINYINT(1) DEFAULT 0, + delimiter VARCHAR(32) DEFAULT '\n\n', + rag_enhancement TEXT, + config TEXT DEFAULT NULL COMMENT 'RAG检索和问答的页面配置参数', + dedup_strategy TINYINT(1) NOT NULL DEFAULT 2 COMMENT '去重策略: 0=NONE 1=BY_NAME 2=BY_CONTENT 3=BY_NAME_OR_CONTENT', + dedup_action TINYINT(1) NOT NULL DEFAULT 0 COMMENT '冲突动作: 0=REJECT 1=SKIP 2=OVERWRITE', + upload_confirm TINYINT(1) NOT NULL DEFAULT 1 COMMENT '上传前二次确认: 0-关 1-开', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- 4.2 RAG 文档表 +CREATE TABLE sai_rag_document +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + rag_id BIGINT NOT NULL, + name VARCHAR(255), + file_type VARCHAR(32), + source_type VARCHAR(32), + source_path VARCHAR(1024), + storage_path VARCHAR(1024), + storage_type VARCHAR(32) DEFAULT 'LOCAL', + file_size BIGINT DEFAULT 0, + content TEXT, + status TINYINT(1) DEFAULT 0 COMMENT '状态: 0-待处理 1-解析中 2-处理中 3-处理完成 4-处理失败', + error_msg TEXT, + chunk_count INT DEFAULT 0, + page_count INT DEFAULT 0 COMMENT 'Docling parse page count', + element_count INT DEFAULT 0 COMMENT 'Docling parse element count', + table_count INT DEFAULT 0 COMMENT 'Docling parse table count', + image_count INT DEFAULT 0 COMMENT 'Docling parse image count', + parse_time INT DEFAULT 0 COMMENT 'Parse duration in milliseconds', + md_content LONGTEXT DEFAULT NULL COMMENT 'Docling markdown content', + doc_metadata LONGTEXT DEFAULT NULL COMMENT 'Docling document metadata JSON', + content_hash VARCHAR(64) DEFAULT NULL COMMENT '文件内容SHA-256哈希,用于去重', + resource_id BIGINT DEFAULT NULL COMMENT '关联资源库 sai_resource.id', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +CREATE INDEX idx_rag_doc_rag ON sai_rag_document (rag_id); +CREATE INDEX idx_rag_content_hash ON sai_rag_document (rag_id, content_hash); +CREATE INDEX idx_rag_name ON sai_rag_document (rag_id, name); +CREATE INDEX idx_rag_doc_resource ON sai_rag_document (resource_id); + +CREATE TABLE sai_rag_document_image +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + rag_id BIGINT NOT NULL, + document_id BIGINT NOT NULL, + chunk_id BIGINT DEFAULT NULL, + resource_id BIGINT DEFAULT NULL, + image_index INT, + image_url VARCHAR(1024), + caption TEXT, + figure_no VARCHAR(64), + figure_title VARCHAR(512), + section_title VARCHAR(512), + source_page INT, + document_name VARCHAR(255), + ocr_text TEXT, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +CREATE INDEX idx_rag_doc_image_rag ON sai_rag_document_image (rag_id); +CREATE INDEX idx_rag_doc_image_document ON sai_rag_document_image (document_id); +CREATE INDEX idx_rag_doc_image_chunk ON sai_rag_document_image (chunk_id); +CREATE INDEX idx_rag_doc_image_resource ON sai_rag_document_image (resource_id); + +-- 4.3 RAG 分块表 +CREATE TABLE sai_rag_chunk +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + rag_id BIGINT NOT NULL, + document_id BIGINT NOT NULL, + paragraph_index INT, + chunk_index INT, + content TEXT, + token_count INT, + vector_id VARCHAR(128), + content_hash VARCHAR(64) DEFAULT NULL COMMENT 'chunk内容SHA-256,用于向量去重', + source_type VARCHAR(20) NOT NULL DEFAULT 'TEXT' COMMENT 'chunk来源类型:TEXT文本、IMAGE图片', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +CREATE INDEX idx_rag_chunk_rag ON sai_rag_chunk (rag_id); +CREATE INDEX idx_rag_chunk_document ON sai_rag_chunk (document_id); +CREATE INDEX idx_chunk_rag_hash ON sai_rag_chunk (rag_id, content_hash); +CREATE INDEX idx_chunk_rag_source_type ON sai_rag_chunk (rag_id, source_type); + + +-- ============================================================ +-- 五、MCP 服务管理 +-- ============================================================ + +-- 5.1 MCP 服务配置表 +CREATE TABLE IF NOT EXISTS sai_mcp_server +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL COMMENT 'MCP服务名称', + description TEXT COMMENT 'MCP服务描述', + transport_type TINYINT(1) DEFAULT 1 COMMENT '传输类型: 1-SSE 2-Streamable HTTP 3-Stdio', + base_uri VARCHAR(1024) COMMENT '服务基础地址(SSE/Streamable HTTP时使用)', + endpoint VARCHAR(1024) COMMENT '端点路径(SSE/Streamable HTTP时可选)', + command VARCHAR(1024) COMMENT 'Stdio命令(Stdio时必填)', + args TEXT COMMENT 'Stdio命令参数(JSON数组)', + env_vars TEXT COMMENT 'Stdio环境变量(JSON对象)', + timeout BIGINT DEFAULT 60000 COMMENT '超时时间(毫秒)', + headers TEXT COMMENT '请求头(JSON对象)', + last_connect_dt TIMESTAMP NULL COMMENT '最后连接时间', + creator_id BIGINT COMMENT '创建者用户ID', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = 'MCP服务配置表'; + +CREATE INDEX idx_mcp_server_creator ON sai_mcp_server (creator_id); + +-- 5.2 智能体与MCP服务关联表(多对多) +CREATE TABLE IF NOT EXISTS sai_agent_mcp_server +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + agent_id BIGINT NOT NULL COMMENT '智能体ID', + mcp_server_id BIGINT NOT NULL COMMENT 'MCP服务ID', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY uk_agent_mcp (agent_id, mcp_server_id) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '智能体MCP服务关联表'; + +CREATE INDEX idx_agent_mcp_agent ON sai_agent_mcp_server (agent_id); +CREATE INDEX idx_agent_mcp_server ON sai_agent_mcp_server (mcp_server_id); + + +-- ============================================================ +-- 六、Skill 技能包管理 +-- ============================================================ + +-- 6.1 Skill 技能包表 +CREATE TABLE IF NOT EXISTS sai_skill +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL COMMENT 'Skill名称(从SKILL.md解析)', + description TEXT COMMENT 'Skill描述(从SKILL.md解析)', + file_name VARCHAR(255) COMMENT '上传的zip文件名', + file_path VARCHAR(1024) COMMENT '解压后存储路径', + file_size BIGINT DEFAULT 0 COMMENT '文件大小(字节)', + skill_content LONGTEXT COMMENT 'SKILL.md正文内容(去除frontmatter)', + storage_path VARCHAR(500) DEFAULT NULL COMMENT '对象存储相对路径前缀(如 skills/123/)', + version BIGINT DEFAULT 0 COMMENT '版本号,文件变更时自增,用于缓存一致性校验', + has_files TINYINT(1) DEFAULT 0 COMMENT '是否包含支撑文件(0=仅SKILL.md,1=有scripts/references等)', + creator_id BIGINT COMMENT '创建者用户ID', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = 'Skill技能包表'; + +CREATE INDEX idx_skill_creator ON sai_skill (creator_id); + +-- 6.2 Skill 支撑文件内容表 +CREATE TABLE IF NOT EXISTS sai_skill_file +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + skill_id BIGINT NOT NULL COMMENT 'Skill ID', + file_path VARCHAR(255) NOT NULL COMMENT '文件相对路径', + content LONGTEXT NOT NULL COMMENT '文件内容', + file_size INT NOT NULL COMMENT '文件大小(字节)', + encoding VARCHAR(50) DEFAULT 'utf-8' COMMENT '编码方式', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + UNIQUE KEY uk_skill_path (skill_id, file_path) COMMENT '同一Skill不能有重复的文件路径', + KEY idx_skill_id (skill_id) COMMENT '技能ID索引' + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = 'Skill支撑文件内容表'; + +-- 6.3 智能体与Skill关联表(多对多) +CREATE TABLE IF NOT EXISTS sai_agent_skill +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + agent_id BIGINT NOT NULL COMMENT '智能体ID', + skill_id BIGINT NOT NULL COMMENT 'Skill ID', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY uk_agent_skill (agent_id, skill_id) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '智能体Skill关联表'; + +CREATE INDEX idx_agent_skill_agent ON sai_agent_skill (agent_id); +CREATE INDEX idx_agent_skill_skill ON sai_agent_skill (skill_id); + + +-- ============================================================ +-- 七、客户端应用与节点 +-- ============================================================ + +-- 7.1 客户端应用 +CREATE TABLE IF NOT EXISTS sai_app +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + app_id VARCHAR(128) NOT NULL COMMENT '应用唯一标识', + app_name VARCHAR(255) NOT NULL COMMENT '应用名称', + description VARCHAR(512) COMMENT '应用描述', + token VARCHAR(128) NOT NULL COMMENT '通信认证令牌', + route_strategy VARCHAR(32) DEFAULT 'LEAST_LOAD' COMMENT '路由策略', + status TINYINT(1) DEFAULT 1 COMMENT '1=启用, 0=停用', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_app_id (app_id) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '客户端应用'; + +-- 7.2 AI客户端实例节点 +CREATE TABLE IF NOT EXISTS sai_client_node +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + app_id VARCHAR(128) NOT NULL COMMENT '所属应用ID', + host_id VARCHAR(128) NOT NULL COMMENT '客户端实例唯一标识', + host_ip VARCHAR(64) NOT NULL COMMENT '客户端IP', + grpc_port INT NOT NULL COMMENT '客户端gRPC端口', + max_concurrent INT DEFAULT 10 COMMENT '最大并发对话数', + active_chats INT DEFAULT 0 COMMENT '当前活跃对话数', + supported_providers TEXT COMMENT '支持的模型提供商(JSON数组)', + labels TEXT COMMENT '路由标签', + expire_dt DATETIME NOT NULL COMMENT '过期时间(心跳更新)', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_client_node (app_id, host_id), + INDEX idx_app_expire (app_id, expire_dt) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = 'AI客户端实例节点'; + + +-- ============================================================ +-- 八、存储与资源 +-- ============================================================ + +-- 8.1 存储实例 +CREATE TABLE IF NOT EXISTS sai_store_instance +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(128) NOT NULL COMMENT '实例名称', + category TINYINT(1) NOT NULL COMMENT '分类: 1-向量库 2-搜索引擎', + type TINYINT(1) NOT NULL COMMENT '类型: 1-PG_VECTOR 2-MILVUS 3-ELASTICSEARCH 4-PG_FULLTEXT', + config TEXT DEFAULT NULL COMMENT '连接参数 JSON', + status TINYINT(1) DEFAULT 1 COMMENT '状态: 0-停用 1-启用', + is_default TINYINT(1) DEFAULT 0 COMMENT '是否为该 category 下默认实例', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '存储实例'; + +CREATE INDEX idx_store_instance_category ON sai_store_instance (category); +CREATE INDEX idx_store_instance_type ON sai_store_instance (type); + +-- 8.2 通用资源存储 +CREATE TABLE IF NOT EXISTS sai_resource +( + id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + storage_key VARCHAR(512) NOT NULL COMMENT '存储键(相对路径或对象Key)', + original_name VARCHAR(255) NOT NULL COMMENT '原始文件名', + file_size BIGINT DEFAULT 0 COMMENT '文件大小(bytes)', + mime_type VARCHAR(128) COMMENT 'MIME类型', + storage_type VARCHAR(32) NOT NULL DEFAULT 'LOCAL' COMMENT '存储类型: LOCAL/MINIO', + access_url VARCHAR(1024) COMMENT '访问URL', + biz_type VARCHAR(64) NOT NULL DEFAULT 'GENERAL' COMMENT '业务类型: AVATAR/ATTACHMENT/DOCUMENT/GENERAL', + biz_id BIGINT COMMENT '关联业务ID', + creator_id BIGINT COMMENT '上传者ID', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_storage_key (storage_key), + INDEX idx_biz (biz_type, biz_id), + INDEX idx_creator (creator_id) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_unicode_ci COMMENT = '通用资源存储'; + + +-- ============================================================ +-- 九、初始化数据 +-- ============================================================ + +-- 默认管理员:admin / admin123 +INSERT INTO sai_user VALUES (1, 2, NULL, 'admin', 'admin', '', 'pbkdf2$120000$c25haWwtYWktYWRtaW4tMQ==$kakglT/wYKOgv/77Ah1stie58d/JbY2nGgq5DwgUBw4=', NULL, NOW(), NOW()); + +-- 插入常见的AI提供商 +INSERT INTO sai_model_provider (provider_name, provider_key, description, is_enabled) +VALUES ('OpenAI', 'openai', 'OpenAI官方模型 (GPT-4, GPT-3.5等)', 1), + ('Claude', 'claude', 'Anthropic Claude模型', 1), + ('Ollama', 'ollama', '本地开源模型 (Llama, Mistral等)', 1), + ('Google Gemini', 'gemini', 'Google Gemini模型', 1), + ('阿里云百炼', 'qwen', '阿里云百炼 OpenAI 兼容模型 (Qwen等)', 1), + ('DeepSeek', 'deepseek', 'DeepSeek OpenAI 兼容模型', 1), + ('智谱AI', 'zhipu', '智谱AI OpenAI 兼容模型 (GLM等)', 1); + +INSERT INTO sai_model_config VALUES (1, 5, 'glm-5.1', 'glm-5.1', 'CHAT', 'openai-compatible', '', '', 'https://dashscope.aliyuncs.com/compatible-mode/v1', '{\"frequencyPenalty\":0.0,\"maxTokens\":20000,\"presencePenalty\":0.0,\"stopSequences\":[],\"stream\":true,\"temperature\":0.7,\"timeoutMs\":300000,\"topK\":1,\"topP\":1.0}', NULL, 'GLOBAL', 1, 1, NOW(), NOW()); + +INSERT INTO sai_agent VALUES (1, '智测先锋专家', '智测先锋专家是一款专注于软件测试与质量保障领域的智能助手。它能够高效生成覆盖全面的测试用例,深度分析Bug根因并提供修复建议,支持编写自动化测试脚本,以及解读复杂的测试报告。适用于软件开发周期的各个QA阶段,包括单元测试、接口测试、UI自动化及回归测试规划。其核心特点是逻辑严密、注重边界与异常场景,帮助团队大幅提升测试效率与软件质量。', NULL, '你是一位资深的软件测试与质量保障(QA)专家,名为“智测先锋专家”。\\n\\n【角色定位】你是开发团队的最后一道防线,致力于保障软件产品的卓越质量。\\n\\n【专业领域】精通黑盒与白盒测试、自动化测试框架(如Selenium、Pytest)、接口与性能测试、安全测试及CI/CD持续集成流程。\\n\\n【回答风格】逻辑严密、条理清晰、客观专业。善于使用结构化排版(如Markdown列表、代码块、表格)呈现测试用例和步骤,语言精炼,直击痛点。\\n\\n【行为指南】\\n1. 生成测试用例:必须覆盖正常流、异常流、边界值和兼容性等方面,确保测试的全面性与无遗漏。\\n2. 分析Bug根因:从代码逻辑、数据状态、环境配置等多维度推导,不仅给出修复建议,更要提供预防性的测试策略。\\n3. 编写自动化脚本:确保代码规范、包含必要注释与断言(Assert),并明确说明运行依赖与环境配置。\\n4. 需求澄清:若用户提问模糊,主动追问业务背景、技术栈等关键细节,拒绝给出宽泛且无实操价值的答案。\\n5. 风险预警:始终秉持质量第一理念,在解答中适时提示潜在的测试盲区与质量风险。', '你好!我是智测先锋专家,你的专属软件测试与质量保障顾问。无论是编写用例还是排查Bug,我都能为你提供专业支持!', '[\"如何为一个用户登录接口设计全面的测试用例?\",\"帮我分析这个空指针异常Bug的可能根因及修复建议。\",\"请提供一段Python的Pytest接口自动化测试脚本示例。\",\"怎样制定一个高效的回归测试策略?\"]', 2, 0, 0, 0, 0, 0, NULL, 1, 20, 1, 0, 1, 1, NULL, '1', NOW(), NOW()); + +INSERT INTO sai_app VALUES (1, '1', '测试', '', 'SAI_566a6bfbc26e4998b4841cc927d50c5d', 'LEAST_LOAD', 1, NOW(), NOW()); + +INSERT INTO sai_openapi_user VALUES (1, '1', '46ed53c6a20044c7bbd870848e80f92f', 1, '1', NOW(), NOW()); diff --git a/script/sql/ry_job.sql b/script/sql/ry_job.sql new file mode 100644 index 000000000..e7b627f49 --- /dev/null +++ b/script/sql/ry_job.sql @@ -0,0 +1,539 @@ +SET NAMES utf8mb4; + +CREATE TABLE `sj_namespace` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(64) NOT NULL COMMENT '名称', + `unique_id` varchar(64) NOT NULL COMMENT '唯一id', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_name` (`name`), + UNIQUE KEY `uk_unique_id` (`unique_id`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='命名空间'; + +INSERT INTO `sj_namespace` VALUES (1, 'Development', 'dev', '', 0, now(), now()); +INSERT INTO `sj_namespace` VALUES (2, 'Production', 'prod', '', 0, now(), now()); + +CREATE TABLE `sj_group_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL DEFAULT '' COMMENT '组名称', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '组描述', + `token` varchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' COMMENT 'token', + `group_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '组状态 0、未启用 1、启用', + `version` int(11) NOT NULL COMMENT '版本号', + `group_partition` int(11) NOT NULL COMMENT '分区', + `id_generator_mode` tinyint(4) NOT NULL DEFAULT 1 COMMENT '唯一id生成模式 默认号段模式', + `init_scene` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否初始化场景 0:否 1:是', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='组配置'; + +INSERT INTO `sj_group_config` VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, now(), now()); +INSERT INTO `sj_group_config` VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, now(), now()); + +CREATE TABLE `sj_notify_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `notify_name` varchar(64) NOT NULL DEFAULT '' COMMENT '通知名称', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务', + `notify_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知状态 0、未启用 1、启用', + `recipient_ids` varchar(128) NOT NULL COMMENT '接收人id列表', + `notify_threshold` int(11) NOT NULL DEFAULT 0 COMMENT '通知阈值', + `notify_scene` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知场景', + `rate_limiter_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '限流状态 0、未启用 1、启用', + `rate_limiter_threshold` int(11) NOT NULL DEFAULT 0 COMMENT '每秒限流阈值', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='通知配置'; + +CREATE TABLE `sj_notify_recipient` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `recipient_name` varchar(64) NOT NULL COMMENT '接收人名称', + `notify_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook', + `notify_attribute` varchar(512) NOT NULL COMMENT '配置属性', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id` (`namespace_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='告警通知接收人'; + +CREATE TABLE `sj_retry_dead_letter` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `group_id` bigint(20) NOT NULL COMMENT '组Id', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `scene_id` bigint(20) NOT NULL COMMENT '场景ID', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + -- jackson 兼容历史数据 预计1.8.0默认改为fury + `serializer_name` varchar(32) NOT NULL DEFAULT 'jackson' COMMENT '执行方法参数序列化器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='死信队列表'; + +CREATE TABLE `sj_retry` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `group_id` bigint(20) NOT NULL COMMENT '组Id', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `scene_id` bigint(20) NOT NULL COMMENT '场景ID', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + -- jackson 兼容历史数据 预计1.8.0默认改为fury + `serializer_name` varchar(32) NOT NULL DEFAULT 'jackson' COMMENT '执行方法参数序列化器名称', + `next_trigger_at` bigint(13) NOT NULL COMMENT '下次触发时间', + `retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '重试次数', + `retry_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '重试状态 0、重试中 1、成功 2、最大重试次数', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `parent_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '父节点id', + `deleted` bigint(20) NOT NULL DEFAULT 0 COMMENT '逻辑删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_retry_status_bucket_index` (`retry_status`, `bucket_index`), + KEY `idx_parent_id` (`parent_id`), + KEY `idx_create_dt` (`create_dt`), + UNIQUE KEY `uk_scene_tasktype_idempotentid_deleted` (`scene_id`, `task_type`, `idempotent_id`, `deleted`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='重试信息表'; + +CREATE TABLE `sj_retry_task` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `retry_id` bigint(20) NOT NULL COMMENT '重试信息Id', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `task_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '重试状态', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据', + `operation_reason` tinyint(4) NOT NULL DEFAULT 0 COMMENT '操作原因', + `client_info` varchar(128) DEFAULT NULL COMMENT '客户端地址 clientId#ip:port', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `task_status` (`task_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_retry_id` (`retry_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='重试任务表'; + +CREATE TABLE `sj_retry_task_log_message` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `retry_id` bigint(20) NOT NULL COMMENT '重试信息Id', + `retry_task_id` bigint(20) NOT NULL COMMENT '重试任务Id', + `message` longtext NOT NULL COMMENT '异常信息', + `log_num` int(11) NOT NULL DEFAULT 1 COMMENT '日志数量', + `real_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上报时间', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_retry_task_id` (`namespace_id`, `group_name`, `retry_task_id`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务调度日志信息记录表'; + +CREATE TABLE `sj_retry_scene_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '组状态 0、未启用 1、启用', + `max_retry_count` int(11) NOT NULL DEFAULT 5 COMMENT '最大重试次数', + `back_off` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、默认等级 2、固定间隔时间 3、CRON 表达式', + `trigger_interval` varchar(16) NOT NULL DEFAULT '' COMMENT '间隔时长', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `deadline_request` bigint(20) unsigned NOT NULL DEFAULT 60000 COMMENT 'Deadline Request 调用链超时 单位毫秒', + `executor_timeout` int(11) unsigned NOT NULL DEFAULT 5 COMMENT '任务执行超时时间,单位秒', + `route_key` tinyint(4) NOT NULL DEFAULT 4 COMMENT '路由策略', + `block_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `cb_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '回调状态 0、不开启 1、开启', + `cb_trigger_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、默认等级 2、固定间隔时间 3、CRON 表达式', + `cb_max_count` int(11) NOT NULL DEFAULT 16 COMMENT '回调的最大执行次数', + `cb_trigger_interval` varchar(16) NOT NULL DEFAULT '' COMMENT '回调的最大执行次数', + `owner_id` bigint(20) NULL DEFAULT NULL COMMENT '负责人id', + `labels` varchar(512) NULL DEFAULT '' COMMENT '标签', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='场景配置'; + +CREATE TABLE `sj_server_node` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `host_id` varchar(64) NOT NULL COMMENT '主机id', + `host_ip` varchar(64) NOT NULL COMMENT '机器ip', + `host_port` int(16) NOT NULL COMMENT '机器端口', + `expire_at` datetime NOT NULL COMMENT '过期时间', + `node_type` tinyint(4) NOT NULL COMMENT '节点类型 1、客户端 2、是服务端', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `labels` varchar(512) NULL DEFAULT '' COMMENT '标签', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_expire_at_node_type` (`expire_at`, `node_type`), + UNIQUE KEY `uk_host_id_host_ip` (`host_id`, `host_ip`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='服务器节点'; + +CREATE TABLE `sj_distributed_lock` +( + `name` varchar(64) NOT NULL COMMENT '锁名称', + `lock_until` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '锁定时长', + `locked_at` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '锁定时间', + `locked_by` varchar(255) NOT NULL COMMENT '锁定者', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='锁定表'; + +CREATE TABLE `sj_system_user` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `username` varchar(64) NOT NULL COMMENT '账号', + `password` varchar(128) NOT NULL COMMENT '密码', + `role` tinyint(4) NOT NULL DEFAULT 0 COMMENT '角色:1-普通用户、2-管理员', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_username` (`username`) USING BTREE +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户表'; + +-- pwd: admin +INSERT INTO `sj_system_user` (username, password, role) +VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2); + +CREATE TABLE `sj_system_user_permission` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `system_user_id` bigint(20) NOT NULL COMMENT '系统用户id', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name_system_user_id` (`namespace_id`, `group_name`, `system_user_id`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户权限表'; + +-- 分布式调度DDL +CREATE TABLE `sj_job` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `biz_id` varchar(64) NOT NULL COMMENT '业务ID', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_name` varchar(64) NOT NULL COMMENT '名称', + `args_str` text DEFAULT NULL COMMENT '执行方法参数', + `args_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '参数类型 ', + `next_trigger_at` bigint(13) NOT NULL COMMENT '下次触发时间', + `job_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务状态 0、关闭、1、开启', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、集群 2、广播 3、切片', + `route_key` tinyint(4) NOT NULL DEFAULT 4 COMMENT '路由策略', + `executor_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '执行器类型', + `executor_info` varchar(255) DEFAULT NULL COMMENT '执行器名称', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `block_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行 4、恢复', + `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒', + `max_retry_times` int(11) NOT NULL DEFAULT 0 COMMENT '最大重试次数', + `parallel_num` int(11) NOT NULL DEFAULT 1 COMMENT '并行数', + `retry_interval` int(11) NOT NULL DEFAULT 0 COMMENT '重试间隔(s)', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `resident` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否是常驻任务', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `owner_id` bigint(20) NULL DEFAULT NULL COMMENT '负责人id', + `labels` varchar(512) NULL DEFAULT '' COMMENT '标签', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_job_status_bucket_index` (`job_status`, `bucket_index`), + KEY `idx_create_dt` (`create_dt`), + UNIQUE KEY `uk_sj_job_01` (`namespace_id`, `biz_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务信息'; + +INSERT INTO `sj_job` VALUES (1, 'dev', 'demo-job', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1, '','', '', 0 , now(), now()); + +CREATE TABLE `sj_job_log_message` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '任务批次id', + `task_id` bigint(20) NOT NULL COMMENT '调度任务id', + `message` longtext NOT NULL COMMENT '调度信息', + `log_num` int(11) NOT NULL DEFAULT 1 COMMENT '日志数量', + `real_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上报时间', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_task_batch_id_task_id` (`task_batch_id`, `task_id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='调度日志'; + +CREATE TABLE `sj_job_task` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '调度任务id', + `parent_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '父执行器id', + `task_status` tinyint NOT NULL DEFAULT 0 COMMENT '执行的状态 0、失败 1、成功', + `retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '重试次数', + `mr_stage` tinyint DEFAULT NULL COMMENT '动态分片所处阶段 1:map 2:reduce 3:mergeReduce', + `leaf` tinyint NOT NULL DEFAULT '1' COMMENT '叶子节点', + `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '任务名称', + `client_info` varchar(128) DEFAULT NULL COMMENT '客户端地址 clientId#ip:port', + `wf_context` text DEFAULT NULL COMMENT '工作流全局上下文', + `result_message` text NOT NULL COMMENT '执行结果', + `args_str` text DEFAULT NULL COMMENT '执行方法参数', + `args_type` tinyint NOT NULL DEFAULT 1 COMMENT '参数类型 ', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_task_batch_id_task_status` (`task_batch_id`, `task_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务实例'; + +CREATE TABLE `sj_job_task_batch` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务id', + `workflow_node_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流节点id', + `parent_workflow_node_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流任务父批次id', + `workflow_task_batch_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流任务批次id', + `task_batch_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT 0 COMMENT '操作原因', + `execution_at` bigint(13) NOT NULL DEFAULT 0 COMMENT '任务执行时间', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务', + `parent_id` varchar(64) NOT NULL DEFAULT '' COMMENT '父节点', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_job_id_task_batch_status` (`job_id`, `task_batch_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_workflow_task_batch_id_workflow_node_id` (`workflow_task_batch_id`, `workflow_node_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务批次'; + +CREATE TABLE `sj_job_summary` +( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', + `business_id` bigint NOT NULL COMMENT '业务id (job_id或workflow_id)', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务', + `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', + `success_num` int NOT NULL DEFAULT 0 COMMENT '执行成功-日志数量', + `fail_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `fail_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `stop_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `stop_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `cancel_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `cancel_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_business_id` (`namespace_id`, `group_name`, business_id), + UNIQUE KEY `uk_trigger_at_system_task_type_business_id` (`trigger_at`, `system_task_type`, `business_id`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Job'; + +CREATE TABLE `sj_retry_summary` +( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', + `scene_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '场景名称', + `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', + `running_num` int NOT NULL DEFAULT 0 COMMENT '重试中-日志数量', + `finish_num` int NOT NULL DEFAULT 0 COMMENT '重试完成-日志数量', + `max_count_num` int NOT NULL DEFAULT 0 COMMENT '重试到达最大次数-日志数量', + `suspend_num` int NOT NULL DEFAULT 0 COMMENT '暂停重试-日志数量', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_trigger_at` (`trigger_at`), + UNIQUE KEY `uk_scene_name_trigger_at` (`namespace_id`, `group_name`, `scene_name`, `trigger_at`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Retry'; + +CREATE TABLE `sj_workflow` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `workflow_name` varchar(64) NOT NULL COMMENT '工作流名称', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `biz_id` varchar(64) NOT NULL COMMENT '业务ID', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `workflow_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '工作流状态 0、关闭、1、开启', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `next_trigger_at` bigint NOT NULL COMMENT '下次触发时间', + `block_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `flow_info` text DEFAULT NULL COMMENT '流程信息', + `wf_context` text DEFAULT NULL COMMENT '上下文', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `version` int(11) NOT NULL COMMENT '版本号', + `owner_id` bigint(20) NULL DEFAULT NULL COMMENT '负责人id', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + UNIQUE KEY `uk_sj_workflow_01` (`namespace_id`, `biz_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流'; + +CREATE TABLE `sj_workflow_node` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `node_name` varchar(64) NOT NULL COMMENT '节点名称', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流ID', + `node_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、任务节点 2、条件节点', + `expression_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '1、SpEl、2、Aviator 3、QL', + `fail_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '失败策略 1、跳过 2、阻塞', + `workflow_node_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '工作流节点状态 0、关闭、1、开启', + `priority_level` int(11) NOT NULL DEFAULT 1 COMMENT '优先级', + `node_info` text DEFAULT NULL COMMENT '节点信息 ', + `version` int(11) NOT NULL COMMENT '版本号', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流节点'; + +CREATE TABLE `sj_workflow_task_batch` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流任务id', + `task_batch_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT 0 COMMENT '操作原因', + `flow_info` text DEFAULT NULL COMMENT '流程信息', + `wf_context` text DEFAULT NULL COMMENT '全局上下文', + `execution_at` bigint(13) NOT NULL DEFAULT 0 COMMENT '任务执行时间', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `version` int(11) NOT NULL DEFAULT 1 COMMENT '版本号', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_job_id_task_batch_status` (`workflow_id`, `task_batch_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流批次'; + +CREATE TABLE `sj_job_executor` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `executor_info` varchar(256) NOT NULL COMMENT '任务执行器名称', + `executor_type` varchar(3) NOT NULL COMMENT '1:java 2:python 3:go', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务执行器信息'; diff --git a/script/sql/ry_vue.sql b/script/sql/ry_vue.sql new file mode 100644 index 000000000..9841276a6 --- /dev/null +++ b/script/sql/ry_vue.sql @@ -0,0 +1,934 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id bigint not null comment '主键', + user_id bigint not null comment '用户ID', + auth_id varchar(255) not null comment '平台+平台唯一id', + source varchar(255) not null comment '用户来源', + open_id varchar(255) default null comment '平台编号唯一id', + user_name varchar(30) not null comment '登录账号', + nick_name varchar(30) default '' comment '用户昵称', + email varchar(255) default '' comment '用户邮箱', + avatar varchar(500) default '' comment '头像地址', + access_token varchar(2000) not null comment '用户的授权令牌', + expire_in int default null comment '用户的授权令牌的有效期,部分平台可能没有', + refresh_token varchar(2000) default null comment '刷新令牌,部分平台可能没有', + access_code varchar(255) default null comment '平台的授权信息,部分平台可能没有', + union_id varchar(255) default null comment '用户的 unionid', + scope varchar(255) default null comment '授予的权限,部分平台可能没有', + token_type varchar(255) default null comment '个别平台的授权信息,部分平台可能没有', + id_token varchar(2000) default null comment 'id token,部分平台可能没有', + mac_algorithm varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + mac_key varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + code varchar(255) default null comment '用户的授权code,部分平台可能没有', + oauth_token varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + oauth_token_secret varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + PRIMARY KEY (id) +) engine=innodb comment = '社会化关系表'; + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table sys_dept ( + dept_id bigint(20) not null comment '部门id', + parent_id bigint(20) default 0 comment '父部门id', + ancestors varchar(500) default '' comment '祖级列表', + dept_name varchar(30) default '' comment '部门名称', + dept_category varchar(100) default null comment '部门类别编码', + order_num int(4) default 0 comment '显示顺序', + leader bigint(20) default null comment '负责人', + phone varchar(11) default null comment '联系电话', + email varchar(50) default null comment '邮箱', + status char(1) default '0' comment '部门状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + primary key (dept_id), + key idx_sys_dept_parent_id (parent_id) +) engine=innodb comment = '部门表'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- + + +insert into sys_dept values(1761000000000000100, 0, '0', 'XXX科技', null, 0, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000101, 1761000000000000100, '0,1761000000000000100', '深圳总公司', null, 1, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000102, 1761000000000000100, '0,1761000000000000100', '长沙分公司', null, 2, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000103, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '研发部门', null, 1, 1761100000000000001, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000104, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '市场部门', null, 2, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000105, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '测试部门', null, 3, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000106, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '财务部门', null, 4, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000107, 1761000000000000101, '0,1761000000000000100,1761000000000000101', '运维部门', null, 5, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000108, 1761000000000000102, '0,1761000000000000100,1761000000000000102', '市场部门', null, 1, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +insert into sys_dept values(1761000000000000109, 1761000000000000102, '0,1761000000000000100,1761000000000000102', '财务部门', null, 2, null, '15888888888', 'xxx@qq.com', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table sys_user ( + user_id bigint(20) not null comment '用户ID', + dept_id bigint(20) default null comment '部门ID', + user_name varchar(30) not null comment '用户账号', + nick_name varchar(30) not null comment '用户昵称', + user_type varchar(10) default 'sys_user' comment '用户类型(sys_user系统用户)', + email varchar(50) default '' comment '用户邮箱', + phone_number varchar(11) default '' comment '手机号码', + gender char(1) default '0' comment '用户性别(0男 1女 2未知)', + avatar bigint(20) comment '头像地址', + password varchar(100) default '' comment '密码', + status char(1) default '0' comment '账号状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + login_ip varchar(128) default '' comment '最后登录IP', + login_date datetime comment '最后登录时间', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (user_id), + key idx_sys_user_dept_id (dept_id), + key idx_sys_user_create_by (create_by), + key idx_sys_user_user_name (user_name), + key idx_sys_user_phone (phone_number) +) engine=innodb comment = '用户信息表'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1761100000000000001, 1761000000000000103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 1761000000000000103, 1761100000000000001, sysdate(), null, null, '管理员'); +insert into sys_user values(1761100000000000003, 1761000000000000108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000003, sysdate(), null); +insert into sys_user values(1761100000000000004, 1761000000000000102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000004, sysdate(), null); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table sys_post +( + post_id bigint(20) not null comment '岗位ID', + dept_id bigint(20) not null comment '部门id', + post_code varchar(64) not null comment '岗位编码', + post_category varchar(100) default null comment '岗位类别编码', + post_name varchar(50) not null comment '岗位名称', + post_sort int(4) not null comment '显示顺序', + status char(1) not null comment '状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (post_id), + key idx_sys_post_dept_id (dept_id) +) engine=innodb comment = '岗位信息表'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1761200000000000001, 1761000000000000103, 'ceo', null, '董事长', 1, '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_post values(1761200000000000002, 1761000000000000100, 'se', null, '项目经理', 2, '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_post values(1761200000000000003, 1761000000000000100, 'hr', null, '人力资源', 3, '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_post values(1761200000000000004, 1761000000000000100, 'user', null, '普通员工', 4, '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table sys_role ( + role_id bigint(20) not null comment '角色ID', + role_name varchar(30) not null comment '角色名称', + role_key varchar(100) not null comment '角色权限字符串', + role_sort int(4) not null comment '显示顺序', + data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限)', + menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示', + dept_check_strictly tinyint(1) default 1 comment '部门树选择项是否关联显示', + status char(1) not null comment '角色状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (role_id), + key idx_sys_role_create_dept (create_dept), + key idx_sys_role_create_by (create_by) +) engine=innodb comment = '角色信息表'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values(1761300000000000001, '超级管理员', 'superadmin', 1, 1, 1, 1, '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '超级管理员'); +insert into sys_role values(1761300000000000003, '本部门及以下', 'test1', 3, 4, 1, 1, '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_role values(1761300000000000004, '仅本人', 'test2', 4, 5, 1, 1, '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table sys_menu ( + menu_id bigint(20) not null comment '菜单ID', + menu_name varchar(50) not null comment '菜单名称', + parent_id bigint(20) default 0 comment '父菜单ID', + order_num int(4) default 0 comment '显示顺序', + path varchar(200) default '' comment '路由地址', + component varchar(255) default null comment '组件路径', + query_param varchar(255) default null comment '路由参数', + is_frame char(1) default 'N' comment '是否为外链(Y是 N否)', + is_cache char(1) default 'Y' comment '是否缓存(Y缓存 N不缓存)', + menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)', + visible char(1) default 0 comment '显示状态(0显示 1隐藏)', + status char(1) default 0 comment '菜单状态(0正常 1停用)', + perms varchar(100) default null comment '权限标识', + icon varchar(100) default '#' comment '菜单图标', + active_menu varchar(255) default '' comment '激活菜单路径', + ext varchar(2000) default '' comment '扩展字段', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default '' comment '备注', + primary key (menu_id) +) engine=innodb comment = '菜单权限表'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values(1761400000000000001, '系统管理', 0, 1, 'system', null, '', 'N', 'Y', 'M', '0', '0', '', 'system', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '系统管理目录'); +insert into sys_menu values(1761400000000000002, '系统监控', 0, 3, 'monitor', null, '', 'N', 'Y', 'M', '0', '0', '', 'monitor', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '系统监控目录'); +insert into sys_menu values(1761400000000000003, '系统工具', 0, 4, 'tool', null, '', 'N', 'Y', 'M', '0', '0', '', 'tool', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '系统工具目录'); +insert into sys_menu values(1761400000000000005, '测试菜单', 0, 5, 'demo', null, '', 'N', 'Y', 'M', '0', '0', '', 'star', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '测试菜单'); +insert into sys_menu values(1761400000000000008, 'AI会话', 0, 8, 'aichat', 'ai/chat/index', '', 'N', 'Y', 'C', '0', '0', '', 'checkbox', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, 'AI聊天菜单'); +insert into sys_menu values(1761400000000000004, 'PLUS官网', 0, 9, 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 'Y', 'Y', 'M', '0', '0', '', 'guide', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, 'RuoYi-Vue-Plus官网地址'); +-- 二级菜单 +insert into sys_menu values(1761400000000000100, '用户管理', 1761400000000000001, 1, 'user', 'system/user/index', '', 'N', 'Y', 'C', '0', '0', 'system:user:list', 'user', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '用户管理菜单'); +insert into sys_menu values(1761400000000000101, '角色管理', 1761400000000000001, 2, 'role', 'system/role/index', '', 'N', 'Y', 'C', '0', '0', 'system:role:list', 'peoples', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '角色管理菜单'); +insert into sys_menu values(1761400000000000102, '菜单管理', 1761400000000000001, 3, 'menu', 'system/menu/index', '', 'N', 'Y', 'C', '0', '0', 'system:menu:list', 'tree-table', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '菜单管理菜单'); +insert into sys_menu values(1761400000000000103, '部门管理', 1761400000000000001, 4, 'dept', 'system/dept/index', '', 'N', 'Y', 'C', '0', '0', 'system:dept:list', 'tree', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '部门管理菜单'); +insert into sys_menu values(1761400000000000104, '岗位管理', 1761400000000000001, 5, 'post', 'system/post/index', '', 'N', 'Y', 'C', '0', '0', 'system:post:list', 'post', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '岗位管理菜单'); +insert into sys_menu values(1761400000000000105, '字典管理', 1761400000000000001, 6, 'dict', 'system/dict/index', '', 'N', 'Y', 'C', '0', '0', 'system:dict:list', 'dict', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '字典管理菜单'); +insert into sys_menu values(1761400000000000106, '参数设置', 1761400000000000001, 7, 'config', 'system/config/index', '', 'N', 'Y', 'C', '0', '0', 'system:config:list', 'edit', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '参数设置菜单'); +insert into sys_menu values(1761400000000000107, '通知公告', 1761400000000000001, 8, 'notice', 'system/notice/index', '', 'N', 'Y', 'C', '0', '0', 'system:notice:list', 'message', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '通知公告菜单'); +insert into sys_menu values(1761400000000000108, '日志管理', 1761400000000000001, 9, 'log', '', '', 'N', 'Y', 'M', '0', '0', '', 'log', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '日志管理菜单'); +insert into sys_menu values(1761400000000000109, '在线用户', 1761400000000000002, 1, 'online', 'monitor/online/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:online:list', 'online', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '在线用户菜单'); +insert into sys_menu values(1761400000000000113, '缓存监控', 1761400000000000002, 5, 'cache', 'monitor/cache/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:cache:list', 'redis', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '缓存监控菜单'); +insert into sys_menu values(1761400000000000115, '代码生成', 1761400000000000003, 2, 'gen', 'tool/gen/index', '', 'N', 'Y', 'C', '0', '0', 'tool:gen:list', 'code', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '代码生成菜单'); +insert into sys_menu values(1761400000000000123, '客户端管理', 1761400000000000001, 11, 'client', 'system/client/index', '', 'N', 'Y', 'C', '0', '0', 'system:client:list', 'international', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '客户端管理菜单'); +insert into sys_menu values(1761400000000000116, '修改生成配置', 1761400000000000003, 2, 'gen-edit/index/:tableId', 'tool/gen/editTable', '', 'N', 'N', 'C', '1', '0', 'tool:gen:edit', '#', '/tool/gen', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000000130, '分配用户', 1761400000000000001, 2, 'role-auth/user/:roleId', 'system/role/authUser', '', 'N', 'N', 'C', '1', '0', 'system:role:edit', '#', '/system/role', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000000131, '分配角色', 1761400000000000001, 1, 'user-auth/role/:userId', 'system/user/authRole', '', 'N', 'N', 'C', '1', '0', 'system:user:edit', '#', '/system/user', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000000133, '文件配置管理', 1761400000000000001, 10, 'oss-config/index', 'system/oss/config', '', 'N', 'N', 'C', '1', '0', 'system:ossConfig:list', '#', '/system/oss', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); + +-- springboot-admin监控 +insert into sys_menu values(1761400000000000117, 'Admin监控', 1761400000000000002, 5, 'Admin', 'monitor/admin/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:admin:list', 'dashboard', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values(1761400000000000118, '文件管理', 1761400000000000001, 10, 'oss', 'system/oss/index', '', 'N', 'Y', 'C', '0', '0', 'system:oss:list', 'upload', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values(1761400000000000120, '任务调度中心', 1761400000000000002, 6, 'snailjob', 'monitor/snailjob/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:snailjob:list', 'job', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, 'SnailJob控制台菜单'); +-- snail-ai server控制台 +insert into sys_menu values(1761400000000000121, 'AI控制台', 1761400000000000002, 7, 'snailai', 'monitor/snailai/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:snailai:list', 'checkbox', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, 'AI控制台菜单'); + +-- 三级菜单 +insert into sys_menu values(1761400000000000500, '操作日志', 1761400000000000108, 1, 'operlog', 'monitor/operlog/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:operlog:list', 'form', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '操作日志菜单'); +insert into sys_menu values(1761400000000000501, '登录日志', 1761400000000000108, 2, 'logininfo', 'monitor/logininfo/index', '', 'N', 'Y', 'C', '0', '0', 'monitor:logininfo:list', 'logininfo', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values(1761400000000001001, '用户查询', 1761400000000000100, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001002, '用户新增', 1761400000000000100, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001003, '用户修改', 1761400000000000100, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001004, '用户删除', 1761400000000000100, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001005, '用户导出', 1761400000000000100, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001006, '用户导入', 1761400000000000100, 6, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:import', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001007, '重置密码', 1761400000000000100, 7, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:user:resetPwd', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 角色管理按钮 +insert into sys_menu values(1761400000000001008, '角色查询', 1761400000000000101, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001009, '角色新增', 1761400000000000101, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001010, '角色修改', 1761400000000000101, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001011, '角色删除', 1761400000000000101, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001012, '角色导出', 1761400000000000101, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:role:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values(1761400000000001013, '菜单查询', 1761400000000000102, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001014, '菜单新增', 1761400000000000102, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001015, '菜单修改', 1761400000000000102, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001016, '菜单删除', 1761400000000000102, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:menu:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 部门管理按钮 +insert into sys_menu values(1761400000000001017, '部门查询', 1761400000000000103, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001018, '部门新增', 1761400000000000103, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001019, '部门修改', 1761400000000000103, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001020, '部门删除', 1761400000000000103, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:dept:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values(1761400000000001021, '岗位查询', 1761400000000000104, 1, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001022, '岗位新增', 1761400000000000104, 2, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001023, '岗位修改', 1761400000000000104, 3, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001024, '岗位删除', 1761400000000000104, 4, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001025, '岗位导出', 1761400000000000104, 5, '', '', '', 'N', 'Y', 'F', '0', '0', 'system:post:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 字典管理按钮 +insert into sys_menu values(1761400000000001026, '字典查询', 1761400000000000105, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001027, '字典新增', 1761400000000000105, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001028, '字典修改', 1761400000000000105, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001029, '字典删除', 1761400000000000105, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001030, '字典导出', 1761400000000000105, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:dict:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 参数设置按钮 +insert into sys_menu values(1761400000000001031, '参数查询', 1761400000000000106, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001032, '参数新增', 1761400000000000106, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001033, '参数修改', 1761400000000000106, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001034, '参数删除', 1761400000000000106, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001035, '参数导出', 1761400000000000106, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:config:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 通知公告按钮 +insert into sys_menu values(1761400000000001036, '公告查询', 1761400000000000107, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001037, '公告新增', 1761400000000000107, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001038, '公告修改', 1761400000000000107, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001039, '公告删除', 1761400000000000107, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:notice:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 操作日志按钮 +insert into sys_menu values(1761400000000001040, '操作查询', 1761400000000000500, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001041, '操作删除', 1761400000000000500, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001042, '日志导出', 1761400000000000500, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:operlog:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 登录日志按钮 +insert into sys_menu values(1761400000000001043, '登录查询', 1761400000000000501, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001044, '登录删除', 1761400000000000501, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001045, '日志导出', 1761400000000000501, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001050, '账户解锁', 1761400000000000501, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:logininfo:unlock', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 在线用户按钮 +insert into sys_menu values(1761400000000001046, '在线查询', 1761400000000000109, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001047, '批量强退', 1761400000000000109, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:batchLogout', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001048, '单条强退', 1761400000000000109, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'monitor:online:forceLogout', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 代码生成按钮 +insert into sys_menu values(1761400000000001055, '生成查询', 1761400000000000115, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001056, '生成修改', 1761400000000000115, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001057, '生成删除', 1761400000000000115, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001058, '导入代码', 1761400000000000115, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:import', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001059, '预览代码', 1761400000000000115, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:preview', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001060, '生成代码', 1761400000000000115, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'tool:gen:code', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- oss相关按钮 +insert into sys_menu values(1761400000000001600, '文件查询', 1761400000000000118, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001601, '文件上传', 1761400000000000118, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:upload', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001602, '文件下载', 1761400000000000118, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:download', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001603, '文件删除', 1761400000000000118, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:oss:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001620, '配置列表', 1761400000000000118, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:list', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001621, '配置添加', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001622, '配置编辑', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001623, '配置删除', 1761400000000000118, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:ossConfig:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); + +-- 客户端管理按钮 +insert into sys_menu values(1761400000000001061, '客户端管理查询', 1761400000000000123, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001062, '客户端管理新增', 1761400000000000123, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001063, '客户端管理修改', 1761400000000000123, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001064, '客户端管理删除', 1761400000000000123, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001065, '客户端管理导出', 1761400000000000123, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'system:client:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 测试菜单 +insert into sys_menu values(1761400000000001500, '测试单表', 1761400000000000005, 1, 'demo', 'demo/demo/index', '', 'N', 'Y', 'C', '0', '0', 'demo:demo:list', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '测试单表菜单'); +insert into sys_menu values(1761400000000001501, '测试单表查询', 1761400000000001500, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001502, '测试单表新增', 1761400000000001500, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001503, '测试单表修改', 1761400000000001500, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001504, '测试单表删除', 1761400000000001500, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001505, '测试单表导出', 1761400000000001500, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:demo:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001506, '测试树表', 1761400000000000005, 1, 'tree', 'demo/tree/index', '', 'N', 'Y', 'C', '0', '0', 'demo:tree:list', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '测试树表菜单'); +insert into sys_menu values(1761400000000001507, '测试树表查询', 1761400000000001506, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001508, '测试树表新增', 1761400000000001506, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001509, '测试树表修改', 1761400000000001506, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001510, '测试树表删除', 1761400000000001506, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values(1761400000000001511, '测试树表导出', 1761400000000001506, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'demo:tree:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table sys_user_role ( + user_id bigint(20) not null comment '用户ID', + role_id bigint(20) not null comment '角色ID', + primary key(user_id, role_id), + key idx_sys_user_role_rid (role_id) +) engine=innodb comment = '用户和角色关联表'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values (1761100000000000001, 1761300000000000001); +insert into sys_user_role values (1761100000000000003, 1761300000000000003); +insert into sys_user_role values (1761100000000000004, 1761300000000000004); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table sys_role_menu ( + role_id bigint(20) not null comment '角色ID', + menu_id bigint(20) not null comment '菜单ID', + primary key(role_id, menu_id) +) engine=innodb comment = '角色和菜单关联表'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values (1761300000000000003, 1761400000000000001); +insert into sys_role_menu values (1761300000000000003, 1761400000000000005); +insert into sys_role_menu values (1761300000000000003, 1761400000000000100); +insert into sys_role_menu values (1761300000000000003, 1761400000000000101); +insert into sys_role_menu values (1761300000000000003, 1761400000000000102); +insert into sys_role_menu values (1761300000000000003, 1761400000000000103); +insert into sys_role_menu values (1761300000000000003, 1761400000000000104); +insert into sys_role_menu values (1761300000000000003, 1761400000000000105); +insert into sys_role_menu values (1761300000000000003, 1761400000000000106); +insert into sys_role_menu values (1761300000000000003, 1761400000000000107); +insert into sys_role_menu values (1761300000000000003, 1761400000000000108); +insert into sys_role_menu values (1761300000000000003, 1761400000000000118); +insert into sys_role_menu values (1761300000000000003, 1761400000000000123); +insert into sys_role_menu values (1761300000000000003, 1761400000000000130); +insert into sys_role_menu values (1761300000000000003, 1761400000000000131); +insert into sys_role_menu values (1761300000000000003, 1761400000000000133); +insert into sys_role_menu values (1761300000000000003, 1761400000000000500); +insert into sys_role_menu values (1761300000000000003, 1761400000000000501); +insert into sys_role_menu values (1761300000000000003, 1761400000000001001); +insert into sys_role_menu values (1761300000000000003, 1761400000000001002); +insert into sys_role_menu values (1761300000000000003, 1761400000000001003); +insert into sys_role_menu values (1761300000000000003, 1761400000000001004); +insert into sys_role_menu values (1761300000000000003, 1761400000000001005); +insert into sys_role_menu values (1761300000000000003, 1761400000000001006); +insert into sys_role_menu values (1761300000000000003, 1761400000000001007); +insert into sys_role_menu values (1761300000000000003, 1761400000000001008); +insert into sys_role_menu values (1761300000000000003, 1761400000000001009); +insert into sys_role_menu values (1761300000000000003, 1761400000000001010); +insert into sys_role_menu values (1761300000000000003, 1761400000000001011); +insert into sys_role_menu values (1761300000000000003, 1761400000000001012); +insert into sys_role_menu values (1761300000000000003, 1761400000000001013); +insert into sys_role_menu values (1761300000000000003, 1761400000000001014); +insert into sys_role_menu values (1761300000000000003, 1761400000000001015); +insert into sys_role_menu values (1761300000000000003, 1761400000000001016); +insert into sys_role_menu values (1761300000000000003, 1761400000000001017); +insert into sys_role_menu values (1761300000000000003, 1761400000000001018); +insert into sys_role_menu values (1761300000000000003, 1761400000000001019); +insert into sys_role_menu values (1761300000000000003, 1761400000000001020); +insert into sys_role_menu values (1761300000000000003, 1761400000000001021); +insert into sys_role_menu values (1761300000000000003, 1761400000000001022); +insert into sys_role_menu values (1761300000000000003, 1761400000000001023); +insert into sys_role_menu values (1761300000000000003, 1761400000000001024); +insert into sys_role_menu values (1761300000000000003, 1761400000000001025); +insert into sys_role_menu values (1761300000000000003, 1761400000000001026); +insert into sys_role_menu values (1761300000000000003, 1761400000000001027); +insert into sys_role_menu values (1761300000000000003, 1761400000000001028); +insert into sys_role_menu values (1761300000000000003, 1761400000000001029); +insert into sys_role_menu values (1761300000000000003, 1761400000000001030); +insert into sys_role_menu values (1761300000000000003, 1761400000000001031); +insert into sys_role_menu values (1761300000000000003, 1761400000000001032); +insert into sys_role_menu values (1761300000000000003, 1761400000000001033); +insert into sys_role_menu values (1761300000000000003, 1761400000000001034); +insert into sys_role_menu values (1761300000000000003, 1761400000000001035); +insert into sys_role_menu values (1761300000000000003, 1761400000000001036); +insert into sys_role_menu values (1761300000000000003, 1761400000000001037); +insert into sys_role_menu values (1761300000000000003, 1761400000000001038); +insert into sys_role_menu values (1761300000000000003, 1761400000000001039); +insert into sys_role_menu values (1761300000000000003, 1761400000000001040); +insert into sys_role_menu values (1761300000000000003, 1761400000000001041); +insert into sys_role_menu values (1761300000000000003, 1761400000000001042); +insert into sys_role_menu values (1761300000000000003, 1761400000000001043); +insert into sys_role_menu values (1761300000000000003, 1761400000000001044); +insert into sys_role_menu values (1761300000000000003, 1761400000000001045); +insert into sys_role_menu values (1761300000000000003, 1761400000000001050); +insert into sys_role_menu values (1761300000000000003, 1761400000000001061); +insert into sys_role_menu values (1761300000000000003, 1761400000000001062); +insert into sys_role_menu values (1761300000000000003, 1761400000000001063); +insert into sys_role_menu values (1761300000000000003, 1761400000000001064); +insert into sys_role_menu values (1761300000000000003, 1761400000000001065); +insert into sys_role_menu values (1761300000000000003, 1761400000000001500); +insert into sys_role_menu values (1761300000000000003, 1761400000000001501); +insert into sys_role_menu values (1761300000000000003, 1761400000000001502); +insert into sys_role_menu values (1761300000000000003, 1761400000000001503); +insert into sys_role_menu values (1761300000000000003, 1761400000000001504); +insert into sys_role_menu values (1761300000000000003, 1761400000000001505); +insert into sys_role_menu values (1761300000000000003, 1761400000000001506); +insert into sys_role_menu values (1761300000000000003, 1761400000000001507); +insert into sys_role_menu values (1761300000000000003, 1761400000000001508); +insert into sys_role_menu values (1761300000000000003, 1761400000000001509); +insert into sys_role_menu values (1761300000000000003, 1761400000000001510); +insert into sys_role_menu values (1761300000000000003, 1761400000000001511); +insert into sys_role_menu values (1761300000000000003, 1761400000000001600); +insert into sys_role_menu values (1761300000000000003, 1761400000000001601); +insert into sys_role_menu values (1761300000000000003, 1761400000000001602); +insert into sys_role_menu values (1761300000000000003, 1761400000000001603); +insert into sys_role_menu values (1761300000000000003, 1761400000000001620); +insert into sys_role_menu values (1761300000000000003, 1761400000000001621); +insert into sys_role_menu values (1761300000000000003, 1761400000000001622); +insert into sys_role_menu values (1761300000000000003, 1761400000000001623); +insert into sys_role_menu values (1761300000000000003, 1761400000000011616); +insert into sys_role_menu values (1761300000000000003, 1761400000000011618); +insert into sys_role_menu values (1761300000000000003, 1761400000000011619); +insert into sys_role_menu values (1761300000000000003, 1761400000000011622); +insert into sys_role_menu values (1761300000000000003, 1761400000000011623); +insert into sys_role_menu values (1761300000000000003, 1761400000000011629); +insert into sys_role_menu values (1761300000000000003, 1761400000000011632); +insert into sys_role_menu values (1761300000000000003, 1761400000000011633); +insert into sys_role_menu values (1761300000000000003, 1761400000000011638); +insert into sys_role_menu values (1761300000000000003, 1761400000000011639); +insert into sys_role_menu values (1761300000000000003, 1761400000000011640); +insert into sys_role_menu values (1761300000000000003, 1761400000000011641); +insert into sys_role_menu values (1761300000000000003, 1761400000000011642); +insert into sys_role_menu values (1761300000000000003, 1761400000000011643); +insert into sys_role_menu values (1761300000000000003, 1761400000000011701); +insert into sys_role_menu values (1761300000000000004, 1761400000000000005); +insert into sys_role_menu values (1761300000000000004, 1761400000000001500); +insert into sys_role_menu values (1761300000000000004, 1761400000000001501); +insert into sys_role_menu values (1761300000000000004, 1761400000000001502); +insert into sys_role_menu values (1761300000000000004, 1761400000000001503); +insert into sys_role_menu values (1761300000000000004, 1761400000000001504); +insert into sys_role_menu values (1761300000000000004, 1761400000000001505); +insert into sys_role_menu values (1761300000000000004, 1761400000000001506); +insert into sys_role_menu values (1761300000000000004, 1761400000000001507); +insert into sys_role_menu values (1761300000000000004, 1761400000000001508); +insert into sys_role_menu values (1761300000000000004, 1761400000000001509); +insert into sys_role_menu values (1761300000000000004, 1761400000000001510); +insert into sys_role_menu values (1761300000000000004, 1761400000000001511); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table sys_role_dept ( + role_id bigint(20) not null comment '角色ID', + dept_id bigint(20) not null comment '部门ID', + primary key(role_id, dept_id) +) engine=innodb comment = '角色和部门关联表'; + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table sys_user_post +( + user_id bigint(20) not null comment '用户ID', + post_id bigint(20) not null comment '岗位ID', + primary key (user_id, post_id) +) engine=innodb comment = '用户与岗位关联表'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values (1761100000000000001, 1761200000000000001); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table sys_oper_log ( + oper_id bigint(20) not null comment '日志主键', + title varchar(50) default '' comment '模块标题', + business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)', + method varchar(100) default '' comment '方法名称', + request_method varchar(10) default '' comment '请求方式', + operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)', + oper_name varchar(50) default '' comment '操作人员', + user_id bigint(20) default null comment '操作用户ID', + dept_id bigint(20) default null comment '操作部门ID', + dept_name varchar(50) default '' comment '部门名称', + client_key varchar(32) default '' comment '客户端', + device_type varchar(32) default '' comment '设备类型', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + oper_url varchar(255) default '' comment '请求URL', + oper_ip varchar(128) default '' comment '主机地址', + oper_location varchar(255) default '' comment '操作地点', + oper_param varchar(4000) default '' comment '请求参数', + json_result varchar(4000) default '' comment '返回参数', + status int(1) default 0 comment '操作状态(0正常 1异常)', + error_msg varchar(4000) default '' comment '错误消息', + oper_time datetime comment '操作时间', + cost_time bigint(20) default 0 comment '消耗时间', + primary key (oper_id), + key idx_sys_oper_log_bt (business_type), + key idx_sys_oper_log_uid (user_id), + key idx_sys_oper_log_s (status), + key idx_sys_oper_log_ot (oper_time) +) engine=innodb comment = '操作日志记录'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table sys_dict_type +( + dict_id bigint(20) not null comment '字典主键', + dict_name varchar(100) default '' comment '字典名称', + dict_type varchar(100) default '' comment '字典类型', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_id), + unique (dict_type) +) engine=innodb comment = '字典类型表'; + +insert into sys_dict_type values(1761500000000000001, '用户性别', 'sys_user_gender', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '用户性别列表'); +insert into sys_dict_type values(1761500000000000002, '菜单状态', 'sys_show_hide', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '菜单状态列表'); +insert into sys_dict_type values(1761500000000000003, '系统开关', 'sys_normal_disable', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '系统开关列表'); +insert into sys_dict_type values(1761500000000000006, '系统是否', 'sys_yes_no', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '系统是否列表'); +insert into sys_dict_type values(1761500000000000007, '通知类型', 'sys_notice_type', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '通知类型列表'); +insert into sys_dict_type values(1761500000000000008, '通知状态', 'sys_notice_status', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '通知状态列表'); +insert into sys_dict_type values(1761500000000000009, '操作类型', 'sys_oper_type', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '操作类型列表'); +insert into sys_dict_type values(1761500000000000010, '系统状态', 'sys_common_status', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '登录状态列表'); +insert into sys_dict_type values(1761500000000000011, '授权类型', 'sys_grant_type', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '认证授权类型'); +insert into sys_dict_type values(1761500000000000012, '设备类型', 'sys_device_type', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '客户端设备类型'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table sys_dict_data +( + dict_code bigint(20) not null comment '字典编码', + dict_sort int(4) default 0 comment '字典排序', + dict_label varchar(100) default '' comment '字典标签', + dict_value varchar(100) default '' comment '字典键值', + dict_type varchar(100) default '' comment '字典类型', + css_class varchar(100) default null comment '样式属性(其他样式扩展)', + list_class varchar(100) default null comment '表格回显样式', + is_default char(1) default 'N' comment '是否默认(Y是 N否)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_code), + key idx_sys_dict_data_type (dict_type) +) engine=innodb comment = '字典数据表'; + +insert into sys_dict_data values(1761600000000000001, 1, '男', '0', 'sys_user_gender', '', '', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '性别男'); +insert into sys_dict_data values(1761600000000000002, 2, '女', '1', 'sys_user_gender', '', '', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '性别女'); +insert into sys_dict_data values(1761600000000000003, 3, '未知', '2', 'sys_user_gender', '', '', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '性别未知'); +insert into sys_dict_data values(1761600000000000004, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '显示菜单'); +insert into sys_dict_data values(1761600000000000005, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '隐藏菜单'); +insert into sys_dict_data values(1761600000000000006, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(1761600000000000007, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '停用状态'); +insert into sys_dict_data values(1761600000000000012, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '系统默认是'); +insert into sys_dict_data values(1761600000000000013, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '系统默认否'); +insert into sys_dict_data values(1761600000000000014, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '通知'); +insert into sys_dict_data values(1761600000000000015, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '公告'); +insert into sys_dict_data values(1761600000000000016, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(1761600000000000017, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '关闭状态'); +insert into sys_dict_data values(1761600000000000029, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '其他操作'); +insert into sys_dict_data values(1761600000000000018, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '新增操作'); +insert into sys_dict_data values(1761600000000000019, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '修改操作'); +insert into sys_dict_data values(1761600000000000020, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '删除操作'); +insert into sys_dict_data values(1761600000000000021, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '授权操作'); +insert into sys_dict_data values(1761600000000000022, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '导出操作'); +insert into sys_dict_data values(1761600000000000023, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '导入操作'); +insert into sys_dict_data values(1761600000000000024, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '强退操作'); +insert into sys_dict_data values(1761600000000000025, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '生成操作'); +insert into sys_dict_data values(1761600000000000026, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '清空操作'); +insert into sys_dict_data values(1761600000000000027, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(1761600000000000028, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '停用状态'); +insert into sys_dict_data values(1761600000000000030, 0, '密码认证', 'password', 'sys_grant_type', 'el-check-tag', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '密码认证'); +insert into sys_dict_data values(1761600000000000031, 0, '短信认证', 'sms', 'sys_grant_type', 'el-check-tag', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '短信认证'); +insert into sys_dict_data values(1761600000000000032, 0, '邮件认证', 'email', 'sys_grant_type', 'el-check-tag', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '邮件认证'); +insert into sys_dict_data values(1761600000000000033, 0, '小程序认证', 'xcx', 'sys_grant_type', 'el-check-tag', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '小程序认证'); +insert into sys_dict_data values(1761600000000000034, 0, '三方登录认证', 'social', 'sys_grant_type', 'el-check-tag', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '三方登录认证'); +insert into sys_dict_data values(1761600000000000035, 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, 'PC'); +insert into sys_dict_data values(1761600000000000036, 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '安卓'); +insert into sys_dict_data values(1761600000000000037, 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, 'iOS'); +insert into sys_dict_data values(1761600000000000038, 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table sys_config ( + config_id bigint(20) not null comment '参数主键', + config_name varchar(100) default '' comment '参数名称', + config_key varchar(100) default '' comment '参数键名', + config_value varchar(500) default '' comment '参数键值', + config_type char(1) default 'N' comment '系统内置(Y是 N否)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (config_id) +) engine=innodb comment = '参数配置表'; + +insert into sys_config values(1761700000000000001, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '初始化密码 123456'); +insert into sys_config values(1761700000000000002, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(1761700000000000003, 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 1761000000000000103, 1761100000000000001, sysdate(), null, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table sys_login_info ( + info_id bigint(20) not null comment '访问ID', + user_name varchar(50) default '' comment '用户账号', + client_key varchar(32) default '' comment '客户端', + device_type varchar(32) default '' comment '设备类型', + ipaddr varchar(128) default '' comment '登录IP地址', + login_location varchar(255) default '' comment '登录地点', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + status char(1) default '0' comment '登录状态(0正常 1异常)', + msg varchar(255) default '' comment '提示消息', + login_time datetime comment '访问时间', + primary key (info_id), + key idx_sys_login_info_s (status), + key idx_sys_login_info_lt (login_time) +) engine=innodb comment = '系统访问记录'; + + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table sys_notice ( + notice_id bigint(20) not null comment '公告ID', + notice_title varchar(50) not null comment '公告标题', + notice_type char(1) not null comment '公告类型(1通知 2公告)', + notice_content longblob default null comment '公告内容', + status char(1) default '0' comment '公告状态(0正常 1关闭)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(255) default null comment '备注', + primary key (notice_id) +) engine=innodb comment = '通知公告表'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values(1761800000000000001, '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '管理员'); +insert into sys_notice values(1761800000000000002, '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '管理员'); + + +-- ---------------------------- +-- 18、消息记录表 +-- ---------------------------- +create table sys_message ( + message_id bigint(20) not null comment '消息ID', + category varchar(20) not null comment '消息分组(system/notice/workflow)', + type varchar(20) not null comment '消息类型', + source varchar(20) not null comment '消息来源', + title varchar(100) default '' comment '标题', + message varchar(500) default '' comment '摘要消息', + content longtext comment '详细内容', + data_json longtext comment '扩展数据JSON', + path varchar(500) default null comment '前端跳转路径', + send_user_ids varchar(2000) not null default '0' comment '目标用户ID串,0表示全局', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + primary key (message_id), + key idx_sys_message_category_time (category, create_time) +) engine=innodb comment = '消息记录表'; + + +-- ---------------------------- +-- 19、代码生成业务表 +-- ---------------------------- +create table gen_table ( + table_id bigint(20) not null comment '编号', + data_name varchar(200) default '' comment '数据源名称', + table_name varchar(200) default '' comment '表名称', + table_comment varchar(500) default '' comment '表描述', + class_name varchar(100) default '' comment '实体类名称', + tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', + frontend_type varchar(50) default 'vue' comment '前端模板类型,对应 vm 下的模板目录', + package_name varchar(100) comment '生成包路径', + module_name varchar(30) comment '生成模块名', + business_name varchar(30) comment '生成业务名', + function_name varchar(50) comment '生成功能名', + function_author varchar(50) comment '生成功能作者', + gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (table_id) +) engine=innodb comment = '代码生成业务表'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +create table gen_table_column ( + column_id bigint(20) not null comment '编号', + table_id bigint(20) comment '归属表编号', + column_name varchar(200) comment '列名称', + column_comment varchar(500) comment '列描述', + column_type varchar(100) comment '列类型', + java_type varchar(500) comment 'JAVA类型', + java_field varchar(200) comment 'JAVA字段名', + is_pk char(1) comment '是否主键(1是)', + is_increment char(1) comment '是否自增(1是)', + is_required char(1) comment '是否必填(1是)', + is_insert char(1) comment '是否为插入字段(1是)', + is_edit char(1) comment '是否编辑字段(1是)', + is_list char(1) comment '是否列表字段(1是)', + is_query char(1) comment '是否查询字段(1是)', + query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)', + html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + dict_type varchar(200) default '' comment '字典类型', + sort int comment '排序', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + primary key (column_id) +) engine=innodb comment = '代码生成业务表字段'; + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table sys_oss ( + oss_id bigint(20) not null comment '对象存储主键', + file_name varchar(255) not null default '' comment '文件名', + original_name varchar(255) not null default '' comment '原名', + file_suffix varchar(10) not null default '' comment '文件后缀名', + url varchar(500) not null comment 'URL地址', + ext1 text default null comment '扩展字段', + create_dept bigint(20) default null comment '创建部门', + create_time datetime default null comment '创建时间', + create_by bigint(20) default null comment '上传人', + update_time datetime default null comment '更新时间', + update_by bigint(20) default null comment '更新人', + service varchar(20) not null default 'minio' comment '服务商', + primary key (oss_id) +) engine=innodb comment ='OSS对象存储表'; + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table sys_oss_config ( + oss_config_id bigint(20) not null comment '主键', + config_key varchar(20) not null default '' comment '配置key', + access_key varchar(255) default '' comment 'accessKey', + secret_key varchar(255) default '' comment '秘钥', + bucket_name varchar(255) default '' comment '桶名称', + prefix varchar(255) default '' comment '前缀', + endpoint varchar(255) default '' comment '访问站点', + domain_url varchar(255) default '' comment '自定义域名', + is_https char(1) default 'N' comment '是否https(Y=是,N=否)', + region varchar(255) default '' comment '域', + access_policy char(1) not null default '1' comment '桶权限类型(0=private 1=public 2=custom)', + status char(1) default 'N' comment '是否默认(Y=是,N=否)', + ext1 varchar(255) default '' comment '扩展字段', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime default null comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime default null comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (oss_config_id) +) engine=innodb comment='对象存储配置表'; + +insert into sys_oss_config values (1761900000000000001, 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '', 'N', '', '1', 'Y', '', 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate(), null); +insert into sys_oss_config values (1761900000000000002, 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '', 'N', '', '1', 'N', '', 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate(), null); +insert into sys_oss_config values (1761900000000000003, 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '', 'N', '', '1', 'N', '', 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate(), null); +insert into sys_oss_config values (1761900000000000004, 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1240000000', '', 'cos.ap-beijing.myqcloud.com', '', 'N', 'ap-beijing', '1', 'N', '', 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate(), null); +insert into sys_oss_config values (1761900000000000005, 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '', 'N', '', '1', 'N', '', 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate(), null); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id bigint(20) not null comment 'id', + client_id varchar(64) default null comment '客户端id', + client_key varchar(32) default null comment '客户端key', + client_secret varchar(255) default null comment '客户端秘钥', + grant_type varchar(255) default null comment '授权类型', + device_type varchar(32) default null comment '设备类型', + access_path varchar(2000) default null comment '允许访问路径', + ip_whitelist varchar(1000) default null comment 'IP白名单', + active_timeout int(11) default 1800 comment 'token活跃超时时间', + timeout int(11) default 604800 comment 'token固定超时', + status char(1) default '0' comment '状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime default null comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime default null comment '更新时间', + primary key (id) +) engine=innodb comment='系统授权表'; + +insert into sys_client values (1762000000000000001, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', null, null, 1800, 604800, 0, 0, 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate()); +insert into sys_client values (1762000000000000002, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', '/app/**', null, 1800, 604800, 0, 0, 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate()); + + +CREATE TABLE test_demo +( + id bigint(0) NOT NULL COMMENT '主键', + dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', + user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', + order_num int(0) NULL DEFAULT 0 COMMENT '排序号', + test_key varchar(255) NULL DEFAULT NULL COMMENT 'key键', + value varchar(255) NULL DEFAULT NULL COMMENT '值', + version int(0) NULL DEFAULT 0 COMMENT '版本', + create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', + create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', + update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', + del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '测试单表'; + +CREATE TABLE test_tree +( + id bigint(0) NOT NULL COMMENT '主键', + parent_id bigint(0) NULL DEFAULT 0 COMMENT '父id', + dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', + user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', + tree_name varchar(255) NULL DEFAULT NULL COMMENT '值', + version int(0) NULL DEFAULT 0 COMMENT '版本', + create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', + create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', + update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', + del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '测试树表'; + +INSERT INTO test_demo VALUES (1762100000000000001, 1761000000000000102, 1761100000000000004, 1, '测试数据权限', '测试', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000002, 1761000000000000102, 1761100000000000003, 2, '子节点1', '111', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000003, 1761000000000000102, 1761100000000000003, 3, '子节点2', '222', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000004, 1761000000000000108, 1761100000000000004, 4, '测试数据', 'demo', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000005, 1761000000000000108, 1761100000000000003, 13, '子节点11', '1111', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000006, 1761000000000000108, 1761100000000000003, 12, '子节点22', '2222', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000007, 1761000000000000108, 1761100000000000003, 11, '子节点33', '3333', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000008, 1761000000000000108, 1761100000000000003, 10, '子节点44', '4444', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000009, 1761000000000000108, 1761100000000000003, 9, '子节点55', '5555', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000010, 1761000000000000108, 1761100000000000003, 8, '子节点66', '6666', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000011, 1761000000000000108, 1761100000000000003, 7, '子节点77', '7777', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000012, 1761000000000000108, 1761100000000000003, 6, '子节点88', '8888', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_demo VALUES (1762100000000000013, 1761000000000000108, 1761100000000000003, 5, '子节点99', '9999', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); + +INSERT INTO test_tree VALUES (1762200000000000001, 0, 1761000000000000102, 1761100000000000004, '测试数据权限', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000002, 1762200000000000001, 1761000000000000102, 1761100000000000003, '子节点1', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000003, 1762200000000000002, 1761000000000000102, 1761100000000000003, '子节点2', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000004, 0, 1761000000000000108, 1761100000000000004, '测试树1', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000005, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点11', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000006, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点22', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000007, 1762200000000000004, 1761000000000000108, 1761100000000000003, '子节点33', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000008, 1762200000000000005, 1761000000000000108, 1761100000000000003, '子节点44', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000009, 1762200000000000006, 1761000000000000108, 1761100000000000003, '子节点55', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000010, 1762200000000000007, 1761000000000000108, 1761100000000000003, '子节点66', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000011, 1762200000000000007, 1761000000000000108, 1761100000000000003, '子节点77', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000012, 1762200000000000010, 1761000000000000108, 1761100000000000003, '子节点88', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); +INSERT INTO test_tree VALUES (1762200000000000013, 1762200000000000010, 1761000000000000108, 1761100000000000003, '子节点99', 0, 1761000000000000103, sysdate(), 1761100000000000001, NULL, NULL, 0); + diff --git a/script/sql/ry_workflow.sql b/script/sql/ry_workflow.sql new file mode 100644 index 000000000..581395dc3 --- /dev/null +++ b/script/sql/ry_workflow.sql @@ -0,0 +1,338 @@ +-- ---------------------------- +-- 0、warm-flow-all.sql,地址:https://gitee.com/dromara/warm-flow/blob/master/sql/mysql/warm-flow-all.sql +-- ---------------------------- +CREATE TABLE `flow_definition` +( + `id` bigint NOT NULL COMMENT '主键id', + `flow_code` varchar(40) NOT NULL COMMENT '流程编码', + `flow_name` varchar(100) NOT NULL COMMENT '流程名称', + `model_value` varchar(40) NOT NULL DEFAULT 'CLASSICS' COMMENT '设计器模型(CLASSICS经典模型 MIMIC仿钉钉模型)', + `category` varchar(100) DEFAULT NULL COMMENT '流程类别', + `version` varchar(20) NOT NULL COMMENT '流程版本', + `is_publish` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否发布(0未发布 1已发布 9失效)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态(0挂起 1激活)', + `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型', + `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径', + `ext` varchar(500) DEFAULT NULL COMMENT '业务详情 存业务表对象json字符串', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) DEFAULT '' COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新人', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程定义表'; + +CREATE TABLE `flow_node` +( + `id` bigint NOT NULL COMMENT '主键id', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `definition_id` bigint NOT NULL COMMENT '流程定义id', + `node_code` varchar(100) NOT NULL COMMENT '流程节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称', + `permission_flag` varchar(200) DEFAULT NULL COMMENT '权限标识(权限类型:权限标识,可以多个,用@@隔开)', + `node_ratio` varchar(200) DEFAULT NULL COMMENT '流程签署比例值', + `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标', + `any_node_skip` varchar(100) DEFAULT NULL COMMENT '任意结点跳转', + `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型', + `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `version` varchar(20) NOT NULL COMMENT '版本', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) DEFAULT '' COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新人', + `ext` text COMMENT '节点扩展属性', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程节点表'; + +CREATE TABLE `flow_skip` +( + `id` bigint NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '流程定义id', + `now_node_code` varchar(100) NOT NULL COMMENT '当前流程节点的编码', + `now_node_type` tinyint(1) DEFAULT NULL COMMENT '当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `next_node_code` varchar(100) NOT NULL COMMENT '下一个流程节点的编码', + `next_node_type` tinyint(1) DEFAULT NULL COMMENT '下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `skip_name` varchar(100) DEFAULT NULL COMMENT '跳转名称', + `skip_type` varchar(40) DEFAULT NULL COMMENT '跳转类型(PASS审批通过 REJECT退回)', + `skip_condition` varchar(200) DEFAULT NULL COMMENT '跳转条件', + `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) DEFAULT '' COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新人', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='节点跳转关联表'; + +CREATE TABLE `flow_instance` +( + `id` bigint NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '对应flow_definition表的id', + `business_id` varchar(40) NOT NULL COMMENT '业务id', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `node_code` varchar(40) NOT NULL COMMENT '流程节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称', + `variable` text COMMENT '任务变量', + `flow_status` varchar(20) NOT NULL COMMENT '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', + `activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态(0挂起 1激活)', + `def_json` text COMMENT '流程定义json', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) DEFAULT '' COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新人', + `ext` varchar(500) DEFAULT NULL COMMENT '扩展字段,预留给业务系统使用', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程实例表'; + +CREATE TABLE `flow_task` +( + `id` bigint NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '对应flow_definition表的id', + `instance_id` bigint NOT NULL COMMENT '对应flow_instance表的id', + `node_code` varchar(100) NOT NULL COMMENT '节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '节点名称', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `flow_status` varchar(20) NOT NULL COMMENT '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) DEFAULT '' COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新人', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='待办任务表'; + +CREATE TABLE `flow_his_task` +( + `id` bigint(20) NOT NULL COMMENT '主键id', + `definition_id` bigint(20) NOT NULL COMMENT '对应flow_definition表的id', + `instance_id` bigint(20) NOT NULL COMMENT '对应flow_instance表的id', + `task_id` bigint(20) NOT NULL COMMENT '对应flow_task表的id', + `node_code` varchar(100) DEFAULT NULL COMMENT '开始节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '开始节点名称', + `node_type` tinyint(1) DEFAULT NULL COMMENT '开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `target_node_code` varchar(200) DEFAULT NULL COMMENT '目标节点编码', + `target_node_name` varchar(200) DEFAULT NULL COMMENT '结束节点名称', + `approver` varchar(40) DEFAULT NULL COMMENT '审批人', + `cooperate_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)', + `collaborator` varchar(500) DEFAULT NULL COMMENT '协作人', + `skip_type` varchar(10) NOT NULL COMMENT '流转类型(PASS通过 REJECT退回 NONE无动作)', + `flow_status` varchar(20) NOT NULL COMMENT '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `message` varchar(500) DEFAULT NULL COMMENT '审批意见', + `variable` TEXT DEFAULT NULL COMMENT '任务变量', + `ext` TEXT DEFAULT NULL COMMENT '业务详情 存业务表对象json字符串', + `create_time` datetime DEFAULT NULL COMMENT '任务开始时间', + `update_time` datetime DEFAULT NULL COMMENT '审批完成时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='历史任务记录表'; + + +CREATE TABLE `flow_user` +( + `id` bigint NOT NULL COMMENT '主键id', + `type` char(1) NOT NULL COMMENT '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)', + `processed_by` varchar(80) DEFAULT NULL COMMENT '权限人', + `associated` bigint NOT NULL COMMENT '任务表id', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(80) DEFAULT NULL COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) DEFAULT '' COMMENT '创建人', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE, + KEY `user_processed_type` (`processed_by`, `type`), + KEY `user_associated` (`associated`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程用户表'; + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +create table flow_category +( + category_id bigint(20) not null comment '流程分类ID', + parent_id bigint(20) default 0 comment '父流程分类id', + ancestors varchar(500) default '' comment '祖级列表', + category_name varchar(30) not null comment '流程分类名称', + order_num int(4) default 0 comment '显示顺序', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) null comment '创建部门', + create_by bigint(20) null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint(20) null comment '更新者', + update_time datetime null comment '更新时间', + primary key (category_id) +) engine = innodb comment = '流程分类'; + +INSERT INTO flow_category values (1762300000000000100, 0, '0', 'OA审批', 0, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000101, 1762300000000000100, '0,1762300000000000100', '假勤管理', 0, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000102, 1762300000000000100, '0,1762300000000000100', '人事管理', 1, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000103, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '请假', 0, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000104, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '出差', 1, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000105, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '加班', 2, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000106, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '换班', 3, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000107, 1762300000000000101, '0,1762300000000000100,1762300000000000101', '外出', 4, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000108, 1762300000000000102, '0,1762300000000000100,1762300000000000102', '转正', 1, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); +INSERT INTO flow_category values (1762300000000000109, 1762300000000000102, '0,1762300000000000100,1762300000000000102', '离职', 2, '0', 1761000000000000103, 1761100000000000001, sysdate(), null, null); + +-- ---------------------------- +-- 流程spel表达式定义表 +-- ---------------------------- + +CREATE TABLE flow_spel ( + id bigint(20) NOT NULL COMMENT '主键id', + component_name varchar(255) DEFAULT NULL COMMENT '组件名称', + method_name varchar(255) DEFAULT NULL COMMENT '方法名', + method_params varchar(255) DEFAULT NULL COMMENT '参数', + view_spel varchar(255) DEFAULT NULL COMMENT '预览spel表达式', + remark varchar(255) DEFAULT NULL COMMENT '备注', + status char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)', + del_flag char(1) DEFAULT '0' COMMENT '删除标志', + create_dept bigint(20) DEFAULT NULL COMMENT '创建部门', + create_by bigint(20) DEFAULT NULL COMMENT '创建者', + create_time datetime DEFAULT NULL COMMENT '创建时间', + update_by bigint(20) DEFAULT NULL COMMENT '更新者', + update_time datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (id) +) ENGINE = InnoDB COMMENT='流程spel表达式定义表'; + +INSERT INTO flow_spel VALUES (1762400000000000001, 'spelRuleComponent', 'selectDeptLeaderById', 'initiatorDeptId', '#{@spelRuleComponent.selectDeptLeaderById(#initiatorDeptId)}', '根据部门id获取部门负责人', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate()); +INSERT INTO flow_spel VALUES (1762400000000000002, NULL, NULL, 'initiator', '${initiator}', '流程发起人', '0', '0', 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate()); + +-- ---------------------------- +-- 流程实例业务扩展表 +-- ---------------------------- + +create table flow_instance_biz_ext ( + id bigint not null comment '主键id', + 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 '更新时间', + business_code varchar(255) null comment '业务编码', + business_title varchar(1000) null comment '业务标题', + del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)', + instance_id bigint null comment '流程实例Id', + business_id varchar(255) null comment '业务Id', + PRIMARY KEY (id) +) ENGINE = InnoDB COMMENT '流程实例业务扩展表'; + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- + +create table test_leave +( + id bigint(20) not null comment 'id', + apply_code varchar(50) not null comment '申请编号', + leave_type varchar(255) not null comment '请假类型', + start_date datetime not null comment '开始时间', + end_date datetime not null comment '结束时间', + leave_days int(10) not null comment '请假天数', + remark varchar(255) null comment '请假原因', + status varchar(255) 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 '更新时间', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '请假申请表'; + +insert into sys_menu values (1761400000000011616, '工作流', 0, 6, 'workflow', '', '', 'N', 'Y', 'M', '0', '0', '', 'workflow', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011618, '我的任务', 0, 7, 'task', '', '', 'N', 'Y', 'M', '0', '0', '', 'my-task', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011619, '我的待办', 1761400000000011618, 2, 'taskWaiting', 'workflow/task/taskWaiting', '', 'N', 'N', 'C', '0', '0', '', 'waiting', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011632, '我的已办', 1761400000000011618, 3, 'taskFinish', 'workflow/task/taskFinish', '', 'N', 'N', 'C', '0', '0', '', 'finish', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011633, '我的抄送', 1761400000000011618, 4, 'taskCopyList', 'workflow/task/taskCopyList', '', 'N', 'N', 'C', '0', '0', '', 'my-copy', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011620, '流程定义', 1761400000000011616, 3, 'processDefinition', 'workflow/processDefinition/index', '', 'N', 'N', 'C', '0', '0', 'workflow:definition:list', 'process-definition', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011621, '流程实例', 1761400000000011630, 1, 'processInstance', 'workflow/processInstance/index', '', 'N', 'N', 'C', '0', '0', 'workflow:instance:list', 'tree-table', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011622, '流程分类', 1761400000000011616, 1, 'category', 'workflow/category/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:category:list', 'category', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011801, '流程表达式', 1761400000000011616, 2, 'spel', 'workflow/spel/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:spel:list', 'input', '', '', 1761000000000000103, 1761100000000000001, sysdate(), 1761100000000000001, sysdate(), '流程达式定义菜单'); +insert into sys_menu values (1761400000000011629, '我发起的', 1761400000000011618, 1, 'myDocument', 'workflow/task/myDocument', '', 'N', 'N', 'C', '0', '0', 'workflow:instance:currentList', 'guide', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011630, '流程监控', 1761400000000011616, 4, 'processMonitor', '', '', 'N', 'Y', 'M', '0', '0', '', 'monitor', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011631, '待办任务', 1761400000000011630, 2, 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', 'N', 'N', 'C', '0', '0', 'workflow:task:list', 'waiting', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu values (1761400000000011660, '待办任务修改', 1761400000000011631, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:task:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011700, '流程设计', 1761400000000011616, 5, 'design/index', 'workflow/processDefinition/design', '', 'N', 'N', 'C', '1', '0', 'workflow:leave:edit', '#', '/workflow/processDefinition', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011701, '请假申请', 1761400000000011616, 6, 'leaveEdit/index', 'workflow/leave/leaveEdit', '', 'N', 'N', 'C', '1', '0', 'workflow:leave:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +-- 流程分类管理相关按钮 +insert into sys_menu values (1761400000000011623, '流程分类查询', 1761400000000011622, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011624, '流程分类新增', 1761400000000011622, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011625, '流程分类修改', 1761400000000011622, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011626, '流程分类删除', 1761400000000011622, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011627, '流程分类导出', 1761400000000011622, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:category:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); + +-- 流程实例管理相关按钮 +insert into sys_menu values (1761400000000011653, '流程实例查询', 1761400000000011621, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011654, '流程变量查询', 1761400000000011621, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variableQuery', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011655, '流程变量修改', 1761400000000011621, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variable', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011656, '流程实例激活/挂起', 1761400000000011621, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:active', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011657, '流程实例删除', 1761400000000011621, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011658, '流程实例作废', 1761400000000011621, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:invalid', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011659, '流程实例撤销', 1761400000000011621, 7, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:cancel', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); + +-- 流程定义管理相关按钮 +insert into sys_menu values (1761400000000011644, '流程定义查询', 1761400000000011620, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011645, '流程定义新增', 1761400000000011620, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011646, '流程定义修改', 1761400000000011620, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011647, '流程定义删除', 1761400000000011620, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011648, '流程定义导出', 1761400000000011620, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011649, '流程定义导入', 1761400000000011620, 6, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:import', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011650, '流程定义发布/取消发布', 1761400000000011620, 7, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:publish', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011651, '流程定义复制', 1761400000000011620, 8, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:copy', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); +insert into sys_menu values (1761400000000011652, '流程定义激活/挂起', 1761400000000011620, 9, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:active', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, ''); + +-- 流程表达式管理相关按钮 +INSERT INTO sys_menu VALUES (1761400000000011802, '流程达式定义查询', 1761400000000011801, 1, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011803, '流程达式定义新增', 1761400000000011801, 2, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011804, '流程达式定义修改', 1761400000000011801, 3, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011805, '流程达式定义删除', 1761400000000011801, 4, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES (1761400000000011806, '流程达式定义导出', 1761400000000011801, 5, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +-- 请假测试相关按钮 +insert into sys_menu VALUES (1761400000000011638, '请假申请', 1761400000000000005, 1, 'leave', 'workflow/leave/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:leave:list', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '请假申请菜单'); +insert into sys_menu VALUES (1761400000000011639, '请假申请查询', 1761400000000011638, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (1761400000000011640, '请假申请新增', 1761400000000011638, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:add', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (1761400000000011641, '请假申请修改', 1761400000000011638, 3, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (1761400000000011642, '请假申请删除', 1761400000000011638, 4, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (1761400000000011643, '请假申请导出', 1761400000000011638, 5, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (1761500000000000013, '业务状态', 'wf_business_status', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (1761500000000000014, '表单类型', 'wf_form_type', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (1761500000000000015, '任务状态', 'wf_task_status', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (1761600000000000039, 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data VALUES (1761600000000000040, 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (1761600000000000041, 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (1761600000000000042, 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '已完成'); +INSERT INTO sys_dict_data VALUES (1761600000000000043, 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '已作废'); +INSERT INTO sys_dict_data VALUES (1761600000000000044, 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '已退回'); +INSERT INTO sys_dict_data VALUES (1761600000000000045, 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (1761600000000000046, 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data VALUES (1761600000000000047, 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '动态表单'); +INSERT INTO sys_dict_data VALUES (1761600000000000048, 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (1761600000000000049, 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (1761600000000000050, 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (1761600000000000051, 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (1761600000000000052, 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (1761600000000000053, 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (1761600000000000054, 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (1761600000000000055, 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (1761600000000000056, 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (1761600000000000057, 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (1761600000000000058, 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (1761600000000000059, 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '超时'); + diff --git a/script/sql/sqlserver/sqlserver_ry_job.sql b/script/sql/sqlserver/sqlserver_ry_job.sql new file mode 100644 index 000000000..759c27afc --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_job.sql @@ -0,0 +1,2911 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : Microsoft SQL Server + Date: 2025-06-21 23:34:44 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(64) NOT NULL, + unique_id nvarchar(64) NOT NULL, + description nvarchar(256) NOT NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'唯一id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace' +GO + +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES (N'Development', N'dev', N'', 0, getdate(), getdate()) +GO +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES (N'Production', N'prod', N'', 0, getdate(), getdate()) +GO + +-- sj_group_config +CREATE TABLE sj_group_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + description nvarchar(256) NOT NULL DEFAULT '', + token nvarchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status tinyint NOT NULL DEFAULT 0, + version int NOT NULL, + group_partition int NOT NULL, + id_generator_mode tinyint NOT NULL DEFAULT 1, + init_scene tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'token', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'token' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'分区', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_partition' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'唯一id生成模式 默认号段模式', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'id_generator_mode' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否初始化场景 0:否 1:是', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'init_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config' +GO + +INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', getdate(), getdate()) +GO +INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, create_dt, update_dt) VALUES (N'prod', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', getdate(), getdate()) +GO + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + notify_name nvarchar(64) NOT NULL DEFAULT '', + system_task_type tinyint NOT NULL DEFAULT 3, + notify_status tinyint NOT NULL DEFAULT 0, + recipient_ids nvarchar(128) NOT NULL, + notify_threshold int NOT NULL DEFAULT 0, + notify_scene tinyint NOT NULL DEFAULT 0, + rate_limiter_status tinyint NOT NULL DEFAULT 0, + rate_limiter_threshold int NOT NULL DEFAULT 0, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收人id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'recipient_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知场景', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'限流状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'rate_limiter_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'每秒限流阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'rate_limiter_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config' +GO + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + recipient_name nvarchar(64) NOT NULL, + notify_type tinyint NOT NULL DEFAULT 0, + notify_attribute nvarchar(512) NOT NULL, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收人名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'recipient_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'notify_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'配置属性', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'notify_attribute' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'告警通知接收人', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient' +GO + +-- sj_retry_dead_letter +CREATE TABLE sj_retry_dead_letter +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + group_id bigint NOT NULL, + scene_name nvarchar(64) NOT NULL, + scene_id bigint NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + serializer_name nvarchar(32) NOT NULL DEFAULT 'jackson', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_retry_dead_letter_01 ON sj_retry_dead_letter (namespace_id, group_name, scene_name) +GO +CREATE INDEX idx_sj_retry_dead_letter_02 ON sj_retry_dead_letter (idempotent_id) +GO +CREATE INDEX idx_sj_retry_dead_letter_03 ON sj_retry_dead_letter (biz_no) +GO +CREATE INDEX idx_sj_retry_dead_letter_04 ON sj_retry_dead_letter (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组Id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'group_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景ID', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'scene_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数序列化器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'serializer_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'死信队列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter' +GO + +-- sj_retry +CREATE TABLE sj_retry +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + group_id bigint NOT NULL, + scene_name nvarchar(64) NOT NULL, + scene_id bigint NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + serializer_name nvarchar(32) NOT NULL DEFAULT 'jackson', + next_trigger_at bigint NOT NULL, + retry_count int NOT NULL DEFAULT 0, + retry_status tinyint NOT NULL DEFAULT 0, + task_type tinyint NOT NULL DEFAULT 1, + bucket_index int NOT NULL DEFAULT 0, + parent_id bigint NOT NULL DEFAULT 0, + deleted bigint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_01 ON sj_retry (scene_id, task_type, idempotent_id, deleted) +GO + +CREATE INDEX idx_sj_retry_01 ON sj_retry (biz_no) +GO +CREATE INDEX idx_sj_retry_02 ON sj_retry (idempotent_id) +GO +CREATE INDEX idx_sj_retry_03 ON sj_retry (retry_status, bucket_index) +GO +CREATE INDEX idx_sj_retry_04 ON sj_retry (parent_id) +GO +CREATE INDEX idx_sj_retry_05 ON sj_retry (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组Id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'group_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景ID', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'scene_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数序列化器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'serializer_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试状态 0、重试中 1、成功 2、最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'retry_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父节点id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试信息表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry' +GO + +-- sj_retry_task +CREATE TABLE sj_retry_task +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + retry_id bigint NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + task_status tinyint NOT NULL DEFAULT 1, + task_type tinyint NOT NULL DEFAULT 1, + operation_reason tinyint NOT NULL DEFAULT 0, + client_info nvarchar(128) NULL DEFAULT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_retry_task_01 ON sj_retry_task (namespace_id, group_name, scene_name) +GO +CREATE INDEX idx_sj_retry_task_02 ON sj_retry_task (task_status) +GO +CREATE INDEX idx_sj_retry_task_03 ON sj_retry_task (create_dt) +GO +CREATE INDEX idx_sj_retry_task_04 ON sj_retry_task (retry_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试信息Id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'retry_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试状态', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'task_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端地址 clientId#ip:port', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'client_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试任务表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task' +GO + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + retry_id bigint NOT NULL, + retry_task_id bigint NOT NULL, + message nvarchar(max) NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, retry_task_id) +GO +CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试信息Id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'retry_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试任务Id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'retry_task_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'log_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上报时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'real_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务调度日志信息记录表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message' +GO + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_status tinyint NOT NULL DEFAULT 0, + max_retry_count int NOT NULL DEFAULT 5, + back_off tinyint NOT NULL DEFAULT 1, + trigger_interval nvarchar(16) NOT NULL DEFAULT '', + notify_ids nvarchar(128) NOT NULL DEFAULT '', + deadline_request bigint NOT NULL DEFAULT 60000, + executor_timeout int NOT NULL DEFAULT 5, + route_key tinyint NOT NULL DEFAULT 4, + block_strategy tinyint NOT NULL DEFAULT 1, + cb_status tinyint NOT NULL DEFAULT 0, + cb_trigger_type tinyint NOT NULL DEFAULT 1, + cb_max_count int NOT NULL DEFAULT 16, + cb_trigger_interval nvarchar(16) NOT NULL DEFAULT '', + owner_id bigint NULL DEFAULT NULL, + labels nvarchar(512) NULL DEFAULT '', + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'scene_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'max_retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、默认等级 2、固定间隔时间 3、CRON 表达式', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'back_off' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'Deadline Request 调用链超时 单位毫秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'deadline_request' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由策略', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'route_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'回调状态 0、不开启 1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'cb_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、默认等级 2、固定间隔时间 3、CRON 表达式', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'cb_trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'回调的最大执行次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'cb_max_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'回调的最大执行次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'cb_trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'负责人id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'owner_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'标签', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'labels' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config' +GO + +-- sj_server_node +CREATE TABLE sj_server_node +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + host_id nvarchar(64) NOT NULL, + host_ip nvarchar(64) NOT NULL, + host_port int NOT NULL, + expire_at datetime2 NOT NULL, + node_type tinyint NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + labels nvarchar(512) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip) +GO + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name) +GO +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主机id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'机器ip', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'机器端口', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_port' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'expire_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点类型 1、客户端 2、是服务端', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'标签', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'labels' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'服务器节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node' +GO + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name nvarchar(64) NOT NULL PRIMARY KEY, + lock_until datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_by nvarchar(255) NOT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'lock_until' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'locked_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定者', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'locked_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock' +GO + +-- sj_system_user +CREATE TABLE sj_system_user +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + username nvarchar(64) NOT NULL, + password nvarchar(128) NOT NULL, + role tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'账号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'username' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'密码', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'password' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色:1-普通用户、2-管理员', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'role' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user' +GO + +INSERT INTO sj_system_user (username, password, role) +VALUES (N'admin', N'465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2) +GO + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + group_name nvarchar(64) NOT NULL, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + system_user_id bigint NOT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'system_user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户权限表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission' +GO + +-- sj_job +CREATE TABLE sj_job +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + biz_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + job_name nvarchar(64) NOT NULL, + args_str nvarchar(max) NULL DEFAULT NULL, + args_type tinyint NOT NULL DEFAULT 1, + next_trigger_at bigint NOT NULL, + job_status tinyint NOT NULL DEFAULT 1, + task_type tinyint NOT NULL DEFAULT 1, + route_key tinyint NOT NULL DEFAULT 4, + executor_type tinyint NOT NULL DEFAULT 1, + executor_info nvarchar(255) NULL DEFAULT NULL, + trigger_type tinyint NOT NULL, + trigger_interval nvarchar(255) NOT NULL, + block_strategy tinyint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + max_retry_times int NOT NULL DEFAULT 0, + parallel_num int NOT NULL DEFAULT 1, + retry_interval int NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + resident tinyint NOT NULL DEFAULT 0, + notify_ids nvarchar(128) NOT NULL DEFAULT '', + owner_id bigint NULL DEFAULT NULL, + labels nvarchar(512) NULL DEFAULT '', + description nvarchar(256) NOT NULL DEFAULT '', + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name) +GO +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index) +GO +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt) +GO +CREATE UNIQUE INDEX uk_sj_job_01 ON sj_job (namespace_id, biz_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务ID', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'biz_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'job_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'args_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'job_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、集群 2、广播 3、切片', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由策略', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'route_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'触发类型 1.CRON 表达式 2. 固定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行 4、恢复', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'max_retry_times' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'并行数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'parallel_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试间隔 ( s)', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'retry_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否是常驻任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'resident' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'负责人id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'owner_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'标签', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'labels' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job' +GO + +INSERT INTO sj_job (namespace_id, biz_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, notify_ids, owner_id, labels, description, ext_attrs, deleted, create_dt, update_dt) VALUES (N'dev', N'demo-job', N'ruoyi_group', N'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, N'testJobExecutor', 2, N'60', 1, 60, 3, 1, 1, 116, 0, N'', 1, N'', N'', N'', 0, getdate(), getdate()) +GO + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + task_id bigint NOT NULL, + message nvarchar(max) NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id) +GO +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt) +GO +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'task_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'log_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上报时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'real_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度日志', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message' +GO + +-- sj_job_task +CREATE TABLE sj_job_task +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + parent_id bigint NOT NULL DEFAULT 0, + task_status tinyint NOT NULL DEFAULT 0, + retry_count int NOT NULL DEFAULT 0, + mr_stage tinyint NULL DEFAULT NULL, + leaf tinyint NOT NULL DEFAULT '1', + task_name nvarchar(255) NOT NULL DEFAULT '', + client_info nvarchar(128) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + result_message nvarchar(max) NOT NULL, + args_str nvarchar(max) NULL DEFAULT NULL, + args_type tinyint NOT NULL DEFAULT 1, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status) +GO +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt) +GO +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父执行器id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行的状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'动态分片所处阶段 1:map 2:reduce 3:mergeReduce', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'mr_stage' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'叶子节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'leaf' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端地址 clientId#ip:port', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'client_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流全局上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行结果', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'result_message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'args_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务实例', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task' +GO + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_node_id bigint NOT NULL DEFAULT 0, + parent_workflow_node_id bigint NOT NULL DEFAULT 0, + workflow_task_batch_id bigint NOT NULL DEFAULT 0, + task_batch_status tinyint NOT NULL DEFAULT 0, + operation_reason tinyint NOT NULL DEFAULT 0, + execution_at bigint NOT NULL DEFAULT 0, + system_task_type tinyint NOT NULL DEFAULT 3, + parent_id nvarchar(64) NOT NULL DEFAULT '', + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status) +GO +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt) +GO +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name) +GO +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'workflow_node_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务父批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'parent_workflow_node_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'workflow_task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'task_batch_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'execution_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch' +GO + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + business_id bigint NOT NULL, + system_task_type tinyint NOT NULL DEFAULT 3, + trigger_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + success_num int NOT NULL DEFAULT 0, + fail_num int NOT NULL DEFAULT 0, + fail_reason nvarchar(512) NOT NULL DEFAULT '', + stop_num int NOT NULL DEFAULT 0, + stop_reason nvarchar(512) NOT NULL DEFAULT '', + cancel_num int NOT NULL DEFAULT 0, + cancel_reason nvarchar(512) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id) +GO + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务id ( job_id或workflow_id)', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'business_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'统计时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行成功-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'success_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'fail_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'fail_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'stop_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'stop_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'cancel_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'cancel_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'DashBoard_Job', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary' +GO + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + scene_name nvarchar(64) NOT NULL DEFAULT '', + trigger_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + running_num int NOT NULL DEFAULT 0, + finish_num int NOT NULL DEFAULT 0, + max_count_num int NOT NULL DEFAULT 0, + suspend_num int NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at) +GO + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'统计时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试中-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'running_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试完成-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'finish_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试到达最大次数-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'max_count_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'暂停重试-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'suspend_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'DashBoard_Retry', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary' +GO + +-- sj_workflow +CREATE TABLE sj_workflow +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + workflow_name nvarchar(64) NOT NULL, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + biz_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + workflow_status tinyint NOT NULL DEFAULT 1, + trigger_type tinyint NOT NULL, + trigger_interval nvarchar(255) NOT NULL, + next_trigger_at bigint NOT NULL, + block_strategy tinyint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + description nvarchar(256) NOT NULL DEFAULT '', + flow_info nvarchar(max) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + notify_ids nvarchar(128) NOT NULL DEFAULT '', + bucket_index int NOT NULL DEFAULT 0, + version int NOT NULL, + owner_id bigint NULL DEFAULT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt) +GO +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name) +GO +CREATE UNIQUE INDEX uk_sj_workflow_01 ON sj_workflow (namespace_id, biz_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'workflow_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务ID', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'biz_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'workflow_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'触发类型 1.CRON 表达式 2. 固定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'flow_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'负责人id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'owner_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow' +GO + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_id bigint NOT NULL, + node_type tinyint NOT NULL DEFAULT 1, + expression_type tinyint NOT NULL DEFAULT 0, + fail_strategy tinyint NOT NULL DEFAULT 1, + workflow_node_status tinyint NOT NULL DEFAULT 1, + priority_level int NOT NULL DEFAULT 1, + node_info nvarchar(max) NULL DEFAULT NULL, + version int NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt) +GO +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流ID', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'workflow_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、任务节点 2、条件节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、SpEl、2、Aviator 3、QL', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'expression_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败策略 1、跳过 2、阻塞', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'fail_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'workflow_node_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'优先级', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'priority_level' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点信息 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node' +GO + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + workflow_id bigint NOT NULL, + task_batch_status tinyint NOT NULL DEFAULT 0, + operation_reason tinyint NOT NULL DEFAULT 0, + flow_info nvarchar(max) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + execution_at bigint NOT NULL DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '', + version int NOT NULL DEFAULT 1, + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status) +GO +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt) +GO +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'workflow_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'task_batch_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'flow_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'全局上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'execution_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流批次', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch' +GO + +-- sj_job_executor +CREATE TABLE sj_job_executor +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + executor_info nvarchar(256) NOT NULL, + executor_type nvarchar(3) NOT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_executor_01 ON sj_job_executor (namespace_id, group_name) +GO +CREATE INDEX idx_sj_job_executor_02 ON sj_job_executor (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_executor', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_executor', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_executor', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_executor', + 'COLUMN', N'executor_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1:java 2:python 3:go', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_executor', + 'COLUMN', N'executor_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_executor', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_executor', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行器信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_executor' +GO diff --git a/script/sql/sqlserver/sqlserver_ry_vue.sql b/script/sql/sqlserver/sqlserver_ry_vue.sql new file mode 100644 index 000000000..c77b125e8 --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_vue.sql @@ -0,0 +1,3473 @@ +create table sys_social +( + id bigint NOT NULL, + user_id bigint NOT NULL, + auth_id nvarchar(255) NOT NULL, + source nvarchar(255) NOT NULL, + open_id nvarchar(255) NULL, + user_name nvarchar(30) NOT NULL, + nick_name nvarchar(30) DEFAULT ('') NULL, + email nvarchar(255) DEFAULT ('') NULL, + avatar nvarchar(500) DEFAULT ('') NULL, + access_token nvarchar(2000) NOT NULL, + expire_in bigint NULL, + refresh_token nvarchar(2000) NULL, + access_code nvarchar(255) NULL, + union_id nvarchar(255) NULL, + scope nvarchar(255) NULL, + token_type nvarchar(255) NULL, + id_token nvarchar(2000) NULL, + mac_algorithm nvarchar(255) NULL, + mac_key nvarchar(255) NULL, + code nvarchar(255) NULL, + oauth_token nvarchar(255) NULL, + oauth_token_secret nvarchar(255) NULL, + create_dept bigint, + create_by bigint, + create_time datetime2(7), + update_by bigint, + update_time datetime2(7), + del_flag nchar DEFAULT ('0') NULL, + CONSTRAINT PK__sys_social__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台+平台唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'auth_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户来源' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'source' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台编号唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'open_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户昵称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'nick_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'头像地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'avatar' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌的有效期,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'expire_in' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'刷新令牌,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'refresh_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的 unionid' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'union_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'授予的权限,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'scope' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'个别平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'token_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id token,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_algorithm' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权code,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token_secret' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'社会化关系表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social' +GO + + +CREATE TABLE gen_table +( + table_id bigint NOT NULL, + data_name nvarchar(200) DEFAULT '' NULL, + table_name nvarchar(200) DEFAULT '' NULL, + table_comment nvarchar(500) DEFAULT '' NULL, + class_name nvarchar(100) DEFAULT '' NULL, + tpl_category nvarchar(200) DEFAULT ('crud') NULL, + frontend_type nvarchar(50) DEFAULT ('vue') NULL, + package_name nvarchar(100) NULL, + module_name nvarchar(30) NULL, + business_name nvarchar(30) NULL, + function_name nvarchar(50) NULL, + function_author nvarchar(50) NULL, + gen_type nchar(1) DEFAULT ('0') NULL, + gen_path nvarchar(200) DEFAULT ('/') NULL, + options nvarchar(1000) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__gen_tabl__B21E8F2427725F8A PRIMARY KEY CLUSTERED (table_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'数据源名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'data_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表描述' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_comment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'实体类名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'class_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'使用的模板(crud单表操作 tree树表操作)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'tpl_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'前端模板类型,对应 vm 下的模板目录' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'frontend_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成包路径' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'package_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成模块名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'module_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成业务名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'business_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成功能名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'function_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成功能作者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'function_author' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成代码方式(0zip压缩包 1自定义路径)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'gen_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成路径(不填默认项目路径)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'gen_path' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'其它生成选项' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'options' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'代码生成业务表' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table' +GO + +CREATE TABLE gen_table_column +( + column_id bigint NOT NULL, + table_id bigint NULL, + column_name nvarchar(200) NULL, + column_comment nvarchar(500) NULL, + column_type nvarchar(100) NULL, + java_type nvarchar(500) NULL, + java_field nvarchar(200) NULL, + is_pk nchar(1) NULL, + is_increment nchar(1) NULL, + is_required nchar(1) NULL, + is_insert nchar(1) NULL, + is_edit nchar(1) NULL, + is_list nchar(1) NULL, + is_query nchar(1) NULL, + query_type nvarchar(200) DEFAULT ('EQ') NULL, + html_type nvarchar(200) NULL, + dict_type nvarchar(200) DEFAULT '' NULL, + sort int NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__gen_tabl__E301851F2E68B4E8 PRIMARY KEY CLUSTERED (column_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'归属表编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'table_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列描述' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_comment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'JAVA类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'java_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'JAVA字段名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'java_field' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否主键(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_pk' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否自增(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_increment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否必填(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_required' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否为插入字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_insert' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否编辑字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_edit' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否列表字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_list' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否查询字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_query' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'查询方式(等于、不等于、大于、小于、范围)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'query_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'html_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'排序' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'代码生成业务表字段' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column' +GO + +CREATE TABLE sys_config +( + config_id bigint NOT NULL, + config_name nvarchar(100) DEFAULT '' NULL, + config_key nvarchar(100) DEFAULT '' NULL, + config_value nvarchar(500) DEFAULT '' NULL, + config_type nchar(1) DEFAULT ('N') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_conf__4AD1BFF182643682 PRIMARY KEY CLUSTERED (config_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数键名' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数键值' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_value' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'系统内置(Y是 N否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数配置表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config' +GO + +INSERT sys_config VALUES (1761700000000000001, N'用户管理-账号初始密码', N'sys.user.initPassword', N'123456', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'初始化密码 123456') +GO +INSERT sys_config VALUES (1761700000000000002, N'账号自助-是否开启用户注册功能', N'sys.account.registerUser', N'false', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'是否开启注册用户功能(true开启,false关闭)') +GO +INSERT sys_config VALUES (1761700000000000003, N'OSS预览列表资源开关', N'sys.oss.previewListResource', N'true', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'true:开启, false:关闭'); +GO + +CREATE TABLE sys_dept +( + dept_id bigint NOT NULL, + parent_id bigint DEFAULT ((0)) NULL, + ancestors nvarchar(500)DEFAULT '' NULL, + dept_name nvarchar(30) NULL, + dept_category nvarchar(100) DEFAULT '' NULL, + order_num int DEFAULT ((0)) NULL, + leader bigint NULL, + phone nvarchar(11) NULL, + email nvarchar(50) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__sys_dept__DCA659747DE13804 PRIMARY KEY CLUSTERED (dept_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_dept_parent_id ON sys_dept (parent_id) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'父部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'parent_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'祖级列表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'ancestors' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门类别编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'order_num' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'负责人' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'leader' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'联系电话' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'phone' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept' +GO + +INSERT sys_dept VALUES (1761000000000000100, 0, N'0', N'XXX科技', NULL, 0, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000101, 1761000000000000100, N'0,1761000000000000100', N'深圳总公司', NULL, 1, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000102, 1761000000000000100, N'0,1761000000000000100', N'长沙分公司', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000103, 1761000000000000101, N'0,1761000000000000100,1761000000000000101', N'研发部门', NULL, 1, 1761100000000000001, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000104, 1761000000000000101, N'0,1761000000000000100,1761000000000000101', N'市场部门', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000105, 1761000000000000101, N'0,1761000000000000100,1761000000000000101', N'测试部门', NULL, 3, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000106, 1761000000000000101, N'0,1761000000000000100,1761000000000000101', N'财务部门', NULL, 4, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000107, 1761000000000000101, N'0,1761000000000000100,1761000000000000101', N'运维部门', NULL, 5, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000108, 1761000000000000102, N'0,1761000000000000100,1761000000000000102', N'市场部门', NULL, 1, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (1761000000000000109, 1761000000000000102, N'0,1761000000000000100,1761000000000000102', N'财务部门', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL) +GO + +CREATE TABLE sys_dict_data +( + dict_code bigint NOT NULL, + dict_sort int DEFAULT ((0)) NULL, + dict_label nvarchar(100) DEFAULT '' NULL, + dict_value nvarchar(100) DEFAULT '' NULL, + dict_type nvarchar(100) DEFAULT '' NULL, + css_class nvarchar(100) NULL, + list_class nvarchar(100) NULL, + is_default nchar(1) DEFAULT ('N') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_dict__19CBC34B661AF3B3 PRIMARY KEY CLUSTERED (dict_code) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_dict_data_type ON sys_dict_data (dict_type) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典排序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典标签' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_label' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典键值' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_value' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'样式属性(其他样式扩展)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'css_class' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表格回显样式' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'list_class' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否默认(Y是 N否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'is_default' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典数据表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data' +GO + +INSERT sys_dict_data VALUES (1761600000000000001, 1, N'男', N'0', N'sys_user_gender', N'', N'', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'性别男') +GO +INSERT sys_dict_data VALUES (1761600000000000002, 2, N'女', N'1', N'sys_user_gender', N'', N'', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'性别女') +GO +INSERT sys_dict_data VALUES (1761600000000000003, 3, N'未知', N'2', N'sys_user_gender', N'', N'', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'性别未知') +GO +INSERT sys_dict_data VALUES (1761600000000000004, 1, N'显示', N'0', N'sys_show_hide', N'', N'primary', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'显示菜单') +GO +INSERT sys_dict_data VALUES (1761600000000000005, 2, N'隐藏', N'1', N'sys_show_hide', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'隐藏菜单') +GO +INSERT sys_dict_data VALUES (1761600000000000006, 1, N'正常', N'0', N'sys_normal_disable', N'', N'primary', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (1761600000000000007, 2, N'停用', N'1', N'sys_normal_disable', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (1761600000000000008, 1, N'正常', N'0', N'sys_job_status', N'', N'primary', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (1761600000000000009, 2, N'暂停', N'1', N'sys_job_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (1761600000000000010, 1, N'默认', N'DEFAULT', N'sys_job_group', N'', N'', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'默认分组') +GO +INSERT sys_dict_data VALUES (1761600000000000011, 2, N'系统', N'SYSTEM', N'sys_job_group', N'', N'', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'系统分组') +GO +INSERT sys_dict_data VALUES (1761600000000000012, 1, N'是', N'Y', N'sys_yes_no', N'', N'primary', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'系统默认是') +GO +INSERT sys_dict_data VALUES (1761600000000000013, 2, N'否', N'N', N'sys_yes_no', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'系统默认否') +GO +INSERT sys_dict_data VALUES (1761600000000000014, 1, N'通知', N'1', N'sys_notice_type', N'', N'warning', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'通知') +GO +INSERT sys_dict_data VALUES (1761600000000000015, 2, N'公告', N'2', N'sys_notice_type', N'', N'success', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'公告') +GO +INSERT sys_dict_data VALUES (1761600000000000016, 1, N'正常', N'0', N'sys_notice_status', N'', N'primary', N'Y', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (1761600000000000017, 2, N'关闭', N'1', N'sys_notice_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'关闭状态') +GO +INSERT sys_dict_data VALUES (1761600000000000029, 99, N'其他', N'0', N'sys_oper_type', N'', N'info', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'其他操作'); +GO +INSERT sys_dict_data VALUES (1761600000000000018, 1, N'新增', N'1', N'sys_oper_type', N'', N'info', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'新增操作') +GO +INSERT sys_dict_data VALUES (1761600000000000019, 2, N'修改', N'2', N'sys_oper_type', N'', N'info', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'修改操作') +GO +INSERT sys_dict_data VALUES (1761600000000000020, 3, N'删除', N'3', N'sys_oper_type', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'删除操作') +GO +INSERT sys_dict_data VALUES (1761600000000000021, 4, N'授权', N'4', N'sys_oper_type', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'授权操作') +GO +INSERT sys_dict_data VALUES (1761600000000000022, 5, N'导出', N'5', N'sys_oper_type', N'', N'warning', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'导出操作') +GO +INSERT sys_dict_data VALUES (1761600000000000023, 6, N'导入', N'6', N'sys_oper_type', N'', N'warning', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'导入操作') +GO +INSERT sys_dict_data VALUES (1761600000000000024, 7, N'强退', N'7', N'sys_oper_type', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'强退操作') +GO +INSERT sys_dict_data VALUES (1761600000000000025, 8, N'生成代码', N'8', N'sys_oper_type', N'', N'warning', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'生成操作') +GO +INSERT sys_dict_data VALUES (1761600000000000026, 9, N'清空数据', N'9', N'sys_oper_type', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'清空操作') +GO +INSERT sys_dict_data VALUES (1761600000000000027, 1, N'成功', N'0', N'sys_common_status', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (1761600000000000028, 2, N'失败', N'1', N'sys_common_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (1761600000000000030, 0, N'密码认证', N'password', N'sys_grant_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'密码认证') +GO +INSERT sys_dict_data VALUES (1761600000000000031, 0, N'短信认证', N'sms', N'sys_grant_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'短信认证') +GO +INSERT sys_dict_data VALUES (1761600000000000032, 0, N'邮件认证', N'email', N'sys_grant_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'邮件认证') +GO +INSERT sys_dict_data VALUES (1761600000000000033, 0, N'小程序认证', N'xcx', N'sys_grant_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'小程序认证') +GO +INSERT sys_dict_data VALUES (1761600000000000034, 0, N'三方登录认证', N'social', N'sys_grant_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'三方登录认证') +GO +INSERT sys_dict_data VALUES (1761600000000000035, 0, N'PC', N'pc', N'sys_device_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'PC') +GO +INSERT sys_dict_data VALUES (1761600000000000036, 0, N'安卓', N'android', N'sys_device_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'安卓') +GO +INSERT sys_dict_data VALUES (1761600000000000037, 0, N'iOS', N'ios', N'sys_device_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'iOS') +GO +INSERT sys_dict_data VALUES (1761600000000000038, 0, N'小程序', N'xcx', N'sys_device_type', N'', N'default', N'N', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'小程序') +GO + +CREATE TABLE sys_dict_type +( + dict_id bigint NOT NULL, + dict_name nvarchar(100) DEFAULT '' NULL, + dict_type nvarchar(100) DEFAULT '' NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_dict__3BD4186C409C5391 PRIMARY KEY CLUSTERED (dict_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX sys_dict_type_index1 ON sys_dict_type (dict_type) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type' +GO + +INSERT sys_dict_type VALUES (1761500000000000001, N'用户性别', N'sys_user_gender', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'用户性别列表') +GO +INSERT sys_dict_type VALUES (1761500000000000002, N'菜单状态', N'sys_show_hide', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'菜单状态列表') +GO +INSERT sys_dict_type VALUES (1761500000000000003, N'系统开关', N'sys_normal_disable', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'系统开关列表') +GO +INSERT sys_dict_type VALUES (1761500000000000004, N'任务状态', N'sys_job_status', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'任务状态列表') +GO +INSERT sys_dict_type VALUES (1761500000000000005, N'任务分组', N'sys_job_group', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'任务分组列表') +GO +INSERT sys_dict_type VALUES (1761500000000000006, N'系统是否', N'sys_yes_no', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'系统是否列表') +GO +INSERT sys_dict_type VALUES (1761500000000000007, N'通知类型', N'sys_notice_type', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'通知类型列表') +GO +INSERT sys_dict_type VALUES (1761500000000000008, N'通知状态', N'sys_notice_status', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'通知状态列表') +GO +INSERT sys_dict_type VALUES (1761500000000000009, N'操作类型', N'sys_oper_type', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'操作类型列表') +GO +INSERT sys_dict_type VALUES (1761500000000000010, N'系统状态', N'sys_common_status', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'登录状态列表') +GO +INSERT sys_dict_type VALUES (1761500000000000011, N'授权类型', N'sys_grant_type', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'认证授权类型') +GO +INSERT sys_dict_type VALUES (1761500000000000012, N'设备类型', N'sys_device_type', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'客户端设备类型') +GO + +CREATE TABLE sys_login_info +( + info_id bigint NOT NULL, + user_name nvarchar(50) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + ipaddr nvarchar(128) DEFAULT '' NULL, + login_location nvarchar(255) DEFAULT '' NULL, + browser nvarchar(50) DEFAULT '' NULL, + os nvarchar(50) DEFAULT '' NULL, + status nchar(1) DEFAULT ('0') NULL, + msg nvarchar(255) DEFAULT '' NULL, + login_time datetime2(7) NULL, + CONSTRAINT PK__sys_logi__3D8A9C1A1854AE10 PRIMARY KEY CLUSTERED (info_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_login_info_s ON sys_login_info (status) +GO +CREATE NONCLUSTERED INDEX idx_sys_login_info_lt ON sys_login_info (login_time) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'访问ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'info_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'客户端' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'client_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'设备类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'device_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录IP地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'ipaddr' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录地点' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'login_location' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'浏览器类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'browser' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作系统' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'os' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录状态(0正常 1异常)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'提示消息' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'msg' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'访问时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info', + 'COLUMN', N'login_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'系统访问记录' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_login_info' +GO + +CREATE TABLE sys_menu +( + menu_id bigint NOT NULL, + menu_name nvarchar(50) NOT NULL, + parent_id bigint DEFAULT ((0)) NULL, + order_num int DEFAULT ((0)) NULL, + path nvarchar(200) DEFAULT '' NULL, + component nvarchar(255) NULL, + query_param nvarchar(255) NULL, + is_frame nchar(1) DEFAULT ('N') NULL, + is_cache nchar(1) DEFAULT ('Y') NULL, + menu_type nchar(1) DEFAULT '' NULL, + visible nchar(1) DEFAULT ((0)) NULL, + status nchar(1) DEFAULT ((0)) NULL, + perms nvarchar(100) NULL, + icon nvarchar(100) DEFAULT ('#') NULL, + active_menu nvarchar(255) DEFAULT '' NULL, + ext nvarchar(2000) DEFAULT '' NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) DEFAULT '' NULL, + CONSTRAINT PK__sys_menu__4CA0FADCF8545C58 PRIMARY KEY CLUSTERED (menu_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'父菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'parent_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'order_num' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'路由地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'path' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'组件路径' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'component' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'路由参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'query_param' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否为外链(Y是 N否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'is_frame' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否缓存(Y缓存 N不缓存)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'is_cache' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单类型(M目录 C菜单 F按钮)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示状态(0显示 1隐藏)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'visible' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'权限标识' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'perms' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单图标' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'icon' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'激活菜单路径' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'active_menu' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'扩展字段' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'ext' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单权限表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu' +GO + +insert into sys_menu values(1761400000000000001, N'系统管理', 0, 1, N'system', NULL, N'', N'N', N'Y', N'M', N'0', N'0', N'', N'system', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'系统管理目录'); +GO +insert into sys_menu values(1761400000000000002, N'系统监控', 0, 3, N'monitor', NULL, N'', N'N', N'Y', N'M', N'0', N'0', N'', N'monitor', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'系统监控目录'); +GO +insert into sys_menu values(1761400000000000003, N'系统工具', 0, 4, N'tool', NULL, N'', N'N', N'Y', N'M', N'0', N'0', N'', N'tool', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'系统工具目录'); +GO +insert into sys_menu values(1761400000000000005, N'测试菜单', 0, 5, N'demo', NULL, N'', N'N', N'Y', N'M', N'0', N'0', NULL, N'star', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000000006, N'AI会话', 0, 8, N'aichat', N'ai/chat/index', N'', N'N', N'Y', N'C', N'0', N'0', N'', N'checkbox', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'AI聊天菜单'); +GO +insert into sys_menu values(1761400000000000004, N'PLUS官网', 0, 9, N'https://gitee.com/dromara/RuoYi-Vue-Plus', null, N'', N'Y', N'Y', N'M', N'0', N'0', N'', N'guide', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), null, null, N'RuoYi-Vue-Plus官网地址'); +GO +insert into sys_menu values(1761400000000000100, N'用户管理', 1761400000000000001, 1, N'user', N'system/user/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:user:list', N'user', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'用户管理菜单'); +GO +insert into sys_menu values(1761400000000000101, N'角色管理', 1761400000000000001, 2, N'role', N'system/role/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:role:list', N'peoples', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'角色管理菜单'); +GO +insert into sys_menu values(1761400000000000102, N'菜单管理', 1761400000000000001, 3, N'menu', N'system/menu/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:menu:list', N'tree-table', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'菜单管理菜单'); +GO +insert into sys_menu values(1761400000000000103, N'部门管理', 1761400000000000001, 4, N'dept', N'system/dept/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:dept:list', N'tree', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'部门管理菜单'); +GO +insert into sys_menu values(1761400000000000104, N'岗位管理', 1761400000000000001, 5, N'post', N'system/post/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:post:list', N'post', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'岗位管理菜单'); +GO +insert into sys_menu values(1761400000000000105, N'字典管理', 1761400000000000001, 6, N'dict', N'system/dict/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:dict:list', N'dict', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'字典管理菜单'); +GO +insert into sys_menu values(1761400000000000106, N'参数设置', 1761400000000000001, 7, N'config', N'system/config/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:config:list', N'edit', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'参数设置菜单'); +GO +insert into sys_menu values(1761400000000000107, N'通知公告', 1761400000000000001, 8, N'notice', N'system/notice/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:notice:list', N'message', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'通知公告菜单'); +GO +insert into sys_menu values(1761400000000000108, N'日志管理', 1761400000000000001, 9, N'log', N'', N'', N'N', N'Y', N'M', N'0', N'0', N'', N'log', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'日志管理菜单'); +GO +insert into sys_menu values(1761400000000000109, N'在线用户', 1761400000000000002, 1, N'online', N'monitor/online/index', N'', N'N', N'Y', N'C', N'0', N'0', N'monitor:online:list', N'online', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'在线用户菜单'); +GO +insert into sys_menu values(1761400000000000113, N'缓存监控', 1761400000000000002, 5, N'cache', N'monitor/cache/index', N'', N'N', N'Y', N'C', N'0', N'0', N'monitor:cache:list', N'redis', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'缓存监控菜单'); +GO +insert into sys_menu values(1761400000000000115, N'代码生成', 1761400000000000003, 2, N'gen', N'tool/gen/index', N'', N'N', N'Y', N'C', N'0', N'0', N'tool:gen:list', N'code', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'代码生成菜单'); +GO +insert into sys_menu values(1761400000000000123, N'客户端管理', 1761400000000000001, 11, N'client', N'system/client/index', N'', N'N', N'Y', N'C', N'0', N'0', N'system:client:list', N'international', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'客户端管理菜单'); +GO +insert into sys_menu values(1761400000000000116, N'修改生成配置', 1761400000000000003, 2, N'gen-edit/index/:tableId', N'tool/gen/editTable', N'', N'N', N'N', N'C', N'1', N'0', N'tool:gen:edit', N'#', N'/tool/gen', N'', 1761000000000000103, 1761100000000000001, getdate(), null, null, N''); +GO +insert into sys_menu values(1761400000000000130, N'分配用户', 1761400000000000001, 2, N'role-auth/user/:roleId', N'system/role/authUser', N'', N'N', N'N', N'C', N'1', N'0', N'system:role:edit', N'#', N'/system/role', N'', 1761000000000000103, 1761100000000000001, getdate(), null, null, N''); +GO +insert into sys_menu values(1761400000000000131, N'分配角色', 1761400000000000001, 1, N'user-auth/role/:userId', N'system/user/authRole', N'', N'N', N'N', N'C', N'1', N'0', N'system:user:edit', N'#', N'/system/user', N'', 1761000000000000103, 1761100000000000001, getdate(), null, null, N''); +GO +insert into sys_menu values(1761400000000000133, N'文件配置管理', 1761400000000000001, 10, N'oss-config/index', N'system/oss/config', N'', N'N', N'N', N'C', N'1', N'0', N'system:ossConfig:list', N'#', N'/system/oss', N'', 1761000000000000103, 1761100000000000001, getdate(), null, null, N''); +GO + +insert into sys_menu values(1761400000000000117, N'Admin监控', 1761400000000000002, 5, N'Admin', N'monitor/admin/index', N'', N'N', N'Y', N'C', N'0', N'0', N'monitor:admin:list', N'dashboard', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'Admin监控菜单'); +GO +insert into sys_menu values(1761400000000000118, N'文件管理', 1761400000000000001, 10, N'oss', N'system/oss/index', N'', N'N', N'Y', N'C', '0', N'0', N'system:oss:list', N'upload', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'文件管理菜单'); +GO +insert into sys_menu values(1761400000000000120, N'任务调度中心', 1761400000000000002, 5, N'snailjob', N'monitor/snailjob/index', N'', N'N', N'Y', N'C', N'0', N'0', N'monitor:snailjob:list', N'job', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'SnailJob控制台菜单'); +GO +insert into sys_menu values(1761400000000000121, N'AI控制台', 1761400000000000002, 7, N'snailai', N'monitor/snailai/index', N'', N'N', N'Y', N'C', N'0', N'0', N'monitor:snailai:list', N'checkbox', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'AI控制台菜单'); +GO +insert into sys_menu values(1761400000000000500, N'操作日志', 1761400000000000108, 1, N'operlog', N'monitor/operlog/index', N'', N'N', N'Y', N'C', N'0', N'0', N'monitor:operlog:list', N'form', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'操作日志菜单'); +GO +insert into sys_menu values(1761400000000000501, N'登录日志', 1761400000000000108, 2, N'logininfo', N'monitor/logininfo/index', N'', N'N', N'Y', N'C', N'0', N'0', N'monitor:logininfo:list', N'logininfo', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'登录日志菜单'); +GO +insert into sys_menu values(1761400000000001001, N'用户查询', 1761400000000000100, 1, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:user:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001002, N'用户新增', 1761400000000000100, 2, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:user:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001003, N'用户修改', 1761400000000000100, 3, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:user:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001004, N'用户删除', 1761400000000000100, 4, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:user:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001005, N'用户导出', 1761400000000000100, 5, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:user:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001006, N'用户导入', 1761400000000000100, 6, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:user:import', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001007, N'重置密码', 1761400000000000100, 7, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:user:resetPwd', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001008, N'角色查询', 1761400000000000101, 1, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:role:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001009, N'角色新增', 1761400000000000101, 2, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:role:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001010, N'角色修改', 1761400000000000101, 3, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:role:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001011, N'角色删除', 1761400000000000101, 4, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:role:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001012, N'角色导出', 1761400000000000101, 5, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:role:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001013, N'菜单查询', 1761400000000000102, 1, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:menu:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001014, N'菜单新增', 1761400000000000102, 2, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:menu:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001015, N'菜单修改', 1761400000000000102, 3, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:menu:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001016, N'菜单删除', 1761400000000000102, 4, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:menu:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001017, N'部门查询', 1761400000000000103, 1, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dept:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001018, N'部门新增', 1761400000000000103, 2, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dept:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001019, N'部门修改', 1761400000000000103, 3, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dept:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001020, N'部门删除', 1761400000000000103, 4, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dept:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001021, N'岗位查询', 1761400000000000104, 1, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:post:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001022, N'岗位新增', 1761400000000000104, 2, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:post:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001023, N'岗位修改', 1761400000000000104, 3, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:post:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001024, N'岗位删除', 1761400000000000104, 4, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:post:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001025, N'岗位导出', 1761400000000000104, 5, N'', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:post:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001026, N'字典查询', 1761400000000000105, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dict:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001027, N'字典新增', 1761400000000000105, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dict:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001028, N'字典修改', 1761400000000000105, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dict:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001029, N'字典删除', 1761400000000000105, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dict:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001030, N'字典导出', 1761400000000000105, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:dict:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001031, N'参数查询', 1761400000000000106, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:config:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001032, N'参数新增', 1761400000000000106, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:config:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001033, N'参数修改', 1761400000000000106, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:config:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001034, N'参数删除', 1761400000000000106, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:config:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001035, N'参数导出', 1761400000000000106, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:config:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001036, N'公告查询', 1761400000000000107, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:notice:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001037, N'公告新增', 1761400000000000107, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:notice:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001038, N'公告修改', 1761400000000000107, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:notice:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001039, N'公告删除', 1761400000000000107, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:notice:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001040, N'操作查询', 1761400000000000500, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:operlog:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001041, N'操作删除', 1761400000000000500, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:operlog:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001042, N'日志导出', 1761400000000000500, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:operlog:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001043, N'登录查询', 1761400000000000501, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:logininfo:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001044, N'登录删除', 1761400000000000501, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:logininfo:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001045, N'日志导出', 1761400000000000501, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:logininfo:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001050, N'账户解锁', 1761400000000000501, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:logininfo:unlock', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001046, N'在线查询', 1761400000000000109, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:online:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001047, N'批量强退', 1761400000000000109, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:online:batchLogout', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001048, N'单条强退', 1761400000000000109, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'monitor:online:forceLogout', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001055, N'生成查询', 1761400000000000115, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'tool:gen:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001056, N'生成修改', 1761400000000000115, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'tool:gen:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001057, N'生成删除', 1761400000000000115, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'tool:gen:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001058, N'导入代码', 1761400000000000115, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'tool:gen:import', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001059, N'预览代码', 1761400000000000115, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'tool:gen:preview', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001060, N'生成代码', 1761400000000000115, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'tool:gen:code', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +-- oss相关按钮 +insert into sys_menu values(1761400000000001600, N'文件查询', 1761400000000000118, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:oss:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001601, N'文件上传', 1761400000000000118, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:oss:upload', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001602, N'文件下载', 1761400000000000118, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:oss:download', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001603, N'文件删除', 1761400000000000118, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:oss:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001620, N'配置列表', 1761400000000000118, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:ossConfig:list', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001621, N'配置添加', 1761400000000000118, 6, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:ossConfig:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001622, N'配置编辑', 1761400000000000118, 6, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:ossConfig:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001623, N'配置删除', 1761400000000000118, 6, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:ossConfig:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +-- 客户端管理按钮 +insert into sys_menu values(1761400000000001061, N'客户端管理查询', 1761400000000000123, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:client:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001062, N'客户端管理新增', 1761400000000000123, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:client:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001063, N'客户端管理修改', 1761400000000000123, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:client:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001064, N'客户端管理删除', 1761400000000000123, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:client:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001065, N'客户端管理导出', 1761400000000000123, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'system:client:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +-- 测试菜单 +insert into sys_menu values(1761400000000001500, N'测试单表', 1761400000000000005, 1, N'demo', N'demo/demo/index', N'', N'N', N'Y', N'C', N'0', N'0', N'demo:demo:list', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'测试单表菜单'); +GO +insert into sys_menu values(1761400000000001501, N'测试单表查询', 1761400000000001500, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:demo:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001502, N'测试单表新增', 1761400000000001500, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:demo:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001503, N'测试单表修改', 1761400000000001500, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:demo:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001504, N'测试单表删除', 1761400000000001500, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:demo:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001505, N'测试单表导出', 1761400000000001500, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:demo:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO + +insert into sys_menu values(1761400000000001506, N'测试树表', 1761400000000000005, 1, N'tree', N'demo/tree/index', N'', N'N', N'Y', N'C', N'0', N'0', N'demo:tree:list', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'测试树表菜单'); +GO +insert into sys_menu values(1761400000000001507, N'测试树表查询', 1761400000000001506, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:tree:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001508, N'测试树表新增', 1761400000000001506, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:tree:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001509, N'测试树表修改', 1761400000000001506, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:tree:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001510, N'测试树表删除', 1761400000000001506, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:tree:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +insert into sys_menu values(1761400000000001511, N'测试树表导出', 1761400000000001506, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'demo:tree:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO + +CREATE TABLE sys_notice +( + notice_id bigint NOT NULL, + notice_title nvarchar(50) NOT NULL, + notice_type nchar(1) NOT NULL, + notice_content nvarchar(max) NULL, + status nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(255) NULL, + CONSTRAINT PK__sys_noti__3E82A5DB0EC94801 PRIMARY KEY CLUSTERED (notice_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +TEXTIMAGE_ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告标题' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_title' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告类型(1通知 2公告)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告内容' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_content' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告状态(0正常 1关闭)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'通知公告表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice' +GO + +INSERT sys_notice VALUES (1761800000000000001, N'温馨提醒:2018-07-01 若依新版本发布啦', N'2', N'新版本内容', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'管理员') +GO +INSERT sys_notice VALUES (1761800000000000002, N'维护通知:2018-07-01 若依系统凌晨维护', N'1', N'维护内容', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'管理员') +GO + +CREATE TABLE sys_message +( + message_id bigint NOT NULL, + category nvarchar(20) NOT NULL, + type nvarchar(20) NOT NULL, + source nvarchar(20) NOT NULL, + title nvarchar(100) DEFAULT ('') NULL, + message nvarchar(500) DEFAULT ('') NULL, + content nvarchar(max) NULL, + data_json nvarchar(max) NULL, + path nvarchar(500) NULL, + send_user_ids nvarchar(2000) DEFAULT ('0') NOT NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__sys_mess__0BBF6EE69F35486A PRIMARY KEY CLUSTERED (message_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +TEXTIMAGE_ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_message_category_time ON sys_message(category, create_time) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'消息ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'message_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'消息分组(system/notice/workflow)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'消息类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'消息来源' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'source' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'标题' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'title' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'摘要消息' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'message' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'详细内容' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'content' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'扩展数据JSON' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'data_json' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'前端跳转路径' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'path' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'目标用户ID串,0表示全局' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'send_user_ids' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'消息记录表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_message' +GO + +CREATE TABLE sys_oper_log +( + oper_id bigint NOT NULL, + title nvarchar(50) DEFAULT '' NULL, + business_type int DEFAULT ((0)) NULL, + method nvarchar(100) DEFAULT '' NULL, + request_method nvarchar(10) DEFAULT '' NULL, + operator_type int DEFAULT ((0)) NULL, + oper_name nvarchar(50) DEFAULT '' NULL, + user_id bigint NULL, + dept_id bigint NULL, + dept_name nvarchar(50) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + browser nvarchar(50) DEFAULT '' NULL, + os nvarchar(50) DEFAULT '' NULL, + oper_url nvarchar(255) DEFAULT '' NULL, + oper_ip nvarchar(128) DEFAULT '' NULL, + oper_location nvarchar(255) DEFAULT '' NULL, + oper_param nvarchar(4000) DEFAULT '' NULL, + json_result nvarchar(4000) DEFAULT '' NULL, + status int DEFAULT ((0)) NULL, + error_msg nvarchar(4000) DEFAULT '' NULL, + oper_time datetime2(7) NULL, + cost_time bigint DEFAULT ((0)) NULL, + CONSTRAINT PK__sys_oper__34723BF9BD954573 PRIMARY KEY CLUSTERED (oper_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_oper_log_bt ON sys_oper_log (business_type) +GO +CREATE NONCLUSTERED INDEX idx_sys_oper_log_uid ON sys_oper_log (user_id) +GO +CREATE NONCLUSTERED INDEX idx_sys_oper_log_s ON sys_oper_log (status) +GO +CREATE NONCLUSTERED INDEX idx_sys_oper_log_ot ON sys_oper_log (oper_time) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'日志主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'模块标题' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'title' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'业务类型(0其它 1新增 2修改 3删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'business_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'方法名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'method' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求方式' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'request_method' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作类别(0其它 1后台用户 2手机端用户)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'operator_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作人员' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作部门ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'dept_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'客户端' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'client_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'设备类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'device_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'浏览器类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'browser' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作系统' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'os' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求URL' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_url' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'主机地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_ip' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作地点' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_location' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_param' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'返回参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'json_result' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作状态(0正常 1异常)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'错误消息' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'error_msg' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'消耗时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'cost_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作日志记录' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log' +GO + +CREATE TABLE sys_post +( + post_id bigint NOT NULL, + dept_id bigint NOT NULL, + post_code nvarchar(64) NOT NULL, + post_category nvarchar(100) NULL, + post_name nvarchar(50) NOT NULL, + post_sort int NOT NULL, + status nchar(1) NOT NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_post__3ED7876668E2D081 PRIMARY KEY CLUSTERED (post_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_post_dept_id ON sys_post (dept_id) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位类别编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post' +GO + +INSERT sys_post VALUES (1761200000000000001, 1761000000000000103, N'ceo', NULL, N'董事长', 1, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (1761200000000000002, 1761000000000000100, N'se', NULL, N'项目经理', 2, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (1761200000000000003, 1761000000000000100, N'hr', NULL, N'人力资源', 3, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (1761200000000000004, 1761000000000000100, N'user', NULL, N'普通员工', 4, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'') +GO + +CREATE TABLE sys_role +( + role_id bigint NOT NULL, + role_name nvarchar(30) NOT NULL, + role_key nvarchar(100) NOT NULL, + role_sort int NOT NULL, + data_scope nchar(1) DEFAULT ('1') NULL, + menu_check_strictly tinyint DEFAULT ((1)) NULL, + dept_check_strictly tinyint DEFAULT ((1)) NULL, + status nchar(1) NOT NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_role__760965CCF9383145 PRIMARY KEY CLUSTERED (role_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_role_create_dept ON sys_role (create_dept) +GO +CREATE NONCLUSTERED INDEX idx_sys_role_create_by ON sys_role (create_by) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色权限字符串' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'data_scope' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单树选择项是否关联显示' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'menu_check_strictly' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门树选择项是否关联显示' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'dept_check_strictly' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role' +GO + +INSERT sys_role VALUES (1761300000000000001, N'超级管理员', N'superadmin', 1, N'1', 1, 1, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'超级管理员') +GO +INSERT sys_role VALUES (1761300000000000003, N'本部门及以下', N'test1', 3, N'4', 1, 1, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO +INSERT sys_role VALUES (1761300000000000004, N'仅本人', N'test2', 4, N'5', 1, 1, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N''); +GO + +CREATE TABLE sys_role_dept +( + role_id bigint NOT NULL, + dept_id bigint NOT NULL, + CONSTRAINT PK__sys_role__2BC3005BABBCA08A PRIMARY KEY CLUSTERED (role_id, dept_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色和部门关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept' +GO + +CREATE TABLE sys_role_menu +( + role_id bigint NOT NULL, + menu_id bigint NOT NULL, + CONSTRAINT PK__sys_role__A2C36A6187BA4B17 PRIMARY KEY CLUSTERED (role_id, menu_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu', + 'COLUMN', N'menu_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色和菜单关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu' +GO + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000001); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000005); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000100); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000101); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000102); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000103); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000104); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000105); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000106); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000107); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000108); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000118); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000123); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000130); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000131); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000133); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000500); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000000501); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001001); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001002); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001003); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001004); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001005); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001006); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001007); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001008); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001009); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001010); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001011); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001012); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001013); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001014); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001015); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001016); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001017); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001018); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001019); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001020); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001021); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001022); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001023); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001024); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001025); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001026); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001027); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001028); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001029); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001030); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001031); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001032); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001033); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001034); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001035); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001036); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001037); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001038); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001039); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001040); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001041); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001042); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001043); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001044); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001045); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001050); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001061); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001062); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001063); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001064); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001065); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001500); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001501); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001502); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001503); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001504); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001505); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001506); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001507); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001508); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001509); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001510); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001511); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001600); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001601); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001602); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001603); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001620); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001621); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001622); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000001623); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011616); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011618); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011619); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011622); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011623); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011629); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011632); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011633); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011638); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011639); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011640); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011641); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011642); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011643); +GO +INSERT sys_role_menu VALUES (1761300000000000003, 1761400000000011701); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000000005); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001500); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001501); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001502); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001503); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001504); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001505); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001506); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001507); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001508); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001509); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001510); +GO +INSERT sys_role_menu VALUES (1761300000000000004, 1761400000000001511); +GO + +CREATE TABLE sys_user +( + user_id bigint NOT NULL, + dept_id bigint NULL, + user_name nvarchar(30) NOT NULL, + nick_name nvarchar(30) NOT NULL, + user_type nvarchar(10) DEFAULT ('sys_user') NULL, + email nvarchar(50) DEFAULT '' NULL, + phone_number nvarchar(11) DEFAULT '' NULL, + gender nchar(1) DEFAULT ('0') NULL, + avatar bigint NULL, + password nvarchar(100) DEFAULT '' NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + login_ip nvarchar(128) DEFAULT '' NULL, + login_date datetime2(7) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_user__B9BE370F79170B6A PRIMARY KEY CLUSTERED (user_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_user_dept_id ON sys_user (dept_id) +GO +CREATE NONCLUSTERED INDEX idx_sys_user_create_by ON sys_user (create_by) +GO +CREATE NONCLUSTERED INDEX idx_sys_user_user_name ON sys_user (user_name) +GO +CREATE NONCLUSTERED INDEX idx_sys_user_phone ON sys_user (phone_number) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户昵称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'nick_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户类型(sys_user系统用户)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'手机号码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'phone_number' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户性别(0男 1女 2未知)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'gender' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'头像地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'avatar' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'密码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'password' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'账号状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'最后登录IP' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'login_ip' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'最后登录时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'login_date' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user' +GO + +INSERT sys_user VALUES (1761100000000000001, 1761000000000000103, N'admin', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL, N'管理员') +GO +INSERT sys_user VALUES (1761100000000000003, 1761000000000000108, N'test', N'本部门及以下 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000003, getdate(), NULL); +GO +INSERT sys_user VALUES (1761100000000000004, 1761000000000000102, N'test1', N'仅本人 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000004, getdate(), NULL); +GO + +CREATE TABLE sys_user_post +( + user_id bigint NOT NULL, + post_id bigint NOT NULL, + CONSTRAINT PK__sys_user__CA534F799C04589B PRIMARY KEY CLUSTERED (user_id, post_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post', + 'COLUMN', N'post_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户与岗位关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post' +GO + +INSERT sys_user_post VALUES (1761100000000000001, 1761200000000000001) +GO + +CREATE TABLE sys_user_role +( + user_id bigint NOT NULL, + role_id bigint NOT NULL, + CONSTRAINT PK__sys_user__6EDEA153FB34D8F0 PRIMARY KEY CLUSTERED (user_id, role_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_user_role_rid ON sys_user_role (role_id) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户和角色关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role' +GO + +INSERT sys_user_role VALUES (1761100000000000001, 1761300000000000001) +GO +INSERT sys_user_role VALUES (1761100000000000003, 1761300000000000003); +GO +INSERT sys_user_role VALUES (1761100000000000004, 1761300000000000004); +GO + +CREATE TABLE sys_oss +( + oss_id bigint NOT NULL, + file_name nvarchar(255) DEFAULT '' NOT NULL, + original_name nvarchar(255) DEFAULT '' NOT NULL, + file_suffix nvarchar(10) DEFAULT '' NOT NULL, + url nvarchar(500) NOT NULL, + ext1 nvarchar(500) DEFAULT '' NULL, + create_dept bigint NULL, + create_time datetime2(7) NULL, + create_by bigint NULL, + update_time datetime2(7) NULL, + update_by bigint NULL, + service nvarchar(20) DEFAULT ('minio') NOT NULL, + CONSTRAINT PK__sys_oss__91241EA442389F0D PRIMARY KEY CLUSTERED (oss_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'对象存储主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'oss_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'文件名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'file_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'原名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'original_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'文件后缀名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'file_suffix' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'URL地址', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'url' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'ext1' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'上传人', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'服务商', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'service' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'OSS对象存储表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss' +GO + +CREATE TABLE sys_oss_config +( + oss_config_id bigint NOT NULL, + config_key nvarchar(20) DEFAULT '' NOT NULL, + access_key nvarchar(255) DEFAULT '' NULL, + secret_key nvarchar(255) DEFAULT '' NULL, + bucket_name nvarchar(255) DEFAULT '' NULL, + prefix nvarchar(255) DEFAULT '' NULL, + endpoint nvarchar(255) DEFAULT '' NULL, + domain_url nvarchar(255) DEFAULT '' NULL, + is_https nchar(1) DEFAULT ('N') NULL, + region nvarchar(255) DEFAULT '' NULL, + access_policy nchar(1) DEFAULT ('1') NOT NULL, + status nchar(1) DEFAULT ('N') NULL, + ext1 nvarchar(255) DEFAULT '' NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_oss___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (oss_config_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'oss_config_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'配置key', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'config_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'accessKey', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'access_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'秘钥', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'secret_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'桶名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'bucket_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'前缀', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'prefix' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'访问站点', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'endpoint' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'自定义域名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'domain_url' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'是否https(Y=是,N=否)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'is_https' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'域', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'region' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'桶权限类型(0=private 1=public 2=custom)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'access_policy' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'是否默认(Y=是,N=否)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'status' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'ext1' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'remark' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'对象存储配置表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config' +GO + +INSERT INTO sys_oss_config VALUES (1761900000000000001, N'minio', N'ruoyi', N'ruoyi123', N'ruoyi', N'', N'127.0.0.1:9000', N'', N'N', N'', N'1', N'Y', N'', 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000001, getdate(), NULL); +GO +INSERT INTO sys_oss_config VALUES (1761900000000000002, N'qiniu', N'XXXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi', N'', N's3-cn-north-1.qiniucs.com', N'', N'N', N'', N'1', N'N', N'', 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000001, getdate(), NULL); +GO +INSERT INTO sys_oss_config VALUES (1761900000000000003, N'aliyun', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi', N'', N'oss-cn-beijing.aliyuncs.com', N'', N'N', N'', N'1', N'N', N'', 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000001, getdate(), NULL); +GO +INSERT INTO sys_oss_config VALUES (1761900000000000004, N'qcloud', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi-1250000000', N'', N'cos.ap-beijing.myqcloud.com', N'', N'N', N'ap-beijing', N'1', N'N', N'', 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000001, getdate(), NULL); +GO +INSERT INTO sys_oss_config VALUES (1761900000000000005, N'image', N'ruoyi', N'ruoyi123', N'ruoyi', N'image', N'127.0.0.1:9000', N'', N'N', N'', N'1', N'N', N'', 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000001, getdate(), NULL); +GO + + +CREATE TABLE sys_client +( + id bigint NOT NULL, + client_id nvarchar(64) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + client_secret nvarchar(255) DEFAULT '' NULL, + grant_type nvarchar(255) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + access_path nvarchar(2000) DEFAULT '' NULL, + ip_whitelist nvarchar(1000) DEFAULT '' NULL, + active_timeout int DEFAULT ((1800)) NULL, + timeout int DEFAULT ((604800)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL + CONSTRAINT PK__sys_client___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'客户端id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'客户端key', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'客户端秘钥', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_secret' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'授权类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'grant_type' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'设备类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'device_type' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'允许访问路径', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'access_path' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'IP白名单', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'ip_whitelist' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'token活跃超时时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'active_timeout' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'token固定超时', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'timeout' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'status' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'系统授权表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client' +GO + +INSERT INTO sys_client VALUES (1762000000000000001, N'e5cd7e4891bf95d1d19206ce24a7b32e', N'pc', N'pc123', N'password,social', N'pc', N'', N'', 1800, 604800, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000001, getdate()); +GO +INSERT INTO sys_client VALUES (1762000000000000002, N'428a8310cd442757ae699df5d894f051', N'app', N'app123', N'password,sms,social', N'android', N'/app/**', N'', 1800, 604800, N'0', N'0', 1761000000000000103, 1761100000000000001, getdate(), 1761100000000000001, getdate()); +GO + +CREATE TABLE test_demo +( + id bigint NOT NULL, + dept_id bigint NULL, + user_id bigint NULL, + order_num int DEFAULT ((0)) NULL, + test_key nvarchar(255) NULL, + value nvarchar(255) NULL, + version int DEFAULT ((0)) NULL, + create_dept bigint NULL, + create_time datetime2(0) NULL, + create_by bigint NULL, + update_time datetime2(0) NULL, + update_by bigint NULL, + del_flag int DEFAULT ((0)) NULL, + CONSTRAINT PK__test_dem__3213E83F176051C8 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'排序号', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'order_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'key键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'test_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'值', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'value' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'version' +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'测试单表', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo' +GO + +CREATE TABLE test_tree +( + id bigint NOT NULL, + parent_id bigint DEFAULT ((0)) NULL, + dept_id bigint NULL, + user_id bigint NULL, + tree_name nvarchar(255) NULL, + version int DEFAULT ((0)) NULL, + create_dept bigint NULL, + create_time datetime2(0) NULL, + create_by bigint NULL, + update_time datetime2(0) NULL, + update_by bigint NULL, + del_flag int DEFAULT ((0)) NULL, + CONSTRAINT PK__test_tre__3213E83FC75A1B63 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'值', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'tree_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'version' +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'测试树表', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree' +GO + +INSERT test_demo VALUES (1762100000000000001, 1761000000000000102, 1761100000000000004, 1, N'测试数据权限', N'测试', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000002, 1761000000000000102, 1761100000000000003, 2, N'子节点1', N'111', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000003, 1761000000000000102, 1761100000000000003, 3, N'子节点2', N'222', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000004, 1761000000000000108, 1761100000000000004, 4, N'测试数据', N'demo', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000005, 1761000000000000108, 1761100000000000003, 13, N'子节点11', N'1111', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000006, 1761000000000000108, 1761100000000000003, 12, N'子节点22', N'2222', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000007, 1761000000000000108, 1761100000000000003, 11, N'子节点33', N'3333', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000008, 1761000000000000108, 1761100000000000003, 10, N'子节点44', N'4444', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000009, 1761000000000000108, 1761100000000000003, 9, N'子节点55', N'5555', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000010, 1761000000000000108, 1761100000000000003, 8, N'子节点66', N'6666', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000011, 1761000000000000108, 1761100000000000003, 7, N'子节点77', N'7777', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000012, 1761000000000000108, 1761100000000000003, 6, N'子节点88', N'8888', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_demo VALUES (1762100000000000013, 1761000000000000108, 1761100000000000003, 5, N'子节点99', N'9999', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO + +INSERT test_tree VALUES (1762200000000000001, NULL, 1761000000000000102, 1761100000000000004, N'测试数据权限', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000002, 1762200000000000001, 1761000000000000102, 1761100000000000003, N'子节点1', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000003, 1762200000000000002, 1761000000000000102, 1761100000000000003, N'子节点2', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000004, NULL, 1761000000000000108, 1761100000000000004, N'测试树1', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000005, 1762200000000000004, 1761000000000000108, 1761100000000000003, N'子节点11', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000006, 1762200000000000004, 1761000000000000108, 1761100000000000003, N'子节点22', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000007, 1762200000000000004, 1761000000000000108, 1761100000000000003, N'子节点33', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000008, 1762200000000000005, 1761000000000000108, 1761100000000000003, N'子节点44', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000009, 1762200000000000006, 1761000000000000108, 1761100000000000003, N'子节点55', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000010, 1762200000000000007, 1761000000000000108, 1761100000000000003, N'子节点66', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000011, 1762200000000000007, 1761000000000000108, 1761100000000000003, N'子节点77', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000012, 1762200000000000010, 1761000000000000108, 1761100000000000003, N'子节点88', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO +INSERT test_tree VALUES (1762200000000000013, 1762200000000000010, 1761000000000000108, 1761100000000000003, N'子节点99', 0, 1761000000000000103, getdate(), 1761100000000000001, NULL, NULL, 0); +GO + diff --git a/script/sql/sqlserver/sqlserver_ry_workflow.sql b/script/sql/sqlserver/sqlserver_ry_workflow.sql new file mode 100644 index 000000000..b91e3c81b --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_workflow.sql @@ -0,0 +1,1691 @@ +-- ---------------------------- +-- 0、warm-flow-all.sql,地址:https://gitee.com/dromara/warm-flow/blob/master/sql/sqlserver/sqlserver.sql +-- ---------------------------- +CREATE TABLE flow_definition ( + id bigint NOT NULL, + flow_code nvarchar(40) NOT NULL, + flow_name nvarchar(100) NOT NULL, + model_value nvarchar(40) DEFAULT('CLASSICS') NOT NULL, + category nvarchar(100) NULL, + version nvarchar(20) NOT NULL, + is_publish tinyint DEFAULT('0') NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + activity_status tinyint DEFAULT('1') NULL, + listener_type nvarchar(100) NULL, + listener_path nvarchar(400) NULL, + ext nvarchar(500) NULL, + create_time datetime2(7) NULL, + create_by nvarchar(64) NULL, + update_time datetime2(7) NULL, + update_by nvarchar(64) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_def__3213E83FEE39AE33 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'flow_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'flow_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'设计器模型(CLASSICS经典模型 MIMIC仿钉钉模型)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'model_value' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程类别', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'category' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程版本', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'是否发布(0未发布 1已发布 9失效)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'is_publish' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程激活状态(0挂起 1激活)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'activity_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器类型', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'listener_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'listener_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务详情 存业务表对象json字符串', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建人', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新人', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义表', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition' +GO + +CREATE TABLE flow_node ( + id bigint NOT NULL, + node_type tinyint NOT NULL, + definition_id bigint NOT NULL, + node_code nvarchar(100) NOT NULL, + node_name nvarchar(100) NULL, + permission_flag nvarchar(200) NULL, + node_ratio nvarchar(200) NULL, + coordinate nvarchar(100) NULL, + any_node_skip nvarchar(100) NULL, + listener_type nvarchar(100) NULL, + listener_path nvarchar(400) NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + version nvarchar(20) NOT NULL, + create_time datetime2(7) NULL, + create_by nvarchar(64) NULL, + update_time datetime2(7) NULL, + update_by nvarchar(64) NULL, + ext nvarchar(max) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_nod__3213E83F372470DE PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'权限标识(权限类型:权限标识,可以多个,用@@隔开)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'permission_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程签署比例值', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_ratio' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'坐标', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'coordinate' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任意结点跳转', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'any_node_skip' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器类型', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'listener_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'listener_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'版本', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建人', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新人', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点扩展属性', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'ext' +GO + + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点表', +'SCHEMA', N'dbo', +'TABLE', N'flow_node' +GO + +CREATE TABLE flow_skip ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + now_node_code nvarchar(100) NOT NULL, + now_node_type tinyint NULL, + next_node_code nvarchar(100) NOT NULL, + next_node_type tinyint NULL, + skip_name nvarchar(100) NULL, + skip_type nvarchar(40) NULL, + skip_condition nvarchar(200) NULL, + coordinate nvarchar(100) NULL, + create_time datetime2(7) NULL, + create_by nvarchar(64) NULL, + update_time datetime2(7) NULL, + update_by nvarchar(64) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_ski__3213E83F073FEE6E PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'当前流程节点的编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'now_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'now_node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'下一个流程节点的编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'next_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'next_node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转类型(PASS审批通过 REJECT退回)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转条件', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_condition' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'坐标', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'coordinate' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建人', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新人', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点跳转关联表', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip' +GO + +CREATE TABLE flow_instance ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + business_id nvarchar(40) NOT NULL, + node_type tinyint NOT NULL, + node_code nvarchar(40) NOT NULL, + node_name nvarchar(100) NULL, + variable nvarchar(max) NULL, + flow_status nvarchar(20) NOT NULL, + activity_status tinyint DEFAULT('1') NULL, + def_json nvarchar(max) NULL, + create_time datetime2(7) NULL, + create_by nvarchar(64) NULL, + update_time datetime2(7) NULL, + update_by nvarchar(64) NULL, + ext nvarchar(500) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_ins__3213E83F5190FEE1 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +TEXTIMAGE_ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'business_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务变量', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'variable' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'flow_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程激活状态(0挂起 1激活)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'activity_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义json', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'def_json' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建人', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新人', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'扩展字段,预留给业务系统使用', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程实例表', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance' +GO + +CREATE TABLE flow_task ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + instance_id bigint NOT NULL, + node_code nvarchar(100) NOT NULL, + node_name nvarchar(100) NULL, + node_type tinyint NOT NULL, + flow_status nvarchar(20) NOT NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + create_time datetime2(7) NULL, + create_by nvarchar(64) NULL, + update_time datetime2(7) NULL, + update_by nvarchar(64) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_tas__3213E83F5AE1F1BA PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_instance表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'instance_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'flow_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建人', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新人', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'待办任务表', +'SCHEMA', N'dbo', +'TABLE', N'flow_task' +GO + +CREATE TABLE flow_his_task ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + instance_id bigint NOT NULL, + task_id bigint NOT NULL, + node_code nvarchar(200) NULL, + node_name nvarchar(200) NULL, + node_type tinyint NULL, + target_node_code nvarchar(100) NULL, + target_node_name nvarchar(100) NULL, + approver nvarchar(40) NULL, + cooperate_type tinyint DEFAULT('0') NULL, + collaborator nvarchar(500) NULL, + skip_type nvarchar(10) NOT NULL, + flow_status nvarchar(20) NOT NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + message nvarchar(500) NULL, + variable nvarchar(max) NULL, + ext nvarchar(max) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_his__3213E83F67951564 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_instance表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'instance_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_task表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'task_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'目标节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'target_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'结束节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'target_node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批者', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'approver' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'cooperate_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'协作人', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'collaborator' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流转类型(PASS通过 REJECT退回 NONE无动作)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'skip_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'flow_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批意见', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务变量', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'variable' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务详情 存业务表对象json字符串', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务开始时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批完成时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'历史任务记录表', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task' +GO + +CREATE TABLE flow_user ( + id bigint NOT NULL, + type nchar(1) NOT NULL, + processed_by nvarchar(80) NULL, + associated bigint NOT NULL, + create_time datetime2(7) NULL, + create_by nvarchar(64) NULL, + update_time datetime2(7) NULL, + update_by nvarchar(64) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_use__3213E83FFA38CA8B PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX user_processed_type ON flow_user (processed_by ASC, type ASC) +GO +CREATE NONCLUSTERED INDEX user_associated_idx ON flow_user (associated ASC) +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'权限人', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'processed_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务表id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'associated' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建人', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新人', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程用户表', +'SCHEMA', N'dbo', +'TABLE', N'flow_user' +GO + +CREATE TABLE flow_category ( + category_id bigint NOT NULL, + parent_id bigint DEFAULT(0) NULL, + ancestors nvarchar(500) DEFAULT('') NULL, + category_name nvarchar(30) NOT NULL, + order_num int DEFAULT(0) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__flow_cat__D54EE9B4AE98B9C1 PRIMARY KEY CLUSTERED (category_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类ID', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'category_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'父流程分类id', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'祖级列表', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'ancestors' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'category_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'显示顺序', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'order_num' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志(0代表存在 1代表删除)', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建部门', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新者', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类', +'SCHEMA', N'dbo', +'TABLE', N'flow_category' +GO + +INSERT flow_category VALUES (1762300000000000100, 0, N'0', N'OA审批', 0, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000101, 1762300000000000100, N'0,1762300000000000100', N'假勤管理', 0, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000102, 1762300000000000100, N'0,1762300000000000100', N'人事管理', 1, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000103, 1762300000000000101, N'0,1762300000000000100,1762300000000000101', N'请假', 0, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000104, 1762300000000000101, N'0,1762300000000000100,1762300000000000101', N'出差', 1, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000105, 1762300000000000101, N'0,1762300000000000100,1762300000000000101', N'加班', 2, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000106, 1762300000000000101, N'0,1762300000000000100,1762300000000000101', N'换班', 3, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000107, 1762300000000000101, N'0,1762300000000000100,1762300000000000101', N'外出', 4, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000108, 1762300000000000102, N'0,1762300000000000100,1762300000000000102', N'转正', 1, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (1762300000000000109, 1762300000000000102, N'0,1762300000000000100,1762300000000000102', N'离职', 2, N'0', 1761000000000000103, 1761100000000000001, getdate(), NULL, NULL); +GO + +CREATE TABLE flow_spel ( + id BIGINT NOT NULL, + component_name VARCHAR(255), + method_name VARCHAR(255), + method_params VARCHAR(255), + view_spel VARCHAR(255), + remark VARCHAR(255), + status CHAR(1) DEFAULT ('0'), + del_flag CHAR(1) DEFAULT ('0'), + create_dept BIGINT, + create_by BIGINT, + create_time DATETIME, + update_by BIGINT, + update_time DATETIME, + CONSTRAINT PK__flow_spel__D54EE9B4AE98B9C1 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +); +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程spel表达式定义表', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键id', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组件名称', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'component_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'方法名', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'method_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'method_params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'预览spel表达式', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'view_spel' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建部门', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_spel', + 'COLUMN', N'update_time' +GO + +INSERT flow_spel VALUES (1762400000000000001, N'spelRuleComponent', N'selectDeptLeaderById', N'initiatorDeptId', N'#{@spelRuleComponent.selectDeptLeaderById(#initiatorDeptId)}', N'根据部门id获取部门负责人', N'0', N'0', 1761000000000000103, 1761100000000000001, GETDATE(), 1761100000000000001, GETDATE()); +GO +INSERT flow_spel VALUES (1762400000000000002, NULL, NULL, N'initiator', N'${initiator}', N'流程发起人', N'0', N'0', 1761000000000000103, 1761100000000000001, GETDATE(), 1761100000000000001, GETDATE()); +GO + +CREATE TABLE flow_instance_biz_ext ( + id BIGINT NOT NULL, + create_dept BIGINT, + create_by BIGINT, + create_time DATETIME, + update_by BIGINT, + update_time DATETIME, + business_code VARCHAR(255), + business_title VARCHAR(1000), + del_flag CHAR(1) DEFAULT ('0'), + instance_id BIGINT, + business_id VARCHAR(255), + CONSTRAINT PK__fi_biz_ext__D54EE9B4AE98B9C1 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +); + +EXEC sp_addextendedproperty + 'MS_Description', N'流程实例业务扩展表', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键id', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建部门', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编码', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'business_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务标题', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'business_title' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程实例Id', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'instance_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务Id', + 'SCHEMA', N'dbo', + 'TABLE', N'flow_instance_biz_ext', + 'COLUMN', N'business_id' +GO + +CREATE TABLE test_leave ( + id bigint NOT NULL, + apply_code nvarchar(50) NOT NULL, + leave_type nvarchar(255) NOT NULL, + start_date datetime2(7) NOT NULL, + end_date datetime2(7) NOT NULL, + leave_days int NOT NULL, + remark nvarchar(255) NULL, + status nvarchar(255) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__test_lea__3213E83F348788FA PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'id', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'申请编号', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'apply_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假类型', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'leave_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'start_date' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'结束时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'end_date' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假天数', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'leave_days' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假原因', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'状态', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建部门', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新者', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假申请表', +'SCHEMA', N'dbo', +'TABLE', N'test_leave' +GO + +INSERT sys_menu VALUES (1761400000000011616, N'工作流', 0, 6, N'workflow', NULL, N'', N'N', N'Y', N'M', N'0', N'0', N'', N'workflow', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011618, N'我的任务', 0, 7, N'task', NULL, N'', N'N', N'Y', N'M', N'0', N'0', N'', N'my-task', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011619, N'我的待办', 1761400000000011618, 2, N'taskWaiting', N'workflow/task/taskWaiting', N'', N'N', N'N', N'C', N'0', N'0', N'', N'waiting', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011632, N'我的已办', 1761400000000011618, 3, N'taskFinish', N'workflow/task/taskFinish', N'', N'N', N'N', N'C', N'0', N'0', N'', N'finish', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011633, N'我的抄送', 1761400000000011618, 4, N'taskCopyList', N'workflow/task/taskCopyList', N'', N'N', N'N', N'C', N'0', N'0', N'', N'my-copy', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011620, N'流程定义', 1761400000000011616, 3, N'processDefinition', N'workflow/processDefinition/index', N'', N'N', N'N', N'C', N'0', N'0', N'workflow:definition:list', N'process-definition', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011621, N'流程实例', 1761400000000011630, 1, N'processInstance', N'workflow/processInstance/index', N'', N'N', N'N', N'C', N'0', N'0', N'workflow:instance:list', N'tree-table', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011622, N'流程分类', 1761400000000011616, 1, N'category', N'workflow/category/index', N'', N'N', N'Y', N'C', N'0', N'0', N'workflow:category:list', N'category', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011629, N'我发起的', 1761400000000011618, 1, N'myDocument', N'workflow/task/myDocument', N'', N'N', N'N', N'C', N'0', N'0', N'workflow:instance:currentList', N'guide', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011630, N'流程监控', 1761400000000011616, 4, N'processMonitor', NULL, N'', N'N', N'Y', N'M', N'0', N'0', N'', N'monitor', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011631, N'待办任务', 1761400000000011630, 2, N'allTaskWaiting', N'workflow/task/allTaskWaiting', N'', N'N', N'N', N'C', N'0', N'0', N'workflow:task:list', N'waiting', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011660, N'待办任务修改', 1761400000000011631, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:task:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011700, N'流程设计', 1761400000000011616, 5, N'design/index', N'workflow/processDefinition/design', N'', N'N', N'N', N'C', N'1', N'0', N'workflow:leave:edit', N'#', N'/workflow/processDefinition', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011701, N'请假申请', 1761400000000011616, 6, N'leaveEdit/index', N'workflow/leave/leaveEdit', N'', N'N', N'N', N'C', N'1', N'0', N'workflow:leave:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO + +-- 流程分类管理相关按钮 +INSERT sys_menu VALUES (1761400000000011623, N'流程分类查询', 1761400000000011622, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:category:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011624, N'流程分类新增', 1761400000000011622, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:category:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011625, N'流程分类修改', 1761400000000011622, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:category:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011626, N'流程分类删除', 1761400000000011622, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:category:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011627, N'流程分类导出', 1761400000000011622, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:category:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO + +-- 流程实例管理相关按钮 +INSERT sys_menu VALUES (1761400000000011653, N'流程实例查询', 1761400000000011621, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011654, N'流程变量查询', 1761400000000011621, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:variableQuery', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011655, N'流程变量修改', 1761400000000011621, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:variable', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011656, N'流程实例激活/挂起', 1761400000000011621, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:active', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011657, N'流程实例删除', 1761400000000011621, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011658, N'流程实例作废', 1761400000000011621, 6, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:invalid', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011659, N'流程实例撤销', 1761400000000011621, 7, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:cancel', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO + +-- 流程定义管理相关按钮 +INSERT sys_menu VALUES (1761400000000011644, N'流程定义查询', 1761400000000011620, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011645, N'流程定义新增', 1761400000000011620, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011646, N'流程定义修改', 1761400000000011620, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011647, N'流程定义删除', 1761400000000011620, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011648, N'流程定义导出', 1761400000000011620, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011649, N'流程定义导入', 1761400000000011620, 6, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:import', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011650, N'流程定义发布/取消发布', 1761400000000011620, 7, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:publish', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011651, N'流程定义复制', 1761400000000011620, 8, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:copy', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011652, N'流程定义激活/挂起', 1761400000000011620, 9, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:active', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO + +INSERT sys_menu VALUES (1761400000000011801, N'流程表达式', 1761400000000011616, 2, N'spel', N'workflow/spel/index', N'', N'N', N'Y', N'C', N'0', N'0', N'workflow:spel:list', N'input', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), 1761100000000000001, GETDATE(), N'流程达式定义菜单'); +GO +INSERT sys_menu VALUES (1761400000000011802, N'流程spel表达式定义查询', 1761400000000011801, 1, N'#', N'', NULL, N'N', N'Y', N'F', N'0', N'0', N'workflow:spel:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011803, N'流程spel表达式定义新增', 1761400000000011801, 2, N'#', N'', NULL, N'N', N'Y', N'F', N'0', N'0', N'workflow:spel:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011804, N'流程spel表达式定义修改', 1761400000000011801, 3, N'#', N'', NULL, N'N', N'Y', N'F', N'0', N'0', N'workflow:spel:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011805, N'流程spel表达式定义删除', 1761400000000011801, 4, N'#', N'', NULL, N'N', N'Y', N'F', N'0', N'0', N'workflow:spel:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011806, N'流程spel表达式定义导出', 1761400000000011801, 5, N'#', N'', NULL, N'N', N'Y', N'F', N'0', N'0', N'workflow:spel:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO + +-- 请假测试相关按钮 +INSERT sys_menu VALUES (1761400000000011638, N'请假申请', 1761400000000000005, 1, N'leave', N'workflow/leave/index', N'', N'N', N'Y', N'C', N'0', N'0', N'workflow:leave:list', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'请假申请菜单'); +GO +INSERT sys_menu VALUES (1761400000000011639, N'请假申请查询', 1761400000000011638, 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:leave:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011640, N'请假申请新增', 1761400000000011638, 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:leave:add', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011641, N'请假申请修改', 1761400000000011638, 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:leave:edit', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011642, N'请假申请删除', 1761400000000011638, 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:leave:remove', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1761400000000011643, N'请假申请导出', 1761400000000011638, 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:leave:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N''); + +INSERT sys_dict_type VALUES (1761500000000000013, N'业务状态', N'wf_business_status', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'业务状态列表'); +GO +INSERT sys_dict_type VALUES (1761500000000000014, N'表单类型', N'wf_form_type', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'表单类型列表'); +GO +INSERT sys_dict_type VALUES (1761500000000000015, N'任务状态', N'wf_task_status', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'任务状态'); +GO + +INSERT sys_dict_data VALUES (1761600000000000039, 1, N'已撤销', N'cancel', N'wf_business_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'已撤销'); +GO +INSERT sys_dict_data VALUES (1761600000000000040, 2, N'草稿', N'draft', N'wf_business_status', N'', N'info', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'草稿'); +GO +INSERT sys_dict_data VALUES (1761600000000000041, 3, N'待审核', N'waiting', N'wf_business_status', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'待审核'); +GO +INSERT sys_dict_data VALUES (1761600000000000042, 4, N'已完成', N'finish', N'wf_business_status', N'', N'success', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'已完成'); +GO +INSERT sys_dict_data VALUES (1761600000000000043, 5, N'已作废', N'invalid', N'wf_business_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'已作废'); +GO +INSERT sys_dict_data VALUES (1761600000000000044, 6, N'已退回', N'back', N'wf_business_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'已退回'); +GO +INSERT sys_dict_data VALUES (1761600000000000045, 7, N'已终止', N'termination', N'wf_business_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'已终止'); +GO +INSERT sys_dict_data VALUES (1761600000000000046, 1, N'自定义表单', N'static', N'wf_form_type', N'', N'success', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'自定义表单'); +GO +INSERT sys_dict_data VALUES (1761600000000000047, 2, N'动态表单', N'dynamic', N'wf_form_type', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'动态表单'); +GO +INSERT sys_dict_data VALUES (1761600000000000048, 1, N'撤销', N'cancel', N'wf_task_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'撤销'); +GO +INSERT sys_dict_data VALUES (1761600000000000049, 2, N'通过', N'pass', N'wf_task_status', N'', N'success', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'通过'); +GO +INSERT sys_dict_data VALUES (1761600000000000050, 3, N'待审核', N'waiting', N'wf_task_status', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'待审核'); +GO +INSERT sys_dict_data VALUES (1761600000000000051, 4, N'作废', N'invalid', N'wf_task_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'作废'); +GO +INSERT sys_dict_data VALUES (1761600000000000052, 5, N'退回', N'back', N'wf_task_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'退回'); +GO +INSERT sys_dict_data VALUES (1761600000000000053, 6, N'终止', N'termination', N'wf_task_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'终止'); +GO +INSERT sys_dict_data VALUES (1761600000000000054, 7, N'转办', N'transfer', N'wf_task_status', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'转办'); +GO +INSERT sys_dict_data VALUES (1761600000000000055, 8, N'委托', N'depute', N'wf_task_status', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'委托'); +GO +INSERT sys_dict_data VALUES (1761600000000000056, 9, N'抄送', N'copy', N'wf_task_status', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'抄送'); +GO +INSERT sys_dict_data VALUES (1761600000000000057, 10, N'加签', N'sign', N'wf_task_status', N'', N'primary', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'加签'); +GO +INSERT sys_dict_data VALUES (1761600000000000058, 11, N'减签', N'sign_off', N'wf_task_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'减签'); +GO +INSERT sys_dict_data VALUES (1761600000000000059, 11, N'超时', N'timeout', N'wf_task_status', N'', N'danger', N'N', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'超时'); +GO