init: 初始化

This commit is contained in:
x6g2
2026-10-31 15:30:13 +08:00
commit 472365ddb4
1343 changed files with 153098 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
---
name: starapi-ai-coding
description: 在仓库内按代码生成器模板、项目 reference 文档和既有约定生成或修改代码。用于新增或修改 CRUD 模块、controller/service/mapper/BO/VO/entity、MyBatis-Plus/MPJ 查询、数据权限、缓存、翻译/JSON 增强、公共 common 模块能力、JavaDoc 注释,以及与后端接口配套的 Vue 或 React 前端页面、types 和 api 文件;触发后应先按任务类型读取对应 references,再阅读目标模块真实代码和 generator 模板。
---
# StarAPI AI 编码规范
先对齐代码生成器产物,再叠加仓库里真实业务代码已经形成的更强约定。
## 适用场景
在下面这些任务里优先使用此 skill:
- 新增标准 CRUD 模块。
- 根据新表结构补齐 entity、bo、vo、mapper、service、controller。
- 修改已有模块的查询、校验、导入导出、数据权限、事务逻辑。
- 修改 `starapi-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 代码前,先读取 `starapi-modules/starapi-gen/src/main/resources/fm/` 下的 FreeMarker 模板。
4. 命名和分层保持与仓库一致:
`domain` entity、`domain.bo`、`domain.vo`、`mapper`、`service`、`service.impl`、`controller`。
5. 优先在生成器结构上扩展,不要自行发明新的分层。
6. 修改 `starapi-system` 这类复杂模块前,先阅读同类现有实现,因为这些模块通常比生成器默认产物多出数据权限、联表、缓存、安全校验等逻辑。
7. 修改 `starapi-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. 公共基础模块修改
修改 `starapi-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<Entity, Vo>`。
- 手写 Service 注入 Mapper 时使用具体业务短名;代码生成器模板按类名首字母小写命名,例如 `SysRoleMapper` 生成 `sysRoleMapper`。
- Service 按场景返回 `PageResult` 或 `List<Vo>`。
- 查询代码优先使用 `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`。
## 推荐提问方式
推荐把任务描述到下面这个粒度:
- 目标模块和业务名
- 是新建模块还是修改已有模块
- 表名或接口前缀
- 是否需要分页、导出、导入、数据权限、字典、翻译、联表
- 希望参考哪个现有模块
例如:
- 使用 `$starapi-ai-coding` 在 `system` 模块新增一个标准单表 CRUD,参考 `SysConfig` 与 generator 模板。
- 使用 `$starapi-ai-coding` 修改 `workflow/category` 的查询和导出逻辑,保持现有模块风格。
@@ -0,0 +1,268 @@
# 后端约定
## 优先参考的代码来源
- `starapi-modules/starapi-gen/src/main/resources/fm/java/*.ftl`
- `starapi-modules/starapi-demo/...`
- `starapi-modules/starapi-system/...`
- `starapi-modules/starapi-workflow/...`
- `starapi-common/starapi-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 规则
- 除非所在模块明显另有约定,否则实体类继承 `com.starsee.starapi.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<Xxx, XxxVo>`。
- 不要为简单的 entity 转 vo 手写重复代码,优先依赖 `BaseMapperPlus`。
- 模块已经使用 `@DataPermission` 时,在重写方法和自定义查询上继续保留。
- 复杂模块里 mapper 可能同时继承 `MPJBaseMapper<Entity>` 并使用 `QueryBuilder.lambdaJoin(...)` 构造 MPJ 查询,遇到这种风格要延续,不要换一种写法。
- 只有在 `selectVoList/selectVoPage` 不够用时,才补 XML 或自定义 mapper 方法。
- Mapper 默认方法可以承载短小的 wrapper 查询;涉及复杂业务编排、缓存、事务或跨 mapper 写入时放到 service。
- `starapi-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<Vo>` 或 `PageResult<Vo>`。
- BO 转实体用 `MapstructUtils.convert(bo, Entity.class)`。
- 查询条件优先返回 `LambdaQueryWrapper`;新增 generator 风格代码优先用 `QueryBuilder.lambda(Entity.class)`,老模块已有 `Wrappers.lambdaQuery()` 时可继续保持。
- 字符串和空值条件优先用 `eqIfText`、`likeIfText`、`eqIfPresent`、`inIfNotEmpty`、`betweenParams` 等项目扩展;老代码已有直接 `StringUtils.isNotBlank(...)` 和 null 判断时可增量保持。
- 分页查询优先采用:
`Page<Vo> 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<T>` 或 `R<Void>`。
- 标准 CRUD 接口通常是:`GET /list`、`POST /export`、`GET /{id}`、`POST`、`PUT`、`DELETE /{ids}`。
- 树表接口通常不分页,`list` 返回 `R<List<Vo>>`;导出路由以目标模块或 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<T>` 并标注 `@TranslationType(type = ...)`。
- 使用方在 VO 字段上通过 `@Translation(type = ..., mapper = "...", other = "...")` 指定翻译来源。
- 批量翻译必须优先实现 `translationBatch(Set<Object> 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、异步回调等框架方法一般按接口覆写语义实现,除非业务不直观,不要添加冗长注释。
## 工作流模块规则
- `starapi-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` 相关处理。
- 不要把 `starapi-system` 这类复杂逻辑强行简化成生成器式单表 CRUD。
## 交付前自检
交付前至少检查这些点:
- CRUD 主链路是否完整。
- BO / VO / Entity 职责是否清晰。
- 分页、查询、删除校验是否与前端对得上。
- 权限、日志、防重、事务是否遗漏。
- 是否只是 generator 裸产物,如果是,需要继续补齐同模块已有增强。
@@ -0,0 +1,101 @@
# 使用案例
## 案例 1:新增标准单表 CRUD
### 用户提问示例
```text
使用 $starapi-plus-ai-coding 在 system 模块新增一个 client 管理的标准 CRUD。
请参考 generator 模板和现有 system 模块写法,补齐 entity、bo、vo、mapper、service、controller。
```
### 期望执行方式
- 先读 generator 的 `domain/bo/vo/service/serviceImpl/controller` 模板。
- 再读 `system` 模块里最接近的现有管理模块。
- 先生成骨架,再补权限、日志、校验、导出等细节。
## 案例 2:修改已有复杂模块
### 用户提问示例
```text
使用 $starapi-plus-ai-coding 修改 workflow/category 的查询和导出逻辑,保持现有模块风格,不要简化成模板式单表 CRUD。
```
### 期望执行方式
- 先读当前 workflow 模块同类代码。
- 判断这是“复杂模块增强”,不是“从零生成”。
- 增量修改原逻辑,不要重写整个 service/controller。
## 案例 3:补唯一性校验与删除前校验
### 用户提问示例
```text
使用 $starapi-plus-ai-coding 为 demo/demo 模块补充新增和修改时的唯一性校验,并补充删除前校验。
```
### 期望执行方式
- 优先修改 `validEntityBeforeSave(...)`。
- 根据模块现有风格补 `ServiceException` 或显式失败返回。
- 删除逻辑只补必要校验,不重构整套 CRUD。
## 案例 4:补数据权限与联表查询
### 用户提问示例
```text
使用 $starapi-plus-ai-coding 为 system 模块某个列表查询增加部门数据权限和联表字段返回,参考现有 user mapper 的 MPJ 与 DataPermission 写法。
```
### 期望执行方式
- 先看 `SysUserMapper` 和相关 service。
- 判断需要 `BaseMapperPlus` 重写还是 MPJ 联表。
- 保持权限注解和联表风格一致。
## 案例 5:新增后端接口并同步前端骨架
### 用户提问示例
```text
使用 $starapi-plus-ai-coding 为 monitor/cache 新增一个导出接口,并同步补齐 Vue 或 React 前端 api/types 调用骨架。
```
### 期望执行方式
- 先补后端 `controller/service`。
- 再根据后端路由和目标前端类型补 `src/api` 或 generator 风格的前端骨架。
- 保证导出接口路径和前端下载调用一致。
## 案例 6:推荐的高质量任务描述
下面这种描述最容易得到稳定结果:
```text
使用 $starapi-plus-ai-coding 在 workflow 模块新增一个标准列表管理功能:
1. 需要分页、导出、详情、增删改
2. 查询包含状态和创建时间范围
3. 保持现有 workflow 模块风格
4. 参考 generator 模板生成基础骨架
5. 删除前需要做业务校验
```
## 不推荐的任务描述
下面这种描述太模糊,容易导致产物偏离项目:
```text
帮我加个后端接口
```
更好的写法至少要补充:
- 模块名
- 表或业务名
- 是新增还是修改
- 是否需要分页、导出、权限、数据范围、联表
- 想参考哪个现有模块
@@ -0,0 +1,101 @@
# 前端约定
## 优先参考的代码来源
- `starapi-modules/starapi-gen/src/main/resources/fm/<frontendType>/*.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/<frontendType>/api.ts.ftl`、`types.ts.ftl`、`index.*.ftl`、`index-tree.*.ftl` 查找模板。
- 页面输出后缀由页面模板文件名决定:`index.vue.ftl` 输出 `index.vue`,`index.tsx.ftl` 输出 `index.tsx`。
- 新增其他前端时优先只新增 `fm/<frontendType>` 目录和对应 FTL 文件,不在 Java 代码里增加数字枚举或硬编码分支。
## API 文件规则
- Vue 模板从 `@/utils/request` 引入 `request`,从 `@/utils/api-types` 引入 `AxiosPromise`,从 `@/api/types` 引入 `PageResult`。
- React 模板从 `@/api/request` 引入 `request`,从 `@/api/types` 引入 `R`、`PageResult`。
- 本模块类型:Vue 模板从 `@/api/<module>/<business>/types` 引入,React 模板从 `./types` 引入。
- Vue 列表接口通常返回 `AxiosPromise<PageResult<Vo>>`;React 列表接口通常返回 `request<R<PageResult<Vo>>>(...)`。
- 常规接口命名和路由保持:
`listXxx` -> `GET /<module>/<business>/list`
`getXxx` -> `GET /<module>/<business>/{id}`
`addXxx` -> `POST /<module>/<business>`
`updateXxx` -> `PUT /<module>/<business>`
`delXxx` -> `DELETE /<module>/<business>/{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<string, unknown>`。
## Vue 页面规则
- 使用 `<script setup lang="ts">`。
- 常见 import 来自本模块 API 和本地 `types`。
- 新版生成器优先使用 hooks:`useLoading`、`useSearchToggle`、`useSearchReset`、`useTableSelection`、`useFormDialog`,日期范围使用 `useDateRangeQuery`。
- 字典通常通过 `toRefs<any>(useDict(...))` 解构。
- 常见状态包括:列表数组、`loading`、`buttonLoading`、`showSearch`、`ids`、`single`、`multiple`、`total`。
- 查询和表单状态通常放在 `reactive<PageData<Form, Query>>({...})` 中,并通过 `toRefs(data)` 暴露。
- 弹窗状态优先由 `useFormDialog` 返回的 `dialog`、`openDialog`、`showDialog`、`closeDialog` 管理。
- 表单引用通常命名为 `queryFormRef` 和 `<business>FormRef`。
## React 页面规则
- 使用 `index.tsx`,组件默认导出 `<BusinessName>Page`。
- 页面主体优先沿用 Ant Design Pro:`PageContainer`、`ProTable`、`ModalForm`、`ProColumns`、`ActionType`。
- 表单优先使用 `Form.useForm<Form>()`,弹窗开关优先使用 `ahooks` 的 `useBoolean`。
- 权限通过 `useUserStore` 取 `userInfo`,再用 `hasPermi(userInfo, ['module:business:action'])` 生成 `canAdd`、`canEdit`、`canRemove`、`canExport`。
- 表格选择使用 `useTableSelection<VO>(row => row.id)`;表格刷新使用 `actionRef.current?.reload()` 或 `reloadAndRest?.()`。
- 字典使用 `useDict` 和 `dictOptions`,展示使用 `DictTag`。
- 日期范围使用 `useDateRangeQuery`,在 `ProTable` 的 `request` 中由 `toPageQuery(params)` 转查询参数后再应用范围字段。
- 导出使用 `useTableExport`,路径保持 `/<module>/<business>/export`。
- 文件、图片、富文本组件使用 React 工程已有的 `FileUpload`、`ImageUpload`、`ImagePreview`、`RichTextEditor`。
## Vue 页面行为规则
- `getList` 负责通过 `withLoading` 设置 loading、处理日期范围参数、调用列表接口、回填 `rows` 和 `total`。
- `handleQuery` 通常先把 `pageNum` 重置为 `1`,再重新查询。
- `resetQuery` 优先使用 `useSearchReset`,通过 `resetExtras` 清空日期范围,再重新加载。
- `handleSelectionChange` 优先使用 `useTableSelection` 返回的方法,更新 `ids`、`single`、`multiple`。
- `handleAdd` 先重置表单,再通过 `openDialog` 打开弹窗。
- `handleUpdate` 先重置并查详情,再 `Object.assign(form.value, res.data)`,最后通过 `showDialog` 打开弹窗。
- `submitForm` 校验表单、切换 `buttonLoading`、根据主键判断调用新增还是更新、提示成功并刷新列表。
- `handleDelete` 使用 `modal.confirm(...)` 确认,再调用删除接口并刷新。
- `handleExport` 使用 `download as requestDownload` 从 `@/utils/request` 导出的下载方法。
## React 页面行为规则
- React `ProTable` 页面通过 `request` 回调加载列表并返回 `toTableData(res)`;新增、修改、删除成功后调用 `actionRef` 刷新。
- React 弹窗提交函数根据主键判断调用新增还是更新,成功后 `message.success('操作成功')` 并重置表单。
## 模板结构规则
- 优先保持生成器的页面布局结构,不在 Vue 和 React 之间互相移植组件体系。
- Vue 保留 `v-hasPermi="['module:business:add']"` 这类权限指令。
- Vue 继续使用仓库已有组件:`right-toolbar`、`pagination`、`dict-tag`、`image-preview`、`image-upload`、`file-upload`、`editor`。
- React 继续使用仓库已有组件:`RowActions`、`DictTag`、`ImagePreview`、`ImageUpload`、`FileUpload`、`RichTextEditor`。
- 已有页面对时间列使用 `parseTime` 时,新页面保持一致。
- Vue BETWEEN 日期查询继续使用 `el-date-picker`,脚本侧通过 `useDateRangeQuery` 生成 `dateRangeXxx`、`applyXxxDateRange`、`resetXxxDateRange`。
- React BETWEEN 日期查询继续使用 `ProTable` 的 `dateTimeRange` 搜索列,查询侧通过 `useDateRangeQuery` 写入 `params`。
## 避免事项
- 生成器风格页面不要突然换成完全不同的状态管理方式,除非该前端目录本身已经这么做。
- 模块已使用字典时,不要把选项文案硬编码到页面里。
- 不要让 API 函数名和路由段偏离后端约定。
- 后端 BO/service 依赖 begin/end 参数时,不要从查询对象里删掉 `params` 和日期范围处理。
- 不要把 Vue 的 `proxy`、`v-hasPermi`、Element Plus 组件写进 React 页面,也不要把 React 的 `ProTable`、`ModalForm`、Ant Design 权限判断写进 Vue 页面。
+18
View File
@@ -0,0 +1,18 @@
# http://editorconfig.org
root = true
# 空格替代Tab缩进在各种编辑工具下效果一致
[*]
indent_style = space
indent_size = 4
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.{json,yml,yaml}]
indent_size = 2
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
+2
View File
@@ -0,0 +1,2 @@
/mvnw text eol=lf
*.cmd text eol=crlf
+55
View File
@@ -0,0 +1,55 @@
######################################################################
# Build Tools
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
target/
!.mvn/wrapper/maven-wrapper.jar
######################################################################
# IDE
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### VS CODE ###
.vscode
### JRebel ###
rebel.xml
### NetBeans ###
nbproject/private/
build/*
nbbuild/
nbdist/
.nb-gradle/
######################################################################
# Others
*.log
*.log.gz
*.xml.versionsBackup
*.swp
!*/build/*.java
!*/build/*.html
!*/build/*.xml
.flattened-pom.xml
application-local.yml
application-ga.yml
+8
View File
@@ -0,0 +1,8 @@
wrapperVersion=3.3.4
distributionType=only-script
# Maven 3.9.X
distributionUrl=https://mirrors.huaweicloud.com/apache/maven/maven-3/3.9.12/binaries/apache-maven-3.9.12-bin.zip
# Maven 4.0
#distributionUrl=https://mirrors.huaweicloud.com/apache/maven/maven-4/4.0.0-rc-5/binaries/apache-maven-4.0.0-rc-5-bin.zip
# 分发类型为 only-script 或 bin 可以不需要该项(因为用不到),具体参考:https://maven.apache.org/tools/wrapper/maven-wrapper-distribution/index.html
#wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar
+12
View File
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="starapi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="starapi/starapi-monitor-admin:6.0.0" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="starapi-extend/starapi-monitor-admin/Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>
+12
View File
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="starapi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="starapi/starapi-server:6.0.0" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="starapi-admin/Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>
+13
View File
@@ -0,0 +1,13 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="starapi-snailai-server" type="docker-deploy" factoryName="dockerfile"
server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="starapi/starapi-snailai-server:6.0.0"/>
<option name="buildOnly" value="true"/>
<option name="sourceFilePath" value="starapi-extend/starapi-snailai-server/Dockerfile"/>
</settings>
</deployment>
<method v="2"/>
</configuration>
</component>
+12
View File
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="starapi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="starapi/starapi-snailjob-server:6.0.0" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="starapi-extend/starapi-snailjob-server/Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>
+20
View File
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2019 StarAPI
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+21
View File
@@ -0,0 +1,21 @@
# 告诉EditorConfig插件,这是根文件,不用继续往上查找
root = true
# 匹配全部文件
[*]
# 缩进风格,可选space、tab
indent_style = space
# 缩进的空格数
indent_size = 2
# 设置字符集
charset = utf-8
# 结尾换行符,可选lf、cr、crlf
end_of_line = lf
# 在文件结尾插入新行
trim_trailing_whitespace = true
# 删除一行中的前后空格
insert_final_newline = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
+42
View File
@@ -0,0 +1,42 @@
# 页面标题
VITE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
# 开发环境配置
VITE_APP_ENV = 'development'
# 开发环境
VITE_APP_BASE_API = '/dev-api'
# 应用访问路径 例如使用前缀 /admin/
VITE_APP_CONTEXT_PATH = '/'
# 监控地址
VITE_APP_MONITOR_ADMIN = 'http://localhost:9090/admin/applications'
# SnailJob 控制台地址
VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job'
# SnailAI 控制台地址
VITE_APP_SNAILAI_ADMIN = 'http://localhost:8900/snail-ai'
VITE_APP_PORT = 80
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
VITE_APP_ENCRYPT = true
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
VITE_APP_RSA_PUBLIC_KEY = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB'
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
VITE_APP_RSA_PRIVATE_KEY = 'MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAObq7yrxfvyieZtTjAYyrdvi59tYTXxjO5ajmPCRSXBY9M9wQ1tli297JN6mnY53UJMNyOFNSZVi8WSFoIXjpR87FmvChJlzeN/dZdd3SEs48Ee66XKeSePYqxa8oO5GKDsnajgpsOHKXSeeVSIysiIPS2/WsEqk0In9P4w3RsRFAgMBAAECgYBiMEWwce24SPICnRzuScBpvmsudrbEDIH7BOd0a6LZlcnLJwZNJ7mJlshPsHNQb+WgEf135+BBGEhioPtn0yuTdEuKP4kB9UdYUKiayWCoWhJpesv7sAD4RDClV7dhuV+gcd1AXD+YzyRIPbGm0VC2U+4q8/+UPRpVjqskbLVTgQJBAPRpou7g3S8n4XB527kq0D8I3+ZYwMxZhszwhrCDpJU319+ucmpLVwYIzDmZVeID2QQdUaDfIEViFHu95xDrGiUCQQDx3YOKn3yaEctk/ERVn7hDAyAXUbd8/pv2b24/M/l1ZevlsFem8U4Jk5Mu64t3z3YGJoymEjQmbucwT01iKhehAkEAxlnccsRmfFh/KkqauKE4M4++NTAd9zlInpUsmZ+cN8UEGnF2RTEzRKBrLOt1uWCqBB7PGiE6DVTVjr7FAQPrSQJAT5yeY87DcONSk9cFlzmPqV8p/QME5rvYEnHzVBKDlkUKNPyqnWToTvaoh9U4fyNmsfeWbEOprszqhFhWHG3GgQJAK8+ynmyFhaw63+Hx2KU5zR4hVuQso2IzrEurGxCxybV6mR7VBerb4502+EPx3PmOgxQL+niUFhcMWxcvBFP9+A=='
# 客户端id
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
# 统一消息推送开关
VITE_APP_MESSAGE_ENABLED = true
# sse / websocket
VITE_APP_MESSAGE_TRANSPORT = 'sse'
# 统一消息推送路径
VITE_APP_MESSAGE_PATH = '/resource/message'
+45
View File
@@ -0,0 +1,45 @@
# 页面标题
VITE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
# 生产环境配置
VITE_APP_ENV = 'production'
# 应用访问路径 例如使用前缀 /admin/
VITE_APP_CONTEXT_PATH = '/'
# 监控地址
VITE_APP_MONITOR_ADMIN = '/admin/applications'
# SnailJob 控制台地址
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
# SnailAI 控制台地址
VITE_APP_SNAILAI_ADMIN = '/snail-ai'
# 生产环境
VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
VITE_APP_PORT = 80
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
VITE_APP_ENCRYPT = true
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
VITE_APP_RSA_PUBLIC_KEY = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB'
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
VITE_APP_RSA_PRIVATE_KEY = 'MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAObq7yrxfvyieZtTjAYyrdvi59tYTXxjO5ajmPCRSXBY9M9wQ1tli297JN6mnY53UJMNyOFNSZVi8WSFoIXjpR87FmvChJlzeN/dZdd3SEs48Ee66XKeSePYqxa8oO5GKDsnajgpsOHKXSeeVSIysiIPS2/WsEqk0In9P4w3RsRFAgMBAAECgYBiMEWwce24SPICnRzuScBpvmsudrbEDIH7BOd0a6LZlcnLJwZNJ7mJlshPsHNQb+WgEf135+BBGEhioPtn0yuTdEuKP4kB9UdYUKiayWCoWhJpesv7sAD4RDClV7dhuV+gcd1AXD+YzyRIPbGm0VC2U+4q8/+UPRpVjqskbLVTgQJBAPRpou7g3S8n4XB527kq0D8I3+ZYwMxZhszwhrCDpJU319+ucmpLVwYIzDmZVeID2QQdUaDfIEViFHu95xDrGiUCQQDx3YOKn3yaEctk/ERVn7hDAyAXUbd8/pv2b24/M/l1ZevlsFem8U4Jk5Mu64t3z3YGJoymEjQmbucwT01iKhehAkEAxlnccsRmfFh/KkqauKE4M4++NTAd9zlInpUsmZ+cN8UEGnF2RTEzRKBrLOt1uWCqBB7PGiE6DVTVjr7FAQPrSQJAT5yeY87DcONSk9cFlzmPqV8p/QME5rvYEnHzVBKDlkUKNPyqnWToTvaoh9U4fyNmsfeWbEOprszqhFhWHG3GgQJAK8+ynmyFhaw63+Hx2KU5zR4hVuQso2IzrEurGxCxybV6mR7VBerb4502+EPx3PmOgxQL+niUFhcMWxcvBFP9+A=='
# 客户端id
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
# 统一消息推送开关
VITE_APP_MESSAGE_ENABLED = true
# sse / websocket
VITE_APP_MESSAGE_TRANSPORT = 'sse'
# 统一消息推送路径
VITE_APP_MESSAGE_PATH = '/resource/message'
+29
View File
@@ -0,0 +1,29 @@
.DS_Store
.history
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
*.iml
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock
# 编译生成的文件
auto-imports.d.ts
components.d.ts
+31
View File
@@ -0,0 +1,31 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"ignorePatterns": [
"src/types/components.d.ts",
"src/types/auto-imports.d.ts",
".ai_state",
".claude",
".codex",
"doc"
],
"printWidth": 120,
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid",
"htmlWhitespaceSensitivity": "ignore",
"experimentalSortPackageJson": {
"sortScripts": true
},
"sortImports": {
"newlinesBetween": false,
"groups": [
"type-import",
["value-builtin", "value-external"],
"type-internal",
"value-internal",
["type-parent", "type-sibling", "type-index"],
["value-parent", "value-sibling", "value-index"],
"unknown"
]
}
}
+25
View File
@@ -0,0 +1,25 @@
{
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
"plugins": ["eslint", "typescript", "unicorn", "oxc", "import", "vue"],
"rules": {
"typescript/no-empty-function": "off",
"typescript/no-explicit-any": "off",
"typescript/no-unused-vars": "off",
"typescript/no-this-alias": "off",
"typescript/no-empty-object-type": "off",
"typescript/no-unused-expressions": "off",
"prefer-rest-params": "off",
"import/no-unassigned-import": "off",
"import/no-named-as-default-member": "off",
"import/no-named-as-default": "off",
"no-shadow": "off",
"unicorn/prefer-add-event-listener": "off",
"unicorn/consistent-function-scoping": "off",
"unicorn/no-instanceof-builtins": "off"
},
"categories": {
"correctness": "error",
"suspicious": "error"
},
"ignorePatterns": [".ai_state", ".claude", ".codex", "doc", "dist/**", "dist-ssr/**", "coverage/**"]
}
+20
View File
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2019 RuoYi-Vue-Plus
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+214
View File
@@ -0,0 +1,214 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link rel="icon" href="/favicon.ico" />
<title>%VITE_APP_TITLE%</title>
<!--[if lt IE 11]>
<script>
window.location.href = '/ie.html';
</script>
<![endif]-->
<style>
html,
body,
#app {
height: 100%;
margin: 0px;
padding: 0px;
}
.chromeframe {
margin: 0.2em 0;
background: #ccc;
color: #000;
padding: 0.2em 0;
}
#loader-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999999;
}
#loader {
display: block;
position: relative;
left: 50%;
top: 50%;
width: 150px;
height: 150px;
margin: -75px 0 0 -75px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #fff;
-webkit-animation: spin 2s linear infinite;
-ms-animation: spin 2s linear infinite;
-moz-animation: spin 2s linear infinite;
-o-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
z-index: 1001;
}
#loader:before {
content: '';
position: absolute;
top: 5px;
left: 5px;
right: 5px;
bottom: 5px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #fff;
-webkit-animation: spin 3s linear infinite;
-moz-animation: spin 3s linear infinite;
-o-animation: spin 3s linear infinite;
-ms-animation: spin 3s linear infinite;
animation: spin 3s linear infinite;
}
#loader:after {
content: '';
position: absolute;
top: 15px;
left: 15px;
right: 15px;
bottom: 15px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #fff;
-moz-animation: spin 1.5s linear infinite;
-o-animation: spin 1.5s linear infinite;
-ms-animation: spin 1.5s linear infinite;
-webkit-animation: spin 1.5s linear infinite;
animation: spin 1.5s linear infinite;
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg);
transform: rotate(360deg);
}
}
#loader-wrapper .loader-section {
position: fixed;
top: 0;
width: 51%;
height: 100%;
background: #7171c6;
z-index: 1000;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
#loader-wrapper .loader-section.section-left {
left: 0;
}
#loader-wrapper .loader-section.section-right {
right: 0;
}
.loaded #loader-wrapper .loader-section.section-left {
-webkit-transform: translateX(-100%);
-ms-transform: translateX(-100%);
transform: translateX(-100%);
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.loaded #loader-wrapper .loader-section.section-right {
-webkit-transform: translateX(100%);
-ms-transform: translateX(100%);
transform: translateX(100%);
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.loaded #loader {
opacity: 0;
-webkit-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
}
.loaded #loader-wrapper {
visibility: hidden;
-webkit-transform: translateY(-100%);
-ms-transform: translateY(-100%);
transform: translateY(-100%);
-webkit-transition: all 0.3s 1s ease-out;
transition: all 0.3s 1s ease-out;
}
.no-js #loader-wrapper {
display: none;
}
.no-js h1 {
color: #222222;
}
#loader-wrapper .load_title {
font-family: 'Open Sans';
color: #fff;
font-size: 19px;
width: 100%;
text-align: center;
z-index: 9999999999999;
position: absolute;
top: 60%;
opacity: 1;
line-height: 30px;
}
#loader-wrapper .load_title span {
font-weight: normal;
font-style: italic;
font-size: 13px;
color: #fff;
opacity: 0.5;
}
</style>
</head>
<body>
<div id="app">
<div id="loader-wrapper">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div class="load_title">正在加载系统资源,请耐心等待</div>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+82
View File
@@ -0,0 +1,82 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "ruoyi-vue-plus",
"version": "6.0.0",
"description": "RuoYi-Vue-Plus后台管理系统",
"license": "MIT",
"author": "LionLi",
"repository": {
"type": "git",
"url": "https://gitee.com/JavaLionLi/plus-ui.git"
},
"type": "module",
"scripts": {
"build": "vite build --mode production",
"build:dev": "vite build --mode development",
"build:prod": "vite build --mode production",
"dev": "vite serve --mode development",
"fmt": "oxfmt .",
"lint": "oxlint src",
"lint:fix": "oxlint --fix src",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "2.3.2",
"@highlightjs/vue-plugin": "2.1.2",
"@iconify/vue": "^5.0.4",
"@noble/ciphers": "^2.4.0",
"@vueuse/core": "15.0.0",
"@wangeditor-next/editor": "6.5.1",
"@wangeditor-next/editor-for-vue": "6.5.1",
"animate.css": "4.1.1",
"await-to-js": "3.0.0",
"axios": "1.20.0",
"echarts": "6.1.0",
"element-plus": "2.14.7",
"highlight.js": "11.12.0",
"image-conversion": "2.1.1",
"jsencrypt": "3.5.4",
"nprogress": "0.2.0",
"pinia": "4.1.0",
"vue": "3.5.44",
"vue-cropper": "1.1.4",
"vue-i18n": "11.4.16",
"vue-json-pretty": "2.6.0",
"vue-router": "5.4.0",
"vue-types": "7.0.1",
"vxe-pc-ui": "4.20.18",
"vxe-table": "4.23.4"
},
"devDependencies": {
"@types/node": "^26.6.5",
"@types/nprogress": "0.2.3",
"@unocss/preset-attributify": "66.11.0",
"@unocss/preset-wind3": "66.11.0",
"@vitejs/plugin-vue": "^6.0.10",
"@vue/compiler-sfc": "3.5.44",
"autoprefixer": "10.6.1",
"oxfmt": "^0.74.0",
"oxlint": "^1.89.0",
"sass": "1.106.1",
"typescript": "^6.0.3",
"unocss": "66.11.0",
"unplugin-auto-import": "21.1.0",
"unplugin-vue-components": "32.1.0",
"unplugin-vue-setup-extend-plus": "1.0.1",
"vite": "^8.3.5",
"vite-plugin-svg-icons-ng": "^1.10.0",
"vitest": "5.0.5",
"vue-tsc": "^3.3.13"
},
"browserslist": [
"Chrome >= 87",
"Edge >= 88",
"Safari >= 14",
"Firefox >= 78"
],
"engines": {
"node": "^22.12.0 || ^24.0.0 || >=26.0.0",
"pnpm": ">=10.0.0"
},
"packageManager": "pnpm@10.34.5"
}
+4453
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
packages:
- '.'
allowBuilds:
'@parcel/watcher': true
es5-ext: true
esbuild: true
overrides:
esbuild: 0.28.1
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

File diff suppressed because one or more lines are too long
+20
View File
@@ -0,0 +1,20 @@
<template>
<el-config-provider :locale="appStore.locale" :size="appStore.size">
<router-view />
</el-config-provider>
</template>
<script setup lang="ts">
import { useAppStore } from '@/store/modules/app';
import { useSettingsStore } from '@/store/modules/settings';
import { handleThemeStyle } from '@/utils/theme';
const appStore = useAppStore();
onMounted(() => {
nextTick(() => {
// 初始化主题样式
handleThemeStyle(useSettingsStore().theme);
});
});
</script>
+48
View File
@@ -0,0 +1,48 @@
// 前缀
const animatePrefix = 'animate__animated ';
// 开启随机动画 随机动画值
const animateList: string[] = [
animatePrefix + 'animate__pulse',
animatePrefix + 'animate__rubberBand',
animatePrefix + 'animate__bounceIn',
animatePrefix + 'animate__bounceInLeft',
animatePrefix + 'animate__fadeIn',
animatePrefix + 'animate__fadeInLeft',
animatePrefix + 'animate__fadeInDown',
animatePrefix + 'animate__fadeInUp',
animatePrefix + 'animate__flipInX',
animatePrefix + 'animate__lightSpeedInLeft',
animatePrefix + 'animate__rotateInDownLeft',
animatePrefix + 'animate__rollIn',
animatePrefix + 'animate__rotateInDownLeft',
animatePrefix + 'animate__zoomIn',
animatePrefix + 'animate__zoomInDown',
animatePrefix + 'animate__slideInLeft',
animatePrefix + 'animate__lightSpeedIn'
];
// 关闭随机动画后的默认效果
const defaultAnimate = animatePrefix + 'animate__fadeIn';
// 搜索隐藏显示动画
const searchAnimate = {
enter: '',
leave: ''
};
// 菜单搜索动画
const menuSearchAnimate = {
enter: animatePrefix + 'animate__fadeIn',
leave: animatePrefix + 'animate__fadeOut'
};
// logo动画
const logoAnimate = {
enter: animatePrefix + 'animate__fadeIn',
leave: animatePrefix + 'animate__fadeOut'
};
export default {
animateList,
defaultAnimate,
searchAnimate,
menuSearchAnimate,
logoAnimate
};
+10
View File
@@ -0,0 +1,10 @@
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { SnailOpenApiUser } from './types';
export const registerCurrentSnailUser = (): AxiosPromise<SnailOpenApiUser> => {
return request({
url: '/snail-ai/user/register',
method: 'post'
});
};
+6
View File
@@ -0,0 +1,6 @@
export interface SnailOpenApiUser {
openId: string;
nickname?: string;
externalId?: string;
created?: boolean;
}
+2
View File
@@ -0,0 +1,2 @@
export * from './agent';
export * from './agent/types';
+63
View File
@@ -0,0 +1,63 @@
import type { DemoForm, DemoQuery, DemoVO } from '@/api/demo/demo/types';
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 查询测试单列表
* @param query
* @returns {*}
*/
export const listDemo = (query?: DemoQuery): AxiosPromise<PageResult<DemoVO>> => {
return request({
url: '/demo/demo/list',
method: 'get',
params: query
});
};
/**
* 查询测试单详细
* @param id
*/
export const getDemo = (id: string | number): AxiosPromise<DemoVO> => {
return request({
url: '/demo/demo/' + id,
method: 'get'
});
};
/**
* 新增测试单
* @param data
*/
export const addDemo = (data: DemoForm) => {
return request({
url: '/demo/demo',
method: 'post',
data: data
});
};
/**
* 修改测试单
* @param data
*/
export const updateDemo = (data: DemoForm) => {
return request({
url: '/demo/demo',
method: 'put',
data: data
});
};
/**
* 删除测试单
* @param id
*/
export const delDemo = (id: string | number | Array<string | number>) => {
return request({
url: '/demo/demo/' + id,
method: 'delete'
});
};
+90
View File
@@ -0,0 +1,90 @@
export interface DemoVO {
/**
* 主键
*/
id: string | number;
/**
* 部门id
*/
deptId: string | number;
/**
* 用户id
*/
userId: string | number;
/**
* 排序号
*/
orderNum: number;
/**
* key键
*/
testKey: string;
/**
* 值
*/
value: string;
}
export interface DemoForm extends BaseEntity {
/**
* 主键
*/
id?: string | number;
/**
* 部门id
*/
deptId?: string | number;
/**
* 用户id
*/
userId?: string | number;
/**
* 排序号
*/
orderNum?: number;
/**
* key键
*/
testKey?: string;
/**
* 值
*/
value?: string;
}
export interface DemoQuery extends PageQuery {
/**
* 部门id
*/
deptId?: string | number;
/**
* 用户id
*/
userId?: string | number;
/**
* 排序号
*/
orderNum?: number;
/**
* key键
*/
testKey?: string;
/**
* 值
*/
value?: string;
}
+62
View File
@@ -0,0 +1,62 @@
import type { TreeForm, TreeQuery, TreeVO } from '@/api/demo/tree/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 查询测试树列表
* @param query
* @returns {*}
*/
export const listTree = (query?: TreeQuery): AxiosPromise<TreeVO[]> => {
return request({
url: '/demo/tree/list',
method: 'get',
params: query
});
};
/**
* 查询测试树详细
* @param id
*/
export const getTree = (id: string | number): AxiosPromise<TreeVO> => {
return request({
url: '/demo/tree/' + id,
method: 'get'
});
};
/**
* 新增测试树
* @param data
*/
export const addTree = (data: TreeForm) => {
return request({
url: '/demo/tree',
method: 'post',
data: data
});
};
/**
* 修改测试树
* @param data
*/
export const updateTree = (data: TreeForm) => {
return request({
url: '/demo/tree',
method: 'put',
data: data
});
};
/**
* 删除测试树
* @param id
*/
export const delTree = (id: string | number | Array<string | number>) => {
return request({
url: '/demo/tree/' + id,
method: 'delete'
});
};
+80
View File
@@ -0,0 +1,80 @@
export interface TreeVO {
/**
* 主键
*/
id: string | number;
/**
* 父id
*/
parentId: string | number;
/**
* 部门id
*/
deptId: string | number;
/**
* 用户id
*/
userId: string | number;
/**
* 值
*/
treeName: string;
/**
* 子对象
*/
children: TreeVO[];
}
export interface TreeForm extends BaseEntity {
/**
* 主键
*/
id?: string | number;
/**
* 父id
*/
parentId?: string | number;
/**
* 部门id
*/
deptId?: string | number;
/**
* 用户id
*/
userId?: string | number;
/**
* 值
*/
treeName?: string;
}
export interface TreeQuery {
/**
* 父id
*/
parentId?: string | number;
/**
* 部门id
*/
deptId?: string | number;
/**
* 用户id
*/
userId?: string | number;
/**
* 值
*/
treeName?: string;
}
+107
View File
@@ -0,0 +1,107 @@
import type { UserInfo } from '@/api/system/user/types';
import type { AxiosPromise } from '@/utils/api-types';
import { closePush } from '@/utils/push';
import request from '@/utils/request';
import type { LoginData, LoginResult, VerifyCodeResult } from './types';
// pc端固定客户端授权id
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
/**
* @param data {LoginData}
* @returns
*/
export function login(data: LoginData): AxiosPromise<LoginResult> {
const params = {
...data,
clientId: data.clientId || clientId,
grantType: data.grantType || 'password'
};
return request({
url: '/auth/login',
headers: {
isToken: false,
isEncrypt: true,
repeatSubmit: false
},
method: 'post',
data: params
});
}
// 注册方法
export function register(data: any) {
const params = {
...data,
clientId: clientId,
grantType: 'password'
};
return request({
url: '/auth/register',
headers: {
isToken: false,
isEncrypt: true,
repeatSubmit: false
},
method: 'post',
data: params
});
}
/**
* 注销
*/
export function logout() {
closePush();
if (
import.meta.env.VITE_APP_MESSAGE_ENABLED === 'true' &&
import.meta.env.VITE_APP_MESSAGE_TRANSPORT.toLowerCase() === 'sse'
) {
request({
url: import.meta.env.VITE_APP_MESSAGE_PATH + '/close',
method: 'get'
});
}
return request({
url: '/auth/logout',
method: 'post'
});
}
/**
* 获取验证码
*/
export function getCodeImg(): AxiosPromise<VerifyCodeResult> {
return request({
url: '/auth/code',
headers: {
isToken: false
},
method: 'get',
timeout: 20000
});
}
/**
* 第三方登录
*/
export function callback(data: LoginData): AxiosPromise<any> {
const LoginData = {
...data,
clientId: clientId,
grantType: 'social'
};
return request({
url: '/auth/social/callback',
method: 'post',
data: LoginData
});
}
// 获取用户详细信息
export function getInfo(): AxiosPromise<UserInfo> {
return request({
url: '/system/user/getInfo',
method: 'get'
});
}
+11
View File
@@ -0,0 +1,11 @@
import type { RouteRecordRaw } from 'vue-router';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
// 获取路由
export function getRouters(): AxiosPromise<RouteRecordRaw[]> {
return request({
url: '/system/menu/getRouters',
method: 'get'
});
}
+12
View File
@@ -0,0 +1,12 @@
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { CacheVO } from './types';
// 查询缓存详细
export function getCache(): AxiosPromise<CacheVO> {
return request({
url: '/monitor/cache',
method: 'get'
});
}
+7
View File
@@ -0,0 +1,7 @@
export interface CacheVO {
commandStats: Array<{ name: string; value: string }>;
dbSize: number;
info: { [key: string]: string };
}
@@ -0,0 +1,37 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { LoginInfoQuery, LoginInfoVO } from './types';
// 查询登录日志列表
export function list(query: LoginInfoQuery): AxiosPromise<PageResult<LoginInfoVO>> {
return request({
url: '/monitor/loginInfo/list',
method: 'get',
params: query
});
}
// 删除登录日志
export function delLoginInfo(infoId: string | number | Array<string | number>) {
return request({
url: '/monitor/loginInfo/' + infoId,
method: 'delete'
});
}
// 解锁用户登录状态
export function unlockLoginInfo(userName: string | Array<string>) {
return request({
url: '/monitor/loginInfo/unlock/' + userName,
method: 'get'
});
}
// 清空登录日志
export function cleanLoginInfo() {
return request({
url: '/monitor/loginInfo/clean',
method: 'delete'
});
}
@@ -0,0 +1,20 @@
export interface LoginInfoVO {
infoId: string | number;
tenantId: string | number;
userName: string;
status: string;
ipaddr: string;
loginLocation: string;
browser: string;
os: string;
msg: string;
loginTime: string;
}
export interface LoginInfoQuery extends PageQuery {
ipaddr: string;
userName: string;
status: string;
orderByColumn: string;
isAsc: string;
}
+37
View File
@@ -0,0 +1,37 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { OnlineQuery, OnlineVO } from './types';
// 查询在线用户列表
export function list(query: OnlineQuery): AxiosPromise<PageResult<OnlineVO>> {
return request({
url: '/monitor/online/list',
method: 'get',
params: query
});
}
// 强退用户
export function forceLogout(tokenId: string) {
return request({
url: '/monitor/online/' + tokenId,
method: 'delete'
});
}
// 获取当前用户登录在线设备
export function getOnline() {
return request({
url: '/monitor/online',
method: 'get'
});
}
// 删除当前在线设备
export function delOnline(tokenId: string) {
return request({
url: '/monitor/online/myself/' + tokenId,
method: 'delete'
});
}
+15
View File
@@ -0,0 +1,15 @@
export interface OnlineQuery extends PageQuery {
ipaddr: string;
userName: string;
}
export interface OnlineVO extends BaseEntity {
tokenId: string;
deptName: string;
userName: string;
ipaddr: string;
loginLocation: string;
browser: string;
os: string;
loginTime: number;
}
+29
View File
@@ -0,0 +1,29 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { OperLogQuery, OperLogVO } from './types';
// 查询操作日志列表
export function list(query: OperLogQuery): AxiosPromise<PageResult<OperLogVO>> {
return request({
url: '/monitor/operlog/list',
method: 'get',
params: query
});
}
// 删除操作日志
export function delOperlog(operId: string | number | Array<string | number>) {
return request({
url: '/monitor/operlog/' + operId,
method: 'delete'
});
}
// 清空操作日志
export function cleanOperlog() {
return request({
url: '/monitor/operlog/clean',
method: 'delete'
});
}
+71
View File
@@ -0,0 +1,71 @@
export interface OperLogQuery extends PageQuery {
operIp: string;
title: string;
operName: string;
userId: string;
deptId: string;
clientKey: string;
deviceType: string;
browser: string;
os: string;
businessType: string;
status: string;
orderByColumn: string;
isAsc: string;
}
export interface OperLogVO extends BaseEntity {
operId: string | number;
tenantId: string;
title: string;
businessType: number;
businessTypes: number[] | undefined;
method: string;
requestMethod: string;
operatorType: number;
operName: string;
userId: string | number;
deptId: string | number;
deptName: string;
clientKey: string;
deviceType: string;
browser: string;
os: string;
operUrl: string;
operIp: string;
operLocation: string;
operParam: string;
jsonResult: string;
status: number;
errorMsg: string;
operTime: string;
costTime: number;
}
export interface OperLogForm {
operId: number | string | undefined;
tenantId: string | number | undefined;
title: string;
businessType: number;
businessTypes: number[] | undefined;
method: string;
requestMethod: string;
operatorType: number;
operName: string;
userId: string | number | undefined;
deptId: string | number | undefined;
deptName: string;
clientKey: string;
deviceType: string;
browser: string;
os: string;
operUrl: string;
operIp: string;
operLocation: string;
operParam: string;
jsonResult: string;
status: number;
errorMsg: string;
operTime: string;
costTime: number;
}
+81
View File
@@ -0,0 +1,81 @@
import type { ClientForm, ClientQuery, ClientVO } from '@/api/system/client/types';
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 查询客户端管理列表
* @param query
* @returns {*}
*/
export const listClient = (query?: ClientQuery): AxiosPromise<PageResult<ClientVO>> => {
return request({
url: '/system/client/list',
method: 'get',
params: query
});
};
/**
* 查询客户端管理详细
* @param id
*/
export const getClient = (id: string | number): AxiosPromise<ClientVO> => {
return request({
url: '/system/client/' + id,
method: 'get'
});
};
/**
* 新增客户端管理
* @param data
*/
export const addClient = (data: ClientForm) => {
return request({
url: '/system/client',
method: 'post',
data: data
});
};
/**
* 修改客户端管理
* @param data
*/
export const updateClient = (data: ClientForm) => {
return request({
url: '/system/client',
method: 'put',
data: data
});
};
/**
* 删除客户端管理
* @param id
*/
export const delClient = (id: string | number | Array<string | number>) => {
return request({
url: '/system/client/' + id,
method: 'delete'
});
};
/**
* 状态修改
* @param clientId 客户端id
* @param status 状态
*/
export function changeStatus(clientId: string, status: string) {
const data = {
clientId,
status
};
return request({
url: '/system/client/changeStatus',
method: 'put',
data: data
});
}
+185
View File
@@ -0,0 +1,185 @@
export interface ClientVO {
/**
* id
*/
id: string | number;
/**
* 客户端id
*/
clientId: string;
/**
* 客户端key
*/
clientKey: string;
/**
* 客户端秘钥
*/
clientSecret: string;
/**
* 授权类型
*/
grantTypeList: string[];
/**
* 设备类型
*/
deviceType: string;
/**
* 允许访问路径
*/
accessPath?: string;
/**
* 允许访问路径列表
*/
accessPathList?: string[];
/**
* IP白名单
*/
ipWhitelist?: string;
/**
* IP白名单列表
*/
ipWhitelistList?: string[];
/**
* token活跃超时时间
*/
activeTimeout: number;
/**
* token固定超时
*/
timeout: number;
/**
* 状态(0正常 1停用)
*/
status: string;
}
export interface ClientForm extends BaseEntity {
/**
* id
*/
id?: string | number;
/**
* 客户端id
*/
clientId?: string | number;
/**
* 客户端key
*/
clientKey?: string;
/**
* 客户端秘钥
*/
clientSecret?: string;
/**
* 授权类型
*/
grantTypeList?: string[];
/**
* 设备类型
*/
deviceType?: string;
/**
* 允许访问路径
*/
accessPath?: string;
/**
* 允许访问路径列表
*/
accessPathList?: string[];
/**
* IP白名单
*/
ipWhitelist?: string;
/**
* IP白名单列表
*/
ipWhitelistList?: string[];
/**
* token活跃超时时间
*/
activeTimeout?: number;
/**
* token固定超时
*/
timeout?: number;
/**
* 状态(0正常 1停用)
*/
status?: string;
}
export interface ClientQuery extends PageQuery {
/**
* 客户端id
*/
clientId?: string | number;
/**
* 客户端key
*/
clientKey?: string;
/**
* 客户端秘钥
*/
clientSecret?: string;
/**
* 授权类型
*/
grantType?: string;
/**
* 设备类型
*/
deviceType?: string;
/**
* 允许访问路径
*/
accessPath?: string;
/**
* IP白名单
*/
ipWhitelist?: string;
/**
* token活跃超时时间
*/
activeTimeout?: number;
/**
* token固定超时
*/
timeout?: number;
/**
* 状态(0正常 1停用)
*/
status?: string;
}
+75
View File
@@ -0,0 +1,75 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { ConfigForm, ConfigQuery, ConfigVO } from './types';
// 查询参数列表
export function listConfig(query: ConfigQuery): AxiosPromise<PageResult<ConfigVO>> {
return request({
url: '/system/config/list',
method: 'get',
params: query
});
}
// 查询参数详细
export function getConfig(configId: string | number): AxiosPromise<ConfigVO> {
return request({
url: '/system/config/' + configId,
method: 'get'
});
}
// 根据参数键名查询参数值
export function getConfigKey(configKey: string): AxiosPromise<string> {
return request({
url: '/system/config/configKey/' + configKey,
method: 'get'
});
}
// 新增参数配置
export function addConfig(data: ConfigForm) {
return request({
url: '/system/config',
method: 'post',
data: data
});
}
// 修改参数配置
export function updateConfig(data: ConfigForm) {
return request({
url: '/system/config',
method: 'put',
data: data
});
}
// 修改参数配置
export function updateConfigByKey(key: string, value: any) {
return request({
url: '/system/config/updateByKey',
method: 'put',
data: {
configKey: key,
configValue: value
}
});
}
// 删除参数配置
export function delConfig(configId: string | number | Array<string | number>) {
return request({
url: '/system/config/' + configId,
method: 'delete'
});
}
// 刷新参数缓存
export function refreshCache() {
return request({
url: '/system/config/refreshCache',
method: 'delete'
});
}
+23
View File
@@ -0,0 +1,23 @@
export interface ConfigVO extends BaseEntity {
configId: number | string;
configName: string;
configKey: string;
configValue: string;
configType: string;
remark: string;
}
export interface ConfigForm {
configId: number | string | undefined;
configName: string;
configKey: string;
configValue: string;
configType: string;
remark: string;
}
export interface ConfigQuery extends PageQuery {
configName: string;
configKey: string;
configType: string;
}
+65
View File
@@ -0,0 +1,65 @@
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import { type DeptForm, type DeptQuery, type DeptVO } from './types';
// 查询部门列表
export const listDept = (query?: DeptQuery) => {
return request({
url: '/system/dept/list',
method: 'get',
params: query
});
};
/**
* 通过deptIds查询部门
* @param deptIds
*/
export const optionSelect = (deptIds: (number | string)[]): AxiosPromise<DeptVO[]> => {
return request({
url: '/system/dept/optionselect?deptIds=' + deptIds,
method: 'get'
});
};
// 查询部门列表(排除节点)
export const listDeptExcludeChild = (deptId: string | number): AxiosPromise<DeptVO[]> => {
return request({
url: '/system/dept/list/exclude/' + deptId,
method: 'get'
});
};
// 查询部门详细
export const getDept = (deptId: string | number): AxiosPromise<DeptVO> => {
return request({
url: '/system/dept/' + deptId,
method: 'get'
});
};
// 新增部门
export const addDept = (data: DeptForm) => {
return request({
url: '/system/dept',
method: 'post',
data: data
});
};
// 修改部门
export const updateDept = (data: DeptForm) => {
return request({
url: '/system/dept',
method: 'put',
data: data
});
};
// 删除部门
export const delDept = (deptId: number | string) => {
return request({
url: '/system/dept/' + deptId,
method: 'delete'
});
};
+60
View File
@@ -0,0 +1,60 @@
/**
* 部门查询参数
*/
export interface DeptQuery extends PageQuery {
deptName?: string;
deptCategory?: string;
status?: number;
}
/**
* 部门类型
*/
export interface DeptVO extends BaseEntity {
id: number | string;
parentName: string;
parentId: number | string;
children: DeptVO[];
deptId: number | string;
deptName: string;
deptCategory: string;
orderNum: number;
leader: string;
phone: string;
email: string;
status: string;
delFlag: string;
ancestors: string;
menuId: string | number;
}
/**
* 部门类型
*/
export interface DeptTreeVO extends BaseEntity {
id: number | string;
label: string;
parentId: number | string;
weight: number;
children: DeptTreeVO[];
disabled: boolean;
}
/**
* 部门表单类型
*/
export interface DeptForm {
parentName?: string;
parentId?: number | string;
children?: DeptForm[];
deptId?: number | string;
deptName?: string;
deptCategory?: string;
orderNum?: number;
leader?: string;
phone?: string;
email?: string;
status?: string;
delFlag?: string;
ancestors?: string;
}
@@ -0,0 +1,54 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { DictDataForm, DictDataQuery, DictDataVO } from './types';
// 根据字典类型查询字典数据信息
export function getDicts(dictType: string): AxiosPromise<DictDataVO[]> {
return request({
url: '/system/dict/data/type/' + dictType,
method: 'get'
});
}
// 查询字典数据列表
export function listData(query: DictDataQuery): AxiosPromise<PageResult<DictDataVO>> {
return request({
url: '/system/dict/data/list',
method: 'get',
params: query
});
}
// 查询字典数据详细
export function getData(dictCode: string | number): AxiosPromise<DictDataVO> {
return request({
url: '/system/dict/data/' + dictCode,
method: 'get'
});
}
// 新增字典数据
export function addData(data: DictDataForm) {
return request({
url: '/system/dict/data',
method: 'post',
data: data
});
}
// 修改字典数据
export function updateData(data: DictDataForm) {
return request({
url: '/system/dict/data',
method: 'put',
data: data
});
}
// 删除字典数据
export function delData(dictCode: string | number | Array<string | number>) {
return request({
url: '/system/dict/data/' + dictCode,
method: 'delete'
});
}
@@ -0,0 +1,26 @@
export interface DictDataQuery extends PageQuery {
dictName: string;
dictType: string;
dictLabel: string;
}
export interface DictDataVO extends BaseEntity {
dictCode: string;
dictLabel: string;
dictValue: string;
cssClass: string;
listClass: ElTagType;
dictSort: number;
remark: string;
}
export interface DictDataForm {
dictType?: string;
dictCode: string | undefined;
dictLabel: string;
dictValue: string;
cssClass: string;
listClass: ElTagType;
dictSort: number;
remark: string;
}
@@ -0,0 +1,63 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { DictTypeForm, DictTypeQuery, DictTypeVO } from './types';
// 查询字典类型列表
export function listType(query: DictTypeQuery): AxiosPromise<PageResult<DictTypeVO>> {
return request({
url: '/system/dict/type/list',
method: 'get',
params: query
});
}
// 查询字典类型详细
export function getType(dictId: number | string): AxiosPromise<DictTypeVO> {
return request({
url: '/system/dict/type/' + dictId,
method: 'get'
});
}
// 新增字典类型
export function addType(data: DictTypeForm) {
return request({
url: '/system/dict/type',
method: 'post',
data: data
});
}
// 修改字典类型
export function updateType(data: DictTypeForm) {
return request({
url: '/system/dict/type',
method: 'put',
data: data
});
}
// 删除字典类型
export function delType(dictId: string | number | Array<string | number>) {
return request({
url: '/system/dict/type/' + dictId,
method: 'delete'
});
}
// 刷新字典缓存
export function refreshCache() {
return request({
url: '/system/dict/type/refreshCache',
method: 'delete'
});
}
// 获取字典选择框列表
export function optionselect(): AxiosPromise<DictTypeVO[]> {
return request({
url: '/system/dict/type/optionselect',
method: 'get'
});
}
@@ -0,0 +1,18 @@
export interface DictTypeVO extends BaseEntity {
dictId: number | string;
dictName: string;
dictType: string;
remark: string;
}
export interface DictTypeForm {
dictId: number | string | undefined;
dictName: string;
dictType: string;
remark: string;
}
export interface DictTypeQuery extends PageQuery {
dictName: string;
dictType: string;
}
+70
View File
@@ -0,0 +1,70 @@
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { MenuForm, MenuQuery, MenuTreeOption, MenuVO, RoleMenuTree } from './types';
// 查询菜单列表
export const listMenu = (query?: MenuQuery): AxiosPromise<MenuVO[]> => {
return request({
url: '/system/menu/list',
method: 'get',
params: query
});
};
// 查询菜单详细
export const getMenu = (menuId: string | number): AxiosPromise<MenuVO> => {
return request({
url: '/system/menu/' + menuId,
method: 'get'
});
};
// 查询菜单下拉树结构
export const treeselect = (): AxiosPromise<MenuTreeOption[]> => {
return request({
url: '/system/menu/treeselect',
method: 'get'
});
};
// 根据角色ID查询菜单下拉树结构
export const roleMenuTreeselect = (roleId: string | number): AxiosPromise<RoleMenuTree> => {
return request({
url: '/system/menu/roleMenuTreeselect/' + roleId,
method: 'get'
});
};
// 新增菜单
export const addMenu = (data: MenuForm) => {
return request({
url: '/system/menu',
method: 'post',
data: data
});
};
// 修改菜单
export const updateMenu = (data: MenuForm) => {
return request({
url: '/system/menu',
method: 'put',
data: data
});
};
// 删除菜单
export const delMenu = (menuId: string | number) => {
return request({
url: '/system/menu/' + menuId,
method: 'delete'
});
};
// 级联删除菜单
export const cascadeDelMenu = (menuIds: Array<string | number>) => {
return request({
url: '/system/menu/cascade/' + menuIds,
method: 'delete'
});
};
+89
View File
@@ -0,0 +1,89 @@
import type { MenuTypeEnum } from '@/enums/MenuTypeEnum';
/**
* 菜单树形结构类型
*/
export interface MenuTreeOption {
id: string | number;
label: string;
parentId: string | number;
weight: number;
menuType?: MenuTypeEnum | string;
visible?: string;
status?: string;
disabled?: boolean;
children?: MenuTreeOption[];
}
export interface RoleMenuTree {
menus: MenuTreeOption[];
checkedKeys: Array<string | number>;
}
/**
* 角色菜单分配中的按钮节点类型
*/
export interface RoleMenuButtonOption {
menuId: string | number;
menuName: string;
parentId: string | number;
perms?: string;
status?: string;
disabled?: boolean;
}
/**
* 菜单查询参数类型
*/
export interface MenuQuery {
keywords?: string;
menuName?: string;
status?: string;
}
/**
* 菜单视图对象类型
*/
export interface MenuVO extends BaseEntity {
parentName: string;
parentId: string | number;
children: MenuVO[];
menuId: string | number;
menuName: string;
orderNum: number;
path: string;
component: string;
queryParam: string;
isFrame: string;
isCache: string;
menuType: MenuTypeEnum;
visible: string;
status: string;
icon: string;
activeMenu: string;
ext: string;
remark: string;
}
export interface MenuForm {
parentName?: string;
parentId?: string | number;
children?: MenuForm[];
menuId?: string | number;
menuName: string;
orderNum: number;
path: string;
component?: string;
queryParam?: string;
isFrame?: string;
isCache?: string;
menuType?: MenuTypeEnum;
visible?: string;
status?: string;
icon?: string;
activeMenu?: string;
ext?: string;
remark?: string;
query?: string;
perms?: string;
}
+10
View File
@@ -0,0 +1,10 @@
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { MessageBoxVO } from './types';
export function getMessageBox(): AxiosPromise<MessageBoxVO> {
return request({
url: '/resource/message/box',
method: 'get'
});
}
+17
View File
@@ -0,0 +1,17 @@
export interface MessageVO extends BaseEntity {
messageId: number | string;
category: string;
type: string;
source: string;
title: string;
message: string;
content?: string;
data?: Record<string, any> | null;
path?: string;
}
export interface MessageBoxVO {
systemList: MessageVO[];
noticeList: MessageVO[];
workflowList: MessageVO[];
}
+46
View File
@@ -0,0 +1,46 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { NoticeForm, NoticeQuery, NoticeVO } from './types';
// 查询公告列表
export function listNotice(query: NoticeQuery): AxiosPromise<PageResult<NoticeVO>> {
return request({
url: '/system/notice/list',
method: 'get',
params: query
});
}
// 查询公告详细
export function getNotice(noticeId: string | number): AxiosPromise<NoticeVO> {
return request({
url: '/system/notice/' + noticeId,
method: 'get'
});
}
// 新增公告
export function addNotice(data: NoticeForm) {
return request({
url: '/system/notice',
method: 'post',
data: data
});
}
// 修改公告
export function updateNotice(data: NoticeForm) {
return request({
url: '/system/notice',
method: 'put',
data: data
});
}
// 删除公告
export function delNotice(noticeId: string | number | Array<string | number>) {
return request({
url: '/system/notice/' + noticeId,
method: 'delete'
});
}
+26
View File
@@ -0,0 +1,26 @@
export interface NoticeVO extends BaseEntity {
noticeId: number;
noticeTitle: string;
noticeType: string;
noticeContent: string;
status: string;
remark: string;
createByName: string;
}
export interface NoticeQuery extends PageQuery {
noticeTitle: string;
createByName: string;
status: string;
noticeType: string;
}
export interface NoticeForm {
noticeId: number | string | undefined;
noticeTitle: string;
noticeType: string;
noticeContent: string;
status: string;
remark: string;
createByName: string;
}
+38
View File
@@ -0,0 +1,38 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { OssQuery, OssUploadVO, OssVO } from './types';
// 查询OSS对象存储列表
export function listOss(query: OssQuery): AxiosPromise<PageResult<OssVO>> {
return request({
url: '/resource/oss/list',
method: 'get',
params: query
});
}
// 查询OSS对象基于id串
export function listByIds(ossId: string | number): AxiosPromise<OssVO[]> {
return request({
url: '/resource/oss/listByIds/' + ossId,
method: 'get'
});
}
// 上传OSS对象存储
export function uploadOss(data: FormData): AxiosPromise<OssUploadVO> {
return request({
url: '/resource/oss/upload',
method: 'post',
data
});
}
// 删除OSS对象存储
export function delOss(ossId: string | number | Array<string | number>) {
return request({
url: '/resource/oss/' + ossId,
method: 'delete'
});
}
+42
View File
@@ -0,0 +1,42 @@
export interface OssVO extends BaseEntity {
ossId: string | number;
fileName: string;
originalName: string;
fileSuffix: string;
url: string;
createByName: string;
service: string;
}
export interface OssUploadVO {
url: string;
fileName: string;
ossId: string;
}
export interface OssQuery extends PageQuery {
fileName: string;
originalName: string;
fileSuffix: string;
createTime: string;
service: string;
orderByColumn: string;
isAsc: string;
}
export interface OssForm {
file: undefined | string;
}
export interface SysOssExt {
bizType?: string;
fileSize?: number;
contentType?: string;
source?: string;
uploadIp?: string;
remark?: string;
tags?: string[];
refId?: string;
refType?: string;
isTemp?: boolean;
md5?: string;
}
@@ -0,0 +1,61 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { OssConfigForm, OssConfigQuery, OssConfigVO } from './types';
// 查询对象存储配置列表
export function listOssConfig(query: OssConfigQuery): AxiosPromise<PageResult<OssConfigVO>> {
return request({
url: '/resource/oss/config/list',
method: 'get',
params: query
});
}
// 查询对象存储配置详细
export function getOssConfig(ossConfigId: string | number): AxiosPromise<OssConfigVO> {
return request({
url: '/resource/oss/config/' + ossConfigId,
method: 'get'
});
}
// 新增对象存储配置
export function addOssConfig(data: OssConfigForm) {
return request({
url: '/resource/oss/config',
method: 'post',
data: data
});
}
// 修改对象存储配置
export function updateOssConfig(data: OssConfigForm) {
return request({
url: '/resource/oss/config',
method: 'put',
data: data
});
}
// 删除对象存储配置
export function delOssConfig(ossConfigId: string | number | Array<string | number>) {
return request({
url: '/resource/oss/config/' + ossConfigId,
method: 'delete'
});
}
// 对象存储状态修改
export function changeOssConfigStatus(ossConfigId: string | number, status: string, configKey: string) {
const data = {
ossConfigId,
status,
configKey
};
return request({
url: '/resource/oss/config/changeStatus',
method: 'put',
data: data
});
}
@@ -0,0 +1,38 @@
export interface OssConfigVO extends BaseEntity {
ossConfigId: number | string;
configKey: string;
accessKey: string;
secretKey: string;
bucketName: string;
prefix: string;
endpoint: string;
domainUrl: string;
isHttps: string;
region: string;
status: string;
ext1: string;
remark: string;
accessPolicy: string;
}
export interface OssConfigQuery extends PageQuery {
configKey: string;
bucketName: string;
status: string;
}
export interface OssConfigForm {
ossConfigId: string | number | undefined;
configKey: string;
accessKey: string;
secretKey: string;
bucketName: string;
prefix: string;
endpoint: string;
domainUrl: string;
isHttps: string;
accessPolicy: string;
region: string;
status: string;
remark: string;
}
+70
View File
@@ -0,0 +1,70 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { DeptTreeVO } from '../dept/types';
import type { PostForm, PostQuery, PostVO } from './types';
// 查询岗位列表
export function listPost(query: PostQuery): AxiosPromise<PageResult<PostVO>> {
return request({
url: '/system/post/list',
method: 'get',
params: query
});
}
// 查询岗位详细
export function getPost(postId: string | number): AxiosPromise<PostVO> {
return request({
url: '/system/post/' + postId,
method: 'get'
});
}
// 获取岗位选择框列表
export function optionselect(deptId?: number | string, postIds?: (number | string)[]): AxiosPromise<PostVO[]> {
return request({
url: '/system/post/optionselect',
method: 'get',
params: {
postIds: postIds,
deptId: deptId
}
});
}
// 新增岗位
export function addPost(data: PostForm) {
return request({
url: '/system/post',
method: 'post',
data: data
});
}
// 修改岗位
export function updatePost(data: PostForm) {
return request({
url: '/system/post',
method: 'put',
data: data
});
}
// 删除岗位
export function delPost(postId: string | number | (string | number)[]) {
return request({
url: '/system/post/' + postId,
method: 'delete'
});
}
/**
* 查询部门下拉树结构
*/
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
return request({
url: '/system/post/deptTree',
method: 'get'
});
};
+31
View File
@@ -0,0 +1,31 @@
export interface PostVO extends BaseEntity {
postId: number | string;
deptId: number | string;
postCode: string;
postName: string;
postCategory: string;
deptName: string;
postSort: number;
status: string;
remark: string;
}
export interface PostForm {
postId: number | string | undefined;
deptId: number | string | undefined;
postCode: string;
postName: string;
postCategory: string;
postSort: number;
status: string;
remark: string;
}
export interface PostQuery extends PageQuery {
deptId: number | string;
belongDeptId: number | string;
postCode: string;
postName: string;
postCategory: string;
status: string;
}
+160
View File
@@ -0,0 +1,160 @@
import type { UserQuery, UserVO } from '@/api/system/user/types';
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { RoleDeptTree, RoleQuery, RoleVO } from './types';
export const listRole = (query: RoleQuery): AxiosPromise<PageResult<RoleVO>> => {
return request({
url: '/system/role/list',
method: 'get',
params: query
});
};
/**
* 通过roleIds查询角色
* @param roleIds
*/
export const optionSelect = (roleIds: (number | string)[]): AxiosPromise<RoleVO[]> => {
return request({
url: '/system/role/optionselect?roleIds=' + roleIds,
method: 'get'
});
};
/**
* 查询角色详细
*/
export const getRole = (roleId: string | number): AxiosPromise<RoleVO> => {
return request({
url: '/system/role/' + roleId,
method: 'get'
});
};
/**
* 新增角色
*/
export const addRole = (data: any) => {
return request({
url: '/system/role',
method: 'post',
data: data
});
};
/**
* 修改角色基础信息
* @param data
*/
export const updateRole = (data: any) => {
return request({
url: '/system/role',
method: 'put',
data: data
});
};
/**
* 修改角色权限(菜单权限 + 数据权限)
*/
export const updateRolePermission = (data: any) => {
return request({
url: '/system/role/permission',
method: 'put',
data: data
});
};
/**
* 角色状态修改
*/
export const changeRoleStatus = (roleId: string | number, status: string) => {
const data = {
roleId,
status
};
return request({
url: '/system/role/changeStatus',
method: 'put',
data: data
});
};
/**
* 删除角色
*/
export const delRole = (roleId: Array<string | number> | string | number) => {
return request({
url: '/system/role/' + roleId,
method: 'delete'
});
};
/**
* 查询角色已授权用户列表
*/
export const allocatedUserList = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
return request({
url: '/system/role/authUser/allocatedList',
method: 'get',
params: query
});
};
/**
* 查询角色未授权用户列表
*/
export const unallocatedUserList = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
return request({
url: '/system/role/authUser/unallocatedList',
method: 'get',
params: query
});
};
/**
* 取消用户授权角色
*/
export const authUserCancel = (data: any) => {
return request({
url: '/system/role/authUser/cancel',
method: 'put',
data: data
});
};
/**
* 批量取消用户授权角色
*/
export const authUserCancelAll = (data: any) => {
return request({
url: '/system/role/authUser/cancelAll',
method: 'put',
params: data
});
};
/**
* 授权用户选择
*/
export const authUserSelectAll = (data: any) => {
return request({
url: '/system/role/authUser/selectAll',
method: 'put',
params: data
});
};
// 根据角色ID查询部门树结构
export const deptTreeSelect = (roleId: string | number): AxiosPromise<RoleDeptTree> => {
return request({
url: '/system/role/deptTree/' + roleId,
method: 'get'
});
};
export default {
optionSelect,
listRole
};
+52
View File
@@ -0,0 +1,52 @@
/**
* 菜单树形结构类型
*/
export interface DeptTreeOption {
id: string;
label: string;
parentId: string;
weight: number;
children?: DeptTreeOption[];
}
export interface RoleDeptTree {
checkedKeys: string[];
depts: DeptTreeOption[];
}
export interface RoleVO extends BaseEntity {
roleId: string | number;
roleName: string;
roleKey: string;
roleSort: number;
dataScope: string;
menuCheckStrictly: boolean;
deptCheckStrictly: boolean;
status: string;
delFlag: string;
remark?: any;
flag: boolean;
menuIds?: Array<string | number>;
deptIds?: Array<string | number>;
admin: boolean;
}
export interface RoleQuery extends PageQuery {
roleName: string;
roleKey: string;
status: string;
}
export interface RoleForm {
roleName: string;
roleKey: string;
roleSort: number;
status: string;
menuCheckStrictly: boolean;
deptCheckStrictly: boolean;
remark: string;
dataScope?: string;
roleId: string | undefined;
menuIds: Array<string | number>;
deptIds: Array<string | number>;
}
+24
View File
@@ -0,0 +1,24 @@
import request from '@/utils/request';
// 获取跳转URL
export function authRouterUrl(source: string) {
return request({
url: '/auth/binding/' + source,
method: 'get'
});
}
// 解绑账号
export function authUnlock(authId: string) {
return request({
url: '/auth/unlock/' + authId,
method: 'delete'
});
}
//获取授权列表
export function getAuthList() {
return request({
url: '/system/social/list',
method: 'get'
});
}
+229
View File
@@ -0,0 +1,229 @@
import type { RoleVO } from '@/api/system/role/types';
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import { parseStrEmpty } from '@/utils/ruoyi';
import type { DeptTreeVO } from './../dept/types';
import type { UserForm, UserInfoVO, UserProfileForm, UserQuery, UserVO } from './types';
/**
* 查询用户列表
* @param query
*/
export const listUser = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
return request({
url: '/system/user/list',
method: 'get',
params: query
});
};
/**
* 通过用户ids查询用户
* @param userIds
*/
export const optionSelect = (userIds: (number | string)[]): AxiosPromise<UserVO[]> => {
return request({
url: '/system/user/optionselect?userIds=' + userIds,
method: 'get'
});
};
/**
* 获取用户详情
* @param userId
*/
export const getUser = (userId?: string | number): AxiosPromise<UserInfoVO> => {
return request({
url: '/system/user/' + parseStrEmpty(userId),
method: 'get'
});
};
/**
* 新增用户
*/
export const addUser = (data: UserForm) => {
return request({
url: '/system/user',
method: 'post',
data: data
});
};
/**
* 修改用户
*/
export const updateUser = (data: UserForm) => {
return request({
url: '/system/user',
method: 'put',
data: data
});
};
/**
* 删除用户
* @param userId 用户ID
*/
export const delUser = (userId: Array<string | number> | string | number) => {
return request({
url: '/system/user/' + userId,
method: 'delete'
});
};
/**
* 用户密码重置
* @param userId 用户ID
* @param password 密码
*/
export const resetUserPwd = (userId: string | number, password: string) => {
const data = {
userId,
password
};
return request({
url: '/system/user/resetPwd',
method: 'put',
headers: {
isEncrypt: true,
repeatSubmit: false
},
data: data
});
};
/**
* 用户状态修改
* @param userId 用户ID
* @param status 用户状态
*/
export const changeUserStatus = (userId: number | string, status: string) => {
const data = {
userId,
status
};
return request({
url: '/system/user/changeStatus',
method: 'put',
data: data
});
};
/**
* 解锁用户
* @param userId 用户ID
*/
export const unlockUser = (userId: number | string) => {
return request({
url: '/system/user/unlock/' + userId,
method: 'get'
});
};
/**
* 查询用户个人信息
*/
export const getUserProfile = (): AxiosPromise<UserInfoVO> => {
return request({
url: '/system/user/profile',
method: 'get'
});
};
/**
* 修改用户个人信息
* @param data 用户信息
*/
export const updateUserProfile = (data: UserProfileForm) => {
return request({
url: '/system/user/profile',
method: 'put',
data: data
});
};
/**
* 用户密码重置
* @param oldPassword 旧密码
* @param newPassword 新密码
*/
export const updateUserPwd = (oldPassword: string, newPassword: string) => {
const data = {
oldPassword,
newPassword
};
return request({
url: '/system/user/profile/updatePwd',
method: 'put',
headers: {
isEncrypt: true,
repeatSubmit: false
},
data: data
});
};
/**
* 查询授权角色
* @param userId 用户ID
*/
export const getAuthRole = (userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> => {
return request({
url: '/system/user/authRole/' + userId,
method: 'get'
});
};
/**
* 保存授权角色
* @param data 用户ID
*/
export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
return request({
url: '/system/user/authRole',
method: 'put',
params: data
});
};
/**
* 查询当前部门的所有用户信息
* @param deptId
*/
export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]> => {
return request({
url: '/system/user/list/dept/' + deptId,
method: 'get'
});
};
/**
* 查询部门下拉树结构
*/
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
return request({
url: '/system/user/deptTree',
method: 'get'
});
};
export default {
listUser,
getUser,
optionSelect,
addUser,
updateUser,
delUser,
resetUserPwd,
changeUserStatus,
unlockUser,
getUserProfile,
updateUserProfile,
updateUserPwd,
getAuthRole,
updateAuthRole,
deptTreeSelect,
listUserByDeptId
};
+101
View File
@@ -0,0 +1,101 @@
import type { PostVO } from '@/api/system/post/types';
import type { RoleVO } from '@/api/system/role/types';
/**
* 用户信息
*/
export interface UserInfo {
user: UserVO;
roles: string[];
permissions: string[];
}
/**
* 用户查询对象类型
*/
export interface UserQuery extends PageQuery {
userName?: string;
nickName?: string;
phoneNumber?: string;
status?: string;
deptId?: string | number;
roleId?: string | number;
userIds?: string | number | (string | number)[] | undefined;
}
/**
* 用户返回对象
*/
export interface UserVO extends BaseEntity {
userId: string | number;
tenantId: string;
deptId: number;
userName: string;
nickName: string;
userType: string;
email: string;
phoneNumber: string;
gender: string;
avatar?: string | number;
avatarUrl?: string;
status: string;
delFlag: string;
loginIp: string;
loginDate: string;
remark: string;
deptName: string;
/** 详情接口可能返回嵌套部门 */
dept?: { deptName?: string };
roles: RoleVO[];
roleIds: any;
postIds: any;
roleId: any;
admin: boolean;
}
/**
* 用户表单类型
*/
export interface UserForm {
id?: string;
userId?: string;
deptId?: number;
userName: string;
nickName?: string;
password: string;
phoneNumber?: string;
email?: string;
gender?: string;
status: string;
remark?: string;
avatar?: string | number;
postIds: string[];
roleIds: string[];
}
/**
* 个人资料表单类型
*/
export interface UserProfileForm {
nickName?: string;
phoneNumber?: string;
email?: string;
gender?: string;
avatar?: string | number;
}
export interface UserInfoVO {
user: UserVO;
roles: RoleVO[];
roleIds: string[];
posts: PostVO[];
postIds: string[];
roleGroup: string;
postGroup: string;
}
export interface ResetPwdForm {
oldPassword: string;
newPassword: string;
confirmPassword: string;
}
+81
View File
@@ -0,0 +1,81 @@
import type { PageResult } from '@/api/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
import type { DbTableForm, DbTableQuery, DbTableVO, GenTableDetailPayload, TableQuery, TableVO } from './types';
export type { GenTableDetailPayload } from './types';
// 查询生成表数据
export const listTable = (query: TableQuery): AxiosPromise<PageResult<TableVO>> => {
return request({
url: '/tool/gen/list',
method: 'get',
params: query
});
};
// 查询db数据库列表
export const listDbTable = (query: DbTableQuery): AxiosPromise<PageResult<DbTableVO>> => {
return request({
url: '/tool/gen/db/list',
method: 'get',
params: query
});
};
// 查询表详细信息
export const getGenTable = (tableId: string | number): AxiosPromise<GenTableDetailPayload> => {
return request({
url: '/tool/gen/' + tableId,
method: 'get'
});
};
// 修改代码生成信息
export const updateGenTable = (data: DbTableForm): AxiosPromise<unknown> => {
return request({
url: '/tool/gen',
method: 'put',
data: data
});
};
// 导入表
export const importTable = (data: { tables: string; dataName: string }): AxiosPromise<unknown> => {
return request({
url: '/tool/gen/importTable',
method: 'post',
params: data
});
};
// 预览生成代码
export const previewTable = (tableId: string | number) => {
return request({
url: '/tool/gen/preview/' + tableId,
method: 'get'
});
};
// 删除表数据
export const delTable = (tableId: string | number | Array<string | number>) => {
return request({
url: '/tool/gen/' + tableId,
method: 'delete'
});
};
// 同步数据库
export const synchDb = (tableId: string | number) => {
return request({
url: '/tool/gen/synchDb/' + tableId,
method: 'get'
});
};
// 获取数据源名称
export const getDataNames = () => {
return request({
url: '/tool/gen/getDataNames',
method: 'get'
});
};
+215
View File
@@ -0,0 +1,215 @@
export interface TableVO extends BaseEntity {
createDept: number | string;
tableId: string | number;
dataName: string;
tableName: string;
tableComment: string;
className: string;
tplCategory: string;
frontendType: string;
packageName: string;
moduleName: string;
businessName: string;
functionName: string;
functionAuthor: string;
pkColumn?: any;
columns?: any;
options?: any;
remark?: any;
treeCode?: any;
treeParentCode?: any;
treeName?: any;
menuIds?: any;
parentMenuId?: any;
parentMenuName?: any;
enableExport?: boolean;
enableStatus?: boolean;
statusField?: string;
enableUnique?: boolean;
uniqueFields?: string[];
enableSort?: boolean;
sortField?: string;
treeRootValue?: string;
treeAncestorsField?: string;
treeOrderField?: string;
tree: boolean;
crud: boolean;
}
export interface TableQuery extends PageQuery {
tableName: string;
tableComment: string;
dataName: string;
}
export interface DbColumnVO extends BaseEntity {
createDept?: any;
columnId?: any;
tableId?: any;
columnName?: any;
columnComment?: any;
columnType?: any;
javaType?: any;
javaField?: any;
isPk?: any;
isIncrement?: any;
isRequired?: any;
isInsert?: any;
isEdit?: any;
isList?: any;
isQuery?: any;
queryType?: any;
htmlType?: any;
dictType?: any;
sort?: any;
increment: boolean;
capJavaField?: any;
usableColumn: boolean;
superColumn: boolean;
list: boolean;
pk: boolean;
insert: boolean;
edit: boolean;
query: boolean;
required: boolean;
}
export interface DbTableVO {
createDept?: any;
tableId?: any;
tableName: string;
tableComment: string;
className?: any;
tplCategory?: any;
frontendType?: string;
packageName?: any;
moduleName?: any;
businessName?: any;
functionName?: any;
functionAuthor?: any;
pkColumn?: any;
columns: DbColumnVO[];
options?: any;
remark?: any;
treeCode?: any;
treeParentCode?: any;
treeName?: any;
menuIds?: any;
parentMenuId?: any;
parentMenuName?: any;
enableExport?: boolean;
enableStatus?: boolean;
statusField?: string;
enableUnique?: boolean;
uniqueFields?: string[];
enableSort?: boolean;
sortField?: string;
treeRootValue?: string;
treeAncestorsField?: string;
treeOrderField?: string;
tree: boolean;
crud: boolean;
}
export interface DbTableQuery extends PageQuery {
dataName: string;
tableName: string;
tableComment: string;
}
/**
* 代码生成表详情接口 data 结构
* - info:当前表 GenTable
* - rows:字段列表 GenTableColumn[]
*/
export interface GenTableDetailPayload {
info: DbTableVO;
rows: DbColumnVO[];
}
export interface DbColumnForm extends BaseEntity {
createDept: number;
columnId: string;
tableId: string;
columnName: string;
columnComment: string;
columnType: string;
javaType: string;
javaField: string;
isPk: string;
isIncrement: string;
isRequired: string;
isInsert?: any;
isEdit: string;
isList: string;
isQuery?: any;
queryType: string;
htmlType: string;
dictType: string;
sort: number;
increment: boolean;
capJavaField: string;
usableColumn: boolean;
superColumn: boolean;
list: boolean;
pk: boolean;
insert: boolean;
edit: boolean;
query: boolean;
required: boolean;
}
export interface DbParamForm {
treeCode?: any;
treeName?: any;
treeParentCode?: any;
parentMenuId: string;
enableExport?: boolean;
enableStatus?: boolean;
statusField?: string;
enableUnique?: boolean;
uniqueFields?: string[];
enableSort?: boolean;
sortField?: string;
treeRootValue?: string;
treeAncestorsField?: string;
treeOrderField?: string;
}
export interface DbTableForm extends BaseEntity {
createDept?: any;
tableId: string | string;
tableName: string;
tableComment: string;
className: string;
tplCategory: string;
frontendType: string;
packageName: string;
moduleName: string;
businessName: string;
functionName: string;
functionAuthor: string;
pkColumn?: any;
columns: DbColumnForm[];
options: string;
remark?: any;
treeCode?: any;
treeParentCode?: any;
treeName?: any;
menuIds?: any;
parentMenuId: string;
parentMenuName?: any;
enableExport?: boolean;
enableStatus?: boolean;
statusField?: string;
enableUnique?: boolean;
uniqueFields?: string[];
enableSort?: boolean;
sortField?: string;
treeRootValue?: string;
treeAncestorsField?: string;
treeOrderField?: string;
tree: boolean;
crud: boolean;
params: DbParamForm;
}
+51
View File
@@ -0,0 +1,51 @@
/**
* 注册
*/
export type RegisterForm = {
username: string;
password: string;
confirmPassword?: string;
code?: string;
uuid?: string;
userType?: string;
};
/**
* 登录请求
*/
export interface LoginData {
username?: string;
password?: string;
rememberMe?: boolean;
socialCode?: string;
socialState?: string;
source?: string;
code?: string;
uuid?: string;
clientId: string;
grantType: string;
}
/**
* 登录响应
*/
export interface LoginResult {
access_token: string;
}
/**
* 验证码返回
*/
export interface VerifyCodeResult {
captchaEnabled: boolean;
uuid?: string;
img?: string;
}
/**
* 分页返回结果
*/
export interface PageResult<T = any> {
total: number;
rows: T[];
}
@@ -0,0 +1,76 @@
import type { CategoryForm, CategoryQuery, CategoryTreeVO, CategoryVO } from '@/api/workflow/category/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 查询流程分类列表
* @param query
* @returns {*}
*/
export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
return request({
url: '/workflow/category/list',
method: 'get',
params: query
});
};
/**
* 查询流程分类详细
* @param categoryId
*/
export const getCategory = (categoryId: string | number): AxiosPromise<CategoryVO> => {
return request({
url: '/workflow/category/' + categoryId,
method: 'get'
});
};
/**
* 新增流程分类
* @param data
*/
export const addCategory = (data: CategoryForm) => {
return request({
url: '/workflow/category',
method: 'post',
data: data
});
};
/**
* 修改流程分类
* @param data
*/
export const updateCategory = (data: CategoryForm) => {
return request({
url: '/workflow/category',
method: 'put',
data: data
});
};
/**
* 删除流程分类
* @param categoryId
*/
export const delCategory = (categoryId: string | number | Array<string | number>) => {
return request({
url: '/workflow/category/' + categoryId,
method: 'delete'
});
};
/**
* 获取流程分类树列表
* @param query 流程实例id
* @returns
*/
export const categoryTree = (query?: CategoryForm): AxiosPromise<CategoryTreeVO[]> => {
return request({
url: `/workflow/category/categoryTree`,
method: 'get',
params: query
});
};
@@ -0,0 +1,67 @@
export interface CategoryTreeVO {
id: number | string;
label: string;
parentId: number | string;
weight: number;
children: CategoryTreeVO[];
}
export interface CategoryVO {
/**
* 流程分类ID
*/
categoryId: string | number;
/**
* 父级id
*/
parentId: string | number;
/**
* 流程分类名称
*/
categoryName: string;
/**
* 显示顺序
*/
orderNum: number;
/**
* 创建时间
*/
createTime: string;
/**
* 子对象
*/
children: CategoryVO[];
}
export interface CategoryForm extends BaseEntity {
/**
* 流程分类ID
*/
categoryId?: string | number;
/**
* 流程分类名称
*/
categoryName?: string;
/**
* 父流程分类id
*/
parentId?: string | number;
/**
* 显示顺序
*/
orderNum?: number;
}
export interface CategoryQuery {
/**
* 流程分类名称
*/
categoryName?: string;
}
@@ -0,0 +1,176 @@
import type { PageResult } from '@/api/types';
import type {
definitionXmlVO,
FlowDefinitionForm,
FlowDefinitionQuery,
FlowDefinitionVo
} from '@/api/workflow/definition/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 获取流程定义列表
* @param query 流程实例id
* @returns
*/
export const listDefinition = (query: FlowDefinitionQuery): AxiosPromise<PageResult<FlowDefinitionVo>> => {
return request({
url: `/workflow/definition/list`,
method: 'get',
params: query
});
};
/**
* 查询未发布的流程定义列表
* @param query 流程实例id
* @returns
*/
export const unPublishList = (query: FlowDefinitionQuery): AxiosPromise<PageResult<FlowDefinitionVo>> => {
return request({
url: `/workflow/definition/unPublishList`,
method: 'get',
params: query
});
};
/**
* 通过流程定义id获取xml
* @param definitionId 流程定义id
* @returns
*/
export const definitionXml = (definitionId: string): AxiosPromise<definitionXmlVO> => {
return request({
url: `/workflow/definition/definitionXml/${definitionId}`,
method: 'get'
});
};
/**
* 删除流程定义
* @param id 流程定义id
* @returns
*/
export const deleteDefinition = (id: string | string[]) => {
return request({
url: `/workflow/definition/${id}`,
method: 'delete'
});
};
/**
* 挂起/激活
* @param definitionId 流程定义id
* @param activityStatus 状态
* @returns
*/
export const active = (definitionId: string, activityStatus: boolean) => {
return request({
url: `/workflow/definition/active/${definitionId}`,
method: 'put',
params: {
active: activityStatus
}
});
};
/**
* 通过zip或xml部署流程定义
* @returns
*/
export function importDef(data: any) {
return request({
url: '/workflow/definition/importDef',
method: 'post',
data: data,
headers: {
repeatSubmit: false
}
});
}
/**
* 发布流程定义
* @param id 流程定义id
* @returns
*/
export const publish = (id: string) => {
return request({
url: `/workflow/definition/publish/${id}`,
method: 'put'
});
};
/**
* 取消发布流程定义
* @param id 流程定义id
* @returns
*/
export const unPublish = (id: string) => {
return request({
url: `/workflow/definition/unPublish/${id}`,
method: 'put'
});
};
/**
* 获取流程定义xml字符串
* @param id 流程定义id
* @returns
*/
export const xmlString = (id: string) => {
return request({
url: `/workflow/definition/xmlString/${id}`,
method: 'get'
});
};
/**
* 新增
* @param data 参数
* @returns
*/
export const add = (data: FlowDefinitionForm) => {
return request({
url: `/workflow/definition`,
method: 'post',
data: data
});
};
/**
* 修改
* @param data 参数
* @returns
*/
export const edit = (data: FlowDefinitionForm) => {
return request({
url: `/workflow/definition`,
method: 'put',
data: data
});
};
/**
* 查询详情
* @param id 参数
* @returns
*/
export const getInfo = (id: number | string) => {
return request({
url: `/workflow/definition/${id}`,
method: 'get'
});
};
/**
* 复制流程定义
* @param id 流程定义id
* @returns
*/
export const copy = (id: string) => {
return request({
url: `/workflow/definition/copy/${id}`,
method: 'post'
});
};
@@ -0,0 +1,34 @@
export interface FlowDefinitionQuery extends PageQuery {
flowCode?: string;
flowName?: string;
category: string | number;
isPublish?: number;
}
export interface FlowDefinitionVo {
id: string;
flowName: string;
flowCode: string;
formPath: string;
version: string;
isPublish: number;
activityStatus: number;
createTime: Date;
updateTime: Date;
}
export interface FlowDefinitionForm {
id: string;
flowName: string;
flowCode: string;
category: string;
ext: string;
formPath: string;
formCustom: string;
modelValue: string;
}
export interface definitionXmlVO {
xml: string[];
xmlStr: string;
}
+126
View File
@@ -0,0 +1,126 @@
import type { PageResult } from '@/api/types';
import type { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 查询运行中实例列表
* @param query
* @returns {*}
*/
export const pageByRunning = (query: FlowInstanceQuery): AxiosPromise<PageResult<FlowInstanceVO>> => {
return request({
url: '/workflow/instance/pageByRunning',
method: 'get',
params: query
});
};
/**
* 查询已完成实例列表
* @param query
* @returns {*}
*/
export const pageByFinish = (query: FlowInstanceQuery): AxiosPromise<PageResult<FlowInstanceVO>> => {
return request({
url: '/workflow/instance/pageByFinish',
method: 'get',
params: query
});
};
/**
* 通过业务id获取历史流程图
*/
export const flowHisTaskList = (businessId: string | number) => {
return request({
url: `/workflow/instance/flowHisTaskList/${businessId}?t=${Math.random()}`,
method: 'get'
});
};
/**
* 分页查询当前登录人单据
* @param query
* @returns {*}
*/
export const pageByCurrent = (query: FlowInstanceQuery): AxiosPromise<PageResult<FlowInstanceVO>> => {
return request({
url: '/workflow/instance/pageByCurrent',
method: 'get',
params: query
});
};
/**
* 撤销流程
* @param data 参数
* @returns
*/
export const cancelProcessApply = (data: any) => {
return request({
url: `/workflow/instance/cancelProcessApply`,
method: 'put',
data: data
});
};
/**
* 获取流程变量
* @param instanceId 实例id
* @returns
*/
export const instanceVariable = (instanceId: string | number) => {
return request({
url: `/workflow/instance/instanceVariable/${instanceId}`,
method: 'get'
});
};
/**
* 删除
* @param instanceIds 流程实例id
* @returns
*/
export const deleteByInstanceIds = (instanceIds: Array<string | number> | string | number) => {
return request({
url: `/workflow/instance/deleteByInstanceIds/${instanceIds}`,
method: 'delete'
});
};
/**
* 删除历史流程实例
* @param instanceIds
*/
export const deleteHisByInstanceIds = (instanceIds: Array<string | number> | string | number) => {
return request({
url: `/workflow/instance/deleteHisByInstanceIds/${instanceIds}`,
method: 'delete'
});
};
/**
* 作废流程
* @param data 参数
* @returns
*/
export const invalid = (data: any) => {
return request({
url: `/workflow/instance/invalid`,
method: 'post',
data: data
});
};
/**
* 修改流程变量
* @param data 参数
* @returns
*/
export const updateVariable = (data: any) => {
return request({
url: `/workflow/instance/updateVariable`,
method: 'put',
data: data
});
};
@@ -0,0 +1,28 @@
import type { FlowTaskVO } from '@/api/workflow/task/types';
export interface FlowInstanceQuery extends PageQuery {
category?: string | number;
nodeName?: string;
flowCode?: string;
flowName?: string;
createByIds?: Array<string | number>;
businessId?: string;
}
export interface FlowInstanceVO extends BaseEntity {
id: string | number;
definitionId: string;
flowName: string;
flowCode: string;
version: string;
businessId: string;
activityStatus: number;
tenantId: string;
createTime: string;
createBy: string;
flowStatus: string;
flowStatusName: string;
flowTaskList: FlowTaskVO[];
businessCode: string;
businessTitle: string;
}
+76
View File
@@ -0,0 +1,76 @@
import type { PageResult } from '@/api/types';
import type { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 查询请假列表
* @param query
* @returns {*}
*/
export const listLeave = (query?: LeaveQuery): AxiosPromise<PageResult<LeaveVO>> => {
return request({
url: '/workflow/leave/list',
method: 'get',
params: query
});
};
/**
* 查询请假详细
* @param id
*/
export const getLeave = (id: string | number): AxiosPromise<LeaveVO> => {
return request({
url: '/workflow/leave/' + id,
method: 'get'
});
};
/**
* 新增请假
* @param data
*/
export const addLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => {
return request({
url: '/workflow/leave',
method: 'post',
data: data
});
};
/**
* 提交请假并发起流程
* @param data
*/
export const submitAndFlowStart = (data: LeaveForm): AxiosPromise<LeaveVO> => {
return request({
url: '/workflow/leave/submitAndFlowStart',
method: 'post',
data: data
});
};
/**
* 修改请假
* @param data
*/
export const updateLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => {
return request({
url: '/workflow/leave',
method: 'put',
data: data
});
};
/**
* 删除请假
* @param id
*/
export const delLeave = (id: string | number | Array<string | number>) => {
return request({
url: '/workflow/leave/' + id,
method: 'delete'
});
};
+26
View File
@@ -0,0 +1,26 @@
export interface LeaveVO {
id: string | number;
applyCode?: string;
leaveType: string;
startDate: string;
endDate: string;
leaveDays: number;
remark: string;
status?: string;
}
export interface LeaveForm extends BaseEntity {
id?: string | number;
applyCode?: string;
leaveType?: string;
startDate?: string;
endDate?: string;
leaveDays?: number;
remark?: string;
status?: string;
}
export interface LeaveQuery extends PageQuery {
startLeaveDays?: number;
endLeaveDays?: number;
}
+64
View File
@@ -0,0 +1,64 @@
import type { PageResult } from '@/api/types';
import type { SpelForm, SpelQuery, SpelVO } from '@/api/workflow/spel/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 查询流程spel表达式定义列表
* @param query
* @returns {*}
*/
export const listSpel = (query?: SpelQuery): AxiosPromise<PageResult<SpelVO>> => {
return request({
url: '/workflow/spel/list',
method: 'get',
params: query
});
};
/**
* 查询流程spel表达式定义详细
* @param id
*/
export const getSpel = (id: string | number): AxiosPromise<SpelVO> => {
return request({
url: '/workflow/spel/' + id,
method: 'get'
});
};
/**
* 新增流程spel表达式定义
* @param data
*/
export const addSpel = (data: SpelForm) => {
return request({
url: '/workflow/spel',
method: 'post',
data: data
});
};
/**
* 修改流程spel表达式定义
* @param data
*/
export const updateSpel = (data: SpelForm) => {
return request({
url: '/workflow/spel',
method: 'put',
data: data
});
};
/**
* 删除流程spel表达式定义
* @param id
*/
export const delSpel = (id: string | number | Array<string | number>) => {
return request({
url: '/workflow/spel/' + id,
method: 'delete'
});
};
+105
View File
@@ -0,0 +1,105 @@
export interface SpelVO {
/**
* 主键id
*/
id: string | number;
/**
* 组件名称
*/
componentName: string;
/**
* 方法名
*/
methodName: string;
/**
* 参数
*/
methodParams: string;
/**
* 预览spel值
*/
viewSpel: string;
/**
* 状态(0正常 1停用)
*/
status: string;
/**
* 备注
*/
remark?: string;
}
export interface SpelForm extends BaseEntity {
/**
* 主键id
*/
id?: string | number;
/**
* 组件名称
*/
componentName?: string;
/**
* 方法名
*/
methodName?: string;
/**
* 参数
*/
methodParams?: string;
/**
* 预览spel值
*/
viewSpel?: string;
/**
* 状态(0正常 1停用)
*/
status?: string;
/**
* 备注
*/
remark?: string;
}
export interface SpelQuery extends PageQuery {
/**
* 组件名称
*/
componentName?: string;
/**
* 方法名
*/
methodName?: string;
/**
* 参数
*/
methodParams?: string;
/**
* 预览spel值
*/
viewSpel?: string;
/**
* 状态(0正常 1停用)
*/
status?: string;
/**
* 日期范围参数
*/
params?: any;
}
+207
View File
@@ -0,0 +1,207 @@
import type { PageResult } from '@/api/types';
import type { FlowTaskVO, TaskOperationBo, TaskQuery } from '@/api/workflow/task/types';
import type { AxiosPromise } from '@/utils/api-types';
import request from '@/utils/request';
/**
* 查询待办列表
* @param query
* @returns {*}
*/
export const pageByTaskWait = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
return request({
url: '/workflow/task/pageByTaskWait',
method: 'get',
params: query
});
};
/**
* 查询已办列表
* @param query
* @returns {*}
*/
export const pageByTaskFinish = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
return request({
url: '/workflow/task/pageByTaskFinish',
method: 'get',
params: query
});
};
/**
* 查询当前用户的抄送列表
* @param query
* @returns {*}
*/
export const pageByTaskCopy = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
return request({
url: '/workflow/task/pageByTaskCopy',
method: 'get',
params: query
});
};
/**
* 查询全部待办任务
* @param query
* @returns {*}
*/
export const pageByAllTaskWait = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
return request({
url: '/workflow/task/pageByAllTaskWait',
method: 'get',
params: query
});
};
/**
* 查询全部已办任务
* @param query
* @returns {*}
*/
export const pageByAllTaskFinish = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
return request({
url: '/workflow/task/pageByAllTaskFinish',
method: 'get',
params: query
});
};
/**
* 启动流程
* @param data
* @returns {*}
*/
export const startWorkFlow = (data: object): any => {
return request({
url: '/workflow/task/startWorkFlow',
method: 'post',
data: data
});
};
/**
* 办理流程
* @param data
* @returns {*}
*/
export const completeTask = (data: object) => {
return request({
url: '/workflow/task/completeTask',
method: 'post',
data: data
});
};
/**
* 任务驳回
* @param data
* @returns {*}
*/
export const backProcess = (data: any): any => {
return request({
url: '/workflow/task/backProcess',
method: 'post',
data: data
});
};
/**
* 获取当前任务
* @param taskId
* @returns
*/
export const getTask = (taskId: string) => {
return request({
url: '/workflow/task/getTask/' + taskId,
method: 'get'
});
};
/**
* 修改任务办理人
* @param taskIdList
* @param userId
* @returns
*/
export const updateAssignee = (taskIdList: Array<string>, userId: string) => {
return request({
url: `/workflow/task/updateAssignee/${userId}`,
method: 'put',
data: taskIdList
});
};
/**
* 终止任务
* @returns
*/
export const terminationTask = (data: any) => {
return request({
url: `/workflow/task/terminationTask`,
method: 'post',
data: data
});
};
/**
* 获取可驳回得任务节点
* @returns
*/
export const getBackTaskNode = (taskId: string | number, nodeCode: string) => {
return request({
url: `/workflow/task/getBackTaskNode/${taskId}/${nodeCode}`,
method: 'get'
});
};
/**
* 任务操作 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
* @returns
*/
export const taskOperation = (data: TaskOperationBo, operation: string) => {
return request({
url: `/workflow/task/taskOperation/${operation}`,
method: 'post',
data: data
});
};
/**
* 获取当前任务办理人
* @param taskId 任务id
* @returns
*/
export const currentTaskAllUser = (taskId: string | number) => {
return request({
url: `/workflow/task/currentTaskAllUser/${taskId}`,
method: 'get'
});
};
/**
* 获取下一节点写
* @param data参数
* @returns
*/
export const getNextNodeList = (data: any): any => {
return request({
url: '/workflow/task/getNextNodeList',
method: 'post',
data: data
});
};
/**
* 催办任务
* @param data参数
* @returns
*/
export const urgeTask = (data: any): any => {
return request({
url: '/workflow/task/urgeTask',
method: 'post',
data: data
});
};
+60
View File
@@ -0,0 +1,60 @@
export interface TaskQuery extends PageQuery {
nodeName?: string;
flowCode?: string;
flowName?: string;
createByIds?: Array<string | number>;
}
export interface ParticipantVo {
groupIds?: string[] | number[];
candidate: string[] | number[];
candidateName: string[];
claim: boolean;
}
export interface FlowTaskVO {
id: string | number;
createTime?: Date;
updateTime?: Date;
tenantId?: string;
definitionId?: string;
instanceId: string;
flowName: string;
businessId: string;
nodeCode: string;
nodeName: string;
flowCode: string;
flowStatus: string;
formCustom: string;
formPath: string;
nodeType: number;
nodeRatio: string | number;
version?: string;
applyNode?: boolean;
buttonList?: ButtonList[];
copyList?: FlowCopyVo[];
varList?: Map<string, string>;
businessCode: string;
businessTitle: string;
}
export interface ButtonList {
code: string;
show: boolean;
}
export interface FlowCopyVo {
userId: string | number;
nickName: string;
}
export interface TaskOperationBo {
//委派/转办人的用户ID(必填,准对委派/转办人操作)
userId?: string;
//加签/减签人的用户ID列表(必填,针对加签/减签操作)
userIds?: string[];
//任务ID(必填)
taskId: string | number;
//消息类型
messageType?: string[];
//意见或备注信息(可选)
message?: string;
}
@@ -0,0 +1,17 @@
import type { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
import tab from '@/plugins/tab';
import router from '@/router';
export default {
routerJump(routerJumpVo: RouterJumpVo) {
tab.closePage(router.currentRoute.value);
router.push({
path: routerJumpVo.formPath,
query: {
id: routerJumpVo.businessId,
type: routerJumpVo.type,
taskId: routerJumpVo.taskId
}
});
}
};
@@ -0,0 +1,14 @@
export interface RouterJumpVo {
businessId: string;
taskId: string | number;
type: string;
formCustom: string;
formPath: string;
}
export interface StartProcessBo {
businessId: string | number;
flowCode: string;
variables: any;
bizExt: any;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

+1
View File
@@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+1
View File
@@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899741379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2054" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M960 591.424V368.96c0-0.288 0.16-0.512 0.16-0.768S960 367.68 960 367.424V192a32 32 0 0 0-32-32H96a32 32 0 0 0-32 32v175.424c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768v222.464c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768V864a32 32 0 0 0 32 32h832a32 32 0 0 0 32-32v-271.04c0-0.288 0.16-0.512 0.16-0.768S960 591.68 960 591.424z m-560-31.232v-160H608v160h-208z m208 64V832h-208v-207.808H608z m-480-224h208v160H128v-160z m544 0h224v160h-224v-160zM896 224v112.192H128V224h768zM128 624.192h208V832H128v-207.808zM672 832v-207.808h224V832h-224z" p-id="2055"></path></svg>

After

Width:  |  Height:  |  Size: 954 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588670460195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1314" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M230.4 307.712c13.824 0 25.088-11.264 25.088-25.088 0-100.352 81.92-182.272 182.272-182.272s182.272 81.408 182.272 182.272c0 13.824 11.264 25.088 25.088 25.088s25.088-11.264 24.576-25.088c0-127.488-103.936-231.936-231.936-231.936S205.824 154.624 205.824 282.624c-0.512 14.336 10.752 25.088 24.576 25.088z m564.736 234.496c-11.264 0-21.504 2.048-31.232 6.144 0-44.544-40.448-81.92-88.064-81.92-14.848 0-28.16 3.584-39.936 10.24-13.824-28.16-44.544-48.128-78.848-48.128-12.288 0-24.576 2.56-35.328 7.68V284.16c0-45.568-37.888-81.92-84.48-81.92s-84.48 36.864-84.48 81.92v348.672l-69.12-112.64c-18.432-28.16-58.368-36.864-91.136-19.968-26.624 14.336-46.592 47.104-30.208 88.064 3.072 8.192 76.8 205.312 171.52 311.296 0 0 28.16 24.576 43.008 58.88 4.096 9.728 13.312 15.36 22.528 15.36 3.072 0 6.656-0.512 9.728-2.048 12.288-5.12 18.432-19.968 12.8-32.256-19.456-44.544-53.76-74.752-53.76-74.752C281.6 768 209.408 573.44 208.384 570.88c-5.12-12.8-2.56-20.992 7.168-26.112 9.216-4.608 21.504-4.608 26.112 2.56l113.152 184.32c4.096 8.704 12.8 14.336 22.528 14.336 13.824 0 25.088-10.752 25.088-25.088V284.16c0-17.92 15.36-32.256 34.816-32.256s34.816 14.336 34.816 32.256v284.16c0 13.824 10.24 25.088 24.576 25.088 13.824 0 25.088-11.264 25.088-25.088v-57.344c0-17.92 15.36-32.768 34.816-32.768 19.968 0 37.376 15.36 37.376 32.768v95.232c0 7.168 3.072 13.312 7.68 17.92 4.608 4.608 10.752 7.168 17.92 7.168 13.824 0 24.576-11.264 24.576-25.088V547.84c0-18.432 13.824-32.256 32.256-32.256 20.48 0 38.912 15.36 38.912 32.256v95.232c0 13.824 11.264 25.088 25.088 25.088s24.576-11.264 25.088-25.088v-18.944c0-18.944 12.8-32.256 30.72-32.256 18.432 0 22.528 18.944 22.528 31.744 0 1.024-11.776 99.84-50.688 173.056-30.72 58.368-45.056 112.128-51.2 146.944-2.56 13.312 6.656 26.112 19.968 28.672 1.536 0 3.072 0.512 4.608 0.512 11.776 0 22.016-8.192 24.064-20.48 5.632-31.232 18.432-79.36 46.08-132.608 43.52-81.92 55.808-186.88 56.32-193.536-0.512-50.688-29.696-83.968-72.704-83.968z"></path></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M321.94 98L158.82 237.78a24 24 0 000 36.44L321.94 414c15.57 13.34 39.62 2.28 39.62-18.22v-279.6c0-20.5-24.05-31.56-39.62-18.18z"/></svg>

After

Width:  |  Height:  |  Size: 223 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M190.06 414l163.12-139.78a24 24 0 000-36.44L190.06 98c-15.57-13.34-39.62-2.28-39.62 18.22v279.6c0 20.5 24.05 31.56 39.62 18.18z"/></svg>

After

Width:  |  Height:  |  Size: 223 B

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576153230908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="971" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M772.87036133 734.06115723c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714843H475.90991211c-56.60705567 0-102.66723633-46.06018067-102.66723633-102.66723633V600.82446289h305.859375c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012S827.9942627 467.50537109 772.87036133 467.50537109c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714844H373.24267578V401.01062011h321.92687989c55.12390137 0 99.94812012-44.82421875 99.94812011-99.94812011V190.07312011C795.11767578 134.94921875 750.29345703 90.125 695.16955567 90.125H251.12963867C196.0057373 90.125 151.18151855 134.94921875 151.18151855 190.07312011V301.0625c0 55.12390137 44.82421875 99.94812012 99.94812012 99.94812012h55.53588867v296.96044921c0 93.35632325 75.97045898 169.32678223 169.32678224 169.32678223h203.19213866c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012s-44.90661622-99.86572266-100.03051758-99.86572265z m0-199.89624024c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857423s-14.91394043 33.28857422-33.28857422 33.28857421-33.28857422-14.91394043-33.28857422-33.28857421 14.91394043-33.28857422 33.28857422-33.28857422zM217.75866699 301.0625V190.07312011c0-18.37463379 14.91394043-33.28857422 33.28857423-33.28857421h444.03991698c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857422V301.0625c0 18.37463379-14.91394043 33.28857422-33.28857422 33.28857422H251.12963867c-18.37463379 0-33.37097168-14.91394043-33.37097168-33.28857422z m555.11169434 566.23535156c-18.37463379 0-33.28857422-14.91394043-33.28857422-33.28857422 0-18.37463379 14.91394043-33.28857422 33.28857422-33.28857422s33.28857422 14.91394043 33.28857422 33.28857422c0.08239747 18.29223633-14.91394043 33.28857422-33.28857422 33.28857422z" p-id="972"></path></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -0,0 +1 @@
<svg t="1715954426124" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3305" width="200" height="200"><path d="M664.081597 1023.943114a78.246037 78.246037 0 0 1-78.985549-76.795456v-284.996471a78.27448 78.27448 0 0 1 78.985549-76.93767h280.843828A78.189152 78.189152 0 0 1 1023.939417 662.151187v284.996471a78.246037 78.246037 0 0 1-79.013992 76.795456z m-585.067605 0a78.246037 78.246037 0 0 1-78.985549-76.795456v-284.996471a78.160709 78.160709 0 0 1 78.985549-76.93767h280.786942a78.302923 78.302923 0 0 1 79.042434 76.93767v284.996471h-0.170656a78.246037 78.246037 0 0 1-78.985549 76.795456z m0-585.096048a78.217594 78.217594 0 0 1-78.985549-76.93767V76.912925a78.189152 78.189152 0 0 1 78.957106-76.795456h280.786942a78.27448 78.27448 0 0 1 79.042435 76.93767v284.996471a78.27448 78.27448 0 0 1-79.013992 76.795456z m589.675333-5.688552a77.193655 77.193655 0 0 1-77.990052-75.885288V75.888985a77.25054 77.25054 0 0 1 77.990052-75.942173h277.26004a77.25054 77.25054 0 0 1 77.961609 75.942173v281.384241a77.421197 77.421197 0 0 1-78.132266 75.885288z" p-id="3306" fill="currentColor"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Some files were not shown because too many files have changed in this diff Show More