Commit 7cbd6cfb68b9230d2be9ba90871d5cf9bf0d5741

Authored by YunaiV
1 parent 42452049

vue3:【menu】

1. 添加 TODO 修改建议
2. 增加注释
3. 调整一些 import、const 的顺序
yudao-ui-admin-vue3/src/api/system/menu/index.ts
1 import request from '@/config/axios' 1 import request from '@/config/axios'
2 import type { MenuVO } from './types' 2 import type { MenuVO } from './types'
3 3
4 -// 查询菜单(精简)列表 4 +// 查询菜单(精简)列表
5 export const listSimpleMenusApi = () => { 5 export const listSimpleMenusApi = () => {
6 return request.get({ url: '/system/menu/list-all-simple' }) 6 return request.get({ url: '/system/menu/list-all-simple' })
7 } 7 }
  8 +
8 // 查询菜单列表 9 // 查询菜单列表
9 export const getMenuListApi = (params) => { 10 export const getMenuListApi = (params) => {
10 return request.get({ url: '/system/menu/list', params }) 11 return request.get({ url: '/system/menu/list', params })
yudao-ui-admin-vue3/src/views/system/menu/index.vue
1 <template> 1 <template>
2 <ContentWrap> 2 <ContentWrap>
  3 + <!-- 搜索工作栏 -->
3 <el-form :model="queryParams" ref="queryForm" :inline="true"> 4 <el-form :model="queryParams" ref="queryForm" :inline="true">
4 <el-form-item label="菜单名称" prop="name"> 5 <el-form-item label="菜单名称" prop="name">
5 <el-input v-model="queryParams.name" placeholder="请输入菜单名称" /> 6 <el-input v-model="queryParams.name" placeholder="请输入菜单名称" />
@@ -15,17 +16,20 @@ @@ -15,17 +16,20 @@
15 </el-select> 16 </el-select>
16 </el-form-item> 17 </el-form-item>
17 <el-form-item> 18 <el-form-item>
  19 + <!-- 操作:搜索 -->
18 <XButton 20 <XButton
19 type="primary" 21 type="primary"
20 preIcon="ep:search" 22 preIcon="ep:search"
21 :title="t('common.query')" 23 :title="t('common.query')"
22 @click="handleQuery()" 24 @click="handleQuery()"
23 /> 25 />
  26 + <!-- 操作:重置 -->
24 <XButton preIcon="ep:refresh-right" :title="t('common.reset')" @click="resetQuery()" /> 27 <XButton preIcon="ep:refresh-right" :title="t('common.reset')" @click="resetQuery()" />
25 </el-form-item> 28 </el-form-item>
26 </el-form> 29 </el-form>
27 <vxe-toolbar> 30 <vxe-toolbar>
28 <template #buttons> 31 <template #buttons>
  32 + <!-- 操作:新增 -->
29 <XButton 33 <XButton
30 type="primary" 34 type="primary"
31 preIcon="ep:zoom-in" 35 preIcon="ep:zoom-in"
@@ -37,6 +41,8 @@ @@ -37,6 +41,8 @@
37 <XButton title="关闭所有" @click="xTable?.clearTreeExpand()" /> 41 <XButton title="关闭所有" @click="xTable?.clearTreeExpand()" />
38 </template> 42 </template>
39 </vxe-toolbar> 43 </vxe-toolbar>
  44 + <!-- 列表 -->
  45 + <!-- TODO 星语:是不是也搞成 grid 会好点,后续代码就统一走 grid 风格? -->
40 <vxe-table 46 <vxe-table
41 show-overflow 47 show-overflow
42 keep-source 48 keep-source
@@ -73,12 +79,14 @@ @@ -73,12 +79,14 @@
73 <vxe-column title="创建时间" field="createTime" formatter="formatDate" /> 79 <vxe-column title="创建时间" field="createTime" formatter="formatDate" />
74 <vxe-column title="操作" width="200"> 80 <vxe-column title="操作" width="200">
75 <template #default="{ row }"> 81 <template #default="{ row }">
  82 + <!-- 操作:修改 -->
76 <XTextButton 83 <XTextButton
77 preIcon="ep:edit" 84 preIcon="ep:edit"
78 :title="t('action.edit')" 85 :title="t('action.edit')"
79 v-hasPermi="['system:menu:update']" 86 v-hasPermi="['system:menu:update']"
80 @click="handleUpdate(row)" 87 @click="handleUpdate(row)"
81 /> 88 />
  89 + <!-- 操作:删除 -->
82 <XTextButton 90 <XTextButton
83 preIcon="ep:delete" 91 preIcon="ep:delete"
84 :title="t('action.del')" 92 :title="t('action.del')"
@@ -89,6 +97,7 @@ @@ -89,6 +97,7 @@
89 </vxe-column> 97 </vxe-column>
90 </vxe-table> 98 </vxe-table>
91 </ContentWrap> 99 </ContentWrap>
  100 + <!-- 添加或修改菜单对话框 -->
92 <XModal v-model="dialogVisible" id="menuModel" :title="dialogTitle"> 101 <XModal v-model="dialogVisible" id="menuModel" :title="dialogTitle">
93 <template #default> 102 <template #default>
94 <!-- 对话框(添加 / 修改) --> 103 <!-- 对话框(添加 / 修改) -->
@@ -227,7 +236,7 @@ @@ -227,7 +236,7 @@
227 </el-form> 236 </el-form>
228 </template> 237 </template>
229 <template #footer> 238 <template #footer>
230 - <!-- 操作按钮 --> 239 + <!-- 按钮:保存 -->
231 <XButton 240 <XButton
232 v-if="['create', 'update'].includes(actionType)" 241 v-if="['create', 'update'].includes(actionType)"
233 type="primary" 242 type="primary"
@@ -235,22 +244,17 @@ @@ -235,22 +244,17 @@
235 @click="submitForm" 244 @click="submitForm"
236 :title="t('action.save')" 245 :title="t('action.save')"
237 /> 246 />
  247 + <!-- 按钮:关闭 -->
238 <XButton :loading="actionLoading" @click="dialogVisible = false" :title="t('dialog.close')" /> 248 <XButton :loading="actionLoading" @click="dialogVisible = false" :title="t('dialog.close')" />
239 </template> 249 </template>
240 </XModal> 250 </XModal>
241 </template> 251 </template>
242 <script setup lang="ts"> 252 <script setup lang="ts">
243 -import * as MenuApi from '@/api/system/menu'  
244 -import { MenuVO } from '@/api/system/menu/types' 253 +// 全局相关的 import
  254 +import { onMounted, reactive, ref } from 'vue'
245 import { useI18n } from '@/hooks/web/useI18n' 255 import { useI18n } from '@/hooks/web/useI18n'
246 import { useMessage } from '@/hooks/web/useMessage' 256 import { useMessage } from '@/hooks/web/useMessage'
247 -import { IconSelect } from '@/components/Icon'  
248 -import { Tooltip } from '@/components/Tooltip'  
249 -import { required } from '@/utils/formRules.js'  
250 -import { onMounted, reactive, ref } from 'vue'  
251 -import { VxeTableInstance } from 'vxe-table'  
252 -import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'  
253 -import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants' 257 +// TODO @星语:是不是 'element-plus' 和 '@/components/Tooltip' 和 '@/components/Icon' 全局直接引入
254 import { 258 import {
255 ElRow, 259 ElRow,
256 ElCol, 260 ElCol,
@@ -264,17 +268,29 @@ import { @@ -264,17 +268,29 @@ import {
264 ElRadioGroup, 268 ElRadioGroup,
265 ElRadioButton 269 ElRadioButton
266 } from 'element-plus' 270 } from 'element-plus'
  271 +import { Tooltip } from '@/components/Tooltip'
  272 +import { IconSelect } from '@/components/Icon'
  273 +import { VxeTableInstance } from 'vxe-table'
  274 +// 业务相关的 import
  275 +import * as MenuApi from '@/api/system/menu'
  276 +import { MenuVO } from '@/api/system/menu/types'
  277 +import { required } from '@/utils/formRules.js'
  278 +import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
  279 +import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
267 import { handleTree } from '@/utils/tree' 280 import { handleTree } from '@/utils/tree'
  281 +
268 const { t } = useI18n() // 国际化 282 const { t } = useI18n() // 国际化
269 -const message = useMessage() 283 +const message = useMessage() // 消息弹窗
  284 +// 列表相关的变量
270 const xTable = ref<VxeTableInstance>() 285 const xTable = ref<VxeTableInstance>()
271 const tableLoading = ref(false) 286 const tableLoading = ref(false)
272 const tableData = ref() 287 const tableData = ref()
273 -const actionLoading = ref(false) // 遮罩层  
274 -const actionType = ref('') // 操作按钮的类型 288 +// 弹窗相关的变量
275 const dialogVisible = ref(false) // 是否显示弹出层 289 const dialogVisible = ref(false) // 是否显示弹出层
276 const dialogTitle = ref('edit') // 弹出层标题 290 const dialogTitle = ref('edit') // 弹出层标题
277 -const statusOption = ref() // 状态选项 291 +const actionType = ref('') // 操作按钮的类型
  292 +const actionLoading = ref(false) // 遮罩层
  293 +// 新增和修改的表单值
278 const menuForm = ref<MenuVO>({ 294 const menuForm = ref<MenuVO>({
279 id: 0, 295 id: 0,
280 name: '', 296 name: '',
@@ -290,12 +306,24 @@ const menuForm = ref&lt;MenuVO&gt;({ @@ -290,12 +306,24 @@ const menuForm = ref&lt;MenuVO&gt;({
290 keepAlive: true, 306 keepAlive: true,
291 createTime: '' 307 createTime: ''
292 }) 308 })
  309 +// 新增和修改的表单校验
  310 +const rules = reactive({
  311 + name: [required],
  312 + sort: [required],
  313 + path: [required],
  314 + status: [required]
  315 +})
  316 +
  317 +// ========== 下拉框[上级菜单] ==========
  318 +// 下拉框[上级菜单]的配置项目
  319 +// TODO @星语:menuProps 貌似也可以抽到全局?
293 const menuProps = { 320 const menuProps = {
294 checkStrictly: true, 321 checkStrictly: true,
295 children: 'children', 322 children: 'children',
296 label: 'name', 323 label: 'name',
297 value: 'id' 324 value: 'id'
298 } 325 }
  326 +// TODO @星语:Tree 可以是全局的
299 interface Tree { 327 interface Tree {
300 id: number 328 id: number
301 name: string 329 name: string
@@ -309,6 +337,7 @@ const getTree = async () =&gt; { @@ -309,6 +337,7 @@ const getTree = async () =&gt; {
309 menu.children = handleTree(res) 337 menu.children = handleTree(res)
310 menuOptions.value.push(menu) 338 menuOptions.value.push(menu)
311 } 339 }
  340 +
312 // ========== 查询 ========== 341 // ========== 查询 ==========
313 const queryParams = reactive({ 342 const queryParams = reactive({
314 name: null, 343 name: null,
@@ -316,58 +345,47 @@ const queryParams = reactive({ @@ -316,58 +345,47 @@ const queryParams = reactive({
316 }) 345 })
317 const getList = async () => { 346 const getList = async () => {
318 tableLoading.value = true 347 tableLoading.value = true
319 - statusOption.value = getIntDictOptions(DICT_TYPE.COMMON_STATUS)  
320 const res = await MenuApi.getMenuListApi(queryParams) 348 const res = await MenuApi.getMenuListApi(queryParams)
321 tableData.value = res 349 tableData.value = res
322 tableLoading.value = false 350 tableLoading.value = false
323 } 351 }
  352 +
  353 +// 查询操作
  354 +const handleQuery = async () => {
  355 + await getList()
  356 +}
  357 +
  358 +// 重置操作
  359 +const resetQuery = async () => {
  360 + queryParams.name = null
  361 + queryParams.status = null
  362 + await getList()
  363 +}
  364 +
  365 +// ========== 新增/修改 ==========
  366 +
324 // 设置标题 367 // 设置标题
325 const setDialogTile = (type: string) => { 368 const setDialogTile = (type: string) => {
326 dialogTitle.value = t('action.' + type) 369 dialogTitle.value = t('action.' + type)
327 actionType.value = type 370 actionType.value = type
328 dialogVisible.value = true 371 dialogVisible.value = true
329 } 372 }
  373 +
330 // 新建操作 374 // 新建操作
331 const handleCreate = () => { 375 const handleCreate = () => {
332 setDialogTile('create') 376 setDialogTile('create')
  377 + // TODO @星语:重置表单
333 } 378 }
  379 +
334 // 修改操作 380 // 修改操作
335 const handleUpdate = async (row: MenuVO) => { 381 const handleUpdate = async (row: MenuVO) => {
  382 + setDialogTile('update')
336 // 设置数据 383 // 设置数据
337 const res = await MenuApi.getMenuApi(row.id) 384 const res = await MenuApi.getMenuApi(row.id)
338 - console.log(res)  
339 menuForm.value = res 385 menuForm.value = res
340 - setDialogTile('update')  
341 -}  
342 -// 删除操作  
343 -const handleDelete = async (row: MenuVO) => {  
344 - message.confirm(t('common.delDataMessage'), t('common.confirmTitle')).then(async () => {  
345 - await MenuApi.deleteMenuApi(row.id)  
346 - message.success(t('common.delSuccess'))  
347 - await getList()  
348 - })  
349 -}  
350 -// 表单校验  
351 -const rules = reactive({  
352 - name: [required],  
353 - sort: [required],  
354 - path: [required],  
355 - status: [required]  
356 -})  
357 -// 查询操作  
358 -const handleQuery = async () => {  
359 - await getList()  
360 -}  
361 -// 重置操作  
362 -const resetQuery = async () => {  
363 - queryParams.name = null  
364 - queryParams.status = null  
365 - await getList()  
366 -}  
367 -// 保存操作  
368 -const isExternal = (path: string) => {  
369 - return /^(https?:|mailto:|tel:)/.test(path)  
370 } 386 }
  387 +
  388 +// 提交新增/修改的表单
371 const submitForm = async () => { 389 const submitForm = async () => {
372 actionLoading.value = true 390 actionLoading.value = true
373 // 提交请求 391 // 提交请求
@@ -400,8 +418,26 @@ const submitForm = async () =&gt; { @@ -400,8 +418,26 @@ const submitForm = async () =&gt; {
400 actionLoading.value = false 418 actionLoading.value = false
401 } 419 }
402 } 420 }
  421 +
  422 +// 判断 path 是不是外部的 HTTP 等链接
  423 +const isExternal = (path: string) => {
  424 + return /^(https?:|mailto:|tel:)/.test(path)
  425 +}
  426 +
  427 +// ========== 删除 ==========
  428 +// 删除操作
  429 +const handleDelete = async (row: MenuVO) => {
  430 + message.confirm(t('common.delDataMessage'), t('common.confirmTitle')).then(async () => {
  431 + await MenuApi.deleteMenuApi(row.id)
  432 + message.success(t('common.delSuccess'))
  433 + await getList()
  434 + })
  435 +}
  436 +
  437 +// ========== 初始化 ==========
403 onMounted(async () => { 438 onMounted(async () => {
404 await getList() 439 await getList()
  440 + // TODO @星语:这个告警解决下;是不是改成新增和修改点击的时候,去加载下好一点哈?
405 getTree() 441 getTree()
406 }) 442 })
407 </script> 443 </script>