3.10号提交

This commit is contained in:
yzl 2026-03-10 23:24:52 +08:00
parent 39596f3224
commit d03552b416
6 changed files with 606 additions and 220 deletions

View File

@ -0,0 +1,52 @@
<!-- src/components/CommonDialog.vue -->
<template>
<el-dialog :model-value="visible" :title="title" :width="width" :destroy-on-close="destroyOnClose" @close="handleClose"
v-bind="$attrs">
<!-- 对话框内容插槽 -->
<slot />
<!-- 底部按钮插槽 -->
<template #footer>
<slot name="footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</slot>
</template>
</el-dialog>
</template>
<script setup lang="ts">
interface Props {
visible: boolean
title: string
width?: string | number
destroyOnClose?: boolean
}
interface Emits {
(e: 'update:visible', value: boolean): void
(e: 'confirm'): void
(e: 'cancel'): void
(e: 'close'): void
}
const props = withDefaults(defineProps<Props>(), {
width: '400px',
destroyOnClose: true,
})
const emit = defineEmits<Emits>()
const handleConfirm = () => {
emit('confirm')
}
const handleCancel = () => {
emit('update:visible', false)
emit('cancel')
}
const handleClose = () => {
emit('close')
}
</script>

View File

@ -0,0 +1,79 @@
<template>
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-bind="$attrs">
<!-- 动态表单项 -->
<template v-for="(item, index) in formItems" :key="index">
<el-form-item :label="item.label" :prop="item.prop" :required="item.required">
<!-- 输入框 -->
<el-input v-if="item.type === 'input'" v-model="formData[item.prop]" :placeholder="item.placeholder"
:disabled="item.disabled" clearable />
<!-- 下拉选择框 -->
<el-select v-else-if="item.type === 'select'" v-model="formData[item.prop]"
:placeholder="item.placeholder" :disabled="item.disabled" clearable style="width: 100%">
<el-option v-for="option in props.optionsMap[item.prop]" :key="option.value" :label="option.label"
:value="option.value">
<template v-if="option.icon" #label>
<span style="display: flex; align-items: center; gap: 8px;">
<el-icon v-if="option.icon">
<component :is="option.icon" />
</el-icon>
<span>{{ option.label }}</span>
</span>
</template>
</el-option>
</el-select>
<!-- 数字输入框 -->
<el-input-number v-else-if="item.type === 'number'" v-model="formData[item.prop]" :min="item.min"
:max="item.max" :placeholder="item.placeholder" :disabled="item.disabled" style="width: 100%" />
<!-- 单选框组 -->
<el-radio-group v-else-if="item.type === 'radio'" v-model="formData[item.prop]">
<el-radio v-for="option in props.optionsMap[item.prop]" :key="option.value" :value="option.value">
{{ option.label }}
</el-radio>
</el-radio-group>
<!-- 自定义插槽 -->
<slot v-else :name="item.slotName" :formData="formData" />
</el-form-item>
</template>
</el-form>
</template>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import type { Component } from 'vue'
interface FormItem {
type: 'input' | 'select' | 'number' | 'radio' | 'slot'
label: string
prop: string
placeholder?: string
required?: boolean
disabled?: boolean
min?: number
max?: number
slotName?: string //
}
interface Props {
formData: Record<string, any>
formRules: FormRules
formItems: FormItem[]
optionsMap: Record<string, Array<{
label: string | undefined
value: string | number
icon?: Component
}>>
}
const formRef = ref<FormInstance>()
const props = defineProps<Props>()
//
defineExpose({
validate: () => formRef.value?.validate(),
resetFields: () => formRef.value?.resetFields()
})
</script>

View File

@ -0,0 +1,45 @@
<!-- src/components/CommonTableHeader.vue -->
<template>
<div class="header">
<h4>{{ title }}</h4>
<div class="header-actions">
<el-button v-for="(btn, index) in buttons" :key="btn.key || index" :type="btn.type || 'default'"
:icon="btn.icon" @click="handleButtonClick(btn)" :disabled="btn.disabled">
{{ btn.label }}
</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import type { ButtonProps } from 'element-plus'
import type { Component } from 'vue'
//
interface HeaderButton {
label: string
type?: ButtonProps['type']
icon?: Component
disabled?: boolean
key?: string | number //
}
//
interface Props {
title: string
buttons: HeaderButton[]
}
const props = defineProps<Props>()
//
const emit = defineEmits<{
// button-click
'button-click': [button: HeaderButton]
}>()
//
const handleButtonClick = (button: HeaderButton) => {
//
emit('button-click', button)
}
</script>

