feat(attach): 付费附件游客跳登录,积分数独立价签并升级下载交互
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1066,6 +1066,45 @@ export function postAttachmentDownloadURL(postId: number | string, attId: number
|
||||
return `/api/posts/${postId}/attachments/${attId}/download`;
|
||||
}
|
||||
|
||||
function filenameFromDisposition(header: string | null, fallback: string): string {
|
||||
if (!header) return fallback;
|
||||
const star = /filename\*\s*=\s*UTF-8''([^;]+)/i.exec(header);
|
||||
if (star?.[1]) {
|
||||
try {
|
||||
return decodeURIComponent(star[1]);
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
const quoted = /filename\s*=\s*"([^"]+)"/i.exec(header);
|
||||
if (quoted?.[1]) return quoted[1];
|
||||
const plain = /filename\s*=\s*([^;]+)/i.exec(header);
|
||||
if (plain?.[1]) return plain[1].trim();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/** 下载帖子附件:走 fetch 以便处理 401/402 JSON,避免整页打开错误文档 */
|
||||
export async function apiDownloadPostAttachment(
|
||||
postId: number | string,
|
||||
attId: number,
|
||||
fallbackName: string
|
||||
): Promise<{ blob?: Blob; filename?: string; error?: string; status?: number }> {
|
||||
const res = await fetchWithRefresh(postAttachmentDownloadURL(postId, attId), {
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
headers: clientHeaders(),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const data = (await res.json().catch(() => ({}))) as { error?: string };
|
||||
return { error: data.error || "下载失败", status: res.status };
|
||||
}
|
||||
const blob = await res.blob();
|
||||
return {
|
||||
blob,
|
||||
filename: filenameFromDisposition(res.headers.get("Content-Disposition"), fallbackName),
|
||||
};
|
||||
}
|
||||
|
||||
export async function apiVotePoll(postId: string, options: number[]) {
|
||||
const res = await fetchWithRefresh(`/api/posts/${postId}/poll/vote`, {
|
||||
method: "POST",
|
||||
|
||||
Reference in New Issue
Block a user