update: 角色管理over

This commit is contained in:
easy 2023-02-07 18:05:00 +08:00
parent a8af608299
commit 3b799e53d7
6 changed files with 185 additions and 68 deletions

View File

@ -91,6 +91,7 @@ const permission = reactive({
},
// /
selectAllOpions: (row: permissionType) => {
row.indeterminate = false
const newValue = props.value.filter(
(item) => item.permission !== row.id,
);

View File

@ -1,8 +1,8 @@
<template>
<div class="role-permiss-container">
<a-card style="max-width: 60%">
<a-card>
<h5>基本信息</h5>
<a-form ref="formRef" :model="form.data" layout="vertical">
<a-form ref="formRef" class="basic-form" :model="form.data" layout="vertical">
<a-form-item
name="name"
label="名称"
@ -19,6 +19,7 @@
v-model:value="form.data.description"
placeholder="请输入说明"
:maxlength="200"
show-count
/>
</a-form-item>
</a-form>
@ -32,6 +33,7 @@
type="primary"
:disabled="form.loading"
@click="form.clickSave"
style="margin-top: 24px;"
>保存</a-button
>
</a-card>
@ -70,7 +72,7 @@ const form = reactive({
},
clickSave: () => {
const updateRole = updateRole_api(form.data);
const updateTree = updatePrimissTree_api(roleId, { menu: form.menus });
const updateTree = updatePrimissTree_api(roleId, { menus: form.menus });
Promise.all([updateRole, updateTree]).then((resp) => {
message.success('操作成功');
@ -82,4 +84,38 @@ const form = reactive({
form.getForm();
</script>
<style lang="less" scoped></style>
<style lang="less" scoped>
.role-permiss-container {
.ant-card {
margin-bottom: 24px;
h5 {
position: relative;
display: flex;
align-items: center;
margin-bottom: 20px;
padding: 4px 0 4px 12px;
font-weight: bold;
font-size: 16px;
&::before {
position: absolute;
top: 5px px;
left: 0;
width: 4px;
height: calc(100% - 10px);
background-color: #1d39c4;
border-radius: 2px;
content: ' ';
}
}
.basic-form {
.ant-form-item {
display: block;
width: 60%;
}
}
}
}
</style>

View File

@ -5,8 +5,9 @@
:data-source="tableData"
:pagination="false"
:rowKey="'id'"
:scroll="{ y: '500px' }"
>
<!-- 自定义表头 -->
<!-- 表头 -->
<template #headerCell="{ column }">
<div v-if="column.key === 'menu'">
<a-checkbox
@ -18,9 +19,16 @@
</div>
<div v-else-if="column.key === 'data'">
<span style="">数据权限</span>
<a-tooltip>
<template #title
>勾选任意数据权限均能看到自己创建的数据权限</template
>
<question-circle-outlined />
</a-tooltip>
<a-checkbox
v-model:checked="bulkShow"
@change="bulkValue = ''"
style="margin-left: 10px"
>批量设置</a-checkbox
>
<a-select
@ -30,19 +38,20 @@
style="width: 200px"
:options="bulkOptions"
@change="bulkChange"
placeholder="请选择"
></a-select>
</div>
<div v-else>
<span>{{ column.title }}</span>
</div>
</template>
<!-- 自定义表格内容 -->
<!-- 表格内容 -->
<template #bodyCell="{ column, record }">
<div v-if="column.key === 'menu'">
<a-checkbox
v-model:checked="record.granted"
:indeterminate="record.indeterminate"
@change="menuChange(record)"
@change="menuChange(record, true)"
>{{ record.name }}</a-checkbox
>
</div>
@ -85,6 +94,7 @@
</template>
<script setup lang="ts">
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
import { cloneDeep } from 'lodash-es';
import { getPrimissTree_api } from '@/api/system/role';
@ -162,31 +172,44 @@ const flatTableData: tableItemType[] = []; // 表格数据的扁平化版本--
const init = () => {
getAllPermiss();
watch(tableData, () => {
const selected = cloneDeep(flatTableData).filter((item) => (item.granted || item.indeterminate) && !item.parentId);
selected.forEach((item) => {
if (
item.accessSupport &&
item.accessSupport.value === 'support' &&
item.selectAccesses
) {
item.selectAccesses = bulkValue.value;
item.assetAccesses?.forEach((asset) => {
if (asset.supportId === item.selectAccesses) {
asset.granted = true;
} else {
asset.granted = false;
}
});
delete item.selectAccesses;
}
delete item.indeterminate
});
emits(
'update:selectItems',
selected,
);
});
//
watch(
tableData,
() => {
//
const selected = cloneDeep(flatTableData).filter(
(item) =>
(item.granted && item.parentId) ||
(item.indeterminate && item.buttons),
);
selected.forEach((item) => {
/**
* 如果该项支持设置数据权限则对其进行数据权限的映射结束后删除用于映射的源属性
* 同时清除用于半全选状态的标记
*/
if (
item.accessSupport &&
item.accessSupport.value === 'support' &&
item.selectAccesses
) {
// item.selectAccesses = bulkValue.value;
item.assetAccesses?.forEach((asset) => {
if (asset.supportId === item.selectAccesses) {
asset.granted = true;
} else {
asset.granted = false;
}
});
delete item.selectAccesses;
}
delete item.indeterminate;
item.granted = true;
});
emits('update:selectItems', selected);
},
{ deep: true },
);
};
init();
@ -218,6 +241,7 @@ function menuChange(
row: tableItemType,
setButtonBool: boolean = true,
): undefined {
//
if (setButtonBool) {
if (row.buttons && row.buttons.length > 0)
row.buttons.forEach((button) => {
@ -225,34 +249,32 @@ function menuChange(
});
row.children && setChildrenChecked(row.children, row.granted);
}
//
const selectList = flatTableData.filter((item) => item.granted); //
//
if (row.buttons && row.buttons.length > 0) setStatus(row, 'buttons');
else setStatus(row, 'children');
//
if (row.selectAccesses !== undefined) {
if (!row.granted) {
row.selectAccesses = '';
} else if (row.selectAccesses === '') {
row.selectAccesses = 'creator';
}
}
//
if (row.parentId) {
// //
const parent = flatTableData.find(
(item) => item.id === row.parentId,
) as tableItemType;
const selectLen = parent.children?.filter((item) => item.granted)
.length as number; //
if (selectLen === parent.children?.length) {
parent.granted = true;
parent.indeterminate = false;
} else if (selectLen > 0) {
parent.granted = false;
parent.indeterminate = true;
} else {
parent.granted = false;
parent.indeterminate = false;
}
setStatus(parent, 'children');
//
if (parent.parentId) {
return menuChange(parent, false);
}
}
//
const selectList = flatTableData.filter((item) => item.granted); //
if (selectList.length === flatTableData.length) {
selectedAll.value = true;
indeterminate.value = false;
@ -270,20 +292,7 @@ function menuChange(
* @param row 触发的项
*/
function actionChange(row: tableItemType) {
const selectLen = row.buttons?.filter((item) => item.granted)
.length as number;
if (selectLen === row.buttons?.length) {
row.granted = true;
row.indeterminate = false;
} else if (selectLen > 0) {
row.granted = false;
row.indeterminate = true;
} else {
row.granted = false;
row.indeterminate = false;
}
setStatus(row, 'buttons');
menuChange(row, false);
}
@ -293,12 +302,15 @@ function actionChange(row: tableItemType) {
*/
function treeToSimple(treeData: tableItemType[]) {
treeData.forEach((item) => {
//
if (item.accessSupport && item.accessSupport.value === 'support') {
const select =
item.assetAccesses?.find((assetItem) => assetItem.granted) ||
{};
item.selectAccesses = select.supportId || '';
}
if (item.buttons && item.buttons.length > 0) setStatus(item, 'buttons');
else setStatus(item, 'children');
flatTableData.push(item);
item.children && treeToSimple(item.children);
});
@ -312,6 +324,7 @@ function setChildrenChecked(childrens: tableItemType[], value: boolean) {
if (childrens.length < 1) return;
childrens.forEach((item) => {
item.granted = value;
item.indeterminate = false;
if (item.buttons && item.buttons.length > 0)
item.buttons.forEach((button) => {
button.granted = value;
@ -319,11 +332,49 @@ function setChildrenChecked(childrens: tableItemType[], value: boolean) {
item.children && setChildrenChecked(item.children, value);
});
}
/**
* 根据taget的prop属性判断对应的全选状态头部全选不适用
* @param target 目标对象
* @param prop 目标属性
*/
function setStatus(
target: tableItemType,
prop: 'children' | 'buttons' = 'children',
) {
const childrens = target[prop] as any[];
if (childrens && childrens instanceof Array) {
//
const indeterminateLen = childrens.filter(
(childrens: buttonItemType | tableItemType) =>
childrens?.indeterminate,
).length;
if (indeterminateLen > 0) {
target.granted = false;
target.indeterminate = true;
return;
}
const selectLen = childrens.filter(
(children: buttonItemType | tableItemType) => children.granted,
).length;
if (selectLen === childrens.length) {
target.granted = true;
target.indeterminate = false;
} else if (selectLen > 0) {
target.granted = false;
target.indeterminate = true;
} else {
target.granted = false;
target.indeterminate = false;
}
}
}
type buttonItemType = {
supportId: string;
name: string;
granted: boolean;
indeterminate?: boolean;
};
type tableItemType = {
id: string;

View File

@ -25,7 +25,7 @@ const activeKey = ref('1');
padding: 24px 0 0 24px;
}
.role-permiss-container {
:deep(.ant-tabs-content-holder) {
padding: 24px;
}
}

View File

@ -61,6 +61,8 @@ import { getRoleList_api, delRole_api } from '@/api/system/role';
import { message } from 'ant-design-vue';
const addDialogRef = ref(); //
const router = useRouter();
const route = useRoute();
//
const query = reactive({
columns: [
@ -122,7 +124,7 @@ const table = reactive({
],
tableData: [],
clickAdd: () => {
addDialogRef.value.openDialog(true, {})
addDialogRef.value.openDialog(true, {});
},
clickDel: (row: any) => {
delRole_api(row.id).then((resp: any) => {
@ -136,7 +138,9 @@ const table = reactive({
router.push(`/system/Role/detail/${row.id}`);
},
});
nextTick(() => {
route.query.save && table.clickAdd();
});
</script>
<style lang="less" scoped></style>

View File

@ -1611,9 +1611,9 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"
commander@^2.19.0, commander@^2.20.0:
commander@^2.19.0, commander@^2.20.0, commander@^2.20.3:
version "2.20.3"
resolved "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz"
resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^8.3.0:
@ -1832,6 +1832,11 @@ css-what@^6.0.1:
resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz"
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
cssfilter@0.0.10:
version "0.0.10"
resolved "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae"
integrity sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==
csstype@^2.6.8:
version "2.6.21"
resolved "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz"
@ -1988,6 +1993,11 @@ dotenv@^5.0.1:
resolved "https://registry.npmmirror.com/dotenv/-/dotenv-5.0.1.tgz"
integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==
driver.js@^0.9.8:
version "0.9.8"
resolved "https://registry.npmjs.org/driver.js/-/driver.js-0.9.8.tgz#4b327f4537b1c9b9fb19419de86174be821ae32a"
integrity sha512-bczjyKdX6XmFyCDkwtRmlaORDwfBk1xXmRO0CAe5VwNQTM98aWaG2LAIiIdTe53iV/B7W5lXlIy2xYtf0JRb7Q==
duplexer3@^0.1.4:
version "0.1.5"
resolved "https://registry.npmmirror.com/duplexer3/-/duplexer3-0.1.5.tgz"
@ -3366,6 +3376,13 @@ markdown-it@^12.3.2:
mdurl "^1.0.1"
uc.micro "^1.0.5"
mavon-editor@^2.10.4:
version "2.10.4"
resolved "https://registry.npmjs.org/mavon-editor/-/mavon-editor-2.10.4.tgz#58d6c4dc208933f0ac4595c10c60655899ba8ba8"
integrity sha512-CFsBLkgt/KZBDg+SJYe2fyYv4zClY149PiwpH0rDAiiP4ae1XNs0GC8nBsoTeipsHcebDLN1QMkt3bUsnMDjQw==
dependencies:
xss "^1.0.6"
mdurl@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz"
@ -5255,6 +5272,14 @@ xdg-basedir@^4.0.0:
resolved "https://registry.npmmirror.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz"
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
xss@^1.0.6:
version "1.0.14"
resolved "https://registry.npmjs.org/xss/-/xss-1.0.14.tgz#4f3efbde75ad0d82e9921cc3c95e6590dd336694"
integrity sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==
dependencies:
commander "^2.20.3"
cssfilter "0.0.10"
y18n@^4.0.0:
version "4.0.3"
resolved "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz"