Commit 1c1cafdc7f58e4f7e0e944c407e8d74c7ca82658

Authored by xingyu4j
1 parent eb5870f3

feat: vxe tree table

yudao-ui-admin-vue3/src/views/system/menu/index.vue
... ... @@ -3,12 +3,27 @@ import * as MenuApi from '@/api/system/menu'
3 3 import { MenuVO } from '@/api/system/menu/types'
4 4 import { useI18n } from '@/hooks/web/useI18n'
5 5 import { useMessage } from '@/hooks/web/useMessage'
  6 +import { IconSelect } from '@/components/Icon'
  7 +import { Tooltip } from '@/components/Tooltip'
6 8 import { required } from '@/utils/formRules.js'
7 9 import { onMounted, reactive, ref } from 'vue'
8 10 import { VxeTableInstance } from 'vxe-table'
9   -import { DICT_TYPE } from '@/utils/dict'
  11 +import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
10 12 import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
11   -
  13 +import {
  14 + ElRow,
  15 + ElCol,
  16 + ElForm,
  17 + ElFormItem,
  18 + ElInput,
  19 + ElInputNumber,
  20 + ElSelect,
  21 + ElTreeSelect,
  22 + ElOption,
  23 + ElRadioGroup,
  24 + ElRadioButton
  25 +} from 'element-plus'
  26 +import { handleTree } from '@/utils/tree'
12 27 const { t } = useI18n() // 国际化
13 28 const message = useMessage()
14 29 const xTable = ref<VxeTableInstance>()
... ... @@ -18,6 +33,7 @@ const actionLoading = ref(false) // 遮罩层
18 33 const actionType = ref('') // 操作按钮的类型
19 34 const dialogVisible = ref(false) // 是否显示弹出层
20 35 const dialogTitle = ref('edit') // 弹出层标题
  36 +const statusOption = ref() // 状态选项
