<template>
|
<ProDialog
|
class="custom-dialog"
|
width="55%"
|
:title="dialogTitle"
|
v-model="visible"
|
:top="'10vh'"
|
:close-on-click-modal="false"
|
:close-on-press-escape="false"
|
>
|
<div class="authorize-wrapper">
|
<div class="container-wrapper left-wrapper">
|
<el-scrollbar>
|
<el-tree
|
class="companyTree"
|
:data="menusTree"
|
:props="{
|
children: 'children',
|
label: 'name',
|
}"
|
node-key="id"
|
:expand-on-click-node="false"
|
:highlight-current="true"
|
default-expand-all
|
show-checkbox
|
ref="moduleTree"
|
:default-checked-keys="checkedModules"
|
>
|
<template #default="{ node }">
|
<div class="custom-tree-node">
|
<type-tip :isMenu="node.data.type === EnumMenuType.Menu" />
|
<div class="node-text" @click="handleSelectModule(node.data)">
|
{{ node.label }}
|
</div>
|
</div>
|
</template>
|
</el-tree>
|
</el-scrollbar>
|
</div>
|
|
<div class="container-wrapper">
|
<div class="type-wrapper">
|
{{ SubModuleTitle[SubModuleType.PageButton] }}
|
</div>
|
<el-scrollbar>
|
<el-tree
|
v-show="!!state.currentMenuId"
|
:data="[
|
{
|
name: '全选',
|
id: 'pageButtonAll',
|
children: menuPageButtons,
|
},
|
]"
|
:props="{
|
children: 'children',
|
label: 'name',
|
}"
|
node-key="id"
|
:expand-on-click-node="false"
|
:highlight-current="true"
|
default-expand-all
|
show-checkbox
|
ref="pageButtonTree"
|
:default-checked-keys="checkedPageButton"
|
>
|
<template #default="{ node }">
|
<div class="custom-tree-node">
|
<span>{{ node.label }}</span>
|
</div>
|
</template>
|
</el-tree>
|
</el-scrollbar>
|
</div>
|
|
<div class="container-wrapper">
|
<div class="type-wrapper">
|
{{ SubModuleTitle[SubModuleType.DataButton] }}
|
</div>
|
<el-scrollbar>
|
<el-tree
|
v-show="!!state.currentMenuId"
|
:data="[
|
{
|
name: '全选',
|
id: 'dataButtonAll',
|
children: menuDataButtons,
|
},
|
]"
|
:props="{
|
children: 'children',
|
label: 'name',
|
}"
|
node-key="id"
|
:expand-on-click-node="false"
|
:highlight-current="true"
|
default-expand-all
|
show-checkbox
|
ref="dataButtonTree"
|
:default-checked-keys="checkedDataButton"
|
>
|
<template #default="{ node }">
|
<div class="custom-tree-node">
|
<span>{{ node.label }}</span>
|
</div>
|
</template>
|
</el-tree>
|
</el-scrollbar>
|
</div>
|
|
<div class="container-wrapper">
|
<div class="type-wrapper">
|
{{ SubModuleTitle[SubModuleType.Column] }}
|
</div>
|
<el-scrollbar>
|
<el-tree
|
v-show="!!state.currentMenuId"
|
:data="[
|
{
|
name: '全选',
|
id: 'dataColumnAll',
|
children: menuFields,
|
},
|
]"
|
:props="{
|
children: 'children',
|
label: 'name',
|
}"
|
node-key="id"
|
:expand-on-click-node="false"
|
:highlight-current="true"
|
default-expand-all
|
show-checkbox
|
ref="dataColumnTree"
|
:default-checked-keys="checkedDataColumn"
|
>
|
<template #default="{ node }">
|
<div class="custom-tree-node">
|
<span>{{ node.label }}</span>
|
</div>
|
</template>
|
</el-tree>
|
</el-scrollbar>
|
</div>
|
</div>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="visible = false">取消</el-button>
|
<el-button type="primary" @click="handleConfirm" class="btn-submit"> 确定 </el-button>
|
</span>
|
</template>
|
</ProDialog>
|
</template>
|
|
<script setup lang="ts">
|
import { Message } from '@bole-core/core';
|
import { AuthorizeType, SubModuleType, SubModuleTitle, EnumMenuType } from '@/constants';
|
import { getTree } from '@/utils';
|
import { TreeInstance } from 'element-plus';
|
import { ProDialog } from '@bole-core/components';
|
import { useMenus, useMenu } from '@/hooks';
|
|
const TypeTip = defineComponent({
|
name: 'TypeTip',
|
props: ['isMenu'],
|
render() {
|
const { isMenu } = this;
|
const tipText = isMenu ? `菜单` : '页面';
|
return h(
|
'span',
|
{
|
class: 'tip-text',
|
style: {
|
color: '#EB6100',
|
},
|
},
|
'[' + tipText + ']'
|
);
|
},
|
});
|
|
type Props = {
|
authorizeType: 'Role' | 'User';
|
};
|
|
const props = withDefaults(defineProps<Props>(), {});
|
|
const visible = defineModel({ type: Boolean });
|
|
type Form = {
|
title?: string;
|
detail: API.GetRoleQueryResult;
|
};
|
|
const form = defineModel<Form>('form');
|
|
const emit = defineEmits<{
|
(e: 'onConfirm', selectedMenuIds: string[], resourceIds: string[]): void;
|
(e: 'onCancel'): void;
|
}>();
|
|
type CheckedResourceItem = {
|
resourceId: string;
|
menuId: string;
|
resourceType: SubModuleType;
|
};
|
|
const state = reactive({
|
currentMenuId: '',
|
checkedInfo: [] as CheckedResourceItem[],
|
});
|
|
watch(visible, (newVal) => {
|
if (newVal) {
|
state.currentMenuId = '';
|
state.checkedInfo = [];
|
}
|
});
|
|
const dialogTitle = computed(() =>
|
props.authorizeType === 'Role' ? '角色功能授权' : '账号功能授权'
|
);
|
|
const moduleTree = useTemplateRef<TreeInstance>('moduleTree');
|
const pageButtonTree = useTemplateRef<TreeInstance>('pageButtonTree');
|
const dataButtonTree = useTemplateRef<TreeInstance>('dataButtonTree');
|
const dataColumnTree = useTemplateRef<TreeInstance>('dataColumnTree');
|
|
const { menusTree, getMenuById } = useMenus({
|
params: computed(() => ({
|
userType: form.value.detail?.userType,
|
clientType: form.value.detail?.clientType,
|
roleId: form.value.detail?.id,
|
})),
|
enabled: computed(() => !!form.value.detail?.id),
|
});
|
|
const { menuFields, menuPageButtons, menuDataButtons } = useMenu({
|
params: computed(() => ({
|
id: state.currentMenuId,
|
roleId: form.value.detail?.id,
|
})),
|
enabled: computed(() => !!state.currentMenuId),
|
});
|
|
const checkedModules = computed(() => {
|
if (form.value.detail) {
|
return form.value.detail.menuIds;
|
}
|
return [];
|
});
|
|
const checkedPageButton = computed(() => initChecked(SubModuleType.PageButton));
|
const checkedDataButton = computed(() => initChecked(SubModuleType.DataButton));
|
const checkedDataColumn = computed(() => initChecked(SubModuleType.Column));
|
|
function initChecked(type: SubModuleType) {
|
return state.checkedInfo.filter((x) => x.resourceType === type).map((x) => x.resourceId);
|
}
|
|
function handleSelectModule(menu: API.GetMenusQueryResultItem) {
|
const modules1 =
|
dataButtonTree &&
|
dataButtonTree.value.getCheckedKeys(true).map((x) => {
|
return {
|
resourceType: SubModuleType.DataButton,
|
resourceId: x,
|
menuId: menu.id,
|
} as CheckedResourceItem;
|
});
|
|
const modules2 =
|
pageButtonTree &&
|
pageButtonTree.value.getCheckedKeys(true).map((x) => {
|
return {
|
resourceType: SubModuleType.PageButton,
|
resourceId: x,
|
menuId: menu.id,
|
} as CheckedResourceItem;
|
});
|
|
const modules3 =
|
dataColumnTree &&
|
dataColumnTree.value.getCheckedKeys(true).map((x) => {
|
return {
|
resourceType: SubModuleType.Column,
|
resourceId: x,
|
menuId: menu.id,
|
} as CheckedResourceItem;
|
});
|
|
const checkExtends = state.checkedInfo.filter(
|
(x) => x.menuId !== menu.id && x.menuId !== undefined
|
);
|
|
if (modules1 && modules1.length) {
|
checkExtends.push(...modules1);
|
}
|
if (modules2 && modules2.length) {
|
checkExtends.push(...modules2);
|
}
|
if (modules3 && modules3.length) {
|
checkExtends.push(...modules3);
|
}
|
|
state.checkedInfo = checkExtends;
|
state.currentMenuId = menu.id;
|
}
|
|
function handleConfirm() {
|
const selectedMenuIds = moduleTree.value.getCheckedNodes(false, true).map((x) => x.id);
|
if (state.currentMenuId) {
|
handleSelectModule(getMenuById(state.currentMenuId));
|
}
|
const resourceIds = state.checkedInfo.map((x) => x.resourceId);
|
emit('onConfirm', selectedMenuIds, resourceIds);
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
:deep(.custom-dialog) {
|
min-width: 900px;
|
}
|
|
.authorize-wrapper {
|
display: flex;
|
|
height: 500px;
|
border-bottom: 2px solid #f5f5f5;
|
background: #dddddd;
|
|
.container-wrapper {
|
width: calc(25%);
|
border-right: 2px solid #f5f5f5;
|
// margin-right: 7px;
|
background: #ffffff;
|
|
.type-wrapper {
|
display: flex;
|
justify-content: flex-start;
|
align-items: center;
|
padding: 10px 16px;
|
border-bottom: 2px solid #f5f5f5;
|
color: #333333;
|
}
|
|
&:last-of-type {
|
margin-right: 0px;
|
}
|
|
&.left-wrapper {
|
margin-right: 7px;
|
padding-top: 10px;
|
width: calc(35% - 7px);
|
|
:deep(.el-scrollbar) {
|
width: 100%;
|
height: 98%;
|
}
|
}
|
|
:deep(.el-scrollbar) {
|
width: 100%;
|
height: calc(98% - 43px);
|
|
.el-scrollbar__wrap {
|
overflow: auto;
|
|
.custom-tree-node {
|
display: flex;
|
}
|
}
|
}
|
}
|
}
|
</style>
|