<template>
|
<basicContainer>
|
<avue-crud
|
:option="option"
|
:table-loading="pageF.loading"
|
:data="tableData"
|
:page="page"
|
:permission="permissionList"
|
:before-open="beforeOpen"
|
v-model="form"
|
ref="crudRef"
|
@row-update="rowUpdate"
|
@row-save="rowSave"
|
@row-del="rowDel"
|
@search-change="searchChange"
|
@search-reset="searchReset"
|
@selection-change="selectionChange"
|
@current-change="currentChange"
|
@size-change="sizeChange"
|
@refresh-change="refreshChange"
|
@on-load="onLoad"
|
>
|
<template #menu-left>
|
<el-button
|
type="info"
|
plain
|
icon="Sort"
|
@click="toggleExpandAll"
|
>展开/折叠
|
</el-button>
|
</template>
|
<template #menu-before="scope">
|
<el-link
|
type="primary"
|
icon="Plus" :underline="false"
|
size="small" v-hasPermi="['system:menu:add']"
|
@click.stop="handleAdd(scope.row)"
|
><span style="margin-left: 5px">新 增</span>
|
</el-link>
|
</template>
|
<template #status="scope">
|
<dict-tag v-if="scope.dic" :options="scope.dic" :value="scope.row.status" />
|
</template>
|
<template #icon="scope">
|
<svg-icon :icon-class="scope.row.icon"/>
|
</template>
|
<template #icon-form>
|
<el-popover
|
placement="bottom-start"
|
:width="460"
|
trigger="click"
|
@show="showSelectIcon"
|
>
|
<template #reference>
|
<el-input v-model="form.icon" placeholder="点击选择图标" @click="showSelectIcon" readonly>
|
<template #prefix>
|
<svg-icon
|
v-if="form.icon"
|
:icon-class="form.icon"
|
class="el-input__icon"
|
style="height: 32px;width: 16px;"
|
/>
|
<el-icon v-else style="height: 32px;width: 16px;">
|
<search/>
|
</el-icon>
|
</template>
|
</el-input>
|
</template>
|
<icon-select ref="iconSelectRef" @selected="selected"/>
|
</el-popover>
|
</template>
|
</avue-crud>
|
</basicContainer>
|
</template>
|
|
<script setup name="menu" lang="ts">
|
import {MenuI, addMenu, delMenu, exportMenu, getMenu, listMenu, updateMenu} from "@/api/system/menu";
|
import useCurrentInstance from "@/utils/useCurrentInstance";
|
import {computed, reactive, ref, toRefs} from "vue";
|
import {PagesInterface, PageQueryInterface} from "@/utils/globalInterface";
|
import {usePagePlus} from "@/hooks/usePagePlus";
|
import {hasPermission} from "@/utils/permissionUtils";
|
import SvgIcon from "@/components/SvgIcon/index.vue";
|
import IconSelect from "@/components/IconSelect/index.vue";
|
|
|
const {proxy} = useCurrentInstance();
|
const crudRef = ref();
|
|
const permissionList = computed(() => {
|
return {
|
addBtn: hasPermission(["system:menu:add"]),
|
delBtn: hasPermission(["system:menu:remove"]),
|
editBtn: hasPermission(["system:menu:edit"]),
|
viewBtn: hasPermission(["system:menu:query"]),
|
}
|
})
|
|
const data = reactive({
|
form: <MenuI>{},
|
queryParams: <MenuI & PageQueryInterface>{},
|
page: <PagesInterface>{
|
pageSize: 10,
|
total: 0,
|
currentPage: 1,
|
},
|
selectionList: [],
|
rowAdd: false,
|
})
|
const {queryParams, form, page, selectionList, rowAdd} = toRefs(data);
|
|
|
|
const option = ref({
|
pageKey: 'menu',
|
rowKey: 'menuId',
|
rowParentKey: 'parentId',
|
tree: true,
|
selection: false,
|
defaultExpandAll: false,
|
viewBtn: false,
|
column: {
|
|
parentId: {
|
label: '上级菜单', value: 0, hide: true, type: 'tree', row: true,
|
addDisabled: false,
|
dicData: [],
|
rules: [
|
{required: true, message: "上级菜单不能为空", trigger: "blur"}
|
],
|
props: {
|
label: "menuName",
|
value: "menuId"
|
},
|
},
|
menuType: {
|
label: '菜单类型', value: "M", hide: true, type: 'radio',
|
dicData: [
|
{dictLabel: '目录', dictValue: 'M',},
|
{dictLabel: '菜单', dictValue: 'C',},
|
{dictLabel: '按钮', dictValue: 'F',},
|
],
|
change: ({value}: { value: string }) => {
|
// 定义一个默认的显示状态对象
|
const defaultDisplayState = {
|
perms: false,
|
status: false,
|
isCache: false,
|
component: false,
|
icon: false,
|
};
|
|
// 初始化所有属性为默认的显示状态
|
const displayState = {...defaultDisplayState};
|
|
// 根据不同的 value 更新显示状态
|
if (value === 'M') {
|
Object.assign(displayState, {
|
status: true,
|
icon: true,
|
});
|
} else if (value === 'C') {
|
Object.assign(displayState, {
|
isCache: true,
|
status: true,
|
perms: true,
|
component: true,
|
icon: true,
|
});
|
} else if (value === 'F') {
|
Object.assign(displayState, {
|
perms: true,
|
component: true,
|
isCache: true,
|
});
|
}
|
|
// 更新 option.value.column 的显示状态
|
Object.keys(displayState).forEach((key: string) => {
|
//@ts-ignore
|
option.value.column[key].display = displayState[key];
|
});
|
}
|
|
},
|
menuName: {
|
label: '菜单名称', width: 180,search: true,
|
rules: [
|
{
|
required: true,
|
message: "菜单名称不能为空", trigger: "blur"
|
}
|
],
|
},
|
icon: {
|
label: '菜单图标', width: 80, display: true,
|
|
},
|
orderNum: {
|
label: '显示顺序', width: 80, type: 'number',
|
min: 0, value: 1,
|
rules: [
|
{required: true, message: "菜单顺序不能为空", trigger: "blur"}
|
]
|
},
|
|
isFrame: {
|
label: '是否外链', value: "1", hide: true, display: true,
|
type: 'radio',
|
tip: '选择是外链则路由地址需要以`http(s)://`开头',
|
dicData: [
|
{dictLabel: '是', dictValue: '0',},
|
{dictLabel: '否', dictValue: '1',},
|
],
|
},
|
path: {
|
label: '路由地址', hide: true, display: true,
|
tip: '访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头',
|
rules: [
|
{
|
required: true,
|
message: "路由地址不能为空", trigger: "blur"
|
}
|
],
|
},
|
|
query: {
|
label: '路由参数', hide: true, display: true,
|
tip: '访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`'
|
},
|
component: {
|
label: '组件路径', display: true,
|
tip: '访问的组件路径,如:`system/user/index`,默认在`views`目录下'
|
},
|
perms: {
|
label: '权限标识', display: true,
|
tip: '控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi(\'system:user:list\')`)'
|
},
|
|
isCache: {
|
label: '是否缓存', value: "0", hide: true, display: true,
|
type: 'radio',
|
tip: '选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致',
|
dicData: [
|
{dictLabel: '缓存', dictValue: '0',},
|
{dictLabel: '不缓存', dictValue: '1',},
|
],
|
},
|
|
visible: {
|
tip: '选择隐藏则路由将不会出现在侧边栏,但仍然可以访问',
|
label: '显示状态', value: "0", hide: true, display: true,
|
type: 'radio', dicUrl: '/system/dict/data/type/sys_show_hide',
|
|
},
|
status: {
|
tip: '选择停用则路由将不会出现在侧边栏,也不能被访问',
|
label: '菜单状态', value: "0", width: 80, display: true,search: true,
|
type: 'radio', dicUrl: '/system/dict/data/type/sys_normal_disable',
|
},
|
|
|
createTime: {
|
label: '创建时间', width: 180, addDisplay: false, editDisplay: false
|
},
|
|
}
|
})
|
|
const {
|
tableData, pageF, rowSave, rowUpdate, rowDel, beforeOpen, searchChange,
|
searchReset, selectionChange, onLoad, currentChange, sizeChange, handleDelete, handleExport, handleUpdate,refreshChange
|
} = usePagePlus({
|
form: form,
|
option:option,
|
queryParams: queryParams,
|
idKey: 'menuId',
|
page: page.value,
|
getListApi: listMenu,
|
getDetailApi: getMenu,
|
exportApi: exportMenu,
|
deleteApi: delMenu,
|
addApi: addMenu,
|
updateApi: updateMenu,
|
handleUpdateFunc: () => {
|
crudRef.value.rowEdit(selectionList.value[0]);
|
},
|
handleSelectionChangeFunc: (selection: any) => {
|
selectionList.value = selection;
|
},
|
getListFunc: (res: any) => {
|
tableData.value = proxy.handleTree(res.data, "menuId");
|
},
|
handleBeforeOpenFunc: () => {
|
listMenu().then(res => {
|
res.data.push({menuId: 0, menuName: '主类目'});
|
option.value.column.parentId.dicData = proxy.handleTree(res.data, "menuId");
|
})
|
}
|
})
|
|
|
/** 展开/折叠操作 */
|
function toggleExpandAll() {
|
option.value.defaultExpandAll = !option.value.defaultExpandAll;
|
crudRef.value.doLayout();
|
crudRef.value.refreshTable();
|
}
|
|
const handleAdd = (row: any) => {
|
option.value.column.parentId.value = row.menuId;
|
option.value.column.parentId.addDisabled = true;
|
form.value.parentId = row.menuId;
|
rowAdd.value = true;
|
crudRef.value.rowAdd();
|
}
|
|
const iconSelectRef = ref();
|
const showSelectIcon = ()=>{
|
iconSelectRef.value.reset();
|
}
|
const selected = (name: string )=>{
|
form.value.icon = name;
|
}
|
|
</script>
|