View File

@ -0,0 +1,47 @@
<template>
<div class="table-container">
<el-table :data="tableData" :row-key="rowKey" :tree-props="treeProps" :border="border" :highlight-current-row="highlightCurrentRow"
v-bind="$attrs">
<!-- 动态表头列 -->
<template v-for="(column, index) in columns" :key="index">
<el-table-column v-if="!column.slotName" :prop="column.prop" :label="column.label" :width="column.width"
:align="column.align || 'left'" />
<!-- 具名插槽列 -->
<el-table-column v-else :label="column.label" :width="column.width" :align="column.align || 'left'">
<template #default="{ row }">
<slot :name="column.slotName" :row="row" />
</template>
</el-table-column>
</template>
</el-table>
</div>
</template>
<script setup lang="ts">
//
interface TableColumn {
prop?: string
label: string
width?: string | number
align?: 'left' | 'center' | 'right'
slotName?: string //
}
//
interface Props {
tableData: any[]
rowKey?: string
treeProps?: {
children: string
}
columns?: TableColumn[],
border?: boolean //
highlightCurrentRow?: boolean //
}
const props = withDefaults(defineProps<Props>(), {
border: true,
highlightCurrentRow: true,
})
</script>

View File

@ -1,256 +1,163 @@
<template>
<div class="system">
<!-- 缺少通配搜索组件 -->
<div class="header">
<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>
<!-- 菜单列表头 -->
<MenuHeader :title="menuTitle" :buttons="menuHeaderButtons" @click="handleAddMenu" />
<!-- 菜单列表表格 -->
<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 }">
<el-tag size="small" :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
<template #action="{ 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>
</MenuTable>
</div>
<el-dialog v-model="dialogVisible" :title="dialogType === 'add' ? '新增菜单' : '编辑菜单'" width="600px" destroy-on-close>
<el-form ref="menuFormRef" :model="menuForm" :rules="menuFormRules">
<el-form-item label="菜单名称" prop="name">
<el-input v-model="menuForm.name" placeholder="请输入菜单名称" />
</el-form-item>
<el-form-item label="父级菜单" prop="parentId">
<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="路由路径" prop="path">
<el-input v-model="menuForm.path" placeholder="例如:/system/menuList" />
</el-form-item>
<el-form-item label="后端路由" prop="api">
<el-input v-model="menuForm.api" placeholder="例如:/api/system/menu/list可选" />
</el-form-item>
<el-form-item label="图标名称" prop="icon">
<el-select v-model="menuForm.icon" placeholder="请选择图标(二级菜单可留空)" style="width: 100%" clearable>
<el-option v-for="item in iconOptions" :key="item.value" :label="item.label" :value="item.value">
<template #label>
<span style="display: flex; align-items: center; gap: 8px;">
<el-icon v-if="item.icon">
<component :is="item.icon" />
</el-icon>
<span>{{ item.label }}</span>
</span>
</template>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="menuForm.sort" :min="0" placeholder="数字越小越靠前默认1" style="width: 100%" />
</el-form-item>
<el-form-item label="菜单类型" prop="type">
<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, dialogType = 'add' } }">取消</el-button>
<el-button type="primary" @click="handleSubmitMenu">确定</el-button>
</template>
</el-dialog>
<!-- 菜单新增/编辑弹窗 -->
<MenuDialog :visible="dialogVisible" :title="dialogTitle" @confirm="handleSubmit" @cancel="handleCancel"
@close="handleClose">
<MenuForm :form-data="menuForm" :form-rules="menuFormRules" :form-items="MenuFormItemOptions"
:options-map="menuFormOptionsMap" ref="menuFormRef" />
</MenuDialog>
</template>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { Tools, List, HomeFilled, UserFilled, Platform, BellFilled, GoodsFilled, WarningFilled, Plus } from '@element-plus/icons-vue'
import { getMenuApi, createMenuApi, deleteMenuApi, editMenuApi } from '@/api/modules/menu'
<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'
//
const iconMap: Record<string, any> = {
Tools,
List,
HomeFilled,
UserFilled,
Platform,
BellFilled,
GoodsFilled,
WarningFilled
}
//
const iconOptions = [
{ label: "无图标", value: "无图标" },
{ label: "Tools(工具)", value: "Tools", icon: Tools },
{ label: "List(列表)", value: "List", icon: List },
{ label: "HomeFilled(首页)", value: "HomeFilled", icon: HomeFilled },
{ label: "UserFilled(用户)", value: "UserFilled", icon: UserFilled },
{ label: "Platform(平台)", value: "Platform", icon: Platform },
{ label: "BellFilled(铃铛)", value: "BellFilled", icon: BellFilled },
{ label: "GoodsFilled(商品)", value: "GoodsFilled", icon: GoodsFilled },
{ label: "WarningFilled(警告)", value: "WarningFilled", icon: WarningFilled },
import { getMenuApi } from '@/api/modules/menu'
// header
const menuTitle = ref('菜单管理')
const menuHeaderButtons = [
{ label: '新增菜单', type: 'primary' as const, icon: Plus, key: 'addMenu' },
]
//menu
//
const menuTree = ref<any[]>([])
const treeProps = { children: 'son' }
//
const dialogVisible = ref(false)
const dialogTitle = ref('')
//
const menuForm = ref({
name: '', //
parentId: '0', //
nameValue: '', //
path: '', //
api: '', //
icon: '', //
sort: 1, // 1
type: 1 //
sort: null, // 1
type: null //
})
const menuFormRef = ref<FormInstance>()
//
const menuFormRules = rules(menuForm.value, iconOptions)
//
const menuFormRules = rules(menuForm.value, MenuiconOptions)
//
const menuFormOptionsMap = ref({
'parentName': [
{ label: '一级菜单', value: '1' },
],
'icon': MenuiconOptions,
'type': [
{ label: '菜单', value: 1 },
{ label: '按钮', value: 2 }
]
})
//
const dialogVisible = ref(false)
// /
const dialogType = ref<'add' | 'edit'>('add')
// ID
const currentEditId = ref(null)
//
/**
@description: 新增菜单
**/
const handleAddMenu = () => {
dialogVisible.value = true
dialogTitle.value = '新增菜单'
console.log('新增菜单')
}
/**
@description: 菜单数据处理
**/
// status=1
const filterMenus = (menuList: any[]) => {
const enabledMenus = menuList.filter(menu => menu.status === 1)
enabledMenus.forEach(menu => {
if (menu.son && menu.son.length) {
menu.son = filterMenus(menu.son)
}
})
return enabledMenus
}
//
onMounted(async () => {
try {
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
const data = await getMenuApi()
menuTree.value = filterMenus(data)
// parentName
const parentNameOptions = data.map(item => ({
label: item.name,
value: item.id ?? ''
}))
menuFormOptionsMap.value.parentName = [
{ label: '一级菜单', value: '1' },
...parentNameOptions
]
} catch (err) {
console.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: '0',
path: '',
api: '',
icon: '',
sort: 1,
type: 1
}
dialogVisible.value = true
console.log('dialogType.value', dialogType.value);
}
//
/**
@description: 处理菜单编辑/删除/状态切换
**/
const handleEditMenu = (row: any) => {
dialogType.value = 'edit'
currentEditId.value = row.id
menuForm.value = {
name: row.name,
parentId: row.parent_id,
path: row.path,
api: row.api,
icon: row.icon,
sort: row.sort,
type: row.type
}
dialogVisible.value = true
dialogTitle.value = '编辑菜单'
console.log('编辑菜单', row)
}
const handleDeleteMenu = (row: any) => {
console.log('删除菜单', row)
}
const handleToggleStatus = (row: any) => {
console.log('切换菜单状态', row)
}
// /
const handleSubmitMenu = async () => {
try {
await menuFormRef.value?.validate()
if (dialogType.value === 'add') {
await createMenuApi({
...menuForm.value,
parent_id: menuForm.value.parentId
})
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
} else {
await editMenuApi({
id: currentEditId.value || 0,
status: menuForm.value.type === 2 ? 0 : 1, //
parent_id: menuForm.value.parentId,
...menuForm.value
})
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
}
dialogVisible.value = false
} catch (err) {
console.log('提交菜单失败', err)
}
/**
@description: 处理弹窗提交/取消/关闭事件
**/
const handleSubmit = () => {
console.log('提交菜单表单')
}
//
const handleDeleteMenu = async (row: any) => {
try {
await deleteMenuApi({ id: row.id })
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
} catch (err) {
console.log('删除菜单失败', err)
}
const handleCancel = () => {
dialogVisible.value = false
}
//
const handleToggleStatus = async (row: any) => {
row.status = row.status === 1 ? 0 : 1
ElMessage.success(`${row.status === 1 ? '启用' : '禁用'}`)
const handleClose = () => {
dialogVisible.value = false
}
</script>
</script>

View File

@ -0,0 +1,256 @@
<template>
<div class="system">
<!-- 缺少通配搜索组件 -->
<div class="header">
<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 ref="menuFormRef" :model="menuForm" :rules="menuFormRules">
<el-form-item label="菜单名称" prop="name">
<el-input v-model="menuForm.name" placeholder="请输入菜单名称" />
</el-form-item>
<el-form-item label="父级菜单" prop="parentId">
<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="路由路径" prop="path">
<el-input v-model="menuForm.path" placeholder="例如:/system/menuList" />
</el-form-item>
<el-form-item label="后端路由" prop="api">
<el-input v-model="menuForm.api" placeholder="例如:/api/system/menu/list可选" />
</el-form-item>
<el-form-item label="图标名称" prop="icon">
<el-select v-model="menuForm.icon" placeholder="请选择图标(二级菜单可留空)" style="width: 100%" clearable>
<el-option v-for="item in iconOptions" :key="item.value" :label="item.label" :value="item.value">
<template #label>
<span style="display: flex; align-items: center; gap: 8px;">
<el-icon v-if="item.icon">
<component :is="item.icon" />
</el-icon>
<span>{{ item.label }}</span>
</span>
</template>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="menuForm.sort" :min="0" placeholder="数字越小越靠前默认1" style="width: 100%" />
</el-form-item>
<el-form-item label="菜单类型" prop="type">
<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, dialogType = 'add' } }">取消</el-button>
<el-button type="primary" @click="handleSubmitMenu">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { Tools, List, HomeFilled, UserFilled, Platform, BellFilled, GoodsFilled, WarningFilled, Plus } from '@element-plus/icons-vue'
import { getMenuApi, createMenuApi, deleteMenuApi, editMenuApi } from '@/api/modules/menu'
import { rules } from './rules'
//
const iconMap: Record<string, any> = {
Tools,
List,
HomeFilled,
UserFilled,
Platform,
BellFilled,
GoodsFilled,
WarningFilled
}
//
const iconOptions = [
{ label: "无图标", value: "无图标" },
{ label: "Tools(工具)", value: "Tools", icon: Tools },
{ label: "List(列表)", value: "List", icon: List },
{ label: "HomeFilled(首页)", value: "HomeFilled", icon: HomeFilled },
{ label: "UserFilled(用户)", value: "UserFilled", icon: UserFilled },
{ label: "Platform(平台)", value: "Platform", icon: Platform },
{ label: "BellFilled(铃铛)", value: "BellFilled", icon: BellFilled },
{ label: "GoodsFilled(商品)", value: "GoodsFilled", icon: GoodsFilled },
{ label: "WarningFilled(警告)", value: "WarningFilled", icon: WarningFilled },
]
//menu
const menuTree = ref<any[]>([])
//
const menuForm = ref({
name: '', //
parentId: '0', //
path: '', //
api: '', //
icon: '', //
sort: 1, // 1
type: 1 //
})
const menuFormRef = ref<FormInstance>()
//
const menuFormRules = rules(menuForm.value, iconOptions)
//
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) {
console.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: '0',
path: '',
api: '',
icon: '',
sort: 1,
type: 1
}
dialogVisible.value = true
console.log('dialogType.value', dialogType.value);
}
//
const handleEditMenu = (row: any) => {
dialogType.value = 'edit'
currentEditId.value = row.id
menuForm.value = {
name: row.name,
parentId: row.parent_id,
path: row.path,
api: row.api,
icon: row.icon,
sort: row.sort,
type: row.type
}
dialogVisible.value = true
}
// /
const handleSubmitMenu = async () => {
try {
await menuFormRef.value?.validate()
if (dialogType.value === 'add') {
await createMenuApi({
...menuForm.value,
parent_id: menuForm.value.parentId
})
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
} else {
await editMenuApi({
id: currentEditId.value || 0,
status: menuForm.value.type === 2 ? 0 : 1, //
parent_id: menuForm.value.parentId,
...menuForm.value
})
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
}
dialogVisible.value = false
} catch (err) {
console.log('提交菜单失败', err)
}
}
//
const handleDeleteMenu = async (row: any) => {
try {
await deleteMenuApi({ id: row.id })
const res = await getMenuApi()
menuTree.value = filterEnabledMenus(res)
} catch (err) {
console.log('删除菜单失败', err)
}
}
//
const handleToggleStatus = async (row: any) => {
row.status = row.status === 1 ? 0 : 1
ElMessage.success(`${row.status === 1 ? '启用' : '禁用'}`)
}
</script>