潘志宝
3 天以前 221918bba28d2384d03c596a68256d7832e4a0e0
提交 | 用户 | 时间
820397 1 <template>
H 2   <!-- 搜索工作栏 -->
3   <ContentWrap>
4     <el-form
5       ref="queryFormRef"
6       :inline="true"
7       :model="queryParams"
8       class="-mb-15px"
9       label-width="68px"
10     >
11       <el-form-item label="菜单名称" prop="name">
12         <el-input
13           v-model="queryParams.name"
14           class="!w-240px"
15           clearable
16           placeholder="请输入菜单名称"
17           @keyup.enter="handleQuery"
18         />
19       </el-form-item>
20       <el-form-item label="状态" prop="status">
21         <el-select
22           v-model="queryParams.status"
23           class="!w-240px"
24           clearable
25           placeholder="请选择菜单状态"
26         >
27           <el-option
28             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
29             :key="dict.value"
30             :label="dict.label"
31             :value="dict.value"
32           />
33         </el-select>
34       </el-form-item>
35       <el-form-item>
36         <el-button @click="handleQuery">
37           <Icon class="mr-5px" icon="ep:search" />
38           搜索
39         </el-button>
40         <el-button @click="resetQuery">
41           <Icon class="mr-5px" icon="ep:refresh" />
42           重置
43         </el-button>
44         <el-button
45           v-hasPermi="['system:menu:create']"
46           plain
47           type="primary"
48           @click="openForm('create')"
49         >
50           <Icon class="mr-5px" icon="ep:plus" />
51           新增
52         </el-button>
53         <el-button plain @click="refreshMenu">
54           <Icon class="mr-5px" icon="ep:refresh" />
55           刷新菜单缓存
56         </el-button>
57       </el-form-item>
58     </el-form>
59   </ContentWrap>
60
61   <!-- 列表 -->
62   <ContentWrap>
c9a6f7 63     <div style="height: 700px">
H 64       <!-- AutoResizer 自动调节大小 -->
65       <el-auto-resizer>
66         <template #default="{ height, width }">
67           <!-- Virtualized Table 虚拟化表格:高性能,解决表格在大数据量下的卡顿问题 -->
68           <el-table-v2
69             v-loading="loading"
70             :columns="columns"
71             :data="list"
72             :width="width"
73             :height="height"
74             expand-column-key="name"
75           />
820397 76         </template>
c9a6f7 77       </el-auto-resizer>
H 78     </div>
820397 79   </ContentWrap>
H 80
81   <!-- 表单弹窗:添加/修改 -->
82   <MenuForm ref="formRef" @success="getList" />
83 </template>
84 <script lang="ts" setup>
85 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
86 import { handleTree } from '@/utils/tree'
87 import * as MenuApi from '@/api/system/menu'
c9a6f7 88 import { MenuVO } from '@/api/system/menu'
820397 89 import MenuForm from './MenuForm.vue'
c9a6f7 90 import { CACHE_KEY, useCache, useSessionCache } from '@/hooks/web/useCache'
H 91 import { h } from 'vue'
92 import { Column, ElButton } from 'element-plus'
93 import { Icon } from '@/components/Icon'
94 import { hasPermission } from '@/directives/permission/hasPermi'
95 import { CommonStatusEnum } from '@/utils/constants'
820397 96
H 97 defineOptions({ name: 'SystemMenu' })
98
99 const { wsCache } = useCache()
271781 100 const { wsSessionCache } = useSessionCache()
820397 101 const { t } = useI18n() // 国际化
H 102 const message = useMessage() // 消息弹窗
103
c9a6f7 104 // 表格的 column 字段
H 105 const columns: Column[] = [
106   {
107     dataKey: 'name',
108     title: '菜单名称',
109     width: 250
110   },
111   {
112     dataKey: 'icon',
113     title: '图标',
114     width: 150,
115     cellRenderer: ({ rowData }) => {
116       return h(Icon, {
117         icon: rowData.icon
118       })
119     }
120   },
121   {
122     dataKey: 'sort',
123     title: '排序',
124     width: 100
125   },
126   {
127     dataKey: 'permission',
128     title: '权限标识',
129     width: 240
130   },
131   {
132     dataKey: 'component',
133     title: '组件路径',
134     width: 240
135   },
136   {
137     dataKey: 'componentName',
138     title: '组件名称',
139     width: 240
140   },
141   {
142     dataKey: 'status',
143     title: '状态',
144     width: 160,
145     cellRenderer: ({ rowData }) => {
146       return h(ElSwitch, {
147         modelValue: rowData.status,
148         activeValue: CommonStatusEnum.ENABLE,
149         inactiveValue: CommonStatusEnum.DISABLE,
150         loading: menuStatusUpdating.value[rowData.id],
151         disabled: !hasPermission(['system:menu:update']),
152         onChange: (val) => handleStatusChanged(rowData, val as number)
153       })
154     }
155   },
156   {
157     dataKey: 'operation',
158     title: '操作',
159     width: 200,
160     cellRenderer: ({ rowData }) => {
161       return h(
162         'div',
163         [
164           hasPermission(['system:menu:update']) &&
165           h(
166             ElButton,
167             {
168               link: true,
169               type: 'primary',
170               onClick: () => openForm('update', rowData.id)
171             },
172             '修改'
173           ),
174           hasPermission(['system:menu:create']) &&
175           h(
176             ElButton,
177             {
178               link: true,
179               type: 'primary',
180               onClick: () => openForm('create', undefined, rowData.id)
181             },
182             '新增'
183           ),
184           hasPermission(['system:menu:delete']) &&
185           h(
186             ElButton,
187             {
188               link: true,
189               type: 'danger',
190               onClick: () => handleDelete(rowData.id)
191             },
192             '删除'
193           )
194         ].filter(Boolean)
195       )
196     }
197   }
198 ]
820397 199 const loading = ref(true) // 列表的加载中
H 200 const list = ref<any>([]) // 列表的数据
201 const queryParams = reactive({
202   name: undefined,
203   status: undefined
204 })
205 const queryFormRef = ref() // 搜索的表单
206
207 /** 查询列表 */
208 const getList = async () => {
209   loading.value = true
210   try {
211     const data = await MenuApi.getMenuList(queryParams)
212     list.value = handleTree(data)
213   } finally {
214     loading.value = false
215   }
216 }
217
218 /** 搜索按钮操作 */
219 const handleQuery = () => {
220   getList()
221 }
222
223 /** 重置按钮操作 */
224 const resetQuery = () => {
225   queryFormRef.value.resetFields()
226   handleQuery()
227 }
228
229 /** 添加/修改操作 */
230 const formRef = ref()
231 const openForm = (type: string, id?: number, parentId?: number) => {
232   formRef.value.open(type, id, parentId)
233 }
234
235 /** 刷新菜单缓存按钮操作 */
236 const refreshMenu = async () => {
237   try {
238     await message.confirm('即将更新缓存刷新浏览器!', '刷新菜单缓存')
239     // 清空,从而触发刷新
240     wsCache.delete(CACHE_KEY.USER)
c9a6f7 241     wsCache.delete(CACHE_KEY.ROLE_ROUTERS)
H 242     wsSessionCache.delete(CACHE_KEY.USER)
271781 243     wsSessionCache.delete(CACHE_KEY.ROLE_ROUTERS)
820397 244     // 刷新浏览器
H 245     location.reload()
246   } catch {}
247 }
248
249 /** 删除按钮操作 */
250 const handleDelete = async (id: number) => {
251   try {
252     // 删除的二次确认
253     await message.delConfirm()
254     // 发起删除
255     await MenuApi.deleteMenu(id)
256     message.success(t('common.delSuccess'))
257     // 刷新列表
258     await getList()
259   } catch {}
260 }
261
c9a6f7 262 /** 开启/关闭菜单的状态 */
H 263 const menuStatusUpdating = ref({}) // 菜单状态更新中的 menu 映射。key:菜单编号,value:是否更新中
264 const handleStatusChanged = async (menu: MenuVO, val: number) => {
265   // 1. 标记 menu.id 更新中
266   menuStatusUpdating.value[menu.id] = true
267   try {
268     // 2. 发起更新状态
269     menu.status = val
270     await MenuApi.updateMenu(menu)
271   } finally {
272     // 3. 标记 menu.id 更新完成
273     menuStatusUpdating.value[menu.id] = false
274   }
275 }
276
820397 277 /** 初始化 **/
H 278 onMounted(() => {
279   getList()
280 })
281 </script>