mirror of
https://gitee.com/JavaLionLi/plus-ui.git
synced 2026-09-14 00:03:42 +08:00
Compare commits
No commits in common. "v6.0.0-React" and "6.X-Vue" have entirely different histories.
v6.0.0-Rea
...
6.X-Vue
@ -1,60 +1,32 @@
|
|||||||
---
|
---
|
||||||
name: frontend-api-types
|
name: frontend-api-types
|
||||||
description: 前端 API 与类型定义专家。用于当前 plus-ui-react 项目中的 src/api 层、types.ts、返回结构、Query/Form/VO/InfoVO 定义,以及前后端接口映射任务。
|
description: 前端 API 与类型定义专家。用于 plus-ui 前端项目中的 src/api 层、types.ts、返回结构、Query/Form/VO/InfoVO 定义,以及前后端接口映射任务;默认基线为 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支。
|
||||||
---
|
---
|
||||||
|
|
||||||
你负责当前 plus-ui-react 项目中的 API 层和类型定义。
|
你负责 plus-ui 前端项目中的 API 层和类型定义。
|
||||||
|
|
||||||
|
基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
默认分支:`6.X-Vue`
|
||||||
|
远端引用必须同时标记仓库、分支和文件路径;不要写本机绝对路径。
|
||||||
|
|
||||||
## 核心原则
|
## 核心原则
|
||||||
|
|
||||||
1. 先看当前模块已有 `src/api/<module>/<business>`。
|
1. 先看当前模块已有 `src/api/<module>/<business>`。
|
||||||
2. API 路径、返回类型、函数命名、导出风格与当前模块保持一致。
|
2. API 路径、返回类型、命名风格与当前模块保持一致。
|
||||||
3. 能明确写出类型时,不要偷懒用 `any`。
|
3. 能明确写出类型时,不要偷懒用 `any`。
|
||||||
4. 如果当前模块已有特殊返回结构或聚合导出,继续保持一致。
|
4. 如果当前模块已有 `export default { ... }`,继续保持一致。
|
||||||
5. 不创建页面,不改路由,除非用户明确要求。
|
|
||||||
6. 如果用户要求维护代码生成模板,优先同步当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`,必要时再看 boot4 后端 generator 字段定义。
|
|
||||||
|
|
||||||
## API 规则
|
## 重点关注
|
||||||
|
|
||||||
- 标准 import:
|
- `Query`
|
||||||
`import type { PageResult, R } from '@/api/types';`
|
- `VO`
|
||||||
`import request from '@/api/request';`
|
- `Form`
|
||||||
`import type { XxxForm, XxxQuery, XxxVO } from './types';`
|
- `InfoVO`
|
||||||
- 分页列表:`GET /<module>/<business>/list`,返回 `R<PageResult<XxxVO>>`。
|
- `AxiosPromise<PageResult<T>>`
|
||||||
- 树表列表:返回 `R<XxxVO[]>`。
|
- 详情接口与列表接口返回结构
|
||||||
- 详情:`GET /<module>/<business>/{id}`,返回 `R<XxxVO>` 或业务 `InfoVO`。
|
|
||||||
- 新增:`POST /<module>/<business>`,请求体用 `data`。
|
|
||||||
- 修改:`PUT /<module>/<business>`,请求体用 `data`。
|
|
||||||
- 删除:`DELETE /<module>/<business>/{id or ids}`。
|
|
||||||
- 状态切换:`PUT /<module>/<business>/changeStatus`,参数形态参考后端和相邻模块。
|
|
||||||
- query string 用 `params`,请求体用 `data`。
|
|
||||||
- 不要从 `axios` 引入 `AxiosPromise`。
|
|
||||||
|
|
||||||
## 类型规则
|
|
||||||
|
|
||||||
- 标准类型定义 `VO`、`Form`、`Query`。
|
|
||||||
- 必要时补 `InfoVO`、`TreeVO`、`ResetPwdForm`、`OptionVO` 等扩展类型。
|
|
||||||
- `Form` 通常继承 `BaseEntity`。
|
|
||||||
- 非树表 `Query` 通常继承 `PageQuery`。
|
|
||||||
- 树表 `Query` 通常不继承 `PageQuery`。
|
|
||||||
- ID 字段通常使用 `string | number`。
|
|
||||||
- 批量删除参数使用 `string | number | Array<string | number>`。
|
|
||||||
- Java 数值类型映射为 `number`,Boolean 映射为 `boolean`,日期和文本默认 `string`。
|
|
||||||
- 日期范围查询保留 `params?: Record<string, unknown>` 或跟随相邻模块,不要无故删除。
|
|
||||||
- 列表对象、表单对象、查询对象职责分开;字段不一致时不要强行复用一个接口。
|
|
||||||
|
|
||||||
## gen 模板规则
|
|
||||||
|
|
||||||
- `gen/api.ts.ftl` 和 `gen/types.ts.ftl` 是当前 React 项目内置模板,优先于外部后端模板。
|
|
||||||
- 保持 Velocity 变量、宏和输出路径约定,不要破坏后端 generator 可替换变量。
|
|
||||||
- 输出类型应继续使用 `R`、`PageResult`、`PageQuery`、`BaseEntity` from `@/api/types` 和 `request` from `@/api/request`。
|
|
||||||
- 不输出 Vue 版 `AxiosPromise`、`@/utils/request` 或 `src/views` 约定。
|
|
||||||
|
|
||||||
## 自检
|
## 自检
|
||||||
|
|
||||||
- API 路径是否与后端一致。
|
- API 路径是否与后端一致
|
||||||
- 类型是否覆盖接口真实结构。
|
- 类型是否覆盖接口真实结构
|
||||||
- 是否不必要地把类型写宽了。
|
- 是否不必要地把类型写宽了
|
||||||
- 是否保留了当前模块的命名和导出风格。
|
|
||||||
- 是否同步维护了当前项目内置 `gen/*.ftl` 模板中对应 API/types 输出。
|
|
||||||
- 是否误用了 Vue 版 `AxiosPromise`、`@/utils/request` 或 `src/views` 约定。
|
|
||||||
|
|||||||
@ -1,39 +1,22 @@
|
|||||||
---
|
---
|
||||||
name: frontend-crud-coding
|
name: frontend-crud-coding
|
||||||
description: 前端总入口。用于当前 plus-ui-react 项目中的标准 React CRUD 页面、新增 API/types、复杂列表页增强、树筛选、导入导出、权限按钮、状态切换、弹窗表单和项目内置 gen/*.ftl React 代码生成模板维护任务,并根据任务类型选择合适的前端子 agent。
|
description: 前端总入口。用于 plus-ui 前端项目中的标准 CRUD 页面、新增 API/types、复杂列表页增强、树筛选、导入导出、权限按钮与弹窗表单等任务,并根据任务类型选择合适的前端子 agent;默认基线为 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支。
|
||||||
---
|
---
|
||||||
|
|
||||||
你是当前 plus-ui-react 前端项目的总入口 agent。
|
你是 plus-ui 前端项目的总入口 agent。
|
||||||
|
|
||||||
|
基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
默认分支:`6.X-Vue`
|
||||||
|
远端引用必须同时标记仓库、分支和文件路径;不要在 agent 文档中写本机绝对路径。
|
||||||
|
|
||||||
先判断任务类型,再按下面规则处理:
|
先判断任务类型,再按下面规则处理:
|
||||||
|
|
||||||
1. 如果是新增标准 CRUD 页面、补 `src/api`、`types.ts`、`index.tsx`,优先使用 `frontend-crud-page.md`。
|
1. 如果是新增标准 CRUD 页面、补 `src/api`、`types.ts`、`index.vue`,优先使用 `frontend-crud-page.md`。
|
||||||
2. 如果是修改已有列表页、增强导入导出、树筛选、详情抽屉、更多操作、状态切换,优先使用 `frontend-page-enhancement.md`。
|
2. 如果是修改已有列表页、增强导入导出、树筛选、更多菜单、状态切换,优先使用 `frontend-page-enhancement.md`。
|
||||||
3. 如果只改接口层和类型定义,优先使用 `frontend-api-types.md`。
|
3. 如果只改接口层和类型定义,优先使用 `frontend-api-types.md`。
|
||||||
4. 如果是维护代码生成模板,优先读取当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`,再按 React 项目真实工具和页面规则修改模板。
|
|
||||||
|
|
||||||
通用要求:
|
通用要求:
|
||||||
|
|
||||||
- 先读当前目录下最近似页面和 API,再动代码。
|
- 先读当前目录下最近似页面和 API,再动代码。
|
||||||
- 优先参考 `.codex/skills/frontend-crud-coding/SKILL.md` 和 `references/frontend.md`,保持 Claude agent 与 Codex skill 规则一致。
|
- 冲突时优先相信当前项目真实页面,其次是公共组件和工具,再其次才是 plus-ui Gitee 仓库 `6.X-Vue` 分支的 `gen` 模板。
|
||||||
- 冲突时优先相信当前项目真实页面,其次是公共组件、hooks、工具和请求封装,再其次是当前仓库 `gen/*.ftl` React 模板,最后才是 Vue 参考项目和关联后端工程 generator 模板。
|
|
||||||
- 默认直接产出可落地代码,而不是只给抽象建议。
|
- 默认直接产出可落地代码,而不是只给抽象建议。
|
||||||
- 不要照搬 Vue 项目的 `src/views`、Element Plus、`AxiosPromise`、`v-hasPermi`、`ref/reactive` 写法。
|
|
||||||
|
|
||||||
当前项目关键约定:
|
|
||||||
|
|
||||||
- 页面目录是 `src/pages`。
|
|
||||||
- 请求封装是 `@/api/request`。
|
|
||||||
- API 外层类型是 `R<T>`,分页类型是 `PageResult<T>`,都来自 `@/api/types`。
|
|
||||||
- 标准页面优先使用 `PageContainer`、`ProTable`、`ModalForm`、ProForm 组件。
|
|
||||||
- 权限通过 `useUserStore` 和 `hasPermi` 计算布尔值。
|
|
||||||
- 多选通过 `useTableSelection`,导出通过 `useTableExport`。
|
|
||||||
- 行操作优先使用 `RowActions` 和 `@ant-design/icons`。
|
|
||||||
- 日期范围、字典 options、树表展开、loading、搜索重置和确认弹窗优先使用 `useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`useLoading`、`useSearchReset`、`confirmAction`/`confirmTitleSafe`。
|
|
||||||
- `gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl` 内容必须生成 React TSX 页面。
|
|
||||||
|
|
||||||
验证要求:
|
|
||||||
|
|
||||||
- 改 TS/TSX/API/types 后优先运行 `pnpm lint` 或 `pnpm exec tsc --noEmit`。
|
|
||||||
- 改公共组件、hooks、构建配置或较大范围页面后运行 `pnpm build`。
|
|
||||||
- 如果验证失败或无法运行,交付时说明命令和原因。
|
|
||||||
|
|||||||
@ -1,73 +1,41 @@
|
|||||||
---
|
---
|
||||||
name: frontend-crud-page
|
name: frontend-crud-page
|
||||||
description: 前端标准 React CRUD 页面专家。用于当前 plus-ui-react 项目中的新建列表页、弹窗表单页、标准 API/types/index.tsx 骨架、项目内置 gen/*.ftl React 模板维护,以及后端 generator 字段到 React + ProTable 项目风格的落地任务。
|
description: 前端标准 CRUD 页面专家。用于 plus-ui 前端项目中的新建列表页、弹窗表单页、标准 API/types/index.vue 骨架,以及 gen 模板到项目风格的落地任务;默认参考 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支。
|
||||||
---
|
---
|
||||||
|
|
||||||
你负责当前 plus-ui-react 项目中的标准 CRUD 页面实现。
|
你负责 plus-ui 前端项目中的标准 CRUD 页面实现。
|
||||||
|
|
||||||
|
基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
默认分支:`6.X-Vue`
|
||||||
|
远端模板引用必须同时标记仓库、分支和路径,例如 `branch=6.X-Vue, path=gen/index.vue.ftl`;不要写本机绝对路径。
|
||||||
|
|
||||||
## 核心原则
|
## 核心原则
|
||||||
|
|
||||||
1. 先看当前模块最近似页面。
|
1. 先看当前模块最近似页面。
|
||||||
2. 再参考 `.codex/skills/frontend-crud-coding/references/frontend.md`。
|
2. 再参考 plus-ui Gitee 仓库 `6.X-Vue` 分支中的 `gen` 模板。
|
||||||
3. 维护或新增生成能力时,优先参考当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。
|
3. 默认同时维护:
|
||||||
4. 必要时参考关联后端工程 generator 模板确认接口、字段、权限和导出能力。
|
|
||||||
5. 默认同时维护:
|
|
||||||
`src/api/<module>/<business>/index.ts`
|
`src/api/<module>/<business>/index.ts`
|
||||||
`src/api/<module>/<business>/types.ts`
|
`src/api/<module>/<business>/types.ts`
|
||||||
`src/pages/<module>/<business>/index.tsx`
|
`src/views/<module>/<business>/index.vue`
|
||||||
|
|
||||||
## 优先参考
|
|
||||||
|
|
||||||
- 标准单表:`src/pages/demo/demo/index.tsx`、`src/api/demo/demo/*`。
|
|
||||||
- 树表:`src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
|
||||||
- 系统管理:`src/pages/system/user/index.tsx`、`system/role`、`system/post`、`system/config`。
|
|
||||||
- workflow:`src/pages/workflow/*`、`src/api/workflow/*`。
|
|
||||||
|
|
||||||
## 页面规则
|
## 页面规则
|
||||||
|
|
||||||
- 页面默认导出函数组件,命名如 `SystemClientPage`、`DemoDemoPage`、`WorkflowCategoryPage`。
|
- 页面优先使用 `<script setup name="Xxx" lang="ts">`
|
||||||
- 标准结构通常包含 `PageContainer`、`ProTable`、工具栏按钮、`ModalForm`。
|
- 标准结构通常包含:
|
||||||
|
搜索区、表格区、工具栏、分页、编辑弹窗
|
||||||
- 常见状态:
|
- 常见状态:
|
||||||
`actionRef`、`form`、`modalOpen`、`modalTitle`、`ids`、`selectedOne`、权限布尔值。
|
`loading`、`showSearch`、`ids`、`single`、`multiple`、`total`
|
||||||
- 表格列使用 `ProColumns<XxxVO>[]`。
|
- 查询与表单优先使用 `reactive<PageData<Form, Query>>({...})`
|
||||||
- 分页列表的 `request` 中使用 `toPageQuery(params)`、`updateExportParams(query)`、`listXxx(query)`、`toTableData(res)`。
|
|
||||||
- 多选使用 `useTableSelection<XxxVO>(row => row.id)`。
|
|
||||||
- 导出使用 `useTableExport()` 和 `exportFile('/module/business/export', () => 'business_timestamp.xlsx')`。
|
|
||||||
- 行操作使用 `RowActions`,行内删除确认放在 `confirm`。
|
|
||||||
- 新增/编辑弹窗使用 `ModalForm<XxxForm>`,字段优先使用 ProForm 组件。
|
|
||||||
- 日期范围使用 `useDateRangeQuery`,字典 options 使用 `dictOptions`。
|
|
||||||
- 状态切换等 Promise 式确认使用 `confirmAction` 或 `confirmTitleSafe`。
|
|
||||||
- 异步 loading 优先使用 `useLoading`,带额外筛选状态的重置优先使用 `useSearchReset`。
|
|
||||||
|
|
||||||
## API / types 规则
|
## API / types 规则
|
||||||
|
|
||||||
- 请求统一通过 `@/api/request`。
|
- 请求统一通过 `@/utils/request`
|
||||||
- 同目录维护 `index.ts` 与 `types.ts`。
|
- 同目录维护 `index.ts` 与 `types.ts`
|
||||||
- 标准 CRUD 通常包含:列表、详情、新增、修改、删除。
|
- 标准 CRUD 通常包含:列表、详情、新增、修改、删除
|
||||||
- 列表分页接口通常返回 `request<R<PageResult<XxxVO>>>`。
|
- 列表接口通常返回 `AxiosPromise<PageResult<XxxVO>>`
|
||||||
- 树表列表接口通常返回 `request<R<XxxVO[]>>`。
|
|
||||||
- 不要从 `axios` 引入 `AxiosPromise`。
|
|
||||||
|
|
||||||
## 树表规则
|
|
||||||
|
|
||||||
- 判断树表后不要生成分页 `PageResult` 页面。
|
|
||||||
- `Query` 通常不继承 `PageQuery`。
|
|
||||||
- 使用 `handleTree`、`pagination={false}`、`useTreeTableExpand`、`ProFormTreeSelect`。
|
|
||||||
- 树表展开/折叠优先使用 `useTreeTableExpand`,不要在页面或模板里重复手写收集 key 的状态逻辑。
|
|
||||||
- 新增子节点时从当前行带入 `parentId`。
|
|
||||||
|
|
||||||
## gen 模板规则
|
|
||||||
|
|
||||||
- `gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl` 内容生成 React TSX。
|
|
||||||
- 保持 Velocity 变量、宏和后端 generator 可识别结构,不为了格式美化破坏模板语法。
|
|
||||||
- 模板应输出当前项目公共工具写法:`useTableSelection`、`useTableExport`、`useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`confirmAction`、`toPageQuery`、`toTableData`、`handleTree`。
|
|
||||||
- 不把 Vue `src/views`、Element Plus、`AxiosPromise`、`v-hasPermi` 写入模板。
|
|
||||||
|
|
||||||
## 自检
|
## 自检
|
||||||
|
|
||||||
- API 路径是否与后端一致。
|
- API 路径是否与后端一致
|
||||||
- `index.ts` 与 `types.ts` 是否同步补齐。
|
- `index.ts` 与 `types.ts` 是否同步补齐
|
||||||
- 页面是否使用 React 项目的 ProTable/ModalForm 骨架。
|
- 页面是否只是模板裸输出,如果是要继续补强到当前项目风格
|
||||||
- 权限标识是否与后端和相邻页面一致。
|
|
||||||
- 是否同步使用当前项目公共 hooks/工具,避免生成重复代码。
|
|
||||||
- 是否误用了 Vue/Element Plus/`src/views` 规则。
|
|
||||||
|
|||||||
@ -1,58 +1,31 @@
|
|||||||
---
|
---
|
||||||
name: frontend-page-enhancement
|
name: frontend-page-enhancement
|
||||||
description: 复杂前端页面增强专家。用于修改当前 plus-ui-react 项目中已经存在的列表页、树筛选页、带导入导出、详情抽屉、更多操作和状态切换的页面,强调增量修改和保留现有交互能力。
|
description: 复杂前端页面增强专家。用于修改 plus-ui 前端项目中已经存在的列表页、树筛选页、带导入导出和更多菜单的页面,强调增量修改和保留现有交互能力;默认基线为 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支。
|
||||||
---
|
---
|
||||||
|
|
||||||
你负责当前 plus-ui-react 项目中已有页面的增强,不是重写页面。
|
你负责 plus-ui 前端项目中已有页面的增强,不是重写页面。
|
||||||
|
|
||||||
|
基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
默认分支:`6.X-Vue`
|
||||||
|
远端引用必须同时标记仓库、分支和文件路径;不要写本机绝对路径。
|
||||||
|
|
||||||
## 核心原则
|
## 核心原则
|
||||||
|
|
||||||
1. 优先阅读当前页面完整实现和相关子组件。
|
1. 优先阅读当前页面完整实现。
|
||||||
2. 增量修改,不重写整页。
|
2. 增量修改,不重写整页。
|
||||||
3. 保留已有树筛选、导入导出、列显隐、详情抽屉、更多操作、状态切换、路由跳转、权限控制和样式壳。
|
3. 保留已有树筛选、导入导出、列显隐、更多菜单、状态切换、路由跳转、SCSS 页面壳。
|
||||||
4. 不要把复杂页面退化成 demo/generator 式基础列表页。
|
4. 不要把复杂页面退化成 generator 式基础列表页。
|
||||||
5. 修改前先看 `.codex/skills/frontend-crud-coding/references/frontend.md` 中对应规则。
|
|
||||||
|
|
||||||
## 常见任务
|
## 常见任务
|
||||||
|
|
||||||
- 调整工具栏按钮和行操作。
|
- 调整工具栏和更多菜单
|
||||||
- 增加筛选条件和日期范围。
|
- 增加筛选条件和日期范围
|
||||||
- 增加导入、导出能力。
|
- 增加导入导出能力
|
||||||
- 增加状态切换、快捷操作、确认弹窗。
|
- 增加状态切换、快捷操作、确认弹窗
|
||||||
- 增加详情抽屉或增强现有抽屉。
|
- 补复杂页面的小型子功能
|
||||||
- 补复杂页面的小型子功能。
|
|
||||||
- 接入新 API 并保持现有页面状态流。
|
|
||||||
|
|
||||||
## React 项目约定
|
|
||||||
|
|
||||||
- 表格页通常使用 `PageContainer` + `ProTable`。
|
|
||||||
- 复杂系统页可包含 `TreePanel`、子组件弹窗、抽屉、授权路由跳转。
|
|
||||||
- 权限通过 `useUserStore` + `hasPermi` 计算,不使用 Vue 指令。
|
|
||||||
- 字典通过 `useDict` 加载,按现有页面映射为 Ant Design options。
|
|
||||||
- 字典 options 优先使用 `dictOptions` from `@/utils/dict`。
|
|
||||||
- 导出通过 `useTableExport`,不要另写下载封装。
|
|
||||||
- 多选通过 `useTableSelection`,不要手写一套重复状态。
|
|
||||||
- 日期范围优先使用 `useDateRangeQuery`,底层保持 `addDateRange` 参数格式。
|
|
||||||
- 树表展开优先使用 `useTreeTableExpand`。
|
|
||||||
- 异步 loading 优先使用 `useLoading`。
|
|
||||||
- 额外筛选状态的重置优先使用 `useSearchReset`。
|
|
||||||
- Promise 式确认框优先使用 `confirmAction` 或 `confirmTitleSafe`。
|
|
||||||
- 状态切换失败时回滚或刷新,参考 `system/user`。
|
|
||||||
|
|
||||||
## 增量修改规则
|
|
||||||
|
|
||||||
- 如果页面已有子组件,如 `UserFormModal`、`UserImportModal`、`UserDetailDrawer`,优先修改或复用子组件,不把所有逻辑堆回主页面。
|
|
||||||
- 如果页面已有权限布尔值,沿用同一命名风格补新权限。
|
|
||||||
- 如果页面已有导出参数缓存,继续通过 `updateExportParams` 更新。
|
|
||||||
- 如果页面已有树筛选状态,查询参数要合并该状态,不要覆盖掉。
|
|
||||||
- 如果页面已有特殊禁用规则、超级管理员保护或业务状态判断,必须保留。
|
|
||||||
- 如果增强的是标准 CRUD 能力或公共工具约定,要评估当前仓库 `gen/*.ftl` 是否也应同步更新。
|
|
||||||
|
|
||||||
## 自检
|
## 自检
|
||||||
|
|
||||||
- 是否破坏了原页面结构和样式。
|
- 是否破坏了原页面结构和样式
|
||||||
- 是否误删了已有权限控制或交互能力。
|
- 是否误删了已有权限控制或交互能力
|
||||||
- 是否保留了树筛选、导入导出、抽屉、路由跳转等复杂能力。
|
- 是否应该拆成子组件而不是继续堆主页面
|
||||||
- 是否应该拆成子组件而不是继续堆主页面。
|
|
||||||
- 是否使用了当前项目已有工具,避免重复手写日期范围、字典 options、树展开、loading、确认框。
|
|
||||||
- 是否误用了 Vue/Element Plus/generator 的简化逻辑。
|
|
||||||
|
|||||||
@ -1,31 +1,41 @@
|
|||||||
---
|
---
|
||||||
name: frontend-crud-coding
|
name: frontend-crud-coding
|
||||||
description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript + Umi Max + Ant Design ProComponents + oxlint/oxfmt 代码风格生成或修改页面、API、types、hooks 接入、样式和项目内置 gen/*.ftl 代码生成模板。用于新增或修改标准 CRUD 列表页、树表页、系统管理页、监控页、workflow 页面、demo 页面,补齐与 RuoYi-Vue-Plus boot4 后端接口对应的 src/api、types 和 src/pages 代码,或维护 gen/api.ts.ftl、gen/types.ts.ftl、gen/index.tsx.ftl、gen/index-tree.tsx.ftl;触发后应先读取适用 references,再阅读目标模块真实代码和项目内置 gen 模板。
|
description: 在 plus-ui 前端项目中按真实 Vue 3 + TypeScript + Element Plus + oxlint/oxfmt 代码风格生成或修改页面、API、types、hooks 接入和样式壳。用于新增或修改标准 CRUD 列表页、树表页、系统管理页、监控页、workflow 页面、demo 页面,补齐与后端接口对应的 src/api、types 和 src/views 代码;默认参考 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支,触发后应先读取适用 references,再阅读目标模块真实代码和项目内 gen 代码生成模板。
|
||||||
---
|
---
|
||||||
|
|
||||||
# 前端编码规范
|
# 前端编码规范
|
||||||
|
|
||||||
先对齐当前 React 项目里的真实实现,再参考项目内置 `gen/` 代码生成模板。Vue 版本 skill 和关联后端工程的代码生成器模板只用于理解字段、权限、任务分型和迁移意图。不要直接套 Vue 3、Element Plus、AxiosPromise 或 `src/views` 规则;要落成当前仓库的 `src/pages`、`src/api`、ProTable、ModalForm、权限、导出和公共工具方式。
|
先对齐当前前端项目里的真实实现,再参考项目内 `gen` 目录下的代码生成模板。不要只套通用 Vue 模板,也不要把 generator 模板原样复制进来而忽略当前项目已经演进出的 hooks、页面壳、类型入口和下载方式。
|
||||||
|
|
||||||
|
## 项目基线
|
||||||
|
|
||||||
|
- 基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
- 默认分支:`6.X-Vue`
|
||||||
|
- 远端引用必须同时标记仓库、分支和文件路径,例如 `https://gitee.com/JavaLionLi/plus-ui/blob/6.X-Vue/gen/index.vue.ftl` 或 `branch=6.X-Vue, path=gen/index.vue.ftl`。
|
||||||
|
- 不要在 skill、reference 或 agent 文档中写本机绝对路径;本地文件读取以运行时工作目录为准。
|
||||||
|
- 如果用户指定其他分支,先按用户分支读取同一仓库的对应文件,并在结果中说明使用的分支。
|
||||||
|
|
||||||
## 执行流程
|
## 执行流程
|
||||||
|
|
||||||
1. 判断任务类型:新增标准 CRUD、树表、已有页面增强、复杂业务页、只补 API/types。
|
1. 判断任务类型:新增标准 CRUD、树表、已有页面增强、复杂业务页、只补 API/types。
|
||||||
2. 按“文档读取规则”读取必要 reference,不一次性展开所有资料。
|
2. 按“文档读取规则”读取必要 reference,不一次性展开所有资料。
|
||||||
3. 阅读目标目录下最近似的真实代码:
|
3. 阅读目标目录下最近似的真实代码:
|
||||||
- 标准单表优先看 `src/pages/demo/demo/index.tsx`、`src/api/demo/demo/*`。
|
- 标准单表优先看 `src/views/demo/demo/index.vue`、`src/api/demo/demo/*`。
|
||||||
- 树表优先看 `src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
- 树表优先看 `src/views/demo/tree/index.vue`、`src/views/workflow/category/index.vue`。
|
||||||
- 系统复杂页优先看 `src/pages/system/user/index.tsx`、`system/role`、`system/post`、`system/config`。
|
- 系统复杂页优先看 `src/views/system/user/index.vue`、`system/role`、`system/post`、`system/config`。
|
||||||
- workflow 业务页优先看 `src/pages/workflow/*` 与 `src/api/workflow/*` 同类页面。
|
- workflow 业务页优先看 `src/views/workflow/*` 同类页面。
|
||||||
4. 新增或维护代码生成能力时,优先阅读当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。这些是 React 版内置 FreeMarker 生成模板,页面模板必须输出当前项目 React/TSX 风格。
|
4. 新增标准页面前,对照项目内模板确认基础骨架:
|
||||||
5. 需要从 Vue 版本迁移经验时,参考 Gitee 项目 `https://gitee.com/JavaLionLi/plus-ui` 的 `6.X-Vue` 分支,目录为 `.codex/skills/frontend-crud-coding` 和 `.claude/agents`,只吸收任务分型、增量修改和自检原则。
|
- API 模板:`gen/api.ts.ftl`
|
||||||
6. 新增标准页面前,可以对照 Gitee 项目 `https://gitee.com/dromara/RuoYi-Vue-Plus` 的 `6.X` 分支,目录为 `ruoyi-modules/ruoyi-gen/src/main/resources/fm`,确认字段、权限和导出能力,但输出和 `gen/` 模板必须保持 React 项目风格。
|
- types 模板:`gen/types.ts.ftl`
|
||||||
7. 新增代码时通常同步维护 `src/api/<module>/<business>/index.ts`、`types.ts`、`src/pages/<module>/<business>/index.tsx`;如果是生成模板优化,同步维护 `gen/` 对应 `.ftl`。
|
- 标准单表页模板:`gen/index.vue.ftl`
|
||||||
8. 增强已有页面时只做增量修改,保留原页面的树筛选、导入导出、列显隐、权限、字典、弹窗、抽屉和路由跳转能力。
|
- 树表页模板:`gen/index-tree.vue.ftl`
|
||||||
9. 修改完成后按影响范围运行验证:优先 `pnpm exec tsc --noEmit` 或 `pnpm lint`;大范围页面、公共组件、构建配置变更再跑 `pnpm build`。
|
5. 新增代码时通常同步维护 `src/api/<module>/<business>/index.ts`、`types.ts`、`src/views/<module>/<business>/index.vue`。
|
||||||
|
6. 增强已有页面时只做增量修改,保留原页面的树筛选、导入导出、列显隐、权限、字典、弹窗和路由跳转能力。
|
||||||
|
7. 修改完成后按影响范围运行验证:优先 `pnpm exec vue-tsc --noEmit`,改动页面或导入时再跑 `pnpm lint`,大范围变更再跑 `pnpm build`。
|
||||||
|
|
||||||
## 文档读取规则
|
## 文档读取规则
|
||||||
|
|
||||||
- 前端 API、types、页面、hooks、样式、权限、导出和验证规则,先读 [references/frontend.md](references/frontend.md)。
|
- 前端 API、types、页面、hooks、样式和验证规则,先读 [references/frontend.md](references/frontend.md)。
|
||||||
- 不确定任务边界、需要标准用例或提问方式时,再读 [references/examples.md](references/examples.md)。
|
- 不确定任务边界、需要标准用例或提问方式时,再读 [references/examples.md](references/examples.md)。
|
||||||
- reference 只约束实现方式和自检范围;发生冲突时,以当前模块真实代码和实际调用点为准。
|
- reference 只约束实现方式和自检范围;发生冲突时,以当前模块真实代码和实际调用点为准。
|
||||||
|
|
||||||
@ -34,46 +44,41 @@ description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript
|
|||||||
发生冲突时按下面顺序决策:
|
发生冲突时按下面顺序决策:
|
||||||
|
|
||||||
1. 目标目录下最近似页面、API、types 的真实实现。
|
1. 目标目录下最近似页面、API、types 的真实实现。
|
||||||
2. 当前项目公共 hooks、组件、工具、样式和请求封装约定。
|
2. 当前项目公共 hooks、组件、工具和样式约定。
|
||||||
3. 当前项目内置 `gen/*.ftl` React 代码生成模板。
|
3. 项目内 `gen` 代码生成模板。
|
||||||
4. Gitee 项目 `plus-ui` 的 `6.X-Vue` 分支 `.codex` / `.claude` 中的任务分型和工作流。
|
4. 通用 Vue 3 / Element Plus 习惯。
|
||||||
5. Gitee 项目 `RuoYi-Vue-Plus` 的 `6.X` 分支 generator 模板。
|
|
||||||
6. 通用 React / Ant Design ProComponents 习惯。
|
|
||||||
|
|
||||||
也就是说:
|
也就是说:
|
||||||
|
|
||||||
- 同模块已有页面怎么写,优先怎么写。
|
- 同模块已有页面怎么写,优先怎么写。
|
||||||
- 没有现成页面时,使用 demo 页面作为骨架,再按后端接口字段和权限补齐。
|
- 没有现成页面时,使用项目内 `gen` 模板作为骨架,再改成当前项目风格。
|
||||||
- 复杂模块不能为了“标准 CRUD”退化成裸模板页。
|
- 复杂模块不能为了“标准 CRUD”退化成裸模板页。
|
||||||
- Vue 版本只作为迁移参考,不复制 Vue 组件、hooks、指令、样式类和类型导入。
|
|
||||||
|
|
||||||
## 仓库通用规则
|
## 仓库通用规则
|
||||||
|
|
||||||
- 遵循 `.editorconfig` 和仓库现状:UTF-8、2 空格缩进、TypeScript、TSX。
|
- 遵循 [`.editorconfig`](../../../.editorconfig):UTF-8、LF、2 空格缩进;Markdown 例外。
|
||||||
- 包管理使用 `pnpm`;格式脚本是 `pnpm run fmt`,lint 脚本是 `pnpm lint`。
|
- 当前仓库没有 `.prettierrc`,格式脚本是 `pnpm run fmt` 调用 `oxfmt .`,lint 脚本是 `pnpm lint` 调用 `oxlint src`。
|
||||||
- 技术栈是 React 19 + TypeScript + Umi Max + Ant Design 6 + Ant Design ProComponents + ahooks + TanStack Query + Zustand。
|
- 页面优先使用 `<script setup name="Xxx" lang="ts">`。
|
||||||
- 页面放在 `src/pages`,不是 Vue 项目的 `src/views`。
|
- API 返回类型优先从 `@/utils/api-types` 引入 `AxiosPromise`,分页结果从 `@/api/types` 引入 `PageResult`。
|
||||||
- 请求统一通过 `src/api/request.ts`,API 返回类型使用 `Promise<R<T>>`,不要从 `axios` 或 Vue 项目引入 `AxiosPromise`。
|
- 请求统一通过 `@/utils/request`,导出下载使用 `import { download as requestDownload } from '@/utils/request';`。
|
||||||
- 分页结果使用 `PageResult<T>` from `@/api/types`,接口外层使用 `R<T>` from `@/api/types`。
|
- 标准列表页优先复用 `useLoading`、`useSearchToggle`、`useSearchReset`、`useTableSelection`、`useFormDialog`、`useDateRangeQuery`。
|
||||||
- 标准列表页优先复用 `ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`、`toPageQuery`、`toTableData`。
|
- 页面壳优先使用 `p-2 app-container <module>-<business>-page`、`search-panel`、`toolbar-shell`、`data-table`、`right-toolbar`、`pagination`。
|
||||||
- 查询、字典、树表、loading、重置和确认弹窗优先复用 `useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`useLoading`、`useSearchReset`、`confirmAction`/`confirmTitleSafe`。
|
- 新页面不要无故引入另一套状态管理、请求封装、样式体系或权限写法。
|
||||||
- 权限用 `const userInfo = useUserStore(state => state.userInfo)` 和 `hasPermi(userInfo, ['module:business:action'])` 计算布尔值。
|
|
||||||
- 新页面不要无故引入另一套状态管理、请求封装、表格封装、样式体系或权限写法。
|
|
||||||
|
|
||||||
## 目录映射规则
|
## 目录映射规则
|
||||||
|
|
||||||
通常按下面关系组织代码:
|
通常按下面关系组织代码:
|
||||||
|
|
||||||
- 后端 `/system/user/*` 对应 `src/api/system/user/*` 与 `src/pages/system/user/*`
|
- 后端 `/system/user/*` 对应 `src/api/system/user/*` 与 `src/views/system/user/*`
|
||||||
- 后端 `/monitor/xxx/*` 对应 `src/api/monitor/xxx/*` 与 `src/pages/monitor/xxx/*`
|
- 后端 `/monitor/xxx/*` 对应 `src/api/monitor/xxx/*` 与 `src/views/monitor/xxx/*`
|
||||||
- 后端 `/workflow/xxx/*` 对应 `src/api/workflow/xxx/*` 与 `src/pages/workflow/xxx/*`
|
- 后端 `/workflow/xxx/*` 对应 `src/api/workflow/xxx/*` 与 `src/views/workflow/xxx/*`
|
||||||
- 后端 `/demo/xxx/*` 对应 `src/api/demo/xxx/*` 与 `src/pages/demo/xxx/*`
|
- 后端 `/demo/xxx/*` 对应 `src/api/demo/xxx/*` 与 `src/views/demo/xxx/*`
|
||||||
|
|
||||||
标准新增通常至少包含:
|
标准新增通常至少包含:
|
||||||
|
|
||||||
- `src/api/<module>/<business>/index.ts`
|
- `src/api/<module>/<business>/index.ts`
|
||||||
- `src/api/<module>/<business>/types.ts`
|
- `src/api/<module>/<business>/types.ts`
|
||||||
- `src/pages/<module>/<business>/index.tsx`
|
- `src/views/<module>/<business>/index.vue`
|
||||||
|
|
||||||
按业务复杂度,可能继续补:
|
按业务复杂度,可能继续补:
|
||||||
|
|
||||||
@ -82,17 +87,17 @@ description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript
|
|||||||
- 树筛选面板
|
- 树筛选面板
|
||||||
- 列显隐配置
|
- 列显隐配置
|
||||||
- 分配/授权子页面
|
- 分配/授权子页面
|
||||||
- 自定义 Less 样式
|
- 自定义 SCSS 样式
|
||||||
|
|
||||||
## 任务分型
|
## 任务分型
|
||||||
|
|
||||||
### 1. 标准单表 CRUD
|
### 1. 标准单表 CRUD
|
||||||
|
|
||||||
以 `src/pages/demo/demo/index.tsx` 和 `src/api/demo/demo/*` 为主要起点,补齐列表、搜索、分页、新增、编辑、删除、导出、权限、类型和验证。
|
以 `gen/index.vue.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl` 和 `src/views/demo/demo/index.vue` 为主要起点,补齐列表、搜索、分页、新增、编辑、删除、导出、权限、类型和验证。
|
||||||
|
|
||||||
### 2. 树表 CRUD
|
### 2. 树表 CRUD
|
||||||
|
|
||||||
以 `src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx` 为主要起点。列表接口通常返回数组,不使用分页 `PageResult`;页面使用 `handleTree`、`useTreeTableExpand`、`ProFormTreeSelect`。
|
以 `src/views/demo/tree/index.vue`、`src/views/workflow/category/index.vue` 为主要起点。列表接口通常返回数组而不是 `PageResult`,页面使用 `handleTree`、`useTreeTableExpand`,`Query` 通常不继承 `PageQuery`。
|
||||||
|
|
||||||
### 3. 强业务页面
|
### 3. 强业务页面
|
||||||
|
|
||||||
@ -100,23 +105,12 @@ description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript
|
|||||||
|
|
||||||
### 4. 工作流页面
|
### 4. 工作流页面
|
||||||
|
|
||||||
workflow 目录优先参考 `src/pages/workflow/*`。流程定义、流程实例、任务列表、请假申请等页面通常有业务按钮、弹窗和路由跳转,不要硬套 system 模块。
|
workflow 目录优先参考 `src/views/workflow/*`。流程定义、流程实例、任务列表、请假申请等页面通常有业务按钮、弹窗和路由跳转,不要硬套 system 模块。
|
||||||
|
|
||||||
### 5. 只补 API 和 types
|
### 5. 只补 API 和 types
|
||||||
|
|
||||||
只维护 `src/api/<module>/<business>/index.ts` 与 `types.ts`,但仍要与后端路由、返回结构、当前模块导入方式和类型入口一致。
|
只维护 `src/api/<module>/<business>/index.ts` 与 `types.ts`,但仍要与后端路由、返回结构、当前模块导入方式和类型入口一致。
|
||||||
|
|
||||||
### 6. 维护 React 生成模板
|
|
||||||
|
|
||||||
模板只放在当前仓库 `gen/` 下,除非用户明确要求写入 boot4 后端工程。维护时保持 FreeMarker 变量和文件名不变:
|
|
||||||
|
|
||||||
- `gen/api.ts.ftl`
|
|
||||||
- `gen/types.ts.ftl`
|
|
||||||
- `gen/index.tsx.ftl`
|
|
||||||
- `gen/index-tree.tsx.ftl`
|
|
||||||
|
|
||||||
模板内容必须生成当前 React 项目代码,并优先使用已有公共工具:`useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`useTableSelection`、`useTableExport`、`confirmAction`、`toPageQuery`、`toTableData`、`handleTree`、`formatDateTimeFields`、`toDayjsFields`。不要把 Vue 模板、Element Plus 组件或 `src/views` 路径写入这些模板。
|
|
||||||
|
|
||||||
## 输出要求
|
## 输出要求
|
||||||
|
|
||||||
使用本 skill 时,默认期望产出应满足:
|
使用本 skill 时,默认期望产出应满足:
|
||||||
@ -125,26 +119,21 @@ workflow 目录优先参考 `src/pages/workflow/*`。流程定义、流程实例
|
|||||||
- API 路径、函数名、权限标识与后端接口保持一致。
|
- API 路径、函数名、权限标识与后端接口保持一致。
|
||||||
- 标准页查询、重置、分页、弹窗、提交、删除、导出流程闭环完整。
|
- 标准页查询、重置、分页、弹窗、提交、删除、导出流程闭环完整。
|
||||||
- 复杂页面保留原有交互能力和业务约束。
|
- 复杂页面保留原有交互能力和业务约束。
|
||||||
- 代码体现当前项目 hooks、页面壳和下载方式,而不是 Vue 版本或 generator 裸输出。
|
- 代码体现当前项目 hooks、页面壳和下载方式,而不是 `gen` 模板裸输出。
|
||||||
- 生成模板变更要同步反映当前项目公共 hooks/工具,避免生成的新页面重复手写日期范围、字典 options、树展开、loading、搜索重置和确认框逻辑。
|
|
||||||
- 交付前说明运行过的验证命令;如果无法验证,说明原因。
|
- 交付前说明运行过的验证命令;如果无法验证,说明原因。
|
||||||
|
|
||||||
## 快速检查清单
|
## 快速检查清单
|
||||||
|
|
||||||
- API 是否从 `@/api/request` 引入 `request`。
|
- `AxiosPromise` 是否来自 `@/utils/api-types`。
|
||||||
- `R`、`PageResult`、`PageQuery`、`BaseEntity` 是否来自 `@/api/types`。
|
- `PageResult` 是否来自 `@/api/types`。
|
||||||
- API `params` 和 `data` 是否与后端方法一致。
|
- API `params` 和 `data` 是否与后端方法一致。
|
||||||
- 分页表格 request 是否通过 `toPageQuery(params)` 和 `toTableData(res)`。
|
- 日期范围是否通过 `useDateRangeQuery` 或附近页面现有方式处理。
|
||||||
- 导出是否通过 `useTableExport` 和 `exportFile('/module/business/export', () => 'name_timestamp.xlsx')`。
|
- 列表 loading 是否通过 `useLoading` 或原页面方式维护。
|
||||||
- 多选是否通过 `useTableSelection<T>(row => row.id)`。
|
- 弹窗是否通过 `useFormDialog` 或原页面方式维护。
|
||||||
- 行操作是否优先使用 `RowActions` 和 Ant Design 图标。
|
- 多选状态是否通过 `useTableSelection` 或原页面方式维护。
|
||||||
- 权限是否通过 `useUserStore` + `hasPermi` 计算,不要写 Vue 指令。
|
- 权限指令是否保持同文件一致,默认使用当前项目主流 `v-hasPermi`。
|
||||||
- 日期范围是否通过 `useDateRangeQuery` 或 `addDateRange` 相关工具处理。
|
- 导出是否使用 `requestDownload('<module>/<business>/export', { ...queryParams.value }, '<name>_<time>.xlsx')`。
|
||||||
- 字典 options 是否通过 `dictOptions`。
|
- 页面壳是否保留 `search-panel`、`table-panel`、`toolbar-shell`、`data-table`、`right-toolbar`、`pagination`。
|
||||||
- 树表是否使用 `handleTree`、`pagination={false}`、`useTreeTableExpand`、`ProFormTreeSelect`。
|
|
||||||
- loading 是否优先使用 `useLoading`,搜索重置是否优先使用 `useSearchReset`。
|
|
||||||
- 需要 Promise 式确认时是否使用 `confirmAction` 或 `confirmTitleSafe`。
|
|
||||||
- 代码生成模板是否仍输出 React TSX 项目风格。
|
|
||||||
|
|
||||||
## 推荐提问方式
|
## 推荐提问方式
|
||||||
|
|
||||||
@ -158,5 +147,5 @@ workflow 目录优先参考 `src/pages/workflow/*`。流程定义、流程实例
|
|||||||
|
|
||||||
例如:
|
例如:
|
||||||
|
|
||||||
- 使用 `$frontend-crud-coding` 为 `/system/client` 补一套 React 标准 CRUD 页面,参考 `demo/demo`、现有 `system/client` 和 boot4 generator 模板。
|
- 使用 `$frontend-crud-coding` 为 `/system/client` 补一套标准 CRUD 页面,参考 `gen` 模板、`demo/demo` 和 `system/client`。
|
||||||
- 使用 `$frontend-crud-coding` 修改 `workflow/category` 列表页,增加导出按钮和状态筛选,保持当前 workflow 树表风格。
|
- 使用 `$frontend-crud-coding` 修改 `workflow/category` 列表页,增加导出按钮和状态筛选,保持当前 workflow 风格。
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
interface:
|
interface:
|
||||||
display_name: "前端编码"
|
display_name: "前端编码"
|
||||||
short_description: "按 plus-ui-react 真实代码和 gen 模板编写 React CRUD"
|
short_description: "按 plus-ui 6.X-Vue 真实代码和 gen 模板编写前端 CRUD"
|
||||||
default_prompt: "使用 $frontend-crud-coding 先读取适用 reference,再按 plus-ui-react 真实页面、项目内置 gen 模板、API/types、ProTable、ModalForm、权限、导出和公共工具约定实现前端修改。"
|
default_prompt: "使用 $frontend-crud-coding 先读取适用 reference,再按 plus-ui Gitee 仓库 6.X-Vue 分支的真实页面、hooks、API/types 约定和项目内 gen 模板实现前端修改。"
|
||||||
|
|
||||||
policy:
|
policy:
|
||||||
allow_implicit_invocation: true
|
allow_implicit_invocation: true
|
||||||
|
|||||||
@ -5,19 +5,18 @@
|
|||||||
### 用户提问示例
|
### 用户提问示例
|
||||||
|
|
||||||
```text
|
```text
|
||||||
使用 $frontend-crud-coding 为 system/client 补一套 React 前端 CRUD 页面。
|
使用 $frontend-crud-coding 为 system/client 补一套前端 CRUD 页面。
|
||||||
后端接口已经有 /system/client/list、/system/client/{id}、POST /system/client、PUT /system/client、DELETE /system/client/{ids}。
|
后端接口已经有 /system/client/list、/system/client/{id}、POST /system/client、PUT /system/client、DELETE /system/client/{ids}。
|
||||||
请参考 src/pages/demo/demo/index.tsx 和现有 system/client 风格实现。
|
请参考 plus-ui Gitee 仓库 6.X-Vue 分支的项目内 gen 模板、src/views/demo/demo/index.vue 和现有 system/client 风格实现。
|
||||||
```
|
```
|
||||||
|
|
||||||
### 期望执行方式
|
### 期望执行方式
|
||||||
|
|
||||||
- 先看 `src/api/system/client/*` 和 `src/pages/system/client/index.tsx` 是否已存在。
|
- 先看 `src/api/system/client/*` 和 `src/views/system/client/index.vue` 是否已存在。
|
||||||
- 再看 `src/pages/demo/demo/index.tsx` 的标准 React CRUD 骨架。
|
- 再看 `src/views/demo/demo/index.vue` 的标准 hooks 版 CRUD 骨架。
|
||||||
- 新增标准生成能力时优先对照当前仓库 `gen/index.tsx.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl`;boot4 generator 只用于核对字段、权限和接口。
|
- 对照项目内 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.vue.ftl`。
|
||||||
- 生成或修改 `api/index.ts`、`types.ts`、`pages/.../index.tsx`。
|
- 生成或修改 `api/index.ts`、`types.ts`、`views/.../index.vue`。
|
||||||
- 使用 `request<R<PageResult<T>>>`、`ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`。
|
- 使用 `AxiosPromise` from `@/utils/api-types`、`PageResult` from `@/api/types`、`useLoading`、`useFormDialog`、`useSearchReset`、`useTableSelection`。
|
||||||
- 日期范围、字典 options、确认框、loading 等优先使用 `useDateRangeQuery`、`dictOptions`、`confirmAction`、`useLoading` 等项目工具。
|
|
||||||
|
|
||||||
## 案例 2:新增树表页面
|
## 案例 2:新增树表页面
|
||||||
|
|
||||||
@ -25,33 +24,17 @@
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
使用 $frontend-crud-coding 为 demo/tree2 新增树表 CRUD,接口返回数组,字段包含 id、parentId、name、orderNum。
|
使用 $frontend-crud-coding 为 demo/tree2 新增树表 CRUD,接口返回数组,字段包含 id、parentId、name、orderNum。
|
||||||
参考 src/pages/demo/tree/index.tsx 和 workflow/category。
|
参考 src/views/demo/tree/index.vue 和 workflow/category。
|
||||||
```
|
```
|
||||||
|
|
||||||
### 期望执行方式
|
### 期望执行方式
|
||||||
|
|
||||||
- 判断这是树表,不生成分页 `PageResult` 页面。
|
- 优先判断这是树表,不生成分页 `PageResult` 页面。
|
||||||
- API 列表返回 `R<Tree2VO[]>`。
|
- API 列表返回 `AxiosPromise<Tree2VO[]>`。
|
||||||
- `Query` 不继承 `PageQuery`。
|
- `Query` 不继承 `PageQuery`。
|
||||||
- 页面使用 `handleTree`、`pagination={false}`、`useTreeTableExpand`、`ProFormTreeSelect`。
|
- 页面使用 `handleTree`、`row-key`、`tree-props`、`useTreeTableExpand`、`el-tree-select`。
|
||||||
- 新增子节点时从当前行带入 `parentId`。
|
- 新增子节点时从当前行带入 `parentId`。
|
||||||
|
|
||||||
## 案例 2.1:优化 React 代码生成模板
|
|
||||||
|
|
||||||
### 用户提问示例
|
|
||||||
|
|
||||||
```text
|
|
||||||
使用 $frontend-crud-coding 优化当前项目 gen 目录下的 React 代码生成模板,让生成页面继续使用新加的工具。
|
|
||||||
```
|
|
||||||
|
|
||||||
### 期望执行方式
|
|
||||||
|
|
||||||
- 读取 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。
|
|
||||||
- 保持 FreeMarker 变量、宏和文件名不变。
|
|
||||||
- 普通表模板继续使用 `useTableSelection`、`useTableExport`、`useDateRangeQuery`、`dictOptions`、`confirmAction`。
|
|
||||||
- 树表模板继续使用 `handleTree`、`filterTree`、`useTreeTableExpand`、`dictOptions`。
|
|
||||||
- 输出仍是 React TSX 项目代码,不写 Vue `src/views`、Element Plus 或 `AxiosPromise`。
|
|
||||||
|
|
||||||
## 案例 3:修改已有复杂列表页
|
## 案例 3:修改已有复杂列表页
|
||||||
|
|
||||||
### 用户提问示例
|
### 用户提问示例
|
||||||
@ -59,15 +42,15 @@
|
|||||||
```text
|
```text
|
||||||
使用 $frontend-crud-coding 修改 system/user 页面:
|
使用 $frontend-crud-coding 修改 system/user 页面:
|
||||||
1. 新增一个创建时间快捷筛选
|
1. 新增一个创建时间快捷筛选
|
||||||
2. 导出按钮保留在工具栏中
|
2. 导出按钮保留在更多菜单中
|
||||||
3. 保持现有树筛选、导入、详情抽屉和角色分配不变
|
3. 保持现有树筛选、导入、列显隐、详情抽屉和角色分配不变
|
||||||
```
|
```
|
||||||
|
|
||||||
### 期望执行方式
|
### 期望执行方式
|
||||||
|
|
||||||
- 判断这是“已有复杂页面增强”,不是重新生成 CRUD。
|
- 判断这是“已有复杂页面增强”,不是重新生成 CRUD。
|
||||||
- 优先阅读 `src/pages/system/user/index.tsx` 和相关子组件。
|
- 优先阅读 `src/views/system/user/index.vue`。
|
||||||
- 保留 `TreePanel`、导入弹窗、`UserDetailDrawer`、角色分配路由、权限控制。
|
- 保留 `TreePanel`、导入弹窗、`right-toolbar` 列显隐、`UserViewDrawer`、角色分配路由、权限控制。
|
||||||
- 只增量修改搜索和查询参数处理。
|
- 只增量修改搜索和查询参数处理。
|
||||||
|
|
||||||
## 案例 4:修改 workflow 页面
|
## 案例 4:修改 workflow 页面
|
||||||
@ -80,8 +63,8 @@
|
|||||||
|
|
||||||
### 期望执行方式
|
### 期望执行方式
|
||||||
|
|
||||||
- 优先看 `src/pages/workflow/category/index.tsx` 和 `src/api/workflow/category/*`。
|
- 优先看 `src/views/workflow/category/index.vue` 和 `src/api/workflow/category/*`。
|
||||||
- 判断是否需要后端新增导出接口;前端导出路径保持 `/workflow/category/export`。
|
- 判断是否需要后端新增导出接口;前端导出路径保持 `workflow/category/export`。
|
||||||
- 不迁移 system/user 的用户专属逻辑。
|
- 不迁移 system/user 的用户专属逻辑。
|
||||||
- 保留树表、`useTreeTableExpand`、`handleTree` 和分类弹窗逻辑。
|
- 保留树表、`useTreeTableExpand`、`handleTree` 和分类弹窗逻辑。
|
||||||
|
|
||||||
@ -96,8 +79,8 @@
|
|||||||
### 期望执行方式
|
### 期望执行方式
|
||||||
|
|
||||||
- 只维护 `src/api/monitor/cache/index.ts` 和 `src/api/monitor/cache/types.ts`。
|
- 只维护 `src/api/monitor/cache/index.ts` 和 `src/api/monitor/cache/types.ts`。
|
||||||
- 仍然检查同目录 monitor API 的命名、返回结构和导出风格。
|
- 仍然检查同目录 monitor API 的 `export function` / `export const` 风格。
|
||||||
- 返回类型使用 `R<T>` 和 `PageResult<T>` from `@/api/types`。
|
- 返回类型使用 `AxiosPromise` from `@/utils/api-types`。
|
||||||
- 不创建页面,不改路由。
|
- 不创建页面,不改路由。
|
||||||
|
|
||||||
## 案例 6:接入后端新增状态切换接口
|
## 案例 6:接入后端新增状态切换接口
|
||||||
@ -105,26 +88,26 @@
|
|||||||
### 用户提问示例
|
### 用户提问示例
|
||||||
|
|
||||||
```text
|
```text
|
||||||
使用 $frontend-crud-coding 给 system/client 页面接入 PUT /system/client/changeStatus,状态字段 status,参考 system/user。
|
使用 $frontend-crud-coding 给 system/client 页面接入 PUT /system/client/changeStatus,状态字段 status,参考 gen 模板。
|
||||||
```
|
```
|
||||||
|
|
||||||
### 期望执行方式
|
### 期望执行方式
|
||||||
|
|
||||||
- API 增加 `changeClientStatus(id, status)`。
|
- API 增加 `changeClientStatus(id, status)`。
|
||||||
- types 确认 `status` 类型是 string、number 还是 boolean。
|
- types 确认 `status` 类型是 string、number 还是 boolean。
|
||||||
- 表格列用 Ant Design `Switch`,checked 值跟后端字段类型一致。
|
- 表格列用 `el-switch`,active/inactive 值跟后端字段类型一致。
|
||||||
- 切换失败时回滚原状态或刷新列表。
|
- 切换失败时回滚原状态。
|
||||||
- 权限使用 `system:client:edit` 或后端实际权限。
|
- 权限使用 `system:client:edit` 或后端实际权限。
|
||||||
|
|
||||||
## 推荐的高质量任务描述
|
## 推荐的高质量任务描述
|
||||||
|
|
||||||
```text
|
```text
|
||||||
使用 $frontend-crud-coding 在当前 React 前端项目中增强 `/system/notice` 列表页:
|
使用 $frontend-crud-coding 在当前前端项目中新增 `/system/notice` 列表页增强:
|
||||||
1. 保留现有页面
|
1. 保留现有页面
|
||||||
2. 新增状态筛选和导出
|
2. 新增状态筛选和导出
|
||||||
3. API 路径沿用后端接口
|
3. API 路径沿用后端接口
|
||||||
4. 参考 system/config 的工具栏与导出交互
|
4. 参考 system/config 的工具栏与导出交互
|
||||||
5. 参考当前项目 gen 模板和 boot4 generator 字段补齐缺失 types
|
5. 参考 plus-ui Gitee 仓库 6.X-Vue 分支的 gen 模板补齐缺失 types
|
||||||
```
|
```
|
||||||
|
|
||||||
## 不推荐的任务描述
|
## 不推荐的任务描述
|
||||||
|
|||||||
@ -2,36 +2,41 @@
|
|||||||
|
|
||||||
## 优先参考的代码来源
|
## 优先参考的代码来源
|
||||||
|
|
||||||
|
- 默认远端基线:`https://gitee.com/JavaLionLi/plus-ui`,分支 `6.X-Vue`。引用远端文件时必须同时写明 `branch=6.X-Vue` 和仓库内路径。
|
||||||
- 当前目标目录下最近似页面、API、types。
|
- 当前目标目录下最近似页面、API、types。
|
||||||
- 当前仓库内置 React 生成模板:`gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。
|
- 标准单表:`src/views/demo/demo/index.vue`、`src/api/demo/demo/index.ts`、`src/api/demo/demo/types.ts`。
|
||||||
- 标准单表:`src/pages/demo/demo/index.tsx`、`src/api/demo/demo/index.ts`、`src/api/demo/demo/types.ts`。
|
- 树表:`src/views/demo/tree/index.vue`、`src/views/workflow/category/index.vue`。
|
||||||
- 树表:`src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
- 复杂系统页:`src/views/system/user/index.vue`、`src/views/system/role/index.vue`、`src/views/system/post/index.vue`、`src/views/system/config/index.vue`。
|
||||||
- 复杂系统页:`src/pages/system/user/index.tsx`、`src/pages/system/role/index.tsx`、`src/pages/system/post/index.tsx`、`src/pages/system/config/index.tsx`。
|
- workflow 页:`src/views/workflow/*`、`src/api/workflow/*`。
|
||||||
- workflow 页:`src/pages/workflow/*`、`src/api/workflow/*`。
|
- 监控页:`src/views/monitor/*`、`src/api/monitor/*`。
|
||||||
- 监控页:`src/pages/monitor/*`、`src/api/monitor/*`。
|
- 公共 hooks:`src/hooks/async/useLoading.ts`、`src/hooks/dialog/*`、`src/hooks/form/*`、`src/hooks/table/*`、`src/hooks/tree/*`。
|
||||||
- 公共 hooks:`src/hooks/useTableSelection.ts`、`src/hooks/useTableExport.ts`、`src/hooks/useDict.ts`、`src/hooks/useDateRangeQuery.ts`、`src/hooks/useTreeTableExpand.ts`、`src/hooks/useLoading.ts`、`src/hooks/useSearchReset.ts`。
|
- 项目内 generator 模板:
|
||||||
- 公共组件:`src/components/common/RowActions.tsx`、`TreePanel.tsx`、`RightToolbar.tsx`、`DictTag.tsx`、上传/预览组件。
|
`gen/api.ts.ftl`
|
||||||
- 工具函数:`src/utils/ruoyi.ts`、`src/utils/permission.ts`、`src/utils/download.ts`、`src/utils/dict.ts`、`src/utils/modal.ts`。
|
`gen/types.ts.ftl`
|
||||||
|
`gen/index.vue.ftl`
|
||||||
|
`gen/index-tree.vue.ftl`
|
||||||
|
|
||||||
## 基础栈与格式
|
## 基础栈与格式
|
||||||
|
|
||||||
- 技术栈是 React + TypeScript + Umi Max + Ant Design + ProComponents + ahooks + Zustand + TanStack Query。
|
- 技术栈是 Vue 3 + TypeScript + Element Plus + Vite + Pinia。
|
||||||
- 包管理按仓库现状使用 pnpm。
|
- 包管理按仓库现状使用 pnpm。
|
||||||
- `.editorconfig` 要求 UTF-8、2 空格缩进。
|
- `.editorconfig` 要求 UTF-8、LF、2 空格缩进。
|
||||||
- 当前仓库没有 Prettier;格式化使用 `pnpm run fmt`,lint 使用 `pnpm lint`。
|
- 当前仓库没有 `.prettierrc`;格式化使用 `pnpm run fmt`,lint 使用 `pnpm lint`。
|
||||||
- 不要在一个页面里混入与仓库不一致的格式和写法。
|
- 不要在一个页面里混入与仓库不一致的格式和写法。
|
||||||
|
- 不要把本机绝对路径写进 skill 输出或参考文档;跨环境参考统一使用 Gitee 仓库 URL、分支和仓库内相对路径。
|
||||||
|
|
||||||
## API 文件规则
|
## API 文件规则
|
||||||
|
|
||||||
- 标准 API 文件放在 `src/api/<module>/<business>/index.ts`,同目录维护 `types.ts`。
|
- 标准 API 文件放在 `src/api/<module>/<business>/index.ts`,同目录维护 `types.ts`。
|
||||||
- import 顺序优先跟随附近文件,标准形式:
|
- import 顺序优先跟随附近文件,标准生成页常见形式:
|
||||||
`import type { PageResult, R } from '@/api/types';`
|
`import type { XxxForm, XxxQuery, XxxVO } from '@/api/<module>/<business>/types';`
|
||||||
`import request from '@/api/request';`
|
`import type { PageResult } from '@/api/types';`
|
||||||
`import type { XxxForm, XxxQuery, XxxVO } from './types';`
|
`import type { AxiosPromise } from '@/utils/api-types';`
|
||||||
- 不要从 `axios` 引入 `AxiosPromise`;当前 `request<T>()` 返回 `Promise<T>`,接口函数通常返回 `Promise<R<T>>`。
|
`import request from '@/utils/request';`
|
||||||
- 列表分页接口通常返回 `request<R<PageResult<XxxVO>>>({ url, method: 'get', params: query })`。
|
- 不要从 `axios` 引入 `AxiosPromise`。
|
||||||
- 树表列表接口通常返回 `request<R<XxxVO[]>>({ url, method: 'get', params: query })`。
|
- 列表分页接口通常返回 `AxiosPromise<PageResult<XxxVO>>`。
|
||||||
- 详情接口返回 `R<XxxVO>`;复杂详情返回单独的 `InfoVO`。
|
- 树表列表接口通常返回 `AxiosPromise<XxxVO[]>`。
|
||||||
|
- 详情接口返回 `AxiosPromise<XxxVO>`;复杂详情返回单独的 `InfoVO`。
|
||||||
- 标准函数命名:
|
- 标准函数命名:
|
||||||
`listXxx` -> `GET /<module>/<business>/list`
|
`listXxx` -> `GET /<module>/<business>/list`
|
||||||
`getXxx` -> `GET /<module>/<business>/{id}`
|
`getXxx` -> `GET /<module>/<business>/{id}`
|
||||||
@ -41,8 +46,8 @@
|
|||||||
`changeXxxStatus` -> `PUT /<module>/<business>/changeStatus`
|
`changeXxxStatus` -> `PUT /<module>/<business>/changeStatus`
|
||||||
- query string 用 `params`,请求体用 `data`。
|
- query string 用 `params`,请求体用 `data`。
|
||||||
- 加密、防重复提交等 headers 直接写在请求配置里,例如用户重置密码中的 `isEncrypt`、`repeatSubmit`。
|
- 加密、防重复提交等 headers 直接写在请求配置里,例如用户重置密码中的 `isEncrypt`、`repeatSubmit`。
|
||||||
- 当前仓库多数 API 使用 `export function`;新增标准 CRUD 优先跟随相邻模块。
|
- 当前仓库有些 API 使用 `export const`,有些使用 `export function`;新增标准 CRUD 优先跟随 `gen/api.ts.ftl` 和相邻模块。
|
||||||
- 只有相邻模块已有聚合对象时才新增默认导出。
|
- 只有相邻模块已有 `export default { ... }` 聚合时才新增默认导出。
|
||||||
|
|
||||||
## 类型文件规则
|
## 类型文件规则
|
||||||
|
|
||||||
@ -52,103 +57,100 @@
|
|||||||
- 树表 `Query` 通常不继承 `PageQuery`。
|
- 树表 `Query` 通常不继承 `PageQuery`。
|
||||||
- ID 字段通常使用 `string | number`,批量删除参数使用 `string | number | Array<string | number>`。
|
- ID 字段通常使用 `string | number`,批量删除参数使用 `string | number | Array<string | number>`。
|
||||||
- Java 数值类型映射为 `number`,Boolean 映射为 `boolean`,日期/文本默认 `string`。
|
- Java 数值类型映射为 `number`,Boolean 映射为 `boolean`,日期/文本默认 `string`。
|
||||||
- 日期范围查询保留 `params?: Record<string, unknown>` 或跟随相邻页面现有类型,不要因为它看起来宽松就删掉。
|
- 日期范围查询保留 `params?: any`,不要因为它看起来宽松就删掉。
|
||||||
- 列表对象、表单对象、查询对象职责分开;字段不一致时不要强行复用一个接口。
|
- 列表对象、表单对象、查询对象职责分开;字段不一致时不要强行复用一个接口。
|
||||||
- 能明确写出类型时不要用 `any`;组件库、字典或历史接口确实无法收窄时再保留。
|
- 能明确写出类型时不要用 `any`;组件库、字典或历史接口确实无法收窄时再保留。
|
||||||
|
|
||||||
## React 页面结构规则
|
## Vue 页面结构规则
|
||||||
|
|
||||||
- 页面默认导出函数组件,命名如 `SystemUserPage`、`DemoDemoPage`、`WorkflowCategoryPage`。
|
- 页面优先使用 `<script setup name="Xxx" lang="ts">`。
|
||||||
- 标准页使用 `PageContainer` 包裹 `ProTable` 和 `ModalForm`。
|
- 标准根节点使用 `class="p-2 app-container <module>-<business>-page"`;已有页面是特殊布局时保持原样。
|
||||||
- 标准列表页常见状态:
|
- 标准列表页结构:
|
||||||
`actionRef`、`form`、`modalOpen`、`modalTitle`、`ids`、`selectedOne`、权限布尔值。
|
搜索卡片 `search-panel`
|
||||||
- 弹窗状态优先使用 `useBoolean(false)`,表单用 `Form.useForm<XxxForm>()`。
|
表格卡片 `table-panel`
|
||||||
- ProTable 使用:
|
工具栏 `toolbar-shell`
|
||||||
`rowKey`
|
表格 `data-table`
|
||||||
`columns`
|
`right-toolbar`
|
||||||
`search={{ labelWidth: 90 }}`
|
`pagination`
|
||||||
`pagination={{ defaultPageSize: 10, showSizeChanger: true }}`
|
新增/编辑 `el-dialog`
|
||||||
`request={async params => { ... }}`
|
- 搜索区通过 `useSearchToggle` 控制 `showSearch`,头部点击切换。
|
||||||
`toolBarRender={() => [...]}`
|
- 列表 loading 通过 `useLoading(true)` 和 `withLoading`。
|
||||||
- 分页查询使用 `toPageQuery(params)`,然后 `updateExportParams(query)`,最后 `return toTableData(res)`。
|
- 选择状态通过 `useTableSelection<XxxVO>(item => item.id)` 返回 `ids`、`single`、`multiple`、`handleSelectionChange`。
|
||||||
- 表格列类型使用 `ProColumns<XxxVO>[]`。
|
- 表单弹窗优先使用 `useFormDialog({ form, formRef, initialFormData })`,返回 `dialog`、`resetForm`、`openDialog`、`showDialog`、`closeDialog`。
|
||||||
- 新增/编辑弹窗使用 `ModalForm<XxxForm>`,字段优先使用 `ProFormText`、`ProFormDigit`、`ProFormSelect`、`ProFormTreeSelect`、`ProFormDateTimeRangePicker` 等 ProForm 组件。
|
- 仅需要简单弹窗状态或一个页面多个弹窗时使用 `useDialogState`。
|
||||||
- ModalForm 成功提交后返回 `true`,并刷新 `actionRef.current?.reload()`。
|
- 日期范围查询优先使用 `useDateRangeQuery()`;带后端参数名时使用 `useDateRangeQuery('CreateTime')` 等相邻页面模式。
|
||||||
|
- 查询和表单状态通常放在 `reactive<PageData<Form, Query>>({ form, queryParams, rules })`,再 `toRefs(data)`。
|
||||||
|
|
||||||
## 页面行为规则
|
## 页面行为规则
|
||||||
|
|
||||||
- `openAdd` 负责 `form.resetFields()`、设置默认值、设置标题、打开弹窗。
|
- `getList` 负责设置 loading、调用列表接口、回填列表和 `total`。
|
||||||
- `openEdit` 先按行或 `selectedOne` 找目标,再查详情,`form.resetFields()`,`form.setFieldsValue(res.data)`,最后打开弹窗。
|
- `handleQuery` 先把 `queryParams.value.pageNum = 1`,再调用 `getList()`;树表无分页时只调用 `getList()`。
|
||||||
- `submitForm` 根据主键判断新增或修改,成功后 `message.success('操作成功')`、重置表单、刷新列表。
|
- `resetQuery` 使用 `useSearchReset`,分页页传 `pageNumKey: 'pageNum'`,需要时传 `pageSizeKey` 和 `resetExtras`。
|
||||||
- `remove` 或 `handleDelete` 支持行删除和批量删除,成功后 `message.success('删除成功')`、`clearSelection()`、`reloadAndRest` 或 `reload`。
|
- `handleAdd` 使用 `openDialog('添加xxx')`;如果有树/联动选项,打开前后按现有页面加载选项。
|
||||||
- 批量按钮通常用 `Popconfirm`,行操作确认优先放在 `RowActions` 的 `confirm`。
|
- `handleUpdate` 先 `reset()`,再按行或 `ids.value[0]` 查详情,`Object.assign(form.value, res.data)`,最后 `showDialog('修改xxx')`。
|
||||||
- 状态切换失败时要回滚或刷新,参考 `src/pages/system/user/index.tsx`。
|
- `submitForm` 表单校验通过后设置 `buttonLoading`,根据主键判断新增或修改,成功后 `modal.msgSuccess('操作成功')`、关闭弹窗、刷新列表。
|
||||||
- 日期范围查询优先使用 `useDateRangeQuery`,底层通过 `addDateRange` 写入 `params.beginXxx/endXxx`。
|
- `handleDelete` 使用 `modal.confirm(...)` 二次确认,再调用删除接口,成功提示并刷新。
|
||||||
- 字典 options 优先使用 `dictOptions(dicts.xxx)`。
|
- `handleExport` 使用 `requestDownload('<module>/<business>/export', { ...queryParams.value }, '<business>_<timestamp>.xlsx')`。
|
||||||
- 导入上传参考 `system/user/components/UserImportModal.tsx` 或流程定义导入弹窗,保留 `globalHeaders()` 和 `appEnv.baseApi` 相关方式。
|
- 状态切换失败时要把 switch 值回滚,参考 generator 模板和现有 `system/user`、`system/role`。
|
||||||
|
- 导入上传使用 `globalHeaders()`、`import.meta.env.VITE_APP_BASE_API`、`ElUpload`,优先参考 `system/user` 或流程定义页面。
|
||||||
|
|
||||||
## 字典、权限与公共工具
|
## 字典、权限与公共工具
|
||||||
|
|
||||||
- 字典使用 `const dicts = useDict('sys_normal_disable', 'sys_user_gender')`。
|
- 字典使用 `useDict`:
|
||||||
- 字典 options 使用 `dictOptions` from `@/utils/dict` 映射为 `{ label, value }`。
|
`const { sys_normal_disable } = toRefs<any>(useDict('sys_normal_disable'));`
|
||||||
- 权限使用:
|
- 新增代码默认使用当前项目主流 `v-hasPermi`。
|
||||||
`const userInfo = useUserStore(state => state.userInfo);`
|
- 如果正在修改的文件已经混用或使用 `v-has-permi`,保持同文件现状,不为统一写法而重排无关代码。
|
||||||
`const canAdd = hasPermi(userInfo, ['system:user:add']);`
|
- `el-dropdown-item` 延迟加载导致权限指令不可靠时,使用 `v-if="checkPermi([...])"`,参考 `system/user`。
|
||||||
- 不要使用 Vue 权限指令 `v-hasPermi`。
|
|
||||||
- 常用工具:
|
- 常用工具:
|
||||||
`hasPermi` from `@/utils/permission`
|
`modal` from `@/plugins/modal`
|
||||||
`handleTree`、`parseStrEmpty`、`toPageQuery`、`toTableData`、`addDateRange`、`formatDateTimeRange` from `@/utils/ruoyi`
|
`download as requestDownload` from `@/utils/request`
|
||||||
`dictOptions` from `@/utils/dict`
|
`useDict` from `@/utils/dict`
|
||||||
`confirmAction`、`confirmTitleSafe` from `@/utils/modal`
|
`checkPermi` from `@/utils/permission`
|
||||||
`download` via `useTableExport`
|
`handleTree`、`parseStrEmpty` from `@/utils/ruoyi`
|
||||||
|
|
||||||
## 组件与样式规则
|
## 组件与样式规则
|
||||||
|
|
||||||
- 行操作优先复用 `RowActions`,并使用 `@ant-design/icons` 图标。
|
- 优先复用公共组件:`right-toolbar`、`pagination`、`DictTag` / `dict-tag`、`ImageUpload` / `image-upload`、`ImagePreview` / `image-preview`、`FileUpload` / `file-upload`、`Editor` / `editor`、`TreePanel`。
|
||||||
- 树筛选优先复用 `TreePanel`,参考 `system/user`。
|
- 标准页面尽量使用已有页面壳类,不堆大量内联样式。
|
||||||
- 导出优先复用 `useTableExport`。
|
- 复杂页面需要 scoped SCSS 时优先复用:
|
||||||
- 多选优先复用 `useTableSelection`。
|
`@use '@/assets/styles/components/page-shell' as pageShell;`
|
||||||
- 异步 loading 优先复用 `useLoading`,不要重复手写 `setLoading(true)` + `finally setLoading(false)`。
|
再按现有 mixin 使用。
|
||||||
- ProTable 重置后还要清空额外筛选状态时,优先复用 `useSearchReset`。
|
|
||||||
- Promise 式确认框优先复用 `confirmAction` 或 `confirmTitleSafe`。
|
|
||||||
- 标准页面尽量使用 `PageContainer`、`ProTable`、ProComponents 页面壳,不堆大量内联样式。
|
|
||||||
- 需要自定义布局时先查 `src/assets/styles` 是否已有 `.tree-table-page`、`.table-panel`、`.page-surface` 等类。
|
|
||||||
- 不要为了单页需求修改全局组件样式。
|
- 不要为了单页需求修改全局组件样式。
|
||||||
|
- 类名保持模块语义:`system-client-page`、`workflow-category-page`、`demo-demo-page`。
|
||||||
|
|
||||||
## 树表规则
|
## 树表规则
|
||||||
|
|
||||||
- 树表列表接口通常返回数组,页面通过 `handleTree<T>(res.data || [], 'id', 'parentId')` 组树。
|
- 树表列表接口通常返回数组,页面通过 `handleTree<T>(res.data, 'id', 'parentId')` 组树。
|
||||||
- `ProTable` 使用 `pagination={false}`。
|
- 使用 `row-key`、`:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"`。
|
||||||
- 使用 `useTreeTableExpand` 控制 `expandedRowKeys`、`onExpandedRowsChange`、`syncExpandedRows`、`toggleExpandAll`。
|
- 展开/折叠使用 `useTreeTableExpand`。
|
||||||
- 展开/折叠按钮参考 `demo/tree` 和 `workflow/category`,用 `SortAscendingOutlined`。
|
- 表单中上级节点使用 `el-tree-select`。
|
||||||
- 表单中上级节点使用 `ProFormTreeSelect`。
|
|
||||||
- 新增子节点时从当前行回填 `parentId`。
|
- 新增子节点时从当前行回填 `parentId`。
|
||||||
- 删除确认文案优先使用业务名称,而不是批量 ID 文案。
|
- 删除确认文案优先使用业务名称,而不是批量 ID 文案。
|
||||||
|
|
||||||
## 与 gen 模板、Vue 参考项目和后端生成器的关系
|
## 与 gen 模板的关系
|
||||||
|
|
||||||
- 当前仓库 `gen/*.ftl` 是 React 版内置代码生成模板,是维护生成能力时的第一参考。
|
- `gen` 是 plus-ui 前端项目内的生成模板;默认远端位置是 `https://gitee.com/JavaLionLi/plus-ui/tree/6.X-Vue/gen`,分支必须标记为 `6.X-Vue`。
|
||||||
- `gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl` 内容必须生成 React TSX 页面。
|
- 本地仓库存在对应文件时优先读本地 `gen`,但不要把本地绝对路径写入 skill 或交付内容。
|
||||||
- 修改公共 hooks/工具后,如果它们能简化标准生成页,要同步评估 `gen/*.ftl` 是否需要更新。
|
- 新增标准单表页面时读取 `gen/index.vue.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl`。
|
||||||
- Vue skill 和 `.claude/agents` 提供的是任务分型、优先级、增量修改、自检方式,不是 React 实现模板。
|
- 新增树表页面时读取 `gen/index-tree.vue.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl`。
|
||||||
- boot4 后端 generator 模板可用于确认字段、权限、导出、状态切换、排序、日期范围等,但不是最终答案。
|
- `gen` 模板是标准骨架,不是最终答案;落地时仍要对照目标模块真实页面和公共 hooks。
|
||||||
- 当前 React 项目的核心骨架是 `ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`。
|
- 当前前端项目已经把生成页升级为 hooks 版:`useLoading`、`useFormDialog`、`useSearchReset`、`useTableSelection`、`useDateRangeQuery`。
|
||||||
- 修改已有页面时,不要把现有强业务逻辑替换回 generator 的简化逻辑。
|
- 新增标准 CRUD 时,先从 `gen` 确认字段、权限、导出、状态切换、排序、日期范围等,再落成当前项目的实际页面壳。
|
||||||
|
- 修改已有页面时,不要把现有强业务逻辑替换回 `gen` 的简化逻辑。
|
||||||
|
|
||||||
## 验证规则
|
## 验证规则
|
||||||
|
|
||||||
- 只改文档、skill 或 `gen/*.ftl` 模板:至少运行 skill 基础校验或 `git diff --check`;如果模板改动依赖项目工具,优先再跑 `pnpm lint`。
|
- 只改文档或 skill:运行 skill 基础校验即可。
|
||||||
- 改前端 TS/TSX/API/types:优先运行 `pnpm exec tsc --noEmit` 或 `pnpm lint`。
|
- 改前端 TS/Vue/API/types:优先运行 `pnpm exec vue-tsc --noEmit`。
|
||||||
- 改页面、import、权限或较多文件:运行 `pnpm lint`。
|
- 改页面模板、import、权限或较多文件:再运行 `pnpm lint`。
|
||||||
- 改公共 hooks、组件、构建相关或大范围页面:再运行 `pnpm build`。
|
- 改公共 hooks、组件、构建相关或大范围页面:再运行 `pnpm build`。
|
||||||
- 如果验证因为环境、依赖或权限失败,交付时说明失败命令和原因。
|
- 如果验证因为环境、依赖或权限失败,交付时说明失败命令和原因。
|
||||||
|
|
||||||
## 避免事项
|
## 避免事项
|
||||||
|
|
||||||
- 不要从 `axios` 引入 `AxiosPromise`。
|
- 不要从 `axios` 引入 `AxiosPromise`。
|
||||||
- 不要绕开 `@/api/request` 或 `useTableExport` 自造请求/下载封装。
|
- 不要绕开 `request` 或 `requestDownload` 自造请求/下载封装。
|
||||||
- 不要跳过 `types.ts`,把类型全写在页面里。
|
- 不要跳过 `types.ts`,把类型全写在页面里。
|
||||||
- 不要把 `src/pages` 写成 Vue 项目的 `src/views`。
|
- 不要删除日期范围 `params`、权限指令、导出、导入、树筛选、列显隐等现有能力。
|
||||||
- 不要使用 Vue 的 `ref`、`reactive`、`toRefs`、`v-hasPermi`、Element Plus 组件或 SCSS 页面壳。
|
|
||||||
- 不要删除日期范围 `params`、权限判断、导出、导入、树筛选、列显隐等现有能力。
|
|
||||||
- 不要为了“更整洁”重写复杂页面的大块业务逻辑。
|
- 不要为了“更整洁”重写复杂页面的大块业务逻辑。
|
||||||
|
- 不要在新增标准页里使用与仓库不一致的 UI 壳或状态管理方式。
|
||||||
|
|||||||
@ -1,9 +1,21 @@
|
|||||||
|
# 告诉EditorConfig插件,这是根文件,不用继续往上查找
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
|
# 匹配全部文件
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
# 缩进风格,可选space、tab
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
# 缩进的空格数
|
||||||
indent_size = 2
|
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
|
||||||
|
|||||||
@ -1,15 +1,42 @@
|
|||||||
VITE_APP_TITLE=RuoYi-React-Plus后台管理系统
|
# 页面标题
|
||||||
VITE_APP_LOGO_TITLE=RuoYi-React-Plus
|
VITE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
|
||||||
VITE_APP_ENV=development
|
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
|
||||||
VITE_APP_BASE_API=/dev-api
|
|
||||||
VITE_APP_CONTEXT_PATH=/
|
# 开发环境配置
|
||||||
VITE_APP_PORT=8000
|
VITE_APP_ENV = 'development'
|
||||||
VITE_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
|
|
||||||
VITE_APP_MESSAGE_ENABLED=true
|
# 开发环境
|
||||||
VITE_APP_MESSAGE_TRANSPORT=sse
|
VITE_APP_BASE_API = '/dev-api'
|
||||||
VITE_APP_MESSAGE_PATH=/resource/message
|
|
||||||
VITE_APP_ENCRYPT=true
|
# 应用访问路径 例如使用前缀 /admin/
|
||||||
VITE_APP_RSA_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB
|
VITE_APP_CONTEXT_PATH = '/'
|
||||||
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==
|
|
||||||
VITE_APP_MONITOR_ADMIN=http://localhost:9090/admin/applications
|
# 监控地址
|
||||||
VITE_APP_SNAILJOB_ADMIN=http://localhost:8800/snail-job
|
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'
|
||||||
|
|||||||
@ -1,15 +1,45 @@
|
|||||||
VITE_APP_TITLE=RuoYi-React-Plus后台管理系统
|
# 页面标题
|
||||||
VITE_APP_LOGO_TITLE=RuoYi-React-Plus
|
VITE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
|
||||||
VITE_APP_ENV=production
|
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
|
||||||
VITE_APP_BASE_API=/prod-api
|
|
||||||
VITE_APP_CONTEXT_PATH=/
|
# 生产环境配置
|
||||||
VITE_APP_PORT=8000
|
VITE_APP_ENV = 'production'
|
||||||
VITE_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
|
|
||||||
VITE_APP_MESSAGE_ENABLED=true
|
# 应用访问路径 例如使用前缀 /admin/
|
||||||
VITE_APP_MESSAGE_TRANSPORT=sse
|
VITE_APP_CONTEXT_PATH = '/'
|
||||||
VITE_APP_MESSAGE_PATH=/resource/message
|
|
||||||
VITE_APP_ENCRYPT=true
|
# 监控地址
|
||||||
VITE_APP_RSA_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB
|
VITE_APP_MONITOR_ADMIN = '/admin/applications'
|
||||||
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==
|
|
||||||
VITE_APP_MONITOR_ADMIN=/admin/applications
|
# SnailJob 控制台地址
|
||||||
VITE_APP_SNAILJOB_ADMIN=/snail-job
|
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'
|
||||||
|
|||||||
37
.gitignore
vendored
37
.gitignore
vendored
@ -1,10 +1,29 @@
|
|||||||
node_modules
|
.DS_Store
|
||||||
dist
|
.history
|
||||||
.umi
|
node_modules/
|
||||||
.umi-production
|
dist/
|
||||||
src/.umi
|
npm-debug.log*
|
||||||
src/.umi-production
|
yarn-debug.log*
|
||||||
.env.local
|
yarn-error.log*
|
||||||
*.log
|
**/*.log
|
||||||
.idea/
|
|
||||||
|
tests/**/coverage/
|
||||||
|
tests/e2e/reports
|
||||||
|
selenium-debug.log
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
*.iml
|
*.iml
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.local
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# 编译生成的文件
|
||||||
|
auto-imports.d.ts
|
||||||
|
components.d.ts
|
||||||
|
|||||||
10
.idea/.gitignore
generated
vendored
10
.idea/.gitignore
generated
vendored
@ -1,10 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Ignored default folder with query files
|
|
||||||
/queries/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
6
.idea/compiler.xml
generated
6
.idea/compiler.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<option name="BUILD_PROCESS_HEAP_SIZE" value="2048" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
3
.idea/dictionaries/LionLi.xml
generated
3
.idea/dictionaries/LionLi.xml
generated
@ -1,3 +0,0 @@
|
|||||||
<component name="ProjectDictionaryState">
|
|
||||||
<dictionary name="LionLi" />
|
|
||||||
</component>
|
|
||||||
6
.idea/encodings.xml
generated
6
.idea/encodings.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
|
||||||
<file url="PROJECT" charset="UTF-8" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
17
.idea/misc.xml
generated
17
.idea/misc.xml
generated
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
|
||||||
<entry key="Project Default">
|
|
||||||
<profile-state>
|
|
||||||
<selected-state>
|
|
||||||
<State>
|
|
||||||
<id>User defined</id>
|
|
||||||
</State>
|
|
||||||
</selected-state>
|
|
||||||
</profile-state>
|
|
||||||
</entry>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="liberica-25" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/plus-ui-react.iml" filepath="$PROJECT_DIR$/.idea/plus-ui-react.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,6 +1,13 @@
|
|||||||
{
|
{
|
||||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||||
"ignorePatterns": ["src/.umi", "src/.umi-production", ".ai_state", ".claude", ".codex", "dist", "node_modules"],
|
"ignorePatterns": [
|
||||||
|
"src/types/components.d.ts",
|
||||||
|
"src/types/auto-imports.d.ts",
|
||||||
|
".ai_state",
|
||||||
|
".claude",
|
||||||
|
".codex",
|
||||||
|
"doc"
|
||||||
|
],
|
||||||
"printWidth": 120,
|
"printWidth": 120,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
|
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
|
||||||
"plugins": ["eslint", "typescript", "unicorn", "oxc", "import", "react"],
|
"plugins": ["eslint", "typescript", "unicorn", "oxc", "import", "vue"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"typescript/no-empty-function": "off",
|
"typescript/no-empty-function": "off",
|
||||||
"typescript/no-explicit-any": "off",
|
"typescript/no-explicit-any": "off",
|
||||||
@ -12,13 +12,7 @@
|
|||||||
"import/no-unassigned-import": "off",
|
"import/no-unassigned-import": "off",
|
||||||
"import/no-named-as-default-member": "off",
|
"import/no-named-as-default-member": "off",
|
||||||
"import/no-named-as-default": "off",
|
"import/no-named-as-default": "off",
|
||||||
"react/react-in-jsx-scope": "off",
|
|
||||||
"react/no-unstable-nested-components": "off",
|
|
||||||
"react/iframe-missing-sandbox": "off",
|
|
||||||
"react-hooks/exhaustive-deps": "off",
|
|
||||||
"no-shadow": "off",
|
"no-shadow": "off",
|
||||||
"unicorn/no-array-sort": "off",
|
|
||||||
"unicorn/no-useless-fallback-in-spread": "off",
|
|
||||||
"unicorn/prefer-add-event-listener": "off",
|
"unicorn/prefer-add-event-listener": "off",
|
||||||
"unicorn/consistent-function-scoping": "off",
|
"unicorn/consistent-function-scoping": "off",
|
||||||
"unicorn/no-instanceof-builtins": "off"
|
"unicorn/no-instanceof-builtins": "off"
|
||||||
@ -27,14 +21,5 @@
|
|||||||
"correctness": "error",
|
"correctness": "error",
|
||||||
"suspicious": "error"
|
"suspicious": "error"
|
||||||
},
|
},
|
||||||
"ignorePatterns": [
|
"ignorePatterns": [".ai_state", ".claude", ".codex", "doc", "dist/**", "dist-ssr/**", "coverage/**"]
|
||||||
"src/.umi",
|
|
||||||
"src/.umi-production",
|
|
||||||
".ai_state",
|
|
||||||
".claude",
|
|
||||||
".codex",
|
|
||||||
"dist/**",
|
|
||||||
"dist-ssr/**",
|
|
||||||
"coverage/**"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
20
LICENSE
Normal file
20
LICENSE
Normal 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.
|
||||||
46
README.md
46
README.md
@ -1,23 +1,21 @@
|
|||||||
# RuoYi-React-Plus
|
|
||||||
|
|
||||||
## 平台简介
|
## 平台简介
|
||||||
|
|
||||||
- 本仓库为前端技术栈 [React](https://react.dev/) + [TypeScript](https://www.typescriptlang.org/) + [Ant Design](https://ant.design/) + [Umi Max](https://umijs.org/) + [Vite](https://vitejs.dev/)。
|
- 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [TS](https://www.typescriptlang.org/) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
|
||||||
- 官方项目: 基于 Vue + ElementPlus 版本前端项目 [plus-ui](https://gitee.com/JavaLionLi/plus-ui)
|
- 官方项目: 基于 React + Ant Design 版本前端项目 [plus-ui-react](https://gitee.com/JavaLionLi/plus-ui/tree/6.X-React/)
|
||||||
- 成员项目: 基于 vben5(ant-design-vue) 的前端项目 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5)
|
- 成员项目: 基于 vben5(ant-design-vue) 的前端项目 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5)
|
||||||
- 成员项目: 基于soybean 的前端项目 [ruoyi-plus-soybean](https://gitee.com/xlsea/ruoyi-plus-soybean)
|
- 成员项目: 基于soybean 的前端项目 [ruoyi-plus-soybean](https://gitee.com/xlsea/ruoyi-plus-soybean)
|
||||||
|
|
||||||
## 配套后端代码仓库地址
|
## 配套后端代码仓库地址
|
||||||
|
|
||||||
| 介绍 | 项目名 | 项目地址 |
|
| 介绍 | 项目名 | 项目地址 |
|
||||||
| -------------- | :--------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ----------------- | :--------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| 分布式集群框架 | RuoYi-Vue-Plus | [Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus) / [GitHub](https://github.com/dromara/RuoYi-Vue-Plus) / [GitCode](https://gitcode.com/dromara/RuoYi-Vue-Plus) |
|
| 🔥 分布式集群框架 | RuoYi-Vue-Plus | - [Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus)<br> - [GitHub](https://github.com/dromara/RuoYi-Vue-Plus)<br> - [GitCode](https://gitcode.com/dromara/RuoYi-Vue-Plus) |
|
||||||
| 微服务框架 | RuoYi-Cloud-Plus | [Gitee](https://gitee.com/dromara/RuoYi-Cloud-Plus) / [GitHub](https://github.com/dromara/RuoYi-Cloud-Plus) / [GitCode](https://gitcode.com/dromara/RuoYi-Cloud-Plus) |
|
| 🔥 微服务框架 | RuoYi-Cloud-Plus | - [Gitee](https://gitee.com/dromara/RuoYi-Cloud-Plus)<br>- [GitHub](https://github.com/dromara/RuoYi-Cloud-Plus)<br> - [GitCode](https://gitcode.com/dromara/RuoYi-Cloud-Plus) |
|
||||||
|
|
||||||
## 分支说明
|
## 分支说明
|
||||||
|
|
||||||
- 6.X-react分支(稳定发布主分支 生产可用)
|
- 6.X分支(稳定发布主分支 生产可用)
|
||||||
- dev-react分支(开发分支 开发过程中使用)
|
- dev分支(开发分支 开发过程中使用)
|
||||||
|
|
||||||
## 前端运行
|
## 前端运行
|
||||||
|
|
||||||
@ -31,7 +29,7 @@ pnpm dev
|
|||||||
# 构建生产环境
|
# 构建生产环境
|
||||||
pnpm build:prod
|
pnpm build:prod
|
||||||
|
|
||||||
# 前端访问地址 http://localhost:8000
|
# 前端访问地址 http://localhost:80
|
||||||
```
|
```
|
||||||
|
|
||||||
## 本框架与RuoYi的业务差异
|
## 本框架与RuoYi的业务差异
|
||||||
@ -63,16 +61,16 @@ pnpm build:prod
|
|||||||
|
|
||||||
| | |
|
| | |
|
||||||
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
import { defineConfig } from '@umijs/max';
|
|
||||||
import { createUmiAppConfig } from '../vite.config';
|
|
||||||
|
|
||||||
const appConfig = createUmiAppConfig();
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
title: appConfig.title,
|
|
||||||
antd: {},
|
|
||||||
access: {},
|
|
||||||
model: {},
|
|
||||||
initialState: {},
|
|
||||||
vite: appConfig.vite,
|
|
||||||
npmClient: 'pnpm',
|
|
||||||
hash: true,
|
|
||||||
esbuildMinifyIIFE: true,
|
|
||||||
history: {
|
|
||||||
type: 'browser'
|
|
||||||
},
|
|
||||||
base: appConfig.base,
|
|
||||||
publicPath: appConfig.publicPath,
|
|
||||||
routes: [
|
|
||||||
{ path: '/login', component: './login', layout: false },
|
|
||||||
{ path: '/register', component: './register', layout: false },
|
|
||||||
{ path: '/social-callback', component: './socialCallback', layout: false },
|
|
||||||
{ path: '/401', component: './error/401', layout: false },
|
|
||||||
{ path: '/404', component: './error/404', layout: false },
|
|
||||||
{ path: '/redirect/*', component: './redirect', layout: false },
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
component: '../layouts/BasicLayout',
|
|
||||||
routes: [
|
|
||||||
{ path: '/', redirect: '/index' },
|
|
||||||
{ path: '/index', component: './index' },
|
|
||||||
{ path: '/user/profile', component: './system/user/profile' },
|
|
||||||
{ path: '*', component: './dynamicPage' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
proxy: appConfig.proxy
|
|
||||||
});
|
|
||||||
@ -1,94 +1,104 @@
|
|||||||
import type { <#if !table.tree>PageResult, </#if> R } from '@/api/types';
|
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
||||||
import request from '@/api/request';
|
<#if !table.tree>
|
||||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from './types';
|
import type { PageResult } from '@/api/types';
|
||||||
|
</#if>
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询${functionName}列表
|
* 查询${functionName}列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export function list${BusinessName}(query?: ${BusinessName}Query) {
|
|
||||||
return request<R<<#if table.tree>${BusinessName}VO[]<#else> PageResult<${BusinessName}VO></#if>>>({
|
export const list${BusinessName} = (query?: ${BusinessName}Query): AxiosPromise<<#if table.tree>${BusinessName}VO[]<#else>PageResult<${BusinessName}VO></#if>> => {
|
||||||
|
return request({
|
||||||
url: '/${moduleName}/${businessName}/list',
|
url: '/${moduleName}/${businessName}/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询${functionName}详细
|
* 查询${functionName}详细
|
||||||
|
* @param ${pkColumn.javaField}
|
||||||
*/
|
*/
|
||||||
export function get${BusinessName}(${pkColumn.javaField}: string | number) {
|
export const get${BusinessName} = (${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> => {
|
||||||
return request<R<${BusinessName}VO>>({
|
return request({
|
||||||
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增${functionName}
|
* 新增${functionName}
|
||||||
|
* @param data
|
||||||
*/
|
*/
|
||||||
export function add${BusinessName}(data: ${BusinessName}Form) {
|
export const add${BusinessName} = (data: ${BusinessName}Form) => {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/${moduleName}/${businessName}',
|
url: '/${moduleName}/${businessName}',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改${functionName}
|
* 修改${functionName}
|
||||||
|
* @param data
|
||||||
*/
|
*/
|
||||||
export function update${BusinessName}(data: ${BusinessName}Form) {
|
export const update${BusinessName} = (data: ${BusinessName}Form) => {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/${moduleName}/${businessName}',
|
url: '/${moduleName}/${businessName}',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
<#if enableStatus>
|
<#if enableStatus>
|
||||||
/**
|
/**
|
||||||
* 修改${functionName}状态
|
* 修改${functionName}状态
|
||||||
|
* @param ${pkColumn.javaField}
|
||||||
|
* @param status
|
||||||
*/
|
*/
|
||||||
export function change${BusinessName}Status(
|
export const change${BusinessName}Status = (${pkColumn.javaField}: string | number, status: <#if statusColumn.javaType == 'Boolean'>boolean<#elseif statusColumn.javaType == 'String'>string<#else> number</#if>) => {
|
||||||
${pkColumn.javaField}: string | number,
|
return request({
|
||||||
${statusField}: <#if statusColumn.javaType == 'Boolean'>boolean<#elseif statusColumn.javaType == 'Integer' || statusColumn.javaType == 'Long'>number<#else> string</#if>
|
|
||||||
) {
|
|
||||||
return request<R>({
|
|
||||||
url: '/${moduleName}/${businessName}/changeStatus',
|
url: '/${moduleName}/${businessName}/changeStatus',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: {
|
data: {
|
||||||
${pkColumn.javaField},
|
${pkColumn.javaField},
|
||||||
${statusField}
|
${statusField}: status
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
<#if enableSort>
|
<#if enableSort>
|
||||||
/**
|
/**
|
||||||
* 调整${functionName}排序
|
* 调整${functionName}排序
|
||||||
|
* @param ${pkColumn.javaField}
|
||||||
|
* @param sortValue
|
||||||
*/
|
*/
|
||||||
export function update${BusinessName}Sort(
|
export const update${BusinessName}Sort = (${pkColumn.javaField}: string | number, sortValue: <#if sortColumn.javaType == 'String' || sortColumn.javaType == 'LocalDateTime'>string<#else> number</#if>) => {
|
||||||
${pkColumn.javaField}: string | number,
|
return request({
|
||||||
${sortField}: <#if sortColumn.javaType == 'LocalDateTime' || sortColumn.javaType == 'String'>string<#else> number</#if>
|
|
||||||
) {
|
|
||||||
return request<R>({
|
|
||||||
url: '/${moduleName}/${businessName}/updateSort',
|
url: '/${moduleName}/${businessName}/updateSort',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: {
|
data: {
|
||||||
${pkColumn.javaField},
|
${pkColumn.javaField},
|
||||||
${sortField}
|
${sortField}: sortValue
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除${functionName}
|
* 删除${functionName}
|
||||||
|
* @param ${pkColumn.javaField}
|
||||||
*/
|
*/
|
||||||
export function del${BusinessName}(${pkColumn.javaField}: string | number | Array<string | number>) {
|
export const del${BusinessName} = (${pkColumn.javaField}: string | number | Array<string | number>) => {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,424 +0,0 @@
|
|||||||
import { DeleteOutlined<#if enableExport>, DownloadOutlined</#if>, EditOutlined, PlusOutlined, SortAscendingOutlined } from '@ant-design/icons';
|
|
||||||
import {
|
|
||||||
ModalForm,
|
|
||||||
PageContainer,
|
|
||||||
<#if needCheckbox>
|
|
||||||
ProFormCheckbox,
|
|
||||||
</#if>
|
|
||||||
<#if needDateField>
|
|
||||||
ProFormDateTimePicker,
|
|
||||||
</#if>
|
|
||||||
<#if needDigit>
|
|
||||||
ProFormDigit,
|
|
||||||
</#if>
|
|
||||||
<#if needSelect>
|
|
||||||
ProFormSelect,
|
|
||||||
</#if>
|
|
||||||
<#if needTextArea>
|
|
||||||
ProFormTextArea,
|
|
||||||
</#if>
|
|
||||||
ProFormText,
|
|
||||||
ProFormTreeSelect,
|
|
||||||
ProTable,
|
|
||||||
type ActionType,
|
|
||||||
type ProColumns
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { useBoolean } from 'ahooks';
|
|
||||||
import { Button, Form, message<#if enableStatus || needSwitchField>, Switch</#if><#if enableSort>, InputNumber</#if> } from 'antd';
|
|
||||||
import { useMemo, useRef, useState } from 'react';
|
|
||||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
|
||||||
import {
|
|
||||||
add${BusinessName},
|
|
||||||
<#if enableStatus>
|
|
||||||
change${BusinessName}Status,
|
|
||||||
</#if>
|
|
||||||
del${BusinessName},
|
|
||||||
get${BusinessName},
|
|
||||||
list${BusinessName},
|
|
||||||
<#if enableSort>
|
|
||||||
update${BusinessName}Sort,
|
|
||||||
</#if>
|
|
||||||
update${BusinessName}
|
|
||||||
} from '@/api/${moduleName}/${businessName}';
|
|
||||||
<#if needDict>
|
|
||||||
import DictTag from '@/components/common/DictTag';
|
|
||||||
</#if>
|
|
||||||
<#if needFileUpload>
|
|
||||||
import FileUpload from '@/components/common/FileUpload';
|
|
||||||
</#if>
|
|
||||||
<#if needImagePreview>
|
|
||||||
import ImagePreview from '@/components/common/ImagePreview';
|
|
||||||
</#if>
|
|
||||||
<#if needImageUpload>
|
|
||||||
import ImageUpload from '@/components/common/ImageUpload';
|
|
||||||
</#if>
|
|
||||||
<#if needEditor>
|
|
||||||
import RichTextEditor from '@/components/common/RichTextEditor';
|
|
||||||
</#if>
|
|
||||||
import RowActions from '@/components/common/RowActions';
|
|
||||||
<#if needDict>
|
|
||||||
import { useDict } from '@/hooks/useDict';
|
|
||||||
</#if>
|
|
||||||
<#if enableExport>
|
|
||||||
import { useTableExport } from '@/hooks/useTableExport';
|
|
||||||
</#if>
|
|
||||||
import { useTableScroll } from '@/hooks/useTableScroll';
|
|
||||||
import { useTreeTableExpand } from '@/hooks/useTreeTableExpand';
|
|
||||||
import { useUserStore } from '@/stores/userStore';
|
|
||||||
<#if needDict>
|
|
||||||
import { dictOptions } from '@/utils/dict';
|
|
||||||
</#if>
|
|
||||||
<#if enableStatus>
|
|
||||||
import { confirmAction } from '@/utils/modal';
|
|
||||||
</#if>
|
|
||||||
import { hasPermi } from '@/utils/permission';
|
|
||||||
import { filterTree<#if needDateField>, formatDateTimeFields</#if>, handleTree<#if needDateField>, toDayjsFields</#if> } from '@/utils/ruoyi';
|
|
||||||
|
|
||||||
const default${BusinessName}Form: ${BusinessName}Form = {
|
|
||||||
${treeParentCode}: ${treeRootValueTsLiteral},
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && !column.pk && column.htmlType == "checkbox">
|
|
||||||
${column.javaField}: [],
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ${BusinessName}SelectNode {
|
|
||||||
title: string;
|
|
||||||
value: string | number;
|
|
||||||
children?: ${BusinessName}SelectNode[];
|
|
||||||
}
|
|
||||||
|
|
||||||
function toTreeSelectData(nodes: ${BusinessName}VO[]): ${BusinessName}SelectNode[] {
|
|
||||||
return nodes.map(node => ({
|
|
||||||
title: String(node.${treeName} || ''),
|
|
||||||
value: node.${treeCode},
|
|
||||||
children: node.children ? toTreeSelectData(node.children) : undefined
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
<#if enableStatus>
|
|
||||||
const ${statusField}ActiveValue = <#if statusColumn.javaType == "Boolean">true<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">0<#else>'0'</#if>;
|
|
||||||
const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'</#if>;
|
|
||||||
|
|
||||||
</#if>
|
|
||||||
export default function ${BusinessName}Page() {
|
|
||||||
const actionRef = useRef<ActionType | undefined>(undefined);
|
|
||||||
const { tableScroll } = useTableScroll(1000);
|
|
||||||
const [form] = Form.useForm<${BusinessName}Form>();
|
|
||||||
const userInfo = useUserStore(state => state.userInfo);
|
|
||||||
<#if needDict>
|
|
||||||
const dicts = useDict(${dicts});
|
|
||||||
</#if>
|
|
||||||
const [treeOptions, setTreeOptions] = useState<${BusinessName}VO[]>([]);
|
|
||||||
const [tableRows, setTableRows] = useState<${BusinessName}VO[]>([]);
|
|
||||||
const { expandAll, expandedRowKeys, onExpandedRowsChange, syncExpandedRows, toggleExpandAll } =
|
|
||||||
useTreeTableExpand<${BusinessName}VO>(row => row.${treeCode});
|
|
||||||
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
|
||||||
const [modalTitle, setModalTitle] = useState('');
|
|
||||||
<#if enableExport>
|
|
||||||
const { updateExportParams, exportFile } = useTableExport();
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
|
|
||||||
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
|
|
||||||
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
|
|
||||||
<#if enableExport>
|
|
||||||
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
|
|
||||||
</#if>
|
|
||||||
const treeSelectData = useMemo(
|
|
||||||
() => [{ title: '顶级节点', value: ${treeRootValueTsLiteral}, children: toTreeSelectData(treeOptions) }],
|
|
||||||
[treeOptions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const loadTreeOptions = async (excludeId?: string | number) => {
|
|
||||||
const res = await list${BusinessName}();
|
|
||||||
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
|
|
||||||
setTreeOptions(excludeId ? filterTree(rows, node => node.${treeCode} !== excludeId) : rows);
|
|
||||||
};
|
|
||||||
|
|
||||||
const openAdd = async (row?: ${BusinessName}VO) => {
|
|
||||||
await loadTreeOptions();
|
|
||||||
form.resetFields();
|
|
||||||
form.setFieldsValue({ ...default${BusinessName}Form, ${treeParentCode}: row?.${treeCode} || treeRootValueTsLiteral });
|
|
||||||
setModalTitle('添加${functionName}');
|
|
||||||
openModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const openEdit = async (row: ${BusinessName}VO) => {
|
|
||||||
await loadTreeOptions(row.${treeCode});
|
|
||||||
const res = await get${BusinessName}(row.${pkColumn.javaField});
|
|
||||||
const data = <#if needDateField>toDayjsFields({ ...res.data }, [
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
|
||||||
'${column.javaField}',
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
])<#else>{ ...res.data }</#if>;
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
|
||||||
if (typeof data.${column.javaField} === 'string') {
|
|
||||||
data.${column.javaField} = data.${column.javaField}.split(',');
|
|
||||||
}
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
form.resetFields();
|
|
||||||
form.setFieldsValue(data);
|
|
||||||
setModalTitle('修改${functionName}');
|
|
||||||
openModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitForm = async (values: ${BusinessName}Form) => {
|
|
||||||
const submitValues = <#if needDateField>formatDateTimeFields({ ...values }, [
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
|
||||||
'${column.javaField}',
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
])<#else>{ ...values }</#if>;
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
|
||||||
if (Array.isArray(submitValues.${column.javaField})) {
|
|
||||||
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
|
|
||||||
}
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
|
|
||||||
message.success('操作成功');
|
|
||||||
form.resetFields();
|
|
||||||
actionRef.current?.reload();
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const remove = async (row: ${BusinessName}VO) => {
|
|
||||||
await del${BusinessName}(row.${pkColumn.javaField});
|
|
||||||
message.success('删除成功');
|
|
||||||
actionRef.current?.reload();
|
|
||||||
};
|
|
||||||
|
|
||||||
<#if enableStatus>
|
|
||||||
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
|
|
||||||
const previousStatus = row.${statusField};
|
|
||||||
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
|
|
||||||
const text = checked ? '启用' : '停用';
|
|
||||||
try {
|
|
||||||
await confirmAction(`确认要"${r'${text}'}"吗?`);
|
|
||||||
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
|
|
||||||
message.success(`${r'${text}'}成功`);
|
|
||||||
actionRef.current?.reload();
|
|
||||||
} catch {
|
|
||||||
row.${statusField} = previousStatus;
|
|
||||||
actionRef.current?.reload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
</#if>
|
|
||||||
<#if enableSort>
|
|
||||||
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
|
|
||||||
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
|
|
||||||
message.success('排序更新成功');
|
|
||||||
actionRef.current?.reload();
|
|
||||||
};
|
|
||||||
|
|
||||||
</#if>
|
|
||||||
const columns: ProColumns<${BusinessName}VO>[] = [
|
|
||||||
<#list columns as column>
|
|
||||||
<#if column.list && !column.pk>
|
|
||||||
<#if enableStatus && statusField == column.javaField>
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
width: 100,
|
|
||||||
<#if column.dictType?has_content>
|
|
||||||
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
|
||||||
</#if>
|
|
||||||
render: (_, row) => (
|
|
||||||
<Switch
|
|
||||||
checked={row.${column.javaField} === ${statusField}ActiveValue}
|
|
||||||
disabled={!canEdit}
|
|
||||||
onChange={checked => handleStatusChange(row, checked)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
<#elseif enableSort && sortField == column.javaField>
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}',
|
|
||||||
search: false,
|
|
||||||
width: 130,
|
|
||||||
render: (_, row) => <InputNumber min={0} value={row.${column.javaField} as number} onChange={value => handleSortChange(row, value)} />
|
|
||||||
},
|
|
||||||
<#elseif column.htmlType == "datetime">
|
|
||||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}', valueType: 'dateTime', search: <#if column.query>true<#else> false</#if>, width: 170 },
|
|
||||||
<#elseif column.htmlType == "imageUpload">
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}Url',
|
|
||||||
search: false,
|
|
||||||
width: 100,
|
|
||||||
render: (_, row) => <ImagePreview src={row.${column.javaField}Url || String(row.${column.javaField} || '')} width={50} height={50} />
|
|
||||||
},
|
|
||||||
<#elseif column.dictColumn>
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
|
||||||
render: (_, row) => <DictTag options={dicts.${column.dictType}} value={row.${column.javaField}} />
|
|
||||||
},
|
|
||||||
<#elseif column.htmlType == "switch">
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
width: 100,
|
|
||||||
render: (_, row) => <Switch checked={row.${column.javaField} === ${column.switchActiveValue}} disabled />
|
|
||||||
},
|
|
||||||
<#else>
|
|
||||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}'<#if !column.query>, search: false</#if> },
|
|
||||||
</#if>
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
valueType: 'option',
|
|
||||||
width: 130,
|
|
||||||
fixed: 'right',
|
|
||||||
render: (_, row) => (
|
|
||||||
<RowActions
|
|
||||||
actions={[
|
|
||||||
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
|
|
||||||
canAdd && { key: 'add', label: '新增', icon: <PlusOutlined />, onClick: () => openAdd(row) },
|
|
||||||
canRemove && {
|
|
||||||
key: 'delete',
|
|
||||||
label: '删除',
|
|
||||||
icon: <DeleteOutlined />,
|
|
||||||
danger: true,
|
|
||||||
confirm: `是否确认删除${functionName}编号为"${r'${row.'}${pkColumn.javaField}${r'}'}"的数据项?`,
|
|
||||||
onClick: () => remove(row)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer title="${functionName}">
|
|
||||||
<ProTable<${BusinessName}VO, ${BusinessName}Query>
|
|
||||||
actionRef={actionRef}
|
|
||||||
rowKey="${treeCode}"
|
|
||||||
columns={columns}
|
|
||||||
scroll={tableScroll}
|
|
||||||
pagination={false}
|
|
||||||
search={{ labelWidth: 90 }}
|
|
||||||
expandable={{
|
|
||||||
expandedRowKeys,
|
|
||||||
onExpandedRowsChange
|
|
||||||
}}
|
|
||||||
request={async params => {
|
|
||||||
const res = await list${BusinessName}(params);
|
|
||||||
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
|
|
||||||
setTableRows(rows);
|
|
||||||
syncExpandedRows(rows, expandAll);
|
|
||||||
<#if enableExport>
|
|
||||||
updateExportParams(params);
|
|
||||||
</#if>
|
|
||||||
return { data: rows, total: rows.length, success: true };
|
|
||||||
}}
|
|
||||||
toolbar={{ title: '${functionName}列表' }}
|
|
||||||
toolBarRender={() => [
|
|
||||||
canAdd && (
|
|
||||||
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={() => openAdd()}>
|
|
||||||
新增
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
<Button
|
|
||||||
key="expand"
|
|
||||||
icon={<SortAscendingOutlined />}
|
|
||||||
onClick={() => toggleExpandAll(tableRows)}
|
|
||||||
>
|
|
||||||
展开/折叠
|
|
||||||
</Button><#if enableExport>,
|
|
||||||
canExport && (
|
|
||||||
<Button
|
|
||||||
key="export"
|
|
||||||
icon={<DownloadOutlined />}
|
|
||||||
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_${r'${Date.now()}'}.xlsx`)}
|
|
||||||
>
|
|
||||||
导出
|
|
||||||
</Button>
|
|
||||||
)</#if>
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ModalForm<${BusinessName}Form>
|
|
||||||
title={modalTitle}
|
|
||||||
open={modalOpen}
|
|
||||||
width={560}
|
|
||||||
form={form}
|
|
||||||
layout="vertical"
|
|
||||||
initialValues={default${BusinessName}Form}
|
|
||||||
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
|
|
||||||
onOpenChange={open => !open && closeModal()}
|
|
||||||
onFinish={submitForm}
|
|
||||||
>
|
|
||||||
<ProFormText name="${pkColumn.javaField}" hidden />
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && !column.pk>
|
|
||||||
<#if column.javaField == treeParentCode>
|
|
||||||
<ProFormTreeSelect
|
|
||||||
name="${column.javaField}"
|
|
||||||
label="${column.columnLabel}"
|
|
||||||
<#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>
|
|
||||||
fieldProps={{
|
|
||||||
allowClear: true,
|
|
||||||
treeDefaultExpandAll: true,
|
|
||||||
treeData: treeSelectData,
|
|
||||||
placeholder: '请选择${column.columnLabel}'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<#elseif column.htmlType == "input">
|
|
||||||
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "textarea">
|
|
||||||
<ProFormTextArea name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "inputNumber">
|
|
||||||
<ProFormDigit name="${column.javaField}" label="${column.columnLabel}" min={0} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif (column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch") && column.dictType?has_content>
|
|
||||||
<ProFormSelect name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
|
|
||||||
<ProFormCheckbox.Group name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "switch">
|
|
||||||
<Form.Item
|
|
||||||
name="${column.javaField}"
|
|
||||||
label="${column.columnLabel}"
|
|
||||||
valuePropName="checked"
|
|
||||||
getValueProps={value => ({ checked: value === ${column.switchActiveValue} })}
|
|
||||||
normalize={checked => (checked ? ${column.switchActiveValue} : ${column.switchInactiveValue})}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
<#elseif column.htmlType == "datetime">
|
|
||||||
<ProFormDateTimePicker name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "imageUpload">
|
|
||||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
|
||||||
<ImageUpload />
|
|
||||||
</Form.Item>
|
|
||||||
<#elseif column.htmlType == "fileUpload">
|
|
||||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
|
||||||
<FileUpload />
|
|
||||||
</Form.Item>
|
|
||||||
<#elseif column.htmlType == "editor">
|
|
||||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
|
||||||
<RichTextEditor />
|
|
||||||
</Form.Item>
|
|
||||||
<#else>
|
|
||||||
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
</#if>
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
</ModalForm>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
691
gen/index-tree.vue.ftl
Normal file
691
gen/index-tree.vue.ftl
Normal file
@ -0,0 +1,691 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2 page-shell ${moduleName}-${businessName}-page">
|
||||||
|
<div class="search-wrap">
|
||||||
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
|
<template #header>
|
||||||
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query>
|
||||||
|
<#if column.htmlType == "input" || column.htmlType == "textarea">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input v-model="queryParams.${column.javaField}" placeholder="请输入${column.columnLabel}" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "inputNumber">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input-number v-model="queryParams.${column.javaField}" controls-position="right" />
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif (column.htmlType == "select" || column.htmlType == "radio") && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable>
|
||||||
|
<el-option v-for="dict in ${column.dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "switch" && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable>
|
||||||
|
<el-option v-for="dict in ${column.dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "switch">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable>
|
||||||
|
<#if column.javaType == "Boolean">
|
||||||
|
<el-option label="是" :value="true" />
|
||||||
|
<el-option label="否" :value="false" />
|
||||||
|
<#elseif column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
<el-option label="开启" :value="0" />
|
||||||
|
<el-option label="关闭" :value="1" />
|
||||||
|
<#else>
|
||||||
|
<el-option label="开启" value="0" />
|
||||||
|
<el-option label="关闭" value="1" />
|
||||||
|
</#if>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif (column.htmlType == "select" || column.htmlType == "radio") && !(column.dictType?has_content)>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable>
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "datetime" && column.queryType != "BETWEEN">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-date-picker clearable
|
||||||
|
v-model="queryParams.${column.javaField}"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
placeholder="选择${column.columnLabel}"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
<el-form-item label="${column.columnLabel}" style="width: 308px">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange${column.capJavaField}"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="-"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-card shadow="hover" class="table-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="toolbar-shell">
|
||||||
|
<div class="table-heading">
|
||||||
|
<h3>${functionName}列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button>
|
||||||
|
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||||
|
<#if enableExport>
|
||||||
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['${moduleName}:${businessName}:export']">导出</el-button>
|
||||||
|
</#if>
|
||||||
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-table
|
||||||
|
ref="${businessName}TableRef"
|
||||||
|
v-loading="loading"
|
||||||
|
class="data-table"
|
||||||
|
:data="${businessName}List"
|
||||||
|
row-key="${treeCode}"
|
||||||
|
border
|
||||||
|
:default-expand-all="isExpandAll"
|
||||||
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
|
>
|
||||||
|
<#assign firstTreeListField = "">
|
||||||
|
<#list columns as tempColumn>
|
||||||
|
<#if !tempColumn.pk && tempColumn.list && "" != tempColumn.javaField && firstTreeListField == "">
|
||||||
|
<#assign firstTreeListField = tempColumn.javaField>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.pk>
|
||||||
|
<#elseif enableStatus && statusField == column.javaField>
|
||||||
|
<#if column.javaField == firstTreeListField>
|
||||||
|
<el-table-column label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<#else>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}">
|
||||||
|
</#if>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch
|
||||||
|
v-model="scope.row.${column.javaField}"
|
||||||
|
:active-value="${statusField}ActiveValue"
|
||||||
|
:inactive-value="${statusField}InactiveValue"
|
||||||
|
@change="handleStatusChange(scope.row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif enableSort && sortField == column.javaField>
|
||||||
|
<#if column.javaField == firstTreeListField>
|
||||||
|
<el-table-column label="${column.columnLabel}" prop="${column.javaField}" width="160">
|
||||||
|
<#else>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="160">
|
||||||
|
</#if>
|
||||||
|
<template #default="scope">
|
||||||
|
<#if column.javaType == "LocalDateTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="scope.row.${column.javaField}"
|
||||||
|
type="datetime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
placeholder="选择${column.columnLabel}"
|
||||||
|
@change="handleSortChange(scope.row)"
|
||||||
|
/>
|
||||||
|
<#else>
|
||||||
|
<el-input-number v-model="scope.row.${column.javaField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
|
||||||
|
</#if>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && column.htmlType == "switch">
|
||||||
|
<#if column.javaField == firstTreeListField>
|
||||||
|
<el-table-column label="${column.columnLabel}" prop="${column.javaField}" width="120">
|
||||||
|
<#else>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="120">
|
||||||
|
</#if>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch
|
||||||
|
v-model="scope.row.${column.javaField}"
|
||||||
|
<#if column.javaType == "Boolean">
|
||||||
|
:active-value="true"
|
||||||
|
:inactive-value="false"
|
||||||
|
<#elseif column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
:active-value="0"
|
||||||
|
:inactive-value="1"
|
||||||
|
<#else>
|
||||||
|
active-value="0"
|
||||||
|
inactive-value="1"
|
||||||
|
</#if>
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && column.htmlType == "datetime">
|
||||||
|
<#if column.javaField == firstTreeListField>
|
||||||
|
<el-table-column label="${column.columnLabel}" prop="${column.javaField}" width="180">
|
||||||
|
<#else>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="180">
|
||||||
|
</#if>
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ parseTime(scope.row.${column.javaField}, '{y}-{m}-{d}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && column.htmlType == "imageUpload">
|
||||||
|
<#if column.javaField == firstTreeListField>
|
||||||
|
<el-table-column label="${column.columnLabel}" prop="${column.javaField}Url" width="100">
|
||||||
|
<#else>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}Url" width="100">
|
||||||
|
</#if>
|
||||||
|
<template #default="scope">
|
||||||
|
<image-preview :src="scope.row.${column.javaField}Url" :width="50" :height="50"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && column.dictColumn>
|
||||||
|
<#if column.javaField == firstTreeListField>
|
||||||
|
<el-table-column label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<#else>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}">
|
||||||
|
</#if>
|
||||||
|
<template #default="scope">
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
<dict-tag :options="${column.dictType}" :value="scope.row.${column.javaField} ? scope.row.${column.javaField}.split(',') : []"/>
|
||||||
|
<#else>
|
||||||
|
<dict-tag :options="${column.dictType}" :value="scope.row.${column.javaField}"/>
|
||||||
|
</#if>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && "" != column.javaField>
|
||||||
|
<#if column.javaField == firstTreeListField>
|
||||||
|
<el-table-column label="${column.columnLabel}" prop="${column.javaField}" />
|
||||||
|
<#else>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" />
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#if enableStatus && !statusColumn.list>
|
||||||
|
<el-table-column label="${statusColumn.columnComment}" align="center" prop="${statusField}">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch
|
||||||
|
v-model="scope.row.${statusField}"
|
||||||
|
:active-value="${statusField}ActiveValue"
|
||||||
|
:inactive-value="${statusField}InactiveValue"
|
||||||
|
@change="handleStatusChange(scope.row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</#if>
|
||||||
|
<#if enableSort && !sortColumn.list>
|
||||||
|
<el-table-column label="${sortColumn.columnComment}" align="center" prop="${sortField}" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
<#if sortColumn.javaType == "LocalDateTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="scope.row.${sortField}"
|
||||||
|
type="datetime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
placeholder="选择${sortColumn.columnComment}"
|
||||||
|
@change="handleSortChange(scope.row)"
|
||||||
|
/>
|
||||||
|
<#else>
|
||||||
|
<el-input-number v-model="scope.row.${sortField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
|
||||||
|
</#if>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</#if>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="修改" placement="top">
|
||||||
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']" />
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="新增" placement="top">
|
||||||
|
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']" />
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="删除" placement="top">
|
||||||
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']" />
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
<!-- 添加或修改${functionName}对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
|
<el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
|
<#list columns as column>
|
||||||
|
<#if (column.insert || column.edit) && !column.pk>
|
||||||
|
<#if "" != treeParentCode && column.javaField == treeParentCode>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${treeParentCode}">
|
||||||
|
<el-tree-select
|
||||||
|
v-model="form.${treeParentCode}"
|
||||||
|
:data="${businessName}Options"
|
||||||
|
:props="{ value: '${treeCode}', label: '${treeName}', children: 'children' } as any"
|
||||||
|
value-key="${treeCode}"
|
||||||
|
placeholder="请选择${column.columnLabel}"
|
||||||
|
check-strictly
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "input">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input v-model="form.${column.javaField}" placeholder="请输入${column.columnLabel}" />
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "inputNumber">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input-number v-model="form.${column.javaField}" controls-position="right" />
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "imageUpload">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<image-upload v-model="form.${column.javaField}"/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "fileUpload">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<file-upload v-model="form.${column.javaField}"/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "editor">
|
||||||
|
<el-form-item label="${column.columnLabel}">
|
||||||
|
<editor v-model="form.${column.javaField}" :min-height="192"/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "select" && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="form.${column.javaField}" placeholder="请选择${column.columnLabel}">
|
||||||
|
<el-option
|
||||||
|
v-for="dict in ${column.dictType}"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
<#if column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
:value="parseInt(dict.value)"
|
||||||
|
<#else>
|
||||||
|
:value="dict.value"
|
||||||
|
</#if>
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "select" && !(column.dictType?has_content)>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="form.${column.javaField}" placeholder="请选择${column.columnLabel}">
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-checkbox-group v-model="form.${column.javaField}">
|
||||||
|
<el-checkbox
|
||||||
|
v-for="dict in ${column.dictType}"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.value">
|
||||||
|
{{dict.label}}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "checkbox" && !(column.dictType?has_content)>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-checkbox-group v-model="form.${column.javaField}">
|
||||||
|
<el-checkbox>请选择字典生成</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "radio" && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-radio-group v-model="form.${column.javaField}">
|
||||||
|
<el-radio
|
||||||
|
v-for="dict in ${column.dictType}"
|
||||||
|
:key="dict.value"
|
||||||
|
<#if column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
:value="parseInt(dict.value)"
|
||||||
|
<#else>
|
||||||
|
:value="dict.value"
|
||||||
|
</#if>
|
||||||
|
>{{dict.label}}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "radio" && !(column.dictType?has_content)>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-radio-group v-model="form.${column.javaField}">
|
||||||
|
<el-radio value="1">请选择字典生成</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "switch">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-switch
|
||||||
|
v-model="form.${column.javaField}"
|
||||||
|
<#if column.javaType == "Boolean">
|
||||||
|
:active-value="true"
|
||||||
|
:inactive-value="false"
|
||||||
|
<#elseif column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
:active-value="0"
|
||||||
|
:inactive-value="1"
|
||||||
|
<#else>
|
||||||
|
active-value="0"
|
||||||
|
inactive-value="1"
|
||||||
|
</#if>
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "datetime">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-date-picker clearable
|
||||||
|
v-model="form.${column.javaField}"
|
||||||
|
type="datetime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
placeholder="选择${column.columnLabel}"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "textarea">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input v-model="form.${column.javaField}" type="textarea" placeholder="请输入内容" />
|
||||||
|
</el-form-item>
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="${BusinessName}" lang="ts">
|
||||||
|
import {
|
||||||
|
add${BusinessName},
|
||||||
|
<#if enableStatus>
|
||||||
|
change${BusinessName}Status,
|
||||||
|
</#if>
|
||||||
|
del${BusinessName},
|
||||||
|
get${BusinessName},
|
||||||
|
list${BusinessName},
|
||||||
|
<#if enableSort>
|
||||||
|
update${BusinessName}Sort,
|
||||||
|
</#if>
|
||||||
|
update${BusinessName}
|
||||||
|
} from '@/api/${moduleName}/${businessName}';
|
||||||
|
import { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
||||||
|
import { useLoading } from '@/hooks/async/useLoading';
|
||||||
|
import { useFormDialog } from '@/hooks/dialog/useFormDialog';
|
||||||
|
<#if needAddDateRange>
|
||||||
|
import { useDateRangeQuery } from '@/hooks/form/useDateRangeQuery';
|
||||||
|
</#if>
|
||||||
|
import { useSearchReset } from '@/hooks/form/useSearchReset';
|
||||||
|
import { useSearchToggle } from '@/hooks/form/useSearchToggle';
|
||||||
|
import { useTreeTableExpand } from '@/hooks/tree/useTreeTableExpand';
|
||||||
|
<#if needDict>
|
||||||
|
import { useDict } from '@/utils/dict';
|
||||||
|
</#if>
|
||||||
|
import modal from '@/plugins/modal';
|
||||||
|
import { handleTree } from '@/utils/ruoyi';
|
||||||
|
<#if enableExport>
|
||||||
|
import { download as requestDownload } from '@/utils/request';
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if needDict>
|
||||||
|
const { ${dictsNoSymbol} } = toRefs<any>(useDict(${dicts}));
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if enableStatus>
|
||||||
|
const ${statusField}ActiveValue = <#if statusColumn.javaType == "Boolean">true<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">0<#else>'0'</#if>;
|
||||||
|
const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'</#if>;
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
type ${BusinessName}Option = {
|
||||||
|
${treeCode}: <#if treeParentColumn.javaType == 'String'>string<#else> number</#if>;
|
||||||
|
${treeName}: string;
|
||||||
|
children?: ${BusinessName}Option[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const ${businessName}List = ref<${BusinessName}VO[]>([]);
|
||||||
|
const ${businessName}Options = ref<${BusinessName}Option[]>([]);
|
||||||
|
const all${BusinessName}Options = ref<${BusinessName}Option[]>([]);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const { showSearch } = useSearchToggle();
|
||||||
|
const { loading, setLoading, withLoading } = useLoading();
|
||||||
|
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
const ${businessName}FormRef = ref<ElFormInstance>();
|
||||||
|
const ${businessName}TableRef = ref<ElTableInstance>();
|
||||||
|
const { isExpandAll, handleToggleExpandAll } = useTreeTableExpand<${BusinessName}VO>({
|
||||||
|
tableRef: ${businessName}TableRef,
|
||||||
|
data: ${businessName}List
|
||||||
|
});
|
||||||
|
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
const {
|
||||||
|
dateRange: dateRange${column.capJavaField},
|
||||||
|
applyDateRange: apply${column.capJavaField}DateRange,
|
||||||
|
resetDateRange: reset${column.capJavaField}DateRange
|
||||||
|
} = useDateRangeQuery('${column.capJavaField}');
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
const initFormData: ${BusinessName}Form = {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.insert || column.edit>
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
${column.javaField}: [],
|
||||||
|
<#else>
|
||||||
|
${column.javaField}: undefined,
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
|
||||||
|
form: {...initFormData},
|
||||||
|
queryParams: {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query>
|
||||||
|
<#if column.htmlType != "datetime" || column.queryType != "BETWEEN">
|
||||||
|
${column.javaField}: undefined,
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
params: {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query>
|
||||||
|
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
${column.javaField}: undefined,
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.insert || column.edit>
|
||||||
|
<#if column.required>
|
||||||
|
${column.javaField}: [
|
||||||
|
{ required: true, message: "${column.columnLabel}不能为空", trigger: <#if column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch" || column.htmlType == "inputNumber">"change"<#else>"blur"</#if> }
|
||||||
|
],
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
const { dialog, resetForm: reset, openDialog, showDialog, closeDialog } = useFormDialog({
|
||||||
|
form,
|
||||||
|
formRef: ${businessName}FormRef,
|
||||||
|
initialFormData: initFormData
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 查询${functionName}列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
await withLoading(async () => {
|
||||||
|
<#if needAddDateRange>
|
||||||
|
let params = queryParams.value;
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
params = apply${column.capJavaField}DateRange(params);
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
const res = await list${BusinessName}(params);
|
||||||
|
<#else>
|
||||||
|
const res = await list${BusinessName}(queryParams.value);
|
||||||
|
</#if>
|
||||||
|
const data = handleTree<${BusinessName}VO>(res.data, '${treeCode}', '${treeParentCode}');
|
||||||
|
if (data) {
|
||||||
|
${businessName}List.value = data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 查询${functionName}下拉树结构 */
|
||||||
|
const getTreeselect = async (excludeId?: string | number) => {
|
||||||
|
const res = await list${BusinessName}();
|
||||||
|
const data: ${BusinessName}Option = { ${treeCode}: ${treeRootValueTsLiteral}, ${treeName}: '顶级节点', children: [] };
|
||||||
|
data.children = handleTree<${BusinessName}Option>(res.data, '${treeCode}', '${treeParentCode}');
|
||||||
|
all${BusinessName}Options.value = [data];
|
||||||
|
${businessName}Options.value = excludeId != null ? filterTreeOptions(all${BusinessName}Options.value, excludeId) : all${BusinessName}Options.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
closeDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const { resetQuery } = useSearchReset({
|
||||||
|
queryFormRef,
|
||||||
|
queryParams,
|
||||||
|
resetExtras: () => {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
reset${column.capJavaField}DateRange();
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
},
|
||||||
|
afterReset: () => {
|
||||||
|
handleQuery();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = (row?: Partial<${BusinessName}VO>) => {
|
||||||
|
openDialog('添加${functionName}');
|
||||||
|
getTreeselect();
|
||||||
|
if (row != null && row.${treeCode}) {
|
||||||
|
form.value.${treeParentCode} = row.${treeCode};
|
||||||
|
} else {
|
||||||
|
form.value.${treeParentCode} = ${treeRootValueTsLiteral};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = async (row: Partial<${BusinessName}VO>) => {
|
||||||
|
reset();
|
||||||
|
await getTreeselect(row.${treeCode});
|
||||||
|
if (row != null) {
|
||||||
|
form.value.${treeParentCode} = row.${treeParentCode};
|
||||||
|
}
|
||||||
|
const res = await get${BusinessName}(row.${pkColumn.javaField});
|
||||||
|
Object.assign(form.value, res.data);
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
form.value.${column.javaField} = form.value.${column.javaField}.split(",");
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
showDialog('修改${functionName}');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
${businessName}FormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true;
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
form.value.${column.javaField} = form.value.${column.javaField}.join(",");
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
if (form.value.${pkColumn.javaField}) {
|
||||||
|
await update${BusinessName}(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
} else {
|
||||||
|
await add${BusinessName}(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
}
|
||||||
|
modal.msgSuccess('操作成功');
|
||||||
|
closeDialog();
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (row: Partial<${BusinessName}VO>) => {
|
||||||
|
await modal.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?');
|
||||||
|
setLoading(true);
|
||||||
|
await del${BusinessName}(row.${pkColumn.javaField}).finally(() => setLoading(false));
|
||||||
|
await getList();
|
||||||
|
modal.msgSuccess('删除成功');
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterTreeOptions = (options: ${BusinessName}Option[], excludeId: string | number): ${BusinessName}Option[] => {
|
||||||
|
return options
|
||||||
|
.filter(item => item.${treeCode} !== excludeId)
|
||||||
|
.map(item => ({
|
||||||
|
...item,
|
||||||
|
children: item.children ? filterTreeOptions(item.children, excludeId) : []
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
<#if enableStatus>
|
||||||
|
/** 状态修改 */
|
||||||
|
const handleStatusChange = async (row: Partial<${BusinessName}VO>) => {
|
||||||
|
const text = row.${statusField} === ${statusField}ActiveValue ? '启用' : '停用';
|
||||||
|
try {
|
||||||
|
await modal.confirm('确认要"' + text + '"吗?');
|
||||||
|
await change${BusinessName}Status(row.${pkColumn.javaField}, row.${statusField});
|
||||||
|
modal.msgSuccess(text + '成功');
|
||||||
|
} catch (err) {
|
||||||
|
row.${statusField} = row.${statusField} === ${statusField}ActiveValue ? ${statusField}InactiveValue : ${statusField}ActiveValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if enableSort>
|
||||||
|
/** 排序调整 */
|
||||||
|
const handleSortChange = async (row: Partial<${BusinessName}VO>) => {
|
||||||
|
try {
|
||||||
|
await update${BusinessName}Sort(row.${pkColumn.javaField}, row.${sortField});
|
||||||
|
modal.msgSuccess('排序更新成功');
|
||||||
|
} catch (err) {
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if enableExport>
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = () => {
|
||||||
|
requestDownload(
|
||||||
|
'${moduleName}/${businessName}/export',
|
||||||
|
{
|
||||||
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`${businessName}_${r'${new Date().getTime()}'}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@ -1,406 +0,0 @@
|
|||||||
import { DeleteOutlined<#if enableExport>, DownloadOutlined</#if>, EditOutlined, PlusOutlined } from '@ant-design/icons';
|
|
||||||
import {
|
|
||||||
ModalForm,
|
|
||||||
PageContainer,
|
|
||||||
<#if needCheckbox>
|
|
||||||
ProFormCheckbox,
|
|
||||||
</#if>
|
|
||||||
<#if needDateField>
|
|
||||||
ProFormDateTimePicker,
|
|
||||||
</#if>
|
|
||||||
<#if needDigit>
|
|
||||||
ProFormDigit,
|
|
||||||
</#if>
|
|
||||||
<#if needSelect>
|
|
||||||
ProFormSelect,
|
|
||||||
</#if>
|
|
||||||
<#if needTextArea>
|
|
||||||
ProFormTextArea,
|
|
||||||
</#if>
|
|
||||||
ProFormText,
|
|
||||||
ProTable,
|
|
||||||
type ActionType,
|
|
||||||
type ProColumns
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { useBoolean } from 'ahooks';
|
|
||||||
import { Button, Form, message, Popconfirm<#if enableStatus || needSwitchField>, Switch</#if><#if enableSort>, InputNumber</#if> } from 'antd';
|
|
||||||
import { useRef, useState } from 'react';
|
|
||||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
|
||||||
import {
|
|
||||||
add${BusinessName},
|
|
||||||
<#if enableStatus>
|
|
||||||
change${BusinessName}Status,
|
|
||||||
</#if>
|
|
||||||
del${BusinessName},
|
|
||||||
get${BusinessName},
|
|
||||||
list${BusinessName},
|
|
||||||
<#if enableSort>
|
|
||||||
update${BusinessName}Sort,
|
|
||||||
</#if>
|
|
||||||
update${BusinessName}
|
|
||||||
} from '@/api/${moduleName}/${businessName}';
|
|
||||||
<#if needDict>
|
|
||||||
import DictTag from '@/components/common/DictTag';
|
|
||||||
</#if>
|
|
||||||
<#if needFileUpload>
|
|
||||||
import FileUpload from '@/components/common/FileUpload';
|
|
||||||
</#if>
|
|
||||||
<#if needImagePreview>
|
|
||||||
import ImagePreview from '@/components/common/ImagePreview';
|
|
||||||
</#if>
|
|
||||||
<#if needImageUpload>
|
|
||||||
import ImageUpload from '@/components/common/ImageUpload';
|
|
||||||
</#if>
|
|
||||||
<#if needEditor>
|
|
||||||
import RichTextEditor from '@/components/common/RichTextEditor';
|
|
||||||
</#if>
|
|
||||||
import RowActions from '@/components/common/RowActions';
|
|
||||||
<#if needDict>
|
|
||||||
import { useDict } from '@/hooks/useDict';
|
|
||||||
</#if>
|
|
||||||
<#if needDateRange>
|
|
||||||
import { useDateRangeQuery } from '@/hooks/useDateRangeQuery';
|
|
||||||
</#if>
|
|
||||||
<#if enableExport>
|
|
||||||
import { useTableExport } from '@/hooks/useTableExport';
|
|
||||||
</#if>
|
|
||||||
import { useTableScroll } from '@/hooks/useTableScroll';
|
|
||||||
import { useTableSelection } from '@/hooks/useTableSelection';
|
|
||||||
import { useUserStore } from '@/stores/userStore';
|
|
||||||
<#if needDict>
|
|
||||||
import { dictOptions } from '@/utils/dict';
|
|
||||||
</#if>
|
|
||||||
<#if enableStatus>
|
|
||||||
import { confirmAction } from '@/utils/modal';
|
|
||||||
</#if>
|
|
||||||
import { hasPermi } from '@/utils/permission';
|
|
||||||
import { <#if needDateField>formatDateTimeFields, toDayjsFields, </#if> toPageQuery, toTableData } from '@/utils/ruoyi';
|
|
||||||
|
|
||||||
const default${BusinessName}Form: ${BusinessName}Form = {
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && !column.pk && column.htmlType == "checkbox">
|
|
||||||
${column.javaField}: [],
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
};
|
|
||||||
|
|
||||||
<#if enableStatus>
|
|
||||||
const ${statusField}ActiveValue = <#if statusColumn.javaType == "Boolean">true<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">0<#else>'0'</#if>;
|
|
||||||
const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'</#if>;
|
|
||||||
|
|
||||||
</#if>
|
|
||||||
export default function ${BusinessName}Page() {
|
|
||||||
const actionRef = useRef<ActionType | undefined>(undefined);
|
|
||||||
const { tableScroll } = useTableScroll(1000);
|
|
||||||
const [form] = Form.useForm<${BusinessName}Form>();
|
|
||||||
const userInfo = useUserStore(state => state.userInfo);
|
|
||||||
<#if needDict>
|
|
||||||
const dicts = useDict(${dicts});
|
|
||||||
</#if>
|
|
||||||
const { ids, selectedOne, handleSelectionChange, clearSelection } = useTableSelection<${BusinessName}VO>(
|
|
||||||
row => row.${pkColumn.javaField}
|
|
||||||
);
|
|
||||||
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
|
||||||
const [modalTitle, setModalTitle] = useState('');
|
|
||||||
<#if enableExport>
|
|
||||||
const { updateExportParams, exportFile } = useTableExport();
|
|
||||||
</#if>
|
|
||||||
<#list columns as column>
|
|
||||||
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
|
||||||
const { applyDateRange: apply${column.capJavaField}DateRange } = useDateRangeQuery('${column.capJavaField}');
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
|
|
||||||
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
|
|
||||||
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
|
|
||||||
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
|
|
||||||
<#if enableExport>
|
|
||||||
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
const openAdd = () => {
|
|
||||||
form.resetFields();
|
|
||||||
form.setFieldsValue(default${BusinessName}Form);
|
|
||||||
setModalTitle('添加${functionName}');
|
|
||||||
openModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const openEdit = async (row?: ${BusinessName}VO) => {
|
|
||||||
const target = row || selectedOne;
|
|
||||||
if (!target?.${pkColumn.javaField}) return;
|
|
||||||
const res = await get${BusinessName}(target.${pkColumn.javaField});
|
|
||||||
const data = <#if needDateField>toDayjsFields({ ...res.data }, [
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
|
||||||
'${column.javaField}',
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
])<#else>{ ...res.data }</#if>;
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
|
||||||
if (typeof data.${column.javaField} === 'string') {
|
|
||||||
data.${column.javaField} = data.${column.javaField}.split(',');
|
|
||||||
}
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
form.resetFields();
|
|
||||||
form.setFieldsValue(data);
|
|
||||||
setModalTitle('修改${functionName}');
|
|
||||||
openModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitForm = async (values: ${BusinessName}Form) => {
|
|
||||||
const submitValues = <#if needDateField>formatDateTimeFields({ ...values }, [
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
|
||||||
'${column.javaField}',
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
])<#else>{ ...values }</#if>;
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
|
||||||
if (Array.isArray(submitValues.${column.javaField})) {
|
|
||||||
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
|
|
||||||
}
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
|
|
||||||
message.success('操作成功');
|
|
||||||
form.resetFields();
|
|
||||||
actionRef.current?.reload();
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const remove = async (row?: ${BusinessName}VO) => {
|
|
||||||
await del${BusinessName}(row?.${pkColumn.javaField} || ids);
|
|
||||||
message.success('删除成功');
|
|
||||||
clearSelection();
|
|
||||||
actionRef.current?.reloadAndRest?.();
|
|
||||||
};
|
|
||||||
|
|
||||||
<#if enableStatus>
|
|
||||||
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
|
|
||||||
const previousStatus = row.${statusField};
|
|
||||||
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
|
|
||||||
const text = checked ? '启用' : '停用';
|
|
||||||
try {
|
|
||||||
await confirmAction(`确认要"${r'${text}'}"吗?`);
|
|
||||||
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
|
|
||||||
message.success(`${r'${text}'}成功`);
|
|
||||||
actionRef.current?.reload();
|
|
||||||
} catch {
|
|
||||||
row.${statusField} = previousStatus;
|
|
||||||
actionRef.current?.reload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
</#if>
|
|
||||||
<#if enableSort>
|
|
||||||
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
|
|
||||||
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
|
|
||||||
message.success('排序更新成功');
|
|
||||||
actionRef.current?.reload();
|
|
||||||
};
|
|
||||||
|
|
||||||
</#if>
|
|
||||||
const columns: ProColumns<${BusinessName}VO>[] = [
|
|
||||||
<#list columns as column>
|
|
||||||
<#if column.list>
|
|
||||||
<#if enableStatus && statusField == column.javaField>
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
width: 100,
|
|
||||||
<#if column.dictType?has_content>
|
|
||||||
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
|
||||||
</#if>
|
|
||||||
render: (_, row) => (
|
|
||||||
<Switch
|
|
||||||
checked={row.${column.javaField} === ${statusField}ActiveValue}
|
|
||||||
disabled={!canEdit}
|
|
||||||
onChange={checked => handleStatusChange(row, checked)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
<#elseif enableSort && sortField == column.javaField>
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}',
|
|
||||||
search: false,
|
|
||||||
width: 130,
|
|
||||||
render: (_, row) => <InputNumber min={0} value={row.${column.javaField} as number} onChange={value => handleSortChange(row, value)} />
|
|
||||||
},
|
|
||||||
<#elseif column.htmlType == "datetime">
|
|
||||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}', valueType: 'dateTime', search: <#if column.query && column.queryType != "BETWEEN">true<#else> false</#if>, width: 170 },
|
|
||||||
<#elseif column.htmlType == "imageUpload">
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}Url',
|
|
||||||
search: false,
|
|
||||||
width: 100,
|
|
||||||
render: (_, row) => <ImagePreview src={row.${column.javaField}Url || String(row.${column.javaField} || '')} width={50} height={50} />
|
|
||||||
},
|
|
||||||
<#elseif column.dictColumn>
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
|
||||||
render: (_, row) => <DictTag options={dicts.${column.dictType}} value={row.${column.javaField}} />
|
|
||||||
},
|
|
||||||
<#elseif column.htmlType == "switch">
|
|
||||||
{
|
|
||||||
title: '${column.columnLabel}',
|
|
||||||
dataIndex: '${column.javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
width: 100,
|
|
||||||
render: (_, row) => <Switch checked={row.${column.javaField} === ${column.switchActiveValue}} disabled />
|
|
||||||
},
|
|
||||||
<#else>
|
|
||||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}'<#if !column.query>, search: false</#if> },
|
|
||||||
</#if>
|
|
||||||
</#if>
|
|
||||||
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
|
||||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}Range', valueType: 'dateTimeRange', hideInTable: true },
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
valueType: 'option',
|
|
||||||
width: 92,
|
|
||||||
fixed: 'right',
|
|
||||||
render: (_, row) => (
|
|
||||||
<RowActions
|
|
||||||
actions={[
|
|
||||||
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
|
|
||||||
canRemove && {
|
|
||||||
key: 'delete',
|
|
||||||
label: '删除',
|
|
||||||
icon: <DeleteOutlined />,
|
|
||||||
danger: true,
|
|
||||||
confirm: `是否确认删除${functionName}编号为"${r'${row.'}${pkColumn.javaField}${r'}'}"的数据项?`,
|
|
||||||
onClick: () => remove(row)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer title="${functionName}">
|
|
||||||
<ProTable<${BusinessName}VO, ${BusinessName}Query<#if needDateRange> & Record<string, unknown></#if>>
|
|
||||||
actionRef={actionRef}
|
|
||||||
rowKey="${pkColumn.javaField}"
|
|
||||||
columns={columns}
|
|
||||||
scroll={tableScroll}
|
|
||||||
search={{ labelWidth: 90 }}
|
|
||||||
pagination={{ defaultPageSize: 10, showSizeChanger: true }}
|
|
||||||
rowSelection={{ selectedRowKeys: ids, onChange: handleSelectionChange }}
|
|
||||||
request={async params => {
|
|
||||||
<#if needDateRange>
|
|
||||||
let query = toPageQuery(params);
|
|
||||||
<#list columns as column>
|
|
||||||
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
|
||||||
query = apply${column.capJavaField}DateRange(query, params.${column.javaField}Range as [string, string] | undefined);
|
|
||||||
delete query.${column.javaField}Range;
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
<#else>
|
|
||||||
const query = toPageQuery(params);
|
|
||||||
</#if>
|
|
||||||
<#if enableExport>
|
|
||||||
updateExportParams(query);
|
|
||||||
</#if>
|
|
||||||
const res = await list${BusinessName}(query);
|
|
||||||
return toTableData(res);
|
|
||||||
}}
|
|
||||||
toolbar={{ title: '${functionName}列表' }}
|
|
||||||
toolBarRender={() => [
|
|
||||||
canAdd && (
|
|
||||||
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={openAdd}>
|
|
||||||
新增
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
canEdit && (
|
|
||||||
<Button key="edit" disabled={!selectedOne} icon={<EditOutlined />} onClick={() => openEdit()}>
|
|
||||||
修改
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
canRemove && (
|
|
||||||
<Popconfirm key="delete" title={`是否确认删除${functionName}编号为"${r'${ids}'}"的数据项?`} onConfirm={() => remove()}>
|
|
||||||
<Button danger disabled={!ids.length} icon={<DeleteOutlined />}>
|
|
||||||
删除
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>
|
|
||||||
)<#if enableExport>,
|
|
||||||
canExport && (
|
|
||||||
<Button
|
|
||||||
key="export"
|
|
||||||
icon={<DownloadOutlined />}
|
|
||||||
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_${r'${Date.now()}'}.xlsx`)}
|
|
||||||
>
|
|
||||||
导出
|
|
||||||
</Button>
|
|
||||||
)</#if>
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ModalForm<${BusinessName}Form>
|
|
||||||
title={modalTitle}
|
|
||||||
open={modalOpen}
|
|
||||||
width={560}
|
|
||||||
form={form}
|
|
||||||
layout="vertical"
|
|
||||||
initialValues={default${BusinessName}Form}
|
|
||||||
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
|
|
||||||
onOpenChange={open => !open && closeModal()}
|
|
||||||
onFinish={submitForm}
|
|
||||||
>
|
|
||||||
<ProFormText name="${pkColumn.javaField}" hidden />
|
|
||||||
<#list columns as column>
|
|
||||||
<#if (column.insert || column.edit) && !column.pk>
|
|
||||||
<#if column.htmlType == "input">
|
|
||||||
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "textarea">
|
|
||||||
<ProFormTextArea name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "inputNumber">
|
|
||||||
<ProFormDigit name="${column.javaField}" label="${column.columnLabel}" min={0} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif (column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch") && column.dictType?has_content>
|
|
||||||
<ProFormSelect name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
|
|
||||||
<ProFormCheckbox.Group name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "switch">
|
|
||||||
<Form.Item
|
|
||||||
name="${column.javaField}"
|
|
||||||
label="${column.columnLabel}"
|
|
||||||
valuePropName="checked"
|
|
||||||
getValueProps={value => ({ checked: value === ${column.switchActiveValue} })}
|
|
||||||
normalize={checked => (checked ? ${column.switchActiveValue} : ${column.switchInactiveValue})}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
<#elseif column.htmlType == "datetime">
|
|
||||||
<ProFormDateTimePicker name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
<#elseif column.htmlType == "imageUpload">
|
|
||||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
|
||||||
<ImageUpload />
|
|
||||||
</Form.Item>
|
|
||||||
<#elseif column.htmlType == "fileUpload">
|
|
||||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
|
||||||
<FileUpload />
|
|
||||||
</Form.Item>
|
|
||||||
<#elseif column.htmlType == "editor">
|
|
||||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
|
||||||
<RichTextEditor />
|
|
||||||
</Form.Item>
|
|
||||||
<#else>
|
|
||||||
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
|
||||||
</#if>
|
|
||||||
</#if>
|
|
||||||
</#list>
|
|
||||||
</ModalForm>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
615
gen/index.vue.ftl
Normal file
615
gen/index.vue.ftl
Normal file
@ -0,0 +1,615 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2 page-shell ${moduleName}-${businessName}-page">
|
||||||
|
<div class="search-wrap">
|
||||||
|
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
|
||||||
|
<template #header>
|
||||||
|
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
|
||||||
|
<div><h3>筛选条件</h3></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query>
|
||||||
|
<#if column.htmlType == "input" || column.htmlType == "textarea">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input v-model="queryParams.${column.javaField}" placeholder="请输入${column.columnLabel}" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "inputNumber">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input-number v-model="queryParams.${column.javaField}" controls-position="right" />
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif (column.htmlType == "select" || column.htmlType == "radio") && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable >
|
||||||
|
<el-option v-for="dict in ${column.dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "switch" && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable >
|
||||||
|
<el-option v-for="dict in ${column.dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "switch">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable >
|
||||||
|
<#if column.javaType == "Boolean">
|
||||||
|
<el-option label="是" :value="true" />
|
||||||
|
<el-option label="否" :value="false" />
|
||||||
|
<#elseif column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
<el-option label="开启" :value="0" />
|
||||||
|
<el-option label="关闭" :value="1" />
|
||||||
|
<#else>
|
||||||
|
<el-option label="开启" value="0" />
|
||||||
|
<el-option label="关闭" value="1" />
|
||||||
|
</#if>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif (column.htmlType == "select" || column.htmlType == "radio") && !(column.dictType?has_content)>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable >
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "datetime" && column.queryType != "BETWEEN">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-date-picker clearable
|
||||||
|
v-model="queryParams.${column.javaField}"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
placeholder="请选择${column.columnLabel}"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "datetime" && column.queryType == "BETWEEN" && column.query>
|
||||||
|
<el-form-item label="${column.columnLabel}" style="width: 308px">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange${column.capJavaField}"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="-"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-card shadow="hover" class="table-panel">
|
||||||
|
<template #header>
|
||||||
|
<div class="toolbar-shell">
|
||||||
|
<div class="table-heading">
|
||||||
|
<h3>${functionName}列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button>
|
||||||
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button>
|
||||||
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button>
|
||||||
|
<#if enableExport>
|
||||||
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['${moduleName}:${businessName}:export']">导出</el-button>
|
||||||
|
</#if>
|
||||||
|
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" border class="data-table" :data="${businessName}List" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.pk && column.list>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" />
|
||||||
|
<#elseif enableStatus && statusField == column.javaField>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch
|
||||||
|
v-model="scope.row.${column.javaField}"
|
||||||
|
:active-value="${statusField}ActiveValue"
|
||||||
|
:inactive-value="${statusField}InactiveValue"
|
||||||
|
@change="handleStatusChange(scope.row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif enableSort && sortField == column.javaField>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
<#if column.javaType == "LocalDateTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="scope.row.${column.javaField}"
|
||||||
|
type="datetime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
placeholder="选择${column.columnLabel}"
|
||||||
|
@change="handleSortChange(scope.row)"
|
||||||
|
/>
|
||||||
|
<#else>
|
||||||
|
<el-input-number v-model="scope.row.${column.javaField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
|
||||||
|
</#if>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && column.htmlType == "switch">
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch
|
||||||
|
v-model="scope.row.${column.javaField}"
|
||||||
|
<#if column.javaType == "Boolean">
|
||||||
|
:active-value="true"
|
||||||
|
:inactive-value="false"
|
||||||
|
<#elseif column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
:active-value="0"
|
||||||
|
:inactive-value="1"
|
||||||
|
<#else>
|
||||||
|
active-value="0"
|
||||||
|
inactive-value="1"
|
||||||
|
</#if>
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && column.htmlType == "datetime">
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ parseTime(scope.row.${column.javaField}, '{y}-{m}-{d}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && column.htmlType == "imageUpload">
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}Url" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<image-preview :src="scope.row.${column.javaField}Url" :width="50" :height="50"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && column.dictColumn>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}">
|
||||||
|
<template #default="scope">
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
<dict-tag :options="${column.dictType}" :value="scope.row.${column.javaField} ? scope.row.${column.javaField}.split(',') : []"/>
|
||||||
|
<#else>
|
||||||
|
<dict-tag :options="${column.dictType}" :value="scope.row.${column.javaField}"/>
|
||||||
|
</#if>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#elseif column.list && "" != column.javaField>
|
||||||
|
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" />
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#if enableStatus && !statusColumn.list>
|
||||||
|
<el-table-column label="${statusColumn.columnComment}" align="center" prop="${statusField}">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch
|
||||||
|
v-model="scope.row.${statusField}"
|
||||||
|
<#if statusColumn.javaType == "Boolean">
|
||||||
|
:active-value="true"
|
||||||
|
:inactive-value="false"
|
||||||
|
<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">
|
||||||
|
:active-value="0"
|
||||||
|
:inactive-value="1"
|
||||||
|
<#else>
|
||||||
|
active-value="0"
|
||||||
|
inactive-value="1"
|
||||||
|
</#if>
|
||||||
|
@change="handleStatusChange(scope.row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</#if>
|
||||||
|
<#if enableSort && !sortColumn.list>
|
||||||
|
<el-table-column label="${sortColumn.columnComment}" align="center" prop="${sortField}" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
<#if sortColumn.javaType == "LocalDateTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="scope.row.${sortField}"
|
||||||
|
type="datetime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
placeholder="选择${sortColumn.columnComment}"
|
||||||
|
@change="handleSortChange(scope.row)"
|
||||||
|
/>
|
||||||
|
<#else>
|
||||||
|
<el-input-number v-model="scope.row.${sortField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
|
||||||
|
</#if>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</#if>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="修改" placement="top">
|
||||||
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="删除" placement="top">
|
||||||
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
|
</el-card>
|
||||||
|
<!-- 添加或修改${functionName}对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
|
<el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
|
<#list columns as column>
|
||||||
|
<#if (column.insert || column.edit) && !column.pk>
|
||||||
|
<#if column.htmlType == "input">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input v-model="form.${column.javaField}" placeholder="请输入${column.columnLabel}" />
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "inputNumber">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input-number v-model="form.${column.javaField}" controls-position="right" />
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "imageUpload">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<image-upload v-model="form.${column.javaField}"/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "fileUpload">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<file-upload v-model="form.${column.javaField}"/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "editor">
|
||||||
|
<el-form-item label="${column.columnLabel}">
|
||||||
|
<editor v-model="form.${column.javaField}" :min-height="192"/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "select" && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="form.${column.javaField}" placeholder="请选择${column.columnLabel}">
|
||||||
|
<el-option
|
||||||
|
v-for="dict in ${column.dictType}"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
<#if column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
:value="parseInt(dict.value)"
|
||||||
|
<#else>
|
||||||
|
:value="dict.value"
|
||||||
|
</#if>
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "select" && !(column.dictType?has_content)>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-select v-model="form.${column.javaField}" placeholder="请选择${column.columnLabel}">
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-checkbox-group v-model="form.${column.javaField}">
|
||||||
|
<el-checkbox
|
||||||
|
v-for="dict in ${column.dictType}"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.value">
|
||||||
|
{{dict.label}}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "checkbox" && !(column.dictType?has_content)>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-checkbox-group v-model="form.${column.javaField}">
|
||||||
|
<el-checkbox>请选择字典生成</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "radio" && column.dictType?has_content>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-radio-group v-model="form.${column.javaField}">
|
||||||
|
<el-radio
|
||||||
|
v-for="dict in ${column.dictType}"
|
||||||
|
:key="dict.value"
|
||||||
|
<#if column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
:value="parseInt(dict.value)"
|
||||||
|
<#else>
|
||||||
|
:value="dict.value"
|
||||||
|
</#if>
|
||||||
|
>{{dict.label}}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "radio" && !(column.dictType?has_content)>
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-radio-group v-model="form.${column.javaField}">
|
||||||
|
<el-radio value="1">请选择字典生成</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "switch">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-switch
|
||||||
|
v-model="form.${column.javaField}"
|
||||||
|
<#if column.javaType == "Boolean">
|
||||||
|
:active-value="true"
|
||||||
|
:inactive-value="false"
|
||||||
|
<#elseif column.javaType == "Integer" || column.javaType == "Long">
|
||||||
|
:active-value="0"
|
||||||
|
:inactive-value="1"
|
||||||
|
<#else>
|
||||||
|
active-value="0"
|
||||||
|
inactive-value="1"
|
||||||
|
</#if>
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "datetime">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-date-picker clearable
|
||||||
|
v-model="form.${column.javaField}"
|
||||||
|
type="datetime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
placeholder="请选择${column.columnLabel}">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<#elseif column.htmlType == "textarea">
|
||||||
|
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
|
||||||
|
<el-input v-model="form.${column.javaField}" type="textarea" placeholder="请输入内容" />
|
||||||
|
</el-form-item>
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="${BusinessName}" lang="ts">
|
||||||
|
import {
|
||||||
|
add${BusinessName},
|
||||||
|
<#if enableStatus>
|
||||||
|
change${BusinessName}Status,
|
||||||
|
</#if>
|
||||||
|
del${BusinessName},
|
||||||
|
get${BusinessName},
|
||||||
|
list${BusinessName},
|
||||||
|
<#if enableSort>
|
||||||
|
update${BusinessName}Sort,
|
||||||
|
</#if>
|
||||||
|
update${BusinessName}
|
||||||
|
} from '@/api/${moduleName}/${businessName}';
|
||||||
|
import { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
||||||
|
import { useLoading } from '@/hooks/async/useLoading';
|
||||||
|
import { useFormDialog } from '@/hooks/dialog/useFormDialog';
|
||||||
|
<#if needAddDateRange>
|
||||||
|
import { useDateRangeQuery } from '@/hooks/form/useDateRangeQuery';
|
||||||
|
</#if>
|
||||||
|
import { useSearchReset } from '@/hooks/form/useSearchReset';
|
||||||
|
import { useSearchToggle } from '@/hooks/form/useSearchToggle';
|
||||||
|
import { useTableSelection } from '@/hooks/table/useTableSelection';
|
||||||
|
<#if needDict>
|
||||||
|
import { useDict } from '@/utils/dict';
|
||||||
|
</#if>
|
||||||
|
<#if needParseTime>
|
||||||
|
import { parseTime } from '@/utils/ruoyi';
|
||||||
|
</#if>
|
||||||
|
import modal from '@/plugins/modal';
|
||||||
|
<#if enableExport>
|
||||||
|
import { download as requestDownload } from '@/utils/request';
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if needDict>
|
||||||
|
const { ${dictsNoSymbol} } = toRefs<any>(useDict(${dicts}));
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if enableStatus>
|
||||||
|
const ${statusField}ActiveValue = <#if statusColumn.javaType == "Boolean">true<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">0<#else>'0'</#if>;
|
||||||
|
const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'</#if>;
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
const ${businessName}List = ref<${BusinessName}VO[]>([]);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const { loading, withLoading } = useLoading(true);
|
||||||
|
const { showSearch } = useSearchToggle();
|
||||||
|
const total = ref(0);
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN" && column.query>
|
||||||
|
const {
|
||||||
|
dateRange: dateRange${column.capJavaField},
|
||||||
|
applyDateRange: apply${column.capJavaField}DateRange,
|
||||||
|
resetDateRange: reset${column.capJavaField}DateRange
|
||||||
|
} = useDateRangeQuery('${column.capJavaField}');
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
const ${businessName}FormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
const initFormData: ${BusinessName}Form = {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.insert || column.edit>
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
${column.javaField}: [],
|
||||||
|
<#else>
|
||||||
|
${column.javaField}: undefined,
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
|
||||||
|
form: { ...initFormData },
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query>
|
||||||
|
<#if column.htmlType != "datetime" || column.queryType != "BETWEEN">
|
||||||
|
${column.javaField}: undefined,
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
params: {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query>
|
||||||
|
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
${column.javaField}: undefined,
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.insert || column.edit>
|
||||||
|
<#if column.required>
|
||||||
|
${column.javaField}: [
|
||||||
|
{ required: true, message: "${column.columnLabel}不能为空", trigger: <#if column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch" || column.htmlType == "inputNumber">"change"<#else>"blur"</#if> }
|
||||||
|
],
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
const { ids, single, multiple, handleSelectionChange } = useTableSelection<${BusinessName}VO>(item => item.${pkColumn.javaField});
|
||||||
|
const { dialog, resetForm: reset, openDialog, showDialog, closeDialog } = useFormDialog({
|
||||||
|
form,
|
||||||
|
formRef: ${businessName}FormRef,
|
||||||
|
initialFormData: initFormData
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 查询${functionName}列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
await withLoading(async () => {
|
||||||
|
<#if needAddDateRange>
|
||||||
|
let params = queryParams.value;
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN" && column.query>
|
||||||
|
params = apply${column.capJavaField}DateRange(params);
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
const res = await list${BusinessName}(params);
|
||||||
|
<#else>
|
||||||
|
const res = await list${BusinessName}(queryParams.value);
|
||||||
|
</#if>
|
||||||
|
${businessName}List.value = res.data?.rows;
|
||||||
|
total.value = res.data?.total;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
closeDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const { resetQuery } = useSearchReset({
|
||||||
|
queryFormRef,
|
||||||
|
queryParams,
|
||||||
|
pageNumKey: 'pageNum',
|
||||||
|
pageSizeKey: 'pageSize',
|
||||||
|
initialPageSize: 10,
|
||||||
|
resetExtras: () => {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN" && column.query>
|
||||||
|
reset${column.capJavaField}DateRange();
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
},
|
||||||
|
afterReset: () => {
|
||||||
|
handleQuery();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = () => {
|
||||||
|
openDialog('添加${functionName}');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = async (row?: Partial<${BusinessName}VO>) => {
|
||||||
|
reset();
|
||||||
|
const _${pkColumn.javaField} = row?.${pkColumn.javaField} || ids.value[0];
|
||||||
|
const res = await get${BusinessName}(_${pkColumn.javaField});
|
||||||
|
Object.assign(form.value, res.data);
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
form.value.${column.javaField} = form.value.${column.javaField}.split(",");
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
showDialog('修改${functionName}');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
${businessName}FormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true;
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
form.value.${column.javaField} = form.value.${column.javaField}.join(",");
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
if (form.value.${pkColumn.javaField}) {
|
||||||
|
await update${BusinessName}(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
} else {
|
||||||
|
await add${BusinessName}(form.value).finally(() => (buttonLoading.value = false));
|
||||||
|
}
|
||||||
|
modal.msgSuccess('操作成功');
|
||||||
|
closeDialog();
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (row?: Partial<${BusinessName}VO>) => {
|
||||||
|
const _${pkColumn.javaField}s = row?.${pkColumn.javaField} || ids.value;
|
||||||
|
await modal.confirm('是否确认删除${functionName}编号为"' + _${pkColumn.javaField}s + '"的数据项?');
|
||||||
|
await del${BusinessName}(_${pkColumn.javaField}s);
|
||||||
|
modal.msgSuccess('删除成功');
|
||||||
|
await getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
<#if enableExport>
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = () => {
|
||||||
|
requestDownload(
|
||||||
|
'${moduleName}/${businessName}/export',
|
||||||
|
{
|
||||||
|
...queryParams.value
|
||||||
|
},
|
||||||
|
`${businessName}_${r'${new Date().getTime()}'}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if enableStatus>
|
||||||
|
/** 状态修改 */
|
||||||
|
const handleStatusChange = async (row: Partial<${BusinessName}VO>) => {
|
||||||
|
const text = row.${statusField} === ${statusField}ActiveValue ? '启用' : '停用';
|
||||||
|
try {
|
||||||
|
await modal.confirm('确认要"' + text + '"吗?');
|
||||||
|
await change${BusinessName}Status(row.${pkColumn.javaField}, row.${statusField});
|
||||||
|
modal.msgSuccess(text + '成功');
|
||||||
|
} catch (err) {
|
||||||
|
row.${statusField} = row.${statusField} === ${statusField}ActiveValue ? ${statusField}InactiveValue : ${statusField}ActiveValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if enableSort>
|
||||||
|
/** 排序调整 */
|
||||||
|
const handleSortChange = async (row: Partial<${BusinessName}VO>) => {
|
||||||
|
try {
|
||||||
|
await update${BusinessName}Sort(row.${pkColumn.javaField}, row.${sortField});
|
||||||
|
modal.msgSuccess('排序更新成功');
|
||||||
|
} catch (err) {
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
@ -1,8 +1,6 @@
|
|||||||
import type { BaseEntity<#if !table.tree>, PageQuery</#if> } from '@/api/types';
|
|
||||||
|
|
||||||
export interface ${BusinessName}VO {
|
export interface ${BusinessName}VO {
|
||||||
<#list columns as column>
|
<#list columns as column>
|
||||||
<#if column.list || column.pk>
|
<#if column.list>
|
||||||
/**
|
/**
|
||||||
* ${column.columnComment}
|
* ${column.columnComment}
|
||||||
*/
|
*/
|
||||||
@ -11,7 +9,7 @@ export interface ${BusinessName}VO {
|
|||||||
/**
|
/**
|
||||||
* ${column.columnComment}Url
|
* ${column.columnComment}Url
|
||||||
*/
|
*/
|
||||||
${column.javaField}Url?: string;
|
${column.javaField}Url: string;
|
||||||
</#if>
|
</#if>
|
||||||
</#if>
|
</#if>
|
||||||
</#list>
|
</#list>
|
||||||
@ -19,22 +17,18 @@ export interface ${BusinessName}VO {
|
|||||||
/**
|
/**
|
||||||
* 子对象
|
* 子对象
|
||||||
*/
|
*/
|
||||||
children?: ${BusinessName}VO[];
|
children: ${BusinessName}VO[];
|
||||||
</#if>
|
</#if>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ${BusinessName}Form extends BaseEntity {
|
export interface ${BusinessName}Form extends BaseEntity {
|
||||||
<#list columns as column>
|
<#list columns as column>
|
||||||
<#if column.insert || column.edit || column.pk>
|
<#if column.insert || column.edit>
|
||||||
/**
|
/**
|
||||||
* ${column.columnComment}
|
* ${column.columnComment}
|
||||||
*/
|
*/
|
||||||
<#if column.htmlType == "checkbox">
|
|
||||||
${column.javaField}?: string | string[];
|
|
||||||
<#else>
|
|
||||||
${column.javaField}?: ${column.tsType};
|
${column.javaField}?: ${column.tsType};
|
||||||
</#if>
|
</#if>
|
||||||
</#if>
|
|
||||||
</#list>
|
</#list>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,5 +44,5 @@ export interface ${BusinessName}Query<#if !table.tree> extends PageQuery</#if> {
|
|||||||
/**
|
/**
|
||||||
* 日期范围参数
|
* 日期范围参数
|
||||||
*/
|
*/
|
||||||
params?: Record<string, unknown>;
|
params?: any;
|
||||||
}
|
}
|
||||||
|
|||||||
214
index.html
Normal file
214
index.html
Normal 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>
|
||||||
111
package.json
111
package.json
@ -1,65 +1,80 @@
|
|||||||
{
|
{
|
||||||
"name": "plus-ui-react",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
|
"name": "ruoyi-vue-plus",
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"private": true,
|
"description": "RuoYi-Vue-Plus后台管理系统",
|
||||||
"description": "React + Ant Design version of RuoYi-Vue-Plus UI",
|
"license": "MIT",
|
||||||
"type": "module",
|
"author": "LionLi",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitee.com/JavaLionLi/plus-ui.git"
|
||||||
|
},
|
||||||
"packageManager": "pnpm@10.34.5",
|
"packageManager": "pnpm@10.34.5",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "pnpm build:prod",
|
"build": "vite build --mode production",
|
||||||
"build:dev": "cross-env UMI_ENV=development BABEL_POLYFILL=none max build",
|
"build:dev": "vite build --mode development",
|
||||||
"build:prod": "cross-env UMI_ENV=production BABEL_POLYFILL=none max build",
|
"build:prod": "vite build --mode production",
|
||||||
"dev": "cross-env UMI_ENV=development MOCK=none BABEL_POLYFILL=none max dev",
|
"dev": "vite serve --mode development",
|
||||||
"fmt": "oxfmt .",
|
"fmt": "oxfmt .",
|
||||||
"lint": "oxlint src config vite.config.ts && cross-env UMI_ENV=development BABEL_POLYFILL=none max setup && tsc --noEmit",
|
"lint": "oxlint src",
|
||||||
"lint:fix": "oxlint --fix src config vite.config.ts",
|
"lint:fix": "oxlint --fix src",
|
||||||
"openapi": "max openapi",
|
"preview": "vite preview"
|
||||||
"preview": "max preview --port 8000",
|
|
||||||
"start": "cross-env UMI_ENV=development MOCK=none BABEL_POLYFILL=none max dev"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^6.3.2",
|
"@element-plus/icons-vue": "2.3.2",
|
||||||
"@ant-design/pro-components": "3.1.12-0",
|
"@highlightjs/vue-plugin": "2.1.2",
|
||||||
"@ant-design/x": "^2.8.0",
|
"@iconify/vue": "^5.0.1",
|
||||||
"@iconify/react": "^6.0.2",
|
"@noble/ciphers": "^2.4.0",
|
||||||
"@tanstack/react-query": "^5.101.4",
|
"@vueuse/core": "14.4.0",
|
||||||
"@umijs/max": "^4.6.82",
|
"@wangeditor-next/editor": "6.4.1",
|
||||||
"@wangeditor-next/editor": "^5.7.16",
|
"@wangeditor-next/editor-for-vue": "6.4.1",
|
||||||
"@wangeditor-next/editor-for-react": "^2.0.3",
|
"animate.css": "4.1.1",
|
||||||
"ahooks": "^3.9.7",
|
"await-to-js": "3.0.0",
|
||||||
"antd": "^6.5.2",
|
"axios": "1.20.0",
|
||||||
"antd-style": "^4.1.0",
|
"echarts": "6.1.0",
|
||||||
"axios": "1.18.1",
|
"element-plus": "2.14.5",
|
||||||
"browser-image-compression": "^2.0.2",
|
"highlight.js": "11.12.0",
|
||||||
"clsx": "^2.1.1",
|
"image-conversion": "2.1.1",
|
||||||
"crypto-js": "4.2.0",
|
|
||||||
"dayjs": "^1.11.21",
|
|
||||||
"echarts": "^6.1.0",
|
|
||||||
"echarts-for-react": "^3.0.6",
|
|
||||||
"jsencrypt": "3.5.4",
|
"jsencrypt": "3.5.4",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"react": "^19.2.8",
|
"pinia": "4.0.3",
|
||||||
"react-dom": "^19.2.8",
|
"vue": "3.5.42",
|
||||||
"react-easy-crop": "^6.2.3",
|
"vue-cropper": "1.1.4",
|
||||||
"react-json-view-lite": "^2.5.0",
|
"vue-i18n": "11.4.10",
|
||||||
"react-syntax-highlighter": "^16.1.1",
|
"vue-json-pretty": "2.6.0",
|
||||||
"screenfull": "^6.0.2",
|
"vue-router": "5.3.1",
|
||||||
"zustand": "^5.0.14"
|
"vue-types": "7.0.0",
|
||||||
|
"vxe-pc-ui": "4.18.9",
|
||||||
|
"vxe-table": "4.21.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/crypto-js": "4.2.2",
|
|
||||||
"@types/node": "^26.1.1",
|
"@types/node": "^26.1.1",
|
||||||
"@types/nprogress": "0.2.3",
|
"@types/nprogress": "0.2.3",
|
||||||
"@types/react": "^19.2.17",
|
"@unocss/preset-attributify": "66.10.1",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@unocss/preset-wind3": "66.10.1",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@vitejs/plugin-vue": "^6.0.8",
|
||||||
"@umijs/lint": "^4.6.82",
|
"@vue/compiler-sfc": "3.5.42",
|
||||||
"@umijs/max-plugin-openapi": "^2.0.3",
|
"autoprefixer": "10.5.5",
|
||||||
"cross-env": "^10.1.0",
|
"oxfmt": "^0.67.0",
|
||||||
"oxfmt": "^0.60.0",
|
"oxlint": "^1.82.0",
|
||||||
"oxlint": "^1.75.0",
|
"sass": "1.104.0",
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^6.0.3",
|
||||||
|
"unocss": "66.10.1",
|
||||||
|
"unplugin-auto-import": "21.1.0",
|
||||||
|
"unplugin-vue-components": "32.1.0",
|
||||||
|
"unplugin-vue-setup-extend-plus": "1.0.1",
|
||||||
|
"vite": "^8.2.2",
|
||||||
|
"vite-plugin-svg-icons-ng": "^1.9.3",
|
||||||
|
"vitest": "4.1.11",
|
||||||
|
"vue-tsc": "^3.3.11"
|
||||||
},
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"Chrome >= 87",
|
||||||
|
"Edge >= 88",
|
||||||
|
"Safari >= 14",
|
||||||
|
"Firefox >= 78"
|
||||||
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.19.0",
|
"node": ">=20.19.0",
|
||||||
"pnpm": ">=10.0.0"
|
"pnpm": ">=10.0.0"
|
||||||
|
|||||||
18483
pnpm-lock.yaml
generated
18483
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
10
pnpm-workspace.yaml
Normal file
10
pnpm-workspace.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
packages:
|
||||||
|
- '.'
|
||||||
|
|
||||||
|
allowBuilds:
|
||||||
|
'@parcel/watcher': true
|
||||||
|
es5-ext: true
|
||||||
|
esbuild: true
|
||||||
|
|
||||||
|
overrides:
|
||||||
|
esbuild: 0.28.1
|
||||||
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
258
public/ie.html
Normal file
258
public/ie.html
Normal file
File diff suppressed because one or more lines are too long
20
src/App.vue
Normal file
20
src/App.vue
Normal 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
src/animate.ts
Normal file
48
src/animate.ts
Normal 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
|
||||||
|
};
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import type { R } from '@/api/types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import request from '@/api/request';
|
import request from '@/utils/request';
|
||||||
import type { SnailOpenApiUser } from './types';
|
import type { SnailOpenApiUser } from './types';
|
||||||
|
|
||||||
export function registerCurrentSnailUser() {
|
export const registerCurrentSnailUser = (): AxiosPromise<SnailOpenApiUser> => {
|
||||||
return request<R<SnailOpenApiUser>>({
|
return request({
|
||||||
url: '/snail-ai/user/register',
|
url: '/snail-ai/user/register',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,41 +1,63 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { DemoForm, DemoQuery, DemoVO } from '@/api/demo/demo/types';
|
||||||
import request from '@/api/request';
|
import type { PageResult } from '@/api/types';
|
||||||
import type { DemoForm, DemoQuery, DemoVO } from './types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function listDemo(query?: DemoQuery) {
|
/**
|
||||||
return request<R<PageResult<DemoVO>>>({
|
* 查询测试单列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const listDemo = (query?: DemoQuery): AxiosPromise<PageResult<DemoVO>> => {
|
||||||
|
return request({
|
||||||
url: '/demo/demo/list',
|
url: '/demo/demo/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getDemo(id: string | number) {
|
/**
|
||||||
return request<R<DemoVO>>({
|
* 查询测试单详细
|
||||||
url: `/demo/demo/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getDemo = (id: string | number): AxiosPromise<DemoVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addDemo(data: DemoForm) {
|
/**
|
||||||
return request<R>({
|
* 新增测试单
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addDemo = (data: DemoForm) => {
|
||||||
|
return request({
|
||||||
url: '/demo/demo',
|
url: '/demo/demo',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateDemo(data: DemoForm) {
|
/**
|
||||||
return request<R>({
|
* 修改测试单
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateDemo = (data: DemoForm) => {
|
||||||
|
return request({
|
||||||
url: '/demo/demo',
|
url: '/demo/demo',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delDemo(id: string | number | Array<string | number>) {
|
/**
|
||||||
return request<R>({
|
* 删除测试单
|
||||||
url: `/demo/demo/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delDemo = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,27 +1,90 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
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 {
|
export interface DemoForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
id?: string | number;
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
deptId?: string | number;
|
deptId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
userId?: string | number;
|
userId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序号
|
||||||
|
*/
|
||||||
orderNum?: number;
|
orderNum?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key键
|
||||||
|
*/
|
||||||
testKey?: string;
|
testKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
value?: string;
|
value?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DemoQuery extends PageQuery {
|
export interface DemoQuery extends PageQuery {
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
deptId?: string | number;
|
deptId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
userId?: string | number;
|
userId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序号
|
||||||
|
*/
|
||||||
orderNum?: number;
|
orderNum?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key键
|
||||||
|
*/
|
||||||
testKey?: string;
|
testKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
value?: string;
|
value?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DemoVO {
|
|
||||||
id: string | number;
|
|
||||||
deptId: string | number;
|
|
||||||
userId: string | number;
|
|
||||||
orderNum: number;
|
|
||||||
testKey: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,41 +1,62 @@
|
|||||||
import type { R } from '@/api/types';
|
import type { TreeForm, TreeQuery, TreeVO } from '@/api/demo/tree/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import type { TreeForm, TreeQuery, TreeVO } from './types';
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function listTree(query?: TreeQuery) {
|
/**
|
||||||
return request<R<TreeVO[]>>({
|
* 查询测试树列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const listTree = (query?: TreeQuery): AxiosPromise<TreeVO[]> => {
|
||||||
|
return request({
|
||||||
url: '/demo/tree/list',
|
url: '/demo/tree/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getTree(id: string | number) {
|
/**
|
||||||
return request<R<TreeVO>>({
|
* 查询测试树详细
|
||||||
url: `/demo/tree/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getTree = (id: string | number): AxiosPromise<TreeVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/tree/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addTree(data: TreeForm) {
|
/**
|
||||||
return request<R>({
|
* 新增测试树
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addTree = (data: TreeForm) => {
|
||||||
|
return request({
|
||||||
url: '/demo/tree',
|
url: '/demo/tree',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateTree(data: TreeForm) {
|
/**
|
||||||
return request<R>({
|
* 修改测试树
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateTree = (data: TreeForm) => {
|
||||||
|
return request({
|
||||||
url: '/demo/tree',
|
url: '/demo/tree',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delTree(id: string | number | Array<string | number>) {
|
/**
|
||||||
return request<R>({
|
* 删除测试树
|
||||||
url: `/demo/tree/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delTree = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/tree/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,25 +1,80 @@
|
|||||||
import type { BaseEntity } from '@/api/types';
|
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 {
|
export interface TreeForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
id?: string | number;
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父id
|
||||||
|
*/
|
||||||
parentId?: string | number;
|
parentId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
deptId?: string | number;
|
deptId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
userId?: string | number;
|
userId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
treeName?: string;
|
treeName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TreeQuery {
|
export interface TreeQuery {
|
||||||
|
/**
|
||||||
|
* 父id
|
||||||
|
*/
|
||||||
parentId?: string | number;
|
parentId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
deptId?: string | number;
|
deptId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
userId?: string | number;
|
userId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
treeName?: string;
|
treeName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TreeVO {
|
|
||||||
id: string | number;
|
|
||||||
parentId: string | number;
|
|
||||||
deptId: string | number;
|
|
||||||
userId: string | number;
|
|
||||||
treeName: string;
|
|
||||||
children?: TreeVO[];
|
|
||||||
}
|
|
||||||
|
|||||||
126
src/api/login.ts
126
src/api/login.ts
@ -1,74 +1,106 @@
|
|||||||
import type { UserInfo } from '@/api/system/user/types';
|
import type { UserInfo } from '@/api/system/user/types';
|
||||||
import type { LoginParams, LoginResult, R, RegisterParams, VerifyCodeResult } from '@/api/types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import request from '@/api/request';
|
import { closePush } from '@/utils/push';
|
||||||
import { appEnv } from '@/utils/env';
|
import request from '@/utils/request';
|
||||||
|
import type { LoginData, LoginResult, VerifyCodeResult } from './types';
|
||||||
|
|
||||||
export function login(data: LoginParams) {
|
// pc端固定客户端授权id
|
||||||
return request<R<LoginResult>>({
|
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',
|
url: '/auth/login',
|
||||||
method: 'post',
|
|
||||||
headers: {
|
headers: {
|
||||||
isToken: false,
|
isToken: false,
|
||||||
isEncrypt: 'true',
|
isEncrypt: true,
|
||||||
repeatSubmit: false
|
repeatSubmit: false
|
||||||
},
|
},
|
||||||
data: {
|
method: 'post',
|
||||||
...data,
|
data: params
|
||||||
clientId: data.clientId || appEnv.clientId,
|
|
||||||
grantType: data.grantType || 'password'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注册方法
|
||||||
|
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() {
|
export function logout() {
|
||||||
return request<R>({
|
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',
|
url: '/auth/logout',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function register(data: RegisterParams) {
|
/**
|
||||||
return request<R>({
|
* 获取验证码
|
||||||
url: '/auth/register',
|
*/
|
||||||
method: 'post',
|
export function getCodeImg(): AxiosPromise<VerifyCodeResult> {
|
||||||
headers: {
|
return request({
|
||||||
isToken: false,
|
|
||||||
isEncrypt: 'true',
|
|
||||||
repeatSubmit: false
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
...data,
|
|
||||||
clientId: appEnv.clientId,
|
|
||||||
grantType: 'password'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function callback(data: LoginParams) {
|
|
||||||
return request<R<LoginResult>>({
|
|
||||||
url: '/auth/social/callback',
|
|
||||||
method: 'post',
|
|
||||||
data: {
|
|
||||||
...data,
|
|
||||||
clientId: appEnv.clientId,
|
|
||||||
grantType: 'social'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCodeImg() {
|
|
||||||
return request<R<VerifyCodeResult>>({
|
|
||||||
url: '/auth/code',
|
url: '/auth/code',
|
||||||
method: 'get',
|
|
||||||
headers: {
|
headers: {
|
||||||
isToken: false
|
isToken: false
|
||||||
},
|
},
|
||||||
|
method: 'get',
|
||||||
timeout: 20000
|
timeout: 20000
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInfo() {
|
/**
|
||||||
return request<R<UserInfo>>({
|
* 第三方登录
|
||||||
|
*/
|
||||||
|
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',
|
url: '/system/user/getInfo',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import type { BackendRoute, R } from '@/api/types';
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function getRouters() {
|
// 获取路由
|
||||||
return request<R<BackendRoute[]>>({
|
export function getRouters(): AxiosPromise<RouteRecordRaw[]> {
|
||||||
|
return request({
|
||||||
url: '/system/menu/getRouters',
|
url: '/system/menu/getRouters',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
|
|||||||
10
src/api/monitor/cache/index.ts
vendored
10
src/api/monitor/cache/index.ts
vendored
@ -1,10 +1,12 @@
|
|||||||
import type { R } from '@/api/types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import request from '@/api/request';
|
import request from '@/utils/request';
|
||||||
import type { CacheVO } from './types';
|
import type { CacheVO } from './types';
|
||||||
|
|
||||||
export function getCache() {
|
// 查询缓存详细
|
||||||
return request<R<CacheVO>>({
|
export function getCache(): AxiosPromise<CacheVO> {
|
||||||
|
return request({
|
||||||
url: '/monitor/cache',
|
url: '/monitor/cache',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
src/api/monitor/cache/types.ts
vendored
8
src/api/monitor/cache/types.ts
vendored
@ -1,5 +1,7 @@
|
|||||||
export interface CacheVO {
|
export interface CacheVO {
|
||||||
commandStats: Array<{ name: string; value: string | number }>;
|
commandStats: Array<{ name: string; value: string }>;
|
||||||
|
|
||||||
dbSize: number;
|
dbSize: number;
|
||||||
info: Record<string, string>;
|
|
||||||
|
info: { [key: string]: string };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,35 +1,36 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
import type { LoginInfoQuery, LoginInfoVO } from './types';
|
import type { LoginInfoQuery, LoginInfoVO } from './types';
|
||||||
|
|
||||||
export function listLoginInfo(query: LoginInfoQuery) {
|
// 查询登录日志列表
|
||||||
return request<R<PageResult<LoginInfoVO>>>({
|
export function list(query: LoginInfoQuery): AxiosPromise<PageResult<LoginInfoVO>> {
|
||||||
|
return request({
|
||||||
url: '/monitor/loginInfo/list',
|
url: '/monitor/loginInfo/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function list(query: LoginInfoQuery) {
|
// 删除登录日志
|
||||||
return listLoginInfo(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function delLoginInfo(infoId: string | number | Array<string | number>) {
|
export function delLoginInfo(infoId: string | number | Array<string | number>) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/monitor/loginInfo/${infoId}`,
|
url: '/monitor/loginInfo/' + infoId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unlockLoginInfo(userName: string | string[]) {
|
// 解锁用户登录状态
|
||||||
return request<R>({
|
export function unlockLoginInfo(userName: string | Array<string>) {
|
||||||
url: `/monitor/loginInfo/unlock/${userName}`,
|
return request({
|
||||||
|
url: '/monitor/loginInfo/unlock/' + userName,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清空登录日志
|
||||||
export function cleanLoginInfo() {
|
export function cleanLoginInfo() {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/monitor/loginInfo/clean',
|
url: '/monitor/loginInfo/clean',
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,24 +1,20 @@
|
|||||||
import type { PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface LoginInfoQuery extends Omit<PageQuery, 'isAsc'> {
|
|
||||||
ipaddr?: string;
|
|
||||||
userName?: string;
|
|
||||||
status?: string;
|
|
||||||
orderByColumn?: string;
|
|
||||||
isAsc?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoginInfoVO {
|
export interface LoginInfoVO {
|
||||||
infoId: string | number;
|
infoId: string | number;
|
||||||
tenantId?: string | number;
|
tenantId: string | number;
|
||||||
userName: string;
|
userName: string;
|
||||||
clientKey?: string;
|
|
||||||
deviceType?: string;
|
|
||||||
status: string;
|
status: string;
|
||||||
ipaddr?: string;
|
ipaddr: string;
|
||||||
loginLocation?: string;
|
loginLocation: string;
|
||||||
browser?: string;
|
browser: string;
|
||||||
os?: string;
|
os: string;
|
||||||
msg?: string;
|
msg: string;
|
||||||
loginTime?: string;
|
loginTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginInfoQuery extends PageQuery {
|
||||||
|
ipaddr: string;
|
||||||
|
userName: string;
|
||||||
|
status: string;
|
||||||
|
orderByColumn: string;
|
||||||
|
isAsc: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +1,37 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
import type { OnlineQuery, OnlineVO } from './types';
|
import type { OnlineQuery, OnlineVO } from './types';
|
||||||
|
|
||||||
export function listOnline(query: OnlineQuery) {
|
// 查询在线用户列表
|
||||||
return request<R<PageResult<OnlineVO>>>({
|
export function list(query: OnlineQuery): AxiosPromise<PageResult<OnlineVO>> {
|
||||||
|
return request({
|
||||||
url: '/monitor/online/list',
|
url: '/monitor/online/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function list(query: OnlineQuery) {
|
// 强退用户
|
||||||
return listOnline(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function forceLogout(tokenId: string) {
|
export function forceLogout(tokenId: string) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/monitor/online/${tokenId}`,
|
url: '/monitor/online/' + tokenId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取当前用户登录在线设备
|
||||||
export function getOnline() {
|
export function getOnline() {
|
||||||
return request<R<OnlineVO[] | PageResult<OnlineVO>>>({
|
return request({
|
||||||
url: '/monitor/online',
|
url: '/monitor/online',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除当前在线设备
|
||||||
export function delOnline(tokenId: string) {
|
export function delOnline(tokenId: string) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/monitor/online/myself/${tokenId}`,
|
url: '/monitor/online/myself/' + tokenId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface OnlineQuery extends PageQuery {
|
export interface OnlineQuery extends PageQuery {
|
||||||
ipaddr?: string;
|
ipaddr: string;
|
||||||
userName?: string;
|
userName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OnlineVO extends BaseEntity {
|
export interface OnlineVO extends BaseEntity {
|
||||||
tokenId: string;
|
tokenId: string;
|
||||||
deptName?: string;
|
deptName: string;
|
||||||
userName: string;
|
userName: string;
|
||||||
clientKey?: string;
|
ipaddr: string;
|
||||||
deviceType?: string;
|
loginLocation: string;
|
||||||
ipaddr?: string;
|
browser: string;
|
||||||
loginLocation?: string;
|
os: string;
|
||||||
browser?: string;
|
loginTime: number;
|
||||||
os?: string;
|
|
||||||
loginTime?: number | string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,28 +1,28 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
import type { OperLogQuery, OperLogVO } from './types';
|
import type { OperLogQuery, OperLogVO } from './types';
|
||||||
|
|
||||||
export function listOperlog(query: OperLogQuery) {
|
// 查询操作日志列表
|
||||||
return request<R<PageResult<OperLogVO>>>({
|
export function list(query: OperLogQuery): AxiosPromise<PageResult<OperLogVO>> {
|
||||||
|
return request({
|
||||||
url: '/monitor/operlog/list',
|
url: '/monitor/operlog/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function list(query: OperLogQuery) {
|
// 删除操作日志
|
||||||
return listOperlog(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function delOperlog(operId: string | number | Array<string | number>) {
|
export function delOperlog(operId: string | number | Array<string | number>) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/monitor/operlog/${operId}`,
|
url: '/monitor/operlog/' + operId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清空操作日志
|
||||||
export function cleanOperlog() {
|
export function cleanOperlog() {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/monitor/operlog/clean',
|
url: '/monitor/operlog/clean',
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,45 +1,71 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
export interface OperLogQuery extends PageQuery {
|
||||||
|
operIp: string;
|
||||||
export interface OperLogQuery extends Omit<PageQuery, 'isAsc'> {
|
title: string;
|
||||||
operIp?: string;
|
operName: string;
|
||||||
title?: string;
|
userId: string;
|
||||||
operName?: string;
|
deptId: string;
|
||||||
userId?: string;
|
clientKey: string;
|
||||||
deptId?: string;
|
deviceType: string;
|
||||||
clientKey?: string;
|
browser: string;
|
||||||
deviceType?: string;
|
os: string;
|
||||||
browser?: string;
|
businessType: string;
|
||||||
os?: string;
|
status: string;
|
||||||
businessType?: string;
|
orderByColumn: string;
|
||||||
status?: string;
|
isAsc: string;
|
||||||
orderByColumn?: string;
|
|
||||||
isAsc?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OperLogVO extends BaseEntity {
|
export interface OperLogVO extends BaseEntity {
|
||||||
operId: string | number;
|
operId: string | number;
|
||||||
tenantId?: string;
|
tenantId: string;
|
||||||
title?: string;
|
title: string;
|
||||||
businessType?: number | string;
|
businessType: number;
|
||||||
businessTypes?: number[];
|
businessTypes: number[] | undefined;
|
||||||
method?: string;
|
method: string;
|
||||||
requestMethod?: string;
|
requestMethod: string;
|
||||||
operatorType?: number;
|
operatorType: number;
|
||||||
operName?: string;
|
operName: string;
|
||||||
userId?: string | number;
|
userId: string | number;
|
||||||
deptId?: string | number;
|
deptId: string | number;
|
||||||
deptName?: string;
|
deptName: string;
|
||||||
clientKey?: string;
|
clientKey: string;
|
||||||
deviceType?: string;
|
deviceType: string;
|
||||||
browser?: string;
|
browser: string;
|
||||||
os?: string;
|
os: string;
|
||||||
operUrl?: string;
|
operUrl: string;
|
||||||
operIp?: string;
|
operIp: string;
|
||||||
operLocation?: string;
|
operLocation: string;
|
||||||
operParam?: string;
|
operParam: string;
|
||||||
jsonResult?: string;
|
jsonResult: string;
|
||||||
status?: number | string;
|
status: number;
|
||||||
errorMsg?: string;
|
errorMsg: string;
|
||||||
operTime?: string;
|
operTime: string;
|
||||||
costTime?: number;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,244 +0,0 @@
|
|||||||
import { history } from '@umijs/max';
|
|
||||||
import { message, Modal } from 'antd';
|
|
||||||
import axios, { type AxiosError, type AxiosRequestConfig } from 'axios';
|
|
||||||
import { useAppStore } from '@/stores/appStore';
|
|
||||||
import { useTagsViewStore } from '@/stores/tagsViewStore';
|
|
||||||
import { getToken, removeToken } from '@/utils/auth';
|
|
||||||
import { decryptBase64, decryptWithAes, encryptBase64, encryptWithAes, generateAesKey } from '@/utils/crypto';
|
|
||||||
import { appEnv } from '@/utils/env';
|
|
||||||
import { decrypt, encrypt } from '@/utils/jsencrypt';
|
|
||||||
import { tansParams } from '@/utils/ruoyi';
|
|
||||||
|
|
||||||
const SUCCESS = 200;
|
|
||||||
const WARN = 601;
|
|
||||||
const SERVER_ERROR = 500;
|
|
||||||
const encryptHeader = 'encrypt-key';
|
|
||||||
const repeatSubmitStorageKey = 'sessionObj';
|
|
||||||
const repeatSubmitInterval = 500;
|
|
||||||
|
|
||||||
export interface RequestConfig<D = unknown> extends AxiosRequestConfig<D> {
|
|
||||||
headers?: AxiosRequestConfig<D>['headers'] & {
|
|
||||||
isToken?: false;
|
|
||||||
isEncrypt?: 'true' | 'false' | boolean;
|
|
||||||
repeatSubmit?: false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isRelogin = { show: false };
|
|
||||||
|
|
||||||
type HandledRequestError = Error & { isHandled?: boolean };
|
|
||||||
|
|
||||||
function createHandledError(message: string) {
|
|
||||||
const error = new Error(message) as HandledRequestError;
|
|
||||||
error.isHandled = true;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHandledRequestError(error: unknown) {
|
|
||||||
return Boolean((error as { isHandled?: boolean } | undefined)?.isHandled);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function globalHeaders() {
|
|
||||||
return {
|
|
||||||
Authorization: `Bearer ${getToken() || ''}`,
|
|
||||||
clientid: appEnv.clientId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function showRequestError(content: string) {
|
|
||||||
message.error({ content, key: `request-error:${content}` });
|
|
||||||
}
|
|
||||||
|
|
||||||
function showReloginConfirm() {
|
|
||||||
if (isRelogin.show) return;
|
|
||||||
isRelogin.show = true;
|
|
||||||
Modal.confirm({
|
|
||||||
title: '系统提示',
|
|
||||||
content: '登录状态已过期,您可以继续留在该页面,或者重新登录',
|
|
||||||
okText: '重新登录',
|
|
||||||
cancelText: '取消',
|
|
||||||
onOk: () => {
|
|
||||||
isRelogin.show = false;
|
|
||||||
removeToken();
|
|
||||||
useTagsViewStore.getState().resetTags();
|
|
||||||
history.replace(
|
|
||||||
`/login?redirect=${encodeURIComponent(`${window.location.pathname || '/'}${window.location.search || ''}`)}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onCancel: () => {
|
|
||||||
isRelogin.show = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function stableDataString(data: unknown) {
|
|
||||||
if (data instanceof FormData) return '';
|
|
||||||
if (typeof data === 'string') return data;
|
|
||||||
if (typeof data === 'undefined' || data === null) return '';
|
|
||||||
if (typeof data === 'object') return JSON.stringify(data);
|
|
||||||
return String(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSessionSubmitRecord() {
|
|
||||||
try {
|
|
||||||
const text = sessionStorage.getItem(repeatSubmitStorageKey);
|
|
||||||
return text ? (JSON.parse(text) as { url?: string; data?: string; time?: number }) : undefined;
|
|
||||||
} catch {
|
|
||||||
sessionStorage.removeItem(repeatSubmitStorageKey);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSessionSubmitRecord(record: { url?: string; data?: string; time: number }) {
|
|
||||||
sessionStorage.setItem(repeatSubmitStorageKey, JSON.stringify(record));
|
|
||||||
}
|
|
||||||
|
|
||||||
const service = axios.create({
|
|
||||||
baseURL: appEnv.baseApi,
|
|
||||||
timeout: 50000,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json;charset=utf-8',
|
|
||||||
clientid: appEnv.clientId
|
|
||||||
},
|
|
||||||
transitional: {
|
|
||||||
clarifyTimeoutError: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
service.interceptors.request.use(config => {
|
|
||||||
config.headers.set('Content-Language', useAppStore.getState().appLocale);
|
|
||||||
|
|
||||||
const isToken = config.headers.get('isToken') === false;
|
|
||||||
const isEncrypt = config.headers.get('isEncrypt') === 'true' || config.headers.get('isEncrypt') === true;
|
|
||||||
const isRepeatSubmitDisabled = config.headers.get('repeatSubmit') === false;
|
|
||||||
|
|
||||||
if (getToken() && !isToken) {
|
|
||||||
config.headers.set('Authorization', `Bearer ${getToken()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.method === 'get' && config.params) {
|
|
||||||
let url = `${config.url}?${tansParams(config.params)}`;
|
|
||||||
url = url.slice(0, -1);
|
|
||||||
config.params = {};
|
|
||||||
config.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isRepeatSubmitDisabled && (config.method === 'post' || config.method === 'put')) {
|
|
||||||
const requestObj = {
|
|
||||||
url: config.url,
|
|
||||||
data: stableDataString(config.data),
|
|
||||||
time: Date.now()
|
|
||||||
};
|
|
||||||
const sessionObj = getSessionSubmitRecord();
|
|
||||||
if (
|
|
||||||
sessionObj &&
|
|
||||||
sessionObj.url === requestObj.url &&
|
|
||||||
sessionObj.data === requestObj.data &&
|
|
||||||
requestObj.time - (sessionObj.time || 0) < repeatSubmitInterval
|
|
||||||
) {
|
|
||||||
return Promise.reject(new Error('数据正在处理,请勿重复提交'));
|
|
||||||
}
|
|
||||||
setSessionSubmitRecord(requestObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appEnv.encryptEnabled && isEncrypt && (config.method === 'post' || config.method === 'put')) {
|
|
||||||
const aesKey = generateAesKey();
|
|
||||||
const encryptedKey = encrypt(encryptBase64(aesKey));
|
|
||||||
if (encryptedKey) {
|
|
||||||
config.headers.set(encryptHeader, encryptedKey);
|
|
||||||
}
|
|
||||||
const data = typeof config.data === 'object' ? JSON.stringify(config.data) : String(config.data ?? '');
|
|
||||||
config.data = encryptWithAes(data, aesKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.data instanceof FormData) {
|
|
||||||
config.headers.delete('Content-Type');
|
|
||||||
}
|
|
||||||
|
|
||||||
config.headers.delete('isToken');
|
|
||||||
config.headers.delete('isEncrypt');
|
|
||||||
config.headers.delete('repeatSubmit');
|
|
||||||
|
|
||||||
return config;
|
|
||||||
});
|
|
||||||
|
|
||||||
function normalizeErrorMessage(message?: string) {
|
|
||||||
if (!message) return undefined;
|
|
||||||
if (message === 'Network Error') return '后端接口连接异常';
|
|
||||||
if (message.includes('timeout')) return '系统接口请求超时';
|
|
||||||
if (message.includes('Request failed with status code')) return `系统接口${message.slice(-3)}异常`;
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function parseResponseErrorData(data: unknown): Promise<string | undefined> {
|
|
||||||
if (!data) return undefined;
|
|
||||||
if (data instanceof Blob) return parseResponseErrorData(await data.text());
|
|
||||||
if (data instanceof ArrayBuffer) return parseResponseErrorData(new TextDecoder().decode(data));
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
const text = data.trim();
|
|
||||||
if (!text) return undefined;
|
|
||||||
try {
|
|
||||||
return parseResponseErrorData(JSON.parse(text));
|
|
||||||
} catch {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeof data === 'object') {
|
|
||||||
const payload = data as { msg?: string; message?: string };
|
|
||||||
return payload.msg || payload.message;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getErrorMessage(error: AxiosError) {
|
|
||||||
const responseMessage = await parseResponseErrorData(error.response?.data);
|
|
||||||
return responseMessage || normalizeErrorMessage(error.message) || '系统未知错误';
|
|
||||||
}
|
|
||||||
|
|
||||||
service.interceptors.response.use(
|
|
||||||
response => {
|
|
||||||
const keyStr = response.headers[encryptHeader];
|
|
||||||
if (appEnv.encryptEnabled && keyStr) {
|
|
||||||
const base64Str = decrypt(keyStr);
|
|
||||||
if (base64Str) {
|
|
||||||
const aesKey = decryptBase64(base64Str);
|
|
||||||
response.data = JSON.parse(decryptWithAes(response.data, aesKey));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.request.responseType === 'blob' || response.request.responseType === 'arraybuffer') {
|
|
||||||
return response.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const code = response.data?.code || SUCCESS;
|
|
||||||
const msg = response.data?.msg || '系统未知错误';
|
|
||||||
|
|
||||||
if (code === 401) {
|
|
||||||
showReloginConfirm();
|
|
||||||
return Promise.reject(createHandledError('无效的会话,或者会话已过期,请重新登录。'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code === SERVER_ERROR || code === WARN || code !== SUCCESS) {
|
|
||||||
showRequestError(msg);
|
|
||||||
return Promise.reject(createHandledError(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.data;
|
|
||||||
},
|
|
||||||
async error => {
|
|
||||||
if (axios.isAxiosError(error) && error.response?.status === 401) {
|
|
||||||
showReloginConfirm();
|
|
||||||
return Promise.reject(createHandledError('无效的会话,或者会话已过期,请重新登录。'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const msg = axios.isAxiosError(error)
|
|
||||||
? await getErrorMessage(error)
|
|
||||||
: normalizeErrorMessage((error as Error | undefined)?.message) || '系统未知错误';
|
|
||||||
showRequestError(msg);
|
|
||||||
return Promise.reject(createHandledError(msg));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function request<T = unknown, D = unknown>(config: RequestConfig<D>): Promise<T> {
|
|
||||||
return service.request<T, T, D>(config);
|
|
||||||
}
|
|
||||||
@ -1,49 +1,81 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { ClientForm, ClientQuery, ClientVO } from '@/api/system/client/types';
|
||||||
import request from '@/api/request';
|
import type { PageResult } from '@/api/types';
|
||||||
import type { ClientForm, ClientQuery, ClientVO } from './types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function listClient(query?: ClientQuery) {
|
/**
|
||||||
return request<R<PageResult<ClientVO>>>({
|
* 查询客户端管理列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listClient = (query?: ClientQuery): AxiosPromise<PageResult<ClientVO>> => {
|
||||||
|
return request({
|
||||||
url: '/system/client/list',
|
url: '/system/client/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getClient(id: string | number) {
|
/**
|
||||||
return request<R<ClientVO>>({
|
* 查询客户端管理详细
|
||||||
url: `/system/client/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getClient = (id: string | number): AxiosPromise<ClientVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/client/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addClient(data: ClientForm) {
|
/**
|
||||||
return request<R>({
|
* 新增客户端管理
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addClient = (data: ClientForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/client',
|
url: '/system/client',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateClient(data: ClientForm) {
|
/**
|
||||||
return request<R>({
|
* 修改客户端管理
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateClient = (data: ClientForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/client',
|
url: '/system/client',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delClient(id: string | number | Array<string | number>) {
|
/**
|
||||||
return request<R>({
|
* 删除客户端管理
|
||||||
url: `/system/client/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delClient = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/client/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态修改
|
||||||
|
* @param clientId 客户端id
|
||||||
|
* @param status 状态
|
||||||
|
*/
|
||||||
export function changeStatus(clientId: string, status: string) {
|
export function changeStatus(clientId: string, status: string) {
|
||||||
return request<R>({
|
const data = {
|
||||||
|
clientId,
|
||||||
|
status
|
||||||
|
};
|
||||||
|
return request({
|
||||||
url: '/system/client/changeStatus',
|
url: '/system/client/changeStatus',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: { clientId, status }
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,46 +1,185 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
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 {
|
export interface ClientForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
id?: string | number;
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端id
|
||||||
|
*/
|
||||||
clientId?: string | number;
|
clientId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端key
|
||||||
|
*/
|
||||||
clientKey?: string;
|
clientKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端秘钥
|
||||||
|
*/
|
||||||
clientSecret?: string;
|
clientSecret?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权类型
|
||||||
|
*/
|
||||||
grantTypeList?: string[];
|
grantTypeList?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
deviceType?: string;
|
deviceType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许访问路径
|
||||||
|
*/
|
||||||
accessPath?: string;
|
accessPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许访问路径列表
|
||||||
|
*/
|
||||||
accessPathList?: string[];
|
accessPathList?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP白名单
|
||||||
|
*/
|
||||||
ipWhitelist?: string;
|
ipWhitelist?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP白名单列表
|
||||||
|
*/
|
||||||
ipWhitelistList?: string[];
|
ipWhitelistList?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token活跃超时时间
|
||||||
|
*/
|
||||||
activeTimeout?: number;
|
activeTimeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token固定超时
|
||||||
|
*/
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
status?: string;
|
status?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientQuery extends PageQuery {
|
export interface ClientQuery extends PageQuery {
|
||||||
|
/**
|
||||||
|
* 客户端id
|
||||||
|
*/
|
||||||
clientId?: string | number;
|
clientId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端key
|
||||||
|
*/
|
||||||
clientKey?: string;
|
clientKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端秘钥
|
||||||
|
*/
|
||||||
clientSecret?: string;
|
clientSecret?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权类型
|
||||||
|
*/
|
||||||
grantType?: string;
|
grantType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
deviceType?: string;
|
deviceType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许访问路径
|
||||||
|
*/
|
||||||
accessPath?: string;
|
accessPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP白名单
|
||||||
|
*/
|
||||||
ipWhitelist?: string;
|
ipWhitelist?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token活跃超时时间
|
||||||
|
*/
|
||||||
activeTimeout?: number;
|
activeTimeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token固定超时
|
||||||
|
*/
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
status?: string;
|
status?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientVO {
|
|
||||||
id: string | number;
|
|
||||||
clientId: string;
|
|
||||||
clientKey: string;
|
|
||||||
clientSecret: string;
|
|
||||||
grantTypeList?: string[];
|
|
||||||
deviceType?: string;
|
|
||||||
accessPath?: string;
|
|
||||||
accessPathList?: string[];
|
|
||||||
ipWhitelist?: string;
|
|
||||||
ipWhitelistList?: string[];
|
|
||||||
activeTimeout?: number;
|
|
||||||
timeout?: number;
|
|
||||||
status: string;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,47 +1,54 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
import type { ConfigForm, ConfigQuery, ConfigVO } from './types';
|
import type { ConfigForm, ConfigQuery, ConfigVO } from './types';
|
||||||
|
|
||||||
export function listConfig(query: ConfigQuery) {
|
// 查询参数列表
|
||||||
return request<R<PageResult<ConfigVO>>>({
|
export function listConfig(query: ConfigQuery): AxiosPromise<PageResult<ConfigVO>> {
|
||||||
|
return request({
|
||||||
url: '/system/config/list',
|
url: '/system/config/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfig(configId: string | number) {
|
// 查询参数详细
|
||||||
return request<R<ConfigVO>>({
|
export function getConfig(configId: string | number): AxiosPromise<ConfigVO> {
|
||||||
url: `/system/config/${configId}`,
|
return request({
|
||||||
|
url: '/system/config/' + configId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfigKey(configKey: string) {
|
// 根据参数键名查询参数值
|
||||||
return request<R<string>>({
|
export function getConfigKey(configKey: string): AxiosPromise<string> {
|
||||||
url: `/system/config/configKey/${configKey}`,
|
return request({
|
||||||
|
url: '/system/config/configKey/' + configKey,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增参数配置
|
||||||
export function addConfig(data: ConfigForm) {
|
export function addConfig(data: ConfigForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/config',
|
url: '/system/config',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改参数配置
|
||||||
export function updateConfig(data: ConfigForm) {
|
export function updateConfig(data: ConfigForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/config',
|
url: '/system/config',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateConfigByKey(key: string, value: unknown) {
|
// 修改参数配置
|
||||||
return request<R>({
|
export function updateConfigByKey(key: string, value: any) {
|
||||||
|
return request({
|
||||||
url: '/system/config/updateByKey',
|
url: '/system/config/updateByKey',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: {
|
data: {
|
||||||
@ -51,20 +58,18 @@ export function updateConfigByKey(key: string, value: unknown) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除参数配置
|
||||||
export function delConfig(configId: string | number | Array<string | number>) {
|
export function delConfig(configId: string | number | Array<string | number>) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/system/config/${configId}`,
|
url: '/system/config/' + configId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function refreshConfigCache() {
|
// 刷新参数缓存
|
||||||
return request<R>({
|
export function refreshCache() {
|
||||||
|
return request({
|
||||||
url: '/system/config/refreshCache',
|
url: '/system/config/refreshCache',
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function refreshCache() {
|
|
||||||
return refreshConfigCache();
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,24 +1,23 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface ConfigForm {
|
|
||||||
configId?: number | string;
|
|
||||||
configName?: string;
|
|
||||||
configKey?: string;
|
|
||||||
configValue?: string;
|
|
||||||
configType?: string;
|
|
||||||
remark?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ConfigQuery extends PageQuery {
|
|
||||||
configName?: string;
|
|
||||||
configKey?: string;
|
|
||||||
configType?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ConfigVO extends BaseEntity {
|
export interface ConfigVO extends BaseEntity {
|
||||||
configId: number | string;
|
configId: number | string;
|
||||||
configName: string;
|
configName: string;
|
||||||
configKey: string;
|
configKey: string;
|
||||||
configValue: string;
|
configValue: string;
|
||||||
configType: 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,55 +1,65 @@
|
|||||||
import type { R } from '@/api/types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import request from '@/api/request';
|
import request from '@/utils/request';
|
||||||
import type { DeptForm, DeptQuery, DeptVO } from './types';
|
import { type DeptForm, type DeptQuery, type DeptVO } from './types';
|
||||||
|
|
||||||
export function listDept(query?: DeptQuery) {
|
// 查询部门列表
|
||||||
return request<R<DeptVO[]>>({
|
export const listDept = (query?: DeptQuery) => {
|
||||||
|
return request({
|
||||||
url: '/system/dept/list',
|
url: '/system/dept/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function optionSelect(deptIds: Array<number | string>) {
|
/**
|
||||||
return request<R<DeptVO[]>>({
|
* 通过deptIds查询部门
|
||||||
url: `/system/dept/optionselect?deptIds=${deptIds}`,
|
* @param deptIds
|
||||||
|
*/
|
||||||
|
export const optionSelect = (deptIds: (number | string)[]): AxiosPromise<DeptVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/optionselect?deptIds=' + deptIds,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function listDeptExcludeChild(deptId: string | number) {
|
// 查询部门列表(排除节点)
|
||||||
return request<R<DeptVO[]>>({
|
export const listDeptExcludeChild = (deptId: string | number): AxiosPromise<DeptVO[]> => {
|
||||||
url: `/system/dept/list/exclude/${deptId}`,
|
return request({
|
||||||
|
url: '/system/dept/list/exclude/' + deptId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getDept(deptId: string | number) {
|
// 查询部门详细
|
||||||
return request<R<DeptVO>>({
|
export const getDept = (deptId: string | number): AxiosPromise<DeptVO> => {
|
||||||
url: `/system/dept/${deptId}`,
|
return request({
|
||||||
|
url: '/system/dept/' + deptId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addDept(data: DeptForm) {
|
// 新增部门
|
||||||
return request<R>({
|
export const addDept = (data: DeptForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/dept',
|
url: '/system/dept',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateDept(data: DeptForm) {
|
// 修改部门
|
||||||
return request<R>({
|
export const updateDept = (data: DeptForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/dept',
|
url: '/system/dept',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delDept(deptId: number | string) {
|
// 删除部门
|
||||||
return request<R>({
|
export const delDept = (deptId: number | string) => {
|
||||||
url: `/system/dept/${deptId}`,
|
return request({
|
||||||
|
url: '/system/dept/' + deptId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,5 +1,48 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
/**
|
||||||
|
* 部门查询参数
|
||||||
|
*/
|
||||||
|
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 {
|
export interface DeptForm {
|
||||||
parentName?: string;
|
parentName?: string;
|
||||||
parentId?: number | string;
|
parentId?: number | string;
|
||||||
@ -8,43 +51,10 @@ export interface DeptForm {
|
|||||||
deptName?: string;
|
deptName?: string;
|
||||||
deptCategory?: string;
|
deptCategory?: string;
|
||||||
orderNum?: number;
|
orderNum?: number;
|
||||||
leader?: string | number;
|
|
||||||
phone?: string;
|
|
||||||
email?: string;
|
|
||||||
status?: string;
|
|
||||||
delFlag?: string;
|
|
||||||
ancestors?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DeptQuery extends PageQuery {
|
|
||||||
deptName?: string;
|
|
||||||
deptCategory?: string;
|
|
||||||
status?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DeptTreeVO extends BaseEntity {
|
|
||||||
id: number | string;
|
|
||||||
label: string;
|
|
||||||
parentId: number | string;
|
|
||||||
weight: number;
|
|
||||||
children?: DeptTreeVO[];
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
leader?: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
delFlag?: string;
|
delFlag?: string;
|
||||||
ancestors?: string;
|
ancestors?: string;
|
||||||
menuId?: string | number;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,48 +1,54 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import type { DictData, DictDataForm, DictDataQuery } from './types';
|
import request from '@/utils/request';
|
||||||
|
import type { DictDataForm, DictDataQuery, DictDataVO } from './types';
|
||||||
export function getDicts(dictType: string) {
|
// 根据字典类型查询字典数据信息
|
||||||
return request<R<DictData[]>>({
|
export function getDicts(dictType: string): AxiosPromise<DictDataVO[]> {
|
||||||
url: `/system/dict/data/type/${dictType}`,
|
return request({
|
||||||
|
url: '/system/dict/data/type/' + dictType,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listData(query: DictDataQuery) {
|
// 查询字典数据列表
|
||||||
return request<R<PageResult<DictData>>>({
|
export function listData(query: DictDataQuery): AxiosPromise<PageResult<DictDataVO>> {
|
||||||
|
return request({
|
||||||
url: '/system/dict/data/list',
|
url: '/system/dict/data/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getData(dictCode: string | number) {
|
// 查询字典数据详细
|
||||||
return request<R<DictData>>({
|
export function getData(dictCode: string | number): AxiosPromise<DictDataVO> {
|
||||||
url: `/system/dict/data/${dictCode}`,
|
return request({
|
||||||
|
url: '/system/dict/data/' + dictCode,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增字典数据
|
||||||
export function addData(data: DictDataForm) {
|
export function addData(data: DictDataForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/dict/data',
|
url: '/system/dict/data',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改字典数据
|
||||||
export function updateData(data: DictDataForm) {
|
export function updateData(data: DictDataForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/dict/data',
|
url: '/system/dict/data',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除字典数据
|
||||||
export function delData(dictCode: string | number | Array<string | number>) {
|
export function delData(dictCode: string | number | Array<string | number>) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/system/dict/data/${dictCode}`,
|
url: '/system/dict/data/' + dictCode,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,32 +1,26 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
export interface DictDataQuery extends PageQuery {
|
||||||
|
dictName: string;
|
||||||
export interface DictData extends BaseEntity {
|
|
||||||
dictCode: string | number;
|
|
||||||
dictSort: number;
|
|
||||||
dictLabel: string;
|
|
||||||
dictValue: string;
|
|
||||||
dictType: string;
|
dictType: string;
|
||||||
cssClass?: string;
|
dictLabel: string;
|
||||||
listClass?: string;
|
|
||||||
isDefault?: string;
|
|
||||||
status: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DictDataVO = DictData;
|
export interface DictDataVO extends BaseEntity {
|
||||||
|
dictCode: string;
|
||||||
|
dictLabel: string;
|
||||||
|
dictValue: string;
|
||||||
|
cssClass: string;
|
||||||
|
listClass: ElTagType;
|
||||||
|
dictSort: number;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DictDataForm {
|
export interface DictDataForm {
|
||||||
dictType?: string;
|
dictType?: string;
|
||||||
dictCode?: string | number;
|
dictCode: string | undefined;
|
||||||
dictLabel?: string;
|
dictLabel: string;
|
||||||
dictValue?: string;
|
dictValue: string;
|
||||||
cssClass?: string;
|
cssClass: string;
|
||||||
listClass?: string;
|
listClass: ElTagType;
|
||||||
dictSort?: number;
|
dictSort: number;
|
||||||
remark?: string;
|
remark: string;
|
||||||
}
|
|
||||||
|
|
||||||
export interface DictDataQuery extends PageQuery {
|
|
||||||
dictName?: string;
|
|
||||||
dictType?: string;
|
|
||||||
dictLabel?: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,54 +1,62 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
import type { DictTypeForm, DictTypeQuery, DictTypeVO } from './types';
|
import type { DictTypeForm, DictTypeQuery, DictTypeVO } from './types';
|
||||||
|
|
||||||
export function listType(query: DictTypeQuery) {
|
// 查询字典类型列表
|
||||||
return request<R<PageResult<DictTypeVO>>>({
|
export function listType(query: DictTypeQuery): AxiosPromise<PageResult<DictTypeVO>> {
|
||||||
|
return request({
|
||||||
url: '/system/dict/type/list',
|
url: '/system/dict/type/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getType(dictId: number | string) {
|
// 查询字典类型详细
|
||||||
return request<R<DictTypeVO>>({
|
export function getType(dictId: number | string): AxiosPromise<DictTypeVO> {
|
||||||
url: `/system/dict/type/${dictId}`,
|
return request({
|
||||||
|
url: '/system/dict/type/' + dictId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增字典类型
|
||||||
export function addType(data: DictTypeForm) {
|
export function addType(data: DictTypeForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/dict/type',
|
url: '/system/dict/type',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改字典类型
|
||||||
export function updateType(data: DictTypeForm) {
|
export function updateType(data: DictTypeForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/dict/type',
|
url: '/system/dict/type',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除字典类型
|
||||||
export function delType(dictId: string | number | Array<string | number>) {
|
export function delType(dictId: string | number | Array<string | number>) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/system/dict/type/${dictId}`,
|
url: '/system/dict/type/' + dictId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新字典缓存
|
||||||
export function refreshCache() {
|
export function refreshCache() {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/dict/type/refreshCache',
|
url: '/system/dict/type/refreshCache',
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function optionselect() {
|
// 获取字典选择框列表
|
||||||
return request<R<DictTypeVO[]>>({
|
export function optionselect(): AxiosPromise<DictTypeVO[]> {
|
||||||
|
return request({
|
||||||
url: '/system/dict/type/optionselect',
|
url: '/system/dict/type/optionselect',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,19 +1,18 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface DictTypeForm {
|
|
||||||
dictId?: number | string;
|
|
||||||
dictName?: string;
|
|
||||||
dictType?: string;
|
|
||||||
remark?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DictTypeQuery extends PageQuery {
|
|
||||||
dictName?: string;
|
|
||||||
dictType?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DictTypeVO extends BaseEntity {
|
export interface DictTypeVO extends BaseEntity {
|
||||||
dictId: number | string;
|
dictId: number | string;
|
||||||
dictName: string;
|
dictName: string;
|
||||||
dictType: 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,63 +1,70 @@
|
|||||||
import type { RoleMenuTree } from '@/api/system/role/types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import type { R } from '@/api/types';
|
import request from '@/utils/request';
|
||||||
import request from '@/api/request';
|
import type { MenuForm, MenuQuery, MenuTreeOption, MenuVO, RoleMenuTree } from './types';
|
||||||
import type { MenuForm, MenuQuery, MenuTreeOption, MenuVO } from './types';
|
|
||||||
|
|
||||||
export function listMenu(query?: MenuQuery) {
|
// 查询菜单列表
|
||||||
return request<R<MenuVO[]>>({
|
export const listMenu = (query?: MenuQuery): AxiosPromise<MenuVO[]> => {
|
||||||
|
return request({
|
||||||
url: '/system/menu/list',
|
url: '/system/menu/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getMenu(menuId: string | number) {
|
// 查询菜单详细
|
||||||
return request<R<MenuVO>>({
|
export const getMenu = (menuId: string | number): AxiosPromise<MenuVO> => {
|
||||||
url: `/system/menu/${menuId}`,
|
return request({
|
||||||
|
url: '/system/menu/' + menuId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function treeselect() {
|
// 查询菜单下拉树结构
|
||||||
return request<R<MenuTreeOption[]>>({
|
export const treeselect = (): AxiosPromise<MenuTreeOption[]> => {
|
||||||
|
return request({
|
||||||
url: '/system/menu/treeselect',
|
url: '/system/menu/treeselect',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function roleMenuTreeselect(roleId: string | number) {
|
// 根据角色ID查询菜单下拉树结构
|
||||||
return request<R<RoleMenuTree>>({
|
export const roleMenuTreeselect = (roleId: string | number): AxiosPromise<RoleMenuTree> => {
|
||||||
url: `/system/menu/roleMenuTreeselect/${roleId}`,
|
return request({
|
||||||
|
url: '/system/menu/roleMenuTreeselect/' + roleId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addMenu(data: MenuForm) {
|
// 新增菜单
|
||||||
return request<R>({
|
export const addMenu = (data: MenuForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/menu',
|
url: '/system/menu',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateMenu(data: MenuForm) {
|
// 修改菜单
|
||||||
return request<R>({
|
export const updateMenu = (data: MenuForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/menu',
|
url: '/system/menu',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delMenu(menuId: string | number) {
|
// 删除菜单
|
||||||
return request<R>({
|
export const delMenu = (menuId: string | number) => {
|
||||||
url: `/system/menu/${menuId}`,
|
return request({
|
||||||
|
url: '/system/menu/' + menuId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function cascadeDelMenu(menuIds: Array<string | number>) {
|
// 级联删除菜单
|
||||||
return request<R>({
|
export const cascadeDelMenu = (menuIds: Array<string | number>) => {
|
||||||
url: `/system/menu/cascade/${menuIds}`,
|
return request({
|
||||||
|
url: '/system/menu/cascade/' + menuIds,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,63 +1,89 @@
|
|||||||
import type { BaseEntity } from '@/api/types';
|
import type { MenuTypeEnum } from '@/enums/MenuTypeEnum';
|
||||||
|
|
||||||
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?: 'M' | 'C' | 'F' | string;
|
|
||||||
visible?: string;
|
|
||||||
status?: string;
|
|
||||||
icon?: string | null;
|
|
||||||
activeMenu?: string;
|
|
||||||
ext?: string;
|
|
||||||
remark?: string;
|
|
||||||
query?: string;
|
|
||||||
perms?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MenuQuery {
|
|
||||||
keywords?: string;
|
|
||||||
menuName?: string;
|
|
||||||
status?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单树形结构类型
|
||||||
|
*/
|
||||||
export interface MenuTreeOption {
|
export interface MenuTreeOption {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
label: string;
|
label: string;
|
||||||
parentId: string | number;
|
parentId: string | number;
|
||||||
weight: number;
|
weight: number;
|
||||||
menuType?: 'M' | 'C' | 'F' | string;
|
menuType?: MenuTypeEnum | string;
|
||||||
visible?: string;
|
visible?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
children?: MenuTreeOption[];
|
children?: MenuTreeOption[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MenuVO extends BaseEntity {
|
export interface RoleMenuTree {
|
||||||
parentName?: string;
|
menus: MenuTreeOption[];
|
||||||
parentId: string | number;
|
checkedKeys: Array<string | number>;
|
||||||
children?: MenuVO[];
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色菜单分配中的按钮节点类型
|
||||||
|
*/
|
||||||
|
export interface RoleMenuButtonOption {
|
||||||
menuId: string | number;
|
menuId: string | number;
|
||||||
menuName: string;
|
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;
|
orderNum: number;
|
||||||
path: string;
|
path: string;
|
||||||
component?: string;
|
component?: string;
|
||||||
queryParam?: string;
|
queryParam?: string;
|
||||||
isFrame?: string;
|
isFrame?: string;
|
||||||
isCache?: string;
|
isCache?: string;
|
||||||
menuType: 'M' | 'C' | 'F' | string;
|
menuType?: MenuTypeEnum;
|
||||||
visible?: string;
|
visible?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
icon?: string | null;
|
icon?: string;
|
||||||
activeMenu?: string;
|
activeMenu?: string;
|
||||||
ext?: string;
|
ext?: string;
|
||||||
|
remark?: string;
|
||||||
|
query?: string;
|
||||||
perms?: string;
|
perms?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import type { R } from '@/api/types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import request from '@/api/request';
|
import request from '@/utils/request';
|
||||||
import type { MessageBoxVO } from './types';
|
import type { MessageBoxVO } from './types';
|
||||||
|
|
||||||
export function getMessageBox() {
|
export function getMessageBox(): AxiosPromise<MessageBoxVO> {
|
||||||
return request<R<MessageBoxVO>>({
|
return request({
|
||||||
url: '/resource/message/box',
|
url: '/resource/message/box',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import type { BaseEntity } from '@/api/types';
|
|
||||||
|
|
||||||
export interface MessageVO extends BaseEntity {
|
export interface MessageVO extends BaseEntity {
|
||||||
messageId: number | string;
|
messageId: number | string;
|
||||||
category: string;
|
category: string;
|
||||||
@ -8,7 +6,7 @@ export interface MessageVO extends BaseEntity {
|
|||||||
title: string;
|
title: string;
|
||||||
message: string;
|
message: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
data?: Record<string, unknown> | null;
|
data?: Record<string, any> | null;
|
||||||
path?: string;
|
path?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,41 +1,46 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
import type { NoticeForm, NoticeQuery, NoticeVO } from './types';
|
import type { NoticeForm, NoticeQuery, NoticeVO } from './types';
|
||||||
|
// 查询公告列表
|
||||||
export function listNotice(query: NoticeQuery) {
|
export function listNotice(query: NoticeQuery): AxiosPromise<PageResult<NoticeVO>> {
|
||||||
return request<R<PageResult<NoticeVO>>>({
|
return request({
|
||||||
url: '/system/notice/list',
|
url: '/system/notice/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNotice(noticeId: string | number) {
|
// 查询公告详细
|
||||||
return request<R<NoticeVO>>({
|
export function getNotice(noticeId: string | number): AxiosPromise<NoticeVO> {
|
||||||
url: `/system/notice/${noticeId}`,
|
return request({
|
||||||
|
url: '/system/notice/' + noticeId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增公告
|
||||||
export function addNotice(data: NoticeForm) {
|
export function addNotice(data: NoticeForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/notice',
|
url: '/system/notice',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改公告
|
||||||
export function updateNotice(data: NoticeForm) {
|
export function updateNotice(data: NoticeForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/notice',
|
url: '/system/notice',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除公告
|
||||||
export function delNotice(noticeId: string | number | Array<string | number>) {
|
export function delNotice(noticeId: string | number | Array<string | number>) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/system/notice/${noticeId}`,
|
url: '/system/notice/' + noticeId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,27 +1,26 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface NoticeForm {
|
|
||||||
noticeId?: number | string;
|
|
||||||
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 NoticeVO extends BaseEntity {
|
export interface NoticeVO extends BaseEntity {
|
||||||
noticeId: number | string;
|
noticeId: number;
|
||||||
noticeTitle: string;
|
noticeTitle: string;
|
||||||
noticeType: string;
|
noticeType: string;
|
||||||
noticeContent: string;
|
noticeContent: string;
|
||||||
status: string;
|
status: string;
|
||||||
createByName?: 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,45 +1,38 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import type { OssQuery, OssUploadResult, OssVO } from './types';
|
import request from '@/utils/request';
|
||||||
|
import type { OssQuery, OssUploadVO, OssVO } from './types';
|
||||||
|
|
||||||
export function listOss(query: OssQuery) {
|
// 查询OSS对象存储列表
|
||||||
return request<R<PageResult<OssVO>>>({
|
export function listOss(query: OssQuery): AxiosPromise<PageResult<OssVO>> {
|
||||||
|
return request({
|
||||||
url: '/resource/oss/list',
|
url: '/resource/oss/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listOssByIds(ossId: string | number) {
|
// 查询OSS对象基于id串
|
||||||
return request<R<OssVO[]>>({
|
export function listByIds(ossId: string | number): AxiosPromise<OssVO[]> {
|
||||||
url: `/resource/oss/listByIds/${ossId}`,
|
return request({
|
||||||
|
url: '/resource/oss/listByIds/' + ossId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listByIds(ossId: string | number) {
|
// 上传OSS对象存储
|
||||||
return listOssByIds(ossId);
|
export function uploadOss(data: FormData): AxiosPromise<OssUploadVO> {
|
||||||
}
|
return request({
|
||||||
|
|
||||||
export function uploadOss(data: FormData) {
|
|
||||||
return request<R<OssUploadResult>>({
|
|
||||||
url: '/resource/oss/upload',
|
url: '/resource/oss/upload',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除OSS对象存储
|
||||||
export function delOss(ossId: string | number | Array<string | number>) {
|
export function delOss(ossId: string | number | Array<string | number>) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/resource/oss/${ossId}`,
|
url: '/resource/oss/' + ossId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadOss(ossId: string | number) {
|
|
||||||
return request<Blob>({
|
|
||||||
url: `/resource/oss/download/${ossId}`,
|
|
||||||
method: 'get',
|
|
||||||
responseType: 'blob'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,27 +1,42 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface OssQuery extends Omit<PageQuery, 'isAsc'> {
|
|
||||||
fileName?: string;
|
|
||||||
originalName?: string;
|
|
||||||
fileSuffix?: string;
|
|
||||||
createTime?: string;
|
|
||||||
service?: string;
|
|
||||||
orderByColumn?: string;
|
|
||||||
isAsc?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OssUploadResult {
|
|
||||||
url?: string;
|
|
||||||
fileName?: string;
|
|
||||||
ossId?: string | number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OssVO extends BaseEntity {
|
export interface OssVO extends BaseEntity {
|
||||||
ossId: string | number;
|
ossId: string | number;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
originalName: string;
|
originalName: string;
|
||||||
fileSuffix: string;
|
fileSuffix: string;
|
||||||
url: string;
|
url: string;
|
||||||
createByName?: string;
|
createByName: string;
|
||||||
service?: 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,49 +1,61 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
import type { OssConfigForm, OssConfigQuery, OssConfigVO } from './types';
|
import type { OssConfigForm, OssConfigQuery, OssConfigVO } from './types';
|
||||||
|
|
||||||
export function listOssConfig(query: OssConfigQuery) {
|
// 查询对象存储配置列表
|
||||||
return request<R<PageResult<OssConfigVO>>>({
|
export function listOssConfig(query: OssConfigQuery): AxiosPromise<PageResult<OssConfigVO>> {
|
||||||
|
return request({
|
||||||
url: '/resource/oss/config/list',
|
url: '/resource/oss/config/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOssConfig(ossConfigId: string | number) {
|
// 查询对象存储配置详细
|
||||||
return request<R<OssConfigVO>>({
|
export function getOssConfig(ossConfigId: string | number): AxiosPromise<OssConfigVO> {
|
||||||
url: `/resource/oss/config/${ossConfigId}`,
|
return request({
|
||||||
|
url: '/resource/oss/config/' + ossConfigId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增对象存储配置
|
||||||
export function addOssConfig(data: OssConfigForm) {
|
export function addOssConfig(data: OssConfigForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/resource/oss/config',
|
url: '/resource/oss/config',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改对象存储配置
|
||||||
export function updateOssConfig(data: OssConfigForm) {
|
export function updateOssConfig(data: OssConfigForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/resource/oss/config',
|
url: '/resource/oss/config',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除对象存储配置
|
||||||
export function delOssConfig(ossConfigId: string | number | Array<string | number>) {
|
export function delOssConfig(ossConfigId: string | number | Array<string | number>) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/resource/oss/config/${ossConfigId}`,
|
url: '/resource/oss/config/' + ossConfigId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 对象存储状态修改
|
||||||
export function changeOssConfigStatus(ossConfigId: string | number, status: string, configKey: string) {
|
export function changeOssConfigStatus(ossConfigId: string | number, status: string, configKey: string) {
|
||||||
return request<R>({
|
const data = {
|
||||||
|
ossConfigId,
|
||||||
|
status,
|
||||||
|
configKey
|
||||||
|
};
|
||||||
|
return request({
|
||||||
url: '/resource/oss/config/changeStatus',
|
url: '/resource/oss/config/changeStatus',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: { ossConfigId, status, configKey }
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,39 +1,38 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface OssConfigForm {
|
|
||||||
ossConfigId?: string | number;
|
|
||||||
configKey?: string;
|
|
||||||
accessKey?: string;
|
|
||||||
secretKey?: string;
|
|
||||||
bucketName?: string;
|
|
||||||
prefix?: string;
|
|
||||||
endpoint?: string;
|
|
||||||
domainUrl?: string;
|
|
||||||
isHttps?: string;
|
|
||||||
accessPolicy?: string;
|
|
||||||
region?: string;
|
|
||||||
status?: string;
|
|
||||||
remark?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OssConfigQuery extends PageQuery {
|
|
||||||
configKey?: string;
|
|
||||||
bucketName?: string;
|
|
||||||
status?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OssConfigVO extends BaseEntity {
|
export interface OssConfigVO extends BaseEntity {
|
||||||
ossConfigId: number | string;
|
ossConfigId: number | string;
|
||||||
configKey: string;
|
configKey: string;
|
||||||
accessKey: string;
|
accessKey: string;
|
||||||
secretKey: string;
|
secretKey: string;
|
||||||
bucketName: string;
|
bucketName: string;
|
||||||
prefix?: string;
|
prefix: string;
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
domainUrl?: string;
|
domainUrl: string;
|
||||||
isHttps: string;
|
isHttps: string;
|
||||||
region?: string;
|
region: string;
|
||||||
status: string;
|
status: string;
|
||||||
ext1?: string;
|
ext1: string;
|
||||||
|
remark: string;
|
||||||
accessPolicy: 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;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,64 +1,70 @@
|
|||||||
import type { DeptTreeVO } from '@/api/system/dept/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import type { PageResult, R } from '@/api/types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import request from '@/api/request';
|
import request from '@/utils/request';
|
||||||
|
import type { DeptTreeVO } from '../dept/types';
|
||||||
import type { PostForm, PostQuery, PostVO } from './types';
|
import type { PostForm, PostQuery, PostVO } from './types';
|
||||||
|
|
||||||
export function listPost(query: PostQuery) {
|
// 查询岗位列表
|
||||||
return request<R<PageResult<PostVO>>>({
|
export function listPost(query: PostQuery): AxiosPromise<PageResult<PostVO>> {
|
||||||
|
return request({
|
||||||
url: '/system/post/list',
|
url: '/system/post/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPost(postId: string | number) {
|
// 查询岗位详细
|
||||||
return request<R<PostVO>>({
|
export function getPost(postId: string | number): AxiosPromise<PostVO> {
|
||||||
url: `/system/post/${postId}`,
|
return request({
|
||||||
|
url: '/system/post/' + postId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function optionSelect(deptId?: number | string, postIds?: Array<number | string>) {
|
// 获取岗位选择框列表
|
||||||
return request<R<PostVO[]>>({
|
export function optionselect(deptId?: number | string, postIds?: (number | string)[]): AxiosPromise<PostVO[]> {
|
||||||
|
return request({
|
||||||
url: '/system/post/optionselect',
|
url: '/system/post/optionselect',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: {
|
params: {
|
||||||
postIds,
|
postIds: postIds,
|
||||||
deptId
|
deptId: deptId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增岗位
|
||||||
export function addPost(data: PostForm) {
|
export function addPost(data: PostForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/post',
|
url: '/system/post',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改岗位
|
||||||
export function updatePost(data: PostForm) {
|
export function updatePost(data: PostForm) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/system/post',
|
url: '/system/post',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function delPost(postId: string | number | Array<string | number>) {
|
// 删除岗位
|
||||||
return request<R>({
|
export function delPost(postId: string | number | (string | number)[]) {
|
||||||
url: `/system/post/${postId}`,
|
return request({
|
||||||
|
url: '/system/post/' + postId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function postDeptTreeSelect() {
|
/**
|
||||||
return request<R<DeptTreeVO[]>>({
|
* 查询部门下拉树结构
|
||||||
|
*/
|
||||||
|
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
|
||||||
|
return request({
|
||||||
url: '/system/post/deptTree',
|
url: '/system/post/deptTree',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function deptTreeSelect() {
|
|
||||||
return postDeptTreeSelect();
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,25 +1,3 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface PostForm {
|
|
||||||
postId?: number | string;
|
|
||||||
deptId?: number | string;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PostVO extends BaseEntity {
|
export interface PostVO extends BaseEntity {
|
||||||
postId: number | string;
|
postId: number | string;
|
||||||
deptId: number | string;
|
deptId: number | string;
|
||||||
@ -29,4 +7,25 @@ export interface PostVO extends BaseEntity {
|
|||||||
deptName: string;
|
deptName: string;
|
||||||
postSort: number;
|
postSort: number;
|
||||||
status: string;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,115 +1,160 @@
|
|||||||
import type { UserQuery, UserVO } from '@/api/system/user/types';
|
import type { UserQuery, UserVO } from '@/api/system/user/types';
|
||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import type { RoleDeptTree, RoleForm, RoleQuery, RoleVO } from './types';
|
import request from '@/utils/request';
|
||||||
|
import type { RoleDeptTree, RoleQuery, RoleVO } from './types';
|
||||||
|
|
||||||
export function listRole(query: RoleQuery) {
|
export const listRole = (query: RoleQuery): AxiosPromise<PageResult<RoleVO>> => {
|
||||||
return request<R<PageResult<RoleVO>>>({
|
return request({
|
||||||
url: '/system/role/list',
|
url: '/system/role/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function optionSelect(roleIds: Array<number | string>) {
|
/**
|
||||||
return request<R<RoleVO[]>>({
|
* 通过roleIds查询角色
|
||||||
url: `/system/role/optionselect?roleIds=${roleIds}`,
|
* @param roleIds
|
||||||
|
*/
|
||||||
|
export const optionSelect = (roleIds: (number | string)[]): AxiosPromise<RoleVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/optionselect?roleIds=' + roleIds,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getRole(roleId: string | number) {
|
/**
|
||||||
return request<R<RoleVO>>({
|
* 查询角色详细
|
||||||
url: `/system/role/${roleId}`,
|
*/
|
||||||
|
export const getRole = (roleId: string | number): AxiosPromise<RoleVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/' + roleId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addRole(data: RoleForm) {
|
/**
|
||||||
return request<R>({
|
* 新增角色
|
||||||
|
*/
|
||||||
|
export const addRole = (data: any) => {
|
||||||
|
return request({
|
||||||
url: '/system/role',
|
url: '/system/role',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateRole(data: RoleForm) {
|
/**
|
||||||
return request<R>({
|
* 修改角色基础信息
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateRole = (data: any) => {
|
||||||
|
return request({
|
||||||
url: '/system/role',
|
url: '/system/role',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateRolePermission(data: RoleForm) {
|
/**
|
||||||
return request<R>({
|
* 修改角色权限(菜单权限 + 数据权限)
|
||||||
|
*/
|
||||||
|
export const updateRolePermission = (data: any) => {
|
||||||
|
return request({
|
||||||
url: '/system/role/permission',
|
url: '/system/role/permission',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function changeRoleStatus(roleId: string | number, status: string) {
|
/**
|
||||||
return request<R>({
|
* 角色状态修改
|
||||||
|
*/
|
||||||
|
export const changeRoleStatus = (roleId: string | number, status: string) => {
|
||||||
|
const data = {
|
||||||
|
roleId,
|
||||||
|
status
|
||||||
|
};
|
||||||
|
return request({
|
||||||
url: '/system/role/changeStatus',
|
url: '/system/role/changeStatus',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: {
|
data: data
|
||||||
roleId,
|
|
||||||
status
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delRole(roleId: Array<string | number> | string | number) {
|
/**
|
||||||
return request<R>({
|
* 删除角色
|
||||||
url: `/system/role/${roleId}`,
|
*/
|
||||||
|
export const delRole = (roleId: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/' + roleId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function allocatedUserList(query: UserQuery) {
|
/**
|
||||||
return request<R<PageResult<UserVO>>>({
|
* 查询角色已授权用户列表
|
||||||
|
*/
|
||||||
|
export const allocatedUserList = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
|
||||||
|
return request({
|
||||||
url: '/system/role/authUser/allocatedList',
|
url: '/system/role/authUser/allocatedList',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function unallocatedUserList(query: UserQuery) {
|
/**
|
||||||
return request<R<PageResult<UserVO>>>({
|
* 查询角色未授权用户列表
|
||||||
|
*/
|
||||||
|
export const unallocatedUserList = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
|
||||||
|
return request({
|
||||||
url: '/system/role/authUser/unallocatedList',
|
url: '/system/role/authUser/unallocatedList',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function authUserCancel(data: { roleId: string | number; userId: string | number }) {
|
/**
|
||||||
return request<R>({
|
* 取消用户授权角色
|
||||||
|
*/
|
||||||
|
export const authUserCancel = (data: any) => {
|
||||||
|
return request({
|
||||||
url: '/system/role/authUser/cancel',
|
url: '/system/role/authUser/cancel',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function authUserCancelAll(data: { roleId: string | number; userIds: string }) {
|
/**
|
||||||
return request<R>({
|
* 批量取消用户授权角色
|
||||||
|
*/
|
||||||
|
export const authUserCancelAll = (data: any) => {
|
||||||
|
return request({
|
||||||
url: '/system/role/authUser/cancelAll',
|
url: '/system/role/authUser/cancelAll',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
params: data
|
params: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function authUserSelectAll(data: { roleId: string | number; userIds: string }) {
|
/**
|
||||||
return request<R>({
|
* 授权用户选择
|
||||||
|
*/
|
||||||
|
export const authUserSelectAll = (data: any) => {
|
||||||
|
return request({
|
||||||
url: '/system/role/authUser/selectAll',
|
url: '/system/role/authUser/selectAll',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
params: data
|
params: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
// 根据角色ID查询部门树结构
|
||||||
export function deptTreeSelect(roleId: string | number) {
|
export const deptTreeSelect = (roleId: string | number): AxiosPromise<RoleDeptTree> => {
|
||||||
return request<R<RoleDeptTree>>({
|
return request({
|
||||||
url: `/system/role/deptTree/${roleId}`,
|
url: '/system/role/deptTree/' + roleId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
optionSelect,
|
||||||
|
listRole
|
||||||
|
};
|
||||||
|
|||||||
@ -1,35 +1,17 @@
|
|||||||
import type { DeptTreeVO } from '@/api/system/dept/types';
|
/**
|
||||||
import type { MenuTreeOption } from '@/api/system/menu/types';
|
* 菜单树形结构类型
|
||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
*/
|
||||||
|
export interface DeptTreeOption {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
parentId: string;
|
||||||
|
weight: number;
|
||||||
|
children?: DeptTreeOption[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface RoleDeptTree {
|
export interface RoleDeptTree {
|
||||||
checkedKeys: Array<string | number>;
|
checkedKeys: string[];
|
||||||
depts: DeptTreeVO[];
|
depts: DeptTreeOption[];
|
||||||
}
|
|
||||||
|
|
||||||
export interface RoleForm {
|
|
||||||
roleId?: string | number;
|
|
||||||
roleName?: string;
|
|
||||||
roleKey?: string;
|
|
||||||
roleSort?: number;
|
|
||||||
status?: string;
|
|
||||||
menuCheckStrictly?: boolean;
|
|
||||||
deptCheckStrictly?: boolean;
|
|
||||||
remark?: string;
|
|
||||||
dataScope?: string;
|
|
||||||
menuIds?: Array<string | number>;
|
|
||||||
deptIds?: Array<string | number>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RoleMenuTree {
|
|
||||||
menus: MenuTreeOption[];
|
|
||||||
checkedKeys: Array<string | number>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RoleQuery extends PageQuery {
|
|
||||||
roleName?: string;
|
|
||||||
roleKey?: string;
|
|
||||||
status?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoleVO extends BaseEntity {
|
export interface RoleVO extends BaseEntity {
|
||||||
@ -38,11 +20,33 @@ export interface RoleVO extends BaseEntity {
|
|||||||
roleKey: string;
|
roleKey: string;
|
||||||
roleSort: number;
|
roleSort: number;
|
||||||
dataScope: string;
|
dataScope: string;
|
||||||
menuCheckStrictly?: boolean;
|
menuCheckStrictly: boolean;
|
||||||
deptCheckStrictly?: boolean;
|
deptCheckStrictly: boolean;
|
||||||
status: string;
|
status: string;
|
||||||
|
delFlag: string;
|
||||||
|
remark?: any;
|
||||||
flag: boolean;
|
flag: boolean;
|
||||||
admin: boolean;
|
|
||||||
menuIds?: Array<string | number>;
|
menuIds?: Array<string | number>;
|
||||||
deptIds?: 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>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
import type { R } from '@/api/types';
|
import request from '@/utils/request';
|
||||||
import request from '@/api/request';
|
|
||||||
import type { SocialAuthVO } from './types';
|
|
||||||
|
|
||||||
|
// 获取跳转URL
|
||||||
export function authRouterUrl(source: string) {
|
export function authRouterUrl(source: string) {
|
||||||
return request<R<string>>({
|
return request({
|
||||||
url: `/auth/binding/${source}`,
|
url: '/auth/binding/' + source,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解绑账号
|
||||||
export function authUnlock(authId: string) {
|
export function authUnlock(authId: string) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: `/auth/unlock/${authId}`,
|
url: '/auth/unlock/' + authId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
//获取授权列表
|
||||||
export function getAuthList() {
|
export function getAuthList() {
|
||||||
return request<R<SocialAuthVO[]>>({
|
return request({
|
||||||
url: '/system/social/list',
|
url: '/system/social/list',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
export interface SocialAuthVO {
|
|
||||||
id: string;
|
|
||||||
source?: string;
|
|
||||||
avatar?: string;
|
|
||||||
userName?: string;
|
|
||||||
createTime?: string;
|
|
||||||
}
|
|
||||||
@ -1,154 +1,229 @@
|
|||||||
import type { DeptTreeVO } from '@/api/system/dept/types';
|
|
||||||
import type { RoleVO } from '@/api/system/role/types';
|
import type { RoleVO } from '@/api/system/role/types';
|
||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
import { parseStrEmpty } from '@/utils/ruoyi';
|
import { parseStrEmpty } from '@/utils/ruoyi';
|
||||||
|
import type { DeptTreeVO } from './../dept/types';
|
||||||
import type { UserForm, UserInfoVO, UserProfileForm, UserQuery, UserVO } from './types';
|
import type { UserForm, UserInfoVO, UserProfileForm, UserQuery, UserVO } from './types';
|
||||||
|
|
||||||
export function listUser(query: UserQuery) {
|
/**
|
||||||
return request<R<PageResult<UserVO>>>({
|
* 查询用户列表
|
||||||
|
* @param query
|
||||||
|
*/
|
||||||
|
export const listUser = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
|
||||||
|
return request({
|
||||||
url: '/system/user/list',
|
url: '/system/user/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function optionSelect(userIds: Array<number | string>) {
|
/**
|
||||||
return request<R<UserVO[]>>({
|
* 通过用户ids查询用户
|
||||||
url: `/system/user/optionselect?userIds=${userIds}`,
|
* @param userIds
|
||||||
|
*/
|
||||||
|
export const optionSelect = (userIds: (number | string)[]): AxiosPromise<UserVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/optionselect?userIds=' + userIds,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getUser(userId?: string | number) {
|
/**
|
||||||
return request<R<UserInfoVO>>({
|
* 获取用户详情
|
||||||
url: `/system/user/${parseStrEmpty(userId)}`,
|
* @param userId
|
||||||
|
*/
|
||||||
|
export const getUser = (userId?: string | number): AxiosPromise<UserInfoVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/' + parseStrEmpty(userId),
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addUser(data: UserForm) {
|
/**
|
||||||
return request<R>({
|
* 新增用户
|
||||||
|
*/
|
||||||
|
export const addUser = (data: UserForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/user',
|
url: '/system/user',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateUser(data: UserForm) {
|
/**
|
||||||
return request<R>({
|
* 修改用户
|
||||||
|
*/
|
||||||
|
export const updateUser = (data: UserForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/user',
|
url: '/system/user',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delUser(userId: Array<string | number> | string | number) {
|
/**
|
||||||
return request<R>({
|
* 删除用户
|
||||||
url: `/system/user/${userId}`,
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
export const delUser = (userId: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/' + userId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function resetUserPwd(userId: string | number, password: string) {
|
/**
|
||||||
return request<R>({
|
* 用户密码重置
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param password 密码
|
||||||
|
*/
|
||||||
|
export const resetUserPwd = (userId: string | number, password: string) => {
|
||||||
|
const data = {
|
||||||
|
userId,
|
||||||
|
password
|
||||||
|
};
|
||||||
|
return request({
|
||||||
url: '/system/user/resetPwd',
|
url: '/system/user/resetPwd',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
headers: {
|
headers: {
|
||||||
isEncrypt: true,
|
isEncrypt: true,
|
||||||
repeatSubmit: false
|
repeatSubmit: false
|
||||||
},
|
},
|
||||||
data: {
|
data: data
|
||||||
userId,
|
|
||||||
password
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function changeUserStatus(userId: number | string, status: string) {
|
/**
|
||||||
return request<R>({
|
* 用户状态修改
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param status 用户状态
|
||||||
|
*/
|
||||||
|
export const changeUserStatus = (userId: number | string, status: string) => {
|
||||||
|
const data = {
|
||||||
|
userId,
|
||||||
|
status
|
||||||
|
};
|
||||||
|
return request({
|
||||||
url: '/system/user/changeStatus',
|
url: '/system/user/changeStatus',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: {
|
data: data
|
||||||
userId,
|
|
||||||
status
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function unlockUser(userId: number | string) {
|
/**
|
||||||
return request<R>({
|
* 解锁用户
|
||||||
url: `/system/user/unlock/${userId}`,
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
export const unlockUser = (userId: number | string) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/unlock/' + userId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getUserProfile() {
|
/**
|
||||||
return request<R<UserInfoVO>>({
|
* 查询用户个人信息
|
||||||
|
*/
|
||||||
|
export const getUserProfile = (): AxiosPromise<UserInfoVO> => {
|
||||||
|
return request({
|
||||||
url: '/system/user/profile',
|
url: '/system/user/profile',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateUserProfile(data: UserProfileForm) {
|
/**
|
||||||
return request<R>({
|
* 修改用户个人信息
|
||||||
|
* @param data 用户信息
|
||||||
|
*/
|
||||||
|
export const updateUserProfile = (data: UserProfileForm) => {
|
||||||
|
return request({
|
||||||
url: '/system/user/profile',
|
url: '/system/user/profile',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateUserPwd(oldPassword: string, newPassword: string) {
|
/**
|
||||||
return request<R>({
|
* 用户密码重置
|
||||||
|
* @param oldPassword 旧密码
|
||||||
|
* @param newPassword 新密码
|
||||||
|
*/
|
||||||
|
export const updateUserPwd = (oldPassword: string, newPassword: string) => {
|
||||||
|
const data = {
|
||||||
|
oldPassword,
|
||||||
|
newPassword
|
||||||
|
};
|
||||||
|
return request({
|
||||||
url: '/system/user/profile/updatePwd',
|
url: '/system/user/profile/updatePwd',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
headers: {
|
headers: {
|
||||||
isEncrypt: true,
|
isEncrypt: true,
|
||||||
repeatSubmit: false
|
repeatSubmit: false
|
||||||
},
|
},
|
||||||
data: {
|
data: data
|
||||||
oldPassword,
|
|
||||||
newPassword
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function importUser(data: FormData, updateSupport: boolean) {
|
/**
|
||||||
return request<R>({
|
* 查询授权角色
|
||||||
url: '/system/user/importData',
|
* @param userId 用户ID
|
||||||
method: 'post',
|
*/
|
||||||
params: {
|
export const getAuthRole = (userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> => {
|
||||||
updateSupport: updateSupport ? 1 : 0
|
return request({
|
||||||
},
|
url: '/system/user/authRole/' + userId,
|
||||||
data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAuthRole(userId: string | number) {
|
|
||||||
return request<R<{ user: UserVO; roles: RoleVO[] }>>({
|
|
||||||
url: `/system/user/authRole/${userId}`,
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateAuthRole(data: { userId: string; roleIds: string }) {
|
/**
|
||||||
return request<R>({
|
* 保存授权角色
|
||||||
|
* @param data 用户ID
|
||||||
|
*/
|
||||||
|
export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
|
||||||
|
return request({
|
||||||
url: '/system/user/authRole',
|
url: '/system/user/authRole',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
params: data
|
params: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function deptTreeSelect() {
|
/**
|
||||||
return request<R<DeptTreeVO[]>>({
|
* 查询当前部门的所有用户信息
|
||||||
|
* @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',
|
url: '/system/user/deptTree',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function listUserByDeptId(deptId: string | number) {
|
export default {
|
||||||
return request<R<UserVO[]>>({
|
listUser,
|
||||||
url: `/system/user/list/dept/${deptId}`,
|
getUser,
|
||||||
method: 'get'
|
optionSelect,
|
||||||
});
|
addUser,
|
||||||
}
|
updateUser,
|
||||||
|
delUser,
|
||||||
|
resetUserPwd,
|
||||||
|
changeUserStatus,
|
||||||
|
unlockUser,
|
||||||
|
getUserProfile,
|
||||||
|
updateUserProfile,
|
||||||
|
updateUserPwd,
|
||||||
|
getAuthRole,
|
||||||
|
updateAuthRole,
|
||||||
|
deptTreeSelect,
|
||||||
|
listUserByDeptId
|
||||||
|
};
|
||||||
|
|||||||
@ -1,37 +1,81 @@
|
|||||||
import type { DeptVO } from '@/api/system/dept/types';
|
|
||||||
import type { PostVO } from '@/api/system/post/types';
|
import type { PostVO } from '@/api/system/post/types';
|
||||||
import type { RoleVO } from '@/api/system/role/types';
|
import type { RoleVO } from '@/api/system/role/types';
|
||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息
|
||||||
|
*/
|
||||||
export interface UserInfo {
|
export interface UserInfo {
|
||||||
user: {
|
user: UserVO;
|
||||||
userId: string | number;
|
|
||||||
userName: string;
|
|
||||||
nickName?: string;
|
|
||||||
avatar?: string | number;
|
|
||||||
avatarUrl?: string;
|
|
||||||
deptName?: string;
|
|
||||||
};
|
|
||||||
roles: string[];
|
roles: string[];
|
||||||
permissions: string[];
|
permissions: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserForm {
|
/**
|
||||||
userId?: string | number;
|
* 用户查询对象类型
|
||||||
deptId?: number | string;
|
*/
|
||||||
|
export interface UserQuery extends PageQuery {
|
||||||
userName?: string;
|
userName?: string;
|
||||||
nickName?: string;
|
nickName?: string;
|
||||||
password?: 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;
|
phoneNumber?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
gender?: string;
|
gender?: string;
|
||||||
status?: string;
|
status: string;
|
||||||
remark?: string;
|
remark?: string;
|
||||||
avatar?: string | number;
|
avatar?: string | number;
|
||||||
postIds?: Array<string | number>;
|
postIds: string[];
|
||||||
roleIds?: Array<string | number>;
|
roleIds: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 个人资料表单类型
|
||||||
|
*/
|
||||||
export interface UserProfileForm {
|
export interface UserProfileForm {
|
||||||
nickName?: string;
|
nickName?: string;
|
||||||
phoneNumber?: string;
|
phoneNumber?: string;
|
||||||
@ -41,42 +85,17 @@ export interface UserProfileForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface UserInfoVO {
|
export interface UserInfoVO {
|
||||||
user?: UserVO;
|
user: UserVO;
|
||||||
roles: RoleVO[];
|
roles: RoleVO[];
|
||||||
roleIds: Array<string | number>;
|
roleIds: string[];
|
||||||
posts: PostVO[];
|
posts: PostVO[];
|
||||||
postIds: Array<string | number>;
|
postIds: string[];
|
||||||
roleGroup?: string;
|
roleGroup: string;
|
||||||
postGroup?: string;
|
postGroup: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserQuery extends PageQuery {
|
export interface ResetPwdForm {
|
||||||
userName?: string;
|
oldPassword: string;
|
||||||
nickName?: string;
|
newPassword: string;
|
||||||
phoneNumber?: string;
|
confirmPassword: string;
|
||||||
status?: string;
|
|
||||||
deptId?: string | number;
|
|
||||||
roleId?: string | number;
|
|
||||||
userIds?: string | number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserVO extends BaseEntity {
|
|
||||||
userId?: string | number;
|
|
||||||
tenantId?: string;
|
|
||||||
deptId?: number | string;
|
|
||||||
userName?: string;
|
|
||||||
nickName?: string;
|
|
||||||
userType?: string;
|
|
||||||
email?: string;
|
|
||||||
phoneNumber?: string;
|
|
||||||
gender?: string;
|
|
||||||
avatar?: string | number;
|
|
||||||
avatarUrl?: string;
|
|
||||||
status?: string;
|
|
||||||
deptName?: string;
|
|
||||||
roles?: RoleVO[];
|
|
||||||
admin?: boolean;
|
|
||||||
loginIp?: string;
|
|
||||||
loginDate?: string;
|
|
||||||
dept?: DeptVO;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,78 +1,81 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import type { DbTableQuery, DbTableVO, GenTableDetailPayload, TableQuery, TableVO } from './types';
|
import request from '@/utils/request';
|
||||||
|
import type { DbTableForm, DbTableQuery, DbTableVO, GenTableDetailPayload, TableQuery, TableVO } from './types';
|
||||||
|
|
||||||
export function listTable(query: TableQuery) {
|
export type { GenTableDetailPayload } from './types';
|
||||||
return request<R<PageResult<TableVO>>>({
|
|
||||||
|
// 查询生成表数据
|
||||||
|
export const listTable = (query: TableQuery): AxiosPromise<PageResult<TableVO>> => {
|
||||||
|
return request({
|
||||||
url: '/tool/gen/list',
|
url: '/tool/gen/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
// 查询db数据库列表
|
||||||
export function listDbTable(query: DbTableQuery) {
|
export const listDbTable = (query: DbTableQuery): AxiosPromise<PageResult<DbTableVO>> => {
|
||||||
return request<R<PageResult<DbTableVO>>>({
|
return request({
|
||||||
url: '/tool/gen/db/list',
|
url: '/tool/gen/db/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getGenTable(tableId: string | number) {
|
// 查询表详细信息
|
||||||
return request<R<GenTableDetailPayload>>({
|
export const getGenTable = (tableId: string | number): AxiosPromise<GenTableDetailPayload> => {
|
||||||
url: `/tool/gen/${tableId}`,
|
return request({
|
||||||
|
url: '/tool/gen/' + tableId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateGenTable(data: DbTableVO & { columns?: unknown[]; params?: Record<string, unknown> }) {
|
// 修改代码生成信息
|
||||||
return request<R>({
|
export const updateGenTable = (data: DbTableForm): AxiosPromise<unknown> => {
|
||||||
|
return request({
|
||||||
url: '/tool/gen',
|
url: '/tool/gen',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function importTable(data: { tables: string; dataName: string }) {
|
// 导入表
|
||||||
return request<R>({
|
export const importTable = (data: { tables: string; dataName: string }): AxiosPromise<unknown> => {
|
||||||
|
return request({
|
||||||
url: '/tool/gen/importTable',
|
url: '/tool/gen/importTable',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: data
|
params: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function previewTable(tableId: string | number) {
|
// 预览生成代码
|
||||||
return request<R<Record<string, string>>>({
|
export const previewTable = (tableId: string | number) => {
|
||||||
url: `/tool/gen/preview/${tableId}`,
|
return request({
|
||||||
|
url: '/tool/gen/preview/' + tableId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delTable(tableId: string | number | Array<string | number>) {
|
// 删除表数据
|
||||||
return request<R>({
|
export const delTable = (tableId: string | number | Array<string | number>) => {
|
||||||
url: `/tool/gen/${tableId}`,
|
return request({
|
||||||
|
url: '/tool/gen/' + tableId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function synchDb(tableId: string | number) {
|
// 同步数据库
|
||||||
return request<R>({
|
export const synchDb = (tableId: string | number) => {
|
||||||
url: `/tool/gen/synchDb/${tableId}`,
|
return request({
|
||||||
|
url: '/tool/gen/synchDb/' + tableId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getDataNames() {
|
// 获取数据源名称
|
||||||
return request<R<string[]>>({
|
export const getDataNames = () => {
|
||||||
|
return request({
|
||||||
url: '/tool/gen/getDataNames',
|
url: '/tool/gen/getDataNames',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function batchGenCode(tableIdStr: string) {
|
|
||||||
return request<Blob>({
|
|
||||||
url: `/tool/gen/batchGenCode?tableIdStr=${tableIdStr}`,
|
|
||||||
method: 'get',
|
|
||||||
responseType: 'blob'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,53 +1,27 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
export interface TableVO extends BaseEntity {
|
||||||
|
createDept: number | string;
|
||||||
export interface DbColumnVO extends BaseEntity {
|
tableId: string | number;
|
||||||
columnId?: string | number;
|
dataName: string;
|
||||||
tableId?: string | number;
|
tableName: string;
|
||||||
columnName?: string;
|
tableComment: string;
|
||||||
columnComment?: string;
|
className: string;
|
||||||
columnType?: string;
|
tplCategory: string;
|
||||||
javaType?: string;
|
frontendType: string;
|
||||||
javaField?: string;
|
packageName: string;
|
||||||
isPk?: string;
|
moduleName: string;
|
||||||
isIncrement?: string;
|
businessName: string;
|
||||||
isRequired?: string;
|
functionName: string;
|
||||||
isInsert?: string;
|
functionAuthor: string;
|
||||||
isEdit?: string;
|
pkColumn?: any;
|
||||||
isList?: string;
|
columns?: any;
|
||||||
isQuery?: string;
|
options?: any;
|
||||||
queryType?: string;
|
remark?: any;
|
||||||
htmlType?: string;
|
treeCode?: any;
|
||||||
dictType?: string;
|
treeParentCode?: any;
|
||||||
sort?: number;
|
treeName?: any;
|
||||||
increment?: boolean;
|
menuIds?: any;
|
||||||
capJavaField?: string;
|
parentMenuId?: any;
|
||||||
usableColumn?: boolean;
|
parentMenuName?: any;
|
||||||
superColumn?: boolean;
|
|
||||||
list?: boolean;
|
|
||||||
pk?: boolean;
|
|
||||||
insert?: boolean;
|
|
||||||
edit?: boolean;
|
|
||||||
query?: boolean;
|
|
||||||
required?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DbTableQuery extends PageQuery {
|
|
||||||
dataName?: string;
|
|
||||||
tableName?: string;
|
|
||||||
tableComment?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DbTableVO extends Omit<TableVO, 'tableId'> {
|
|
||||||
tableId?: string | number;
|
|
||||||
columns?: DbColumnVO[];
|
|
||||||
options?: string;
|
|
||||||
remark?: string;
|
|
||||||
treeCode?: string;
|
|
||||||
treeParentCode?: string;
|
|
||||||
treeName?: string;
|
|
||||||
menuIds?: Array<string | number>;
|
|
||||||
parentMenuId?: string | number;
|
|
||||||
parentMenuName?: string;
|
|
||||||
enableExport?: boolean;
|
enableExport?: boolean;
|
||||||
enableStatus?: boolean;
|
enableStatus?: boolean;
|
||||||
statusField?: string;
|
statusField?: string;
|
||||||
@ -55,37 +29,187 @@ export interface DbTableVO extends Omit<TableVO, 'tableId'> {
|
|||||||
uniqueFields?: string[];
|
uniqueFields?: string[];
|
||||||
enableSort?: boolean;
|
enableSort?: boolean;
|
||||||
sortField?: string;
|
sortField?: string;
|
||||||
frontendType?: string;
|
|
||||||
treeRootValue?: string;
|
treeRootValue?: string;
|
||||||
treeAncestorsField?: string;
|
treeAncestorsField?: string;
|
||||||
treeOrderField?: 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 {
|
export interface GenTableDetailPayload {
|
||||||
info: DbTableVO;
|
info: DbTableVO;
|
||||||
rows: DbColumnVO[];
|
rows: DbColumnVO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableQuery extends PageQuery {
|
export interface DbColumnForm extends BaseEntity {
|
||||||
tableName?: string;
|
createDept: number;
|
||||||
tableComment?: string;
|
columnId: string;
|
||||||
dataName?: 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 TableVO extends BaseEntity {
|
export interface DbParamForm {
|
||||||
createDept?: number | string;
|
treeCode?: any;
|
||||||
tableId: string | number;
|
treeName?: any;
|
||||||
dataName?: string;
|
treeParentCode?: any;
|
||||||
tableName: string;
|
parentMenuId: string;
|
||||||
tableComment?: string;
|
enableExport?: boolean;
|
||||||
className?: string;
|
enableStatus?: boolean;
|
||||||
tplCategory?: string;
|
statusField?: string;
|
||||||
frontendType?: string;
|
enableUnique?: boolean;
|
||||||
packageName?: string;
|
uniqueFields?: string[];
|
||||||
moduleName?: string;
|
enableSort?: boolean;
|
||||||
businessName?: string;
|
sortField?: string;
|
||||||
functionName?: string;
|
treeRootValue?: string;
|
||||||
functionAuthor?: string;
|
treeAncestorsField?: string;
|
||||||
tree?: boolean;
|
treeOrderField?: string;
|
||||||
crud?: boolean;
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
113
src/api/types.ts
113
src/api/types.ts
@ -1,88 +1,51 @@
|
|||||||
import type { MenuDataItem } from '@ant-design/pro-components';
|
/**
|
||||||
|
* 注册
|
||||||
export interface BaseEntity {
|
*/
|
||||||
createBy?: string;
|
export type RegisterForm = {
|
||||||
createTime?: string;
|
username: string;
|
||||||
updateBy?: string;
|
password: string;
|
||||||
updateTime?: string;
|
|
||||||
remark?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoginParams {
|
|
||||||
username?: string;
|
|
||||||
password?: string;
|
|
||||||
code?: string;
|
|
||||||
uuid?: string;
|
|
||||||
rememberMe?: boolean;
|
|
||||||
socialCode?: string;
|
|
||||||
socialState?: string;
|
|
||||||
source?: string;
|
|
||||||
clientId?: string;
|
|
||||||
grantType?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoginResult {
|
|
||||||
access_token: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PageQuery {
|
|
||||||
pageNum?: number;
|
|
||||||
pageSize?: number;
|
|
||||||
orderByColumn?: string;
|
|
||||||
isAsc?: 'ascending' | 'descending';
|
|
||||||
params?: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PageResult<T = unknown> {
|
|
||||||
total: number;
|
|
||||||
rows: T[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface R<T = unknown> {
|
|
||||||
code: number;
|
|
||||||
msg: string;
|
|
||||||
data: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RegisterParams {
|
|
||||||
username?: string;
|
|
||||||
password?: string;
|
|
||||||
confirmPassword?: string;
|
confirmPassword?: string;
|
||||||
code?: string;
|
code?: string;
|
||||||
uuid?: string;
|
uuid?: string;
|
||||||
userType?: string;
|
userType?: string;
|
||||||
clientId?: string;
|
};
|
||||||
grantType?: 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 {
|
export interface VerifyCodeResult {
|
||||||
captchaEnabled: boolean;
|
captchaEnabled: boolean;
|
||||||
uuid?: string;
|
uuid?: string;
|
||||||
img?: string;
|
img?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RouteMeta {
|
/**
|
||||||
title?: string;
|
* 分页返回结果
|
||||||
icon?: string | null;
|
*/
|
||||||
noCache?: boolean;
|
export interface PageResult<T = any> {
|
||||||
link?: string;
|
total: number;
|
||||||
hidden?: boolean;
|
rows: T[];
|
||||||
activeMenu?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BackendRoute {
|
|
||||||
name?: string;
|
|
||||||
path: string;
|
|
||||||
component?: string;
|
|
||||||
redirect?: string;
|
|
||||||
query?: string;
|
|
||||||
hidden?: boolean;
|
|
||||||
alwaysShow?: boolean;
|
|
||||||
meta?: RouteMeta;
|
|
||||||
children?: BackendRoute[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type RuntimeMenuItem = Omit<MenuDataItem, 'routes'> & {
|
|
||||||
backendRoute?: BackendRoute;
|
|
||||||
routes?: RuntimeMenuItem[];
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,49 +1,76 @@
|
|||||||
import type { R } from '@/api/types';
|
import type { CategoryForm, CategoryQuery, CategoryTreeVO, CategoryVO } from '@/api/workflow/category/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import type { CategoryForm, CategoryQuery, CategoryTreeVO, CategoryVO } from './types';
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function listCategory(query?: CategoryQuery) {
|
/**
|
||||||
return request<R<CategoryVO[]>>({
|
* 查询流程分类列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/category/list',
|
url: '/workflow/category/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getCategory(categoryId: string | number) {
|
/**
|
||||||
return request<R<CategoryVO>>({
|
* 查询流程分类详细
|
||||||
url: `/workflow/category/${categoryId}`,
|
* @param categoryId
|
||||||
|
*/
|
||||||
|
export const getCategory = (categoryId: string | number): AxiosPromise<CategoryVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/category/' + categoryId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addCategory(data: CategoryForm) {
|
/**
|
||||||
return request<R>({
|
* 新增流程分类
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addCategory = (data: CategoryForm) => {
|
||||||
|
return request({
|
||||||
url: '/workflow/category',
|
url: '/workflow/category',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateCategory(data: CategoryForm) {
|
/**
|
||||||
return request<R>({
|
* 修改流程分类
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateCategory = (data: CategoryForm) => {
|
||||||
|
return request({
|
||||||
url: '/workflow/category',
|
url: '/workflow/category',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delCategory(categoryId: string | number | Array<string | number>) {
|
/**
|
||||||
return request<R>({
|
* 删除流程分类
|
||||||
url: `/workflow/category/${categoryId}`,
|
* @param categoryId
|
||||||
|
*/
|
||||||
|
export const delCategory = (categoryId: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/category/' + categoryId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function categoryTree(query?: CategoryForm) {
|
/**
|
||||||
return request<R<CategoryTreeVO[]>>({
|
* 获取流程分类树列表
|
||||||
url: '/workflow/category/categoryTree',
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const categoryTree = (query?: CategoryForm): AxiosPromise<CategoryTreeVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/category/categoryTree`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,29 +1,67 @@
|
|||||||
import type { BaseEntity } from '@/api/types';
|
|
||||||
|
|
||||||
export interface CategoryForm extends BaseEntity {
|
|
||||||
categoryId?: string | number;
|
|
||||||
categoryName?: string;
|
|
||||||
parentId?: string | number;
|
|
||||||
orderNum?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CategoryQuery {
|
|
||||||
categoryName?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CategoryTreeVO {
|
export interface CategoryTreeVO {
|
||||||
id: number | string;
|
id: number | string;
|
||||||
label: string;
|
label: string;
|
||||||
parentId: number | string;
|
parentId: number | string;
|
||||||
weight: number;
|
weight: number;
|
||||||
children?: CategoryTreeVO[];
|
children: CategoryTreeVO[];
|
||||||
|
}
|
||||||
|
export interface CategoryVO {
|
||||||
|
/**
|
||||||
|
* 流程分类ID
|
||||||
|
*/
|
||||||
|
categoryId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父级id
|
||||||
|
*/
|
||||||
|
parentId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程分类名称
|
||||||
|
*/
|
||||||
|
categoryName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示顺序
|
||||||
|
*/
|
||||||
|
orderNum: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
createTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子对象
|
||||||
|
*/
|
||||||
|
children: CategoryVO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoryVO {
|
export interface CategoryForm extends BaseEntity {
|
||||||
categoryId: string | number;
|
/**
|
||||||
|
* 流程分类ID
|
||||||
|
*/
|
||||||
|
categoryId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程分类名称
|
||||||
|
*/
|
||||||
|
categoryName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父流程分类id
|
||||||
|
*/
|
||||||
parentId?: string | number;
|
parentId?: string | number;
|
||||||
categoryName: string;
|
|
||||||
orderNum: number;
|
/**
|
||||||
createTime?: string;
|
* 显示顺序
|
||||||
children?: CategoryVO[];
|
*/
|
||||||
|
orderNum?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryQuery {
|
||||||
|
/**
|
||||||
|
* 流程分类名称
|
||||||
|
*/
|
||||||
|
categoryName?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,137 +1,176 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type {
|
||||||
import type { definitionXmlVO, FlowDefinitionForm, FlowDefinitionQuery, FlowDefinitionVO } from './types';
|
definitionXmlVO,
|
||||||
|
FlowDefinitionForm,
|
||||||
|
FlowDefinitionQuery,
|
||||||
|
FlowDefinitionVo
|
||||||
|
} from '@/api/workflow/definition/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function listDefinition(query: FlowDefinitionQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowDefinitionVO>>>({
|
* 获取流程定义列表
|
||||||
url: '/workflow/definition/list',
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const listDefinition = (query: FlowDefinitionQuery): AxiosPromise<PageResult<FlowDefinitionVo>> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/list`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function unPublishList(query: FlowDefinitionQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowDefinitionVO>>>({
|
* 查询未发布的流程定义列表
|
||||||
url: '/workflow/definition/unPublishList',
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const unPublishList = (query: FlowDefinitionQuery): AxiosPromise<PageResult<FlowDefinitionVo>> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/unPublishList`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function definitionXml(definitionId: string) {
|
/**
|
||||||
return request<R<definitionXmlVO>>({
|
* 通过流程定义id获取xml
|
||||||
|
* @param definitionId 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const definitionXml = (definitionId: string): AxiosPromise<definitionXmlVO> => {
|
||||||
|
return request({
|
||||||
url: `/workflow/definition/definitionXml/${definitionId}`,
|
url: `/workflow/definition/definitionXml/${definitionId}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function deleteDefinition(id: string | string[]) {
|
/**
|
||||||
return request<R>({
|
* 删除流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteDefinition = (id: string | string[]) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/definition/${id}`,
|
url: `/workflow/definition/${id}`,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function activeDefinition(definitionId: string, activityStatus: boolean) {
|
/**
|
||||||
return request<R>({
|
* 挂起/激活
|
||||||
|
* @param definitionId 流程定义id
|
||||||
|
* @param activityStatus 状态
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const active = (definitionId: string, activityStatus: boolean) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/definition/active/${definitionId}`,
|
url: `/workflow/definition/active/${definitionId}`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
params: { active: activityStatus }
|
params: {
|
||||||
|
active: activityStatus
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function active(definitionId: string, activityStatus: boolean) {
|
/**
|
||||||
return activeDefinition(definitionId, activityStatus);
|
* 通过zip或xml部署流程定义
|
||||||
}
|
* @returns
|
||||||
|
*/
|
||||||
export function importDefinition(data: FormData) {
|
export function importDef(data: any) {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/workflow/definition/importDef',
|
url: '/workflow/definition/importDef',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data: data,
|
||||||
headers: { repeatSubmit: false }
|
headers: {
|
||||||
|
repeatSubmit: false
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importDef(data: FormData) {
|
/**
|
||||||
return importDefinition(data);
|
* 发布流程定义
|
||||||
}
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
export function publishDefinition(id: string) {
|
*/
|
||||||
return request<R>({
|
export const publish = (id: string) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/definition/publish/${id}`,
|
url: `/workflow/definition/publish/${id}`,
|
||||||
method: 'put'
|
method: 'put'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function publish(id: string) {
|
/**
|
||||||
return publishDefinition(id);
|
* 取消发布流程定义
|
||||||
}
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
export function unPublish(id: string) {
|
*/
|
||||||
return request<R>({
|
export const unPublish = (id: string) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/definition/unPublish/${id}`,
|
url: `/workflow/definition/unPublish/${id}`,
|
||||||
method: 'put'
|
method: 'put'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function xmlString(id: string) {
|
/**
|
||||||
return request<R<string>>({
|
* 获取流程定义xml字符串
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const xmlString = (id: string) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/definition/xmlString/${id}`,
|
url: `/workflow/definition/xmlString/${id}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addDefinition(data: FlowDefinitionForm) {
|
/**
|
||||||
return request<R>({
|
* 新增
|
||||||
url: '/workflow/definition',
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const add = (data: FlowDefinitionForm) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function add(data: FlowDefinitionForm) {
|
/**
|
||||||
return addDefinition(data);
|
* 修改
|
||||||
}
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
export function editDefinition(data: FlowDefinitionForm) {
|
*/
|
||||||
return request<R>({
|
export const edit = (data: FlowDefinitionForm) => {
|
||||||
url: '/workflow/definition',
|
return request({
|
||||||
|
url: `/workflow/definition`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function edit(data: FlowDefinitionForm) {
|
/**
|
||||||
return editDefinition(data);
|
* 查询详情
|
||||||
}
|
* @param id 参数
|
||||||
|
* @returns
|
||||||
export function getDefinition(id: string) {
|
*/
|
||||||
return request<R<FlowDefinitionVO>>({
|
export const getInfo = (id: number | string) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/definition/${id}`,
|
url: `/workflow/definition/${id}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getInfo(id: string | number) {
|
/**
|
||||||
return getDefinition(String(id));
|
* 复制流程定义
|
||||||
}
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
export function copyDefinition(id: string) {
|
*/
|
||||||
return request<R>({
|
export const copy = (id: string) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/definition/copy/${id}`,
|
url: `/workflow/definition/copy/${id}`,
|
||||||
method: 'post'
|
method: 'post'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function copy(id: string) {
|
|
||||||
return copyDefinition(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function exportDefinition(id: string) {
|
|
||||||
return request<Blob>({
|
|
||||||
url: `/workflow/definition/exportDef/${id}`,
|
|
||||||
method: 'post',
|
|
||||||
responseType: 'blob'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,41 +1,32 @@
|
|||||||
import type { PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface FlowDefinitionForm {
|
|
||||||
id?: string;
|
|
||||||
flowName?: string;
|
|
||||||
flowCode?: string;
|
|
||||||
category?: string | number;
|
|
||||||
ext?: string;
|
|
||||||
formPath?: string;
|
|
||||||
formCustom?: string;
|
|
||||||
modelValue?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlowDefinitionQuery extends PageQuery {
|
export interface FlowDefinitionQuery extends PageQuery {
|
||||||
flowCode?: string;
|
flowCode?: string;
|
||||||
flowName?: string;
|
flowName?: string;
|
||||||
category?: string | number;
|
category: string | number;
|
||||||
isPublish?: number;
|
isPublish?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FlowDefinitionVO {
|
export interface FlowDefinitionVo {
|
||||||
id: string;
|
id: string;
|
||||||
flowName: string;
|
flowName: string;
|
||||||
flowCode: string;
|
flowCode: string;
|
||||||
category?: string | number;
|
formPath: string;
|
||||||
categoryName?: string;
|
version: string;
|
||||||
formPath?: string;
|
isPublish: number;
|
||||||
formCustom?: string;
|
activityStatus: number;
|
||||||
modelValue?: string;
|
createTime: Date;
|
||||||
version?: string | number;
|
updateTime: Date;
|
||||||
isPublish?: number;
|
|
||||||
activityStatus?: number;
|
|
||||||
ext?: string;
|
|
||||||
createTime?: string | Date;
|
|
||||||
updateTime?: string | Date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FlowDefinitionVo = FlowDefinitionVO;
|
export interface FlowDefinitionForm {
|
||||||
|
id: string;
|
||||||
|
flowName: string;
|
||||||
|
flowCode: string;
|
||||||
|
category: string;
|
||||||
|
ext: string;
|
||||||
|
formPath: string;
|
||||||
|
formCustom: string;
|
||||||
|
modelValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface definitionXmlVO {
|
export interface definitionXmlVO {
|
||||||
xml: string[];
|
xml: string[];
|
||||||
|
|||||||
@ -1,84 +1,126 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types';
|
||||||
import type { FlowHisTaskResult, FlowInstanceQuery, FlowInstanceVO } from './types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function pageByRunning(query: FlowInstanceQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowInstanceVO>>>({
|
* 查询运行中实例列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByRunning = (query: FlowInstanceQuery): AxiosPromise<PageResult<FlowInstanceVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/instance/pageByRunning',
|
url: '/workflow/instance/pageByRunning',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function pageByFinish(query: FlowInstanceQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowInstanceVO>>>({
|
* 查询已完成实例列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByFinish = (query: FlowInstanceQuery): AxiosPromise<PageResult<FlowInstanceVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/instance/pageByFinish',
|
url: '/workflow/instance/pageByFinish',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function pageByCurrent(query: FlowInstanceQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowInstanceVO>>>({
|
* 通过业务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',
|
url: '/workflow/instance/pageByCurrent',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function cancelProcessApply(data: {
|
/**
|
||||||
id?: string | number;
|
* 撤销流程
|
||||||
businessId?: string | number;
|
* @param data 参数
|
||||||
comment?: string;
|
* @returns
|
||||||
message?: string;
|
*/
|
||||||
}) {
|
export const cancelProcessApply = (data: any) => {
|
||||||
return request<R>({
|
return request({
|
||||||
url: '/workflow/instance/cancelProcessApply',
|
url: `/workflow/instance/cancelProcessApply`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function instanceVariable(instanceId: string | number) {
|
/**
|
||||||
return request<R<{ variable: string }>>({
|
* 获取流程变量
|
||||||
|
* @param instanceId 实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const instanceVariable = (instanceId: string | number) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/instance/instanceVariable/${instanceId}`,
|
url: `/workflow/instance/instanceVariable/${instanceId}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function deleteByInstanceIds(instanceIds: Array<string | number> | string | number) {
|
/**
|
||||||
return request<R>({
|
* 删除
|
||||||
|
* @param instanceIds 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteByInstanceIds = (instanceIds: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/instance/deleteByInstanceIds/${instanceIds}`,
|
url: `/workflow/instance/deleteByInstanceIds/${instanceIds}`,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function deleteHisByInstanceIds(instanceIds: Array<string | number> | string | number) {
|
/**
|
||||||
return request<R>({
|
* 删除历史流程实例
|
||||||
|
* @param instanceIds
|
||||||
|
*/
|
||||||
|
export const deleteHisByInstanceIds = (instanceIds: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/instance/deleteHisByInstanceIds/${instanceIds}`,
|
url: `/workflow/instance/deleteHisByInstanceIds/${instanceIds}`,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function invalid(data: { id: string | number; comment?: string }) {
|
/**
|
||||||
return request<R>({
|
* 作废流程
|
||||||
url: '/workflow/instance/invalid',
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const invalid = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/invalid`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
/**
|
||||||
export function updateVariable(data: { instanceId?: string | number; key?: string; value?: string }) {
|
* 修改流程变量
|
||||||
return request<R>({
|
* @param data 参数
|
||||||
url: '/workflow/instance/updateVariable',
|
* @returns
|
||||||
|
*/
|
||||||
|
export const updateVariable = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/updateVariable`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function flowHisTaskList(businessId: string | number) {
|
|
||||||
return request<R<FlowHisTaskResult>>({
|
|
||||||
url: `/workflow/instance/flowHisTaskList/${businessId}?t=${Math.random()}`,
|
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,10 +1,4 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
import type { FlowTaskVO } from '@/api/workflow/task/types';
|
||||||
import type { FlowHistoryVO, FlowTaskVO } from '@/api/workflow/task/types';
|
|
||||||
|
|
||||||
export interface FlowHisTaskResult {
|
|
||||||
list: FlowHistoryVO[];
|
|
||||||
instanceId?: string | number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlowInstanceQuery extends PageQuery {
|
export interface FlowInstanceQuery extends PageQuery {
|
||||||
category?: string | number;
|
category?: string | number;
|
||||||
@ -17,25 +11,18 @@ export interface FlowInstanceQuery extends PageQuery {
|
|||||||
|
|
||||||
export interface FlowInstanceVO extends BaseEntity {
|
export interface FlowInstanceVO extends BaseEntity {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
definitionId?: string;
|
definitionId: string;
|
||||||
flowName?: string;
|
flowName: string;
|
||||||
flowCode?: string;
|
flowCode: string;
|
||||||
version?: string | number;
|
version: string;
|
||||||
businessId: string;
|
businessId: string;
|
||||||
activityStatus?: number;
|
activityStatus: number;
|
||||||
tenantId?: string;
|
tenantId: string;
|
||||||
createTime?: string;
|
createTime: string;
|
||||||
updateTime?: string;
|
createBy: string;
|
||||||
createBy?: string;
|
flowStatus: string;
|
||||||
createByName?: string;
|
flowStatusName: string;
|
||||||
flowStatus?: string;
|
flowTaskList: FlowTaskVO[];
|
||||||
flowStatusName?: string;
|
businessCode: string;
|
||||||
flowTaskList?: FlowTaskVO[];
|
businessTitle: string;
|
||||||
businessCode?: string;
|
|
||||||
businessTitle?: string;
|
|
||||||
nodeName?: string;
|
|
||||||
categoryName?: string;
|
|
||||||
isSuspended?: boolean;
|
|
||||||
formCustom?: string;
|
|
||||||
formPath?: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,49 +1,76 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||||
import type { LeaveForm, LeaveQuery, LeaveVO } from './types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function listLeave(query?: LeaveQuery) {
|
/**
|
||||||
return request<R<PageResult<LeaveVO>>>({
|
* 查询请假列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listLeave = (query?: LeaveQuery): AxiosPromise<PageResult<LeaveVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/leave/list',
|
url: '/workflow/leave/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getLeave(id: string | number) {
|
/**
|
||||||
return request<R<LeaveVO>>({
|
* 查询请假详细
|
||||||
url: `/workflow/leave/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getLeave = (id: string | number): AxiosPromise<LeaveVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/leave/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addLeave(data: LeaveForm) {
|
/**
|
||||||
return request<R<LeaveVO>>({
|
* 新增请假
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/leave',
|
url: '/workflow/leave',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function submitAndFlowStart(data: LeaveForm) {
|
/**
|
||||||
return request<R<LeaveVO>>({
|
* 提交请假并发起流程
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const submitAndFlowStart = (data: LeaveForm): AxiosPromise<LeaveVO> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/leave/submitAndFlowStart',
|
url: '/workflow/leave/submitAndFlowStart',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateLeave(data: LeaveForm) {
|
/**
|
||||||
return request<R<LeaveVO>>({
|
* 修改请假
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/leave',
|
url: '/workflow/leave',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delLeave(id: string | number | Array<string | number>) {
|
/**
|
||||||
return request<R>({
|
* 删除请假
|
||||||
url: `/workflow/leave/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delLeave = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/leave/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,4 +1,13 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
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 {
|
export interface LeaveForm extends BaseEntity {
|
||||||
id?: string | number;
|
id?: string | number;
|
||||||
@ -15,14 +24,3 @@ export interface LeaveQuery extends PageQuery {
|
|||||||
startLeaveDays?: number;
|
startLeaveDays?: number;
|
||||||
endLeaveDays?: number;
|
endLeaveDays?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LeaveVO {
|
|
||||||
id: string | number;
|
|
||||||
applyCode?: string;
|
|
||||||
leaveType?: string;
|
|
||||||
startDate?: string;
|
|
||||||
endDate?: string;
|
|
||||||
leaveDays?: number;
|
|
||||||
remark?: string;
|
|
||||||
status?: string;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,41 +1,64 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import type { SpelForm, SpelQuery, SpelVO } from '@/api/workflow/spel/types';
|
||||||
import type { SpelForm, SpelQuery, SpelVO } from './types';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function listSpel(query?: SpelQuery) {
|
/**
|
||||||
return request<R<PageResult<SpelVO>>>({
|
* 查询流程spel表达式定义列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listSpel = (query?: SpelQuery): AxiosPromise<PageResult<SpelVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/spel/list',
|
url: '/workflow/spel/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getSpel(id: string | number) {
|
/**
|
||||||
return request<R<SpelVO>>({
|
* 查询流程spel表达式定义详细
|
||||||
url: `/workflow/spel/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getSpel = (id: string | number): AxiosPromise<SpelVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/spel/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addSpel(data: SpelForm) {
|
/**
|
||||||
return request<R>({
|
* 新增流程spel表达式定义
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addSpel = (data: SpelForm) => {
|
||||||
|
return request({
|
||||||
url: '/workflow/spel',
|
url: '/workflow/spel',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateSpel(data: SpelForm) {
|
/**
|
||||||
return request<R>({
|
* 修改流程spel表达式定义
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateSpel = (data: SpelForm) => {
|
||||||
|
return request({
|
||||||
url: '/workflow/spel',
|
url: '/workflow/spel',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function delSpel(id: string | number | Array<string | number>) {
|
/**
|
||||||
return request<R>({
|
* 删除流程spel表达式定义
|
||||||
url: `/workflow/spel/${id}`,
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delSpel = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/spel/' + id,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,29 +1,105 @@
|
|||||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
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 {
|
export interface SpelForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
id?: string | number;
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件名称
|
||||||
|
*/
|
||||||
componentName?: string;
|
componentName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法名
|
||||||
|
*/
|
||||||
methodName?: string;
|
methodName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
methodParams?: string;
|
methodParams?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览spel值
|
||||||
|
*/
|
||||||
viewSpel?: string;
|
viewSpel?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
status?: string;
|
status?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
remark?: string;
|
remark?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SpelQuery extends PageQuery {
|
export interface SpelQuery extends PageQuery {
|
||||||
|
/**
|
||||||
|
* 组件名称
|
||||||
|
*/
|
||||||
componentName?: string;
|
componentName?: string;
|
||||||
methodName?: string;
|
|
||||||
methodParams?: string;
|
|
||||||
viewSpel?: string;
|
|
||||||
status?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SpelVO {
|
/**
|
||||||
id: string | number;
|
* 方法名
|
||||||
componentName?: string;
|
*/
|
||||||
methodName?: string;
|
methodName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
methodParams?: string;
|
methodParams?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览spel值
|
||||||
|
*/
|
||||||
viewSpel?: string;
|
viewSpel?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
status?: string;
|
status?: string;
|
||||||
remark?: string;
|
|
||||||
|
/**
|
||||||
|
* 日期范围参数
|
||||||
|
*/
|
||||||
|
params?: any;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,129 +1,207 @@
|
|||||||
import type { PageResult, R } from '@/api/types';
|
import type { PageResult } from '@/api/types';
|
||||||
import type { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
import type { FlowTaskVO, TaskOperationBo, TaskQuery } from '@/api/workflow/task/types';
|
||||||
import request from '@/api/request';
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
import type { FlowNextNodeVO, FlowTaskVO, StartWorkflowResult, TaskOperationBo, TaskQuery } from './types';
|
import request from '@/utils/request';
|
||||||
|
|
||||||
export function pageByTaskWait(query: TaskQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowTaskVO>>>({
|
* 查询待办列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByTaskWait = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/task/pageByTaskWait',
|
url: '/workflow/task/pageByTaskWait',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function pageByTaskFinish(query: TaskQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowTaskVO>>>({
|
* 查询已办列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByTaskFinish = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/task/pageByTaskFinish',
|
url: '/workflow/task/pageByTaskFinish',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function pageByTaskCopy(query: TaskQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowTaskVO>>>({
|
* 查询当前用户的抄送列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByTaskCopy = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/task/pageByTaskCopy',
|
url: '/workflow/task/pageByTaskCopy',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function pageByAllTaskWait(query: TaskQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowTaskVO>>>({
|
* 查询全部待办任务
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByAllTaskWait = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/task/pageByAllTaskWait',
|
url: '/workflow/task/pageByAllTaskWait',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function pageByAllTaskFinish(query: TaskQuery) {
|
/**
|
||||||
return request<R<PageResult<FlowTaskVO>>>({
|
* 查询全部已办任务
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByAllTaskFinish = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
url: '/workflow/task/pageByAllTaskFinish',
|
url: '/workflow/task/pageByAllTaskFinish',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function startWorkFlow(data: StartProcessBo) {
|
/**
|
||||||
return request<R<StartWorkflowResult>>({
|
* 启动流程
|
||||||
|
* @param data
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const startWorkFlow = (data: object): any => {
|
||||||
|
return request({
|
||||||
url: '/workflow/task/startWorkFlow',
|
url: '/workflow/task/startWorkFlow',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function updateAssignee(taskIdList: Array<string | number>, userId: string | number) {
|
/**
|
||||||
return request<R>({
|
* 办理流程
|
||||||
|
* @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}`,
|
url: `/workflow/task/updateAssignee/${userId}`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: taskIdList
|
data: taskIdList
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function urgeTask(data: { taskIdList: Array<string | number>; message?: string; messageType?: string[] }) {
|
/**
|
||||||
return request<R>({
|
* 终止任务
|
||||||
url: '/workflow/task/urgeTask',
|
* @returns
|
||||||
|
*/
|
||||||
|
export const terminationTask = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/task/terminationTask`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function completeTask(data: Record<string, unknown>) {
|
/**
|
||||||
return request<R>({
|
* 获取可驳回得任务节点
|
||||||
url: '/workflow/task/completeTask',
|
* @returns
|
||||||
method: 'post',
|
*/
|
||||||
data
|
export const getBackTaskNode = (taskId: string | number, nodeCode: string) => {
|
||||||
});
|
return request({
|
||||||
}
|
url: `/workflow/task/getBackTaskNode/${taskId}/${nodeCode}`,
|
||||||
|
|
||||||
export function backProcess(data: Record<string, unknown>) {
|
|
||||||
return request<R>({
|
|
||||||
url: '/workflow/task/backProcess',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTask(taskId: string | number) {
|
|
||||||
return request<R<FlowTaskVO>>({
|
|
||||||
url: `/workflow/task/getTask/${taskId}`,
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function terminationTask(data: { taskId?: string | number; comment?: string }) {
|
/**
|
||||||
return request<R>({
|
* 任务操作 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
|
||||||
url: '/workflow/task/terminationTask',
|
* @returns
|
||||||
method: 'post',
|
*/
|
||||||
data
|
export const taskOperation = (data: TaskOperationBo, operation: string) => {
|
||||||
});
|
return request({
|
||||||
}
|
|
||||||
|
|
||||||
export function getBackTaskNode(taskId: string | number, nodeCode?: string) {
|
|
||||||
return request<R<FlowNextNodeVO[]>>({
|
|
||||||
url: `/workflow/task/getBackTaskNode/${taskId}/${nodeCode || ''}`,
|
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function taskOperation(data: TaskOperationBo, operation: string) {
|
|
||||||
return request<R>({
|
|
||||||
url: `/workflow/task/taskOperation/${operation}`,
|
url: `/workflow/task/taskOperation/${operation}`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function currentTaskAllUser(taskId: string | number) {
|
/**
|
||||||
return request<R<Array<{ userId: string | number; nickName: string; nodeName?: string }>>>({
|
* 获取当前任务办理人
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const currentTaskAllUser = (taskId: string | number) => {
|
||||||
|
return request({
|
||||||
url: `/workflow/task/currentTaskAllUser/${taskId}`,
|
url: `/workflow/task/currentTaskAllUser/${taskId}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getNextNodeList(data: { taskId?: string | number; variables?: Record<string, unknown> }) {
|
/**
|
||||||
return request<R<FlowNextNodeVO[]>>({
|
* 获取下一节点写
|
||||||
|
* @param data参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getNextNodeList = (data: any): any => {
|
||||||
|
return request({
|
||||||
url: '/workflow/task/getNextNodeList',
|
url: '/workflow/task/getNextNodeList',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 催办任务
|
||||||
|
* @param data参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const urgeTask = (data: any): any => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/urgeTask',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@ -1,82 +1,60 @@
|
|||||||
import type { OssVO } from '@/api/system/oss/types';
|
|
||||||
import type { PageQuery } from '@/api/types';
|
|
||||||
|
|
||||||
export interface ButtonList {
|
|
||||||
code: string;
|
|
||||||
show: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlowCopyVo {
|
|
||||||
userId: string | number;
|
|
||||||
nickName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlowHistoryVO {
|
|
||||||
nodeName?: string;
|
|
||||||
approverName?: string;
|
|
||||||
flowStatus?: string;
|
|
||||||
message?: string;
|
|
||||||
createTime?: string;
|
|
||||||
updateTime?: string;
|
|
||||||
runDuration?: string;
|
|
||||||
ext?: string | number;
|
|
||||||
attachmentList?: OssVO[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlowNextNodeVO {
|
|
||||||
nodeCode: string;
|
|
||||||
nodeName: string;
|
|
||||||
permissionFlag?: string | Array<string | number>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlowTaskVO {
|
|
||||||
id: string | number;
|
|
||||||
createTime?: string | Date;
|
|
||||||
updateTime?: string | Date;
|
|
||||||
tenantId?: string;
|
|
||||||
definitionId?: string;
|
|
||||||
instanceId?: string;
|
|
||||||
flowName?: string;
|
|
||||||
businessId: string;
|
|
||||||
nodeCode?: string;
|
|
||||||
nodeName?: string;
|
|
||||||
flowCode?: string;
|
|
||||||
flowStatus?: string;
|
|
||||||
flowStatusName?: string;
|
|
||||||
flowTaskStatus?: string;
|
|
||||||
formCustom?: string;
|
|
||||||
formPath?: string;
|
|
||||||
nodeType?: number;
|
|
||||||
nodeRatio?: string | number;
|
|
||||||
version?: string;
|
|
||||||
applyNode?: boolean;
|
|
||||||
buttonList?: ButtonList[];
|
|
||||||
copyList?: FlowCopyVo[];
|
|
||||||
varList?: Record<string, string>;
|
|
||||||
businessCode?: string;
|
|
||||||
businessTitle?: string;
|
|
||||||
categoryName?: string;
|
|
||||||
createByName?: string;
|
|
||||||
assigneeNames?: string;
|
|
||||||
approverName?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StartWorkflowResult {
|
|
||||||
taskId?: string | number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TaskOperationBo {
|
|
||||||
taskId?: string | number;
|
|
||||||
userId?: string | number;
|
|
||||||
userIds?: Array<string | number>;
|
|
||||||
message?: string;
|
|
||||||
messageType?: string[];
|
|
||||||
variables?: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TaskQuery extends PageQuery {
|
export interface TaskQuery extends PageQuery {
|
||||||
nodeName?: string;
|
nodeName?: string;
|
||||||
flowCode?: string;
|
flowCode?: string;
|
||||||
flowName?: string;
|
flowName?: string;
|
||||||
createByIds?: Array<string | number>;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
import { history } from '@umijs/max';
|
import type { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
|
||||||
import { normalizePath } from '@/utils/ruoyi';
|
import tab from '@/plugins/tab';
|
||||||
import type { RouterJumpVO } from './types';
|
import router from '@/router';
|
||||||
|
|
||||||
export function routerJump(routerJump: RouterJumpVO) {
|
|
||||||
history.push(
|
|
||||||
`${normalizePath(routerJump.formPath || '/workflow/leaveEdit/index')}?${new URLSearchParams({
|
|
||||||
id: routerJump.businessId,
|
|
||||||
type: routerJump.type,
|
|
||||||
taskId: String(routerJump.taskId)
|
|
||||||
}).toString()}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
routerJump
|
routerJump(routerJumpVo: RouterJumpVo) {
|
||||||
|
tab.closePage(router.currentRoute.value);
|
||||||
|
router.push({
|
||||||
|
path: routerJumpVo.formPath,
|
||||||
|
query: {
|
||||||
|
id: routerJumpVo.businessId,
|
||||||
|
type: routerJumpVo.type,
|
||||||
|
taskId: routerJumpVo.taskId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export interface RouterJumpVO {
|
export interface RouterJumpVo {
|
||||||
businessId: string;
|
businessId: string;
|
||||||
taskId: string | number;
|
taskId: string | number;
|
||||||
type: string;
|
type: string;
|
||||||
@ -9,6 +9,6 @@ export interface RouterJumpVO {
|
|||||||
export interface StartProcessBo {
|
export interface StartProcessBo {
|
||||||
businessId: string | number;
|
businessId: string | number;
|
||||||
flowCode: string;
|
flowCode: string;
|
||||||
variables: Record<string, unknown>;
|
variables: any;
|
||||||
bizExt: Record<string, unknown>;
|
bizExt: any;
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/app.tsx
14
src/app.tsx
@ -1,14 +0,0 @@
|
|||||||
import type { ReactNode } from 'react';
|
|
||||||
import { QueryClientProvider } from '@tanstack/react-query';
|
|
||||||
import { appEnv } from '@/utils/env';
|
|
||||||
import { queryClient } from '@/utils/queryClient';
|
|
||||||
|
|
||||||
export async function getInitialState() {
|
|
||||||
return {
|
|
||||||
name: appEnv.logoTitle
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function rootContainer(container: ReactNode) {
|
|
||||||
return <QueryClientProvider client={queryClient}>{container}</QueryClientProvider>;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user