数字督察一体化平台-前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

370 lines
12 KiB

<template>
<div class="container">
<header class="flex between mb-20">
<div>
<el-button type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增</el-button
>
</div>
<div></div>
</header>
<div class="table-container">
<el-table :data="menus" row-key="id">
<el-table-column label="菜单名称" prop="menuName" />
<el-table-column label="类型">
<template #default="{ row }">
<div
class="flex v-center gap-4"
v-if="row.menuType === MenuEnum.CATALOGUE"
>
<icon name="el-icon-Folder" />
<span>目录</span>
</div>
<div
class="flex v-center gap-4"
v-else-if="row.menuType === MenuEnum.MENU"
>
<icon name="local-icon-menu" />
<span>菜单</span>
</div>
<div
class="flex v-center gap-4"
v-else-if="row.menuType === MenuEnum.BUTTON"
>
<icon name="el-icon-SwitchButton" />
<span>按钮</span>
</div>
</template>
</el-table-column>
<el-table-column label="图标">
<template #default="{ row }">
<icon :name="row.icon" :size="16" v-if="row.icon" />
</template>
</el-table-column>
<el-table-column label="权限标识" prop="perms" />
<el-table-column label="排序" prop="menuSort" />
<el-table-column label="最后更新时间" prop="updateTime" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)"
>编辑</el-button
>
<el-button type="danger" link @click="handleDelete(row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog
v-model="show"
:title="mode === 'add' ? '新增菜单' : '编辑菜单'"
width="600"
>
<el-form label-width="120" ref="formRef" :model="formData">
<el-form-item
label="菜单类型"
prop="menuType"
:rules="{
required: true,
message: '请选择菜单类型',
trigger: ['blur'],
}"
>
<el-radio-group v-model="formData.menuType">
<el-radio :label="MenuEnum.CATALOGUE">目录</el-radio>
<el-radio :label="MenuEnum.MENU">菜单</el-radio>
<el-radio :label="MenuEnum.BUTTON">按钮</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
label="父级菜单"
prop="menuType"
:rules="{
required: true,
message: '请选择父级菜单',
trigger: ['blur'],
}"
>
<el-tree-select
class="flex-1"
v-model="formData.pid"
:data="menuOptions"
clearable
node-key="id"
:props="{
label: 'menuName',
}"
:default-expanded-keys="[MENU_ROOT_ID]"
placeholder="请选择父级菜单"
check-strictly
/>
</el-form-item>
<el-form-item
label="菜单名称"
prop="menuName"
:rules="{
required: true,
message: '请输入菜单名称',
trigger: ['blur'],
}"
>
<el-input
v-model="formData.menuName"
placeholder="请输入菜单名称"
clearable
/>
</el-form-item>
<el-form-item
label="菜单图标"
v-if="formData.menuType === MenuEnum.CATALOGUE"
:rules="{
required: true,
message: '请选择图标',
}"
prop="icon"
>
<icon-picker class="flex-1" v-model="formData.icon" />
</el-form-item>
<el-form-item
label="菜单路径"
v-if="formData.menuType === MenuEnum.MENU"
:rules="{
required: true,
message: '请输入菜单路径',
trigger: ['blur'],
}"
>
<el-input
v-model="formData.paths"
placeholder="请输入路由路径"
clearable
/>
</el-form-item>
<el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="组件路径"
prop="component"
>
<div class="flex-1">
<el-autocomplete
class="w-full"
v-model="formData.component"
:fetch-suggestions="querySearch"
clearable
placeholder="请输入组件路径"
/>
<!-- <el-input v-model="formData.component" placeholder="请输入组件路径" /> -->
<div class="form-tips">
访问的组件路径,如:`permission/admin/index`,默认在`views`目录下
</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType != MenuEnum.CATALOGUE"
label="权限字符"
prop="perms"
>
<div class="flex-1">
<el-input
v-model="formData.perms"
placeholder="请输入权限字符"
clearable
/>
<div class="form-tips">
将作为server端API验权使用,如`system:admin:list`,请谨慎修改
</div>
</div>
</el-form-item>
<!-- <el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="路由参数"
prop="params"
>
<div>
<div class="flex-1">
<el-input
v-model="formData.params"
placeholder="请输入路由参数"
clearable
/>
</div>
<div class="form-tips">
访问路由的默认传递参数,如:`{"id": 1, "name":
"admin"}`或`id=1&name=admin`
</div>
</div>
</el-form-item> -->
<el-form-item
v-if="formData.menuType === MenuEnum.MENU"
label="打开新页面"
prop="openNewPage"
:rules="{
required: true,
message: '请选择是否打开新页面',
trigger: ['blur'],
}"
>
<el-radio-group v-model="formData.openNewPage">
<el-radio :value="false">否</el-radio>
<el-radio :value="true">是</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="是否缓存"
prop="isCache"
required
>
<div>
<el-radio-group v-model="formData.isCache">
<el-radio :label="1">缓存</el-radio>
<el-radio :label="0">不缓存</el-radio>
</el-radio-group>
<div class="form-tips">选择缓存则会被`keep-alive`缓存</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType != MenuEnum.BUTTON"
label="是否显示"
prop="isShow"
:rules="{
required: true,
message: '请选择是否显示',
trigger: ['blur'],
}"
>
<div>
<el-radio-group v-model="formData.isShow">
<el-radio :label="1">显示</el-radio>
<el-radio :label="0">隐藏</el-radio>
</el-radio-group>
<div class="form-tips">
选择隐藏则路由将不会出现在侧边栏但仍然可以访问
</div>
</div>
</el-form-item>
<el-form-item label="菜单排序" prop="menuSort">
<div>
<el-input-number v-model="formData.menuSort" :max="9999" />
<div class="form-tips">数值越小越排前</div>
</div>
</el-form-item>
</el-form>
<footer class="flex end">
<el-button @click="show = false">取消</el-button>
<el-button type="primary" @click="submit" :disabled="disabled"
>确定</el-button
>
</footer>
</el-dialog>
</template>
<script lang="ts" setup>
import { MenuEnum, MENU_ROOT_ID } from "@/enums/appEnums";
import { listMenu, addMenu, updateMenu, delMenu } from "@/api/system/menu";
import feedback from "@/utils/feedback";
import { watch } from "vue";
const menus = ref([]);
const menuOptions = ref([
{
id: MENU_ROOT_ID,
menuName: "顶级",
children: [],
},
]);
function getList() {
listMenu().then((data) => {
menus.value = data;
if (!menuOptions.value[0].children.length) {
menuOptions.value[0].children = data;
}
});
}
getList();
const show = ref(false);
const formData = ref({
openNewPage: false,
isShow: 1,
isCache: 1,
});
const formRef = ref();
const querySearch = (queryString, cb) => {
const results = queryString
? menus.value.filter((item) =>
item.menuName.toLowerCase().includes(queryString.toLowerCase())
)
: [];
cb(results.map((item) => ({ value: item })));
};
const mode = ref<string>("add");
watch(mode, (val) => {
if (val === "add") {
initFormData();
}
});
function initFormData() {
formData.value = {
openNewPage: false,
isShow: 1,
isCache: 1,
};
}
function handleAdd() {
show.value = true;
mode.value = "add";
}
const disabled = ref(false);
async function submit() {
await formRef.value.validate();
disabled.value = true;
try {
if (mode.value === "add") {
await addMenu(formData.value);
initFormData();
} else {
await updateMenu(formData.value);
}
} catch(e) {
console.error(e)
disabled.value = false;
return
}
disabled.value = false;
show.value = false;
getList();
feedback.msgSuccess('操作成功')
}
function handleEdit(row) {
show.value = true;
mode.value = "edit";
formData.value = { ...row };
}
const handleDelete = async (row) => {
await feedback.confirm(`确定要删除 ${row.menuName}`);
await delMenu(row.id);
feedback.msgSuccess("删除成功");
getList();
};
</script>
<style lang="scss" scoped>
.form-tips {
font-size: 12px;
line-height: 1.2;
color: #666;
}
</style>