97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import type { PlatformPermission } from "../../services/api";
|
|
|
|
import { Checkbox } from "~/components/ui/checkbox";
|
|
import {
|
|
adminEmptyClass,
|
|
permissionGroupClass,
|
|
permissionGroupTitleClass,
|
|
permissionGroupsClass,
|
|
permissionItemClassName,
|
|
} from "./adminUi";
|
|
|
|
/** 模块编码 → 展示名(用于权限分组标题)。 */
|
|
const MODULE_LABELS: Record<string, string> = {
|
|
dashboard: "工作台",
|
|
script: "构建脚本",
|
|
schedule: "调度配置",
|
|
system: "系统管理",
|
|
};
|
|
|
|
/** 勾选框样式:复刻原生 checkbox 外观(白底、灰边、蓝色勾选),并对齐 permission item 的 3px 顶部偏移。 */
|
|
const CHECKBOX_CLASS =
|
|
"mt-[3px] size-[16px] rounded-[3px] border-[#cdd9e4] bg-white disabled:opacity-100 data-checked:border-[#1277d3] data-checked:bg-[#1277d3] data-checked:text-white";
|
|
|
|
/**
|
|
* 权限勾选列表:按 module_code 分组渲染。
|
|
* - targetRoleCode === "admin" 时 system:view 锁定勾选(后端守卫);
|
|
* - 非 admin 角色 system:* 全部锁定(后端守卫)。
|
|
*/
|
|
export function PermissionCheckboxList({
|
|
permissions,
|
|
selected,
|
|
targetRoleCode,
|
|
onToggle,
|
|
}: {
|
|
permissions: PlatformPermission[];
|
|
selected: string[];
|
|
targetRoleCode: string;
|
|
onToggle: (code: string) => void;
|
|
}) {
|
|
const groups = permissions.reduce<Record<string, PlatformPermission[]>>(
|
|
(acc, permission) => {
|
|
const bucket = acc[permission.module_code] ?? [];
|
|
bucket.push(permission);
|
|
acc[permission.module_code] = bucket;
|
|
return acc;
|
|
},
|
|
{},
|
|
);
|
|
|
|
if (permissions.length === 0) {
|
|
return <p className={adminEmptyClass}>暂无可用权限</p>;
|
|
}
|
|
|
|
const isAdmin = targetRoleCode === "admin";
|
|
|
|
return (
|
|
<div className={permissionGroupsClass}>
|
|
{Object.entries(groups).map(([module, items]) => (
|
|
<div className={permissionGroupClass} key={module}>
|
|
<div className={permissionGroupTitleClass}>
|
|
{MODULE_LABELS[module] ?? module}
|
|
</div>
|
|
{items.map((permission) => {
|
|
const code = permission.permission_code;
|
|
const locked = isAdmin
|
|
? code === "system:view"
|
|
: code.startsWith("system:");
|
|
const checked = selected.includes(code);
|
|
return (
|
|
<label
|
|
className={permissionItemClassName(locked)}
|
|
key={code}
|
|
>
|
|
<Checkbox
|
|
checked={checked}
|
|
disabled={locked}
|
|
onCheckedChange={() => onToggle(code)}
|
|
className={CHECKBOX_CLASS}
|
|
/>
|
|
<span>
|
|
<strong>{permission.permission_name}</strong>
|
|
<small>
|
|
{code}
|
|
{permission.description
|
|
? ` · ${permission.description}`
|
|
: ""}
|
|
</small>
|
|
</span>
|
|
</label>
|
|
);
|
|
})}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|