234 lines
8.0 KiB
Vue
234 lines
8.0 KiB
Vue
<template>
|
||
<div class="menu-list">
|
||
<!-- 缺少通配搜索组件 -->
|
||
|
||
<div class="menu-action">
|
||
<h4>菜单列表</h4>
|
||
<el-button type="primary" :icon="Plus" @click="handleAddMenu">新增菜单</el-button>
|
||
</div>
|
||
|
||
<div class="table-container">
|
||
<el-table :data="menuTree" row-key="id" :tree-props="{ children: 'son' }" border highlight-current-row>
|
||
<el-table-column prop="name" label="菜单名称" />
|
||
<el-table-column prop="path" label="路由路径" />
|
||
<el-table-column prop="icon" label="图标">
|
||
<template #default="{ row }">
|
||
<el-icon v-if="row.icon && iconMap[row.icon]">
|
||
<component :is="iconMap[row.icon]" />
|
||
</el-icon>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="type" label="类型">
|
||
<template #default="{ row }">
|
||
{{ row.type === 1 ? '目录' : '按钮' }}
|
||
</template>
|
||
</el-table-column>
|
||
<!-- 新增:状态列 -->
|
||
<el-table-column prop="status" label="状态">
|
||
<template #default="{ row }">
|
||
<el-tag size="small" :type="row.status === 1 ? 'success' : 'danger'">
|
||
{{ row.status === 1 ? '启用' : '禁用' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作">
|
||
<template #default="{ row }">
|
||
<el-button link type="primary" size="small" @click="handleEditMenu(row)">
|
||
编辑
|
||
</el-button>
|
||
<el-button link type="danger" size="small" @click="handleDeleteMenu(row)">
|
||
删除
|
||
</el-button>
|
||
<el-button link size="small" :type="row.status === 1 ? 'warning' : 'success'"
|
||
@click="handleToggleStatus(row)">
|
||
{{ row.status === 1 ? '禁用' : '启用' }}
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
<el-dialog v-model="dialogVisible" :title="dialogType === 'add' ? '新增菜单' : '编辑菜单'" width="600px" destroy-on-close>
|
||
<el-form label-width="100px">
|
||
<el-form-item label="菜单名称">
|
||
<el-input v-model="menuForm.name" placeholder="请输入菜单名称" />
|
||
</el-form-item>
|
||
<el-form-item label="父级菜单">
|
||
<el-select v-model="menuForm.parentId" placeholder="请选择父级菜单" style="width:100%">
|
||
<el-option label="一级菜单" value="0" />
|
||
<el-option v-for="item in menuTree" :key="item.id" :label="item.name" :value="item.id + ''" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="路由路径">
|
||
<el-input v-model="menuForm.path" placeholder="例如:/system/menuList" />
|
||
</el-form-item>
|
||
<el-form-item label="后端路由">
|
||
<el-input v-model="menuForm.api" placeholder="例如:/api/system/menu/list(可选)" />
|
||
</el-form-item>
|
||
<el-form-item label="图标名称">
|
||
<el-input v-model="menuForm.icon" placeholder="例如:Tools、List" />
|
||
<div style="margin-top:8px;font-size:12px;color:#909399;">
|
||
支持的图标:Tools、List、HomeFilled、UserFilled、Platform、BellFilled、GoodsFilled、WarningFilled
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="排序">
|
||
<el-input-number v-model="menuForm.sort" :min="0" placeholder="数字越小越靠前(默认1)" />
|
||
</el-form-item>
|
||
<el-form-item label="菜单类型">
|
||
<el-radio-group v-model="menuForm.type">
|
||
<el-radio :value="1">菜单(显示在侧边栏)</el-radio>
|
||
<el-radio :value="2">按钮(权限控制)</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="handleSubmitMenu">确定</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { Tools, List, HomeFilled, UserFilled, Platform, BellFilled, GoodsFilled, WarningFilled, Plus } from '@element-plus/icons-vue'
|
||
|
||
import { getMenuApi, addMenuApi, deleteMenuApi, editMenuApi } from '@/api/modules/menu'
|
||
|
||
//menu数据
|
||
const menuTree = ref<any[]>([])
|
||
|
||
// 定义菜单表单数据
|
||
const menuForm = ref({
|
||
name: '', // 菜单名称
|
||
parentId: 0, // 默认一级菜单
|
||
path: '', // 路由路径
|
||
api: '', // 后端路由
|
||
icon: '', // 图标名称
|
||
sort: 1, // 排序(默认1)
|
||
type: 1 // 默认是菜单类型
|
||
})
|
||
|
||
// 定义图标映射表(和侧边栏逻辑一致)
|
||
const iconMap: Record<string, any> = {
|
||
Tools,
|
||
List,
|
||
HomeFilled,
|
||
UserFilled,
|
||
Platform,
|
||
BellFilled,
|
||
GoodsFilled,
|
||
WarningFilled
|
||
}
|
||
// 定义弹窗显示状态
|
||
const dialogVisible = ref(false)
|
||
// 新增:区分新增/编辑模式
|
||
const dialogType = ref<'add' | 'edit'>('add')
|
||
// 编辑菜单ID
|
||
const currentEditId = ref(null)
|
||
|
||
//所有的方法
|
||
|
||
// 获取菜单列表
|
||
onMounted(async () => {
|
||
try {
|
||
const res = await getMenuApi()
|
||
menuTree.value = filterEnabledMenus(res)
|
||
} catch (err) {
|
||
ElMessage.error('获取菜单列表失败')
|
||
}
|
||
})
|
||
|
||
// 处理菜单状态,只保留 status=1 的菜单
|
||
const filterEnabledMenus = (menuList: any[]) => {
|
||
const enabledMenus = menuList.filter(menu => menu.status === 1)
|
||
enabledMenus.forEach(menu => {
|
||
if (menu.son && menu.son.length) {
|
||
menu.son = filterEnabledMenus(menu.son)
|
||
}
|
||
})
|
||
return enabledMenus
|
||
}
|
||
|
||
// 打开新增弹窗
|
||
const handleAddMenu = () => {
|
||
// 清空表单
|
||
menuForm.value = {
|
||
name: '',
|
||
parentId: '',
|
||
path: '',
|
||
api: '',
|
||
icon: '',
|
||
sort: 1,
|
||
type: 1
|
||
}
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
//打开编辑弹窗
|
||
const handleEditMenu = (row: any) => {
|
||
dialogType.value = 'edit'
|
||
currentEditId.value = row.id
|
||
|
||
menuForm.value = {
|
||
name: row.name,
|
||
parentId: row.parentId,
|
||
path: row.path,
|
||
api: row.api,
|
||
icon: row.icon,
|
||
sort: row.sort,
|
||
type: row.type
|
||
}
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
// 提交表单(新增/编辑)
|
||
const handleSubmitMenu = async () => {
|
||
//添加校验,校验通过后提交表单
|
||
try {
|
||
if (dialogType.value === 'add') {
|
||
await addMenuApi({
|
||
...menuForm.value,
|
||
parent_id: menuForm.value.parentId
|
||
})
|
||
} else {
|
||
await editMenuApi({
|
||
id: currentEditId.value || 0,
|
||
status: menuForm.value.type === 2 ? 0 : 1, // 按钮默认禁用
|
||
parent_id: menuForm.value.parentId,
|
||
...menuForm.value
|
||
})
|
||
}
|
||
dialogVisible.value = false
|
||
} catch (err) {
|
||
ElMessage.error('操作失败')
|
||
}
|
||
}
|
||
|
||
//删除菜单
|
||
const handleDeleteMenu = async (row: any) => {
|
||
try {
|
||
await deleteMenuApi({ id: row.id })
|
||
} catch (err) {
|
||
console.log('删除菜单失败', err)
|
||
}
|
||
}
|
||
|
||
|
||
// 切换状态
|
||
const handleToggleStatus = async (row: any) => {
|
||
row.status = row.status === 1 ? 0 : 1
|
||
ElMessage.success(`已${row.status === 1 ? '启用' : '禁用'}`)
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.menu-list {
|
||
.menu-action {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
}
|
||
</style>
|