177 lines
4.8 KiB
Vue
177 lines
4.8 KiB
Vue
<template>
|
||
<div v-can="{ value: [corePermissionCodes.role.read, corePermissionCodes.permission.read], mode: 'and' }" class="permission-list">
|
||
<t-pull-down-refresh
|
||
class="list-wrapper"
|
||
v-model="isRefreshing"
|
||
:refresh-timeout="30000"
|
||
@refresh="refresh"
|
||
>
|
||
<div class="content">
|
||
<t-cell-group v-entrance-transition class="header" theme="card">
|
||
<t-cell title="当前账号角色聚合权限 P">
|
||
<template #description>
|
||
<div>你拥有以下权限,可执行权限对应的功能,这些权限来自上级角色直接授权或子角色继承。</div>
|
||
<permission-legend />
|
||
</template>
|
||
</t-cell>
|
||
</t-cell-group>
|
||
<t-cell-group v-if="sortedPermissions.length" theme="card">
|
||
<t-swipe-cell
|
||
v-entrance-transition="index * 30"
|
||
v-for="(item, index) in sortedPermissions"
|
||
:key="item.id"
|
||
class="item"
|
||
>
|
||
<permission-cell :permission="item" :source="item.source" />
|
||
</t-swipe-cell>
|
||
</t-cell-group>
|
||
<t-empty v-if="!permissionStore.loading && !isSourceLoading" description="暂无权限" />
|
||
</div>
|
||
</t-pull-down-refresh>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { type Role as UserRole, RoleAPI, useUserStore } from "timi-web-api";
|
||
import type { Permission } from "@/store/permissionSettingsStore";
|
||
import { moduleCode, usePermissionSettingsStore } from "@/store/permissionSettingsStore";
|
||
import { corePermissionCodes } from "@/utils/permission";
|
||
import PermissionCell from "@/pages/permission/component/PermissionCell.vue";
|
||
import PermissionLegend from "@/pages/permission/component/PermissionLegend.vue";
|
||
|
||
defineOptions({
|
||
name: "PermissionList"
|
||
});
|
||
|
||
const permissionStore = usePermissionSettingsStore();
|
||
const userStore = useUserStore();
|
||
const isRefreshing = ref(false);
|
||
const isSourceLoading = ref(false);
|
||
|
||
// ---------- 列表数据 ----------
|
||
|
||
type PermissionSource = "direct" | "inherited" | "unknown";
|
||
type PermissionWithSource = Permission & {
|
||
source: PermissionSource;
|
||
};
|
||
|
||
const sourceRoleList = ref<UserRole[]>([]);
|
||
const sortedPermissions = computed<PermissionWithSource[]>(() => {
|
||
const permissionMap = new Map<string, PermissionWithSource>();
|
||
for (const role of sourceRoleList.value) {
|
||
for (const permission of getRoleAggregatePermissions(role)) {
|
||
permissionMap.set(permission.id, {
|
||
...permission,
|
||
source: getPermissionSource(permission.id)
|
||
});
|
||
}
|
||
}
|
||
for (const permission of getLoginUserPermissions()) {
|
||
if (!permissionMap.has(permission.id)) {
|
||
permissionMap.set(permission.id, {
|
||
...permission,
|
||
source: "unknown"
|
||
});
|
||
}
|
||
}
|
||
return Array.from(permissionMap.values()).sort((left, right) => formatPermissionCode(left).localeCompare(formatPermissionCode(right)));
|
||
});
|
||
|
||
function getRoleAggregatePermissions(role: UserRole): Permission[] {
|
||
if (role.allPermissionList?.length) {
|
||
return role.allPermissionList;
|
||
}
|
||
if (role.permissionList?.length) {
|
||
return role.permissionList;
|
||
}
|
||
return (role.permissionIdList || []).map(permissionStore.getPermissionById).filter(Boolean) as Permission[];
|
||
}
|
||
|
||
function getLoginUserPermissions(): Permission[] {
|
||
const permissionCodeSet = new Set(userStore.getPermissionList());
|
||
return permissionStore.permissionList.filter(item => permissionCodeSet.has(formatPermissionCode(item)));
|
||
}
|
||
|
||
function getPermissionSource(permissionId: string): PermissionSource {
|
||
if (sourceRoleList.value.some(role => getDirectPermissionIdSet(role).has(permissionId))) {
|
||
return "direct";
|
||
}
|
||
if (sourceRoleList.value.some(role => role.allPermissionList?.some(permission => permission.id === permissionId))) {
|
||
return "inherited";
|
||
}
|
||
return "unknown";
|
||
}
|
||
|
||
function getDirectPermissionIdSet(role: UserRole): Set<string> {
|
||
if (role.permissionList?.length) {
|
||
return new Set(role.permissionList.map(item => item.id));
|
||
}
|
||
return new Set(role.permissionIdList || []);
|
||
}
|
||
|
||
function formatPermissionCode(permission: Permission): string {
|
||
return `${permission.moduleCode}:${permission.code}`;
|
||
}
|
||
|
||
// ---------- 页面数据 ----------
|
||
|
||
async function refresh(): Promise<void> {
|
||
isRefreshing.value = true;
|
||
try {
|
||
await permissionStore.loadAll(true);
|
||
await loadSourceRoles();
|
||
} finally {
|
||
isRefreshing.value = false;
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
await permissionStore.loadAll();
|
||
await loadSourceRoles();
|
||
});
|
||
|
||
async function loadSourceRoles(): Promise<void> {
|
||
isSourceLoading.value = true;
|
||
try {
|
||
sourceRoleList.value = await RoleAPI.currentDetailList(moduleCode);
|
||
} finally {
|
||
isSourceLoading.value = false;
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.permission-list {
|
||
padding: calc(var(--app-nav-height) + 1rem) 0 1rem 0;
|
||
|
||
.list-wrapper {
|
||
|
||
.content {
|
||
gap: 1rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.header {
|
||
|
||
.description {
|
||
gap: .5rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
}
|
||
|
||
.item {
|
||
|
||
&:last-child {
|
||
|
||
:deep(.t-cell:after) {
|
||
display: none;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
</style>
|