Files
jiang13-bbs/frontend/lib/postFile.ts
freefire 61bf9fb48c feat(attach): 附件可配置限额、流式落盘与分阶段上传
管理端可配类型/体积;上传改流式避免整文件进内存;发帖先选再传并拦截未上传提交;提高 Next proxy 体积上限。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 07:33:16 +08:00

59 lines
1.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 帖子附件客户端校验(与后端 setting / fileallow 对齐;安全边界仍在 Go) */
export const FILE_MAX_MB_DEFAULT = 20;
export const FILE_MAX_COUNT_DEFAULT = 10;
export function normalizeExt(nameOrExt: string): string {
const base = nameOrExt.includes("/")
? nameOrExt.split(/[/\\]/).pop() || ""
: nameOrExt;
const i = base.lastIndexOf(".");
const ext = (i >= 0 ? base.slice(i + 1) : base).trim().toLowerCase();
return ext.replace(/[^a-z0-9]/g, "").slice(0, 16);
}
export function buildAcceptAttr(exts: string[], limit: boolean): string | undefined {
if (!limit) return undefined;
if (!exts.length) return undefined;
return exts.map((e) => `.${e}`).join(",");
}
export function isAllowedPostFileName(
name: string,
opts: { limit: boolean; exts: string[] }
): boolean {
if (!opts.limit) return true;
const ext = normalizeExt(name);
if (!ext) return false;
return opts.exts.includes(ext);
}
export function formatMB(n: number): string {
return `${n}MB`;
}
export type PostFileRejectReason = "size" | "type" | "count" | null;
export function rejectPostFile(
file: File,
opts: {
limit: boolean;
exts: string[];
maxMB: number;
maxCount: number;
currentCount: number;
}
): { reason: PostFileRejectReason; message?: string } {
if (opts.currentCount >= opts.maxCount) {
return { reason: "count", message: `最多 ${opts.maxCount} 个附件` };
}
const maxBytes = opts.maxMB * 1024 * 1024;
if (file.size > maxBytes) {
return { reason: "size", message: `附件不能超过 ${opts.maxMB}MB` };
}
if (!isAllowedPostFileName(file.name, opts)) {
return { reason: "type", message: "不支持该附件格式" };
}
return { reason: null };
}