feat(20240629_role_menu): 优化权限配置

- 重构权限配置前端页面布局
This commit is contained in:
李小涛
2024-06-29 22:42:37 +08:00
parent e1d9f555c8
commit 798f9e8a7f
3 changed files with 364 additions and 753 deletions

View File

@@ -284,27 +284,21 @@ class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
RoleMenuPermission.objects.filter(role=pk).delete() RoleMenuPermission.objects.filter(role=pk).delete()
RoleMenuButtonPermission.objects.filter(role=pk).delete() RoleMenuButtonPermission.objects.filter(role=pk).delete()
for item in body: for item in body:
for menu in item["children"]: if item.get('isCheck'):
if menu.get('isCheck'): RoleMenuPermission.objects.create(role_id=pk, menu_id=item["id"])
menu_parent = Menu.get_all_parent(menu.get('id')) for btn in item.get('btns'):
role_menu_permission_list = [] if btn.get('isCheck'):
for d in menu_parent: data_range = btn.get('data_range', 0) or 0
role_menu_permission_list.append(RoleMenuPermission(role_id=pk, menu_id=d["id"])) instance = RoleMenuButtonPermission.objects.create(role_id=pk, menu_button_id=btn.get('id'),
RoleMenuPermission.objects.bulk_create(role_menu_permission_list) data_range=data_range)
# RoleMenuPermission.objects.create(role_id=pk, menu_id=menu.get('id')) instance.dept.set(btn.get('dept', []))
for btn in menu.get('btns'): for col in item.get('columns'):
if btn.get('isCheck'): FieldPermission.objects.update_or_create(role_id=pk, field_id=col.get('id'),
data_range = btn.get('data_range', 0) or 0 defaults={
instance = RoleMenuButtonPermission.objects.create(role_id=pk, menu_button_id=btn.get('id'), 'is_query': col.get('is_query'),
data_range=data_range) 'is_create': col.get('is_create'),
instance.dept.set(btn.get('dept', [])) 'is_update': col.get('is_update')
for col in menu.get('columns'): })
FieldPermission.objects.update_or_create(role_id=pk, field_id=col.get('id'),
defaults={
'is_query': col.get('is_query'),
'is_create': col.get('is_create'),
'is_update': col.get('is_update')
})
return DetailResponse(msg="授权成功") return DetailResponse(msg="授权成功")
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated]) @action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])

View File

