多文件: 菜单parentId由string改成uint

This commit is contained in:
crazyrunsnail
2024-04-11 16:38:09 +08:00
parent 032910f87a
commit baa48a1679
9 changed files with 343 additions and 445 deletions

View File

@@ -2,28 +2,23 @@
<div>
<div class="gva-table-box">
<div class="gva-btn-list">
<el-button
type="primary"
icon="plus"
@click="addMenu('0')"
>新增根菜单</el-button>
<el-button type="primary" icon="plus" @click="addMenu('0')"
>新增根菜单</el-button
>
<el-icon
class="cursor-pointer"
@click="toDoc('https://www.bilibili.com/video/BV1kv4y1g7nT/?p=4&vd_source=f2640257c21e3b547a790461ed94875e')"
><VideoCameraFilled /></el-icon>
@click="
toDoc(
'https://www.bilibili.com/video/BV1kv4y1g7nT/?p=4&vd_source=f2640257c21e3b547a790461ed94875e'
)
"
><VideoCameraFilled
/></el-icon>
</div>
<!-- 由于此处菜单跟左侧列表一一对应所以不需要分页 pageSize默认999 -->
<el-table
:data="tableData"
row-key="ID"
>
<el-table-column
align="left"
label="ID"
min-width="100"
prop="ID"
/>
<el-table :data="tableData" row-key="ID">
<el-table-column align="left" label="ID" min-width="100" prop="ID" />
<el-table-column
align="left"
label="展示名称"
@@ -41,10 +36,7 @@
prop="authorityName"
>
<template #default="scope">
<div
v-if="scope.row.meta.icon"
class="icon-column"
>
<div v-if="scope.row.meta.icon" class="icon-column">
<el-icon>
<component :is="scope.row.meta.icon" />
</el-icon>
@@ -73,7 +65,7 @@
prop="hidden"
>
<template #default="scope">
<span>{{ scope.row.hidden?"隐藏":"显示" }}</span>
<span>{{ scope.row.hidden ? "隐藏" : "显示" }}</span>
</template>
</el-table-column>
<el-table-column
@@ -82,44 +74,36 @@
min-width="90"
prop="parentId"
/>
<el-table-column
align="left"
label="排序"
min-width="70"
prop="sort"
/>
<el-table-column align="left" label="排序" min-width="70" prop="sort" />
<el-table-column
align="left"
label="文件路径"
min-width="360"
prop="component"
/>
<el-table-column
align="left"
fixed="right"
label="操作"
width="300"
>
<el-table-column align="left" fixed="right" label="操作" width="300">
<template #default="scope">
<el-button
type="primary"
link
icon="plus"
@click="addMenu(scope.row.ID)"
>添加子菜单</el-button>
>添加子菜单</el-button
>
<el-button
type="primary"
link
icon="edit"
@click="editMenu(scope.row.ID)"
>编辑</el-button>
>编辑</el-button
>
<el-button
type="primary"
link
icon="delete"
@click="deleteMenu(scope.row.ID)"
>删除</el-button>
>删除</el-button
>
</template>
</el-table-column>
</el-table>
@@ -135,10 +119,7 @@
<span class="text-lg">{{ dialogTitle }}</span>
<div>
<el-button @click="closeDialog"> </el-button>
<el-button
type="primary"
@click="enterDialog"
> </el-button>
<el-button type="primary" @click="enterDialog"> </el-button>
</div>
</div>
</template>
@@ -153,11 +134,7 @@
label-position="top"
label-width="85px"
>
<el-form-item
label="路由Name"
prop="path"
style="width:30%"
>
<el-form-item label="路由Name" prop="path" style="width: 30%">
<el-input
v-model="form.name"
autocomplete="off"
@@ -165,17 +142,15 @@
@change="changeName"
/>
</el-form-item>
<el-form-item
prop="path"
style="width:30%"
>
<el-form-item prop="path" style="width: 30%">
<template #label>
<span style="display: inline-flex;align-items: center;">
<span style="display: inline-flex; align-items: center">
<span>路由Path</span>
<el-checkbox
v-model="checkFlag"
style="margin-left:12px;height: auto"
>添加参数</el-checkbox>
style="margin-left: 12px; height: auto"
>添加参数</el-checkbox
>
</span>
</template>
@@ -186,88 +161,54 @@
placeholder="建议只在后方拼接参数"
/>
</el-form-item>
<el-form-item
label="是否隐藏"
style="width:30%"
>
<el-select
v-model="form.hidden"
placeholder="是否在列表隐藏"
>
<el-option
:value="false"
label="否"
/>
<el-option
:value="true"
label="是"
/>
<el-form-item label="是否隐藏" style="width: 30%">
<el-select v-model="form.hidden" placeholder="是否在列表隐藏">
<el-option :value="false" label="否" />
<el-option :value="true" label="是" />
</el-select>
</el-form-item>
<el-form-item
label="父节点ID"
style="width:30%"
>
<el-form-item label="父节点ID" style="width: 30%">
<el-cascader
v-model="form.parentId"
style="width:100%"
style="width: 100%"
:disabled="!isEdit"
:options="menuOption"
:props="{ checkStrictly: true,label:'title',value:'ID',disabled:'disabled',emitPath:false}"
:props="{
checkStrictly: true,
label: 'title',
value: 'ID',
disabled: 'disabled',
emitPath: false,
}"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item
label="文件路径"
prop="component"
style="width:60%"
>
<el-form-item label="文件路径" prop="component" style="width: 60%">
<el-input
v-model="form.component"
autocomplete="off"
placeholder="页面:view/xxx/xx.vue 插件:plugin/xx/xx.vue"
@blur="fmtComponent"
/>
<span style="font-size:12px;margin-right:12px;">如果菜单包含子菜单请创建router-view二级路由页面或者</span><el-button
style="margin-top:4px"
<span style="font-size: 12px; margin-right: 12px"
>如果菜单包含子菜单请创建router-view二级路由页面或者</span
><el-button
style="margin-top: 4px"
@click="form.component = 'view/routerHolder.vue'"
>点我设置</el-button>
>点我设置</el-button
>
</el-form-item>
<el-form-item
label="展示名称"
prop="meta.title"
style="width:30%"
>
<el-input
v-model="form.meta.title"
autocomplete="off"
/>
<el-form-item label="展示名称" prop="meta.title" style="width: 30%">
<el-input v-model="form.meta.title" autocomplete="off" />
</el-form-item>
<el-form-item
label="图标"
prop="meta.icon"
style="width:30%"
>
<icon
:meta="form.meta"
style="width:100%"
/>
<el-form-item label="图标" prop="meta.icon" style="width: 30%">
<icon :meta="form.meta" style="width: 100%" />
</el-form-item>
<el-form-item
label="排序标记"
prop="sort"
style="width:30%"
>
<el-input
v-model.number="form.sort"
autocomplete="off"
/>
<el-form-item label="排序标记" prop="sort" style="width: 30%">
<el-input v-model.number="form.sort" autocomplete="off" />
</el-form-item>
<el-form-item
prop="meta.activeName"
style="width:30%"
>
<el-form-item prop="meta.activeName" style="width: 30%">
<template #label>
<div>
<span> 高亮菜单 </span>
@@ -289,44 +230,28 @@
<el-form-item
label="KeepAlive"
prop="meta.keepAlive"
style="width:30%"
style="width: 30%"
>
<el-select
v-model="form.meta.keepAlive"
style="width:100%"
style="width: 100%"
placeholder="是否keepAlive缓存页面"
>
<el-option
:value="false"
label="否"
/>
<el-option
:value="true"
label="是"
/>
<el-option :value="false" label="否" />
<el-option :value="true" label="是" />
</el-select>
</el-form-item>
<el-form-item
label="CloseTab"
prop="meta.closeTab"
style="width:30%"
>
<el-form-item label="CloseTab" prop="meta.closeTab" style="width: 30%">
<el-select
v-model="form.meta.closeTab"
style="width:100%"
style="width: 100%"
placeholder="是否自动关闭tab"
>
<el-option
:value="false"
label="否"
/>
<el-option
:value="true"
label="是"
/>
<el-option :value="false" label="否" />
<el-option :value="true" label="是" />
</el-select>
</el-form-item>
<el-form-item style="width:30%">
<el-form-item style="width: 30%">
<template #label>
<div>
<span> 是否为基础页面 </span>
@@ -342,36 +267,30 @@
<el-select
v-model="form.meta.defaultMenu"
style="width:100%"
style="width: 100%"
placeholder="是否为基础页面"
>
<el-option
:value="false"
label="否"
/>
<el-option
:value="true"
label="是"
/>
<el-option :value="false" label="否" />
<el-option :value="true" label="是" />
</el-select>
</el-form-item>
</el-form>
<div>
<div class="flex items-center gap-2">
<el-button
type="primary"
icon="edit"
@click="addParameter(form)"
>新增菜单参数</el-button>
<el-button type="primary" icon="edit" @click="addParameter(form)"
>新增菜单参数</el-button
>
<el-icon
class="cursor-pointer"
@click="toDoc('https://www.bilibili.com/video/BV1kv4y1g7nT?p=9&vd_source=f2640257c21e3b547a790461ed94875e')"
><VideoCameraFilled /></el-icon>
@click="
toDoc(
'https://www.bilibili.com/video/BV1kv4y1g7nT?p=9&vd_source=f2640257c21e3b547a790461ed94875e'
)
"
><VideoCameraFilled
/></el-icon>
</div>
<el-table
:data="form.parameters"
style="width: 100%;margin-top: 12px;"
>
<el-table :data="form.parameters" style="width: 100%; margin-top: 12px">
<el-table-column
align="left"
prop="type"
@@ -379,40 +298,20 @@
width="180"
>
<template #default="scope">
<el-select
v-model="scope.row.type"
placeholder="请选择"
>
<el-option
key="query"
value="query"
label="query"
/>
<el-option
key="params"
value="params"
label="params"
/>
<el-select v-model="scope.row.type" placeholder="请选择">
<el-option key="query" value="query" label="query" />
<el-option key="params" value="params" label="params" />
</el-select>
</template>
</el-table-column>
<el-table-column
align="left"
prop="key"
label="参数key"
width="180"
>
<el-table-column align="left" prop="key" label="参数key" width="180">
<template #default="scope">
<div>
<el-input v-model="scope.row.key" />
</div>
</template>
</el-table-column>
<el-table-column
align="left"
prop="value"
label="参数值"
>
<el-table-column align="left" prop="value" label="参数值">
<template #default="scope">
<div>
<el-input v-model="scope.row.value" />
@@ -424,36 +323,38 @@
<div>
<el-button
type="danger"
icon="delete"
@click="deleteParameter(form.parameters,scope.$index)"
>删除</el-button>
@click="deleteParameter(form.parameters, scope.$index)"
>删除</el-button
>
</div>
</template>
</el-table-column>
</el-table>
<div class="flex items-center gap-2 mt-3">
<el-button
type="primary"
icon="edit"
@click="addBtn(form)"
>新增可控按钮
<el-button type="primary" icon="edit" @click="addBtn(form)"
>新增可控按钮
</el-button>
<el-icon
class="cursor-pointer"
@click="toDoc('https://www.gin-vue-admin.com/guide/web/button-auth.html')"
><QuestionFilled /></el-icon>
@click="
toDoc('https://www.gin-vue-admin.com/guide/web/button-auth.html')
"
><QuestionFilled
/></el-icon>
<el-icon
class="cursor-pointer"
@click="toDoc('https://www.bilibili.com/video/BV1kv4y1g7nT?p=11&vd_source=f2640257c21e3b547a790461ed94875e')"
><VideoCameraFilled /></el-icon>
@click="
toDoc(
'https://www.bilibili.com/video/BV1kv4y1g7nT?p=11&vd_source=f2640257c21e3b547a790461ed94875e'
)
"
><VideoCameraFilled
/></el-icon>
</div>
<el-table
:data="form.menuBtn"
style="width: 100%;margin-top: 12px;"
>
<el-table :data="form.menuBtn" style="width: 100%; margin-top: 12px">
<el-table-column
align="left"
prop="name"
@@ -466,12 +367,7 @@
</div>
</template>
</el-table-column>
<el-table-column
align="left"
prop="name"
label="备注"
width="180"
>
<el-table-column align="left" prop="name" label="备注" width="180">
<template #default="scope">
<div>
<el-input v-model="scope.row.desc" />
@@ -483,10 +379,10 @@
<div>
<el-button
type="danger"
icon="delete"
@click="deleteBtn(form.menuBtn,scope.$index)"
>删除</el-button>
@click="deleteBtn(form.menuBtn, scope.$index)"
>删除</el-button
>
</div>
</template>
</el-table-column>
@@ -502,270 +398,271 @@ import {
getMenuList,
addBaseMenu,
deleteBaseMenu,
getBaseMenuById
} from '@/api/menu'
import icon from '@/view/superAdmin/menu/icon.vue'
import WarningBar from '@/components/warningBar/warningBar.vue'
import { canRemoveAuthorityBtnApi } from '@/api/authorityBtn'
import { reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { QuestionFilled, VideoCameraFilled } from '@element-plus/icons-vue'
getBaseMenuById,
} from "@/api/menu";
import icon from "@/view/superAdmin/menu/icon.vue";
import WarningBar from "@/components/warningBar/warningBar.vue";
import { canRemoveAuthorityBtnApi } from "@/api/authorityBtn";
import { reactive, ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { QuestionFilled, VideoCameraFilled } from "@element-plus/icons-vue";
import { toDoc } from '@/utils/doc'
import { toDoc } from "@/utils/doc";
defineOptions({
name: 'Menus',
})
name: "Menus",
});
const rules = reactive({
path: [{ required: true, message: '请输入菜单name', trigger: 'blur' }],
component: [
{ required: true, message: '请输入文件路径', trigger: 'blur' }
path: [{ required: true, message: "请输入菜单name", trigger: "blur" }],
component: [{ required: true, message: "请输入文件路径", trigger: "blur" }],
"meta.title": [
{ required: true, message: "请输入菜单展示名称", trigger: "blur" },
],
'meta.title': [
{ required: true, message: '请输入菜单展示名称', trigger: 'blur' }
]
})
});
const page = ref(1)
const total = ref(0)
const pageSize = ref(999)
const tableData = ref([])
const searchInfo = ref({})
const page = ref(1);
const total = ref(0);
const pageSize = ref(999);
const tableData = ref([]);
const searchInfo = ref({});
// 查询
const getTableData = async() => {
const table = await getMenuList({ page: page.value, pageSize: pageSize.value, ...searchInfo.value })
const getTableData = async () => {
const table = await getMenuList({
page: page.value,
pageSize: pageSize.value,
...searchInfo.value,
});
if (table.code === 0) {
tableData.value = table.data.list
total.value = table.data.total
page.value = table.data.page
pageSize.value = table.data.pageSize
tableData.value = table.data.list;
total.value = table.data.total;
page.value = table.data.page;
pageSize.value = table.data.pageSize;
}
}
};
getTableData()
getTableData();
// 新增参数
const addParameter = (form) => {
if (!form.parameters) {
form.parameters = []
form.parameters = [];
}
form.parameters.push({
type: 'query',
key: '',
value: ''
})
}
type: "query",
key: "",
value: "",
});
};
const fmtComponent = () => {
form.value.component = form.value.component.replace(/\\/g, '/')
}
form.value.component = form.value.component.replace(/\\/g, "/");
};
// 删除参数
const deleteParameter = (parameters, index) => {
parameters.splice(index, 1)
}
parameters.splice(index, 1);
};
// 新增可控按钮
const addBtn = (form) => {
if (!form.menuBtn) {
form.menuBtn = []
form.menuBtn = [];
}
form.menuBtn.push({
name: '',
desc: '',
})
}
name: "",
desc: "",
});
};
// 删除可控按钮
const deleteBtn = async(btns, index) => {
const btn = btns[index]
const deleteBtn = async (btns, index) => {
const btn = btns[index];
if (btn.ID === 0) {
btns.splice(index, 1)
return
btns.splice(index, 1);
return;
}
const res = await canRemoveAuthorityBtnApi({ id: btn.ID })
const res = await canRemoveAuthorityBtnApi({ id: btn.ID });
if (res.code === 0) {
btns.splice(index, 1)
btns.splice(index, 1);
}
}
};
const form = ref({
ID: 0,
path: '',
name: '',
path: "",
name: "",
hidden: false,
parentId: '',
component: '',
parentId: 0,
component: "",
meta: {
activeName: '',
title: '',
icon: '',
activeName: "",
title: "",
icon: "",
defaultMenu: false,
closeTab: false,
keepAlive: false
keepAlive: false,
},
parameters: [],
menuBtn: []
})
menuBtn: [],
});
const changeName = () => {
form.value.path = form.value.name
}
form.value.path = form.value.name;
};
const handleClose = (done) => {
initForm()
done()
}
initForm();
done();
};
// 删除菜单
const deleteMenu = (ID) => {
ElMessageBox.confirm('此操作将永久删除所有角色下该菜单, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
ElMessageBox.confirm("此操作将永久删除所有角色下该菜单, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async() => {
const res = await deleteBaseMenu({ ID })
.then(async () => {
const res = await deleteBaseMenu({ ID });
if (res.code === 0) {
ElMessage({
type: 'success',
message: '删除成功!'
})
type: "success",
message: "删除成功!",
});
if (tableData.value.length === 1 && page.value > 1) {
page.value--
page.value--;
}
getTableData()
getTableData();
}
})
.catch(() => {
ElMessage({
type: 'info',
message: '已取消删除'
})
})
}
type: "info",
message: "已取消删除",
});
});
};
// 初始化弹窗内表格方法
const menuForm = ref(null)
const checkFlag = ref(false)
const menuForm = ref(null);
const checkFlag = ref(false);
const initForm = () => {
checkFlag.value = false
menuForm.value.resetFields()
checkFlag.value = false;
menuForm.value.resetFields();
form.value = {
ID: 0,
path: '',
name: '',
path: "",
name: "",
hidden: false,
parentId: '',
component: '',
parentId: 0,
component: "",
meta: {
title: '',
icon: '',
title: "",
icon: "",
defaultMenu: false,
closeTab: false,
keepAlive: false
}
}
}
keepAlive: false,
},
};
};
// 关闭弹窗
const dialogFormVisible = ref(false)
const dialogFormVisible = ref(false);
const closeDialog = () => {
initForm()
dialogFormVisible.value = false
}
initForm();
dialogFormVisible.value = false;
};
// 添加menu
const enterDialog = async() => {
menuForm.value.validate(async valid => {
const enterDialog = async () => {
menuForm.value.validate(async (valid) => {
if (valid) {
let res
let res;
if (isEdit.value) {
res = await updateBaseMenu(form.value)
res = await updateBaseMenu(form.value);
} else {
res = await addBaseMenu(form.value)
res = await addBaseMenu(form.value);
}
if (res.code === 0) {
ElMessage({
type: 'success',
message: isEdit.value ? '编辑成功' : '添加成功!'
})
getTableData()
type: "success",
message: isEdit.value ? "编辑成功" : "添加成功!",
});
getTableData();
}
initForm()
dialogFormVisible.value = false
initForm();
dialogFormVisible.value = false;
}
})
}
});
};
const menuOption = ref([
{
ID: '0',
title: '根菜单'
}
])
ID: "0",
title: "根菜单",
},
]);
const setOptions = () => {
menuOption.value = [
{
ID: '0',
title: '根目录'
}
]
setMenuOptions(tableData.value, menuOption.value, false)
}
ID: 0,
title: "根目录",
},
];
setMenuOptions(tableData.value, menuOption.value, false);
};
const setMenuOptions = (menuData, optionsData, disabled) => {
menuData &&
menuData.forEach(item => {
if (item.children && item.children.length) {
const option = {
title: item.meta.title,
ID: String(item.ID),
disabled: disabled || item.ID === form.value.ID,
children: []
}
setMenuOptions(
item.children,
option.children,
disabled || item.ID === form.value.ID
)
optionsData.push(option)
} else {
const option = {
title: item.meta.title,
ID: String(item.ID),
disabled: disabled || item.ID === form.value.ID
}
optionsData.push(option)
}
})
}
menuData.forEach((item) => {
if (item.children && item.children.length) {
const option = {
title: item.meta.title,
ID: item.ID,
disabled: disabled || item.ID === form.value.ID,
children: [],
};
setMenuOptions(
item.children,
option.children,
disabled || item.ID === form.value.ID
);
optionsData.push(option);
} else {
const option = {
title: item.meta.title,
ID: item.ID,
disabled: disabled || item.ID === form.value.ID,
};
optionsData.push(option);
}
});
};
// 添加菜单方法id为 0则为添加根菜单
const isEdit = ref(false)
const dialogTitle = ref('新增菜单')
const isEdit = ref(false);
const dialogTitle = ref("新增菜单");
const addMenu = (id) => {
dialogTitle.value = '新增菜单'
form.value.parentId = String(id)
isEdit.value = false
setOptions()
dialogFormVisible.value = true
}
dialogTitle.value = "新增菜单";
form.value.parentId = id;
isEdit.value = false;
setOptions();
dialogFormVisible.value = true;
};
// 修改菜单方法
const editMenu = async(id) => {
dialogTitle.value = '编辑菜单'
const res = await getBaseMenuById({ id })
form.value = res.data.menu
isEdit.value = true
setOptions()
dialogFormVisible.value = true
}
const editMenu = async (id) => {
dialogTitle.value = "编辑菜单";
const res = await getBaseMenuById({ id });
form.value = res.data.menu;
isEdit.value = true;
setOptions();
dialogFormVisible.value = true;
};
</script>
<style scoped lang="scss">
.warning {
color: #dc143c;
}
.icon-column{
.icon-column {
display: flex;
align-items: center;
.el-icon{
.el-icon {
margin-right: 8px;
}
}