文档权限面板

SharePoint 权限页范式的资源级 ACL 面板:继承 banner 三态(继承含父链 / 已断继承警示 / 例外 N 项 is-partial)、授权行主体五类(user/group/org/anyone/link,组行带「24 成员 · 由 IT 管理」注记)、显式 deny 一票否决置顶红(order:-1)、Limited Access 类系统行不可删(is-system 隐藏删除钮)、链接授权带范围与到期(is-expiring)、exposureCount 过度授权警示「对 1,204 人可见」(不去重计数)。renderKbAcl(el, model, opts?) 快照渲染;求值语义(先显式 deny → allow 并集 → 默认拒绝)由 kb-core evaluateAcl 提供。

继承自:公司库 › 财务部空间 例外 1 项
竞对黑名单 拒绝 直接 · 一票否决
finance-team 可编辑 继承自 财务部空间 · 24 成员 · 由 IT 管理
Limited Access 可查看 系统管理 · 不可手工增删
对 1,204 人可见

deny 行置顶红 · 组织内链接行 2026-11-01 到期(is-expiring)· 系统行无删除钮 · 底部「对 1,204 人可见」为过度授权警示

<div id="kb-acl-demo">  <section class="kb-acl">    <div class="kb-acl-inherit">继承自:公司库 <span class="kb-acl-chain-link">›</span> 财务部空间 <span class="kb-meta">例外 1 项</span></div>    <div class="kb-acl-grant is-deny">      <span class="kb-acl-subject" data-kind="user">竞对黑名单</span>      <span class="kb-acl-role kb-chip">拒绝</span>      <span class="kb-acl-meta">直接 · 一票否决</span>    </div>    <div class="kb-acl-grant">      <span class="kb-acl-subject" data-kind="group">finance-team</span>      <span class="kb-acl-role kb-chip">可编辑</span>      <span class="kb-acl-meta">继承自 财务部空间 · 24 成员 · 由 IT 管理</span>    </div>    <div class="kb-acl-grant is-system">      <span class="kb-acl-subject" data-kind="org">Limited Access</span>      <span class="kb-acl-role kb-chip">可查看</span>      <span class="kb-acl-meta">系统管理 · 不可手工增删</span>    </div>    <footer class="kb-acl-foot">      <span class="kb-meta">对 <span class="kb-num">1,204</span> 人可见</span>    </footer>  </section></div><p class="demo-label" id="kb-acl-log" style="margin-top:8px">deny 行置顶红 · 组织内链接行 2026-11-01 到期(is-expiring)· 系统行无删除钮 · 底部「对 1,204 人可见」为过度授权警示</p>

安装

bun add @icen.ai/ui

一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):

import '@icen.ai/ui/kit/kb-acl';

也可以用脚手架直接打印引入行:

bunx --bun @icen.ai/ui add kb-acl

Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/kb-perm.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。

用法

import { renderKbAcl } from '@icen.ai/ui/kit/kb-acl'; const request = {  resource: '2026 财务规划',  parentChain: ['公司库', '财务部空间'],   // 继承 banner 父链;broken: true 转已断警示态  broken: false,  exceptions: { label: 'Q3 并购草案.docx', count: 1 },   // 部分继承(例外 N 项,is-partial)  entries: [    { subject: { kind: 'group', id: 'finance-team', label: 'finance-team', note: '24 成员 · 由 IT 管理' },      role: 'editor', inheritedFrom: '财务部空间' },    { subject: { kind: 'user', id: 'u-lisi', label: '李四' }, role: 'owner' },    { subject: { kind: 'user', id: 'u-rival', label: '竞对黑名单' }, role: 'viewer', deny: true },  // 一票否决置顶    { subject: { kind: 'org', id: 'sys-limited', label: 'Limited Access', note: '系统自动' },      role: 'viewer', system: true },                                                               // 系统行不可删  ],  links: [    { subject: { kind: 'link', id: 'l-org', label: '组织内任何有链接者' },      role: 'viewer', expiresAt: '2026-11-01T00:00:00.000Z' },   // 到期一等公民  ],  exposureCount: 1204,              // 「对 1,204 人可见」过度授权警示(不去重计数)};renderKbAcl(el, request, {  onGrant: () => openSubjectPicker(),                     // 与 icen:kb-acl-grant 双通道  onRemove: (subject) => api.revoke(subject.id),          // 与 icen:kb-acl-remove 双通道  onBreak: () => api.breakInheritance(request.resource),  // 与 icen:kb-acl-inherit {action:'break'} 双通道  onRestore: () => api.restoreInheritance(request.resource),});// 事件:icen:kb-acl-grant {} / icen:kb-acl-remove {subject} / icen:kb-acl-inherit {action:'break'|'restore'}