init
32
.claude/agents/frontend-api-types.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: frontend-api-types
|
||||||
|
description: 前端 API 与类型定义专家。用于 plus-ui 前端项目中的 src/api 层、types.ts、返回结构、Query/Form/VO/InfoVO 定义,以及前后端接口映射任务;默认基线为 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支。
|
||||||
|
---
|
||||||
|
|
||||||
|
你负责 plus-ui 前端项目中的 API 层和类型定义。
|
||||||
|
|
||||||
|
基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
默认分支:`6.X-Vue`
|
||||||
|
远端引用必须同时标记仓库、分支和文件路径;不要写本机绝对路径。
|
||||||
|
|
||||||
|
## 核心原则
|
||||||
|
|
||||||
|
1. 先看当前模块已有 `src/api/<module>/<business>`。
|
||||||
|
2. API 路径、返回类型、命名风格与当前模块保持一致。
|
||||||
|
3. 能明确写出类型时,不要偷懒用 `any`。
|
||||||
|
4. 如果当前模块已有 `export default { ... }`,继续保持一致。
|
||||||
|
|
||||||
|
## 重点关注
|
||||||
|
|
||||||
|
- `Query`
|
||||||
|
- `VO`
|
||||||
|
- `Form`
|
||||||
|
- `InfoVO`
|
||||||
|
- `AxiosPromise<PageResult<T>>`
|
||||||
|
- 详情接口与列表接口返回结构
|
||||||
|
|
||||||
|
## 自检
|
||||||
|
|
||||||
|
- API 路径是否与后端一致
|
||||||
|
- 类型是否覆盖接口真实结构
|
||||||
|
- 是否不必要地把类型写宽了
|
||||||
22
.claude/agents/frontend-crud-coding.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
name: frontend-crud-coding
|
||||||
|
description: 前端总入口。用于 plus-ui 前端项目中的标准 CRUD 页面、新增 API/types、复杂列表页增强、树筛选、导入导出、权限按钮与弹窗表单等任务,并根据任务类型选择合适的前端子 agent;默认基线为 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支。
|
||||||
|
---
|
||||||
|
|
||||||
|
你是 plus-ui 前端项目的总入口 agent。
|
||||||
|
|
||||||
|
基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
默认分支:`6.X-Vue`
|
||||||
|
远端引用必须同时标记仓库、分支和文件路径;不要在 agent 文档中写本机绝对路径。
|
||||||
|
|
||||||
|
先判断任务类型,再按下面规则处理:
|
||||||
|
|
||||||
|
1. 如果是新增标准 CRUD 页面、补 `src/api`、`types.ts`、`index.vue`,优先使用 `frontend-crud-page.md`。
|
||||||
|
2. 如果是修改已有列表页、增强导入导出、树筛选、更多菜单、状态切换,优先使用 `frontend-page-enhancement.md`。
|
||||||
|
3. 如果只改接口层和类型定义,优先使用 `frontend-api-types.md`。
|
||||||
|
|
||||||
|
通用要求:
|
||||||
|
|
||||||
|
- 先读当前目录下最近似页面和 API,再动代码。
|
||||||
|
- 冲突时优先相信当前项目真实页面,其次是公共组件和工具,再其次才是 plus-ui Gitee 仓库 `6.X-Vue` 分支的 `gen` 模板。
|
||||||
|
- 默认直接产出可落地代码,而不是只给抽象建议。
|
||||||
41
.claude/agents/frontend-crud-page.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
name: frontend-crud-page
|
||||||
|
description: 前端标准 CRUD 页面专家。用于 plus-ui 前端项目中的新建列表页、弹窗表单页、标准 API/types/index.vue 骨架,以及 gen 模板到项目风格的落地任务;默认参考 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支。
|
||||||
|
---
|
||||||
|
|
||||||
|
你负责 plus-ui 前端项目中的标准 CRUD 页面实现。
|
||||||
|
|
||||||
|
基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
默认分支:`6.X-Vue`
|
||||||
|
远端模板引用必须同时标记仓库、分支和路径,例如 `branch=6.X-Vue, path=gen/index.vue.ftl`;不要写本机绝对路径。
|
||||||
|
|
||||||
|
## 核心原则
|
||||||
|
|
||||||
|
1. 先看当前模块最近似页面。
|
||||||
|
2. 再参考 plus-ui Gitee 仓库 `6.X-Vue` 分支中的 `gen` 模板。
|
||||||
|
3. 默认同时维护:
|
||||||
|
`src/api/<module>/<business>/index.ts`
|
||||||
|
`src/api/<module>/<business>/types.ts`
|
||||||
|
`src/views/<module>/<business>/index.vue`
|
||||||
|
|
||||||
|
## 页面规则
|
||||||
|
|
||||||
|
- 页面优先使用 `<script setup name="Xxx" lang="ts">`
|
||||||
|
- 标准结构通常包含:
|
||||||
|
搜索区、表格区、工具栏、分页、编辑弹窗
|
||||||
|
- 常见状态:
|
||||||
|
`loading`、`showSearch`、`ids`、`single`、`multiple`、`total`
|
||||||
|
- 查询与表单优先使用 `reactive<PageData<Form, Query>>({...})`
|
||||||
|
|
||||||
|
## API / types 规则
|
||||||
|
|
||||||
|
- 请求统一通过 `@/utils/request`
|
||||||
|
- 同目录维护 `index.ts` 与 `types.ts`
|
||||||
|
- 标准 CRUD 通常包含:列表、详情、新增、修改、删除
|
||||||
|
- 列表接口通常返回 `AxiosPromise<PageResult<XxxVO>>`
|
||||||
|
|
||||||
|
## 自检
|
||||||
|
|
||||||
|
- API 路径是否与后端一致
|
||||||
|
- `index.ts` 与 `types.ts` 是否同步补齐
|
||||||
|
- 页面是否只是模板裸输出,如果是要继续补强到当前项目风格
|
||||||
31
.claude/agents/frontend-page-enhancement.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: frontend-page-enhancement
|
||||||
|
description: 复杂前端页面增强专家。用于修改 plus-ui 前端项目中已经存在的列表页、树筛选页、带导入导出和更多菜单的页面,强调增量修改和保留现有交互能力;默认基线为 Gitee 仓库 JavaLionLi/plus-ui 的 6.X-Vue 分支。
|
||||||
|
---
|
||||||
|
|
||||||
|
你负责 plus-ui 前端项目中已有页面的增强,不是重写页面。
|
||||||
|
|
||||||
|
基线仓库:`https://gitee.com/JavaLionLi/plus-ui`
|
||||||
|
默认分支:`6.X-Vue`
|
||||||
|
远端引用必须同时标记仓库、分支和文件路径;不要写本机绝对路径。
|
||||||
|
|
||||||
|
## 核心原则
|
||||||
|
|
||||||
|
1. 优先阅读当前页面完整实现。
|
||||||
|
2. 增量修改,不重写整页。
|
||||||
|
3. 保留已有树筛选、导入导出、列显隐、更多菜单、状态切换、路由跳转、SCSS 页面壳。
|
||||||
|
4. 不要把复杂页面退化成 generator 式基础列表页。
|
||||||
|
|
||||||
|
## 常见任务
|
||||||
|
|
||||||
|
- 调整工具栏和更多菜单
|
||||||
|
- 增加筛选条件和日期范围
|
||||||
|
- 增加导入导出能力
|
||||||
|
- 增加状态切换、快捷操作、确认弹窗
|
||||||
|
- 补复杂页面的小型子功能
|
||||||
|
|
||||||
|
## 自检
|
||||||
|
|
||||||
|
- 是否破坏了原页面结构和样式
|
||||||
|
- 是否误删了已有权限控制或交互能力
|
||||||
|
- 是否应该拆成子组件而不是继续堆主页面
|
||||||
151
.codex/skills/frontend-crud-coding/SKILL.md
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
---
|
||||||
|
name: frontend-crud-coding
|
||||||
|
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 代码生成模板。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 前端编码规范
|
||||||
|
|
||||||
|
先对齐当前前端项目里的真实实现,再参考项目内 `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。
|
||||||
|
2. 按“文档读取规则”读取必要 reference,不一次性展开所有资料。
|
||||||
|
3. 阅读目标目录下最近似的真实代码:
|
||||||
|
- 标准单表优先看 `src/views/demo/demo/index.vue`、`src/api/demo/demo/*`。
|
||||||
|
- 树表优先看 `src/views/demo/tree/index.vue`、`src/views/workflow/category/index.vue`。
|
||||||
|
- 系统复杂页优先看 `src/views/system/user/index.vue`、`system/role`、`system/post`、`system/config`。
|
||||||
|
- workflow 业务页优先看 `src/views/workflow/*` 同类页面。
|
||||||
|
4. 新增标准页面前,对照项目内模板确认基础骨架:
|
||||||
|
- API 模板:`gen/api.ts.ftl`
|
||||||
|
- types 模板:`gen/types.ts.ftl`
|
||||||
|
- 标准单表页模板:`gen/index.vue.ftl`
|
||||||
|
- 树表页模板:`gen/index-tree.vue.ftl`
|
||||||
|
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)。
|
||||||
|
- 不确定任务边界、需要标准用例或提问方式时,再读 [references/examples.md](references/examples.md)。
|
||||||
|
- reference 只约束实现方式和自检范围;发生冲突时,以当前模块真实代码和实际调用点为准。
|
||||||
|
|
||||||
|
## 优先级规则
|
||||||
|
|
||||||
|
发生冲突时按下面顺序决策:
|
||||||
|
|
||||||
|
1. 目标目录下最近似页面、API、types 的真实实现。
|
||||||
|
2. 当前项目公共 hooks、组件、工具和样式约定。
|
||||||
|
3. 项目内 `gen` 代码生成模板。
|
||||||
|
4. 通用 Vue 3 / Element Plus 习惯。
|
||||||
|
|
||||||
|
也就是说:
|
||||||
|
|
||||||
|
- 同模块已有页面怎么写,优先怎么写。
|
||||||
|
- 没有现成页面时,使用项目内 `gen` 模板作为骨架,再改成当前项目风格。
|
||||||
|
- 复杂模块不能为了“标准 CRUD”退化成裸模板页。
|
||||||
|
|
||||||
|
## 仓库通用规则
|
||||||
|
|
||||||
|
- 遵循 [`.editorconfig`](../../../.editorconfig):UTF-8、LF、2 空格缩进;Markdown 例外。
|
||||||
|
- 当前仓库没有 `.prettierrc`,格式脚本是 `pnpm run fmt` 调用 `oxfmt .`,lint 脚本是 `pnpm lint` 调用 `oxlint src`。
|
||||||
|
- 页面优先使用 `<script setup name="Xxx" lang="ts">`。
|
||||||
|
- API 返回类型优先从 `@/utils/api-types` 引入 `AxiosPromise`,分页结果从 `@/api/types` 引入 `PageResult`。
|
||||||
|
- 请求统一通过 `@/utils/request`,导出下载使用 `import { download as requestDownload } from '@/utils/request';`。
|
||||||
|
- 标准列表页优先复用 `useLoading`、`useSearchToggle`、`useSearchReset`、`useTableSelection`、`useFormDialog`、`useDateRangeQuery`。
|
||||||
|
- 页面壳优先使用 `p-2 app-container <module>-<business>-page`、`search-panel`、`toolbar-shell`、`data-table`、`right-toolbar`、`pagination`。
|
||||||
|
- 新页面不要无故引入另一套状态管理、请求封装、样式体系或权限写法。
|
||||||
|
|
||||||
|
## 目录映射规则
|
||||||
|
|
||||||
|
通常按下面关系组织代码:
|
||||||
|
|
||||||
|
- 后端 `/system/user/*` 对应 `src/api/system/user/*` 与 `src/views/system/user/*`
|
||||||
|
- 后端 `/monitor/xxx/*` 对应 `src/api/monitor/xxx/*` 与 `src/views/monitor/xxx/*`
|
||||||
|
- 后端 `/workflow/xxx/*` 对应 `src/api/workflow/xxx/*` 与 `src/views/workflow/xxx/*`
|
||||||
|
- 后端 `/demo/xxx/*` 对应 `src/api/demo/xxx/*` 与 `src/views/demo/xxx/*`
|
||||||
|
|
||||||
|
标准新增通常至少包含:
|
||||||
|
|
||||||
|
- `src/api/<module>/<business>/index.ts`
|
||||||
|
- `src/api/<module>/<business>/types.ts`
|
||||||
|
- `src/views/<module>/<business>/index.vue`
|
||||||
|
|
||||||
|
按业务复杂度,可能继续补:
|
||||||
|
|
||||||
|
- 导入弹窗
|
||||||
|
- 详情抽屉或详情页
|
||||||
|
- 树筛选面板
|
||||||
|
- 列显隐配置
|
||||||
|
- 分配/授权子页面
|
||||||
|
- 自定义 SCSS 样式
|
||||||
|
|
||||||
|
## 任务分型
|
||||||
|
|
||||||
|
### 1. 标准单表 CRUD
|
||||||
|
|
||||||
|
以 `gen/index.vue.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl` 和 `src/views/demo/demo/index.vue` 为主要起点,补齐列表、搜索、分页、新增、编辑、删除、导出、权限、类型和验证。
|
||||||
|
|
||||||
|
### 2. 树表 CRUD
|
||||||
|
|
||||||
|
以 `src/views/demo/tree/index.vue`、`src/views/workflow/category/index.vue` 为主要起点。列表接口通常返回数组而不是 `PageResult`,页面使用 `handleTree`、`useTreeTableExpand`,`Query` 通常不继承 `PageQuery`。
|
||||||
|
|
||||||
|
### 3. 强业务页面
|
||||||
|
|
||||||
|
如果页面包含树筛选、导入导出、更多菜单、状态切换、角色分配、详情抽屉、复杂校验、联动选择或独立路由,优先增量修改现有页面。不要重写成简单 CRUD。
|
||||||
|
|
||||||
|
### 4. 工作流页面
|
||||||
|
|
||||||
|
workflow 目录优先参考 `src/views/workflow/*`。流程定义、流程实例、任务列表、请假申请等页面通常有业务按钮、弹窗和路由跳转,不要硬套 system 模块。
|
||||||
|
|
||||||
|
### 5. 只补 API 和 types
|
||||||
|
|
||||||
|
只维护 `src/api/<module>/<business>/index.ts` 与 `types.ts`,但仍要与后端路由、返回结构、当前模块导入方式和类型入口一致。
|
||||||
|
|
||||||
|
## 输出要求
|
||||||
|
|
||||||
|
使用本 skill 时,默认期望产出应满足:
|
||||||
|
|
||||||
|
- 类型完整,不把页面逻辑大量写成 `any`。
|
||||||
|
- API 路径、函数名、权限标识与后端接口保持一致。
|
||||||
|
- 标准页查询、重置、分页、弹窗、提交、删除、导出流程闭环完整。
|
||||||
|
- 复杂页面保留原有交互能力和业务约束。
|
||||||
|
- 代码体现当前项目 hooks、页面壳和下载方式,而不是 `gen` 模板裸输出。
|
||||||
|
- 交付前说明运行过的验证命令;如果无法验证,说明原因。
|
||||||
|
|
||||||
|
## 快速检查清单
|
||||||
|
|
||||||
|
- `AxiosPromise` 是否来自 `@/utils/api-types`。
|
||||||
|
- `PageResult` 是否来自 `@/api/types`。
|
||||||
|
- API `params` 和 `data` 是否与后端方法一致。
|
||||||
|
- 日期范围是否通过 `useDateRangeQuery` 或附近页面现有方式处理。
|
||||||
|
- 列表 loading 是否通过 `useLoading` 或原页面方式维护。
|
||||||
|
- 弹窗是否通过 `useFormDialog` 或原页面方式维护。
|
||||||
|
- 多选状态是否通过 `useTableSelection` 或原页面方式维护。
|
||||||
|
- 权限指令是否保持同文件一致,默认使用当前项目主流 `v-hasPermi`。
|
||||||
|
- 导出是否使用 `requestDownload('<module>/<business>/export', { ...queryParams.value }, '<name>_<time>.xlsx')`。
|
||||||
|
- 页面壳是否保留 `search-panel`、`table-panel`、`toolbar-shell`、`data-table`、`right-toolbar`、`pagination`。
|
||||||
|
|
||||||
|
## 推荐提问方式
|
||||||
|
|
||||||
|
推荐把请求描述到下面粒度:
|
||||||
|
|
||||||
|
- 目标模块和业务名
|
||||||
|
- 后端接口前缀
|
||||||
|
- 是新增页面、修改页面,还是只补 API/types
|
||||||
|
- 是否需要导入、导出、树筛选、树表、状态切换、字典、权限按钮
|
||||||
|
- 希望参考哪个现有页面
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
- 使用 `$frontend-crud-coding` 为 `/system/client` 补一套标准 CRUD 页面,参考 `gen` 模板、`demo/demo` 和 `system/client`。
|
||||||
|
- 使用 `$frontend-crud-coding` 修改 `workflow/category` 列表页,增加导出按钮和状态筛选,保持当前 workflow 风格。
|
||||||
7
.codex/skills/frontend-crud-coding/agents/openai.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "前端编码"
|
||||||
|
short_description: "按 plus-ui 6.X-Vue 真实代码和 gen 模板编写前端 CRUD"
|
||||||
|
default_prompt: "使用 $frontend-crud-coding 先读取适用 reference,再按 plus-ui Gitee 仓库 6.X-Vue 分支的真实页面、hooks、API/types 约定和项目内 gen 模板实现前端修改。"
|
||||||
|
|
||||||
|
policy:
|
||||||
|
allow_implicit_invocation: true
|
||||||
126
.codex/skills/frontend-crud-coding/references/examples.md
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
# 使用案例
|
||||||
|
|
||||||
|
## 案例 1:新增标准 CRUD 页面
|
||||||
|
|
||||||
|
### 用户提问示例
|
||||||
|
|
||||||
|
```text
|
||||||
|
使用 $frontend-crud-coding 为 system/client 补一套前端 CRUD 页面。
|
||||||
|
后端接口已经有 /system/client/list、/system/client/{id}、POST /system/client、PUT /system/client、DELETE /system/client/{ids}。
|
||||||
|
请参考 plus-ui Gitee 仓库 6.X-Vue 分支的项目内 gen 模板、src/views/demo/demo/index.vue 和现有 system/client 风格实现。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 期望执行方式
|
||||||
|
|
||||||
|
- 先看 `src/api/system/client/*` 和 `src/views/system/client/index.vue` 是否已存在。
|
||||||
|
- 再看 `src/views/demo/demo/index.vue` 的标准 hooks 版 CRUD 骨架。
|
||||||
|
- 对照项目内 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.vue.ftl`。
|
||||||
|
- 生成或修改 `api/index.ts`、`types.ts`、`views/.../index.vue`。
|
||||||
|
- 使用 `AxiosPromise` from `@/utils/api-types`、`PageResult` from `@/api/types`、`useLoading`、`useFormDialog`、`useSearchReset`、`useTableSelection`。
|
||||||
|
|
||||||
|
## 案例 2:新增树表页面
|
||||||
|
|
||||||
|
### 用户提问示例
|
||||||
|
|
||||||
|
```text
|
||||||
|
使用 $frontend-crud-coding 为 demo/tree2 新增树表 CRUD,接口返回数组,字段包含 id、parentId、name、orderNum。
|
||||||
|
参考 src/views/demo/tree/index.vue 和 workflow/category。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 期望执行方式
|
||||||
|
|
||||||
|
- 优先判断这是树表,不生成分页 `PageResult` 页面。
|
||||||
|
- API 列表返回 `AxiosPromise<Tree2VO[]>`。
|
||||||
|
- `Query` 不继承 `PageQuery`。
|
||||||
|
- 页面使用 `handleTree`、`row-key`、`tree-props`、`useTreeTableExpand`、`el-tree-select`。
|
||||||
|
- 新增子节点时从当前行带入 `parentId`。
|
||||||
|
|
||||||
|
## 案例 3:修改已有复杂列表页
|
||||||
|
|
||||||
|
### 用户提问示例
|
||||||
|
|
||||||
|
```text
|
||||||
|
使用 $frontend-crud-coding 修改 system/user 页面:
|
||||||
|
1. 新增一个创建时间快捷筛选
|
||||||
|
2. 导出按钮保留在更多菜单中
|
||||||
|
3. 保持现有树筛选、导入、列显隐、详情抽屉和角色分配不变
|
||||||
|
```
|
||||||
|
|
||||||
|
### 期望执行方式
|
||||||
|
|
||||||
|
- 判断这是“已有复杂页面增强”,不是重新生成 CRUD。
|
||||||
|
- 优先阅读 `src/views/system/user/index.vue`。
|
||||||
|
- 保留 `TreePanel`、导入弹窗、`right-toolbar` 列显隐、`UserViewDrawer`、角色分配路由、权限控制。
|
||||||
|
- 只增量修改搜索和查询参数处理。
|
||||||
|
|
||||||
|
## 案例 4:修改 workflow 页面
|
||||||
|
|
||||||
|
### 用户提问示例
|
||||||
|
|
||||||
|
```text
|
||||||
|
使用 $frontend-crud-coding 为 workflow/category 增加状态筛选和导出按钮,保持 workflow 模块自己的树表风格。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 期望执行方式
|
||||||
|
|
||||||
|
- 优先看 `src/views/workflow/category/index.vue` 和 `src/api/workflow/category/*`。
|
||||||
|
- 判断是否需要后端新增导出接口;前端导出路径保持 `workflow/category/export`。
|
||||||
|
- 不迁移 system/user 的用户专属逻辑。
|
||||||
|
- 保留树表、`useTreeTableExpand`、`handleTree` 和分类弹窗逻辑。
|
||||||
|
|
||||||
|
## 案例 5:只补 API 和 types
|
||||||
|
|
||||||
|
### 用户提问示例
|
||||||
|
|
||||||
|
```text
|
||||||
|
使用 $frontend-crud-coding 为 monitor/cache 补全前端 API 和 types,页面先不改。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 期望执行方式
|
||||||
|
|
||||||
|
- 只维护 `src/api/monitor/cache/index.ts` 和 `src/api/monitor/cache/types.ts`。
|
||||||
|
- 仍然检查同目录 monitor API 的 `export function` / `export const` 风格。
|
||||||
|
- 返回类型使用 `AxiosPromise` from `@/utils/api-types`。
|
||||||
|
- 不创建页面,不改路由。
|
||||||
|
|
||||||
|
## 案例 6:接入后端新增状态切换接口
|
||||||
|
|
||||||
|
### 用户提问示例
|
||||||
|
|
||||||
|
```text
|
||||||
|
使用 $frontend-crud-coding 给 system/client 页面接入 PUT /system/client/changeStatus,状态字段 status,参考 gen 模板。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 期望执行方式
|
||||||
|
|
||||||
|
- API 增加 `changeClientStatus(id, status)`。
|
||||||
|
- types 确认 `status` 类型是 string、number 还是 boolean。
|
||||||
|
- 表格列用 `el-switch`,active/inactive 值跟后端字段类型一致。
|
||||||
|
- 切换失败时回滚原状态。
|
||||||
|
- 权限使用 `system:client:edit` 或后端实际权限。
|
||||||
|
|
||||||
|
## 推荐的高质量任务描述
|
||||||
|
|
||||||
|
```text
|
||||||
|
使用 $frontend-crud-coding 在当前前端项目中新增 `/system/notice` 列表页增强:
|
||||||
|
1. 保留现有页面
|
||||||
|
2. 新增状态筛选和导出
|
||||||
|
3. API 路径沿用后端接口
|
||||||
|
4. 参考 system/config 的工具栏与导出交互
|
||||||
|
5. 参考 plus-ui Gitee 仓库 6.X-Vue 分支的 gen 模板补齐缺失 types
|
||||||
|
```
|
||||||
|
|
||||||
|
## 不推荐的任务描述
|
||||||
|
|
||||||
|
```text
|
||||||
|
帮我写个后台页面
|
||||||
|
```
|
||||||
|
|
||||||
|
更好的写法至少补充:
|
||||||
|
|
||||||
|
- 模块名
|
||||||
|
- 业务名
|
||||||
|
- 后端接口前缀
|
||||||
|
- 是新增还是修改
|
||||||
|
- 是否需要分页、导出、树表、字典、权限
|
||||||
|
- 想参考哪个现有页面
|
||||||
156
.codex/skills/frontend-crud-coding/references/frontend.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
# 前端约定
|
||||||
|
|
||||||
|
## 优先参考的代码来源
|
||||||
|
|
||||||
|
- 默认远端基线:`https://gitee.com/JavaLionLi/plus-ui`,分支 `6.X-Vue`。引用远端文件时必须同时写明 `branch=6.X-Vue` 和仓库内路径。
|
||||||
|
- 当前目标目录下最近似页面、API、types。
|
||||||
|
- 标准单表:`src/views/demo/demo/index.vue`、`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/views/system/user/index.vue`、`src/views/system/role/index.vue`、`src/views/system/post/index.vue`、`src/views/system/config/index.vue`。
|
||||||
|
- workflow 页:`src/views/workflow/*`、`src/api/workflow/*`。
|
||||||
|
- 监控页:`src/views/monitor/*`、`src/api/monitor/*`。
|
||||||
|
- 公共 hooks:`src/hooks/async/useLoading.ts`、`src/hooks/dialog/*`、`src/hooks/form/*`、`src/hooks/table/*`、`src/hooks/tree/*`。
|
||||||
|
- 项目内 generator 模板:
|
||||||
|
`gen/api.ts.ftl`
|
||||||
|
`gen/types.ts.ftl`
|
||||||
|
`gen/index.vue.ftl`
|
||||||
|
`gen/index-tree.vue.ftl`
|
||||||
|
|
||||||
|
## 基础栈与格式
|
||||||
|
|
||||||
|
- 技术栈是 Vue 3 + TypeScript + Element Plus + Vite + Pinia。
|
||||||
|
- 包管理按仓库现状使用 pnpm。
|
||||||
|
- `.editorconfig` 要求 UTF-8、LF、2 空格缩进。
|
||||||
|
- 当前仓库没有 `.prettierrc`;格式化使用 `pnpm run fmt`,lint 使用 `pnpm lint`。
|
||||||
|
- 不要在一个页面里混入与仓库不一致的格式和写法。
|
||||||
|
- 不要把本机绝对路径写进 skill 输出或参考文档;跨环境参考统一使用 Gitee 仓库 URL、分支和仓库内相对路径。
|
||||||
|
|
||||||
|
## API 文件规则
|
||||||
|
|
||||||
|
- 标准 API 文件放在 `src/api/<module>/<business>/index.ts`,同目录维护 `types.ts`。
|
||||||
|
- import 顺序优先跟随附近文件,标准生成页常见形式:
|
||||||
|
`import type { XxxForm, XxxQuery, XxxVO } from '@/api/<module>/<business>/types';`
|
||||||
|
`import type { PageResult } from '@/api/types';`
|
||||||
|
`import type { AxiosPromise } from '@/utils/api-types';`
|
||||||
|
`import request from '@/utils/request';`
|
||||||
|
- 不要从 `axios` 引入 `AxiosPromise`。
|
||||||
|
- 列表分页接口通常返回 `AxiosPromise<PageResult<XxxVO>>`。
|
||||||
|
- 树表列表接口通常返回 `AxiosPromise<XxxVO[]>`。
|
||||||
|
- 详情接口返回 `AxiosPromise<XxxVO>`;复杂详情返回单独的 `InfoVO`。
|
||||||
|
- 标准函数命名:
|
||||||
|
`listXxx` -> `GET /<module>/<business>/list`
|
||||||
|
`getXxx` -> `GET /<module>/<business>/{id}`
|
||||||
|
`addXxx` -> `POST /<module>/<business>`
|
||||||
|
`updateXxx` -> `PUT /<module>/<business>`
|
||||||
|
`delXxx` -> `DELETE /<module>/<business>/{id or ids}`
|
||||||
|
`changeXxxStatus` -> `PUT /<module>/<business>/changeStatus`
|
||||||
|
- query string 用 `params`,请求体用 `data`。
|
||||||
|
- 加密、防重复提交等 headers 直接写在请求配置里,例如用户重置密码中的 `isEncrypt`、`repeatSubmit`。
|
||||||
|
- 当前仓库有些 API 使用 `export const`,有些使用 `export function`;新增标准 CRUD 优先跟随 `gen/api.ts.ftl` 和相邻模块。
|
||||||
|
- 只有相邻模块已有 `export default { ... }` 聚合时才新增默认导出。
|
||||||
|
|
||||||
|
## 类型文件规则
|
||||||
|
|
||||||
|
- 标准类型定义 `VO`、`Form`、`Query`,必要时补 `InfoVO`、`TreeVO`、`ResetPwdForm` 等扩展类型。
|
||||||
|
- `Form` 通常继承 `BaseEntity`。
|
||||||
|
- 非树表 `Query` 通常继承 `PageQuery`。
|
||||||
|
- 树表 `Query` 通常不继承 `PageQuery`。
|
||||||
|
- ID 字段通常使用 `string | number`,批量删除参数使用 `string | number | Array<string | number>`。
|
||||||
|
- Java 数值类型映射为 `number`,Boolean 映射为 `boolean`,日期/文本默认 `string`。
|
||||||
|
- 日期范围查询保留 `params?: any`,不要因为它看起来宽松就删掉。
|
||||||
|
- 列表对象、表单对象、查询对象职责分开;字段不一致时不要强行复用一个接口。
|
||||||
|
- 能明确写出类型时不要用 `any`;组件库、字典或历史接口确实无法收窄时再保留。
|
||||||
|
|
||||||
|
## Vue 页面结构规则
|
||||||
|
|
||||||
|
- 页面优先使用 `<script setup name="Xxx" lang="ts">`。
|
||||||
|
- 标准根节点使用 `class="p-2 app-container <module>-<business>-page"`;已有页面是特殊布局时保持原样。
|
||||||
|
- 标准列表页结构:
|
||||||
|
搜索卡片 `search-panel`
|
||||||
|
表格卡片 `table-panel`
|
||||||
|
工具栏 `toolbar-shell`
|
||||||
|
表格 `data-table`
|
||||||
|
`right-toolbar`
|
||||||
|
`pagination`
|
||||||
|
新增/编辑 `el-dialog`
|
||||||
|
- 搜索区通过 `useSearchToggle` 控制 `showSearch`,头部点击切换。
|
||||||
|
- 列表 loading 通过 `useLoading(true)` 和 `withLoading`。
|
||||||
|
- 选择状态通过 `useTableSelection<XxxVO>(item => item.id)` 返回 `ids`、`single`、`multiple`、`handleSelectionChange`。
|
||||||
|
- 表单弹窗优先使用 `useFormDialog({ form, formRef, initialFormData })`,返回 `dialog`、`resetForm`、`openDialog`、`showDialog`、`closeDialog`。
|
||||||
|
- 仅需要简单弹窗状态或一个页面多个弹窗时使用 `useDialogState`。
|
||||||
|
- 日期范围查询优先使用 `useDateRangeQuery()`;带后端参数名时使用 `useDateRangeQuery('CreateTime')` 等相邻页面模式。
|
||||||
|
- 查询和表单状态通常放在 `reactive<PageData<Form, Query>>({ form, queryParams, rules })`,再 `toRefs(data)`。
|
||||||
|
|
||||||
|
## 页面行为规则
|
||||||
|
|
||||||
|
- `getList` 负责设置 loading、调用列表接口、回填列表和 `total`。
|
||||||
|
- `handleQuery` 先把 `queryParams.value.pageNum = 1`,再调用 `getList()`;树表无分页时只调用 `getList()`。
|
||||||
|
- `resetQuery` 使用 `useSearchReset`,分页页传 `pageNumKey: 'pageNum'`,需要时传 `pageSizeKey` 和 `resetExtras`。
|
||||||
|
- `handleAdd` 使用 `openDialog('添加xxx')`;如果有树/联动选项,打开前后按现有页面加载选项。
|
||||||
|
- `handleUpdate` 先 `reset()`,再按行或 `ids.value[0]` 查详情,`Object.assign(form.value, res.data)`,最后 `showDialog('修改xxx')`。
|
||||||
|
- `submitForm` 表单校验通过后设置 `buttonLoading`,根据主键判断新增或修改,成功后 `modal.msgSuccess('操作成功')`、关闭弹窗、刷新列表。
|
||||||
|
- `handleDelete` 使用 `modal.confirm(...)` 二次确认,再调用删除接口,成功提示并刷新。
|
||||||
|
- `handleExport` 使用 `requestDownload('<module>/<business>/export', { ...queryParams.value }, '<business>_<timestamp>.xlsx')`。
|
||||||
|
- 状态切换失败时要把 switch 值回滚,参考 generator 模板和现有 `system/user`、`system/role`。
|
||||||
|
- 导入上传使用 `globalHeaders()`、`import.meta.env.VITE_APP_BASE_API`、`ElUpload`,优先参考 `system/user` 或流程定义页面。
|
||||||
|
|
||||||
|
## 字典、权限与公共工具
|
||||||
|
|
||||||
|
- 字典使用 `useDict`:
|
||||||
|
`const { sys_normal_disable } = toRefs<any>(useDict('sys_normal_disable'));`
|
||||||
|
- 新增代码默认使用当前项目主流 `v-hasPermi`。
|
||||||
|
- 如果正在修改的文件已经混用或使用 `v-has-permi`,保持同文件现状,不为统一写法而重排无关代码。
|
||||||
|
- `el-dropdown-item` 延迟加载导致权限指令不可靠时,使用 `v-if="checkPermi([...])"`,参考 `system/user`。
|
||||||
|
- 常用工具:
|
||||||
|
`modal` from `@/plugins/modal`
|
||||||
|
`download as requestDownload` from `@/utils/request`
|
||||||
|
`useDict` from `@/utils/dict`
|
||||||
|
`checkPermi` from `@/utils/permission`
|
||||||
|
`handleTree`、`parseStrEmpty` from `@/utils/ruoyi`
|
||||||
|
|
||||||
|
## 组件与样式规则
|
||||||
|
|
||||||
|
- 优先复用公共组件:`right-toolbar`、`pagination`、`DictTag` / `dict-tag`、`ImageUpload` / `image-upload`、`ImagePreview` / `image-preview`、`FileUpload` / `file-upload`、`Editor` / `editor`、`TreePanel`。
|
||||||
|
- 标准页面尽量使用已有页面壳类,不堆大量内联样式。
|
||||||
|
- 复杂页面需要 scoped SCSS 时优先复用:
|
||||||
|
`@use '@/assets/styles/components/page-shell' as pageShell;`
|
||||||
|
再按现有 mixin 使用。
|
||||||
|
- 不要为了单页需求修改全局组件样式。
|
||||||
|
- 类名保持模块语义:`system-client-page`、`workflow-category-page`、`demo-demo-page`。
|
||||||
|
|
||||||
|
## 树表规则
|
||||||
|
|
||||||
|
- 树表列表接口通常返回数组,页面通过 `handleTree<T>(res.data, 'id', 'parentId')` 组树。
|
||||||
|
- 使用 `row-key`、`:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"`。
|
||||||
|
- 展开/折叠使用 `useTreeTableExpand`。
|
||||||
|
- 表单中上级节点使用 `el-tree-select`。
|
||||||
|
- 新增子节点时从当前行回填 `parentId`。
|
||||||
|
- 删除确认文案优先使用业务名称,而不是批量 ID 文案。
|
||||||
|
|
||||||
|
## 与 gen 模板的关系
|
||||||
|
|
||||||
|
- `gen` 是 plus-ui 前端项目内的生成模板;默认远端位置是 `https://gitee.com/JavaLionLi/plus-ui/tree/6.X-Vue/gen`,分支必须标记为 `6.X-Vue`。
|
||||||
|
- 本地仓库存在对应文件时优先读本地 `gen`,但不要把本地绝对路径写入 skill 或交付内容。
|
||||||
|
- 新增标准单表页面时读取 `gen/index.vue.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl`。
|
||||||
|
- 新增树表页面时读取 `gen/index-tree.vue.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl`。
|
||||||
|
- `gen` 模板是标准骨架,不是最终答案;落地时仍要对照目标模块真实页面和公共 hooks。
|
||||||
|
- 当前前端项目已经把生成页升级为 hooks 版:`useLoading`、`useFormDialog`、`useSearchReset`、`useTableSelection`、`useDateRangeQuery`。
|
||||||
|
- 新增标准 CRUD 时,先从 `gen` 确认字段、权限、导出、状态切换、排序、日期范围等,再落成当前项目的实际页面壳。
|
||||||
|
- 修改已有页面时,不要把现有强业务逻辑替换回 `gen` 的简化逻辑。
|
||||||
|
|
||||||
|
## 验证规则
|
||||||
|
|
||||||
|
- 只改文档或 skill:运行 skill 基础校验即可。
|
||||||
|
- 改前端 TS/Vue/API/types:优先运行 `pnpm exec vue-tsc --noEmit`。
|
||||||
|
- 改页面模板、import、权限或较多文件:再运行 `pnpm lint`。
|
||||||
|
- 改公共 hooks、组件、构建相关或大范围页面:再运行 `pnpm build`。
|
||||||
|
- 如果验证因为环境、依赖或权限失败,交付时说明失败命令和原因。
|
||||||
|
|
||||||
|
## 避免事项
|
||||||
|
|
||||||
|
- 不要从 `axios` 引入 `AxiosPromise`。
|
||||||
|
- 不要绕开 `request` 或 `requestDownload` 自造请求/下载封装。
|
||||||
|
- 不要跳过 `types.ts`,把类型全写在页面里。
|
||||||
|
- 不要删除日期范围 `params`、权限指令、导出、导入、树筛选、列显隐等现有能力。
|
||||||
|
- 不要为了“更整洁”重写复杂页面的大块业务逻辑。
|
||||||
|
- 不要在新增标准页里使用与仓库不一致的 UI 壳或状态管理方式。
|
||||||
21
.editorconfig
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# 告诉EditorConfig插件,这是根文件,不用继续往上查找
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# 匹配全部文件
|
||||||
|
[*]
|
||||||
|
# 缩进风格,可选space、tab
|
||||||
|
indent_style = space
|
||||||
|
# 缩进的空格数
|
||||||
|
indent_size = 2
|
||||||
|
# 设置字符集
|
||||||
|
charset = utf-8
|
||||||
|
# 结尾换行符,可选lf、cr、crlf
|
||||||
|
end_of_line = lf
|
||||||
|
# 在文件结尾插入新行
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
# 删除一行中的前后空格
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
insert_final_newline = false
|
||||||
|
trim_trailing_whitespace = false
|
||||||
42
.env.development
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = 智净云 · 智能家居管理后台
|
||||||
|
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
|
||||||
|
|
||||||
|
# 开发环境配置
|
||||||
|
VITE_APP_ENV = 'development'
|
||||||
|
|
||||||
|
# 开发环境
|
||||||
|
VITE_APP_BASE_API = '/dev-api'
|
||||||
|
|
||||||
|
# 应用访问路径 例如使用前缀 /admin/
|
||||||
|
VITE_APP_CONTEXT_PATH = '/'
|
||||||
|
|
||||||
|
# 监控地址
|
||||||
|
VITE_APP_MONITOR_ADMIN = 'http://localhost:9090/admin/applications'
|
||||||
|
|
||||||
|
# SnailJob 控制台地址
|
||||||
|
VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job'
|
||||||
|
|
||||||
|
# SnailAI 控制台地址
|
||||||
|
VITE_APP_SNAILAI_ADMIN = 'http://localhost:8900/snail-ai'
|
||||||
|
|
||||||
|
VITE_APP_PORT = 54123
|
||||||
|
|
||||||
|
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
||||||
|
VITE_APP_ENCRYPT = true
|
||||||
|
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||||
|
VITE_APP_RSA_PUBLIC_KEY = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB'
|
||||||
|
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
||||||
|
VITE_APP_RSA_PRIVATE_KEY = 'MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAObq7yrxfvyieZtTjAYyrdvi59tYTXxjO5ajmPCRSXBY9M9wQ1tli297JN6mnY53UJMNyOFNSZVi8WSFoIXjpR87FmvChJlzeN/dZdd3SEs48Ee66XKeSePYqxa8oO5GKDsnajgpsOHKXSeeVSIysiIPS2/WsEqk0In9P4w3RsRFAgMBAAECgYBiMEWwce24SPICnRzuScBpvmsudrbEDIH7BOd0a6LZlcnLJwZNJ7mJlshPsHNQb+WgEf135+BBGEhioPtn0yuTdEuKP4kB9UdYUKiayWCoWhJpesv7sAD4RDClV7dhuV+gcd1AXD+YzyRIPbGm0VC2U+4q8/+UPRpVjqskbLVTgQJBAPRpou7g3S8n4XB527kq0D8I3+ZYwMxZhszwhrCDpJU319+ucmpLVwYIzDmZVeID2QQdUaDfIEViFHu95xDrGiUCQQDx3YOKn3yaEctk/ERVn7hDAyAXUbd8/pv2b24/M/l1ZevlsFem8U4Jk5Mu64t3z3YGJoymEjQmbucwT01iKhehAkEAxlnccsRmfFh/KkqauKE4M4++NTAd9zlInpUsmZ+cN8UEGnF2RTEzRKBrLOt1uWCqBB7PGiE6DVTVjr7FAQPrSQJAT5yeY87DcONSk9cFlzmPqV8p/QME5rvYEnHzVBKDlkUKNPyqnWToTvaoh9U4fyNmsfeWbEOprszqhFhWHG3GgQJAK8+ynmyFhaw63+Hx2KU5zR4hVuQso2IzrEurGxCxybV6mR7VBerb4502+EPx3PmOgxQL+niUFhcMWxcvBFP9+A=='
|
||||||
|
|
||||||
|
# 客户端id
|
||||||
|
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||||
|
|
||||||
|
# 统一消息推送开关
|
||||||
|
VITE_APP_MESSAGE_ENABLED = true
|
||||||
|
|
||||||
|
# sse / websocket
|
||||||
|
VITE_APP_MESSAGE_TRANSPORT = 'sse'
|
||||||
|
|
||||||
|
# 统一消息推送路径
|
||||||
|
VITE_APP_MESSAGE_PATH = '/resource/message'
|
||||||
45
.env.production
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
|
||||||
|
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
|
||||||
|
|
||||||
|
# 生产环境配置
|
||||||
|
VITE_APP_ENV = 'production'
|
||||||
|
|
||||||
|
# 应用访问路径 例如使用前缀 /admin/
|
||||||
|
VITE_APP_CONTEXT_PATH = '/'
|
||||||
|
|
||||||
|
# 监控地址
|
||||||
|
VITE_APP_MONITOR_ADMIN = '/admin/applications'
|
||||||
|
|
||||||
|
# SnailJob 控制台地址
|
||||||
|
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
|
||||||
|
|
||||||
|
# SnailAI 控制台地址
|
||||||
|
VITE_APP_SNAILAI_ADMIN = '/snail-ai'
|
||||||
|
|
||||||
|
# 生产环境
|
||||||
|
VITE_APP_BASE_API = '/prod-api'
|
||||||
|
|
||||||
|
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||||
|
VITE_BUILD_COMPRESS = gzip
|
||||||
|
|
||||||
|
VITE_APP_PORT = 80
|
||||||
|
|
||||||
|
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
||||||
|
VITE_APP_ENCRYPT = true
|
||||||
|
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||||
|
VITE_APP_RSA_PUBLIC_KEY = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB'
|
||||||
|
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
||||||
|
VITE_APP_RSA_PRIVATE_KEY = 'MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAObq7yrxfvyieZtTjAYyrdvi59tYTXxjO5ajmPCRSXBY9M9wQ1tli297JN6mnY53UJMNyOFNSZVi8WSFoIXjpR87FmvChJlzeN/dZdd3SEs48Ee66XKeSePYqxa8oO5GKDsnajgpsOHKXSeeVSIysiIPS2/WsEqk0In9P4w3RsRFAgMBAAECgYBiMEWwce24SPICnRzuScBpvmsudrbEDIH7BOd0a6LZlcnLJwZNJ7mJlshPsHNQb+WgEf135+BBGEhioPtn0yuTdEuKP4kB9UdYUKiayWCoWhJpesv7sAD4RDClV7dhuV+gcd1AXD+YzyRIPbGm0VC2U+4q8/+UPRpVjqskbLVTgQJBAPRpou7g3S8n4XB527kq0D8I3+ZYwMxZhszwhrCDpJU319+ucmpLVwYIzDmZVeID2QQdUaDfIEViFHu95xDrGiUCQQDx3YOKn3yaEctk/ERVn7hDAyAXUbd8/pv2b24/M/l1ZevlsFem8U4Jk5Mu64t3z3YGJoymEjQmbucwT01iKhehAkEAxlnccsRmfFh/KkqauKE4M4++NTAd9zlInpUsmZ+cN8UEGnF2RTEzRKBrLOt1uWCqBB7PGiE6DVTVjr7FAQPrSQJAT5yeY87DcONSk9cFlzmPqV8p/QME5rvYEnHzVBKDlkUKNPyqnWToTvaoh9U4fyNmsfeWbEOprszqhFhWHG3GgQJAK8+ynmyFhaw63+Hx2KU5zR4hVuQso2IzrEurGxCxybV6mR7VBerb4502+EPx3PmOgxQL+niUFhcMWxcvBFP9+A=='
|
||||||
|
|
||||||
|
# 客户端id
|
||||||
|
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||||
|
|
||||||
|
# 统一消息推送开关
|
||||||
|
VITE_APP_MESSAGE_ENABLED = true
|
||||||
|
|
||||||
|
# sse / websocket
|
||||||
|
VITE_APP_MESSAGE_TRANSPORT = 'sse'
|
||||||
|
|
||||||
|
# 统一消息推送路径
|
||||||
|
VITE_APP_MESSAGE_PATH = '/resource/message'
|
||||||
29
.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
.DS_Store
|
||||||
|
.history
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
**/*.log
|
||||||
|
|
||||||
|
tests/**/coverage/
|
||||||
|
tests/e2e/reports
|
||||||
|
selenium-debug.log
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.iml
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.local
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# 编译生成的文件
|
||||||
|
auto-imports.d.ts
|
||||||
|
components.d.ts
|
||||||
31
.oxfmtrc.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||||
|
"ignorePatterns": [
|
||||||
|
"src/types/components.d.ts",
|
||||||
|
"src/types/auto-imports.d.ts",
|
||||||
|
".ai_state",
|
||||||
|
".claude",
|
||||||
|
".codex",
|
||||||
|
"doc"
|
||||||
|
],
|
||||||
|
"printWidth": 120,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"htmlWhitespaceSensitivity": "ignore",
|
||||||
|
"experimentalSortPackageJson": {
|
||||||
|
"sortScripts": true
|
||||||
|
},
|
||||||
|
"sortImports": {
|
||||||
|
"newlinesBetween": false,
|
||||||
|
"groups": [
|
||||||
|
"type-import",
|
||||||
|
["value-builtin", "value-external"],
|
||||||
|
"type-internal",
|
||||||
|
"value-internal",
|
||||||
|
["type-parent", "type-sibling", "type-index"],
|
||||||
|
["value-parent", "value-sibling", "value-index"],
|
||||||
|
"unknown"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
25
.oxlintrc.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
|
||||||
|
"plugins": ["eslint", "typescript", "unicorn", "oxc", "import", "vue"],
|
||||||
|
"rules": {
|
||||||
|
"typescript/no-empty-function": "off",
|
||||||
|
"typescript/no-explicit-any": "off",
|
||||||
|
"typescript/no-unused-vars": "off",
|
||||||
|
"typescript/no-this-alias": "off",
|
||||||
|
"typescript/no-empty-object-type": "off",
|
||||||
|
"typescript/no-unused-expressions": "off",
|
||||||
|
"prefer-rest-params": "off",
|
||||||
|
"import/no-unassigned-import": "off",
|
||||||
|
"import/no-named-as-default-member": "off",
|
||||||
|
"import/no-named-as-default": "off",
|
||||||
|
"no-shadow": "off",
|
||||||
|
"unicorn/prefer-add-event-listener": "off",
|
||||||
|
"unicorn/consistent-function-scoping": "off",
|
||||||
|
"unicorn/no-instanceof-builtins": "off"
|
||||||
|
},
|
||||||
|
"categories": {
|
||||||
|
"correctness": "error",
|
||||||
|
"suspicious": "error"
|
||||||
|
},
|
||||||
|
"ignorePatterns": [".ai_state", ".claude", ".codex", "doc", "dist/**", "dist-ssr/**", "coverage/**"]
|
||||||
|
}
|
||||||
20
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.
|
||||||
76
README.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
## 平台简介
|
||||||
|
|
||||||
|
- 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [TS](https://www.typescriptlang.org/) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
|
||||||
|
- 官方项目: 基于 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)
|
||||||
|
- 成员项目: 基于soybean 的前端项目 [ruoyi-plus-soybean](https://gitee.com/xlsea/ruoyi-plus-soybean)
|
||||||
|
|
||||||
|
## 配套后端代码仓库地址
|
||||||
|
|
||||||
|
| 介绍 | 项目名 | 项目地址 |
|
||||||
|
| ----------------- | :--------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| 🔥 分布式集群框架 | 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)<br>- [GitHub](https://github.com/dromara/RuoYi-Cloud-Plus)<br> - [GitCode](https://gitcode.com/dromara/RuoYi-Cloud-Plus) |
|
||||||
|
|
||||||
|
## 分支说明
|
||||||
|
|
||||||
|
- 6.X分支(稳定发布主分支 生产可用)
|
||||||
|
- dev分支(开发分支 开发过程中使用)
|
||||||
|
|
||||||
|
## 前端运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 安装依赖
|
||||||
|
pnpm install --registry=https://registry.npmmirror.com
|
||||||
|
|
||||||
|
# 启动服务
|
||||||
|
pnpm dev
|
||||||
|
|
||||||
|
# 构建生产环境
|
||||||
|
pnpm build:prod
|
||||||
|
|
||||||
|
# 前端访问地址 http://localhost:80
|
||||||
|
```
|
||||||
|
|
||||||
|
## 本框架与RuoYi的业务差异
|
||||||
|
|
||||||
|
| 业务 | 功能说明 | 本框架 | RuoYi |
|
||||||
|
| ------------ | ------------------------------------------------------------- | ------ | ----------------------------- |
|
||||||
|
| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 |
|
||||||
|
| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 |
|
||||||
|
| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 |
|
||||||
|
| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 |
|
||||||
|
| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 |
|
||||||
|
| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 |
|
||||||
|
| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 |
|
||||||
|
| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 |
|
||||||
|
| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 |
|
||||||
|
| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 |
|
||||||
|
| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 |
|
||||||
|
| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 |
|
||||||
|
| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 |
|
||||||
|
| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 |
|
||||||
|
| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 |
|
||||||
|
| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 |
|
||||||
|
| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 |
|
||||||
|
| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 |
|
||||||
|
| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 |
|
||||||
|
| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 |
|
||||||
|
|
||||||
|
## 演示图例
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
|
|  |  |
|
||||||
104
gen/api.ts.ftl
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
||||||
|
<#if !table.tree>
|
||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
</#if>
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询${functionName}列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const list${BusinessName} = (query?: ${BusinessName}Query): AxiosPromise<<#if table.tree>${BusinessName}VO[]<#else>PageResult<${BusinessName}VO></#if>> => {
|
||||||
|
return request({
|
||||||
|
url: '/${moduleName}/${businessName}/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询${functionName}详细
|
||||||
|
* @param ${pkColumn.javaField}
|
||||||
|
*/
|
||||||
|
export const get${BusinessName} = (${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> => {
|
||||||
|
return request({
|
||||||
|
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增${functionName}
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const add${BusinessName} = (data: ${BusinessName}Form) => {
|
||||||
|
return request({
|
||||||
|
url: '/${moduleName}/${businessName}',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改${functionName}
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const update${BusinessName} = (data: ${BusinessName}Form) => {
|
||||||
|
return request({
|
||||||
|
url: '/${moduleName}/${businessName}',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
<#if enableStatus>
|
||||||
|
/**
|
||||||
|
* 修改${functionName}状态
|
||||||
|
* @param ${pkColumn.javaField}
|
||||||
|
* @param status
|
||||||
|
*/
|
||||||
|
export const change${BusinessName}Status = (${pkColumn.javaField}: string | number, status: <#if statusColumn.javaType == 'Boolean'>boolean<#elseif statusColumn.javaType == 'String'>string<#else> number</#if>) => {
|
||||||
|
return request({
|
||||||
|
url: '/${moduleName}/${businessName}/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
${pkColumn.javaField},
|
||||||
|
${statusField}: status
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if enableSort>
|
||||||
|
/**
|
||||||
|
* 调整${functionName}排序
|
||||||
|
* @param ${pkColumn.javaField}
|
||||||
|
* @param sortValue
|
||||||
|
*/
|
||||||
|
export const update${BusinessName}Sort = (${pkColumn.javaField}: string | number, sortValue: <#if sortColumn.javaType == 'String' || sortColumn.javaType == 'LocalDateTime'>string<#else> number</#if>) => {
|
||||||
|
return request({
|
||||||
|
url: '/${moduleName}/${businessName}/updateSort',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
${pkColumn.javaField},
|
||||||
|
${sortField}: sortValue
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除${functionName}
|
||||||
|
* @param ${pkColumn.javaField}
|
||||||
|
*/
|
||||||
|
export const del${BusinessName} = (${pkColumn.javaField}: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
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>
|
||||||
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>
|
||||||
|
|
||||||
48
gen/types.ts.ftl
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
export interface ${BusinessName}VO {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.list>
|
||||||
|
/**
|
||||||
|
* ${column.columnComment}
|
||||||
|
*/
|
||||||
|
${column.javaField}: ${column.tsType};
|
||||||
|
<#if column.htmlType == "imageUpload">
|
||||||
|
/**
|
||||||
|
* ${column.columnComment}Url
|
||||||
|
*/
|
||||||
|
${column.javaField}Url: string;
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#if table.tree>
|
||||||
|
/**
|
||||||
|
* 子对象
|
||||||
|
*/
|
||||||
|
children: ${BusinessName}VO[];
|
||||||
|
</#if>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ${BusinessName}Form extends BaseEntity {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.insert || column.edit>
|
||||||
|
/**
|
||||||
|
* ${column.columnComment}
|
||||||
|
*/
|
||||||
|
${column.javaField}?: ${column.tsType};
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ${BusinessName}Query<#if !table.tree> extends PageQuery</#if> {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query>
|
||||||
|
/**
|
||||||
|
* ${column.columnComment}
|
||||||
|
*/
|
||||||
|
${column.javaField}?: ${column.tsType};
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
/**
|
||||||
|
* 日期范围参数
|
||||||
|
*/
|
||||||
|
params?: any;
|
||||||
|
}
|
||||||
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>
|
||||||
82
package.json
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/package",
|
||||||
|
"name": "ruoyi-vue-plus",
|
||||||
|
"version": "6.0.0",
|
||||||
|
"description": "RuoYi-Vue-Plus后台管理系统",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "LionLi",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitee.com/JavaLionLi/plus-ui.git"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.34.5",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "vite build --mode production",
|
||||||
|
"build:dev": "vite build --mode development",
|
||||||
|
"build:prod": "vite build --mode production",
|
||||||
|
"dev": "vite serve --mode development",
|
||||||
|
"fmt": "oxfmt .",
|
||||||
|
"lint": "oxlint src",
|
||||||
|
"lint:fix": "oxlint --fix src",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@element-plus/icons-vue": "2.3.2",
|
||||||
|
"@highlightjs/vue-plugin": "2.1.2",
|
||||||
|
"@iconify/vue": "^5.0.1",
|
||||||
|
"@noble/ciphers": "^2.4.0",
|
||||||
|
"@vueuse/core": "14.4.0",
|
||||||
|
"@wangeditor-next/editor": "6.4.1",
|
||||||
|
"@wangeditor-next/editor-for-vue": "6.4.1",
|
||||||
|
"animate.css": "4.1.1",
|
||||||
|
"await-to-js": "3.0.0",
|
||||||
|
"axios": "1.20.0",
|
||||||
|
"echarts": "6.1.0",
|
||||||
|
"element-plus": "2.14.5",
|
||||||
|
"highlight.js": "11.12.0",
|
||||||
|
"image-conversion": "2.1.1",
|
||||||
|
"jsencrypt": "3.5.4",
|
||||||
|
"nprogress": "0.2.0",
|
||||||
|
"pinia": "4.0.3",
|
||||||
|
"vue": "3.5.42",
|
||||||
|
"vue-cropper": "1.1.4",
|
||||||
|
"vue-i18n": "11.4.10",
|
||||||
|
"vue-json-pretty": "2.6.0",
|
||||||
|
"vue-router": "5.3.1",
|
||||||
|
"vue-types": "7.0.0",
|
||||||
|
"vxe-pc-ui": "4.18.9",
|
||||||
|
"vxe-table": "4.21.9"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^26.1.1",
|
||||||
|
"@types/nprogress": "0.2.3",
|
||||||
|
"@unocss/preset-attributify": "66.10.1",
|
||||||
|
"@unocss/preset-wind3": "66.10.1",
|
||||||
|
"@vitejs/plugin-vue": "^6.0.8",
|
||||||
|
"@vue/compiler-sfc": "3.5.42",
|
||||||
|
"autoprefixer": "10.5.5",
|
||||||
|
"oxfmt": "^0.67.0",
|
||||||
|
"oxlint": "^1.82.0",
|
||||||
|
"sass": "1.104.0",
|
||||||
|
"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": {
|
||||||
|
"node": ">=20.19.0",
|
||||||
|
"pnpm": ">=10.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
4898
pnpm-lock.yaml
generated
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
|
||||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
258
public/ie.html
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
@@ -0,0 +1,48 @@
|
|||||||
|
// 前缀
|
||||||
|
const animatePrefix = 'animate__animated ';
|
||||||
|
// 开启随机动画 随机动画值
|
||||||
|
const animateList: string[] = [
|
||||||
|
animatePrefix + 'animate__pulse',
|
||||||
|
animatePrefix + 'animate__rubberBand',
|
||||||
|
animatePrefix + 'animate__bounceIn',
|
||||||
|
animatePrefix + 'animate__bounceInLeft',
|
||||||
|
animatePrefix + 'animate__fadeIn',
|
||||||
|
animatePrefix + 'animate__fadeInLeft',
|
||||||
|
animatePrefix + 'animate__fadeInDown',
|
||||||
|
animatePrefix + 'animate__fadeInUp',
|
||||||
|
animatePrefix + 'animate__flipInX',
|
||||||
|
animatePrefix + 'animate__lightSpeedInLeft',
|
||||||
|
animatePrefix + 'animate__rotateInDownLeft',
|
||||||
|
animatePrefix + 'animate__rollIn',
|
||||||
|
animatePrefix + 'animate__rotateInDownLeft',
|
||||||
|
animatePrefix + 'animate__zoomIn',
|
||||||
|
animatePrefix + 'animate__zoomInDown',
|
||||||
|
animatePrefix + 'animate__slideInLeft',
|
||||||
|
animatePrefix + 'animate__lightSpeedIn'
|
||||||
|
];
|
||||||
|
// 关闭随机动画后的默认效果
|
||||||
|
const defaultAnimate = animatePrefix + 'animate__fadeIn';
|
||||||
|
// 搜索隐藏显示动画
|
||||||
|
const searchAnimate = {
|
||||||
|
enter: '',
|
||||||
|
leave: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// 菜单搜索动画
|
||||||
|
const menuSearchAnimate = {
|
||||||
|
enter: animatePrefix + 'animate__fadeIn',
|
||||||
|
leave: animatePrefix + 'animate__fadeOut'
|
||||||
|
};
|
||||||
|
// logo动画
|
||||||
|
const logoAnimate = {
|
||||||
|
enter: animatePrefix + 'animate__fadeIn',
|
||||||
|
leave: animatePrefix + 'animate__fadeOut'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
animateList,
|
||||||
|
defaultAnimate,
|
||||||
|
searchAnimate,
|
||||||
|
menuSearchAnimate,
|
||||||
|
logoAnimate
|
||||||
|
};
|
||||||
10
src/api/ai/agent/index.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { SnailOpenApiUser } from './types';
|
||||||
|
|
||||||
|
export const registerCurrentSnailUser = (): AxiosPromise<SnailOpenApiUser> => {
|
||||||
|
return request({
|
||||||
|
url: '/snail-ai/user/register',
|
||||||
|
method: 'post'
|
||||||
|
});
|
||||||
|
};
|
||||||
6
src/api/ai/agent/types.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export interface SnailOpenApiUser {
|
||||||
|
openId: string;
|
||||||
|
nickname?: string;
|
||||||
|
externalId?: string;
|
||||||
|
created?: boolean;
|
||||||
|
}
|
||||||
2
src/api/ai/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './agent';
|
||||||
|
export * from './agent/types';
|
||||||
63
src/api/demo/demo/index.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import type { DemoForm, DemoQuery, DemoVO } from '@/api/demo/demo/types';
|
||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询测试单列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const listDemo = (query?: DemoQuery): AxiosPromise<PageResult<DemoVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询测试单详细
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getDemo = (id: string | number): AxiosPromise<DemoVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增测试单
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addDemo = (data: DemoForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改测试单
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateDemo = (data: DemoForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除测试单
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delDemo = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
90
src/api/demo/demo/types.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
export interface DemoVO {
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
id: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
|
deptId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
userId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序号
|
||||||
|
*/
|
||||||
|
orderNum: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key键
|
||||||
|
*/
|
||||||
|
testKey: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DemoForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
|
deptId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
userId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序号
|
||||||
|
*/
|
||||||
|
orderNum?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key键
|
||||||
|
*/
|
||||||
|
testKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DemoQuery extends PageQuery {
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
|
deptId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
userId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序号
|
||||||
|
*/
|
||||||
|
orderNum?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key键
|
||||||
|
*/
|
||||||
|
testKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
62
src/api/demo/tree/index.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import type { TreeForm, TreeQuery, TreeVO } from '@/api/demo/tree/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询测试树列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const listTree = (query?: TreeQuery): AxiosPromise<TreeVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/tree/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询测试树详细
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getTree = (id: string | number): AxiosPromise<TreeVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/tree/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增测试树
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addTree = (data: TreeForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/tree',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改测试树
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateTree = (data: TreeForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/tree',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除测试树
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delTree = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/demo/tree/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
80
src/api/demo/tree/types.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
export interface TreeVO {
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
id: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父id
|
||||||
|
*/
|
||||||
|
parentId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
|
deptId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
userId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
|
treeName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子对象
|
||||||
|
*/
|
||||||
|
children: TreeVO[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TreeForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父id
|
||||||
|
*/
|
||||||
|
parentId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
|
deptId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
userId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
|
treeName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TreeQuery {
|
||||||
|
/**
|
||||||
|
* 父id
|
||||||
|
*/
|
||||||
|
parentId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
|
deptId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
userId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
|
treeName?: string;
|
||||||
|
}
|
||||||
107
src/api/login.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import type { UserInfo } from '@/api/system/user/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import { closePush } from '@/utils/push';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { LoginData, LoginResult, VerifyCodeResult } from './types';
|
||||||
|
|
||||||
|
// pc端固定客户端授权id
|
||||||
|
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param data {LoginData}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function login(data: LoginData): AxiosPromise<LoginResult> {
|
||||||
|
const params = {
|
||||||
|
...data,
|
||||||
|
clientId: data.clientId || clientId,
|
||||||
|
grantType: data.grantType || 'password'
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/auth/login',
|
||||||
|
headers: {
|
||||||
|
isToken: false,
|
||||||
|
isEncrypt: true,
|
||||||
|
repeatSubmit: false
|
||||||
|
},
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册方法
|
||||||
|
export function register(data: any) {
|
||||||
|
const params = {
|
||||||
|
...data,
|
||||||
|
clientId: clientId,
|
||||||
|
grantType: 'password'
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/auth/register',
|
||||||
|
headers: {
|
||||||
|
isToken: false,
|
||||||
|
isEncrypt: true,
|
||||||
|
repeatSubmit: false
|
||||||
|
},
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注销
|
||||||
|
*/
|
||||||
|
export function logout() {
|
||||||
|
closePush();
|
||||||
|
if (
|
||||||
|
import.meta.env.VITE_APP_MESSAGE_ENABLED === 'true' &&
|
||||||
|
import.meta.env.VITE_APP_MESSAGE_TRANSPORT.toLowerCase() === 'sse'
|
||||||
|
) {
|
||||||
|
request({
|
||||||
|
url: import.meta.env.VITE_APP_MESSAGE_PATH + '/close',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/auth/logout',
|
||||||
|
method: 'post'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验证码
|
||||||
|
*/
|
||||||
|
export function getCodeImg(): AxiosPromise<VerifyCodeResult> {
|
||||||
|
return request({
|
||||||
|
url: '/auth/code',
|
||||||
|
headers: {
|
||||||
|
isToken: false
|
||||||
|
},
|
||||||
|
method: 'get',
|
||||||
|
timeout: 20000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登录
|
||||||
|
*/
|
||||||
|
export function callback(data: LoginData): AxiosPromise<any> {
|
||||||
|
const LoginData = {
|
||||||
|
...data,
|
||||||
|
clientId: clientId,
|
||||||
|
grantType: 'social'
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/auth/social/callback',
|
||||||
|
method: 'post',
|
||||||
|
data: LoginData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户详细信息
|
||||||
|
export function getInfo(): AxiosPromise<UserInfo> {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/getInfo',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
11
src/api/menu.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 获取路由
|
||||||
|
export function getRouters(): AxiosPromise<RouteRecordRaw[]> {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/getRouters',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
12
src/api/monitor/cache/index.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { CacheVO } from './types';
|
||||||
|
|
||||||
|
// 查询缓存详细
|
||||||
|
export function getCache(): AxiosPromise<CacheVO> {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/cache',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
7
src/api/monitor/cache/types.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface CacheVO {
|
||||||
|
commandStats: Array<{ name: string; value: string }>;
|
||||||
|
|
||||||
|
dbSize: number;
|
||||||
|
|
||||||
|
info: { [key: string]: string };
|
||||||
|
}
|
||||||
37
src/api/monitor/logininfo/index.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { LoginInfoQuery, LoginInfoVO } from './types';
|
||||||
|
|
||||||
|
// 查询登录日志列表
|
||||||
|
export function list(query: LoginInfoQuery): AxiosPromise<PageResult<LoginInfoVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/loginInfo/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除登录日志
|
||||||
|
export function delLoginInfo(infoId: string | number | Array<string | number>) {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/loginInfo/' + infoId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解锁用户登录状态
|
||||||
|
export function unlockLoginInfo(userName: string | Array<string>) {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/loginInfo/unlock/' + userName,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空登录日志
|
||||||
|
export function cleanLoginInfo() {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/loginInfo/clean',
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
20
src/api/monitor/logininfo/types.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
export interface LoginInfoVO {
|
||||||
|
infoId: string | number;
|
||||||
|
tenantId: string | number;
|
||||||
|
userName: string;
|
||||||
|
status: string;
|
||||||
|
ipaddr: string;
|
||||||
|
loginLocation: string;
|
||||||
|
browser: string;
|
||||||
|
os: string;
|
||||||
|
msg: string;
|
||||||
|
loginTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginInfoQuery extends PageQuery {
|
||||||
|
ipaddr: string;
|
||||||
|
userName: string;
|
||||||
|
status: string;
|
||||||
|
orderByColumn: string;
|
||||||
|
isAsc: string;
|
||||||
|
}
|
||||||
37
src/api/monitor/online/index.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { OnlineQuery, OnlineVO } from './types';
|
||||||
|
|
||||||
|
// 查询在线用户列表
|
||||||
|
export function list(query: OnlineQuery): AxiosPromise<PageResult<OnlineVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/online/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强退用户
|
||||||
|
export function forceLogout(tokenId: string) {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/online/' + tokenId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前用户登录在线设备
|
||||||
|
export function getOnline() {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/online',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除当前在线设备
|
||||||
|
export function delOnline(tokenId: string) {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/online/myself/' + tokenId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
15
src/api/monitor/online/types.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export interface OnlineQuery extends PageQuery {
|
||||||
|
ipaddr: string;
|
||||||
|
userName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OnlineVO extends BaseEntity {
|
||||||
|
tokenId: string;
|
||||||
|
deptName: string;
|
||||||
|
userName: string;
|
||||||
|
ipaddr: string;
|
||||||
|
loginLocation: string;
|
||||||
|
browser: string;
|
||||||
|
os: string;
|
||||||
|
loginTime: number;
|
||||||
|
}
|
||||||
29
src/api/monitor/operlog/index.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { OperLogQuery, OperLogVO } from './types';
|
||||||
|
|
||||||
|
// 查询操作日志列表
|
||||||
|
export function list(query: OperLogQuery): AxiosPromise<PageResult<OperLogVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/operlog/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除操作日志
|
||||||
|
export function delOperlog(operId: string | number | Array<string | number>) {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/operlog/' + operId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空操作日志
|
||||||
|
export function cleanOperlog() {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/operlog/clean',
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
71
src/api/monitor/operlog/types.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
export interface OperLogQuery extends PageQuery {
|
||||||
|
operIp: string;
|
||||||
|
title: string;
|
||||||
|
operName: string;
|
||||||
|
userId: string;
|
||||||
|
deptId: string;
|
||||||
|
clientKey: string;
|
||||||
|
deviceType: string;
|
||||||
|
browser: string;
|
||||||
|
os: string;
|
||||||
|
businessType: string;
|
||||||
|
status: string;
|
||||||
|
orderByColumn: string;
|
||||||
|
isAsc: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OperLogVO extends BaseEntity {
|
||||||
|
operId: string | number;
|
||||||
|
tenantId: string;
|
||||||
|
title: string;
|
||||||
|
businessType: number;
|
||||||
|
businessTypes: number[] | undefined;
|
||||||
|
method: string;
|
||||||
|
requestMethod: string;
|
||||||
|
operatorType: number;
|
||||||
|
operName: string;
|
||||||
|
userId: string | number;
|
||||||
|
deptId: string | number;
|
||||||
|
deptName: string;
|
||||||
|
clientKey: string;
|
||||||
|
deviceType: string;
|
||||||
|
browser: string;
|
||||||
|
os: string;
|
||||||
|
operUrl: string;
|
||||||
|
operIp: string;
|
||||||
|
operLocation: string;
|
||||||
|
operParam: string;
|
||||||
|
jsonResult: string;
|
||||||
|
status: number;
|
||||||
|
errorMsg: string;
|
||||||
|
operTime: string;
|
||||||
|
costTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OperLogForm {
|
||||||
|
operId: number | string | undefined;
|
||||||
|
tenantId: string | number | undefined;
|
||||||
|
title: string;
|
||||||
|
businessType: number;
|
||||||
|
businessTypes: number[] | undefined;
|
||||||
|
method: string;
|
||||||
|
requestMethod: string;
|
||||||
|
operatorType: number;
|
||||||
|
operName: string;
|
||||||
|
userId: string | number | undefined;
|
||||||
|
deptId: string | number | undefined;
|
||||||
|
deptName: string;
|
||||||
|
clientKey: string;
|
||||||
|
deviceType: string;
|
||||||
|
browser: string;
|
||||||
|
os: string;
|
||||||
|
operUrl: string;
|
||||||
|
operIp: string;
|
||||||
|
operLocation: string;
|
||||||
|
operParam: string;
|
||||||
|
jsonResult: string;
|
||||||
|
status: number;
|
||||||
|
errorMsg: string;
|
||||||
|
operTime: string;
|
||||||
|
costTime: number;
|
||||||
|
}
|
||||||
81
src/api/system/client/index.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import type { ClientForm, ClientQuery, ClientVO } from '@/api/system/client/types';
|
||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询客户端管理列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listClient = (query?: ClientQuery): AxiosPromise<PageResult<ClientVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/client/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询客户端管理详细
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getClient = (id: string | number): AxiosPromise<ClientVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/client/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增客户端管理
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addClient = (data: ClientForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/client',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改客户端管理
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateClient = (data: ClientForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/client',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除客户端管理
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delClient = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/client/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态修改
|
||||||
|
* @param clientId 客户端id
|
||||||
|
* @param status 状态
|
||||||
|
*/
|
||||||
|
export function changeStatus(clientId: string, status: string) {
|
||||||
|
const data = {
|
||||||
|
clientId,
|
||||||
|
status
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/system/client/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
185
src/api/system/client/types.ts
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
export interface ClientVO {
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
id: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端id
|
||||||
|
*/
|
||||||
|
clientId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端key
|
||||||
|
*/
|
||||||
|
clientKey: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端秘钥
|
||||||
|
*/
|
||||||
|
clientSecret: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权类型
|
||||||
|
*/
|
||||||
|
grantTypeList: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
|
deviceType: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许访问路径
|
||||||
|
*/
|
||||||
|
accessPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许访问路径列表
|
||||||
|
*/
|
||||||
|
accessPathList?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP白名单
|
||||||
|
*/
|
||||||
|
ipWhitelist?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP白名单列表
|
||||||
|
*/
|
||||||
|
ipWhitelistList?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token活跃超时时间
|
||||||
|
*/
|
||||||
|
activeTimeout: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token固定超时
|
||||||
|
*/
|
||||||
|
timeout: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端id
|
||||||
|
*/
|
||||||
|
clientId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端key
|
||||||
|
*/
|
||||||
|
clientKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端秘钥
|
||||||
|
*/
|
||||||
|
clientSecret?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权类型
|
||||||
|
*/
|
||||||
|
grantTypeList?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
|
deviceType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许访问路径
|
||||||
|
*/
|
||||||
|
accessPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许访问路径列表
|
||||||
|
*/
|
||||||
|
accessPathList?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP白名单
|
||||||
|
*/
|
||||||
|
ipWhitelist?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP白名单列表
|
||||||
|
*/
|
||||||
|
ipWhitelistList?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token活跃超时时间
|
||||||
|
*/
|
||||||
|
activeTimeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token固定超时
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientQuery extends PageQuery {
|
||||||
|
/**
|
||||||
|
* 客户端id
|
||||||
|
*/
|
||||||
|
clientId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端key
|
||||||
|
*/
|
||||||
|
clientKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端秘钥
|
||||||
|
*/
|
||||||
|
clientSecret?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权类型
|
||||||
|
*/
|
||||||
|
grantType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
|
deviceType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许访问路径
|
||||||
|
*/
|
||||||
|
accessPath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP白名单
|
||||||
|
*/
|
||||||
|
ipWhitelist?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token活跃超时时间
|
||||||
|
*/
|
||||||
|
activeTimeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token固定超时
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
75
src/api/system/config/index.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ConfigForm, ConfigQuery, ConfigVO } from './types';
|
||||||
|
|
||||||
|
// 查询参数列表
|
||||||
|
export function listConfig(query: ConfigQuery): AxiosPromise<PageResult<ConfigVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询参数详细
|
||||||
|
export function getConfig(configId: string | number): AxiosPromise<ConfigVO> {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/' + configId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据参数键名查询参数值
|
||||||
|
export function getConfigKey(configKey: string): AxiosPromise<string> {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/configKey/' + configKey,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增参数配置
|
||||||
|
export function addConfig(data: ConfigForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改参数配置
|
||||||
|
export function updateConfig(data: ConfigForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改参数配置
|
||||||
|
export function updateConfigByKey(key: string, value: any) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/updateByKey',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
configKey: key,
|
||||||
|
configValue: value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除参数配置
|
||||||
|
export function delConfig(configId: string | number | Array<string | number>) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/' + configId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新参数缓存
|
||||||
|
export function refreshCache() {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/refreshCache',
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
23
src/api/system/config/types.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export interface ConfigVO extends BaseEntity {
|
||||||
|
configId: number | string;
|
||||||
|
configName: string;
|
||||||
|
configKey: string;
|
||||||
|
configValue: string;
|
||||||
|
configType: string;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConfigForm {
|
||||||
|
configId: number | string | undefined;
|
||||||
|
configName: string;
|
||||||
|
configKey: string;
|
||||||
|
configValue: string;
|
||||||
|
configType: string;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConfigQuery extends PageQuery {
|
||||||
|
configName: string;
|
||||||
|
configKey: string;
|
||||||
|
configType: string;
|
||||||
|
}
|
||||||
65
src/api/system/dept/index.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import { type DeptForm, type DeptQuery, type DeptVO } from './types';
|
||||||
|
|
||||||
|
// 查询部门列表
|
||||||
|
export const listDept = (query?: DeptQuery) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过deptIds查询部门
|
||||||
|
* @param deptIds
|
||||||
|
*/
|
||||||
|
export const optionSelect = (deptIds: (number | string)[]): AxiosPromise<DeptVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/optionselect?deptIds=' + deptIds,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询部门列表(排除节点)
|
||||||
|
export const listDeptExcludeChild = (deptId: string | number): AxiosPromise<DeptVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/list/exclude/' + deptId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询部门详细
|
||||||
|
export const getDept = (deptId: string | number): AxiosPromise<DeptVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/' + deptId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增部门
|
||||||
|
export const addDept = (data: DeptForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改部门
|
||||||
|
export const updateDept = (data: DeptForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除部门
|
||||||
|
export const delDept = (deptId: number | string) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/' + deptId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
60
src/api/system/dept/types.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* 部门查询参数
|
||||||
|
*/
|
||||||
|
export interface DeptQuery extends PageQuery {
|
||||||
|
deptName?: string;
|
||||||
|
deptCategory?: string;
|
||||||
|
status?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门类型
|
||||||
|
*/
|
||||||
|
export interface DeptVO extends BaseEntity {
|
||||||
|
id: number | string;
|
||||||
|
parentName: string;
|
||||||
|
parentId: number | string;
|
||||||
|
children: DeptVO[];
|
||||||
|
deptId: number | string;
|
||||||
|
deptName: string;
|
||||||
|
deptCategory: string;
|
||||||
|
orderNum: number;
|
||||||
|
leader: string;
|
||||||
|
phone: string;
|
||||||
|
email: string;
|
||||||
|
status: string;
|
||||||
|
delFlag: string;
|
||||||
|
ancestors: string;
|
||||||
|
menuId: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门类型
|
||||||
|
*/
|
||||||
|
export interface DeptTreeVO extends BaseEntity {
|
||||||
|
id: number | string;
|
||||||
|
label: string;
|
||||||
|
parentId: number | string;
|
||||||
|
weight: number;
|
||||||
|
children: DeptTreeVO[];
|
||||||
|
disabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门表单类型
|
||||||
|
*/
|
||||||
|
export interface DeptForm {
|
||||||
|
parentName?: string;
|
||||||
|
parentId?: number | string;
|
||||||
|
children?: DeptForm[];
|
||||||
|
deptId?: number | string;
|
||||||
|
deptName?: string;
|
||||||
|
deptCategory?: string;
|
||||||
|
orderNum?: number;
|
||||||
|
leader?: string;
|
||||||
|
phone?: string;
|
||||||
|
email?: string;
|
||||||
|
status?: string;
|
||||||
|
delFlag?: string;
|
||||||
|
ancestors?: string;
|
||||||
|
}
|
||||||
54
src/api/system/dict/data/index.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { DictDataForm, DictDataQuery, DictDataVO } from './types';
|
||||||
|
// 根据字典类型查询字典数据信息
|
||||||
|
export function getDicts(dictType: string): AxiosPromise<DictDataVO[]> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/type/' + dictType,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询字典数据列表
|
||||||
|
export function listData(query: DictDataQuery): AxiosPromise<PageResult<DictDataVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询字典数据详细
|
||||||
|
export function getData(dictCode: string | number): AxiosPromise<DictDataVO> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/' + dictCode,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增字典数据
|
||||||
|
export function addData(data: DictDataForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改字典数据
|
||||||
|
export function updateData(data: DictDataForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除字典数据
|
||||||
|
export function delData(dictCode: string | number | Array<string | number>) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/' + dictCode,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
26
src/api/system/dict/data/types.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export interface DictDataQuery extends PageQuery {
|
||||||
|
dictName: string;
|
||||||
|
dictType: string;
|
||||||
|
dictLabel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DictDataVO extends BaseEntity {
|
||||||
|
dictCode: string;
|
||||||
|
dictLabel: string;
|
||||||
|
dictValue: string;
|
||||||
|
cssClass: string;
|
||||||
|
listClass: ElTagType;
|
||||||
|
dictSort: number;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DictDataForm {
|
||||||
|
dictType?: string;
|
||||||
|
dictCode: string | undefined;
|
||||||
|
dictLabel: string;
|
||||||
|
dictValue: string;
|
||||||
|
cssClass: string;
|
||||||
|
listClass: ElTagType;
|
||||||
|
dictSort: number;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
63
src/api/system/dict/type/index.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { DictTypeForm, DictTypeQuery, DictTypeVO } from './types';
|
||||||
|
|
||||||
|
// 查询字典类型列表
|
||||||
|
export function listType(query: DictTypeQuery): AxiosPromise<PageResult<DictTypeVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询字典类型详细
|
||||||
|
export function getType(dictId: number | string): AxiosPromise<DictTypeVO> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/' + dictId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增字典类型
|
||||||
|
export function addType(data: DictTypeForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改字典类型
|
||||||
|
export function updateType(data: DictTypeForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除字典类型
|
||||||
|
export function delType(dictId: string | number | Array<string | number>) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/' + dictId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新字典缓存
|
||||||
|
export function refreshCache() {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/refreshCache',
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字典选择框列表
|
||||||
|
export function optionselect(): AxiosPromise<DictTypeVO[]> {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/optionselect',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
18
src/api/system/dict/type/types.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export interface DictTypeVO extends BaseEntity {
|
||||||
|
dictId: number | string;
|
||||||
|
dictName: string;
|
||||||
|
dictType: string;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DictTypeForm {
|
||||||
|
dictId: number | string | undefined;
|
||||||
|
dictName: string;
|
||||||
|
dictType: string;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DictTypeQuery extends PageQuery {
|
||||||
|
dictName: string;
|
||||||
|
dictType: string;
|
||||||
|
}
|
||||||
70
src/api/system/menu/index.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { MenuForm, MenuQuery, MenuTreeOption, MenuVO, RoleMenuTree } from './types';
|
||||||
|
|
||||||
|
// 查询菜单列表
|
||||||
|
export const listMenu = (query?: MenuQuery): AxiosPromise<MenuVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询菜单详细
|
||||||
|
export const getMenu = (menuId: string | number): AxiosPromise<MenuVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/' + menuId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询菜单下拉树结构
|
||||||
|
export const treeselect = (): AxiosPromise<MenuTreeOption[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/treeselect',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据角色ID查询菜单下拉树结构
|
||||||
|
export const roleMenuTreeselect = (roleId: string | number): AxiosPromise<RoleMenuTree> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/roleMenuTreeselect/' + roleId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增菜单
|
||||||
|
export const addMenu = (data: MenuForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改菜单
|
||||||
|
export const updateMenu = (data: MenuForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除菜单
|
||||||
|
export const delMenu = (menuId: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/' + menuId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 级联删除菜单
|
||||||
|
export const cascadeDelMenu = (menuIds: Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/cascade/' + menuIds,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
89
src/api/system/menu/types.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import type { MenuTypeEnum } from '@/enums/MenuTypeEnum';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单树形结构类型
|
||||||
|
*/
|
||||||
|
export interface MenuTreeOption {
|
||||||
|
id: string | number;
|
||||||
|
label: string;
|
||||||
|
parentId: string | number;
|
||||||
|
weight: number;
|
||||||
|
menuType?: MenuTypeEnum | string;
|
||||||
|
visible?: string;
|
||||||
|
status?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
children?: MenuTreeOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoleMenuTree {
|
||||||
|
menus: MenuTreeOption[];
|
||||||
|
checkedKeys: Array<string | number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色菜单分配中的按钮节点类型
|
||||||
|
*/
|
||||||
|
export interface RoleMenuButtonOption {
|
||||||
|
menuId: string | number;
|
||||||
|
menuName: string;
|
||||||
|
parentId: string | number;
|
||||||
|
perms?: string;
|
||||||
|
status?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单查询参数类型
|
||||||
|
*/
|
||||||
|
export interface MenuQuery {
|
||||||
|
keywords?: string;
|
||||||
|
menuName?: string;
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单视图对象类型
|
||||||
|
*/
|
||||||
|
export interface MenuVO extends BaseEntity {
|
||||||
|
parentName: string;
|
||||||
|
parentId: string | number;
|
||||||
|
children: MenuVO[];
|
||||||
|
menuId: string | number;
|
||||||
|
menuName: string;
|
||||||
|
orderNum: number;
|
||||||
|
path: string;
|
||||||
|
component: string;
|
||||||
|
queryParam: string;
|
||||||
|
isFrame: string;
|
||||||
|
isCache: string;
|
||||||
|
menuType: MenuTypeEnum;
|
||||||
|
visible: string;
|
||||||
|
status: string;
|
||||||
|
icon: string;
|
||||||
|
activeMenu: string;
|
||||||
|
ext: string;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuForm {
|
||||||
|
parentName?: string;
|
||||||
|
parentId?: string | number;
|
||||||
|
children?: MenuForm[];
|
||||||
|
menuId?: string | number;
|
||||||
|
menuName: string;
|
||||||
|
orderNum: number;
|
||||||
|
path: string;
|
||||||
|
component?: string;
|
||||||
|
queryParam?: string;
|
||||||
|
isFrame?: string;
|
||||||
|
isCache?: string;
|
||||||
|
menuType?: MenuTypeEnum;
|
||||||
|
visible?: string;
|
||||||
|
status?: string;
|
||||||
|
icon?: string;
|
||||||
|
activeMenu?: string;
|
||||||
|
ext?: string;
|
||||||
|
remark?: string;
|
||||||
|
query?: string;
|
||||||
|
perms?: string;
|
||||||
|
}
|
||||||
10
src/api/system/message/index.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { MessageBoxVO } from './types';
|
||||||
|
|
||||||
|
export function getMessageBox(): AxiosPromise<MessageBoxVO> {
|
||||||
|
return request({
|
||||||
|
url: '/resource/message/box',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
17
src/api/system/message/types.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export interface MessageVO extends BaseEntity {
|
||||||
|
messageId: number | string;
|
||||||
|
category: string;
|
||||||
|
type: string;
|
||||||
|
source: string;
|
||||||
|
title: string;
|
||||||
|
message: string;
|
||||||
|
content?: string;
|
||||||
|
data?: Record<string, any> | null;
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessageBoxVO {
|
||||||
|
systemList: MessageVO[];
|
||||||
|
noticeList: MessageVO[];
|
||||||
|
workflowList: MessageVO[];
|
||||||
|
}
|
||||||
46
src/api/system/notice/index.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { NoticeForm, NoticeQuery, NoticeVO } from './types';
|
||||||
|
// 查询公告列表
|
||||||
|
export function listNotice(query: NoticeQuery): AxiosPromise<PageResult<NoticeVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询公告详细
|
||||||
|
export function getNotice(noticeId: string | number): AxiosPromise<NoticeVO> {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/' + noticeId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增公告
|
||||||
|
export function addNotice(data: NoticeForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改公告
|
||||||
|
export function updateNotice(data: NoticeForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除公告
|
||||||
|
export function delNotice(noticeId: string | number | Array<string | number>) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/' + noticeId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
26
src/api/system/notice/types.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export interface NoticeVO extends BaseEntity {
|
||||||
|
noticeId: number;
|
||||||
|
noticeTitle: string;
|
||||||
|
noticeType: string;
|
||||||
|
noticeContent: string;
|
||||||
|
status: string;
|
||||||
|
remark: string;
|
||||||
|
createByName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NoticeQuery extends PageQuery {
|
||||||
|
noticeTitle: string;
|
||||||
|
createByName: string;
|
||||||
|
status: string;
|
||||||
|
noticeType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NoticeForm {
|
||||||
|
noticeId: number | string | undefined;
|
||||||
|
noticeTitle: string;
|
||||||
|
noticeType: string;
|
||||||
|
noticeContent: string;
|
||||||
|
status: string;
|
||||||
|
remark: string;
|
||||||
|
createByName: string;
|
||||||
|
}
|
||||||
38
src/api/system/oss/index.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { OssQuery, OssUploadVO, OssVO } from './types';
|
||||||
|
|
||||||
|
// 查询OSS对象存储列表
|
||||||
|
export function listOss(query: OssQuery): AxiosPromise<PageResult<OssVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询OSS对象基于id串
|
||||||
|
export function listByIds(ossId: string | number): AxiosPromise<OssVO[]> {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/listByIds/' + ossId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传OSS对象存储
|
||||||
|
export function uploadOss(data: FormData): AxiosPromise<OssUploadVO> {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/upload',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除OSS对象存储
|
||||||
|
export function delOss(ossId: string | number | Array<string | number>) {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/' + ossId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
42
src/api/system/oss/types.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
export interface OssVO extends BaseEntity {
|
||||||
|
ossId: string | number;
|
||||||
|
fileName: string;
|
||||||
|
originalName: string;
|
||||||
|
fileSuffix: string;
|
||||||
|
url: string;
|
||||||
|
createByName: string;
|
||||||
|
service: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OssUploadVO {
|
||||||
|
url: string;
|
||||||
|
fileName: string;
|
||||||
|
ossId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OssQuery extends PageQuery {
|
||||||
|
fileName: string;
|
||||||
|
originalName: string;
|
||||||
|
fileSuffix: string;
|
||||||
|
createTime: string;
|
||||||
|
service: string;
|
||||||
|
orderByColumn: string;
|
||||||
|
isAsc: string;
|
||||||
|
}
|
||||||
|
export interface OssForm {
|
||||||
|
file: undefined | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SysOssExt {
|
||||||
|
bizType?: string;
|
||||||
|
fileSize?: number;
|
||||||
|
contentType?: string;
|
||||||
|
source?: string;
|
||||||
|
uploadIp?: string;
|
||||||
|
remark?: string;
|
||||||
|
tags?: string[];
|
||||||
|
refId?: string;
|
||||||
|
refType?: string;
|
||||||
|
isTemp?: boolean;
|
||||||
|
md5?: string;
|
||||||
|
}
|
||||||
61
src/api/system/ossConfig/index.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { OssConfigForm, OssConfigQuery, OssConfigVO } from './types';
|
||||||
|
|
||||||
|
// 查询对象存储配置列表
|
||||||
|
export function listOssConfig(query: OssConfigQuery): AxiosPromise<PageResult<OssConfigVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/config/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询对象存储配置详细
|
||||||
|
export function getOssConfig(ossConfigId: string | number): AxiosPromise<OssConfigVO> {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/config/' + ossConfigId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增对象存储配置
|
||||||
|
export function addOssConfig(data: OssConfigForm) {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/config',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改对象存储配置
|
||||||
|
export function updateOssConfig(data: OssConfigForm) {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/config',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除对象存储配置
|
||||||
|
export function delOssConfig(ossConfigId: string | number | Array<string | number>) {
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/config/' + ossConfigId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对象存储状态修改
|
||||||
|
export function changeOssConfigStatus(ossConfigId: string | number, status: string, configKey: string) {
|
||||||
|
const data = {
|
||||||
|
ossConfigId,
|
||||||
|
status,
|
||||||
|
configKey
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/resource/oss/config/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
38
src/api/system/ossConfig/types.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
export interface OssConfigVO extends BaseEntity {
|
||||||
|
ossConfigId: number | string;
|
||||||
|
configKey: string;
|
||||||
|
accessKey: string;
|
||||||
|
secretKey: string;
|
||||||
|
bucketName: string;
|
||||||
|
prefix: string;
|
||||||
|
endpoint: string;
|
||||||
|
domainUrl: string;
|
||||||
|
isHttps: string;
|
||||||
|
region: string;
|
||||||
|
status: string;
|
||||||
|
ext1: string;
|
||||||
|
remark: string;
|
||||||
|
accessPolicy: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OssConfigQuery extends PageQuery {
|
||||||
|
configKey: string;
|
||||||
|
bucketName: string;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OssConfigForm {
|
||||||
|
ossConfigId: string | number | undefined;
|
||||||
|
configKey: string;
|
||||||
|
accessKey: string;
|
||||||
|
secretKey: string;
|
||||||
|
bucketName: string;
|
||||||
|
prefix: string;
|
||||||
|
endpoint: string;
|
||||||
|
domainUrl: string;
|
||||||
|
isHttps: string;
|
||||||
|
accessPolicy: string;
|
||||||
|
region: string;
|
||||||
|
status: string;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
70
src/api/system/post/index.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { DeptTreeVO } from '../dept/types';
|
||||||
|
import type { PostForm, PostQuery, PostVO } from './types';
|
||||||
|
|
||||||
|
// 查询岗位列表
|
||||||
|
export function listPost(query: PostQuery): AxiosPromise<PageResult<PostVO>> {
|
||||||
|
return request({
|
||||||
|
url: '/system/post/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询岗位详细
|
||||||
|
export function getPost(postId: string | number): AxiosPromise<PostVO> {
|
||||||
|
return request({
|
||||||
|
url: '/system/post/' + postId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取岗位选择框列表
|
||||||
|
export function optionselect(deptId?: number | string, postIds?: (number | string)[]): AxiosPromise<PostVO[]> {
|
||||||
|
return request({
|
||||||
|
url: '/system/post/optionselect',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
postIds: postIds,
|
||||||
|
deptId: deptId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增岗位
|
||||||
|
export function addPost(data: PostForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/post',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改岗位
|
||||||
|
export function updatePost(data: PostForm) {
|
||||||
|
return request({
|
||||||
|
url: '/system/post',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除岗位
|
||||||
|
export function delPost(postId: string | number | (string | number)[]) {
|
||||||
|
return request({
|
||||||
|
url: '/system/post/' + postId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询部门下拉树结构
|
||||||
|
*/
|
||||||
|
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/post/deptTree',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
31
src/api/system/post/types.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
export interface PostVO extends BaseEntity {
|
||||||
|
postId: number | string;
|
||||||
|
deptId: number | string;
|
||||||
|
postCode: string;
|
||||||
|
postName: string;
|
||||||
|
postCategory: string;
|
||||||
|
deptName: string;
|
||||||
|
postSort: number;
|
||||||
|
status: string;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PostForm {
|
||||||
|
postId: number | string | undefined;
|
||||||
|
deptId: number | string | undefined;
|
||||||
|
postCode: string;
|
||||||
|
postName: string;
|
||||||
|
postCategory: string;
|
||||||
|
postSort: number;
|
||||||
|
status: string;
|
||||||
|
remark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PostQuery extends PageQuery {
|
||||||
|
deptId: number | string;
|
||||||
|
belongDeptId: number | string;
|
||||||
|
postCode: string;
|
||||||
|
postName: string;
|
||||||
|
postCategory: string;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
160
src/api/system/role/index.ts
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
import type { UserQuery, UserVO } from '@/api/system/user/types';
|
||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { RoleDeptTree, RoleQuery, RoleVO } from './types';
|
||||||
|
|
||||||
|
export const listRole = (query: RoleQuery): AxiosPromise<PageResult<RoleVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过roleIds查询角色
|
||||||
|
* @param roleIds
|
||||||
|
*/
|
||||||
|
export const optionSelect = (roleIds: (number | string)[]): AxiosPromise<RoleVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/optionselect?roleIds=' + roleIds,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询角色详细
|
||||||
|
*/
|
||||||
|
export const getRole = (roleId: string | number): AxiosPromise<RoleVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/' + roleId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增角色
|
||||||
|
*/
|
||||||
|
export const addRole = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改角色基础信息
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateRole = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改角色权限(菜单权限 + 数据权限)
|
||||||
|
*/
|
||||||
|
export const updateRolePermission = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/permission',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色状态修改
|
||||||
|
*/
|
||||||
|
export const changeRoleStatus = (roleId: string | number, status: string) => {
|
||||||
|
const data = {
|
||||||
|
roleId,
|
||||||
|
status
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/system/role/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除角色
|
||||||
|
*/
|
||||||
|
export const delRole = (roleId: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/' + roleId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询角色已授权用户列表
|
||||||
|
*/
|
||||||
|
export const allocatedUserList = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/allocatedList',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询角色未授权用户列表
|
||||||
|
*/
|
||||||
|
export const unallocatedUserList = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/unallocatedList',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消用户授权角色
|
||||||
|
*/
|
||||||
|
export const authUserCancel = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/cancel',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量取消用户授权角色
|
||||||
|
*/
|
||||||
|
export const authUserCancelAll = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/cancelAll',
|
||||||
|
method: 'put',
|
||||||
|
params: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权用户选择
|
||||||
|
*/
|
||||||
|
export const authUserSelectAll = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/selectAll',
|
||||||
|
method: 'put',
|
||||||
|
params: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 根据角色ID查询部门树结构
|
||||||
|
export const deptTreeSelect = (roleId: string | number): AxiosPromise<RoleDeptTree> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/deptTree/' + roleId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
optionSelect,
|
||||||
|
listRole
|
||||||
|
};
|
||||||
52
src/api/system/role/types.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* 菜单树形结构类型
|
||||||
|
*/
|
||||||
|
export interface DeptTreeOption {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
parentId: string;
|
||||||
|
weight: number;
|
||||||
|
children?: DeptTreeOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoleDeptTree {
|
||||||
|
checkedKeys: string[];
|
||||||
|
depts: DeptTreeOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoleVO extends BaseEntity {
|
||||||
|
roleId: string | number;
|
||||||
|
roleName: string;
|
||||||
|
roleKey: string;
|
||||||
|
roleSort: number;
|
||||||
|
dataScope: string;
|
||||||
|
menuCheckStrictly: boolean;
|
||||||
|
deptCheckStrictly: boolean;
|
||||||
|
status: string;
|
||||||
|
delFlag: string;
|
||||||
|
remark?: any;
|
||||||
|
flag: boolean;
|
||||||
|
menuIds?: Array<string | number>;
|
||||||
|
deptIds?: Array<string | number>;
|
||||||
|
admin: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoleQuery extends PageQuery {
|
||||||
|
roleName: string;
|
||||||
|
roleKey: string;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoleForm {
|
||||||
|
roleName: string;
|
||||||
|
roleKey: string;
|
||||||
|
roleSort: number;
|
||||||
|
status: string;
|
||||||
|
menuCheckStrictly: boolean;
|
||||||
|
deptCheckStrictly: boolean;
|
||||||
|
remark: string;
|
||||||
|
dataScope?: string;
|
||||||
|
roleId: string | undefined;
|
||||||
|
menuIds: Array<string | number>;
|
||||||
|
deptIds: Array<string | number>;
|
||||||
|
}
|
||||||
24
src/api/system/social/auth.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 获取跳转URL
|
||||||
|
export function authRouterUrl(source: string) {
|
||||||
|
return request({
|
||||||
|
url: '/auth/binding/' + source,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解绑账号
|
||||||
|
export function authUnlock(authId: string) {
|
||||||
|
return request({
|
||||||
|
url: '/auth/unlock/' + authId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//获取授权列表
|
||||||
|
export function getAuthList() {
|
||||||
|
return request({
|
||||||
|
url: '/system/social/list',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
229
src/api/system/user/index.ts
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
import type { RoleVO } from '@/api/system/role/types';
|
||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import { parseStrEmpty } from '@/utils/ruoyi';
|
||||||
|
import type { DeptTreeVO } from './../dept/types';
|
||||||
|
import type { UserForm, UserInfoVO, UserProfileForm, UserQuery, UserVO } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户列表
|
||||||
|
* @param query
|
||||||
|
*/
|
||||||
|
export const listUser = (query: UserQuery): AxiosPromise<PageResult<UserVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过用户ids查询用户
|
||||||
|
* @param userIds
|
||||||
|
*/
|
||||||
|
export const optionSelect = (userIds: (number | string)[]): AxiosPromise<UserVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/optionselect?userIds=' + userIds,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户详情
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
export const getUser = (userId?: string | number): AxiosPromise<UserInfoVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/' + parseStrEmpty(userId),
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增用户
|
||||||
|
*/
|
||||||
|
export const addUser = (data: UserForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户
|
||||||
|
*/
|
||||||
|
export const updateUser = (data: UserForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户
|
||||||
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
export const delUser = (userId: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/' + userId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户密码重置
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param password 密码
|
||||||
|
*/
|
||||||
|
export const resetUserPwd = (userId: string | number, password: string) => {
|
||||||
|
const data = {
|
||||||
|
userId,
|
||||||
|
password
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/system/user/resetPwd',
|
||||||
|
method: 'put',
|
||||||
|
headers: {
|
||||||
|
isEncrypt: true,
|
||||||
|
repeatSubmit: false
|
||||||
|
},
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户状态修改
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param status 用户状态
|
||||||
|
*/
|
||||||
|
export const changeUserStatus = (userId: number | string, status: string) => {
|
||||||
|
const data = {
|
||||||
|
userId,
|
||||||
|
status
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/system/user/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解锁用户
|
||||||
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
export const unlockUser = (userId: number | string) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/unlock/' + userId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户个人信息
|
||||||
|
*/
|
||||||
|
export const getUserProfile = (): AxiosPromise<UserInfoVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户个人信息
|
||||||
|
* @param data 用户信息
|
||||||
|
*/
|
||||||
|
export const updateUserProfile = (data: UserProfileForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户密码重置
|
||||||
|
* @param oldPassword 旧密码
|
||||||
|
* @param newPassword 新密码
|
||||||
|
*/
|
||||||
|
export const updateUserPwd = (oldPassword: string, newPassword: string) => {
|
||||||
|
const data = {
|
||||||
|
oldPassword,
|
||||||
|
newPassword
|
||||||
|
};
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile/updatePwd',
|
||||||
|
method: 'put',
|
||||||
|
headers: {
|
||||||
|
isEncrypt: true,
|
||||||
|
repeatSubmit: false
|
||||||
|
},
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询授权角色
|
||||||
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
export const getAuthRole = (userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/authRole/' + userId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存授权角色
|
||||||
|
* @param data 用户ID
|
||||||
|
*/
|
||||||
|
export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/authRole',
|
||||||
|
method: 'put',
|
||||||
|
params: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询当前部门的所有用户信息
|
||||||
|
* @param deptId
|
||||||
|
*/
|
||||||
|
export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/list/dept/' + deptId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询部门下拉树结构
|
||||||
|
*/
|
||||||
|
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/deptTree',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
listUser,
|
||||||
|
getUser,
|
||||||
|
optionSelect,
|
||||||
|
addUser,
|
||||||
|
updateUser,
|
||||||
|
delUser,
|
||||||
|
resetUserPwd,
|
||||||
|
changeUserStatus,
|
||||||
|
unlockUser,
|
||||||
|
getUserProfile,
|
||||||
|
updateUserProfile,
|
||||||
|
updateUserPwd,
|
||||||
|
getAuthRole,
|
||||||
|
updateAuthRole,
|
||||||
|
deptTreeSelect,
|
||||||
|
listUserByDeptId
|
||||||
|
};
|
||||||
101
src/api/system/user/types.ts
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import type { PostVO } from '@/api/system/post/types';
|
||||||
|
import type { RoleVO } from '@/api/system/role/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息
|
||||||
|
*/
|
||||||
|
export interface UserInfo {
|
||||||
|
user: UserVO;
|
||||||
|
roles: string[];
|
||||||
|
permissions: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户查询对象类型
|
||||||
|
*/
|
||||||
|
export interface UserQuery extends PageQuery {
|
||||||
|
userName?: string;
|
||||||
|
nickName?: string;
|
||||||
|
phoneNumber?: string;
|
||||||
|
status?: string;
|
||||||
|
deptId?: string | number;
|
||||||
|
roleId?: string | number;
|
||||||
|
userIds?: string | number | (string | number)[] | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户返回对象
|
||||||
|
*/
|
||||||
|
export interface UserVO extends BaseEntity {
|
||||||
|
userId: string | number;
|
||||||
|
tenantId: string;
|
||||||
|
deptId: number;
|
||||||
|
userName: string;
|
||||||
|
nickName: string;
|
||||||
|
userType: string;
|
||||||
|
email: string;
|
||||||
|
phoneNumber: string;
|
||||||
|
gender: string;
|
||||||
|
avatar?: string | number;
|
||||||
|
avatarUrl?: string;
|
||||||
|
status: string;
|
||||||
|
delFlag: string;
|
||||||
|
loginIp: string;
|
||||||
|
loginDate: string;
|
||||||
|
remark: string;
|
||||||
|
deptName: string;
|
||||||
|
/** 详情接口可能返回嵌套部门 */
|
||||||
|
dept?: { deptName?: string };
|
||||||
|
roles: RoleVO[];
|
||||||
|
roleIds: any;
|
||||||
|
postIds: any;
|
||||||
|
roleId: any;
|
||||||
|
admin: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户表单类型
|
||||||
|
*/
|
||||||
|
export interface UserForm {
|
||||||
|
id?: string;
|
||||||
|
userId?: string;
|
||||||
|
deptId?: number;
|
||||||
|
userName: string;
|
||||||
|
nickName?: string;
|
||||||
|
password: string;
|
||||||
|
phoneNumber?: string;
|
||||||
|
email?: string;
|
||||||
|
gender?: string;
|
||||||
|
status: string;
|
||||||
|
remark?: string;
|
||||||
|
avatar?: string | number;
|
||||||
|
postIds: string[];
|
||||||
|
roleIds: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 个人资料表单类型
|
||||||
|
*/
|
||||||
|
export interface UserProfileForm {
|
||||||
|
nickName?: string;
|
||||||
|
phoneNumber?: string;
|
||||||
|
email?: string;
|
||||||
|
gender?: string;
|
||||||
|
avatar?: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserInfoVO {
|
||||||
|
user: UserVO;
|
||||||
|
roles: RoleVO[];
|
||||||
|
roleIds: string[];
|
||||||
|
posts: PostVO[];
|
||||||
|
postIds: string[];
|
||||||
|
roleGroup: string;
|
||||||
|
postGroup: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResetPwdForm {
|
||||||
|
oldPassword: string;
|
||||||
|
newPassword: string;
|
||||||
|
confirmPassword: string;
|
||||||
|
}
|
||||||
81
src/api/tool/gen/index.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import type { DbTableForm, DbTableQuery, DbTableVO, GenTableDetailPayload, TableQuery, TableVO } from './types';
|
||||||
|
|
||||||
|
export type { GenTableDetailPayload } from './types';
|
||||||
|
|
||||||
|
// 查询生成表数据
|
||||||
|
export const listTable = (query: TableQuery): AxiosPromise<PageResult<TableVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 查询db数据库列表
|
||||||
|
export const listDbTable = (query: DbTableQuery): AxiosPromise<PageResult<DbTableVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/db/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询表详细信息
|
||||||
|
export const getGenTable = (tableId: string | number): AxiosPromise<GenTableDetailPayload> => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/' + tableId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改代码生成信息
|
||||||
|
export const updateGenTable = (data: DbTableForm): AxiosPromise<unknown> => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导入表
|
||||||
|
export const importTable = (data: { tables: string; dataName: string }): AxiosPromise<unknown> => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/importTable',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 预览生成代码
|
||||||
|
export const previewTable = (tableId: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/preview/' + tableId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除表数据
|
||||||
|
export const delTable = (tableId: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/' + tableId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 同步数据库
|
||||||
|
export const synchDb = (tableId: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/synchDb/' + tableId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取数据源名称
|
||||||
|
export const getDataNames = () => {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/getDataNames',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
215
src/api/tool/gen/types.ts
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
export interface TableVO extends BaseEntity {
|
||||||
|
createDept: number | string;
|
||||||
|
tableId: string | number;
|
||||||
|
dataName: string;
|
||||||
|
tableName: string;
|
||||||
|
tableComment: string;
|
||||||
|
className: string;
|
||||||
|
tplCategory: string;
|
||||||
|
frontendType: string;
|
||||||
|
packageName: string;
|
||||||
|
moduleName: string;
|
||||||
|
businessName: string;
|
||||||
|
functionName: string;
|
||||||
|
functionAuthor: string;
|
||||||
|
pkColumn?: any;
|
||||||
|
columns?: any;
|
||||||
|
options?: any;
|
||||||
|
remark?: any;
|
||||||
|
treeCode?: any;
|
||||||
|
treeParentCode?: any;
|
||||||
|
treeName?: any;
|
||||||
|
menuIds?: any;
|
||||||
|
parentMenuId?: any;
|
||||||
|
parentMenuName?: any;
|
||||||
|
enableExport?: boolean;
|
||||||
|
enableStatus?: boolean;
|
||||||
|
statusField?: string;
|
||||||
|
enableUnique?: boolean;
|
||||||
|
uniqueFields?: string[];
|
||||||
|
enableSort?: boolean;
|
||||||
|
sortField?: string;
|
||||||
|
treeRootValue?: string;
|
||||||
|
treeAncestorsField?: string;
|
||||||
|
treeOrderField?: string;
|
||||||
|
tree: boolean;
|
||||||
|
crud: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TableQuery extends PageQuery {
|
||||||
|
tableName: string;
|
||||||
|
tableComment: string;
|
||||||
|
dataName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbColumnVO extends BaseEntity {
|
||||||
|
createDept?: any;
|
||||||
|
columnId?: any;
|
||||||
|
tableId?: any;
|
||||||
|
columnName?: any;
|
||||||
|
columnComment?: any;
|
||||||
|
columnType?: any;
|
||||||
|
javaType?: any;
|
||||||
|
javaField?: any;
|
||||||
|
isPk?: any;
|
||||||
|
isIncrement?: any;
|
||||||
|
isRequired?: any;
|
||||||
|
isInsert?: any;
|
||||||
|
isEdit?: any;
|
||||||
|
isList?: any;
|
||||||
|
isQuery?: any;
|
||||||
|
queryType?: any;
|
||||||
|
htmlType?: any;
|
||||||
|
dictType?: any;
|
||||||
|
sort?: any;
|
||||||
|
increment: boolean;
|
||||||
|
capJavaField?: any;
|
||||||
|
usableColumn: boolean;
|
||||||
|
superColumn: boolean;
|
||||||
|
list: boolean;
|
||||||
|
pk: boolean;
|
||||||
|
insert: boolean;
|
||||||
|
edit: boolean;
|
||||||
|
query: boolean;
|
||||||
|
required: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTableVO {
|
||||||
|
createDept?: any;
|
||||||
|
tableId?: any;
|
||||||
|
tableName: string;
|
||||||
|
tableComment: string;
|
||||||
|
className?: any;
|
||||||
|
tplCategory?: any;
|
||||||
|
frontendType?: string;
|
||||||
|
packageName?: any;
|
||||||
|
moduleName?: any;
|
||||||
|
businessName?: any;
|
||||||
|
functionName?: any;
|
||||||
|
functionAuthor?: any;
|
||||||
|
pkColumn?: any;
|
||||||
|
columns: DbColumnVO[];
|
||||||
|
options?: any;
|
||||||
|
remark?: any;
|
||||||
|
treeCode?: any;
|
||||||
|
treeParentCode?: any;
|
||||||
|
treeName?: any;
|
||||||
|
menuIds?: any;
|
||||||
|
parentMenuId?: any;
|
||||||
|
parentMenuName?: any;
|
||||||
|
enableExport?: boolean;
|
||||||
|
enableStatus?: boolean;
|
||||||
|
statusField?: string;
|
||||||
|
enableUnique?: boolean;
|
||||||
|
uniqueFields?: string[];
|
||||||
|
enableSort?: boolean;
|
||||||
|
sortField?: string;
|
||||||
|
treeRootValue?: string;
|
||||||
|
treeAncestorsField?: string;
|
||||||
|
treeOrderField?: string;
|
||||||
|
tree: boolean;
|
||||||
|
crud: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTableQuery extends PageQuery {
|
||||||
|
dataName: string;
|
||||||
|
tableName: string;
|
||||||
|
tableComment: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码生成表详情接口 data 结构
|
||||||
|
* - info:当前表 GenTable
|
||||||
|
* - rows:字段列表 GenTableColumn[]
|
||||||
|
*/
|
||||||
|
export interface GenTableDetailPayload {
|
||||||
|
info: DbTableVO;
|
||||||
|
rows: DbColumnVO[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbColumnForm extends BaseEntity {
|
||||||
|
createDept: number;
|
||||||
|
columnId: string;
|
||||||
|
tableId: string;
|
||||||
|
columnName: string;
|
||||||
|
columnComment: string;
|
||||||
|
columnType: string;
|
||||||
|
javaType: string;
|
||||||
|
javaField: string;
|
||||||
|
isPk: string;
|
||||||
|
isIncrement: string;
|
||||||
|
isRequired: string;
|
||||||
|
isInsert?: any;
|
||||||
|
isEdit: string;
|
||||||
|
isList: string;
|
||||||
|
isQuery?: any;
|
||||||
|
queryType: string;
|
||||||
|
htmlType: string;
|
||||||
|
dictType: string;
|
||||||
|
sort: number;
|
||||||
|
increment: boolean;
|
||||||
|
capJavaField: string;
|
||||||
|
usableColumn: boolean;
|
||||||
|
superColumn: boolean;
|
||||||
|
list: boolean;
|
||||||
|
pk: boolean;
|
||||||
|
insert: boolean;
|
||||||
|
edit: boolean;
|
||||||
|
query: boolean;
|
||||||
|
required: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbParamForm {
|
||||||
|
treeCode?: any;
|
||||||
|
treeName?: any;
|
||||||
|
treeParentCode?: any;
|
||||||
|
parentMenuId: string;
|
||||||
|
enableExport?: boolean;
|
||||||
|
enableStatus?: boolean;
|
||||||
|
statusField?: string;
|
||||||
|
enableUnique?: boolean;
|
||||||
|
uniqueFields?: string[];
|
||||||
|
enableSort?: boolean;
|
||||||
|
sortField?: string;
|
||||||
|
treeRootValue?: string;
|
||||||
|
treeAncestorsField?: string;
|
||||||
|
treeOrderField?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTableForm extends BaseEntity {
|
||||||
|
createDept?: any;
|
||||||
|
tableId: string | string;
|
||||||
|
tableName: string;
|
||||||
|
tableComment: string;
|
||||||
|
className: string;
|
||||||
|
tplCategory: string;
|
||||||
|
frontendType: string;
|
||||||
|
packageName: string;
|
||||||
|
moduleName: string;
|
||||||
|
businessName: string;
|
||||||
|
functionName: string;
|
||||||
|
functionAuthor: string;
|
||||||
|
pkColumn?: any;
|
||||||
|
columns: DbColumnForm[];
|
||||||
|
options: string;
|
||||||
|
remark?: any;
|
||||||
|
treeCode?: any;
|
||||||
|
treeParentCode?: any;
|
||||||
|
treeName?: any;
|
||||||
|
menuIds?: any;
|
||||||
|
parentMenuId: string;
|
||||||
|
parentMenuName?: any;
|
||||||
|
enableExport?: boolean;
|
||||||
|
enableStatus?: boolean;
|
||||||
|
statusField?: string;
|
||||||
|
enableUnique?: boolean;
|
||||||
|
uniqueFields?: string[];
|
||||||
|
enableSort?: boolean;
|
||||||
|
sortField?: string;
|
||||||
|
treeRootValue?: string;
|
||||||
|
treeAncestorsField?: string;
|
||||||
|
treeOrderField?: string;
|
||||||
|
tree: boolean;
|
||||||
|
crud: boolean;
|
||||||
|
params: DbParamForm;
|
||||||
|
}
|
||||||
51
src/api/types.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*/
|
||||||
|
export type RegisterForm = {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
confirmPassword?: string;
|
||||||
|
code?: string;
|
||||||
|
uuid?: string;
|
||||||
|
userType?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录请求
|
||||||
|
*/
|
||||||
|
export interface LoginData {
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
rememberMe?: boolean;
|
||||||
|
socialCode?: string;
|
||||||
|
socialState?: string;
|
||||||
|
source?: string;
|
||||||
|
code?: string;
|
||||||
|
uuid?: string;
|
||||||
|
clientId: string;
|
||||||
|
grantType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录响应
|
||||||
|
*/
|
||||||
|
export interface LoginResult {
|
||||||
|
access_token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码返回
|
||||||
|
*/
|
||||||
|
export interface VerifyCodeResult {
|
||||||
|
captchaEnabled: boolean;
|
||||||
|
uuid?: string;
|
||||||
|
img?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页返回结果
|
||||||
|
*/
|
||||||
|
export interface PageResult<T = any> {
|
||||||
|
total: number;
|
||||||
|
rows: T[];
|
||||||
|
}
|
||||||
76
src/api/workflow/category/index.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import type { CategoryForm, CategoryQuery, CategoryTreeVO, CategoryVO } from '@/api/workflow/category/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流程分类列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/category/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流程分类详细
|
||||||
|
* @param categoryId
|
||||||
|
*/
|
||||||
|
export const getCategory = (categoryId: string | number): AxiosPromise<CategoryVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/category/' + categoryId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增流程分类
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addCategory = (data: CategoryForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/category',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改流程分类
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateCategory = (data: CategoryForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/category',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除流程分类
|
||||||
|
* @param categoryId
|
||||||
|
*/
|
||||||
|
export const delCategory = (categoryId: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/category/' + categoryId,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程分类树列表
|
||||||
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const categoryTree = (query?: CategoryForm): AxiosPromise<CategoryTreeVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/category/categoryTree`,
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
67
src/api/workflow/category/types.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
export interface CategoryTreeVO {
|
||||||
|
id: number | string;
|
||||||
|
label: string;
|
||||||
|
parentId: number | string;
|
||||||
|
weight: number;
|
||||||
|
children: CategoryTreeVO[];
|
||||||
|
}
|
||||||
|
export interface CategoryVO {
|
||||||
|
/**
|
||||||
|
* 流程分类ID
|
||||||
|
*/
|
||||||
|
categoryId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父级id
|
||||||
|
*/
|
||||||
|
parentId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程分类名称
|
||||||
|
*/
|
||||||
|
categoryName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示顺序
|
||||||
|
*/
|
||||||
|
orderNum: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
createTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子对象
|
||||||
|
*/
|
||||||
|
children: CategoryVO[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 流程分类ID
|
||||||
|
*/
|
||||||
|
categoryId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程分类名称
|
||||||
|
*/
|
||||||
|
categoryName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父流程分类id
|
||||||
|
*/
|
||||||
|
parentId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示顺序
|
||||||
|
*/
|
||||||
|
orderNum?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryQuery {
|
||||||
|
/**
|
||||||
|
* 流程分类名称
|
||||||
|
*/
|
||||||
|
categoryName?: string;
|
||||||
|
}
|
||||||
176
src/api/workflow/definition/index.ts
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type {
|
||||||
|
definitionXmlVO,
|
||||||
|
FlowDefinitionForm,
|
||||||
|
FlowDefinitionQuery,
|
||||||
|
FlowDefinitionVo
|
||||||
|
} from '@/api/workflow/definition/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程定义列表
|
||||||
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const listDefinition = (query: FlowDefinitionQuery): AxiosPromise<PageResult<FlowDefinitionVo>> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/list`,
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询未发布的流程定义列表
|
||||||
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const unPublishList = (query: FlowDefinitionQuery): AxiosPromise<PageResult<FlowDefinitionVo>> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/unPublishList`,
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过流程定义id获取xml
|
||||||
|
* @param definitionId 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const definitionXml = (definitionId: string): AxiosPromise<definitionXmlVO> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/definitionXml/${definitionId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteDefinition = (id: string | string[]) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/${id}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 挂起/激活
|
||||||
|
* @param definitionId 流程定义id
|
||||||
|
* @param activityStatus 状态
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const active = (definitionId: string, activityStatus: boolean) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/active/${definitionId}`,
|
||||||
|
method: 'put',
|
||||||
|
params: {
|
||||||
|
active: activityStatus
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过zip或xml部署流程定义
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function importDef(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/definition/importDef',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
headers: {
|
||||||
|
repeatSubmit: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const publish = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/publish/${id}`,
|
||||||
|
method: 'put'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消发布流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const unPublish = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/unPublish/${id}`,
|
||||||
|
method: 'put'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程定义xml字符串
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const xmlString = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/xmlString/${id}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const add = (data: FlowDefinitionForm) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const edit = (data: FlowDefinitionForm) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition`,
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询详情
|
||||||
|
* @param id 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getInfo = (id: number | string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/${id}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const copy = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/copy/${id}`,
|
||||||
|
method: 'post'
|
||||||
|
});
|
||||||
|
};
|
||||||
34
src/api/workflow/definition/types.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
export interface FlowDefinitionQuery extends PageQuery {
|
||||||
|
flowCode?: string;
|
||||||
|
flowName?: string;
|
||||||
|
category: string | number;
|
||||||
|
isPublish?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FlowDefinitionVo {
|
||||||
|
id: string;
|
||||||
|
flowName: string;
|
||||||
|
flowCode: string;
|
||||||
|
formPath: string;
|
||||||
|
version: string;
|
||||||
|
isPublish: number;
|
||||||
|
activityStatus: number;
|
||||||
|
createTime: Date;
|
||||||
|
updateTime: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FlowDefinitionForm {
|
||||||
|
id: string;
|
||||||
|
flowName: string;
|
||||||
|
flowCode: string;
|
||||||
|
category: string;
|
||||||
|
ext: string;
|
||||||
|
formPath: string;
|
||||||
|
formCustom: string;
|
||||||
|
modelValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface definitionXmlVO {
|
||||||
|
xml: string[];
|
||||||
|
xmlStr: string;
|
||||||
|
}
|
||||||
126
src/api/workflow/instance/index.ts
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询运行中实例列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByRunning = (query: FlowInstanceQuery): AxiosPromise<PageResult<FlowInstanceVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/instance/pageByRunning',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询已完成实例列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByFinish = (query: FlowInstanceQuery): AxiosPromise<PageResult<FlowInstanceVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/instance/pageByFinish',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过业务id获取历史流程图
|
||||||
|
*/
|
||||||
|
export const flowHisTaskList = (businessId: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/flowHisTaskList/${businessId}?t=${Math.random()}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询当前登录人单据
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByCurrent = (query: FlowInstanceQuery): AxiosPromise<PageResult<FlowInstanceVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/instance/pageByCurrent',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤销流程
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const cancelProcessApply = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/cancelProcessApply`,
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程变量
|
||||||
|
* @param instanceId 实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const instanceVariable = (instanceId: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/instanceVariable/${instanceId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
* @param instanceIds 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteByInstanceIds = (instanceIds: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/deleteByInstanceIds/${instanceIds}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除历史流程实例
|
||||||
|
* @param instanceIds
|
||||||
|
*/
|
||||||
|
export const deleteHisByInstanceIds = (instanceIds: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/deleteHisByInstanceIds/${instanceIds}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作废流程
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const invalid = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/invalid`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 修改流程变量
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const updateVariable = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/updateVariable`,
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
28
src/api/workflow/instance/types.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import type { FlowTaskVO } from '@/api/workflow/task/types';
|
||||||
|
|
||||||
|
export interface FlowInstanceQuery extends PageQuery {
|
||||||
|
category?: string | number;
|
||||||
|
nodeName?: string;
|
||||||
|
flowCode?: string;
|
||||||
|
flowName?: string;
|
||||||
|
createByIds?: Array<string | number>;
|
||||||
|
businessId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FlowInstanceVO extends BaseEntity {
|
||||||
|
id: string | number;
|
||||||
|
definitionId: string;
|
||||||
|
flowName: string;
|
||||||
|
flowCode: string;
|
||||||
|
version: string;
|
||||||
|
businessId: string;
|
||||||
|
activityStatus: number;
|
||||||
|
tenantId: string;
|
||||||
|
createTime: string;
|
||||||
|
createBy: string;
|
||||||
|
flowStatus: string;
|
||||||
|
flowStatusName: string;
|
||||||
|
flowTaskList: FlowTaskVO[];
|
||||||
|
businessCode: string;
|
||||||
|
businessTitle: string;
|
||||||
|
}
|
||||||
76
src/api/workflow/leave/index.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询请假列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listLeave = (query?: LeaveQuery): AxiosPromise<PageResult<LeaveVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/leave/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询请假详细
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getLeave = (id: string | number): AxiosPromise<LeaveVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/leave/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增请假
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/leave',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交请假并发起流程
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const submitAndFlowStart = (data: LeaveForm): AxiosPromise<LeaveVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/leave/submitAndFlowStart',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改请假
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/leave',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除请假
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delLeave = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/leave/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
26
src/api/workflow/leave/types.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export interface LeaveVO {
|
||||||
|
id: string | number;
|
||||||
|
applyCode?: string;
|
||||||
|
leaveType: string;
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
leaveDays: number;
|
||||||
|
remark: string;
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LeaveForm extends BaseEntity {
|
||||||
|
id?: string | number;
|
||||||
|
applyCode?: string;
|
||||||
|
leaveType?: string;
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
leaveDays?: number;
|
||||||
|
remark?: string;
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LeaveQuery extends PageQuery {
|
||||||
|
startLeaveDays?: number;
|
||||||
|
endLeaveDays?: number;
|
||||||
|
}
|
||||||
64
src/api/workflow/spel/index.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { SpelForm, SpelQuery, SpelVO } from '@/api/workflow/spel/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流程spel表达式定义列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listSpel = (query?: SpelQuery): AxiosPromise<PageResult<SpelVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/spel/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流程spel表达式定义详细
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getSpel = (id: string | number): AxiosPromise<SpelVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/spel/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增流程spel表达式定义
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addSpel = (data: SpelForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/spel',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改流程spel表达式定义
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateSpel = (data: SpelForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/spel',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除流程spel表达式定义
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delSpel = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/spel/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
105
src/api/workflow/spel/types.ts
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
export interface SpelVO {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
id: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件名称
|
||||||
|
*/
|
||||||
|
componentName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法名
|
||||||
|
*/
|
||||||
|
methodName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
methodParams: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览spel值
|
||||||
|
*/
|
||||||
|
viewSpel: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
status: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
remark?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SpelForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件名称
|
||||||
|
*/
|
||||||
|
componentName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法名
|
||||||
|
*/
|
||||||
|
methodName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
methodParams?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览spel值
|
||||||
|
*/
|
||||||
|
viewSpel?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
status?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
remark?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SpelQuery extends PageQuery {
|
||||||
|
/**
|
||||||
|
* 组件名称
|
||||||
|
*/
|
||||||
|
componentName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法名
|
||||||
|
*/
|
||||||
|
methodName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
methodParams?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览spel值
|
||||||
|
*/
|
||||||
|
viewSpel?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
status?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期范围参数
|
||||||
|
*/
|
||||||
|
params?: any;
|
||||||
|
}
|
||||||
207
src/api/workflow/task/index.ts
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
import type { PageResult } from '@/api/types';
|
||||||
|
import type { FlowTaskVO, TaskOperationBo, TaskQuery } from '@/api/workflow/task/types';
|
||||||
|
import type { AxiosPromise } from '@/utils/api-types';
|
||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询待办列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByTaskWait = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/pageByTaskWait',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询已办列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByTaskFinish = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/pageByTaskFinish',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询当前用户的抄送列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByTaskCopy = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/pageByTaskCopy',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询全部待办任务
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByAllTaskWait = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/pageByAllTaskWait',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询全部已办任务
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByAllTaskFinish = (query: TaskQuery): AxiosPromise<PageResult<FlowTaskVO>> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/pageByAllTaskFinish',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动流程
|
||||||
|
* @param data
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const startWorkFlow = (data: object): any => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/startWorkFlow',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办理流程
|
||||||
|
* @param data
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const completeTask = (data: object) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/completeTask',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务驳回
|
||||||
|
* @param data
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const backProcess = (data: any): any => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/backProcess',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前任务
|
||||||
|
* @param taskId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getTask = (taskId: string) => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/getTask/' + taskId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改任务办理人
|
||||||
|
* @param taskIdList
|
||||||
|
* @param userId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const updateAssignee = (taskIdList: Array<string>, userId: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/task/updateAssignee/${userId}`,
|
||||||
|
method: 'put',
|
||||||
|
data: taskIdList
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终止任务
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const terminationTask = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/task/terminationTask`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可驳回得任务节点
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getBackTaskNode = (taskId: string | number, nodeCode: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/task/getBackTaskNode/${taskId}/${nodeCode}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务操作 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const taskOperation = (data: TaskOperationBo, operation: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/task/taskOperation/${operation}`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前任务办理人
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const currentTaskAllUser = (taskId: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/task/currentTaskAllUser/${taskId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下一节点写
|
||||||
|
* @param data参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getNextNodeList = (data: any): any => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/getNextNodeList',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 催办任务
|
||||||
|
* @param data参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const urgeTask = (data: any): any => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/task/urgeTask',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
60
src/api/workflow/task/types.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
export interface TaskQuery extends PageQuery {
|
||||||
|
nodeName?: string;
|
||||||
|
flowCode?: string;
|
||||||
|
flowName?: string;
|
||||||
|
createByIds?: Array<string | number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ParticipantVo {
|
||||||
|
groupIds?: string[] | number[];
|
||||||
|
candidate: string[] | number[];
|
||||||
|
candidateName: string[];
|
||||||
|
claim: boolean;
|
||||||
|
}
|
||||||
|
export interface FlowTaskVO {
|
||||||
|
id: string | number;
|
||||||
|
createTime?: Date;
|
||||||
|
updateTime?: Date;
|
||||||
|
tenantId?: string;
|
||||||
|
definitionId?: string;
|
||||||
|
instanceId: string;
|
||||||
|
flowName: string;
|
||||||
|
businessId: string;
|
||||||
|
nodeCode: string;
|
||||||
|
nodeName: string;
|
||||||
|
flowCode: string;
|
||||||
|
flowStatus: string;
|
||||||
|
formCustom: string;
|
||||||
|
formPath: string;
|
||||||
|
nodeType: number;
|
||||||
|
nodeRatio: string | number;
|
||||||
|
version?: string;
|
||||||
|
applyNode?: boolean;
|
||||||
|
buttonList?: ButtonList[];
|
||||||
|
copyList?: FlowCopyVo[];
|
||||||
|
varList?: Map<string, string>;
|
||||||
|
businessCode: string;
|
||||||
|
businessTitle: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ButtonList {
|
||||||
|
code: string;
|
||||||
|
show: boolean;
|
||||||
|
}
|
||||||
|
export interface FlowCopyVo {
|
||||||
|
userId: string | number;
|
||||||
|
nickName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TaskOperationBo {
|
||||||
|
//委派/转办人的用户ID(必填,准对委派/转办人操作)
|
||||||
|
userId?: string;
|
||||||
|
//加签/减签人的用户ID列表(必填,针对加签/减签操作)
|
||||||
|
userIds?: string[];
|
||||||
|
//任务ID(必填)
|
||||||
|
taskId: string | number;
|
||||||
|
//消息类型
|
||||||
|
messageType?: string[];
|
||||||
|
//意见或备注信息(可选)
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
17
src/api/workflow/workflowCommon/index.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
|
||||||
|
import tab from '@/plugins/tab';
|
||||||
|
import router from '@/router';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
routerJump(routerJumpVo: RouterJumpVo) {
|
||||||
|
tab.closePage(router.currentRoute.value);
|
||||||
|
router.push({
|
||||||
|
path: routerJumpVo.formPath,
|
||||||
|
query: {
|
||||||
|
id: routerJumpVo.businessId,
|
||||||
|
type: routerJumpVo.type,
|
||||||
|
taskId: routerJumpVo.taskId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
14
src/api/workflow/workflowCommon/types.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export interface RouterJumpVo {
|
||||||
|
businessId: string;
|
||||||
|
taskId: string | number;
|
||||||
|
type: string;
|
||||||
|
formCustom: string;
|
||||||
|
formPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StartProcessBo {
|
||||||
|
businessId: string | number;
|
||||||
|
flowCode: string;
|
||||||
|
variables: any;
|
||||||
|
bizExt: any;
|
||||||
|
}
|
||||||
BIN
src/assets/401_images/401.gif
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
src/assets/404_images/404.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
src/assets/404_images/404_cloud.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
1
src/assets/icons/svg/404.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
1
src/assets/icons/svg/bug.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
1
src/assets/icons/svg/build.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899741379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2054" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M960 591.424V368.96c0-0.288 0.16-0.512 0.16-0.768S960 367.68 960 367.424V192a32 32 0 0 0-32-32H96a32 32 0 0 0-32 32v175.424c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768v222.464c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768V864a32 32 0 0 0 32 32h832a32 32 0 0 0 32-32v-271.04c0-0.288 0.16-0.512 0.16-0.768S960 591.68 960 591.424z m-560-31.232v-160H608v160h-208z m208 64V832h-208v-207.808H608z m-480-224h208v160H128v-160z m544 0h224v160h-224v-160zM896 224v112.192H128V224h768zM128 624.192h208V832H128v-207.808zM672 832v-207.808h224V832h-224z" p-id="2055"></path></svg>
|
||||||
|
After Width: | Height: | Size: 954 B |
1
src/assets/icons/svg/button.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588670460195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1314" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M230.4 307.712c13.824 0 25.088-11.264 25.088-25.088 0-100.352 81.92-182.272 182.272-182.272s182.272 81.408 182.272 182.272c0 13.824 11.264 25.088 25.088 25.088s25.088-11.264 24.576-25.088c0-127.488-103.936-231.936-231.936-231.936S205.824 154.624 205.824 282.624c-0.512 14.336 10.752 25.088 24.576 25.088z m564.736 234.496c-11.264 0-21.504 2.048-31.232 6.144 0-44.544-40.448-81.92-88.064-81.92-14.848 0-28.16 3.584-39.936 10.24-13.824-28.16-44.544-48.128-78.848-48.128-12.288 0-24.576 2.56-35.328 7.68V284.16c0-45.568-37.888-81.92-84.48-81.92s-84.48 36.864-84.48 81.92v348.672l-69.12-112.64c-18.432-28.16-58.368-36.864-91.136-19.968-26.624 14.336-46.592 47.104-30.208 88.064 3.072 8.192 76.8 205.312 171.52 311.296 0 0 28.16 24.576 43.008 58.88 4.096 9.728 13.312 15.36 22.528 15.36 3.072 0 6.656-0.512 9.728-2.048 12.288-5.12 18.432-19.968 12.8-32.256-19.456-44.544-53.76-74.752-53.76-74.752C281.6 768 209.408 573.44 208.384 570.88c-5.12-12.8-2.56-20.992 7.168-26.112 9.216-4.608 21.504-4.608 26.112 2.56l113.152 184.32c4.096 8.704 12.8 14.336 22.528 14.336 13.824 0 25.088-10.752 25.088-25.088V284.16c0-17.92 15.36-32.256 34.816-32.256s34.816 14.336 34.816 32.256v284.16c0 13.824 10.24 25.088 24.576 25.088 13.824 0 25.088-11.264 25.088-25.088v-57.344c0-17.92 15.36-32.768 34.816-32.768 19.968 0 37.376 15.36 37.376 32.768v95.232c0 7.168 3.072 13.312 7.68 17.92 4.608 4.608 10.752 7.168 17.92 7.168 13.824 0 24.576-11.264 24.576-25.088V547.84c0-18.432 13.824-32.256 32.256-32.256 20.48 0 38.912 15.36 38.912 32.256v95.232c0 13.824 11.264 25.088 25.088 25.088s24.576-11.264 25.088-25.088v-18.944c0-18.944 12.8-32.256 30.72-32.256 18.432 0 22.528 18.944 22.528 31.744 0 1.024-11.776 99.84-50.688 173.056-30.72 58.368-45.056 112.128-51.2 146.944-2.56 13.312 6.656 26.112 19.968 28.672 1.536 0 3.072 0.512 4.608 0.512 11.776 0 22.016-8.192 24.064-20.48 5.632-31.232 18.432-79.36 46.08-132.608 43.52-81.92 55.808-186.88 56.32-193.536-0.512-50.688-29.696-83.968-72.704-83.968z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
1
src/assets/icons/svg/caret-back.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M321.94 98L158.82 237.78a24 24 0 000 36.44L321.94 414c15.57 13.34 39.62 2.28 39.62-18.22v-279.6c0-20.5-24.05-31.56-39.62-18.18z"/></svg>
|
||||||
|
After Width: | Height: | Size: 223 B |
1
src/assets/icons/svg/caret-forward.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M190.06 414l163.12-139.78a24 24 0 000-36.44L190.06 98c-15.57-13.34-39.62-2.28-39.62 18.22v279.6c0 20.5 24.05 31.56 39.62 18.18z"/></svg>
|
||||||
|
After Width: | Height: | Size: 223 B |
1
src/assets/icons/svg/cascader.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576153230908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="971" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M772.87036133 734.06115723c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714843H475.90991211c-56.60705567 0-102.66723633-46.06018067-102.66723633-102.66723633V600.82446289h305.859375c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012S827.9942627 467.50537109 772.87036133 467.50537109c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714844H373.24267578V401.01062011h321.92687989c55.12390137 0 99.94812012-44.82421875 99.94812011-99.94812011V190.07312011C795.11767578 134.94921875 750.29345703 90.125 695.16955567 90.125H251.12963867C196.0057373 90.125 151.18151855 134.94921875 151.18151855 190.07312011V301.0625c0 55.12390137 44.82421875 99.94812012 99.94812012 99.94812012h55.53588867v296.96044921c0 93.35632325 75.97045898 169.32678223 169.32678224 169.32678223h203.19213866c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012s-44.90661622-99.86572266-100.03051758-99.86572265z m0-199.89624024c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857423s-14.91394043 33.28857422-33.28857422 33.28857421-33.28857422-14.91394043-33.28857422-33.28857421 14.91394043-33.28857422 33.28857422-33.28857422zM217.75866699 301.0625V190.07312011c0-18.37463379 14.91394043-33.28857422 33.28857423-33.28857421h444.03991698c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857422V301.0625c0 18.37463379-14.91394043 33.28857422-33.28857422 33.28857422H251.12963867c-18.37463379 0-33.37097168-14.91394043-33.37097168-33.28857422z m555.11169434 566.23535156c-18.37463379 0-33.28857422-14.91394043-33.28857422-33.28857422 0-18.37463379 14.91394043-33.28857422 33.28857422-33.28857422s33.28857422 14.91394043 33.28857422 33.28857422c0.08239747 18.29223633-14.91394043 33.28857422-33.28857422 33.28857422z" p-id="972"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
1
src/assets/icons/svg/category.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg t="1715954426124" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3305" width="200" height="200"><path d="M664.081597 1023.943114a78.246037 78.246037 0 0 1-78.985549-76.795456v-284.996471a78.27448 78.27448 0 0 1 78.985549-76.93767h280.843828A78.189152 78.189152 0 0 1 1023.939417 662.151187v284.996471a78.246037 78.246037 0 0 1-79.013992 76.795456z m-585.067605 0a78.246037 78.246037 0 0 1-78.985549-76.795456v-284.996471a78.160709 78.160709 0 0 1 78.985549-76.93767h280.786942a78.302923 78.302923 0 0 1 79.042434 76.93767v284.996471h-0.170656a78.246037 78.246037 0 0 1-78.985549 76.795456z m0-585.096048a78.217594 78.217594 0 0 1-78.985549-76.93767V76.912925a78.189152 78.189152 0 0 1 78.957106-76.795456h280.786942a78.27448 78.27448 0 0 1 79.042435 76.93767v284.996471a78.27448 78.27448 0 0 1-79.013992 76.795456z m589.675333-5.688552a77.193655 77.193655 0 0 1-77.990052-75.885288V75.888985a77.25054 77.25054 0 0 1 77.990052-75.942173h277.26004a77.25054 77.25054 0 0 1 77.961609 75.942173v281.384241a77.421197 77.421197 0 0 1-78.132266 75.885288z" p-id="3306" fill="currentColor"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |