diff --git a/hub/filelib-web/src/lib/GrantsPanel.svelte b/hub/filelib-web/src/lib/GrantsPanel.svelte index 24fa650..80c7c7b 100644 --- a/hub/filelib-web/src/lib/GrantsPanel.svelte +++ b/hub/filelib-web/src/lib/GrantsPanel.svelte @@ -60,6 +60,7 @@ (g) => g.principalId.toLowerCase().includes(q) || (g.principalName ?? "").toLowerCase().includes(q) || + (g.principalOpenId ?? "").toLowerCase().includes(q) || (g.principalType === "USER" ? "个人" : "group").includes(q), ); }); @@ -241,12 +242,12 @@ {:else} - + {#if shown.length === 0} - @@ -256,15 +257,14 @@ + +
成员类型权限加入时间
成员userId飞书 ID类型权限加入时间
+ {searchText.trim() === "" ? "暂无授权" : `无匹配「${searchText.trim()}」的授权`}
- - - {g.principalName ?? g.principalId} - {#if g.isCreatorGrant}(创建者){/if} - - {g.principalId} + + {g.principalName ?? g.principalId} + {#if g.isCreatorGrant}(创建者){/if} {g.principalType === "USER" ? g.principalId : "—"}{g.principalOpenId ?? "—"} {g.principalType === "USER" ? "个人" : "Group"} diff --git a/hub/filelib-web/src/lib/types.ts b/hub/filelib-web/src/lib/types.ts index 3a92fdc..b46e774 100644 --- a/hub/filelib-web/src/lib/types.ts +++ b/hub/filelib-web/src/lib/types.ts @@ -107,6 +107,8 @@ export interface Grant { readonly principalId: string; /** 主体显示名(用户 displayName / 组 name);主体已删为 null,展示回落 principalId。 */ readonly principalName: string | null; + /** USER 主体的飞书 openId;GROUP 或主体已删为 null。 */ + readonly principalOpenId: string | null; readonly role: Role; /** 创建者授权不可收回、不可改(契约 8.1)。 */ readonly isCreatorGrant: boolean; diff --git a/hub/src/database/filelib/grantService.ts b/hub/src/database/filelib/grantService.ts index e52ea09..f7be820 100644 --- a/hub/src/database/filelib/grantService.ts +++ b/hub/src/database/filelib/grantService.ts @@ -27,6 +27,8 @@ export interface GrantDto { readonly principalId: string; /** 主体显示名(用户 displayName / 组 name);主体已删时为 null,前端回落 principalId。 */ readonly principalName: string | null; + /** USER 主体的飞书 openId;GROUP 或主体已删时为 null。 */ + readonly principalOpenId: string | null; readonly role: FileLibRole; readonly isCreatorGrant: boolean; readonly createdAt: Date; @@ -38,13 +40,14 @@ function toDto(grant: FileLibGrant): GrantDto { principalType: grant.principalType, principalId: grant.principalId, principalName: null, + principalOpenId: null, role: grant.role, isCreatorGrant: grant.isCreatorGrant, createdAt: grant.createdAt, }; } -/** 批量回填主体显示名(两次查询,不做 per-row 往返)。可在事务内调用。 */ +/** 批量回填主体显示名与飞书 openId(两次查询,不做 per-row 往返)。可在事务内调用。 */ async function withPrincipalNames( prisma: Pick, grants: readonly GrantDto[], @@ -53,7 +56,10 @@ async function withPrincipalNames( const groupIds = [...new Set(grants.filter((g) => g.principalType === "GROUP").map((g) => g.principalId))]; const users = userIds.length === 0 ? [] - : await prisma.user.findMany({ where: { id: { in: userIds } }, select: { id: true, displayName: true } }); + : await prisma.user.findMany({ + where: { id: { in: userIds } }, + select: { id: true, displayName: true, feishuOpenId: true }, + }); const groups = groupIds.length === 0 ? [] : await prisma.memberGroup.findMany({ where: { id: { in: groupIds } }, select: { id: true, name: true } }); @@ -61,7 +67,12 @@ async function withPrincipalNames( ...users.map((u) => [u.id, u.displayName] as const), ...groups.map((g) => [g.id, g.name] as const), ]); - return grants.map((g) => ({ ...g, principalName: nameById.get(g.principalId) ?? null })); + const openIdById = new Map(users.map((u) => [u.id, u.feishuOpenId] as const)); + return grants.map((g) => ({ + ...g, + principalName: nameById.get(g.principalId) ?? null, + principalOpenId: g.principalType === "USER" ? openIdById.get(g.principalId) ?? null : null, + })); } type Tx = Prisma.TransactionClient;