21 37 const menuForm = ref<MenuVO>({
22 38 id: 0,
23 39 name: '',
... ... @@ -33,12 +49,32 @@ const menuForm = ref&lt;MenuVO&gt;({
33 49 keepAlive: true,
34 50 createTime: ''
35 51 })
  52 +const menuProps = {
  53 + checkStrictly: true,
  54 + children: 'children',
  55 + label: 'name',
  56 + value: 'id'
  57 +}
  58 +interface Tree {
  59 + id: number
  60 + name: string
  61 + children?: Tree[] | any[]
  62 +}
  63 +const menuOptions = ref<any[]>([]) // 树形结构
  64 +const getTree = async () => {
  65 + menuOptions.value = []
  66 + const res = await MenuApi.listSimpleMenusApi()
  67 + let menu: Tree = { id: 0, name: '主类目', children: [] }
  68 + menu.children = handleTree(res)
  69 + menuOptions.value.push(menu)
  70 +}
36 71 // ========== 查询 ==========
37 72 const queryParams = reactive({
38   - name: undefined,
39   - status: undefined
  73 + name: null,
  74 + status: null
40 75 })
41 76 const getList = async () => {
  77 + statusOption.value = getIntDictOptions(DICT_TYPE.COMMON_STATUS)
42 78 tableLoading.value = true
43 79 const res = await MenuApi.getMenuListApi(queryParams)
44 80 tableData.value = res
... ... @@ -50,6 +86,10 @@ const setDialogTile = (type: string) =&gt; {
50 86 actionType.value = type
51 87 dialogVisible.value = true
52 88 }
  89 +// 新建操作
  90 +const handleCreate = () => {
  91 + setDialogTile('create')
  92 +}
53 93 // 修改操作
54 94 const handleUpdate = async (row: MenuVO) => {
55 95 // 设置数据
... ... @@ -73,6 +113,16 @@ const rules = reactive({
73 113 path: [required],
74 114 status: [required]
75 115 })
  116 +// 查询操作
  117 +const handleQuery = async () => {
  118 + await getList()
  119 +}
  120 +// 重置操作
  121 +const resetQuery = async () => {
  122 + queryParams.name = null
  123 + queryParams.status = null
  124 + await getList()
  125 +}
76 126 // 保存操作
77 127 const isExternal = (path: string) => {
78 128 return /^(https?:|mailto:|tel:)/.test(path)
... ... @@ -111,12 +161,41 @@ const submitForm = async () =&gt; {
111 161 }
112 162 onMounted(async () => {
113 163 await getList()
  164 + getTree()
114 165 })
115 166 </script>
116 167 <template>
117 168 <ContentWrap>
  169 + <el-form :model="queryParams" ref="queryForm" :inline="true">
  170 + <el-form-item label="菜单名称" prop="name">
  171 + <el-input v-model="queryParams.name" placeholder="请输入菜单名称" />
  172 + </el-form-item>
  173 + <el-form-item label="状态" prop="status">
  174 + <el-select v-model="queryParams.status" placeholder="请选择菜单状态">
  175 + <el-option
  176 + v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
  177 + :key="dict.value"
  178 + :label="dict.label"
  179 + :value="dict.value"
  180 + />
  181 + </el-select>
  182 + </el-form-item>
  183 + <el-form-item>
  184 + <el-button type="primary" @click="handleQuery">
  185 + <Icon icon="ep:search" class="mr-5px" />
  186 + {{ t('common.query') }}
  187 + </el-button>
  188 + <el-button @click="resetQuery">
  189 + <Icon icon="ep:refresh-right" class="mr-5px" />
  190 + {{ t('common.reset') }}
  191 + </el-button>
  192 + </el-form-item>
  193 + </el-form>
118 194 <vxe-toolbar>
119 195 <template #buttons>
  196 + <vxe-button status="primary" v-hasPermi="['system:post:create']" @click="handleCreate">
  197 + <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
  198 + </vxe-button>
120 199 <vxe-button @click="xTable?.setAllTreeExpand(true)">展开所有</vxe-button>
121 200 <vxe-button @click="xTable?.clearTreeExpand()">关闭所有</vxe-button>
122 201 </template>
... ... @@ -181,31 +260,160 @@ onMounted(async () =&gt; {
181 260 id="menuModel"
182 261 :title="dialogTitle"
183 262 width="800"
184   - height="400"
  263 + height="6f00"
185 264 min-width="460"
186 265 min-height="320"
187 266 show-zoom
188 267 resize
189   - remember
190   - storage
191 268 transfer
192 269 show-footer
193 270 >
194 271 <template #default>
195 272 <!-- 对话框(添加 / 修改) -->
196   - <vxe-form
197   - ref="xForm"
198   - v-if="['create', 'update'].includes(actionType)"
199   - :data="menuForm"
  273 + <el-form
  274 + :model="menuForm"
200 275 :rules="rules"
201   - @submit="submitForm"
  276 + :inline="true"
  277 + label-width="120px"
  278 + label-position="right"
202 279 >
203   - <vxe-form-item title="菜单名称" field="name" :item-render="{}">
204   - <template #default="{ data }">
205   - <vxe-input v-model="data.name" placeholder="请输入菜单名称" clearable />
  280 + <el-row :gutter="24">
  281 + <el-col :span="24">
  282 + <el-form-item label="上级菜单">
  283 + <el-tree-select
  284 + node-key="id"
  285 + v-model="menuForm.parentId"
  286 + :props="menuProps"
  287 + :data="menuOptions"
  288 + check-strictly
  289 + />
  290 + </el-form-item>
  291 + </el-col>
  292 + <el-col :span="12">
  293 + <el-form-item label="菜单类型" prop="type">
  294 + <el-radio-group v-model="menuForm.type">
  295 + <el-radio-button
  296 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_MENU_TYPE)"
  297 + :key="dict.value"
  298 + :label="dict.value"
  299 + >
  300 + {{ dict.label }}
  301 + </el-radio-button>
  302 + </el-radio-group>
  303 + </el-form-item>
  304 + </el-col>
  305 + <el-col :span="12">
  306 + <el-form-item label="菜单名称" prop="name">
  307 + <el-input v-model="menuForm.name" placeholder="请输入菜单名称" clearable />
  308 + </el-form-item>
  309 + </el-col>
  310 + <template v-if="menuForm.type !== 3">
  311 + <el-col :span="12">
  312 + <el-form-item label="菜单图标">
  313 + <IconSelect v-model="menuForm.icon" clearable />
  314 + </el-form-item>
  315 + </el-col>
  316 + <el-col :span="12">
  317 + <el-form-item label="路由地址" prop="path">
  318 + <template #label>
  319 + <Tooltip
  320 + titel="路由地址"
  321 + message="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头"
  322 + />
  323 + </template>
  324 + <el-input v-model="menuForm.path" placeholder="请输入路由地址" clearable />
  325 + </el-form-item>
  326 + </el-col>
  327 + </template>
  328 + <template v-if="menuForm.type === 2">
  329 + <el-col :span="12">
  330 + <el-form-item label="路由地址" prop="component">
  331 + <el-input v-model="menuForm.component" placeholder="请输入组件地址" clearable />
  332 + </el-form-item>
  333 + </el-col>
  334 + </template>
  335 + <template v-if="menuForm.type !== 1">
  336 + <el-col :span="12">
  337 + <el-form-item label="权限标识" prop="permission">
  338 + <template #label>
  339 + <Tooltip
  340 + titel="权限标识"
  341 + message="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)"
  342 + />
  343 + </template>
  344 + <el-input v-model="menuForm.permission" placeholder="请输入权限标识" clearable />
  345 + </el-form-item>
  346 + </el-col>
  347 + </template>
  348 + <el-col :span="12">
  349 + <el-form-item label="显示排序" prop="sort">
  350 + <el-input-number
  351 + v-model="menuForm.sort"
  352 + controls-position="right"
  353 + :min="0"
  354 + clearable
  355 + />
  356 + </el-form-item>
  357 + </el-col>
  358 + <el-col :span="12">
  359 + <el-form-item label="菜单状态" prop="status">
  360 + <el-radio-group v-model="menuForm.status">
  361 + <el-radio-button
  362 + v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
  363 + :key="dict.value"
  364 + :label="dict.value"
  365 + >
  366 + {{ dict.label }}
  367 + </el-radio-button>
  368 + </el-radio-group>
  369 + </el-form-item>
  370 + </el-col>
  371 + <template v-if="menuForm.type !== 3">
  372 + <el-col :span="12">
  373 + <el-form-item label="显示状态" prop="status">
  374 + <template #label>
  375 + <Tooltip
  376 + titel="显示状态"
  377 + message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问"
  378 + />
  379 + </template>
  380 + <el-radio-group v-model="menuForm.visible">
  381 + <el-radio-button key="true" :label="true">显示</el-radio-button>
  382 + <el-radio-button key="false" :label="false">隐藏</el-radio-button>
  383 + </el-radio-group>
  384 + </el-form-item>
  385 + </el-col>
206 386 </template>
207   - </vxe-form-item>
208   - </vxe-form>
  387 + <template v-if="menuForm.type === 2">
  388 + <el-col :span="12">
  389 + <el-form-item label="缓存状态" prop="keepAlive">
  390 + <template #label>
  391 + <Tooltip
  392 + titel="缓存状态"
  393 + message="选择缓存时,则会被 `keep-alive` 缓存,需要匹配组件的 `name` 和路由地址保持一致"
  394 + />
  395 + </template>
  396 + <el-radio-group v-model="menuForm.keepAlive">
  397 + <el-radio-button key="true" :label="true">缓存</el-radio-button>
  398 + <el-radio-button key="false" :label="false">不缓存</el-radio-button>
  399 + </el-radio-group>
  400 + </el-form-item>
  401 + </el-col>
  402 + </template>
  403 + </el-row>
  404 + </el-form>
  405 + </template>
  406 + <template #footer>
  407 + <!-- 操作按钮 -->
  408 + <el-button
  409 + v-if="['create', 'update'].includes(actionType)"
  410 + type="primary"
  411 + :loading="actionLoading"
  412 + @click="submitForm"
  413 + >
  414 + {{ t('action.save') }}
  415 + </el-button>
  416 + <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
209 417 </template>
210 418 </vxe-modal>
211 419 </template>
... ...
yudao-ui-admin-vue3/src/views/system/menu/indexd.vue deleted
1   -<script setup lang="ts">
2   -import { ref, reactive, onMounted } from 'vue'
3   -import { handleTree } from '@/utils/tree'
4   -import dayjs from 'dayjs'
5   -import { IconSelect } from '@/components/Icon'
6   -import { Tooltip } from '@/components/Tooltip'
7   -import * as MenuApi from '@/api/system/menu'
8   -import { useI18n } from '@/hooks/web/useI18n'
9   -import {
10   - ElRow,
11   - ElCol,
12   - ElTable,
13   - ElTableColumn,
14   - ElForm,
15   - ElFormItem,
16   - ElInput,
17   - ElInputNumber,
18   - ElSelect,
19   - ElTreeSelect,
20   - ElOption,
21   - ElRadioGroup,
22   - ElRadioButton
23   -} from 'element-plus'
24   -import { MenuVO } from '@/api/system/menu/types'
25   -import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
26   -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
27   -import { useMessage } from '@/hooks/web/useMessage'
28   -import { required } from '@/utils/formRules.js'
29   -const message = useMessage()
30   -const { t } = useI18n() // 国际化
31   -// ========== 创建菜单树结构 ==========
32   -const loading = ref(true)
33   -const menuData = ref<any[]>([]) // 树形结构
34   -const getList = async () => {
35   - const res = await MenuApi.getMenuListApi(queryParams)
36   - menuData.value = handleTree(res)
37   - loading.value = false
38   -}
39   -const menuProps = {
40   - checkStrictly: true,
41   - children: 'children',
42   - label: 'name',
43   - value: 'id'
44   -}
45   -interface Tree {
46   - id: number
47   - name: string
48   - children?: Tree[] | any[]
49   -}
50   -const menuOptions = ref<any[]>([]) // 树形结构
51   -const getTree = async () => {
52   - menuOptions.value = []
53   - const res = await MenuApi.listSimpleMenusApi()
54   - let menu: Tree = { id: 0, name: '主类目', children: [] }
55   - menu.children = handleTree(res)
56   - menuOptions.value.push(menu)
57   -}
58   -// ========== 查询 ==========
59   -const queryParams = reactive({
60   - name: undefined,
61   - status: undefined
62   -})
63   -// 查询操作
64   -const handleQuery = async () => {
65   - await getList()
66   -}
67   -// 重置操作
68   -const resetQuery = async () => {
69   - queryParams.name = undefined
70   - queryParams.status = undefined
71   - await getList()
72   -}
73   -// ========== CRUD 相关 ==========
74   -const actionLoading = ref(false) // 遮罩层
75   -const actionType = ref('') // 操作按钮的类型
76   -const dialogVisible = ref(false) // 是否显示弹出层
77   -const dialogTitle = ref('edit') // 弹出层标题
78   -const menuForm = ref<MenuVO>({
79   - id: 0,
80   - name: '',
81   - permission: '',
82   - type: SystemMenuTypeEnum.DIR,
83   - sort: 1,
84   - parentId: 0,
85   - path: '',
86   - icon: '',
87   - component: '',
88   - status: CommonStatusEnum.ENABLE,
89   - visible: true,
90   - keepAlive: true,
91   - createTime: ''
92   -})
93   -// 表单校验
94   -const rules = reactive({
95   - name: [required],
96   - sort: [required],
97   - path: [required],
98   - status: [required]
99   -})
100   -// 设置标题
101   -const setDialogTile = (type: string) => {
102   - dialogTitle.value = t('action.' + type)
103   - actionType.value = type
104   - dialogVisible.value = true
105   -}
106   -// 新建操作
107   -const handleCreate = () => {
108   - // 重置表单
109   - setDialogTile('create')
110   -}
111   -// 修改操作
112   -const handleUpdate = async (row: MenuVO) => {
113   - // 设置数据
114   - const res = await MenuApi.getMenuApi(row.id)
115   - menuForm.value = res
116   - setDialogTile('update')
117   -}
118   -// 删除操作
119   -const handleDelete = async (row: MenuVO) => {
120   - message
121   - .confirm(t('common.delDataMessage'), t('common.confirmTitle'))
122   - .then(async () => {
123   - await MenuApi.deleteMenuApi(row.id)
124   - message.success(t('common.delSuccess'))
125   - })
126   - .catch(() => {})
127   - await getList()
128   -}
129   -// 保存操作
130   -const isExternal = (path: string) => {
131   - return /^(https?:|mailto:|tel:)/.test(path)
132   -}
133   -const submitForm = async () => {
134   - actionLoading.value = true
135   - // 提交请求
136   - try {
137   - if (
138   - menuForm.value.type === SystemMenuTypeEnum.DIR ||
139   - menuForm.value.type === SystemMenuTypeEnum.MENU
140   - ) {
141   - if (!isExternal(menuForm.value.path)) {
142   - if (menuForm.value.parentId === 0 && menuForm.value.path.charAt(0) !== '/') {
143   - message.error('路径必须以 / 开头')
144   - return
145   - } else if (menuForm.value.parentId !== 0 && menuForm.value.path.charAt(0) === '/') {
146   - message.error('路径不能以 / 开头')
147   - return
148   - }
149   - }
150   - }
151   - if (actionType.value === 'create') {
152   - await MenuApi.createMenuApi(menuForm.value)
153   - message.success(t('common.createSuccess'))
154   - } else {
155   - await MenuApi.updateMenuApi(menuForm.value)
156   - message.success(t('common.updateSuccess'))
157   - }
158   - // 操作成功,重新加载列表
159   - dialogVisible.value = false
160   - await getList()
161   - } finally {
162   - actionLoading.value = false
163   - }
164   -}
165   -// ========== 初始化 ==========
166   -onMounted(async () => {
167   - await getList()
168   - getTree()
169   -})
170   -</script>
171   -<template>
172   - <!-- 搜索工作区 -->
173   - <ContentWrap>
174   - <el-form :model="queryParams" ref="queryForm" :inline="true">
175   - <el-form-item label="菜单名称" prop="name">
176   - <el-input v-model="queryParams.name" placeholder="请输入菜单名称" />
177   - </el-form-item>
178   - <el-form-item label="状态" prop="status">
179   - <el-select v-model="queryParams.status" placeholder="请选择菜单状态">
180   - <el-option
181   - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
182   - :key="dict.value"
183   - :label="dict.label"
184   - :value="dict.value"
185   - />
186   - </el-select>
187   - </el-form-item>
188   - <el-form-item>
189   - <el-button type="primary" @click="handleQuery">
190   - <Icon icon="ep:search" class="mr-5px" />
191   - {{ t('common.query') }}
192   - </el-button>
193   - <el-button @click="resetQuery">
194   - <Icon icon="ep:refresh-right" class="mr-5px" />
195   - {{ t('common.reset') }}
196   - </el-button>
197   - </el-form-item>
198   - </el-form>
199   - </ContentWrap>
200   - <!-- 列表 -->
201   - <ContentWrap>
202   - <div class="mb-10px">
203   - <el-button type="primary" v-hasPermi="['system:notice:create']" @click="handleCreate">
204   - <Icon icon="ep:zoom-in" class="mr-1px" /> {{ t('action.add') }}
205   - </el-button>
206   - </div>
207   - <el-table
208   - v-loading="loading"
209   - table-layout="auto"
210   - row-key="id"
211   - :data="menuData"
212   - :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
213   - >
214   - <el-table-column label="菜单名称" prop="name" width="240px">
215   - <template #default="scope">
216   - <Icon :icon="scope.row.icon" />
217   - <span class="ml-3">{{ scope.row.name }}</span>
218   - </template>
219   - </el-table-column>
220   - <el-table-column label="菜单类型" prop="type">
221   - <template #default="scope">
222   - <DictTag :type="DICT_TYPE.SYSTEM_MENU_TYPE" :value="scope.row.type" />
223   - </template>
224   - </el-table-column>
225   - <el-table-column label="路由地址" prop="path" />
226   - <el-table-column label="组件路径" prop="component" />
227   - <el-table-column label="权限标识" prop="permission" />
228   - <el-table-column label="排序" prop="sort" />
229   - <el-table-column label="状态" prop="status">
230   - <template #default="scope">
231   - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
232   - </template>
233   - </el-table-column>
234   - <el-table-column label="创建时间" prop="createTime">
235   - <template #default="scope">
236   - <span>{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
237   - </template>
238   - </el-table-column>
239   - <el-table-column label="操作">
240   - <template #default="scope">
241   - <el-button
242   - link
243   - type="primary"
244   - v-hasPermi="['system:menu:update']"
245   - @click="handleUpdate(scope.row)"
246   - >
247   - <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
248   - </el-button>
249   - <el-button
250   - link
251   - type="primary"
252   - v-hasPermi="['system:menu:delete']"
253   - @click="handleDelete(scope.row)"
254   - >
255   - <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
256   - </el-button>
257   - </template>
258   - </el-table-column>
259   - </el-table>
260   - </ContentWrap>
261   - <!-- 添加或修改菜单对话框 -->
262   - <Dialog v-model="dialogVisible" :title="dialogTitle" maxHeight="400px" width="45%">
263   - <el-form
264   - :model="menuForm"
265   - :rules="rules"
266   - :inline="true"
267   - label-width="120px"
268   - label-position="right"
269   - >
270   - <el-row :gutter="24">
271   - <el-col :span="24">
272   - <el-form-item label="上级菜单">
273   - <el-tree-select
274   - node-key="id"
275   - v-model="menuForm.parentId"
276   - :props="menuProps"
277   - :data="menuOptions"
278   - check-strictly
279   - />
280   - </el-form-item>
281   - </el-col>
282   - <el-col :span="12">
283   - <el-form-item label="菜单类型" prop="type">
284   - <el-radio-group v-model="menuForm.type">
285   - <el-radio-button
286   - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_MENU_TYPE)"
287   - :key="dict.value"
288   - :label="dict.value"
289   - >
290   - {{ dict.label }}
291   - </el-radio-button>
292   - </el-radio-group>
293   - </el-form-item>
294   - </el-col>
295   - <el-col :span="12">
296   - <el-form-item label="菜单名称" prop="name">
297   - <el-input v-model="menuForm.name" placeholder="请输入菜单名称" clearable />
298   - </el-form-item>
299   - </el-col>
300   - <template v-if="menuForm.type !== 3">
301   - <el-col :span="12">
302   - <el-form-item label="菜单图标">
303   - <IconSelect v-model="menuForm.icon" clearable />
304   - </el-form-item>
305   - </el-col>
306   - <el-col :span="12">
307   - <el-form-item label="路由地址" prop="path">
308   - <template #label>
309   - <Tooltip
310   - titel="路由地址"
311   - message="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头"
312   - />
313   - </template>
314   - <el-input v-model="menuForm.path" placeholder="请输入路由地址" clearable />
315   - </el-form-item>
316   - </el-col>
317   - </template>
318   - <template v-if="menuForm.type === 2">
319   - <el-col :span="12">
320   - <el-form-item label="路由地址" prop="component">
321   - <el-input v-model="menuForm.component" placeholder="请输入组件地址" clearable />
322   - </el-form-item>
323   - </el-col>
324   - </template>
325   - <template v-if="menuForm.type !== 1">
326   - <el-col :span="12">
327   - <el-form-item label="权限标识" prop="permission">
328   - <template #label>
329   - <Tooltip
330   - titel="权限标识"
331   - message="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)"
332   - />
333   - </template>
334   - <el-input v-model="menuForm.permission" placeholder="请输入权限标识" clearable />
335   - </el-form-item>
336   - </el-col>
337   - </template>
338   - <el-col :span="12">
339   - <el-form-item label="显示排序" prop="sort">
340   - <el-input-number v-model="menuForm.sort" controls-position="right" :min="0" clearable />
341   - </el-form-item>
342   - </el-col>
343   - <el-col :span="12">
344   - <el-form-item label="菜单状态" prop="status">
345   - <el-radio-group v-model="menuForm.status">
346   - <el-radio-button
347   - v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
348   - :key="dict.value"
349   - :label="dict.value"
350   - >
351   - {{ dict.label }}
352   - </el-radio-button>
353   - </el-radio-group>
354   - </el-form-item>
355   - </el-col>
356   - <template v-if="menuForm.type !== 3">
357   - <el-col :span="12">
358   - <el-form-item label="显示状态" prop="status">
359   - <template #label>
360   - <Tooltip
361   - titel="显示状态"
362   - message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问"
363   - />
364   - </template>
365   - <el-radio-group v-model="menuForm.visible">
366   - <el-radio-button key="true" :label="true">显示</el-radio-button>
367   - <el-radio-button key="false" :label="false">隐藏</el-radio-button>
368   - </el-radio-group>
369   - </el-form-item>
370   - </el-col>
371   - </template>
372   - <template v-if="menuForm.type === 2">
373   - <el-col :span="12">
374   - <el-form-item label="缓存状态" prop="keepAlive">
375   - <template #label>
376   - <Tooltip
377   - titel="缓存状态"
378   - message="选择缓存时,则会被 `keep-alive` 缓存,需要匹配组件的 `name` 和路由地址保持一致"
379   - />
380   - </template>
381   - <el-radio-group v-model="menuForm.keepAlive">
382   - <el-radio-button key="true" :label="true">缓存</el-radio-button>
383   - <el-radio-button key="false" :label="false">不缓存</el-radio-button>
384   - </el-radio-group>
385   - </el-form-item>
386   - </el-col>
387   - </template>
388   - </el-row>
389   - </el-form>
390   - <!-- 操作按钮 -->
391   - <template #footer>
392   - <el-button
393   - v-if="['create', 'update'].includes(actionType)"
394   - type="primary"
395   - :loading="actionLoading"
396   - @click="submitForm"
397   - >
398   - {{ t('action.save') }}
399   - </el-button>
400   - <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
401   - </template>
402   - </Dialog>
403   -</template>
404   -<style lang="less" scoped>
405   -:deep(.el-button.is-text) {
406   - margin-left: 0;
407   - padding: 8px 10px;
408   -}
409   -</style>
yudao-ui-admin-vue3/src/views/system/post/index.vue
... ... @@ -131,8 +131,6 @@ const submitForm: VxeFormEvents.Submit = async () =&gt; {
131 131 min-height="320"
132 132 show-zoom
133 133 resize
134   - remember
135   - storage
136 134 transfer
137 135 show-footer
138 136 >
... ... @@ -144,7 +142,6 @@ const submitForm: VxeFormEvents.Submit = async () =&gt; {
144 142 :data="formData"
145 143 :items="formItems"
146 144 :rules="rules"
147   - @submit="submitForm"
148 145 />
149 146 <Descriptions
150 147 v-if="actionType === 'detail'"
... ... @@ -159,5 +156,15 @@ const submitForm: VxeFormEvents.Submit = async () =&gt; {
159 156 </template>
160 157 </Descriptions>
161 158 </template>
  159 + <template #footer>
  160 + <vxe-button
  161 + v-if="['create', 'update'].includes(actionType)"
  162 + status="primary"
  163 + @click="submitForm"
  164 + >
  165 + {{ t('action.save') }}
  166 + </vxe-button>
  167 + <vxe-button @click="dialogVisible = false">{{ t('dialog.close') }}</vxe-button>
  168 + </template>
162 169 </vxe-modal>
163 170 </template>
... ...