<template>
|
<LoadingLayout :loading="state.loading">
|
<AppContainer>
|
<ProTableQueryFilterBar @on-reset="handleReset">
|
<template #query>
|
<div class="query-filter-list-item">
|
<SearchInput
|
v-model="state.searchValue"
|
placeholder="菜单名称"
|
@on-click-search="handleSearch"
|
@keyup.enter="handleSearch()"
|
>
|
</SearchInput>
|
</div>
|
</template>
|
<template #btn>
|
<el-button @click="handleAddOrEditRootModule()" icon="Plus" type="primary"
|
>新增</el-button
|
>
|
<el-button @click="toggleExpand(true)" icon="FolderOpened" type="primary"
|
>全部展开</el-button
|
>
|
<el-button @click="toggleExpand(false)" icon="Folder" type="primary">全部折叠</el-button>
|
</template>
|
</ProTableQueryFilterBar>
|
<ProTableV2
|
:tableData="moduleTreeStore.data"
|
:table-props="{
|
rowKey: 'id',
|
}"
|
:tableRef="(r) => (tableRef = r)"
|
:show-seq-column="false"
|
:columns="ModuleColumns"
|
:operationBtns="ModuleOperationBtns"
|
:operationColumnWidth="300"
|
>
|
<template #columns="{ row, column }">
|
<template v-if="column.property === 'isCache'">
|
<el-switch
|
v-show="!ModuleUtils.isRootModule(row)"
|
v-model="row.isCache"
|
inline-prompt
|
@change="(v: boolean) => handleChangeStatus(v, row, 'isCache')"
|
></el-switch>
|
</template>
|
<template v-else-if="column.property === 'isMenu'">
|
<el-switch
|
:modelValue="row.type === EnumMenuType.Menu"
|
:onUpdate:modelValue="(v: boolean) =>{
|
row.type=v?EnumMenuType.Menu:EnumMenuType.Page
|
}"
|
inline-prompt
|
@change="(v: number) => handleChangeStatus(v, row, 'isMenu')"
|
></el-switch>
|
</template>
|
<template v-else-if="column.property === 'enabledMark'">
|
<el-switch
|
:modelValue="!row.isDisabled"
|
:onUpdate:modelValue="(v: boolean) => row.isDisabled =!v"
|
@change="(v: number) => handleChangeStatus(v, row, 'enabledMark')"
|
></el-switch>
|
</template>
|
</template>
|
</ProTableV2>
|
<AddOrEditModuleDialog
|
v-model="editDialogFormVisible"
|
v-model:form="editForm"
|
:moduleTreeStore="moduleTreeStore"
|
:currentAddingOrEditParentModule="currentAddingOrEditParentModule"
|
@on-confirm="handleAddOrEditModule"
|
@on-cancel="editDialogFormVisible = false"
|
/>
|
<SubModuleEditDrawer
|
v-model="drawerVisible"
|
:title="SubModuleTitle[drawerState.type]"
|
v-model:data="drawerState.tableData"
|
:type="drawerState.type"
|
@on-add-sub-module="handleAddSubModule"
|
@on-batch-add-column="handleBatchAddColumn"
|
@on-save-sub-module="handleSaveSubModule"
|
@on-delete-sub-module="handleDeleteSubModule"
|
@on-add-fast-btn="handleAddFastBtn"
|
@on-batch-save-column="handelBatchSaveColumn"
|
/>
|
</AppContainer>
|
</LoadingLayout>
|
</template>
|
|
<script setup lang="ts">
|
import {
|
ProTableQueryFilterBar,
|
ProTableV2,
|
AppContainer,
|
LoadingLayout,
|
OperationBtnType,
|
SearchInput,
|
} from '@bole-core/components';
|
import { ModuleUtils, TreeModuleDtoGroupDto, Message, TreeStore, flattenTree } from '@/utils';
|
import { TableInstance } from 'element-plus';
|
import {
|
SubModuleType,
|
SubModuleTitle,
|
SubModuleKey,
|
FastBtn,
|
ModuleColumns,
|
EnumMenuType,
|
} from '@/constants';
|
import SubModuleEditDrawer from './components/SubModuleEditDrawer.vue';
|
import AddOrEditModuleDialog from './components/AddOrEditModuleDialog.vue';
|
import { useDebounceFn } from '@vueuse/core';
|
import _ from 'lodash';
|
import { useReset } from '@bole-core/core';
|
import * as menuServices from '@/services/api/menu';
|
import { DrawerTableDataItem } from './types';
|
|
defineOptions({
|
name: 'ModuleManage',
|
});
|
|
const ModuleOperationBtns: OperationBtnType[] = [
|
{
|
data: {
|
name: '编辑',
|
},
|
emits: {
|
onClick: (row) => {
|
ModuleUtils.isRootModule(row) ? handleAddOrEditRootModule(row) : handleEditChildModule(row);
|
},
|
},
|
},
|
{
|
data: {
|
name: '新增子菜单',
|
},
|
emits: {
|
onClick: (row) => handleAddChildModule(row),
|
},
|
},
|
{
|
data: {
|
name: '页面按钮',
|
},
|
emits: {
|
onClick: (row) => openDrawer(row, SubModuleType.PageButton),
|
},
|
extraProps: {
|
hide: (row) => ModuleUtils.isRootModule(row),
|
},
|
},
|
{
|
data: {
|
name: '数据按钮',
|
},
|
emits: {
|
onClick: (row) => openDrawer(row, SubModuleType.DataButton),
|
},
|
extraProps: {
|
hide: (row) => ModuleUtils.isRootModule(row),
|
},
|
},
|
{
|
data: {
|
name: '数据列',
|
},
|
emits: {
|
onClick: (row) => openDrawer(row, SubModuleType.Column),
|
},
|
extraProps: {
|
hide: (row) => ModuleUtils.isRootModule(row),
|
},
|
},
|
{
|
data: {
|
name: '删除',
|
},
|
emits: {
|
onClick: (row) => handleDelete(row),
|
},
|
props: { type: 'danger' },
|
},
|
];
|
const BaseState = {
|
loading: true,
|
searchValue: '',
|
group: 'default',
|
};
|
const state = reactive({ ...BaseState });
|
const moduleTreeStore = ref<TreeStore<TreeModuleDtoGroupDto>>();
|
// 源数据
|
const originModuleTree = ref<TreeModuleDtoGroupDto[]>([]);
|
const tableRef = ref<TableInstance>();
|
// form
|
const editDialogFormVisible = ref(false);
|
const BaseFormData = {
|
enCode: '',
|
name: '',
|
icon: '',
|
parentId: '',
|
sortCode: 0,
|
path: '',
|
isCache: true,
|
isMenu: true,
|
enabledMark: true,
|
showCacheSelect: false,
|
showIconSelect: false,
|
showSubMenuIconSelect: false,
|
showParentSelect: false,
|
title: '',
|
};
|
const editForm = reactive({ ...BaseFormData });
|
const currentDialogModule = ref<API.GetMenuQueryResult>({});
|
//drawer
|
const drawerVisible = ref(false);
|
const currentDrawerModule = ref<API.GetMenuQueryResult>({});
|
|
const drawerState = reactive<{
|
type: SubModuleType;
|
tableData: DrawerTableDataItem[];
|
}>({
|
type: SubModuleType.PageButton,
|
tableData: [],
|
});
|
onMounted(async () => {
|
await getAllModule();
|
state.loading = false;
|
});
|
async function getAllModule() {
|
try {
|
let res = await menuServices.getMenus(
|
{
|
userType: EnumUserType.Operation,
|
clientType: EnumClientType.PcWeb,
|
},
|
{
|
showLoading: false,
|
}
|
);
|
const treeStore = ModuleUtils.convertToModuleGroup(flattenTree(res));
|
moduleTreeStore.value = treeStore;
|
originModuleTree.value = [...treeStore.data];
|
} catch (error) {}
|
}
|
type StatusEventType = {
|
isCache: boolean;
|
isMenu: number;
|
enabledMark: number;
|
};
|
async function handleChangeStatus<T extends keyof StatusEventType>(
|
value: StatusEventType[T],
|
data: TreeModuleDtoGroupDto,
|
statusType: T
|
) {
|
try {
|
// let params = {
|
// ..._.omit(data, ['children', 'parentNode']),
|
// [statusType]: value,
|
// };
|
// await baseModuleServices.addOrEditModule(params);
|
} catch (error) {
|
Message.errorMessage('操作失败');
|
}
|
}
|
|
async function getMenu(id: string) {
|
return await menuServices.getMenu({ id: id });
|
}
|
|
async function openDialog(options: {
|
module?: TreeModuleDtoGroupDto;
|
showCacheSelect: boolean;
|
showIconSelect: boolean;
|
showSubMenuIconSelect: boolean;
|
showParentSelect: boolean;
|
parentId: string;
|
baseSortCode?: number;
|
}) {
|
try {
|
const {
|
module,
|
showCacheSelect,
|
showIconSelect,
|
showSubMenuIconSelect,
|
showParentSelect,
|
parentId,
|
baseSortCode,
|
} = options;
|
if (module) {
|
currentDialogModule.value = await getMenu(module.id);
|
useSetReactive(editForm, {
|
title: `${module.name}编辑`,
|
enCode: module.code,
|
name: module.name,
|
icon: module.icon,
|
sortCode: module.sort,
|
path: module.url,
|
isMenu: module.type == EnumMenuType.Menu,
|
enabledMark: !module.isDisabled,
|
parentId: parentId,
|
showCacheSelect,
|
showIconSelect,
|
showSubMenuIconSelect,
|
showParentSelect,
|
isCache: module.isCache,
|
});
|
} else {
|
currentDialogModule.value = {};
|
useSetReactive(editForm, BaseFormData, {
|
title: '新增功能模块',
|
parentId: parentId,
|
showCacheSelect,
|
showIconSelect,
|
showSubMenuIconSelect,
|
showParentSelect,
|
sortCode: baseSortCode,
|
});
|
}
|
editDialogFormVisible.value = true;
|
} catch (error) {}
|
}
|
function handleAddOrEditRootModule(module?: TreeModuleDtoGroupDto) {
|
const showCacheSelect = false;
|
const showIconSelect = true;
|
const showSubMenuIconSelect = false;
|
const showParentSelect = false;
|
const parentId = '';
|
openDialog({
|
module,
|
showCacheSelect,
|
showIconSelect,
|
showSubMenuIconSelect,
|
showParentSelect,
|
parentId,
|
baseSortCode: ModuleUtils.getSortCode(moduleTreeStore.value, module) + 1,
|
});
|
}
|
//当前正在新增子菜单的module或正在编辑的子菜单的父级菜单
|
const currentAddingOrEditParentModule = ref<TreeModuleDtoGroupDto>({});
|
function handleAddChildModule(parentModule: TreeModuleDtoGroupDto) {
|
handleAddOrEditChildModule(parentModule);
|
}
|
function handleEditChildModule(module: TreeModuleDtoGroupDto) {
|
const parentModule = ModuleUtils.getParentModule(moduleTreeStore.value, module);
|
handleAddOrEditChildModule(parentModule, module);
|
}
|
function handleAddOrEditChildModule(
|
parentModule: TreeModuleDtoGroupDto,
|
module?: TreeModuleDtoGroupDto
|
) {
|
const showCacheSelect = true;
|
const showIconSelect = false;
|
const showParentSelect = true;
|
const parentId = parentModule.id;
|
currentAddingOrEditParentModule.value = parentModule;
|
//如果是编辑 SortCode为上一个加1
|
const baseSortCode = ModuleUtils.getLastChildSortCode(moduleTreeStore.value, parentModule) + 1;
|
openDialog({
|
module: module,
|
showCacheSelect,
|
showIconSelect,
|
showSubMenuIconSelect: true,
|
showParentSelect,
|
parentId,
|
baseSortCode,
|
});
|
}
|
async function handleAddOrEditModule() {
|
try {
|
let params: API.SaveMenuCommand = {
|
userType: EnumUserType.Operation,
|
clientType: EnumClientType.PcWeb,
|
code: editForm.enCode,
|
name: editForm.name,
|
type: editForm.isMenu ? EnumMenuType.Menu : EnumMenuType.Page,
|
visitLevel: EnumMenuVisitLevel.NeedPower,
|
icon: editForm.icon,
|
url: editForm.path,
|
isDisabled: !editForm.enabledMark,
|
sort: editForm.sortCode,
|
};
|
if (editForm.showCacheSelect) {
|
params.isCache = editForm.isCache;
|
}
|
if (editForm.parentId) {
|
params.parentId = editForm.parentId;
|
}
|
if (currentDialogModule.value.id) {
|
params.id = currentDialogModule.value.id;
|
params.groups = currentDialogModule.value.groups;
|
}
|
const res = await saveMenu(params);
|
if (res) {
|
Message.successMessage('保存成功');
|
getAllModule();
|
editDialogFormVisible.value = false;
|
}
|
} catch (e) {}
|
}
|
|
async function saveMenu(params: API.SaveMenuCommand) {
|
try {
|
const res = await menuServices.saveMenu(params);
|
return res;
|
} catch (error) {}
|
}
|
|
async function handleDelete(module: TreeModuleDtoGroupDto) {
|
try {
|
await Message.deleteMessage();
|
const res = await menuServices.deleteMenu({ ids: [module.id] });
|
if (res) {
|
Message.successMessage('删除成功');
|
getAllModule();
|
}
|
} catch (error) {}
|
}
|
async function openDrawer(module: TreeModuleDtoGroupDto, type: SubModuleType) {
|
try {
|
drawerState.type = type;
|
getBaseModuleGetAllSubModule(module, type);
|
} catch (error) {}
|
}
|
async function getBaseModuleGetAllSubModule(module: TreeModuleDtoGroupDto, type: SubModuleType) {
|
try {
|
const menu = await getMenu(module.id);
|
currentDrawerModule.value = menu;
|
const currentGroup = menu.groups.find((g) => g.group === state.group) ?? {};
|
if (type === SubModuleType.Column) {
|
drawerState.tableData = (currentGroup.fields ?? []).map((f) => ({
|
enCode: f.code,
|
name: f.name,
|
sortCode: f.sort,
|
width: f.width,
|
isEdit: false,
|
isShow: false,
|
id: f.id,
|
}));
|
} else {
|
drawerState.tableData = (
|
currentGroup.buttonLocations?.find((b) => b.location === SubModuleKey[type])?.buttons ?? []
|
).map((b) => ({
|
enCode: b.code,
|
name: b.name,
|
sortCode: b.sort,
|
width: b.width,
|
isEdit: false,
|
isShow: false,
|
id: b.id,
|
}));
|
}
|
drawerVisible.value = true;
|
} catch (error) {}
|
}
|
function handleAddSubModule() {
|
let sortCode = getDefaultSortCode();
|
let baseData = {
|
enCode: '',
|
name: '',
|
sortCode: sortCode,
|
width: 0 as any as string,
|
isEdit: true,
|
// apiName: '',
|
// realColumn: '',
|
isShow: true,
|
};
|
drawerState.tableData?.push(baseData);
|
}
|
function getDefaultSortCode() {
|
return drawerState.tableData.length > 0
|
? drawerState.tableData[drawerState.tableData.length - 1].sortCode + 1
|
: 0;
|
}
|
function handleBatchAddColumn(keys: string[]) {
|
let sortCode = getDefaultSortCode();
|
let baseDataList = keys.map((key, index) => ({
|
enCode: key,
|
name: '',
|
sortCode: sortCode + index,
|
width: 0 as any as string,
|
isEdit: true,
|
}));
|
drawerState.tableData?.push(...baseDataList);
|
}
|
function handleAddFastBtn(fastBtn: FastBtn) {
|
let subModule: DrawerTableDataItem = {
|
enCode: fastBtn.enCode,
|
name: fastBtn.name,
|
sortCode: getDefaultSortCode(),
|
};
|
if (drawerState.type === SubModuleType.Column) {
|
//@ts-ignore
|
subModule.width = fastBtn.width;
|
}
|
handleSaveSubModule(subModule);
|
}
|
async function handleSaveSubModule(subModule: DrawerTableDataItem) {
|
try {
|
let params: API.SaveMenuFieldCommand = {
|
parentId: currentDrawerModule.value.id,
|
code: subModule.enCode,
|
name: subModule.name,
|
group: state.group,
|
// location: 'string',
|
width: subModule.width,
|
sort: subModule.sortCode,
|
};
|
if (subModule.id) {
|
params.id = subModule.id;
|
}
|
if (drawerState.type === SubModuleType.Column) {
|
} else {
|
params.location = SubModuleKey[drawerState.type];
|
}
|
let res = null;
|
if (drawerState.type === SubModuleType.Column) {
|
res = await menuServices.saveMenuField(params);
|
} else {
|
res = await menuServices.saveMenuButton(params);
|
}
|
if (res) {
|
getBaseModuleGetAllSubModule(currentDrawerModule.value, drawerState.type);
|
Message.successMessage('保存成功');
|
}
|
} catch (error) {}
|
}
|
async function handelBatchSaveColumn() {
|
try {
|
if (drawerState.type === SubModuleType.Column) {
|
let columnModuleList = drawerState.tableData; //.filter((d) => d.isEdit);
|
if (columnModuleList.length > 0) {
|
const groups = currentDrawerModule.value.groups.map((group) => {
|
if (group.group === state.group) {
|
group.fields ==
|
columnModuleList.map((c) => ({
|
code: c.enCode,
|
name: c.name,
|
width: c.width,
|
sort: c.sortCode,
|
}));
|
}
|
return group;
|
});
|
let params: API.SaveMenuCommand = {
|
...currentDrawerModule.value,
|
groups: groups,
|
};
|
const res = await saveMenu(params);
|
if (res) {
|
getBaseModuleGetAllSubModule(currentDrawerModule.value, drawerState.type);
|
Message.successMessage('保存成功');
|
}
|
}
|
}
|
} catch (error) {}
|
}
|
|
async function handleDeleteSubModule(subModule: DrawerTableDataItem) {
|
try {
|
await Message.deleteMessage();
|
let res = await menuServices.deleteMenu({
|
ids: [subModule.id],
|
});
|
if (res) {
|
Message.successMessage('删除成功');
|
getBaseModuleGetAllSubModule(currentDrawerModule.value, drawerState.type);
|
}
|
} catch (error) {}
|
}
|
function toggleExpand(expanded: boolean) {
|
if (!tableRef.value) return;
|
moduleTreeStore.value.data.forEach((module) => {
|
tableRef.value?.toggleRowExpansion(module, expanded);
|
});
|
}
|
const handleSearch = useDebounceFn(() => {
|
if (state.searchValue) {
|
// @ts-ignore
|
moduleTreeStore.value.data = ModuleUtils.filterModuleTree(
|
state.searchValue,
|
originModuleTree.value
|
);
|
nextTick(() => {
|
toggleExpand(true);
|
});
|
} else {
|
moduleTreeStore.value.data = originModuleTree.value;
|
}
|
});
|
const handleReset = useReset(state, BaseState, getAllModule);
|
</script>
|