feat: 书库导入导出/图片变体/书籍搜索/小组件运行时等

新增:
- 书库导入导出(library_import/library_export)及测试
- 图片变体生成(image_variants)与响应式图片(responsiveImage)
- 书籍搜索(bookSearch)+ BookSearch/LibrarySearchGrid 组件
- 小组件运行时(widgetRuntime)与静态检查(widgetLint)
- 上传缓存中间件(upload_cache)与字体 CSS 提取脚本

其它:
- 后端 handlers/services 全量调整
- 前端页面、组件、库函数与配置更新
This commit is contained in:
2026-10-01 03:06:05 +08:00
parent 7fbd6ba699
commit ff2ab286fb
141 changed files with 7527 additions and 1407 deletions

View File

@@ -44,6 +44,38 @@ export function isOwner(role?: string | null): boolean {
return role === ROLES.OWNER;
}
// 后台功能点权限码(与后端 service.Perm* 一致)。
// 渠道类权限可由超管/站长账号级授予任意账号;/me 下发的 perms 为
// 角色默认 ∪ 账号授予的生效集合,前端只做显隐判定,最终权限以后端为准。
export const PERMS = {
ANNOUNCEMENTS: "announcements",
PAGES: "pages",
LIBRARY: "library",
ADS: "ads",
MESSAGES: "messages",
} as const;
export type PermKey = (typeof PERMS)[keyof typeof PERMS];
/** 可账号级授予的渠道权限(与后端 GrantablePerms 一致) */
export const CHANNEL_PERMS = [
PERMS.ANNOUNCEMENTS,
PERMS.PAGES,
PERMS.LIBRARY,
PERMS.ADS,
] as const;
/** 渠道权限展示元信息(角色与账号弹窗/后台导航共用) */
export const PERM_META: Record<
(typeof CHANNEL_PERMS)[number],
{ label: string; desc: string }
> = {
[PERMS.ANNOUNCEMENTS]: { label: "公告管理", desc: "发布、编辑、置顶与删除站点公告" },
[PERMS.PAGES]: { label: "单页管理", desc: "创建与维护站点单页(/p/:slug)" },
[PERMS.LIBRARY]: { label: "书库管理", desc: "管理书库条目、章节与文件" },
[PERMS.ADS]: { label: "广告与赞助", desc: "管理广告位与赞助配置、审批投放" },
};
/** 站长/超管:群聊监管旁路(可见全部群含私聊、撤回任意消息) */
export function canOverseeChat(role?: string | null): boolean {
return role === ROLES.OWNER || role === ROLES.SUPER_ADMIN;
@@ -59,10 +91,23 @@ export interface RoleUserLike {
role?: string | null;
board_ids?: number[] | null;
can_manage_messages?: boolean | null;
/** 生效权限码(/me 下发;角色默认 ∪ 账号授予) */
perms?: string[] | null;
/** 是否至少管理一个群(/me 可带;后台入口用) */
chat_admin_room_count?: number | null;
}
/** 是否拥有某后台功能点(依据 /me 下发的生效权限码;最终以后端校验为准) */
export function hasPerm(user: RoleUserLike | null | undefined, perm: string): boolean {
if (!user) return false;
return (user.perms ?? []).includes(perm);
}
/** 是否拥有任一渠道权限(后台准入判定用) */
export function hasAnyChannelPerm(user: RoleUserLike | null | undefined): boolean {
return CHANNEL_PERMS.some((p) => hasPerm(user, p));
}
/**
* 能否管理指定板块的内容(帖子/评论的编辑删除审核):
* 管理员及以上不限板块;板块管理员仅限被授权板块