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) => { selectAllOpions: (row: permissionType) => {
row.indeterminate = false
const newValue = props.value.filter( const newValue = props.value.filter(
(item) => item.permission !== row.id, (item) => item.permission !== row.id,
); );

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="role-permiss-container"> <div class="role-permiss-container">
<a-card style="max-width: 60%"> <a-card>
<h5>基本信息</h5> <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 <a-form-item
name="name" name="name"
label="名称" label="名称"
@ -19,6 +19,7 @@
v-model:value="form.data.description" v-model:value="form.data.description"
placeholder="请输入说明" placeholder="请输入说明"
:maxlength="200" :maxlength="200"
show-count
/> />
</a-form-item> </a-form-item>
</a-form> </a-form>
@ -32,6 +33,7 @@
type="primary" type="primary"
:disabled="form.loading" :disabled="form.loading"
@click="form.clickSave" @click="form.clickSave"
style="margin-top: 24px;"
>保存</a-button >保存</a-button
> >
</a-card> </a-card>
@ -70,7 +72,7 @@ const form = reactive({
}, },
clickSave: () => { clickSave: () => {
const updateRole = updateRole_api(form.data); 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) => { Promise.all([updateRole, updateTree]).then((resp) => {
message.success('操作成功'); message.success('操作成功');
@ -82,4 +84,38 @@ const form = reactive({
form.getForm(); form.getForm();
</script> </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" :data-source="tableData"
:pagination="false" :pagination="false"
:rowKey="'id'" :rowKey="'id'"
:scroll="{ y: '500px' }"
> >
<!-- 自定义表头 --> <!-- 表头 -->
<template #headerCell="{ column }"> <template #headerCell="{ column }">
<div v-if="column.key === 'menu'"> <div v-if="column.key === 'menu'">
<a-checkbox <a-checkbox
@ -18,9 +19,16 @@
</div> </div>
<div v-else-if="column.key === 'data'"> <div v-else-if="column.key === 'data'">
<span style="">数据权限</span> <span style="">数据权限</span>
<a-tooltip>
<template #title
>勾选任意数据权限均能看到自己创建的数据权限</template
>
<question-circle-outlined />
</a-tooltip>
<a-checkbox <a-checkbox
v-model:checked="bulkShow" v-model:checked="bulkShow"
@change="bulkValue = ''" @change="bulkValue = ''"
style="margin-left: 10px"
>批量设置</a-checkbox >批量设置</a-checkbox
> >
<a-select <a-select
@ -30,19 +38,20 @@
style="width: 200px" style="width: 200px"
:options="bulkOptions" :options="bulkOptions"
@change="bulkChange" @change="bulkChange"
placeholder="请选择"
></a-select> ></a-select>
</div> </div>
<div v-else> <div v-else>
<span>{{ column.title }}</span> <span>{{ column.title }}</span>
</div> </div>
</template> </template>
<!-- 自定义表格内容 --> <!-- 表格内容 -->
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<div v-if="column.key === 'menu'"> <div v-if="column.key === 'menu'">
<a-checkbox <a-checkbox
v-model:checked="record.granted" v-model:checked="record.granted"
:indeterminate="record.indeterminate" :indeterminate="record.indeterminate"
@change="menuChange(record)" @change="menuChange(record, true)"
>{{ record.name }}</a-checkbox >{{ record.name }}</a-checkbox
> >
</div> </div>
@ -85,6 +94,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { getPrimissTree_api } from '@/api/system/role'; import { getPrimissTree_api } from '@/api/system/role';
@ -162,31 +172,44 @@ const flatTableData: tableItemType[] = []; // 表格数据的扁平化版本--
const init = () => { const init = () => {
getAllPermiss(); getAllPermiss();
watch(tableData, () => { //
const selected = cloneDeep(flatTableData).filter((item) => (item.granted || item.indeterminate) && !item.parentId); watch(
selected.forEach((item) => { tableData,
if ( () => {
item.accessSupport && //
item.accessSupport.value === 'support' && const selected = cloneDeep(flatTableData).filter(
item.selectAccesses (item) =>
) { (item.granted && item.parentId) ||
item.selectAccesses = bulkValue.value; (item.indeterminate && item.buttons),
item.assetAccesses?.forEach((asset) => { );
if (asset.supportId === item.selectAccesses) {
asset.granted = true; selected.forEach((item) => {
} else { /**
asset.granted = false; * 如果该项支持设置数据权限则对其进行数据权限的映射结束后删除用于映射的源属性
} * 同时清除用于半全选状态的标记
}); */
delete item.selectAccesses; if (
} item.accessSupport &&
delete item.indeterminate item.accessSupport.value === 'support' &&
}); item.selectAccesses
emits( ) {
'update:selectItems', // item.selectAccesses = bulkValue.value;
selected, 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(); init();
@ -218,6 +241,7 @@ function menuChange(
row: tableItemType, row: tableItemType,
setButtonBool: boolean = true, setButtonBool: boolean = true,
): undefined { ): undefined {
//
if (setButtonBool) { if (setButtonBool) {
if (row.buttons && row.buttons.length > 0) if (row.buttons && row.buttons.length > 0)
row.buttons.forEach((button) => { row.buttons.forEach((button) => {
@ -225,34 +249,32 @@ function menuChange(
}); });
row.children && setChildrenChecked(row.children, row.granted); row.children && setChildrenChecked(row.children, row.granted);
} }
//
// if (row.buttons && row.buttons.length > 0) setStatus(row, 'buttons');
const selectList = flatTableData.filter((item) => item.granted); // else setStatus(row, 'children');
//
if (row.selectAccesses !== undefined) {
if (!row.granted) {
row.selectAccesses = '';
} else if (row.selectAccesses === '') {
row.selectAccesses = 'creator';
}
}
//
if (row.parentId) { if (row.parentId) {
// // // //
const parent = flatTableData.find( const parent = flatTableData.find(
(item) => item.id === row.parentId, (item) => item.id === row.parentId,
) as tableItemType; ) as tableItemType;
const selectLen = parent.children?.filter((item) => item.granted) setStatus(parent, 'children');
.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;
}
if (parent.parentId) { if (parent.parentId) {
return menuChange(parent, false); return menuChange(parent, false);
} }
} }
// //
const selectList = flatTableData.filter((item) => item.granted); //
if (selectList.length === flatTableData.length) { if (selectList.length === flatTableData.length) {
selectedAll.value = true; selectedAll.value = true;
indeterminate.value = false; indeterminate.value = false;
@ -270,20 +292,7 @@ function menuChange(
* @param row 触发的项 * @param row 触发的项
*/ */
function actionChange(row: tableItemType) { function actionChange(row: tableItemType) {
const selectLen = row.buttons?.filter((item) => item.granted) setStatus(row, 'buttons');
.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;
}
menuChange(row, false); menuChange(row, false);
} }
@ -293,12 +302,15 @@ function actionChange(row: tableItemType) {
*/ */
function treeToSimple(treeData: tableItemType[]) { function treeToSimple(treeData: tableItemType[]) {
treeData.forEach((item) => { treeData.forEach((item) => {
//
if (item.accessSupport && item.accessSupport.value === 'support') { if (item.accessSupport && item.accessSupport.value === 'support') {
const select = const select =
item.assetAccesses?.find((assetItem) => assetItem.granted) || item.assetAccesses?.find((assetItem) => assetItem.granted) ||
{}; {};
item.selectAccesses = select.supportId || ''; item.selectAccesses = select.supportId || '';
} }
if (item.buttons && item.buttons.length > 0) setStatus(item, 'buttons');
else setStatus(item, 'children');
flatTableData.push(item); flatTableData.push(item);
item.children && treeToSimple(item.children); item.children && treeToSimple(item.children);
}); });
@ -312,6 +324,7 @@ function setChildrenChecked(childrens: tableItemType[], value: boolean) {
if (childrens.length < 1) return; if (childrens.length < 1) return;
childrens.forEach((item) => { childrens.forEach((item) => {
item.granted = value; item.granted = value;
item.indeterminate = false;
if (item.buttons && item.buttons.length > 0) if (item.buttons && item.buttons.length > 0)
item.buttons.forEach((button) => { item.buttons.forEach((button) => {
button.granted = value; button.granted = value;
@ -319,11 +332,49 @@ function setChildrenChecked(childrens: tableItemType[], value: boolean) {
item.children && setChildrenChecked(item.children, value); 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 = { type buttonItemType = {
supportId: string; supportId: string;
name: string; name: string;
granted: boolean; granted: boolean;
indeterminate?: boolean;
}; };
type tableItemType = { type tableItemType = {
id: string; id: string;

View File

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

View File

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

View File

@ -1611,9 +1611,9 @@ combined-stream@^1.0.8:
dependencies: dependencies:
delayed-stream "~1.0.0" 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" 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== integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^8.3.0: 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" resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz"
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== 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: csstype@^2.6.8:
version "2.6.21" version "2.6.21"
resolved "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz" 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" resolved "https://registry.npmmirror.com/dotenv/-/dotenv-5.0.1.tgz"
integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow== 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: duplexer3@^0.1.4:
version "0.1.5" version "0.1.5"
resolved "https://registry.npmmirror.com/duplexer3/-/duplexer3-0.1.5.tgz" resolved "https://registry.npmmirror.com/duplexer3/-/duplexer3-0.1.5.tgz"
@ -3366,6 +3376,13 @@ markdown-it@^12.3.2:
mdurl "^1.0.1" mdurl "^1.0.1"
uc.micro "^1.0.5" 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: mdurl@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz" 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" resolved "https://registry.npmmirror.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz"
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== 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: y18n@^4.0.0:
version "4.0.3" version "4.0.3"
resolved "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz" resolved "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz"