239 lines
6.4 KiB
Vue
239 lines
6.4 KiB
Vue
<template>
|
||
<div class="system">
|
||
<!-- 菜单列表头 -->
|
||
<div class="header">
|
||
<h4>菜单列表</h4>
|
||
<el-button type="primary" @click="handleAddMenu" v-auth="'menus_create'">新增菜单</el-button>
|
||
</div>
|
||
<!-- 菜单列表表格 -->
|
||
<MenuTable
|
||
:table-data="menuTree"
|
||
:columns="menuTableColumns"
|
||
row-key="id"
|
||
:tree-props="treeProps"
|
||
>
|
||
<template #icon="{ row }">
|
||
<el-icon v-if="row.icon && menuiconMap[row.icon]">
|
||
<component :is="menuiconMap[row.icon]" />
|
||
</el-icon>
|
||
<span v-else>-</span>
|
||
</template>
|
||
<template #type="{ row }">
|
||
{{ row.type === 1 ? '目录' : '按钮' }}
|
||
</template>
|
||
<template #status="{ row }">
|
||
{{ row.status === 1 ? '启用' : '禁用' }}
|
||
</template>
|
||
<template #action="{ row }">
|
||
<el-button
|
||
link
|
||
type="primary"
|
||
size="small"
|
||
@click="handleEditMenu(row)"
|
||
v-auth="'menus_edit'"
|
||
>
|
||
编辑
|
||
</el-button>
|
||
<el-button
|
||
link
|
||
type="danger"
|
||
size="small"
|
||
@click="handleDeleteMenu(row)"
|
||
v-auth="'menus_del'"
|
||
>
|
||
删除
|
||
</el-button>
|
||
</template>
|
||
</MenuTable>
|
||
</div>
|
||
<!-- 菜单新增/编辑弹窗 -->
|
||
<MenuDialog
|
||
:visible="dialogVisible"
|
||
:title="dialogTitle"
|
||
:type="dialogType"
|
||
@confirm="handleSubmit"
|
||
@cancel="handleCancel"
|
||
@close="handleClose"
|
||
>
|
||
<MenuForm
|
||
:form-data="menuForm"
|
||
:form-rules="menuFormRules"
|
||
:form-items="menuFormItemOptions"
|
||
:options-map="menuFormOptionsMap"
|
||
ref="menuFormRef"
|
||
/>
|
||
</MenuDialog>
|
||
</template>
|
||
<script lang="ts" setup>
|
||
import type { FormInstance } from 'element-plus'
|
||
import { Plus } from '@element-plus/icons-vue'
|
||
// 组件配置
|
||
import MenuHeader from '@/components/common/Header.vue'
|
||
import MenuTable from '@/components/common/Table.vue'
|
||
import MenuDialog from '@/components/common/Dialog.vue'
|
||
import MenuForm from '@/components/common/Form.vue'
|
||
import { menuTableColumns, menuiconOptions, menuiconMap, menuFormItemOptions } from './options'
|
||
import { rules } from './rules'
|
||
|
||
import { getMenuApi, createMenuApi, editMenuApi, deleteMenuApi } from '@/api/modules/system/menu'
|
||
// 定义header配置
|
||
const menuTitle = ref('菜单管理')
|
||
const menuHeaderButtons = [
|
||
{ label: '新增菜单', type: 'primary' as const, icon: Plus, key: 'addMenu' },
|
||
]
|
||
|
||
// 定义表格配置
|
||
const menuTree = ref<any[]>([])
|
||
const treeProps = { children: 'son' }
|
||
|
||
// 定义弹窗配置
|
||
const dialogVisible = ref(false)
|
||
const dialogTitle = ref('')
|
||
const dialogType = ref('add')
|
||
|
||
// 定义菜单表单数据
|
||
const menuForm = ref({
|
||
name: '', // 菜单名称
|
||
parentName: '', // 上级菜单名称
|
||
path: '', // 路由路径
|
||
api: '', // 后端路由
|
||
icon: '', // 图标名称
|
||
sort: null, // 排序(默认1)
|
||
type: null, // 默认是菜单类型
|
||
status: null, // 默认是启用状态
|
||
})
|
||
const menuFormRef = ref<FormInstance>()
|
||
// 表单验证规则
|
||
const menuFormRules = rules(menuForm.value, menuiconOptions)
|
||
// icon和菜单表单选项映射
|
||
const menuFormOptionsMap = ref({
|
||
parentName: [] as any[],
|
||
icon: menuiconOptions,
|
||
type: [
|
||
{ label: '菜单', value: 1 },
|
||
{ label: '按钮', value: 2 },
|
||
],
|
||
status: [
|
||
{ label: '启用', value: 1 },
|
||
{ label: '禁用', value: 2 },
|
||
],
|
||
})
|
||
|
||
/**
|
||
@description: 新增菜单
|
||
**/
|
||
const handleAddMenu = () => {
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '新增菜单'
|
||
menuForm.value.status = 1 as any // 默认是启用状态
|
||
}
|
||
|
||
/**
|
||
@description: 菜单数据处理
|
||
**/
|
||
|
||
// 获取菜单列表
|
||
const fetchMenuList = async () => {
|
||
try {
|
||
const data = await getMenuApi()
|
||
menuTree.value = data
|
||
// 处理parentName选项,添加一级菜单选项
|
||
const parentNameOptions = data.map((item) => ({
|
||
label: item.name,
|
||
value: item.id ?? '',
|
||
}))
|
||
menuFormOptionsMap.value.parentName = [{ label: '一级菜单', value: '0' }, ...parentNameOptions]
|
||
} catch (err) {
|
||
console.error('获取菜单列表失败', err)
|
||
}
|
||
}
|
||
// 页面加载时获取菜单列表
|
||
onMounted(async () => {
|
||
await fetchMenuList()
|
||
})
|
||
|
||
/**
|
||
@description: 处理菜单编辑/删除/状态切换
|
||
**/
|
||
const handleEditMenu = (row: any) => {
|
||
console.log('编辑菜单', row)
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '编辑菜单'
|
||
dialogType.value = 'edit'
|
||
menuForm.value = {
|
||
...row,
|
||
id: row.id, // 菜单id
|
||
parentName: row.name,
|
||
status: row.status ?? 1, // 默认是启用状态
|
||
api: row.api, // 后端路由
|
||
}
|
||
}
|
||
const handleDeleteMenu = async (row: any) => {
|
||
try {
|
||
await deleteMenuApi({ id: row.id })
|
||
await fetchMenuList()
|
||
} catch (err) {
|
||
console.error('删除菜单失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
@description: 处理弹窗提交/取消/关闭事件
|
||
**/
|
||
const handleSubmit = async () => {
|
||
console.log('提交菜单表单')
|
||
try {
|
||
await menuFormRef.value?.validate()
|
||
if (dialogType.value === 'add') {
|
||
const params = {
|
||
name: menuForm.value.name, // 菜单名称
|
||
parent_id: menuForm.value.parentName, // 上级菜单id
|
||
path: menuForm.value.path, // 路由路径
|
||
api: menuForm.value.api, // 后端路由
|
||
icon: menuForm.value.icon, // 图标名称
|
||
sort: menuForm.value.sort ?? 1, // 排序(默认1)
|
||
type: menuForm.value.type ?? 1, // 默认是菜单类型
|
||
}
|
||
await createMenuApi(params)
|
||
await fetchMenuList()
|
||
} else {
|
||
await editMenuApi(menuForm.value)
|
||
console.log('编辑菜单成功', menuForm.value)
|
||
await fetchMenuList()
|
||
}
|
||
dialogVisible.value = false
|
||
} catch (err) {
|
||
console.log('表单验证失败')
|
||
return
|
||
}
|
||
}
|
||
const handleCancel = () => {
|
||
dialogVisible.value = false
|
||
dialogType.value = 'add'
|
||
menuForm.value = {
|
||
name: '', // 菜单名称
|
||
parentName: '', // 上级菜单名称
|
||
path: '', // 路由路径
|
||
api: '', // 后端路由
|
||
icon: '', // 图标名称
|
||
sort: null, // 排序(默认1)
|
||
type: null, // 默认是菜单类型
|
||
status: null, // 默认是启用状态
|
||
}
|
||
}
|
||
const handleClose = () => {
|
||
dialogVisible.value = false
|
||
dialogType.value = 'add'
|
||
menuForm.value = {
|
||
name: '', // 菜单名称
|
||
parentName: '', // 上级菜单名称
|
||
path: '', // 路由路径
|
||
api: '', // 后端路由
|
||
icon: '', // 图标名称
|
||
sort: null, // 排序(默认1)
|
||
type: null, // 默认是菜单类型
|
||
status: null, // 默认是启用状态
|
||
}
|
||
}
|
||
</script>
|