feat(admin): batch ops, transfer, watermark, usage and qr share pages

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-20 21:10:30 +08:00
parent 618d1d796c
commit f08d68bebf
31 changed files with 2717 additions and 34 deletions
+39
View File
@@ -0,0 +1,39 @@
/**
* 分享链接与二维码纯逻辑(P4a Task 9,依赖注入 qrcode 实现供 vitest 覆盖)
*
* - viewer URL:VITE_VIEWER_BASE + /a/{publicToken}(viewer 路由
* /a/:token;base 缺省兜底本机 dev 5175,尾斜杠容忍)
* - 二维码:node-qrcode canvas 渲染;实现经参数注入(单测不拉真库),
* 组件侧默认传 QRCode.toCanvas
*/
/** viewer 部署基址(缺省兜底本机 dev) */
export const VIEWER_BASE_FALLBACK = 'http://127.0.0.1:5175'
/** 部署基址 + 公开令牌 → viewer 相册页 URL(尾斜杠容忍) */
export function buildViewerAlbumUrl(base: string, publicToken: string): string {
return `${base.replace(/\/+$/, '')}/a/${publicToken}`
}
/** 环境基址(VITE_VIEWER_BASE 缺省兜底;Vite 注入 import.meta.env) */
export function viewerBaseFromEnv(env: { VITE_VIEWER_BASE?: string }): string {
const base = env.VITE_VIEWER_BASE?.trim()
return base && base !== '' ? base : VIEWER_BASE_FALLBACK
}
/** 二维码单点绘制函数(注入边界:组件包 QRCode.toCanvas,单测传假实现——
@types/qrcode 的 callback 重载使整模块注入不可赋值,收窄到本签名) */
export type QrDraw = (
canvas: HTMLCanvasElement,
text: string,
options: { width: number; margin: number }
) => Promise<unknown> | void
/** URL → 二维码 canvas(组件 watch 相册变化时调用) */
export async function renderShareQr(
canvas: HTMLCanvasElement,
url: string,
draw: QrDraw
): Promise<void> {
await draw(canvas, url, { width: 200, margin: 2 })
}