diff --git a/reimburse/AdminView.swift b/reimburse/AdminView.swift index 41996fe..a7d5701 100644 --- a/reimburse/AdminView.swift +++ b/reimburse/AdminView.swift @@ -706,18 +706,32 @@ struct AdminView: View { } } else if permissionSection == "现有授权" { sectionCard("现有授权", icon: "person.crop.rectangle.badge.checkmark") { - Text("显示当前账号可查看的授权;撤销仅影响所选角色及范围。") + Text("显示当前账号可查看的授权;撤销仅影响所选角色及范围。列表会同时显示姓名和账户 ID,便于准确识别成员。") .font(.callout).foregroundStyle(.secondary) if model.grants.isEmpty { Text("暂无可显示的授权记录").foregroundStyle(.secondary) } - ForEach(model.grants) { g in - HStack { - Text("账户 \(g.userId)"); Text(g.role == "leader" ? "项目负责人" : g.role == "group" ? "组管理员" : "平台管理员") - Text("范围 #\(g.scopeId)").foregroundStyle(.secondary); Spacer() - if g.role != "platform" { - Button("撤销授权") { confirm("撤销账户 \(g.userId) 的这项授权?") { try await model.grant(userID: g.userId, role: g.role, scope: g.scopeId, revoke: true) } } - } - } - } + ForEach(model.grants) { g in + let roleName = g.role == "leader" ? "项目负责人" : g.role == "group" ? "组管理员" : "平台管理员" + let scopeName = grantScopeName(g) + HStack(spacing: 14) { + Image(systemName: g.role == "platform" ? "crown" : "person.crop.circle") + .foregroundStyle(g.role == "platform" ? .orange : .accentColor) + .frame(width: 28) + VStack(alignment: .leading, spacing: 4) { + HStack(spacing: 8) { + Text(g.name.isEmpty ? "未设置姓名" : g.name).font(.headline) + Text(roleName).font(.caption.weight(.medium)).padding(.horizontal, 8).padding(.vertical, 4) + .background(Color.accentColor.opacity(0.12)).clipShape(Capsule()) + } + Text("账户 ID:\(g.userId) · \(scopeName)").font(.caption).foregroundStyle(.secondary) + } + Spacer() + if g.role != "platform" { + Button("撤销授权") { confirm("撤销“\(g.name.isEmpty ? "账户 \(g.userId)" : g.name)”的\(roleName)授权?") { try await model.grant(userID: g.userId, role: g.role, scope: g.scopeId, revoke: true) } } + } + } + .padding(.vertical, 6) + Divider() + } } } else { sectionCard("1 · 选择角色和范围", icon: "person.badge.key") { @@ -791,6 +805,14 @@ struct AdminView: View { } }.padding(20) } + + private func grantScopeName(_ grant: AdminGrant) -> String { + if grant.role == "platform" { return "全部项目与范围" } + if grant.role == "leader" { + return "项目:" + (model.access?.projects.first { $0.id == grant.scopeId }?.name ?? "范围 #\(grant.scopeId)") + } + return "组:" + (model.access?.groups.first { $0.id == grant.scopeId }?.label ?? "范围 #\(grant.scopeId)") + } private var filteredAudit: [AdminAudit] { model.audit.filter { AdminDisplayFilter.matches(auditSearch, fields: [$0.actorId, $0.action, $0.resourceId, $0.detail, $0.date]) } }