Commit 8cfc0736faf6a303ebfaee523d9bfc059f1ccdac
1 parent
753d8dda
refactor: use vxeCrud refactor menus
Showing
5 changed files
with
120 additions
and
150 deletions
yudao-ui-admin-vue3/src/router/index.ts
| @@ -14,7 +14,7 @@ import { usePermissionStoreWithOut } from '@/store/modules/permission' | @@ -14,7 +14,7 @@ import { usePermissionStoreWithOut } from '@/store/modules/permission' | ||
| 14 | import { getInfoApi } from '@/api/login' | 14 | import { getInfoApi } from '@/api/login' |
| 15 | import { listSimpleDictDataApi } from '@/api/system/dict/dict.data' | 15 | import { listSimpleDictDataApi } from '@/api/system/dict/dict.data' |
| 16 | 16 | ||
| 17 | -const { wsCache } = useCache('sessionStorage') | 17 | +const { wsCache } = useCache() |
| 18 | 18 | ||
| 19 | const { start, done } = useNProgress() | 19 | const { start, done } = useNProgress() |
| 20 | 20 |
yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts
| @@ -12,8 +12,7 @@ export const rules = reactive({ | @@ -12,8 +12,7 @@ export const rules = reactive({ | ||
| 12 | email: [required], | 12 | email: [required], |
| 13 | phone: [ | 13 | phone: [ |
| 14 | { | 14 | { |
| 15 | - min: 11, | ||
| 16 | - max: 11, | 15 | + len: 11, |
| 17 | trigger: 'blur', | 16 | trigger: 'blur', |
| 18 | message: '请输入正确的手机号码' | 17 | message: '请输入正确的手机号码' |
| 19 | } | 18 | } |
yudao-ui-admin-vue3/src/views/system/dept/index.vue
| @@ -75,16 +75,15 @@ | @@ -75,16 +75,15 @@ | ||
| 75 | </XModal> | 75 | </XModal> |
| 76 | </template> | 76 | </template> |
| 77 | <script setup lang="ts" name="Dept"> | 77 | <script setup lang="ts" name="Dept"> |
| 78 | -import { nextTick, onMounted, reactive, ref, unref } from 'vue' | 78 | +import { nextTick, onMounted, ref, unref } from 'vue' |
| 79 | import { ElSelect, ElTreeSelect, ElOption } from 'element-plus' | 79 | import { ElSelect, ElTreeSelect, ElOption } from 'element-plus' |
| 80 | import { VxeGridInstance } from 'vxe-table' | 80 | import { VxeGridInstance } from 'vxe-table' |
| 81 | import { handleTree, defaultProps } from '@/utils/tree' | 81 | import { handleTree, defaultProps } from '@/utils/tree' |
| 82 | -import { required } from '@/utils/formRules.js' | ||
| 83 | import { useI18n } from '@/hooks/web/useI18n' | 82 | import { useI18n } from '@/hooks/web/useI18n' |
| 84 | import { useMessage } from '@/hooks/web/useMessage' | 83 | import { useMessage } from '@/hooks/web/useMessage' |
| 85 | import { useVxeGrid } from '@/hooks/web/useVxeGrid' | 84 | import { useVxeGrid } from '@/hooks/web/useVxeGrid' |
| 86 | import { FormExpose } from '@/components/Form' | 85 | import { FormExpose } from '@/components/Form' |
| 87 | -import { allSchemas } from './dept.data' | 86 | +import { allSchemas, rules } from './dept.data' |
| 88 | import * as DeptApi from '@/api/system/dept' | 87 | import * as DeptApi from '@/api/system/dept' |
| 89 | import { getListSimpleUsersApi, UserVO } from '@/api/system/user' | 88 | import { getListSimpleUsersApi, UserVO } from '@/api/system/user' |
| 90 | 89 | ||
| @@ -107,13 +106,6 @@ const actionLoading = ref(false) // 遮罩层 | @@ -107,13 +106,6 @@ const actionLoading = ref(false) // 遮罩层 | ||
| 107 | const formRef = ref<FormExpose>() // 表单 Ref | 106 | const formRef = ref<FormExpose>() // 表单 Ref |
| 108 | const deptOptions = ref() // 树形结构 | 107 | const deptOptions = ref() // 树形结构 |
| 109 | const userOption = ref<UserVO[]>([]) | 108 | const userOption = ref<UserVO[]>([]) |
| 110 | -// 新增和修改的表单校验 | ||
| 111 | -const rules = reactive({ | ||
| 112 | - name: [required], | ||
| 113 | - sort: [required], | ||
| 114 | - path: [required], | ||
| 115 | - status: [required] | ||
| 116 | -}) | ||
| 117 | 109 | ||
| 118 | const getUserList = async () => { | 110 | const getUserList = async () => { |
| 119 | const res = await getListSimpleUsersApi() | 111 | const res = await getListSimpleUsersApi() |
yudao-ui-admin-vue3/src/views/system/menu/index.vue
| 1 | <template> | 1 | <template> |
| 2 | <ContentWrap> | 2 | <ContentWrap> |
| 3 | - <!-- 搜索工作栏 --> | ||
| 4 | - <el-form :model="queryParams" ref="queryForm" :inline="true"> | ||
| 5 | - <el-form-item label="菜单名称" prop="name"> | ||
| 6 | - <el-input v-model="queryParams.name" placeholder="请输入菜单名称" /> | ||
| 7 | - </el-form-item> | ||
| 8 | - <el-form-item label="状态" prop="status"> | ||
| 9 | - <el-select v-model="queryParams.status" placeholder="请选择菜单状态"> | ||
| 10 | - <el-option | ||
| 11 | - v-for="(dict, index) in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" | ||
| 12 | - :key="index" | ||
| 13 | - :label="dict.label" | ||
| 14 | - :value="dict.value" | ||
| 15 | - /> | ||
| 16 | - </el-select> | ||
| 17 | - </el-form-item> | ||
| 18 | - <el-form-item> | ||
| 19 | - <!-- 操作:搜索 --> | ||
| 20 | - <XButton | ||
| 21 | - type="primary" | ||
| 22 | - preIcon="ep:search" | ||
| 23 | - :title="t('common.query')" | ||
| 24 | - @click="handleQuery()" | ||
| 25 | - /> | ||
| 26 | - <!-- 操作:重置 --> | ||
| 27 | - <XButton preIcon="ep:refresh-right" :title="t('common.reset')" @click="resetQuery()" /> | ||
| 28 | - </el-form-item> | ||
| 29 | - </el-form> | ||
| 30 | - <vxe-toolbar> | ||
| 31 | - <template #buttons> | 3 | + <!-- 列表 --> |
| 4 | + <vxe-grid ref="xGrid" v-bind="gridOptions" show-overflow class="xtable-scrollbar"> | ||
| 5 | + <template #toolbar_buttons> | ||
| 32 | <!-- 操作:新增 --> | 6 | <!-- 操作:新增 --> |
| 33 | <XButton | 7 | <XButton |
| 34 | type="primary" | 8 | type="primary" |
| @@ -37,63 +11,26 @@ | @@ -37,63 +11,26 @@ | ||
| 37 | v-hasPermi="['system:menu:create']" | 11 | v-hasPermi="['system:menu:create']" |
| 38 | @click="handleCreate()" | 12 | @click="handleCreate()" |
| 39 | /> | 13 | /> |
| 40 | - <XButton title="展开所有" @click="xTable?.setAllTreeExpand(true)" /> | ||
| 41 | - <XButton title="关闭所有" @click="xTable?.clearTreeExpand()" /> | 14 | + <XButton title="展开所有" @click="xGrid?.setAllTreeExpand(true)" /> |
| 15 | + <XButton title="关闭所有" @click="xGrid?.clearTreeExpand()" /> | ||
| 42 | </template> | 16 | </template> |
| 43 | - </vxe-toolbar> | ||
| 44 | - <!-- 列表 --> | ||
| 45 | - <vxe-table | ||
| 46 | - show-overflow | ||
| 47 | - keep-source | ||
| 48 | - ref="xTable" | ||
| 49 | - :loading="tableLoading" | ||
| 50 | - :row-config="{ keyField: 'id' }" | ||
| 51 | - :column-config="{ resizable: true }" | ||
| 52 | - :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }" | ||
| 53 | - :print-config="{}" | ||
| 54 | - :export-config="{}" | ||
| 55 | - :data="tableData" | ||
| 56 | - > | ||
| 57 | - <vxe-column title="菜单名称" field="name" width="200" tree-node> | ||
| 58 | - <template #default="{ row }"> | ||
| 59 | - <Icon :icon="row.icon" /> | ||
| 60 | - <span class="ml-3">{{ row.name }}</span> | ||
| 61 | - </template> | ||
| 62 | - </vxe-column> | ||
| 63 | - <vxe-column title="菜单类型" field="type"> | ||
| 64 | - <template #default="{ row }"> | ||
| 65 | - <DictTag :type="DICT_TYPE.SYSTEM_MENU_TYPE" :value="row.type" /> | ||
| 66 | - </template> | ||
| 67 | - </vxe-column> | ||
| 68 | - <vxe-column title="路由地址" field="path" /> | ||
| 69 | - <vxe-column title="组件路径" field="component" /> | ||
| 70 | - <vxe-column title="权限标识" field="permission" /> | ||
| 71 | - <vxe-column title="排序" field="sort" /> | ||
| 72 | - <vxe-column title="状态" field="status"> | ||
| 73 | - <template #default="{ row }"> | ||
| 74 | - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" /> | ||
| 75 | - </template> | ||
| 76 | - </vxe-column> | ||
| 77 | - <vxe-column title="创建时间" field="createTime" formatter="formatDate" /> | ||
| 78 | - <vxe-column title="操作" width="200"> | ||
| 79 | - <template #default="{ row }"> | ||
| 80 | - <!-- 操作:修改 --> | ||
| 81 | - <XTextButton | ||
| 82 | - preIcon="ep:edit" | ||
| 83 | - :title="t('action.edit')" | ||
| 84 | - v-hasPermi="['system:menu:update']" | ||
| 85 | - @click="handleUpdate(row.id)" | ||
| 86 | - /> | ||
| 87 | - <!-- 操作:删除 --> | ||
| 88 | - <XTextButton | ||
| 89 | - preIcon="ep:delete" | ||
| 90 | - :title="t('action.del')" | ||
| 91 | - v-hasPermi="['system:menu:delete']" | ||
| 92 | - @click="handleDelete(row.id)" | ||
| 93 | - /> | ||
| 94 | - </template> | ||
| 95 | - </vxe-column> | ||
| 96 | - </vxe-table> | 17 | + <template #actionbtns_default="{ row }"> |
| 18 | + <!-- 操作:修改 --> | ||
| 19 | + <XTextButton | ||
| 20 | + preIcon="ep:edit" | ||
| 21 | + :title="t('action.edit')" | ||
| 22 | + v-hasPermi="['system:menu:update']" | ||
| 23 | + @click="handleUpdate(row.id)" | ||
| 24 | + /> | ||
| 25 | + <!-- 操作:删除 --> | ||
| 26 | + <XTextButton | ||
| 27 | + preIcon="ep:delete" | ||
| 28 | + :title="t('action.del')" | ||
| 29 | + v-hasPermi="['system:menu:delete']" | ||
| 30 | + @click="handleDelete(row.id)" | ||
| 31 | + /> | ||
| 32 | + </template> | ||
| 33 | + </vxe-grid> | ||
| 97 | </ContentWrap> | 34 | </ContentWrap> |
| 98 | <!-- 添加或修改菜单对话框 --> | 35 | <!-- 添加或修改菜单对话框 --> |
| 99 | <XModal id="menuModel" v-model="dialogVisible" :title="dialogTitle"> | 36 | <XModal id="menuModel" v-model="dialogVisible" :title="dialogTitle"> |
| @@ -235,7 +172,7 @@ | @@ -235,7 +172,7 @@ | ||
| 235 | </template> | 172 | </template> |
| 236 | <script setup lang="ts" name="Menu"> | 173 | <script setup lang="ts" name="Menu"> |
| 237 | // 全局相关的 import | 174 | // 全局相关的 import |
| 238 | -import { onMounted, reactive, ref } from 'vue' | 175 | +import { ref } from 'vue' |
| 239 | import { useI18n } from '@/hooks/web/useI18n' | 176 | import { useI18n } from '@/hooks/web/useI18n' |
| 240 | import { CACHE_KEY, useCache } from '@/hooks/web/useCache' | 177 | import { CACHE_KEY, useCache } from '@/hooks/web/useCache' |
| 241 | import { useMessage } from '@/hooks/web/useMessage' | 178 | import { useMessage } from '@/hooks/web/useMessage' |
| @@ -245,9 +182,7 @@ import { | @@ -245,9 +182,7 @@ import { | ||
| 245 | ElFormItem, | 182 | ElFormItem, |
| 246 | ElInput, | 183 | ElInput, |
| 247 | ElInputNumber, | 184 | ElInputNumber, |
| 248 | - ElSelect, | ||
| 249 | ElTreeSelect, | 185 | ElTreeSelect, |
| 250 | - ElOption, | ||
| 251 | ElRadio, | 186 | ElRadio, |
| 252 | ElRadioGroup, | 187 | ElRadioGroup, |
| 253 | ElRadioButton, | 188 | ElRadioButton, |
| @@ -255,21 +190,33 @@ import { | @@ -255,21 +190,33 @@ import { | ||
| 255 | } from 'element-plus' | 190 | } from 'element-plus' |
| 256 | import { Tooltip } from '@/components/Tooltip' | 191 | import { Tooltip } from '@/components/Tooltip' |
| 257 | import { IconSelect } from '@/components/Icon' | 192 | import { IconSelect } from '@/components/Icon' |
| 258 | -import { VxeTableInstance } from 'vxe-table' | 193 | +import { VxeGridInstance } from 'vxe-table' |
| 259 | // 业务相关的 import | 194 | // 业务相关的 import |
| 260 | -import * as MenuApi from '@/api/system/menu' | ||
| 261 | -import { required } from '@/utils/formRules.js' | ||
| 262 | import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' | 195 | import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' |
| 263 | import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants' | 196 | import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants' |
| 264 | import { handleTree, defaultProps } from '@/utils/tree' | 197 | import { handleTree, defaultProps } from '@/utils/tree' |
| 198 | +import * as MenuApi from '@/api/system/menu' | ||
| 199 | +import { allSchemas, rules } from './menu.data' | ||
| 200 | +import { useVxeGrid } from '@/hooks/web/useVxeGrid' | ||
| 265 | 201 | ||
| 266 | const { t } = useI18n() // 国际化 | 202 | const { t } = useI18n() // 国际化 |
| 267 | const message = useMessage() // 消息弹窗 | 203 | const message = useMessage() // 消息弹窗 |
| 268 | const { wsCache } = useCache() | 204 | const { wsCache } = useCache() |
| 269 | // 列表相关的变量 | 205 | // 列表相关的变量 |
| 270 | -const xTable = ref<VxeTableInstance>() | ||
| 271 | -const tableLoading = ref(false) | ||
| 272 | -const tableData = ref() | 206 | +// 列表相关的变量 |
| 207 | +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref | ||
| 208 | +const treeConfig = { | ||
| 209 | + transform: true, | ||
| 210 | + rowField: 'id', | ||
| 211 | + parentField: 'parentId', | ||
| 212 | + expandAll: false | ||
| 213 | +} | ||
| 214 | +const { gridOptions, getList, deleteData } = useVxeGrid<MenuApi.MenuVO>({ | ||
| 215 | + allSchemas: allSchemas, | ||
| 216 | + treeConfig: treeConfig, | ||
| 217 | + getListApi: MenuApi.getMenuListApi, | ||
| 218 | + deleteApi: MenuApi.deleteMenuApi | ||
| 219 | +}) | ||
| 273 | // 弹窗相关的变量 | 220 | // 弹窗相关的变量 |
| 274 | const dialogVisible = ref(false) // 是否显示弹出层 | 221 | const dialogVisible = ref(false) // 是否显示弹出层 |
| 275 | const dialogTitle = ref('edit') // 弹出层标题 | 222 | const dialogTitle = ref('edit') // 弹出层标题 |
| @@ -292,13 +239,6 @@ const menuForm = ref<MenuApi.MenuVO>({ | @@ -292,13 +239,6 @@ const menuForm = ref<MenuApi.MenuVO>({ | ||
| 292 | keepAlive: true, | 239 | keepAlive: true, |
| 293 | createTime: new Date() | 240 | createTime: new Date() |
| 294 | }) | 241 | }) |
| 295 | -// 新增和修改的表单校验 | ||
| 296 | -const rules = reactive({ | ||
| 297 | - name: [required], | ||
| 298 | - sort: [required], | ||
| 299 | - path: [required], | ||
| 300 | - status: [required] | ||
| 301 | -}) | ||
| 302 | 242 | ||
| 303 | // ========== 下拉框[上级菜单] ========== | 243 | // ========== 下拉框[上级菜单] ========== |
| 304 | const menuOptions = ref<any[]>([]) // 树形结构 | 244 | const menuOptions = ref<any[]>([]) // 树形结构 |
| @@ -311,31 +251,6 @@ const getTree = async () => { | @@ -311,31 +251,6 @@ const getTree = async () => { | ||
| 311 | menuOptions.value.push(menu) | 251 | menuOptions.value.push(menu) |
| 312 | } | 252 | } |
| 313 | 253 | ||
| 314 | -// ========== 查询 ========== | ||
| 315 | -const queryParams = reactive<MenuApi.MenuPageReqVO>({ | ||
| 316 | - name: undefined, | ||
| 317 | - status: undefined | ||
| 318 | -}) | ||
| 319 | -// 执行查询 | ||
| 320 | -const getList = async () => { | ||
| 321 | - tableLoading.value = true | ||
| 322 | - const res = await MenuApi.getMenuListApi(queryParams) | ||
| 323 | - tableData.value = res | ||
| 324 | - tableLoading.value = false | ||
| 325 | -} | ||
| 326 | - | ||
| 327 | -// 查询操作 | ||
| 328 | -const handleQuery = async () => { | ||
| 329 | - await getList() | ||
| 330 | -} | ||
| 331 | - | ||
| 332 | -// 重置操作 | ||
| 333 | -const resetQuery = async () => { | ||
| 334 | - queryParams.name = undefined | ||
| 335 | - queryParams.status = undefined | ||
| 336 | - await getList() | ||
| 337 | -} | ||
| 338 | - | ||
| 339 | // ========== 新增/修改 ========== | 254 | // ========== 新增/修改 ========== |
| 340 | 255 | ||
| 341 | // 设置标题 | 256 | // 设置标题 |
| @@ -407,7 +322,7 @@ const submitForm = async () => { | @@ -407,7 +322,7 @@ const submitForm = async () => { | ||
| 407 | actionLoading.value = false | 322 | actionLoading.value = false |
| 408 | wsCache.delete(CACHE_KEY.ROLE_ROUTERS) | 323 | wsCache.delete(CACHE_KEY.ROLE_ROUTERS) |
| 409 | // 操作成功,重新加载列表 | 324 | // 操作成功,重新加载列表 |
| 410 | - await getList() | 325 | + await getList(xGrid) |
| 411 | } | 326 | } |
| 412 | } | 327 | } |
| 413 | 328 | ||
| @@ -419,15 +334,6 @@ const isExternal = (path: string) => { | @@ -419,15 +334,6 @@ const isExternal = (path: string) => { | ||
| 419 | // ========== 删除 ========== | 334 | // ========== 删除 ========== |
| 420 | // 删除操作 | 335 | // 删除操作 |
| 421 | const handleDelete = async (rowId: number) => { | 336 | const handleDelete = async (rowId: number) => { |
| 422 | - message.delConfirm().then(async () => { | ||
| 423 | - await MenuApi.deleteMenuApi(rowId) | ||
| 424 | - message.success(t('common.delSuccess')) | ||
| 425 | - await getList() | ||
| 426 | - }) | 337 | + await deleteData(xGrid, rowId) |
| 427 | } | 338 | } |
| 428 | - | ||
| 429 | -// ========== 初始化 ========== | ||
| 430 | -onMounted(async () => { | ||
| 431 | - await getList() | ||
| 432 | -}) | ||
| 433 | </script> | 339 | </script> |
yudao-ui-admin-vue3/src/views/system/menu/menu.data.ts
0 → 100644
| 1 | +import { reactive } from 'vue' | ||
| 2 | +import { useI18n } from '@/hooks/web/useI18n' | ||
| 3 | +import { DICT_TYPE } from '@/utils/dict' | ||
| 4 | +import { required } from '@/utils/formRules' | ||
| 5 | +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas' | ||
| 6 | +const { t } = useI18n() // 国际化 | ||
| 7 | + | ||
| 8 | +// 新增和修改的表单校验 | ||
| 9 | +export const rules = reactive({ | ||
| 10 | + name: [required], | ||
| 11 | + sort: [required], | ||
| 12 | + path: [required], | ||
| 13 | + status: [required] | ||
| 14 | +}) | ||
| 15 | + | ||
| 16 | +// CrudSchema | ||
| 17 | +const crudSchemas = reactive<VxeCrudSchema>({ | ||
| 18 | + primaryKey: 'id', | ||
| 19 | + primaryType: null, | ||
| 20 | + action: true, | ||
| 21 | + columns: [ | ||
| 22 | + { | ||
| 23 | + title: '上级菜单', | ||
| 24 | + field: 'parentId', | ||
| 25 | + isTable: false | ||
| 26 | + }, | ||
| 27 | + { | ||
| 28 | + title: '菜单名称', | ||
| 29 | + field: 'name', | ||
| 30 | + isSearch: true, | ||
| 31 | + table: { | ||
| 32 | + treeNode: true, | ||
| 33 | + align: 'left', | ||
| 34 | + width: '200px' | ||
| 35 | + } | ||
| 36 | + }, | ||
| 37 | + { | ||
| 38 | + title: '菜单类型', | ||
| 39 | + field: 'type', | ||
| 40 | + dictType: DICT_TYPE.SYSTEM_MENU_TYPE | ||
| 41 | + }, | ||
| 42 | + { | ||
| 43 | + title: '路由地址', | ||
| 44 | + field: 'path' | ||
| 45 | + }, | ||
| 46 | + { | ||
| 47 | + title: '组件路径', | ||
| 48 | + field: 'component' | ||
| 49 | + }, | ||
| 50 | + { | ||
| 51 | + title: '权限标识', | ||
| 52 | + field: 'permission' | ||
| 53 | + }, | ||
| 54 | + { | ||
| 55 | + title: '排序', | ||
| 56 | + field: 'sort' | ||
| 57 | + }, | ||
| 58 | + { | ||
| 59 | + title: t('common.status'), | ||
| 60 | + field: 'status', | ||
| 61 | + dictType: DICT_TYPE.COMMON_STATUS, | ||
| 62 | + dictClass: 'number', | ||
| 63 | + isSearch: true | ||
| 64 | + }, | ||
| 65 | + { | ||
| 66 | + title: t('common.createTime'), | ||
| 67 | + field: 'createTime', | ||
| 68 | + formatter: 'formatDate', | ||
| 69 | + isForm: false | ||
| 70 | + } | ||
| 71 | + ] | ||
| 72 | +}) | ||
| 73 | +export const { allSchemas } = useVxeCrudSchemas(crudSchemas) |