Commit f3e1fc4f9b9fb13db52ba8ebd4458ab17356ae67
Committed by
芋道源码
1 parent
35413b52
!238 新增 todo done 页面,优化redis页面
* chore: update deps * feat: add todo done pages * chore: update deps * docs: update * feat: redis dialog
Showing
12 changed files
with
466 additions
and
68 deletions
README.md
| @@ -193,7 +193,7 @@ ps:核心功能已经实现,正在对接微信小程序中... | @@ -193,7 +193,7 @@ ps:核心功能已经实现,正在对接微信小程序中... | ||
| 193 | |----------------------------------------------------------------------|------------------|--------| | 193 | |----------------------------------------------------------------------|------------------|--------| |
| 194 | | [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.37 | | 194 | | [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.37 | |
| 195 | | [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.3 | | 195 | | [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.3 | |
| 196 | -| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.9 | | 196 | +| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.11 | |
| 197 | | [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.7.4 | | 197 | | [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.7.4 | |
| 198 | | [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.17 | | 198 | | [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.17 | |
| 199 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.1.10 | | 199 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.1.10 | |
yudao-ui-admin-vue3/README.md
| 1 | <h1>🌈 yudao-ui-admin-vue3</h1> | 1 | <h1>🌈 yudao-ui-admin-vue3</h1> |
| 2 | - | 2 | +<p align="center"> |
| 3 | + <img src="https://img.shields.io/badge/-Vue3.2-34495e?logo=vue.j" /> | ||
| 4 | + <img src="https://img.shields.io/badge/-Vite3-646cff?logo=vite&logoColor=white" /> | ||
| 5 | + <img src="https://img.shields.io/badge/-TypeScript4.7-blue?logo=typescript&logoColor=white" /> | ||
| 6 | + <img src="https://img.shields.io/badge/-Pinia2-yellow?logo=picpay&logoColor=white" /> | ||
| 7 | + <img src="https://img.shields.io/badge/-ESLint-4b32c3?logo=eslint&logoColor=white" /> | ||
| 8 | + <img src="https://img.shields.io/badge/-pnpm7-F69220?logo=pnpm&logoColor=white" /> | ||
| 9 | + <img src="https://img.shields.io/badge/-Axios-008fc7?logo=axios.js&logoColor=white" /> | ||
| 10 | + <img src="https://img.shields.io/badge/-Prettier-ef9421?logo=Prettier&logoColor=white" alt="Prettier"> | ||
| 11 | + <img src="https://img.shields.io/badge/-Less-1D365D?logo=less&logoColor=white" alt="Less"> | ||
| 12 | + <img src="https://img.shields.io/badge/-Wind%20CSS-06B6D4?logo=Tailwind%20CSS&logoColor=white" alt="Taiwind"> | ||
| 13 | + <img src="" alt=""> | ||
| 14 | +</p> | ||
| 3 | ## 介绍 | 15 | ## 介绍 |
| 4 | 16 | ||
| 5 | - 基于 vue3.2+ ,TypeScript ,Element Plus 2.2.0+ ,Vite3 ,Pinia ,Windicss 等开发的后台管理系统 | 17 | - 基于 vue3.2+ ,TypeScript ,Element Plus 2.2.0+ ,Vite3 ,Pinia ,Windicss 等开发的后台管理系统 |
| @@ -12,19 +24,19 @@ | @@ -12,19 +24,19 @@ | ||
| 12 | 24 | ||
| 13 | ### 前端依赖 | 25 | ### 前端依赖 |
| 14 | 26 | ||
| 15 | -| 框架 | 说明 | 版本 | | ||
| 16 | -| --- | --- | --- | | 27 | +| 框架 | 说明 | 版本 | |
| 28 | +| --- | --- |--------| | ||
| 17 | | [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.37 | | 29 | | [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.37 | |
| 18 | -| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.2 | | ||
| 19 | -| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.9 | | ||
| 20 | -| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.7.4 | | ||
| 21 | -| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.16 | | ||
| 22 | -| [vueuse](https://vueuse.org//) | 常用工具集 | 8.9.4 | | 30 | +| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.3 | |
| 31 | +| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.11 | | ||
| 32 | +| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.7.4 | | ||
| 33 | +| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.17 | | ||
| 34 | +| [vueuse](https://vueuse.org//) | 常用工具集 | 9.0.0 | | ||
| 23 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.1.10 | | 35 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.1.10 | |
| 24 | -| [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.2 | | ||
| 25 | -| [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 | | ||
| 26 | -| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 | | ||
| 27 | -| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.10 | | 36 | +| [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.3 | |
| 37 | +| [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 | | ||
| 38 | +| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 | | ||
| 39 | +| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.14 | | ||
| 28 | 40 | ||
| 29 | ### 推荐 VScode 开发,插件如下 | 41 | ### 推荐 VScode 开发,插件如下 |
| 30 | 42 |
yudao-ui-admin-vue3/package.json
| @@ -56,12 +56,12 @@ | @@ -56,12 +56,12 @@ | ||
| 56 | "devDependencies": { | 56 | "devDependencies": { |
| 57 | "@commitlint/cli": "^17.0.3", | 57 | "@commitlint/cli": "^17.0.3", |
| 58 | "@commitlint/config-conventional": "^17.0.3", | 58 | "@commitlint/config-conventional": "^17.0.3", |
| 59 | - "@iconify/json": "^2.1.84", | 59 | + "@iconify/json": "^2.1.85", |
| 60 | "@intlify/vite-plugin-vue-i18n": "^5.0.1", | 60 | "@intlify/vite-plugin-vue-i18n": "^5.0.1", |
| 61 | "@purge-icons/generated": "^0.8.1", | 61 | "@purge-icons/generated": "^0.8.1", |
| 62 | "@types/intro.js": "^5.1.0", | 62 | "@types/intro.js": "^5.1.0", |
| 63 | "@types/lodash-es": "^4.17.6", | 63 | "@types/lodash-es": "^4.17.6", |
| 64 | - "@types/node": "^18.6.1", | 64 | + "@types/node": "^18.6.2", |
| 65 | "@types/nprogress": "^0.2.0", | 65 | "@types/nprogress": "^0.2.0", |
| 66 | "@types/qrcode": "^1.4.2", | 66 | "@types/qrcode": "^1.4.2", |
| 67 | "@types/qs": "^6.9.7", | 67 | "@types/qs": "^6.9.7", |
| @@ -101,8 +101,7 @@ | @@ -101,8 +101,7 @@ | ||
| 101 | "vite-plugin-svg-icons": "^2.0.1", | 101 | "vite-plugin-svg-icons": "^2.0.1", |
| 102 | "vite-plugin-windicss": "^1.8.7", | 102 | "vite-plugin-windicss": "^1.8.7", |
| 103 | "vue-tsc": "^0.39.2", | 103 | "vue-tsc": "^0.39.2", |
| 104 | - "windicss": "^3.5.6", | ||
| 105 | - "windicss-analysis": "^0.3.5" | 104 | + "windicss": "^3.5.6" |
| 106 | }, | 105 | }, |
| 107 | "engines": { | 106 | "engines": { |
| 108 | "node": ">= 14.18.0" | 107 | "node": ">= 14.18.0" |
yudao-ui-admin-vue3/src/api/bpm/task/types.ts
| @@ -7,3 +7,33 @@ export type FormVO = { | @@ -7,3 +7,33 @@ export type FormVO = { | ||
| 7 | remark: string | 7 | remark: string |
| 8 | createTime: string | 8 | createTime: string |
| 9 | } | 9 | } |
| 10 | + | ||
| 11 | +export type TaskProcessVO = { | ||
| 12 | + id: string | ||
| 13 | + name: string | ||
| 14 | + startUserId: number | ||
| 15 | + startUserNickname: string | ||
| 16 | + processDefinitionId: string | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +export type TaskTodoVO = { | ||
| 20 | + id: string | ||
| 21 | + name: string | ||
| 22 | + claimTime: string | ||
| 23 | + createTime: string | ||
| 24 | + suspensionState: number | ||
| 25 | + processInstance: TaskProcessVO | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +export type TaskDoneVO = { | ||
| 29 | + id: string | ||
| 30 | + name: string | ||
| 31 | + claimTime: string | ||
| 32 | + createTime: string | ||
| 33 | + endTime: string | ||
| 34 | + durationInMillis: number | ||
| 35 | + suspensionState: number | ||
| 36 | + result: number | ||
| 37 | + reason: string | ||
| 38 | + processInstance: TaskProcessVO | ||
| 39 | +} |
yudao-ui-admin-vue3/src/api/infra/redis/index.ts
| @@ -24,16 +24,16 @@ export const getKeyListApi = (keyTemplate: string) => { | @@ -24,16 +24,16 @@ export const getKeyListApi = (keyTemplate: string) => { | ||
| 24 | }) | 24 | }) |
| 25 | } | 25 | } |
| 26 | // 获取缓存内容 | 26 | // 获取缓存内容 |
| 27 | -export const getKeyValue = (key: string) => { | 27 | +export const getKeyValueApi = (key: string) => { |
| 28 | return request.get({ url: '/infra/redis/get-key-value?key=' + key }) | 28 | return request.get({ url: '/infra/redis/get-key-value?key=' + key }) |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | // 根据键名删除缓存 | 31 | // 根据键名删除缓存 |
| 32 | -export const deleteKey = (key: string) => { | 32 | +export const deleteKeyApi = (key: string) => { |
| 33 | return request.delete({ url: '/infra/redis/delete-key?key=' + key }) | 33 | return request.delete({ url: '/infra/redis/delete-key?key=' + key }) |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | -export const deleteKeys = (keyTemplate: string) => { | 36 | +export const deleteKeysApi = (keyTemplate: string) => { |
| 37 | return request.delete({ | 37 | return request.delete({ |
| 38 | url: '/infra/redis/delete-keys?', | 38 | url: '/infra/redis/delete-keys?', |
| 39 | params: { | 39 | params: { |
yudao-ui-admin-vue3/src/views/bpm/task/done/done.data.ts
0 → 100644
| 1 | +import { reactive } from 'vue' | ||
| 2 | +import { useI18n } from '@/hooks/web/useI18n' | ||
| 3 | +import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' | ||
| 4 | +import { DICT_TYPE } from '@/utils/dict' | ||
| 5 | +const { t } = useI18n() // 国际化 | ||
| 6 | + | ||
| 7 | +// CrudSchema | ||
| 8 | +const crudSchemas = reactive<CrudSchema[]>([ | ||
| 9 | + { | ||
| 10 | + label: t('common.index'), | ||
| 11 | + field: 'id', | ||
| 12 | + type: 'index' | ||
| 13 | + }, | ||
| 14 | + { | ||
| 15 | + label: '任务名称', | ||
| 16 | + field: 'name', | ||
| 17 | + search: { | ||
| 18 | + show: true | ||
| 19 | + } | ||
| 20 | + }, | ||
| 21 | + { | ||
| 22 | + label: '所属流程', | ||
| 23 | + field: 'processInstance.name' | ||
| 24 | + }, | ||
| 25 | + { | ||
| 26 | + label: '流程发起人', | ||
| 27 | + field: 'processInstance.startUserNickname' | ||
| 28 | + }, | ||
| 29 | + { | ||
| 30 | + label: '结果', | ||
| 31 | + field: 'result', | ||
| 32 | + dictType: DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT | ||
| 33 | + }, | ||
| 34 | + { | ||
| 35 | + label: '审批意见', | ||
| 36 | + field: 'reason' | ||
| 37 | + }, | ||
| 38 | + { | ||
| 39 | + label: t('common.createTime'), | ||
| 40 | + field: 'createTime', | ||
| 41 | + search: { | ||
| 42 | + show: true, | ||
| 43 | + component: 'DatePicker', | ||
| 44 | + componentProps: { | ||
| 45 | + type: 'datetimerange', | ||
| 46 | + valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||
| 47 | + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)], | ||
| 48 | + shortcuts: [ | ||
| 49 | + { | ||
| 50 | + text: '近一周', | ||
| 51 | + value: () => { | ||
| 52 | + const end = new Date() | ||
| 53 | + const start = new Date() | ||
| 54 | + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7) | ||
| 55 | + return [start, end] | ||
| 56 | + } | ||
| 57 | + }, | ||
| 58 | + { | ||
| 59 | + text: '近一个月', | ||
| 60 | + value: () => { | ||
| 61 | + const end = new Date() | ||
| 62 | + const start = new Date() | ||
| 63 | + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30) | ||
| 64 | + return [start, end] | ||
| 65 | + } | ||
| 66 | + }, | ||
| 67 | + { | ||
| 68 | + text: '近三个月', | ||
| 69 | + value: () => { | ||
| 70 | + const end = new Date() | ||
| 71 | + const start = new Date() | ||
| 72 | + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90) | ||
| 73 | + return [start, end] | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + ] | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + }, | ||
| 80 | + { | ||
| 81 | + label: '审批时间', | ||
| 82 | + field: 'endTime' | ||
| 83 | + }, | ||
| 84 | + { | ||
| 85 | + label: '耗时', | ||
| 86 | + field: 'durationInMillis' | ||
| 87 | + }, | ||
| 88 | + { | ||
| 89 | + label: t('table.action'), | ||
| 90 | + field: 'action', | ||
| 91 | + width: '100px' | ||
| 92 | + } | ||
| 93 | +]) | ||
| 94 | +export const { allSchemas } = useCrudSchemas(crudSchemas) |
yudao-ui-admin-vue3/src/views/bpm/task/done/index.vue
| 1 | -<script setup lang="ts"></script> | 1 | +<script setup lang="ts"> |
| 2 | +import dayjs from 'dayjs' | ||
| 3 | +import duration from 'dayjs/plugin/duration' | ||
| 4 | +import { DICT_TYPE } from '@/utils/dict' | ||
| 5 | +import { useTable } from '@/hooks/web/useTable' | ||
| 6 | +import { useI18n } from '@/hooks/web/useI18n' | ||
| 7 | +import type { TaskDoneVO } from '@/api/bpm/task/types' | ||
| 8 | +import { allSchemas } from './done.data' | ||
| 9 | +import * as TaskDoneApi from '@/api/bpm/task' | ||
| 10 | +import { useRouter } from 'vue-router' | ||
| 11 | +dayjs.extend(duration) | ||
| 12 | +const { t } = useI18n() // 国际化 | ||
| 13 | +const { push } = useRouter() | ||
| 14 | +// ========== 列表相关 ========== | ||
| 15 | +const { register, tableObject, methods } = useTable<TaskDoneVO>({ | ||
| 16 | + getListApi: TaskDoneApi.getDoneTaskPage | ||
| 17 | +}) | ||
| 18 | +const { getList, setSearchParams } = methods | ||
| 19 | + | ||
| 20 | +// 审批操作 | ||
| 21 | +const handleAudit = async (row: TaskDoneVO) => { | ||
| 22 | + push('/bpm/process-instance/detail?id=' + row.processInstance.id) | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +// ========== 初始化 ========== | ||
| 26 | +getList() | ||
| 27 | +</script> | ||
| 2 | 28 | ||
| 3 | <template> | 29 | <template> |
| 4 | - <div>index</div> | 30 | + <!-- 搜索工作区 --> |
| 31 | + <ContentWrap> | ||
| 32 | + <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" /> | ||
| 33 | + </ContentWrap> | ||
| 34 | + <ContentWrap> | ||
| 35 | + <!-- 列表 --> | ||
| 36 | + <Table | ||
| 37 | + :columns="allSchemas.tableColumns" | ||
| 38 | + :selection="false" | ||
| 39 | + :data="tableObject.tableList" | ||
| 40 | + :loading="tableObject.loading" | ||
| 41 | + :pagination="{ | ||
| 42 | + total: tableObject.total | ||
| 43 | + }" | ||
| 44 | + v-model:pageSize="tableObject.pageSize" | ||
| 45 | + v-model:currentPage="tableObject.currentPage" | ||
| 46 | + @register="register" | ||
| 47 | + > | ||
| 48 | + <template #status="{ row }"> | ||
| 49 | + <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" /> | ||
| 50 | + </template> | ||
| 51 | + <template #createTime="{ row }"> | ||
| 52 | + <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span> | ||
| 53 | + </template> | ||
| 54 | + <template #endTime="{ row }"> | ||
| 55 | + <span>{{ dayjs(row.endTime).format('YYYY-MM-DD HH:mm:ss') }}</span> | ||
| 56 | + </template> | ||
| 57 | + <template #durationInMillis="{ row }"> | ||
| 58 | + <span>{{ dayjs.duration(row.durationInMillis).asMilliseconds() }}</span> | ||
| 59 | + </template> | ||
| 60 | + <template #action="{ row }"> | ||
| 61 | + <el-button link type="primary" v-hasPermi="['bpm:task:query']" @click="handleAudit(row)"> | ||
| 62 | + <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }} | ||
| 63 | + </el-button> | ||
| 64 | + </template> | ||
| 65 | + </Table> | ||
| 66 | + </ContentWrap> | ||
| 5 | </template> | 67 | </template> |
| 6 | - | ||
| 7 | -<style scoped></style> |
yudao-ui-admin-vue3/src/views/bpm/task/todo/done.data.ts
0 → 100644
| 1 | +import { reactive } from 'vue' | ||
| 2 | +import { useI18n } from '@/hooks/web/useI18n' | ||
| 3 | +import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' | ||
| 4 | +const { t } = useI18n() // 国际化 | ||
| 5 | + | ||
| 6 | +// CrudSchema | ||
| 7 | +const crudSchemas = reactive<CrudSchema[]>([ | ||
| 8 | + { | ||
| 9 | + label: t('common.index'), | ||
| 10 | + field: 'id', | ||
| 11 | + type: 'index' | ||
| 12 | + }, | ||
| 13 | + { | ||
| 14 | + label: '任务名称', | ||
| 15 | + field: 'name', | ||
| 16 | + search: { | ||
| 17 | + show: true | ||
| 18 | + } | ||
| 19 | + }, | ||
| 20 | + { | ||
| 21 | + label: '所属流程', | ||
| 22 | + field: 'processInstance.name' | ||
| 23 | + }, | ||
| 24 | + { | ||
| 25 | + label: '流程发起人', | ||
| 26 | + field: 'processInstance.startUserNickname' | ||
| 27 | + }, | ||
| 28 | + { | ||
| 29 | + label: t('common.createTime'), | ||
| 30 | + field: 'createTime', | ||
| 31 | + search: { | ||
| 32 | + show: true, | ||
| 33 | + component: 'DatePicker', | ||
| 34 | + componentProps: { | ||
| 35 | + type: 'datetimerange', | ||
| 36 | + valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||
| 37 | + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)], | ||
| 38 | + shortcuts: [ | ||
| 39 | + { | ||
| 40 | + text: '近一周', | ||
| 41 | + value: () => { | ||
| 42 | + const end = new Date() | ||
| 43 | + const start = new Date() | ||
| 44 | + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7) | ||
| 45 | + return [start, end] | ||
| 46 | + } | ||
| 47 | + }, | ||
| 48 | + { | ||
| 49 | + text: '近一个月', | ||
| 50 | + value: () => { | ||
| 51 | + const end = new Date() | ||
| 52 | + const start = new Date() | ||
| 53 | + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30) | ||
| 54 | + return [start, end] | ||
| 55 | + } | ||
| 56 | + }, | ||
| 57 | + { | ||
| 58 | + text: '近三个月', | ||
| 59 | + value: () => { | ||
| 60 | + const end = new Date() | ||
| 61 | + const start = new Date() | ||
| 62 | + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90) | ||
| 63 | + return [start, end] | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + ] | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + }, | ||
| 70 | + { | ||
| 71 | + label: t('table.action'), | ||
| 72 | + field: 'action', | ||
| 73 | + width: '100px' | ||
| 74 | + } | ||
| 75 | +]) | ||
| 76 | +export const { allSchemas } = useCrudSchemas(crudSchemas) |
yudao-ui-admin-vue3/src/views/bpm/task/todo/index.vue
| 1 | -<script setup lang="ts"></script> | 1 | +<script setup lang="ts"> |
| 2 | +import dayjs from 'dayjs' | ||
| 3 | +import { DICT_TYPE } from '@/utils/dict' | ||
| 4 | +import { useTable } from '@/hooks/web/useTable' | ||
| 5 | +import type { TaskTodoVO } from '@/api/bpm/task/types' | ||
| 6 | +import { allSchemas } from './done.data' | ||
| 7 | +import * as TaskTodoApi from '@/api/bpm/task' | ||
| 8 | +import { useRouter } from 'vue-router' | ||
| 9 | +const { push } = useRouter() | ||
| 10 | +// ========== 列表相关 ========== | ||
| 11 | +const { register, tableObject, methods } = useTable<TaskTodoVO>({ | ||
| 12 | + getListApi: TaskTodoApi.getTodoTaskPage | ||
| 13 | +}) | ||
| 14 | +const { getList, setSearchParams } = methods | ||
| 15 | + | ||
| 16 | +// 审批操作 | ||
| 17 | +const handleAudit = async (row: TaskTodoVO) => { | ||
| 18 | + push('/bpm/process-instance/detail?id=' + row.processInstance.id) | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +// ========== 初始化 ========== | ||
| 22 | +getList() | ||
| 23 | +</script> | ||
| 2 | 24 | ||
| 3 | <template> | 25 | <template> |
| 4 | - <div>index</div> | 26 | + <!-- 搜索工作区 --> |
| 27 | + <ContentWrap> | ||
| 28 | + <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" /> | ||
| 29 | + </ContentWrap> | ||
| 30 | + <ContentWrap> | ||
| 31 | + <!-- 列表 --> | ||
| 32 | + <Table | ||
| 33 | + :columns="allSchemas.tableColumns" | ||
| 34 | + :selection="false" | ||
| 35 | + :data="tableObject.tableList" | ||
| 36 | + :loading="tableObject.loading" | ||
| 37 | + :pagination="{ | ||
| 38 | + total: tableObject.total | ||
| 39 | + }" | ||
| 40 | + v-model:pageSize="tableObject.pageSize" | ||
| 41 | + v-model:currentPage="tableObject.currentPage" | ||
| 42 | + @register="register" | ||
| 43 | + > | ||
| 44 | + <template #status="{ row }"> | ||
| 45 | + <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" /> | ||
| 46 | + </template> | ||
| 47 | + <template #createTime="{ row }"> | ||
| 48 | + <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span> | ||
| 49 | + </template> | ||
| 50 | + <template #action="{ row }"> | ||
| 51 | + <el-button link type="primary" v-hasPermi="['bpm:task:update']" @click="handleAudit(row)"> | ||
| 52 | + <Icon icon="ep:edit" class="mr-1px" /> 审批 | ||
| 53 | + </el-button> | ||
| 54 | + </template> | ||
| 55 | + </Table> | ||
| 56 | + </ContentWrap> | ||
| 5 | </template> | 57 | </template> |
| 6 | - | ||
| 7 | -<style scoped></style> |
yudao-ui-admin-vue3/src/views/infra/redis/index.vue
| @@ -13,7 +13,8 @@ import { | @@ -13,7 +13,8 @@ import { | ||
| 13 | ElTableColumn, | 13 | ElTableColumn, |
| 14 | ElScrollbar, | 14 | ElScrollbar, |
| 15 | ElDescriptions, | 15 | ElDescriptions, |
| 16 | - ElDescriptionsItem | 16 | + ElDescriptionsItem, |
| 17 | + ElMessage | ||
| 17 | } from 'element-plus' | 18 | } from 'element-plus' |
| 18 | const cache = ref<RedisMonitorInfoVO>() | 19 | const cache = ref<RedisMonitorInfoVO>() |
| 19 | const keyListLoad = ref(true) | 20 | const keyListLoad = ref(true) |
| @@ -121,7 +122,33 @@ const loadEchartOptions = (stats) => { | @@ -121,7 +122,33 @@ const loadEchartOptions = (stats) => { | ||
| 121 | ] | 122 | ] |
| 122 | }) | 123 | }) |
| 123 | } | 124 | } |
| 124 | - | 125 | +const dialogVisible = ref(false) |
| 126 | +const keyTemplate = ref('') | ||
| 127 | +const cacheKeys = ref() | ||
| 128 | +const cacheForm = ref<{ | ||
| 129 | + key: string | ||
| 130 | + value: string | ||
| 131 | +}>({ | ||
| 132 | + key: '', | ||
| 133 | + value: '' | ||
| 134 | +}) | ||
| 135 | +const openKeyTemplate = async (row: RedisKeyInfo) => { | ||
| 136 | + keyTemplate.value = row.keyTemplate | ||
| 137 | + cacheKeys.value = await RedisApi.getKeyListApi(row.keyTemplate) | ||
| 138 | + dialogVisible.value = true | ||
| 139 | +} | ||
| 140 | +const handleDeleteKey = async (row) => { | ||
| 141 | + RedisApi.deleteKeyApi(row) | ||
| 142 | + ElMessage.success('删除成功') | ||
| 143 | +} | ||
| 144 | +const handleDeleteKeys = async (row) => { | ||
| 145 | + RedisApi.deleteKeysApi(row) | ||
| 146 | + ElMessage.success('删除成功') | ||
| 147 | +} | ||
| 148 | +const handleKeyValue = async (row) => { | ||
| 149 | + const res = await RedisApi.getKeyValueApi(row) | ||
| 150 | + cacheForm.value = res | ||
| 151 | +} | ||
| 125 | onBeforeMount(() => { | 152 | onBeforeMount(() => { |
| 126 | readRedisInfo() | 153 | readRedisInfo() |
| 127 | }) | 154 | }) |
| @@ -186,7 +213,12 @@ onBeforeMount(() => { | @@ -186,7 +213,12 @@ onBeforeMount(() => { | ||
| 186 | <el-row style="margin-top: 10px"> | 213 | <el-row style="margin-top: 10px"> |
| 187 | <el-col :span="24" class="card-box" shadow="hover"> | 214 | <el-col :span="24" class="card-box" shadow="hover"> |
| 188 | <el-card> | 215 | <el-card> |
| 189 | - <el-table v-loading="keyListLoad" :data="keyList" row-key="id"> | 216 | + <el-table |
| 217 | + v-loading="keyListLoad" | ||
| 218 | + :data="keyList" | ||
| 219 | + row-key="id" | ||
| 220 | + @row-click="openKeyTemplate" | ||
| 221 | + > | ||
| 190 | <el-table-column prop="keyTemplate" label="Key 模板" width="200" /> | 222 | <el-table-column prop="keyTemplate" label="Key 模板" width="200" /> |
| 191 | <el-table-column prop="keyType" label="Key 类型" width="100" /> | 223 | <el-table-column prop="keyType" label="Key 类型" width="100" /> |
| 192 | <el-table-column prop="valueType" label="Value 类型" /> | 224 | <el-table-column prop="valueType" label="Value 类型" /> |
| @@ -202,4 +234,58 @@ onBeforeMount(() => { | @@ -202,4 +234,58 @@ onBeforeMount(() => { | ||
| 202 | </el-col> | 234 | </el-col> |
| 203 | </el-row> | 235 | </el-row> |
| 204 | </el-scrollbar> | 236 | </el-scrollbar> |
| 237 | + <Dialog v-model="dialogVisible" :title="keyTemplate + ' 模板'" width="60%" maxHeight="800px"> | ||
| 238 | + <el-row> | ||
| 239 | + <el-col :span="14" style="margin-top: 10px"> | ||
| 240 | + <el-card shadow="always"> | ||
| 241 | + <template #header> | ||
| 242 | + <div class="card-header"> | ||
| 243 | + <span>键名列表</span> | ||
| 244 | + </div> | ||
| 245 | + </template> | ||
| 246 | + <el-table :data="cacheKeys" style="width: 100%" @row-click="handleKeyValue"> | ||
| 247 | + <el-table-column label="缓存键名" align="center" :show-overflow-tooltip="true"> | ||
| 248 | + <template #default="{ row }"> | ||
| 249 | + {{ row }} | ||
| 250 | + </template> | ||
| 251 | + </el-table-column> | ||
| 252 | + <el-table-column label="操作" align="right" width="60"> | ||
| 253 | + <template #default="{ row }"> | ||
| 254 | + <el-button link type="primary" @click="handleDeleteKey(row)"> | ||
| 255 | + <Icon icon="ep:delete" /> | ||
| 256 | + </el-button> | ||
| 257 | + </template> | ||
| 258 | + </el-table-column> | ||
| 259 | + </el-table> | ||
| 260 | + </el-card> | ||
| 261 | + </el-col> | ||
| 262 | + <el-col :span="10" style="margin-top: 10px"> | ||
| 263 | + <el-card shadow="always"> | ||
| 264 | + <template #header> | ||
| 265 | + <div class="card-header"> | ||
| 266 | + <span>缓存内容</span> | ||
| 267 | + <el-button | ||
| 268 | + link | ||
| 269 | + type="primary" | ||
| 270 | + @click="handleDeleteKeys(keyTemplate)" | ||
| 271 | + style="float: right; padding: 3px 0" | ||
| 272 | + > | ||
| 273 | + <Icon icon="ep:refresh" />清理全部 | ||
| 274 | + </el-button> | ||
| 275 | + </div> | ||
| 276 | + </template> | ||
| 277 | + <el-descriptions :column="1"> | ||
| 278 | + <el-descriptions-item label="缓存键名:">{{ cacheForm.key }}</el-descriptions-item> | ||
| 279 | + <el-descriptions-item label="缓存内容:">{{ cacheForm.value }}</el-descriptions-item> | ||
| 280 | + </el-descriptions> | ||
| 281 | + </el-card> | ||
| 282 | + </el-col> | ||
| 283 | + </el-row> | ||
| 284 | + </Dialog> | ||
| 205 | </template> | 285 | </template> |
| 286 | +<style scoped> | ||
| 287 | +.redis { | ||
| 288 | + height: 600px; | ||
| 289 | + max-height: 860px; | ||
| 290 | +} | ||
| 291 | +</style> |
yudao-ui-admin-vue3/src/views/system/role/index.vue
| 1 | <script setup lang="ts"> | 1 | <script setup lang="ts"> |
| 2 | -import { reactive, ref, unref } from 'vue' | 2 | +import { onMounted, reactive, ref, unref } from 'vue' |
| 3 | import dayjs from 'dayjs' | 3 | import dayjs from 'dayjs' |
| 4 | import { DICT_TYPE, getDictOptions } from '@/utils/dict' | 4 | import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
| 5 | import { useTable } from '@/hooks/web/useTable' | 5 | import { useTable } from '@/hooks/web/useTable' |
| @@ -18,7 +18,7 @@ import { | @@ -18,7 +18,7 @@ import { | ||
| 18 | ElMessage, | 18 | ElMessage, |
| 19 | ElTree, | 19 | ElTree, |
| 20 | ElCard, | 20 | ElCard, |
| 21 | - ElCheckbox | 21 | + ElSwitch |
| 22 | } from 'element-plus' | 22 | } from 'element-plus' |
| 23 | import { listSimpleMenusApi } from '@/api/system/menu' | 23 | import { listSimpleMenusApi } from '@/api/system/menu' |
| 24 | import { listSimpleDeptApi } from '@/api/system/dept' | 24 | import { listSimpleDeptApi } from '@/api/system/dept' |
| @@ -98,7 +98,6 @@ const dataScopeForm = reactive({ | @@ -98,7 +98,6 @@ const dataScopeForm = reactive({ | ||
| 98 | name: '', | 98 | name: '', |
| 99 | code: '', | 99 | code: '', |
| 100 | dataScope: 0, | 100 | dataScope: 0, |
| 101 | - checkStrictly: true, | ||
| 102 | checkList: [] | 101 | checkList: [] |
| 103 | }) | 102 | }) |
| 104 | const defaultProps = { | 103 | const defaultProps = { |
| @@ -113,15 +112,18 @@ const dialogScopeTitle = ref('数据权限') | @@ -113,15 +112,18 @@ const dialogScopeTitle = ref('数据权限') | ||
| 113 | const actionScopeType = ref('') | 112 | const actionScopeType = ref('') |
| 114 | const dataScopeDictDatas = ref() | 113 | const dataScopeDictDatas = ref() |
| 115 | // 选项 | 114 | // 选项 |
| 115 | +const checkStrictly = ref(true) | ||
| 116 | const treeNodeAll = ref(false) | 116 | const treeNodeAll = ref(false) |
| 117 | // 权限操作 | 117 | // 权限操作 |
| 118 | const handleScope = async (type: string, row: RoleVO) => { | 118 | const handleScope = async (type: string, row: RoleVO) => { |
| 119 | + checkStrictly.value = true | ||
| 120 | + treeNodeAll.value = false | ||
| 121 | + dataScopeForm.dataScope = 0 | ||
| 119 | dataScopeForm.name = row.name | 122 | dataScopeForm.name = row.name |
| 120 | dataScopeForm.code = row.code | 123 | dataScopeForm.code = row.code |
| 121 | if (type === 'menu') { | 124 | if (type === 'menu') { |
| 122 | const menuRes = await listSimpleMenusApi() | 125 | const menuRes = await listSimpleMenusApi() |
| 123 | treeOptions.value = handleTree(menuRes) | 126 | treeOptions.value = handleTree(menuRes) |
| 124 | - dataScopeDictDatas.value = getDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE) | ||
| 125 | } else if (type === 'dept') { | 127 | } else if (type === 'dept') { |
| 126 | const deptRes = await listSimpleDeptApi() | 128 | const deptRes = await listSimpleDeptApi() |
| 127 | treeOptions.value = handleTree(deptRes) | 129 | treeOptions.value = handleTree(deptRes) |
| @@ -129,20 +131,22 @@ const handleScope = async (type: string, row: RoleVO) => { | @@ -129,20 +131,22 @@ const handleScope = async (type: string, row: RoleVO) => { | ||
| 129 | actionScopeType.value = type | 131 | actionScopeType.value = type |
| 130 | dialogScopeVisible.value = true | 132 | dialogScopeVisible.value = true |
| 131 | } | 133 | } |
| 132 | -// 树权限(父子联动) | ||
| 133 | -const handleCheckedTreeConnect = (value) => { | ||
| 134 | - dataScopeForm.checkStrictly = value ? true : false | ||
| 135 | -} | ||
| 136 | // 全选/全不选 | 134 | // 全选/全不选 |
| 137 | -const handleCheckedTreeNodeAll = (value) => { | ||
| 138 | - treeRef.value?.setCheckedNodes(value ? dataScopeForm.checkList : []) | 135 | +const handleCheckedTreeNodeAll = () => { |
| 136 | + treeRef.value?.setCheckedNodes(treeNodeAll.value ? treeOptions.value : []) | ||
| 139 | } | 137 | } |
| 140 | // TODO:保存 | 138 | // TODO:保存 |
| 141 | const submitScope = () => { | 139 | const submitScope = () => { |
| 142 | console.info() | 140 | console.info() |
| 143 | } | 141 | } |
| 142 | +const init = () => { | ||
| 143 | + dataScopeDictDatas.value = getDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE) | ||
| 144 | +} | ||
| 144 | // ========== 初始化 ========== | 145 | // ========== 初始化 ========== |
| 145 | -getList() | 146 | +onMounted(() => { |
| 147 | + getList() | ||
| 148 | + init() | ||
| 149 | +}) | ||
| 146 | </script> | 150 | </script> |
| 147 | 151 | ||
| 148 | <template> | 152 | <template> |
| @@ -261,7 +265,7 @@ getList() | @@ -261,7 +265,7 @@ getList() | ||
| 261 | <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button> | 265 | <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button> |
| 262 | </template> | 266 | </template> |
| 263 | </Dialog> | 267 | </Dialog> |
| 264 | - <Dialog v-model="dialogScopeVisible" :title="dialogScopeTitle"> | 268 | + <Dialog v-model="dialogScopeVisible" :title="dialogScopeTitle" max-height="600px"> |
| 265 | <el-form :model="dataScopeForm"> | 269 | <el-form :model="dataScopeForm"> |
| 266 | <el-form-item label="角色名称"> | 270 | <el-form-item label="角色名称"> |
| 267 | <el-input v-model="dataScopeForm.name" :disabled="true" /> | 271 | <el-input v-model="dataScopeForm.name" :disabled="true" /> |
| @@ -289,21 +293,23 @@ getList() | @@ -289,21 +293,23 @@ getList() | ||
| 289 | > | 293 | > |
| 290 | <el-card class="box-card"> | 294 | <el-card class="box-card"> |
| 291 | <template #header> | 295 | <template #header> |
| 292 | - <el-checkbox | ||
| 293 | - :checked="!dataScopeForm.checkStrictly" | ||
| 294 | - @change="handleCheckedTreeConnect($event)" | ||
| 295 | - >父子联动(选中父节点,自动选择子节点) | ||
| 296 | - </el-checkbox> | ||
| 297 | - <el-checkbox v-model="treeNodeAll" @change="handleCheckedTreeNodeAll($event)"> | ||
| 298 | - 全选/全不选 | ||
| 299 | - </el-checkbox> | 296 | + 父子联动(选中父节点,自动选择子节点): |
| 297 | + <el-switch v-model="checkStrictly" inline-prompt active-text="是" inactive-text="否" /> | ||
| 298 | + 全选/全不选: | ||
| 299 | + <el-switch | ||
| 300 | + v-model="treeNodeAll" | ||
| 301 | + inline-prompt | ||
| 302 | + active-text="是" | ||
| 303 | + inactive-text="否" | ||
| 304 | + @change="handleCheckedTreeNodeAll()" | ||
| 305 | + /> | ||
| 300 | </template> | 306 | </template> |
| 301 | <el-tree | 307 | <el-tree |
| 302 | ref="treeRef" | 308 | ref="treeRef" |
| 303 | node-key="id" | 309 | node-key="id" |
| 304 | show-checkbox | 310 | show-checkbox |
| 305 | default-expand-all | 311 | default-expand-all |
| 306 | - :check-strictly="dataScopeForm.checkStrictly" | 312 | + :check-strictly="!checkStrictly" |
| 307 | :props="defaultProps" | 313 | :props="defaultProps" |
| 308 | :data="treeOptions" | 314 | :data="treeOptions" |
| 309 | empty-text="加载中,请稍后" | 315 | empty-text="加载中,请稍后" |
yudao-ui-admin-vue3/windi.config.ts
| 1 | -import { defineConfig } from 'windicss/helpers' | 1 | +import { defineConfig } from 'vite-plugin-windicss' |
| 2 | import plugin from 'windicss/plugin' | 2 | import plugin from 'windicss/plugin' |
| 3 | 3 | ||
| 4 | function range(size, startAt = 1) { | 4 | function range(size, startAt = 1) { |
| @@ -18,22 +18,7 @@ export default defineConfig({ | @@ -18,22 +18,7 @@ export default defineConfig({ | ||
| 18 | // 暗黑背景色 | 18 | // 暗黑背景色 |
| 19 | 'v-dark': 'var(--dark-bg-color)' | 19 | 'v-dark': 'var(--dark-bg-color)' |
| 20 | } | 20 | } |
| 21 | - // screens: { | ||
| 22 | - // sm: '768px', | ||
| 23 | - // md: '992px', | ||
| 24 | - // lg: '1200px', | ||
| 25 | - // xl: '1920px' | ||
| 26 | - // } | ||
| 27 | } | 21 | } |
| 28 | - // height: { | ||
| 29 | - // ...range(50).map((i) => `h-${i}px`) | ||
| 30 | - // }, | ||
| 31 | - // margin: { | ||
| 32 | - // // ...range(50).map((i) => `mt-${i}px`), | ||
| 33 | - // // ...range(50).map((i) => `mr-${i}px`), | ||
| 34 | - // // ...range(50).map((i) => `mb-${i}px`), | ||
| 35 | - // // ...range(50).map((i) => `ml-${i}px`) | ||
| 36 | - // } | ||
| 37 | }, | 22 | }, |
| 38 | plugins: [ | 23 | plugins: [ |
| 39 | plugin(({ addComponents }) => { | 24 | plugin(({ addComponents }) => { |