refactor file tree

This commit is contained in:
Timi
2026-08-11 15:24:36 +08:00
parent 575d41b2e2
commit 819c1623eb
42 changed files with 86 additions and 86 deletions
+302
View File
@@ -0,0 +1,302 @@
<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 class="header" theme="card">
<t-cell title="当前账号角色聚合权限 P">
<template #description>
<div class="description">
<div>你拥有以下权限,可执行权限对应的功能,这些权限来自上级角色直接授权或子角色继承。</div>
<div class="legends">
<div class="legend">
<span class="block direct"></span>
<span>上级角色直接授权</span>
</div>
<div class="legend">
<span class="block inherited"></span>
<span>子角色继承授权</span>
</div>
</div>
</div>
</template>
</t-cell>
</t-cell-group>
<t-cell-group v-if="sortedPermissions.length" theme="card">
<t-swipe-cell
v-for="item in sortedPermissions"
:key="item.id"
class="item"
>
<t-cell :title="item.name">
<template #leftIcon>
<span class="source" :class="`source-${item.source}`"/>
</template>
<template #note>
<span class="code" v-text="formatPermissionCode(item)" />
</template>
</t-cell>
</t-swipe-cell>
</t-cell-group>
<t-empty v-else-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";
import type { Permission } from "@/store/permissionSettingsStore";
import { moduleCode, usePermissionSettingsStore } from "@/store/permissionSettingsStore";
import { corePermissionCodes } from "@/utils/permission";
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 {
--source-direct-color: #2563EB;
--source-inherited-color: #14B8A6;
--source-unknown-color: #94A3B8;
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;
.legends {
gap: 1.5rem;
display: flex;
.legend {
gap: .25rem;
display: flex;
align-items: center;
.block {
width: 1rem;
height: 1rem;
display: block;
border-radius: .25rem;
&.direct {
background: var(--source-direct-color);
}
&.inherited {
background: var(--source-inherited-color);
}
}
}
}
}
}
.item {
&:last-child {
:deep(.t-cell:after) {
display: none;
}
}
:deep(.t-cell) {
&__left {
display: flex;
align-items: center;
}
&__title {
flex: 1 1 0;
min-width: 0;
}
&__title-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&__note {
flex: 0 1 auto;
min-width: 0;
max-width: 56%;
text-align: right;
justify-content: flex-end;
}
.source {
width: 1rem;
height: 1rem;
display: block;
border-radius: .25rem;
&-direct {
background: var(--source-direct-color);
}
&-inherited {
background: var(--source-inherited-color);
}
&-unknown {
background: var(--source-unknown-color);
}
}
.code {
width: 100%;
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
}
}
:global(html.theme-dark) {
.permission-list {
.list-wrapper {
.content {
.item {
:deep(.t-cell) {
.source {
&-direct {
background: #60a5fa;
}
&-inherited {
background: #2dd4bf;
}
&-unknown {
background: #64748b;
}
}
}
}
}
}
}
}
</style>