@@ -1,420 +0,0 @@
<template>
<el-drawer v-model="drawerVisible" title="权限配置" direction="rtl" size="60%" :close-on-click-modal="false"
:before-close="handleDrawerClose" :destroy-on-close="true">
<template #header>
<el-row>
<el-col :span="4">
<div>当前授权角色
<el-tag>{{ props.roleName }}</el-tag>
</div>
</el-col>
<el-col :span="6">
<div>
<el-button size="small" type="primary" class="pc-save-btn" @click="handleSavePermission">保存菜单授权
</el-button>
</div>
</el-col>
</el-row>
</template>
<div class="permission-com">
<el-tabs>
<el-tab-pane v-for="(item, mIndex) in menuData" :key="mIndex" :label="item.name">
<el-tabs tab-position="left">
<el-tab-pane v-for="(menu, mIndex) in item.children" :key="mIndex" :label="menu.name">
<el-checkbox v-model="menu.isCheck">页面显示权限</el-checkbox>
<div class="pc-collapse-main">
<div class="pccm-item">
<div class="menu-form-alert"> 配置操作功能接口权限,配置数据权限点击小齿轮 </div>
<el-checkbox v-for="(btn, bIndex) in menu.btns" :key="bIndex" v-model="btn.isCheck"
:label="btn.value">
<div class="btn-item">
{{ btn.data_range !== null ? `${btn.name}(${formatDataRange(btn.data_range)})` : btn.name }}
<span v-show="btn.isCheck" @click.stop.prevent="handleSettingClick(menu, btn)">
<el-icon>
<Setting />
</el-icon>
</span>
</div>
</el-checkbox>
</div>
<div class="pccm-item" v-if="menu.columns && menu.columns.length > 0">
<div class="menu-form-alert"> 配置数据列字段权限 </div>
<ul class="columns-list">
<li class="columns-head">
<div class="width-txt">
<span>字段</span>
</div>
<div v-for="(head, hIndex) in column.header" :key="hIndex" class="width-check">
<el-checkbox :label="head.value"
@change="handleColumnChange($event, menu, head.value, head.disabled)">
<span>{{ head.label }}</span>
</el-checkbox>
</div>
</li>
<li v-for="(c_item, c_index) in menu.columns" :key="c_index" class="columns-item">
<div class="width-txt">{{ c_item.title }}</div>
<div v-for="(col, cIndex) in column.header" :key="cIndex" class="width-check">
<el-checkbox v-model="c_item[col.value]" class="ci-checkout"
:disabled="c_item[col.disabled]"></el-checkbox>
</div>
</li>
</ul>
</div>
</div>
</el-tab-pane>
</el-tabs>
</el-tab-pane>
</el-tabs>
<el-dialog v-model="dialogVisible" title="数据权限配置" width="400px" :close-on-click-modal="false"
:before-close="handleDialogClose">
<div class="pc-dialog">
<el-select v-model="dataPermission" @change="handlePermissionRangeChange" class="dialog-select"
placeholder="请选择">
<el-option v-for="item in dataPermissionRange" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-tree-select v-show="dataPermission === 4" node-key="id" v-model="customDataPermission"
:props="defaultTreeProps" :data="deptData" multiple check-strictly :render-after-expand="false"
show-checkbox class="dialog-tree" />
</div>
<template #footer>
<div>
<el-button type="primary" @click="handleDialogConfirm"> 确定</el-button>
<el-button @click="handleDialogClose"> 取消</el-button>
</div>
</template>
</el-dialog>
</div>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, onMounted, defineProps, watch, computed, reactive } from 'vue';
import XEUtils from 'xe-utils';
import { errorNotification } from '/@/utils/message';
import {
getDataPermissionRange,
getDataPermissionDept,
getRolePermission,
setRolePremission,
setBtnDatarange,
} from './api';
import { MenuDataType, DataPermissionRangeType, CustomDataPermissionDeptType } from './types';
import { ElMessage } from 'element-plus'
const props = defineProps({
roleId: {
type: Number,
default: -1
},
roleName: {
type: String,
default: ''
},
drawerVisible: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:drawerVisible'])
const drawerVisible = ref(false)
watch(
() => props.drawerVisible,
(val) => {
drawerVisible.value = val;
getMenuBtnPermission()
getDataPermissionRangeLable()
}
);
const handleDrawerClose = () => {
emit('update:drawerVisible', false);
}
const defaultTreeProps = {
children: 'children',
label: 'name',
value: 'id',
};
let menuData = ref<MenuDataType[]>([]);
let collapseCurrent = ref<number[]>([]);
let menuCurrent = ref<Partial<MenuDataType>>({});
let menuBtnCurrent = ref<number>(-1);
let dialogVisible = ref(false);
let dataPermissionRange = ref<DataPermissionRangeType[]>([]);
let dataPermissionRangeLabel = ref<DataPermissionRangeType[]>([]);
const formatDataRange = computed(() => {
return function (datarange: number) {
const findItem = dataPermissionRangeLabel.value.find((i) => i.value === datarange);
return findItem?.label || ''
}
})
let deptData = ref<CustomDataPermissionDeptType[]>([]);
let dataPermission = ref();
let customDataPermission = ref([]);
//获取菜单,按钮,权限
const getMenuBtnPermission = async () => {
const resMenu = await getRolePermission({ role: props.roleId })
menuData.value = resMenu
}
// 获取按钮的数据权限下拉选项
const getDataPermissionRangeLable = async () => {
const resRange = await getDataPermissionRange({ role: props.roleId })
dataPermissionRangeLabel.value = resRange.data;
}
/**
* 获取按钮数据权限下拉选项
* @param btnId 按钮id
*/
const fetchData = async (btnId: number) => {
try {
const resRange = await getDataPermissionRange({ menu_button: btnId });
if (resRange?.code === 2000) {
dataPermissionRange.value = resRange.data;
}
} catch {
return;
}
};
// const handleCollapseChange = (val: number) => {
// collapseCurrent.value = [val];
// };
/**
* 设置按钮数据权限
* @param record 当前菜单
* @param btnType 按钮类型
*/
const handleSettingClick = (record: MenuDataType, btn: MenuDataType['btns'][number]) => {
menuCurrent.value = record;
menuBtnCurrent.value = btn.id;
dialogVisible.value = true;
dataPermission.value = btn.data_range;
handlePermissionRangeChange(btn.data_range)
fetchData(btn.id)
};
/**
* 设置列权限
* @param val 是否选中
* @param record 当前菜单
* @param btnType 按钮类型
* @param disabledType 禁用类型
*/
const handleColumnChange = (val: boolean, record: MenuDataType, btnType: string, disabledType: string) => {
for (const iterator of record.columns) {
iterator[btnType] = iterator[disabledType] ? iterator[btnType] : val;
}
};
/**
* 数据权限设置
*/
const handlePermissionRangeChange = async (val: number) => {
if (val === 4) {
const res = await getDataPermissionDept({ role: props.roleId, menu_button: menuBtnCurrent.value });
const depts = XEUtils.toArrayTree(res.data, { parentKey: 'parent', strict: false });
deptData.value = depts;
const btnObj = XEUtils.find(menuCurrent.value.btns, item => item.id === menuBtnCurrent.value)
customDataPermission.value = btnObj.dept;
}
};
/**
* 数据权限设置确认
*/
const handleDialogConfirm = () => {
if (dataPermission.value !== 0 && !dataPermission.value) {
errorNotification('请选择');
return;
}
for (const item of menuData.value) {
for (const iterator of item.children) {
if (iterator.id === menuCurrent.value.id) {
for (const btn of iterator.btns) {
if (btn.id === menuBtnCurrent.value) {
const findItem = dataPermissionRange.value.find((i) => i.value === dataPermission.value);
btn.data_range = findItem?.value || 0;
if (btn.data_range === 4) {
btn.dept = customDataPermission.value
}
}
}
}
}
}
handleDialogClose();
};
const handleDialogClose = () => {
dialogVisible.value = false;
customDataPermission.value = [];
dataPermission.value = null;
};
//保存菜单授权
const handleSavePermission = () => {
setRolePremission(props.roleId, menuData.value).then((res: any) => {
ElMessage({
message: res.msg,
type: 'success',
})
})
}
const column = reactive({
header: [
{ value: 'is_create', label: '新增可见', disabled: 'disabled_create' },
{ value: 'is_update', label: '编辑可见', disabled: 'disabled_update' },
{ value: 'is_query', label: '列表可见', disabled: 'disabled_query' }
]
})
onMounted(() => {
});
</script>
<style lang="scss" scoped>
.permission-com {
margin: 15px;
box-sizing: border-box;
.pc-save-btn {
margin-bottom: 15px;
}
.pc-collapse-title {
line-height: 32px;
text-align: left;
span {
font-size: 16px;
}
}
.pc-collapse-main {
padding-top: 15px;
box-sizing: border-box;
.pccm-item {
margin-bottom: 10px;
.menu-form-alert {
color: #fff;
line-height: 24px;
padding: 8px 16px;
margin-bottom: 20px;
border-radius: 4px;
background-color: var(--el-color-primary);
}
.btn-item {
display: flex;
align-items: center;
span {
margin-left: 5px;
}
}
.columns-list {
.width-txt {
width: 200px;
}
.width-check {
width: 100px;
}
.width-icon {
cursor: pointer;
}
.columns-head {
display: flex;
align-items: center;
padding: 6px 0;
border-bottom: 1px solid #ebeef5;
box-sizing: border-box;
span {
font-weight: 900;
}
}
.columns-item {
display: flex;
align-items: center;
padding: 6px 0;
box-sizing: border-box;
.ci-checkout {
height: auto !important;
}
}
}
}
}
.pc-dialog {
.dialog-select {
width: 100%;
}
.dialog-tree {
width: 100%;
margin-top: 20px;
}
}
}
</style>
<style lang="scss">
.permission-com {
.el-collapse {
border-top: none;
border-bottom: none;
}
.el-collapse-item {
margin-bottom: 15px;
}
.el-collapse-item__header {
height: auto;
padding: 15px;
border-radius: 8px;
border-top: 1px solid #ebeef5;
border-left: 1px solid #ebeef5;
border-right: 1px solid #ebeef5;
box-sizing: border-box;
background-color: #fafafa;
}
.el-collapse-item__header.is-active {
border-radius: 8px 8px 0 0;
background-color: #fafafa;
}
.el-collapse-item__wrap {
padding: 15px;
border-left: 1px solid #ebeef5;
border-right: 1px solid #ebeef5;
border-top: 1px solid #ebeef5;
border-radius: 0 0 8px 8px;
background-color: #fafafa;
box-sizing: border-box;
.el-collapse-item__content {
padding-bottom: 0;
}
}
}
</style>

View File

@@ -1,205 +1,244 @@
<template> <template>
<el-drawer v-model="drawerVisible" title="权限配置" direction="rtl" size="60%" :close-on-click-modal="false" <el-drawer
:before-close="handleDrawerClose" :destroy-on-close="true"> v-model="drawerVisibleNew"
<template #header> title="权限配置"
<el-row> direction="rtl"
<el-col :span="4"> size="60%"
<div>当前授权角色 :close-on-click-modal="false"
<el-tag>{{ props.roleName }}</el-tag> :before-close="handleDrawerClose"
</div> :destroy-on-close="true"
</el-col> >
<el-col :span="6"> <template #header>
<div> <el-row>
<el-button size="small" type="primary" class="pc-save-btn" @click="handleSavePermission">保存菜单授权 <el-col :span="4">
</el-button> <div>
</div> 当前授权角色
</el-col> <el-tag>{{ props.roleName }}</el-tag>
</el-row> </div>
</template> </el-col>
<div class="permission-com"> <el-col :span="6">
<el-tabs> <div>
<el-tab-pane v-for="(item, mIndex) in menuData" :key="mIndex" :label="item.name"> <el-button size="small" type="primary" class="pc-save-btn" @click="handleSavePermission">保存菜单授权 </el-button>
<el-tabs tab-position="left"> </div>
<el-tab-pane v-for="(menu, mIndex) in item.children" :key="mIndex" :label="menu.name"> </el-col>
<el-checkbox v-model="menu.isCheck">页面显示权限</el-checkbox> </el-row>
<div class="pc-collapse-main"> </template>
<div class="pccm-item"> <div class="permission-com">
<div class="menu-form-alert"> 配置操作功能接口权限,配置数据权限点击小齿轮 </div> <el-row class="menu-el-row" :gutter="20">
<el-checkbox v-for="(btn, bIndex) in menu.btns" :key="bIndex" v-model="btn.isCheck" <el-col :span="6">
:label="btn.value"> <div class="menu-box menu-left-box">
<div class="btn-item"> <el-tree
{{ btn.data_range !== null ? `${btn.name}(${formatDataRange(btn.data_range)})` : btn.name }} ref="treeRef"
<span v-show="btn.isCheck" @click.stop.prevent="handleSettingClick(menu, btn)"> :data="menuData"
<el-icon> :props="defaultTreeProps"
<Setting /> :default-checked-keys="menuDefaultCheckedKeys"
</el-icon> @check="handleMenuCheck"
</span> @node-click="handleMenuClick"
</div> node-key="id"
</el-checkbox> check-strictly
</div> highlight-current
show-checkbox
default-expand-all
>
</el-tree>
</div>
</el-col>
<div class="pccm-item" v-if="menu.columns && menu.columns.length > 0"> <el-col :span="18">
<div class="menu-form-alert"> 配置数据列字段权限 </div> <div class="pc-collapse-main" v-if="menuCurrent.btns && menuCurrent.btns.length > 0">
<ul class="columns-list"> <div class="pccm-item">
<li class="columns-head"> <div class="menu-form-alert">配置操作功能接口权限,配置数据权限点击小齿轮</div>
<div class="width-txt"> <el-checkbox v-for="(btn, bIndex) in menuCurrent.btns" :key="bIndex" v-model="btn.isCheck" :label="btn.value">
<span>字段</span> <div class="btn-item">
</div> {{ btn.data_range !== null ? `${btn.name}(${formatDataRange(btn.data_range)})` : btn.name }}
<div v-for="(head, hIndex) in column.header" :key="hIndex" class="width-check"> <span v-show="btn.isCheck" @click.stop.prevent="handleSettingClick(menuCurrent, btn)">
<el-checkbox :label="head.value" <el-icon>
@change="handleColumnChange($event, menu, head.value, head.disabled)"> <Setting />
<span>{{ head.label }}</span> </el-icon>
</el-checkbox> </span>
</div> </div>
</li> </el-checkbox>
</div>
<li v-for="(c_item, c_index) in menu.columns" :key="c_index" class="columns-item"> <div class="pccm-item" v-if="menuCurrent.columns && menuCurrent.columns.length > 0">
<div class="width-txt">{{ c_item.title }}</div> <div class="menu-form-alert">配置数据列字段权限</div>
<div v-for="(col, cIndex) in column.header" :key="cIndex" class="width-check"> <ul class="columns-list">
<el-checkbox v-model="c_item[col.value]" class="ci-checkout" <li class="columns-head">
:disabled="c_item[col.disabled]"></el-checkbox> <div class="width-txt">
</div> <span>字段</span>
</li> </div>
</ul> <div v-for="(head, hIndex) in column.header" :key="hIndex" class="width-check">
</div> <el-checkbox :label="head.value" @change="handleColumnChange($event, menuCurrent, head.value, head.disabled)">
</div> <span>{{ head.label }}</span>
</el-tab-pane> </el-checkbox>
</el-tabs> </div>
</el-tab-pane> </li>
</el-tabs>
<el-dialog v-model="dialogVisible" title="数据权限配置" width="400px" :close-on-click-modal="false" <li v-for="(c_item, c_index) in menuCurrent.columns" :key="c_index" class="columns-item">
:before-close="handleDialogClose"> <div class="width-txt">{{ c_item.title }}</div>
<div class="pc-dialog"> <div v-for="(col, cIndex) in column.header" :key="cIndex" class="width-check">
<el-select v-model="dataPermission" @change="handlePermissionRangeChange" class="dialog-select" <el-checkbox v-model="c_item[col.value]" class="ci-checkout" :disabled="c_item[col.disabled]"></el-checkbox>
placeholder="请选择"> </div>
<el-option v-for="item in dataPermissionRange" :key="item.value" :label="item.label" :value="item.value" /> </li>
</el-select> </ul>
<el-tree-select v-show="dataPermission === 4" node-key="id" v-model="customDataPermission" </div>
:props="defaultTreeProps" :data="deptData" multiple check-strictly :render-after-expand="false" </div>
show-checkbox class="dialog-tree" /> </el-col>
</div> </el-row>
<template #footer>
<div> <el-dialog v-model="dialogVisible" title="数据权限配置" width="400px" :close-on-click-modal="false" :before-close="handleDialogClose">
<el-button type="primary" @click="handleDialogConfirm"> 确定</el-button> <div class="pc-dialog">
<el-button @click="handleDialogClose"> 取消</el-button> <el-select v-model="dataPermission" @change="handlePermissionRangeChange" class="dialog-select" placeholder="请选择">
</div> <el-option v-for="item in dataPermissionRange" :key="item.value" :label="item.label" :value="item.value" />
</template> </el-select>
</el-dialog> <el-tree-select
</div> v-show="dataPermission === 4"
</el-drawer> node-key="id"
v-model="customDataPermission"
:props="defaultTreeProps"
:data="deptData"
multiple
check-strictly
:render-after-expand="false"
show-checkbox
class="dialog-tree"
/>
</div>
<template #footer>
<div>
<el-button type="primary" @click="handleDialogConfirm"> 确定</el-button>
<el-button @click="handleDialogClose"> 取消</el-button>
</div>
</template>
</el-dialog>
</div>
</el-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, defineProps, watch, computed, reactive } from 'vue'; import { ref, onMounted, defineProps, watch, computed, reactive } from 'vue';
import XEUtils from 'xe-utils'; import XEUtils from 'xe-utils';
import { errorNotification } from '/@/utils/message'; import { errorNotification } from '/@/utils/message';
import { import { getDataPermissionRange, getDataPermissionDept, getRolePermission, setRolePremission, setBtnDatarange } from './api';
getDataPermissionRange,
getDataPermissionDept,
getRolePermission,
setRolePremission,
setBtnDatarange,
} from './api';
import { MenuDataType, DataPermissionRangeType, CustomDataPermissionDeptType } from './types'; import { MenuDataType, DataPermissionRangeType, CustomDataPermissionDeptType } from './types';
import { ElMessage } from 'element-plus' import { ElMessage, ElTree } from 'element-plus';
const props = defineProps({ const props = defineProps({
roleId: { roleId: {
type: Number, type: Number,
default: -1 default: -1,
}, },
roleName: { roleName: {
type: String, type: String,
default: '' default: '',
}, },
drawerVisible: { drawerVisible: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}) });
const emit = defineEmits(['update:drawerVisible']) const emit = defineEmits(['update:drawerVisible']);
const drawerVisible = ref(false) const drawerVisibleNew = ref(false);
watch( watch(
() => props.drawerVisible, () => props.drawerVisible,
(val) => { (val) => {
drawerVisible.value = val; drawerVisibleNew .value = val;
getMenuBtnPermission() getMenuBtnPermission();
getDataPermissionRangeLable() getDataPermissionRangeLable();
menuCurrent.value = {};
} }
); );
const handleDrawerClose = () => { const handleDrawerClose = () => {
emit('update:drawerVisible', false); emit('update:drawerVisible', false);
}
const defaultTreeProps = {
children: 'children',
label: 'name',
value: 'id',
}; };
let menuData = ref<MenuDataType[]>([]); const defaultTreeProps = {
let collapseCurrent = ref<number[]>([]); children: 'children',
let menuCurrent = ref<Partial<MenuDataType>>({}); label: 'name',
value: 'id',
};
let menuData = ref<MenuDataType[]>([]); // 菜单列表数据
let menuDefaultCheckedKeys = ref<number[]>([]); // 默认选中的菜单列表
let menuCurrent = ref<Partial<MenuDataType>>({}); // 当前选中的菜单
let menuBtnCurrent = ref<number>(-1); let menuBtnCurrent = ref<number>(-1);
let dialogVisible = ref(false); let dialogVisible = ref(false);
let dataPermissionRange = ref<DataPermissionRangeType[]>([]); let dataPermissionRange = ref<DataPermissionRangeType[]>([]);
let dataPermissionRangeLabel = ref<DataPermissionRangeType[]>([]); let dataPermissionRangeLabel = ref<DataPermissionRangeType[]>([]);
const formatDataRange = computed(() => { const formatDataRange = computed(() => {
return function (datarange: number) { return function (datarange: number) {
const findItem = dataPermissionRangeLabel.value.find((i) => i.value === datarange); const findItem = dataPermissionRangeLabel.value.find((i) => i.value === datarange);
return findItem?.label || '' return findItem?.label || '';
} };
}) });
let deptData = ref<CustomDataPermissionDeptType[]>([]); let deptData = ref<CustomDataPermissionDeptType[]>([]);
let dataPermission = ref(); let dataPermission = ref();
let customDataPermission = ref([]); let customDataPermission = ref([]);
/**
* 菜单复选框选中
* @param node
* @param data
*/
const handleMenuCheck = (node: any, data: any) => {
XEUtils.eachTree(menuData.value, (item) => {
item.isCheck = data.checkedKeys.includes(item.id);
});
};
/**
* 菜单点击
* @param node
* @param data
*/
const handleMenuClick = (selectNode: MenuDataType) => {
menuCurrent.value = selectNode;
};
//获取菜单,按钮,权限 //获取菜单,按钮,权限
const getMenuBtnPermission = async () => { const getMenuBtnPermission = async () => {
const resMenu = await getRolePermission({ role: props.roleId }) const resMenu = await getRolePermission({ role: props.roleId });
menuData.value = resMenu menuData.value = resMenu;
menuDefaultCheckedKeys.value = XEUtils.toTreeArray(resMenu)
} .filter((i) => i.isCheck)
.map((i) => i.id);
};
// 获取按钮的数据权限下拉选项 // 获取按钮的数据权限下拉选项
const getDataPermissionRangeLable = async () => { const getDataPermissionRangeLable = async () => {
const resRange = await getDataPermissionRange({ role: props.roleId }) const resRange = await getDataPermissionRange({ role: props.roleId });
dataPermissionRangeLabel.value = resRange.data; dataPermissionRangeLabel.value = resRange.data;
} };
/** /**
* 获取按钮数据权限下拉选项 * 获取按钮数据权限下拉选项
* @param btnId 按钮id * @param btnId 按钮id
*/ */
const fetchData = async (btnId: number) => { const fetchData = async (btnId: number) => {
try { try {
const resRange = await getDataPermissionRange({ menu_button: btnId }); const resRange = await getDataPermissionRange({ menu_button: btnId });
if (resRange?.code === 2000) { if (resRange?.code === 2000) {
dataPermissionRange.value = resRange.data; dataPermissionRange.value = resRange.data;
} }
} catch { } catch {
return; return;
} }
}; };
// const handleCollapseChange = (val: number) => {
// collapseCurrent.value = [val];
// };
/** /**
* 设置按钮数据权限 * 设置按钮数据权限
* @param record 当前菜单 * @param record 当前菜单
* @param btnType 按钮类型 * @param btnType 按钮类型
*/ */
const handleSettingClick = (record: MenuDataType, btn: MenuDataType['btns'][number]) => { const handleSettingClick = (record: any, btn: MenuDataType['btns'][number]) => {
menuCurrent.value = record; menuCurrent.value = record;
menuBtnCurrent.value = btn.id; menuBtnCurrent.value = btn.id;
dialogVisible.value = true; dialogVisible.value = true;
dataPermission.value = btn.data_range; dataPermission.value = btn.data_range;
handlePermissionRangeChange(btn.data_range) handlePermissionRangeChange(btn.data_range);
fetchData(btn.id) fetchData(btn.id);
}; };
/** /**
@@ -209,212 +248,210 @@ const handleSettingClick = (record: MenuDataType, btn: MenuDataType['btns'][numb
* @param btnType 按钮类型 * @param btnType 按钮类型
* @param disabledType 禁用类型 * @param disabledType 禁用类型
*/ */
const handleColumnChange = (val: boolean, record: MenuDataType, btnType: string, disabledType: string) => { const handleColumnChange = (val: boolean, record: any, btnType: string, disabledType: string) => {
for (const iterator of record.columns) { for (const iterator of record.columns) {
iterator[btnType] = iterator[disabledType] ? iterator[btnType] : val; iterator[btnType] = iterator[disabledType] ? iterator[btnType] : val;
} }
}; };
/** /**
* 数据权限设置 * 数据权限设置
*/ */
const handlePermissionRangeChange = async (val: number) => { const handlePermissionRangeChange = async (val: number) => {
if (val === 4) { if (val === 4) {
const res = await getDataPermissionDept({ role: props.roleId, menu_button: menuBtnCurrent.value }); const res = await getDataPermissionDept({ role: props.roleId, menu_button: menuBtnCurrent.value });
const depts = XEUtils.toArrayTree(res.data, { parentKey: 'parent', strict: false }); const depts = XEUtils.toArrayTree(res.data, { parentKey: 'parent', strict: false });
deptData.value = depts; deptData.value = depts;
const btnObj = XEUtils.find(menuCurrent.value.btns, item => item.id === menuBtnCurrent.value) const btnObj = XEUtils.find(menuCurrent.value.btns, (item) => item.id === menuBtnCurrent.value);
customDataPermission.value = btnObj.dept; customDataPermission.value = btnObj.dept;
} }
}; };
/** /**
* 数据权限设置确认 * 数据权限设置确认
*/ */
const handleDialogConfirm = () => { const handleDialogConfirm = () => {
if (dataPermission.value !== 0 && !dataPermission.value) { if (dataPermission.value !== 0 && !dataPermission.value) {
errorNotification('请选择'); errorNotification('请选择');
return; return;
} }
for (const item of menuData.value) { for (const item of menuData.value) {
for (const iterator of item.children) { for (const iterator of item.children) {
if (iterator.id === menuCurrent.value.id) { if (iterator.id === menuCurrent.value.id) {
for (const btn of iterator.btns) { for (const btn of iterator.btns) {
if (btn.id === menuBtnCurrent.value) { if (btn.id === menuBtnCurrent.value) {
const findItem = dataPermissionRange.value.find((i) => i.value === dataPermission.value); const findItem = dataPermissionRange.value.find((i) => i.value === dataPermission.value);
btn.data_range = findItem?.value || 0; btn.data_range = findItem?.value || 0;
if (btn.data_range === 4) { if (btn.data_range === 4) {
btn.dept = customDataPermission.value btn.dept = customDataPermission.value;
} }
} }
} }
} }
} }
} }
handleDialogClose(); handleDialogClose();
}; };
const handleDialogClose = () => { const handleDialogClose = () => {
dialogVisible.value = false; dialogVisible.value = false;
customDataPermission.value = []; customDataPermission.value = [];
dataPermission.value = null; dataPermission.value = null;
}; };
//保存菜单授权 //保存菜单授权
const handleSavePermission = () => { const handleSavePermission = () => {
setRolePremission(props.roleId, menuData.value).then((res: any) => { setRolePremission(props.roleId, XEUtils.toTreeArray(menuData.value)).then((res: any) => {
ElMessage({ ElMessage({
message: res.msg, message: res.msg,
type: 'success', type: 'success',
}) });
}) });
} };
const column = reactive({ const column = reactive({
header: [ header: [
{ value: 'is_create', label: '新增可见', disabled: 'disabled_create' }, { value: 'is_create', label: '新增可见', disabled: 'disabled_create' },
{ value: 'is_update', label: '编辑可见', disabled: 'disabled_update' }, { value: 'is_update', label: '编辑可见', disabled: 'disabled_update' },
{ value: 'is_query', label: '列表可见', disabled: 'disabled_query' } { value: 'is_query', label: '列表可见', disabled: 'disabled_query' },
] ],
})
onMounted(() => {
}); });
onMounted(() => {});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.permission-com { .permission-com {
margin: 15px; margin: 15px;
box-sizing: border-box; box-sizing: border-box;
.pc-save-btn { .pc-save-btn {
margin-bottom: 15px; margin-bottom: 15px;
} }
.pc-collapse-title { .pc-collapse-title {
line-height: 32px; line-height: 32px;
text-align: left; text-align: left;
span { span {
font-size: 16px; font-size: 16px;
} }
} }
.pc-collapse-main { .pc-collapse-main {
padding-top: 15px; box-sizing: border-box;
box-sizing: border-box;
.pccm-item { .pccm-item {
margin-bottom: 10px; margin-bottom: 10px;
.menu-form-alert { .menu-form-alert {
color: #fff; color: #fff;
line-height: 24px; line-height: 24px;
padding: 8px 16px; padding: 8px 16px;
margin-bottom: 20px; margin-bottom: 20px;
border-radius: 4px; border-radius: 4px;
background-color: var(--el-color-primary); background-color: var(--el-color-primary);
} }
.btn-item { .btn-item {
display: flex; display: flex;
align-items: center; align-items: center;
span { span {
margin-left: 5px; margin-left: 5px;
} }
} }
.columns-list { .columns-list {
.width-txt { .width-txt {
width: 200px; width: 200px;
} }
.width-check { .width-check {
width: 100px; width: 100px;
} }
.width-icon { .width-icon {
cursor: pointer; cursor: pointer;
} }
.columns-head { .columns-head {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 6px 0; padding: 6px 0;
border-bottom: 1px solid #ebeef5; border-bottom: 1px solid #ebeef5;
box-sizing: border-box; box-sizing: border-box;
span { span {
font-weight: 900; font-weight: 900;
} }
} }
.columns-item { .columns-item {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 6px 0; padding: 6px 0;
box-sizing: border-box; box-sizing: border-box;
.ci-checkout { .ci-checkout {
height: auto !important; height: auto !important;
} }
} }
} }
} }
} }
.pc-dialog { .pc-dialog {
.dialog-select { .dialog-select {
width: 100%; width: 100%;
} }
.dialog-tree { .dialog-tree {
width: 100%; width: 100%;
margin-top: 20px; margin-top: 20px;
} }
} }
} }
</style> </style>
<style lang="scss"> <style lang="scss">
.permission-com { .permission-com {
.el-collapse { .el-collapse {
border-top: none; border-top: none;
border-bottom: none; border-bottom: none;
} }
.el-collapse-item { .el-collapse-item {
margin-bottom: 15px; margin-bottom: 15px;
} }
.el-collapse-item__header { .el-collapse-item__header {
height: auto; height: auto;
padding: 15px; padding: 15px;
border-radius: 8px; border-radius: 8px;
border-top: 1px solid #ebeef5; border-top: 1px solid #ebeef5;
border-left: 1px solid #ebeef5; border-left: 1px solid #ebeef5;
border-right: 1px solid #ebeef5; border-right: 1px solid #ebeef5;
box-sizing: border-box; box-sizing: border-box;
background-color: #fafafa; background-color: #fafafa;
} }
.el-collapse-item__header.is-active { .el-collapse-item__header.is-active {
border-radius: 8px 8px 0 0; border-radius: 8px 8px 0 0;
background-color: #fafafa; background-color: #fafafa;
} }
.el-collapse-item__wrap { .el-collapse-item__wrap {
padding: 15px; padding: 15px;
border-left: 1px solid #ebeef5; border-left: 1px solid #ebeef5;
border-right: 1px solid #ebeef5; border-right: 1px solid #ebeef5;
border-top: 1px solid #ebeef5; border-top: 1px solid #ebeef5;
border-radius: 0 0 8px 8px; border-radius: 0 0 8px 8px;
background-color: #fafafa; background-color: #fafafa;
box-sizing: border-box; box-sizing: border-box;
.el-collapse-item__content { .el-collapse-item__content {
padding-bottom: 0; padding-bottom: 0;
} }
} }
} }
</style> </style>