Commit f3e1fc4f9b9fb13db52ba8ebd4458ab17356ae67

Authored by xingyu
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
README.md
... ... @@ -193,7 +193,7 @@ ps:核心功能已经实现,正在对接微信小程序中...
193 193 |----------------------------------------------------------------------|------------------|--------|
194 194 | [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.37 |
195 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 197 | [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.7.4 |
198 198 | [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.17 |
199 199 | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.1.10 |
... ...
yudao-ui-admin-vue3/README.md
1 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 17 - 基于 vue3.2+ ,TypeScript ,Element Plus 2.2.0+ ,Vite3 ,Pinia ,Windicss 等开发的后台管理系统
... ... @@ -12,19 +24,19 @@
12 24  
13 25 ### 前端依赖
14 26  
15   -| 框架 | 说明 | 版本 |
16   -| --- | --- | --- |
  27 +| 框架 | 说明 | 版本 |
  28 +| --- | --- |--------|
17 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 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 41 ### 推荐 VScode 开发,插件如下
30 42  
... ...
yudao-ui-admin-vue3/package.json
... ... @@ -56,12 +56,12 @@
56 56 "devDependencies": {
57 57 "@commitlint/cli": "^17.0.3",
58 58 "@commitlint/config-conventional": "^17.0.3",
59   - "@iconify/json": "^2.1.84",
  59 + "@iconify/json": "^2.1.85",
60 60 "@intlify/vite-plugin-vue-i18n": "^5.0.1",
61 61 "@purge-icons/generated": "^0.8.1",
62 62 "@types/intro.js": "^5.1.0",
63 63 "@types/lodash-es": "^4.17.6",
64   - "@types/node": "^18.6.1",
  64 + "@types/node": "^18.6.2",
65 65 "@types/nprogress": "^0.2.0",
66 66 "@types/qrcode": "^1.4.2",
67 67 "@types/qs": "^6.9.7",
... ... @@ -101,8 +101,7 @@
101 101 "vite-plugin-svg-icons": "^2.0.1",
102 102 "vite-plugin-windicss": "^1.8.7",
103 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 106 "engines": {
108 107 "node": ">= 14.18.0"
... ...
yudao-ui-admin-vue3/src/api/bpm/task/types.ts
... ... @@ -7,3 +7,33 @@ export type FormVO = {
7 7 remark: string
8 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) =&gt; {
24 24 })
25 25 }
26 26 // 获取缓存内容
27   -export const getKeyValue = (key: string) => {
  27 +export const getKeyValueApi = (key: string) => {
28 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 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 37 return request.delete({
38 38 url: '/infra/redis/delete-keys?',
39 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 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 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 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 57 </template>
6   -
7   -<style scoped></style>
... ...
yudao-ui-admin-vue3/src/views/infra/redis/index.vue
... ... @@ -13,7 +13,8 @@ import {
13 13 ElTableColumn,
14 14 ElScrollbar,
15 15 ElDescriptions,
16   - ElDescriptionsItem
  16 + ElDescriptionsItem,
  17 + ElMessage
17 18 } from 'element-plus'
18 19 const cache = ref<RedisMonitorInfoVO>()
19 20 const keyListLoad = ref(true)
... ... @@ -121,7 +122,33 @@ const loadEchartOptions = (stats) =&gt; {
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 152 onBeforeMount(() => {
126 153 readRedisInfo()
127 154 })
... ... @@ -186,7 +213,12 @@ onBeforeMount(() =&gt; {
186 213 <el-row style="margin-top: 10px">
187 214 <el-col :span="24" class="card-box" shadow="hover">
188 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 222 <el-table-column prop="keyTemplate" label="Key 模板" width="200" />
191 223 <el-table-column prop="keyType" label="Key 类型" width="100" />
192 224 <el-table-column prop="valueType" label="Value 类型" />
... ... @@ -202,4 +234,58 @@ onBeforeMount(() =&gt; {
202 234 </el-col>
203 235 </el-row>
204 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 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 1 <script setup lang="ts">
2   -import { reactive, ref, unref } from 'vue'
  2 +import { onMounted, reactive, ref, unref } from 'vue'
3 3 import dayjs from 'dayjs'
4 4 import { DICT_TYPE, getDictOptions } from '@/utils/dict'
5 5 import { useTable } from '@/hooks/web/useTable'
... ... @@ -18,7 +18,7 @@ import {
18 18 ElMessage,
19 19 ElTree,
20 20 ElCard,
21   - ElCheckbox
  21 + ElSwitch
22 22 } from 'element-plus'
23 23 import { listSimpleMenusApi } from '@/api/system/menu'
24 24 import { listSimpleDeptApi } from '@/api/system/dept'
... ... @@ -98,7 +98,6 @@ const dataScopeForm = reactive({
98 98 name: '',
99 99 code: '',
100 100 dataScope: 0,
101   - checkStrictly: true,
102 101 checkList: []
103 102 })
104 103 const defaultProps = {
... ... @@ -113,15 +112,18 @@ const dialogScopeTitle = ref(&#39;数据权限&#39;)
113 112 const actionScopeType = ref('')
114 113 const dataScopeDictDatas = ref()
115 114 // 选项
  115 +const checkStrictly = ref(true)
116 116 const treeNodeAll = ref(false)
117 117 // 权限操作
118 118 const handleScope = async (type: string, row: RoleVO) => {
  119 + checkStrictly.value = true
  120 + treeNodeAll.value = false
  121 + dataScopeForm.dataScope = 0
119 122 dataScopeForm.name = row.name
120 123 dataScopeForm.code = row.code
121 124 if (type === 'menu') {
122 125 const menuRes = await listSimpleMenusApi()
123 126 treeOptions.value = handleTree(menuRes)
124   - dataScopeDictDatas.value = getDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE)
125 127 } else if (type === 'dept') {
126 128 const deptRes = await listSimpleDeptApi()
127 129 treeOptions.value = handleTree(deptRes)
... ... @@ -129,20 +131,22 @@ const handleScope = async (type: string, row: RoleVO) =&gt; {
129 131 actionScopeType.value = type
130 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 138 // TODO:保存
141 139 const submitScope = () => {
142 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 150 </script>
147 151  
148 152 <template>
... ... @@ -261,7 +265,7 @@ getList()
261 265 <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
262 266 </template>
263 267 </Dialog>
264   - <Dialog v-model="dialogScopeVisible" :title="dialogScopeTitle">
  268 + <Dialog v-model="dialogScopeVisible" :title="dialogScopeTitle" max-height="600px">
265 269 <el-form :model="dataScopeForm">
266 270 <el-form-item label="角色名称">
267 271 <el-input v-model="dataScopeForm.name" :disabled="true" />
... ... @@ -289,21 +293,23 @@ getList()
289 293 >
290 294 <el-card class="box-card">
291 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 306 </template>
301 307 <el-tree
302 308 ref="treeRef"
303 309 node-key="id"
304 310 show-checkbox
305 311 default-expand-all
306   - :check-strictly="dataScopeForm.checkStrictly"
  312 + :check-strictly="!checkStrictly"
307 313 :props="defaultProps"
308 314 :data="treeOptions"
309 315 empty-text="加载中,请稍后"
... ...
yudao-ui-admin-vue3/windi.config.ts
1   -import { defineConfig } from 'windicss/helpers'
  1 +import { defineConfig } from 'vite-plugin-windicss'
2 2 import plugin from 'windicss/plugin'
3 3  
4 4 function range(size, startAt = 1) {
... ... @@ -18,22 +18,7 @@ export default defineConfig({
18 18 // 暗黑背景色
19 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 23 plugins: [
39 24 plugin(({ addComponents }) => {
... ...