<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="defaultCheckedKeys"
|
@check="handleModuleCheck"
|
>
|
<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="defaultCheckedKeys"
|
@check="handlePageButtonCheck"
|
>
|
<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="defaultCheckedKeys"
|
@check="handleDataButtonCheck"
|
>
|
<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="defaultCheckedKeys"
|
@check="handleDataColumnCheck"
|
>
|
<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, treeEach } from '@/utils';
|
import { TreeInstance } from 'element-plus';
|
import { ProDialog } from '@bole-core/components';
|
import { useMenus, useMenu } from '@/hooks';
|
import data from '@iconify-icons/ep/tickets';
|
|
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[]): void;
|
(e: 'onCancel'): void;
|
}>();
|
|
type CheckedResourceItem = {
|
resourceId: string;
|
menuId: string;
|
resourceType: SubModuleType;
|
};
|
|
const state = reactive({
|
currentMenuId: '',
|
selectedMenuIds: [] as string[],
|
});
|
|
const defaultCheckedKeys = computed(() => Array.from(state.selectedMenuIds));
|
|
watch(visible, (newVal) => {
|
if (newVal) {
|
state.currentMenuId = '';
|
const menuIds = form.value.detail?.menuIds ?? [];
|
// menuIds.forEach((id) => state.selectedMenuIds.add(id));
|
state.selectedMenuIds = [...menuIds];
|
}
|
});
|
|
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');
|
|
type TreeRef = ReturnType<typeof useTemplateRef<TreeInstance>>;
|
|
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),
|
});
|
|
function handleSelectModule(menu: API.GetMenusQueryResultItem) {
|
state.currentMenuId = menu.id;
|
}
|
|
function handleModuleCheck(data, params) {
|
handleCheck(data, params, moduleTree);
|
}
|
|
function handlePageButtonCheck(data, params) {
|
handleCheck(data, params, pageButtonTree);
|
}
|
|
function handleDataButtonCheck(data, params) {
|
handleCheck(data, params, dataButtonTree);
|
}
|
|
function handleDataColumnCheck(data, params) {
|
handleCheck(data, params, dataColumnTree);
|
}
|
|
function handleCheck(data, params, treeRef: TreeRef) {
|
const dataMap = {};
|
treeEach(
|
[treeRef.value.store.root],
|
(node) => (dataMap[node.key] = node),
|
(node) => node.childNodes
|
);
|
|
const uncachedCheckedKeys = params.checkedKeys.filter(
|
(item) => !['pageButtonAll', 'dataButtonAll', 'dataColumnAll'].includes(item)
|
);
|
const cachedKeys = state.selectedMenuIds.filter(
|
(item) => !(item in dataMap) && !uncachedCheckedKeys.includes(item)
|
);
|
state.selectedMenuIds = cachedKeys.concat(uncachedCheckedKeys);
|
}
|
|
function handleConfirm() {
|
emit('onConfirm', state.selectedMenuIds);
|
}
|
</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>
|