184 lines
5.5 KiB
Vue
184 lines
5.5 KiB
Vue
<template>
|
|
<div
|
|
v-can="{ value: [corePermissionCodes.role.read, corePermissionCodes.permission.read], mode: 'and' }"
|
|
class="permission-settings"
|
|
>
|
|
<t-cell-group title="权限配置" theme="card">
|
|
<t-cell
|
|
v-can="corePermissionCodes.role.read"
|
|
title="角色管理"
|
|
:note="`${roleCount} 个角色`"
|
|
arrow
|
|
@click="router.push('/management/permissions/roles')"
|
|
>
|
|
<template #leftIcon>
|
|
<t-icon name="user-setting" size="1.75rem" />
|
|
</template>
|
|
</t-cell>
|
|
<t-cell
|
|
v-can="corePermissionCodes.permission.read"
|
|
title="权限管理"
|
|
:note="`${permissionCount} 个权限`"
|
|
arrow
|
|
@click="router.push('/management/permissions/items')"
|
|
>
|
|
<template #leftIcon>
|
|
<t-icon name="secured" size="1.75rem" />
|
|
</template>
|
|
</t-cell>
|
|
<t-cell
|
|
v-can="rolePermissionAssignAccess"
|
|
title="角色直接授权 P"
|
|
arrow
|
|
@click="router.push('/management/permissions/assign/p')"
|
|
>
|
|
<template #leftIcon>
|
|
<t-icon name="secured" size="1.75rem" />
|
|
</template>
|
|
</t-cell>
|
|
<t-cell
|
|
v-can="rolePermissionAssignAccess"
|
|
title="角色转授权限 D"
|
|
arrow
|
|
@click="router.push('/management/permissions/assign/d')"
|
|
>
|
|
<template #leftIcon>
|
|
<t-icon name="user-checked" size="1.75rem" />
|
|
</template>
|
|
</t-cell>
|
|
<t-cell
|
|
v-can="corePermissionCodes.userRole.read"
|
|
title="用户角色授权"
|
|
arrow
|
|
@click="router.push('/management/permissions/user-roles')"
|
|
>
|
|
<template #leftIcon>
|
|
<t-icon name="usergroup" size="1.75rem" />
|
|
</template>
|
|
</t-cell>
|
|
</t-cell-group>
|
|
<t-cell-group v-entrance-transition title="当前角色结构" theme="card">
|
|
<t-cell
|
|
v-can="{ value: [corePermissionCodes.role.read, corePermissionCodes.permission.read], mode: 'and' }"
|
|
v-for="item in visibleRoleTree"
|
|
:key="item.id"
|
|
:arrow="canAssignRole(item)"
|
|
:hover="canAssignRole(item)"
|
|
@click="canAssignRole(item) && toAssign(item.id)"
|
|
>
|
|
<template #title>
|
|
<div class="title" v-text="item.name" :style="{ paddingLeft: `${item.level * 1.25}rem` }" />
|
|
</template>
|
|
</t-cell>
|
|
</t-cell-group>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useUserStore } from "timi-web";
|
|
import type { Role } from "@/store/permissionSettingsStore";
|
|
import { usePermissionSettingsStore } from "@/store/permissionSettingsStore";
|
|
import { corePermissionCodes, coreRoleCodes } from "@/utils/permission";
|
|
|
|
defineOptions({
|
|
name: "PermissionSettings"
|
|
});
|
|
|
|
const router = useRouter();
|
|
const userStore = useUserStore();
|
|
const permissionStore = usePermissionSettingsStore();
|
|
const authorizationRoleList = ref<Role[]>([]);
|
|
const isSystemAdmin = computed(() => userStore.hasRoles(coreRoleCodes.admin));
|
|
const roleCount = computed(() => authorizationRoleList.value.length);
|
|
const permissionCount = computed(() => permissionStore.permissionList.length);
|
|
type RoleTreeItem = Pick<Role, "id" | "name" | "parentRoleId" | "protectedRole"> & { level: number };
|
|
|
|
const visibleRoleTree = computed<RoleTreeItem[]>(() => {
|
|
if (isSystemAdmin.value) {
|
|
return permissionStore.roleTree;
|
|
}
|
|
|
|
const roleMap = new Map(authorizationRoleList.value.map(item => [item.id, item]));
|
|
const roleIdSet = new Set(authorizationRoleList.value.map(item => item.id));
|
|
const roots = authorizationRoleList.value.filter(item => !item.parentRoleId || !roleIdSet.has(item.parentRoleId));
|
|
const buildTree = (roleId: string, level: number, visitedRoleIds: Set<string>): RoleTreeItem[] => {
|
|
const role = roleMap.get(roleId);
|
|
if (!role || visitedRoleIds.has(roleId)) {
|
|
return [];
|
|
}
|
|
|
|
const nextVisitedRoleIds = new Set(visitedRoleIds);
|
|
nextVisitedRoleIds.add(roleId);
|
|
const childRoleIdList = authorizationRoleList.value
|
|
.filter(item => item.parentRoleId === roleId)
|
|
.map(item => item.id);
|
|
return [{ ...role, level }, ...childRoleIdList.flatMap(childRoleId => buildTree(childRoleId, level + 1, nextVisitedRoleIds))];
|
|
};
|
|
return roots.flatMap(item => buildTree(item.id, 0, new Set<string>()));
|
|
});
|
|
|
|
// ---------- 权限入口 ----------
|
|
|
|
const rolePermissionAssignAccess = {
|
|
value: [
|
|
corePermissionCodes.role.read,
|
|
corePermissionCodes.permission.read,
|
|
corePermissionCodes.rolePermission.read
|
|
],
|
|
mode: "and"
|
|
} as const;
|
|
|
|
async function toAssign(roleId: string): Promise<void> {
|
|
await router.push({
|
|
path: "/management/permissions/assign/p",
|
|
query: {
|
|
roleId
|
|
}
|
|
});
|
|
}
|
|
|
|
function canAssignRole(role: Pick<Role, "protectedRole">): boolean {
|
|
return isSystemAdmin.value || role.protectedRole !== true;
|
|
}
|
|
|
|
// ---------- 页面数据 ----------
|
|
|
|
onMounted(async () => {
|
|
if (isSystemAdmin.value) {
|
|
await permissionStore.loadAll();
|
|
authorizationRoleList.value = permissionStore.roleList;
|
|
return;
|
|
}
|
|
|
|
await permissionStore.loadAll();
|
|
const roleList = await permissionStore.loadManageableRoles();
|
|
authorizationRoleList.value = roleList;
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.permission-settings {
|
|
gap: 1rem;
|
|
padding: calc(var(--app-nav-height) + 1rem) 0 1rem 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.struct {
|
|
|
|
.header {
|
|
display: flex;
|
|
padding: 0 var(--td-cell-group-title-padding-left, 16px);
|
|
font-size: var(--td-cell-group-title-font-size, 14px);
|
|
text-align: left;
|
|
background: var(--td-cell-group-title-bg-color, var(--td-bg-color-secondarycontainer, var(--td-gray-color-1, #f3f3f3)));
|
|
line-height: var(--td-cell-group-title-line-height, 45px);
|
|
justify-content: space-between;
|
|
|
|
.title {
|
|
color: var(--td-cell-group-title-color, var(--td-text-color-placeholder, var(--td-font-gray-3, rgba(0, 0, 0, 0.4))));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|