feat(ops): v4.0.7 HQ 活动图快链与勾选导出
HQ 指定一张活动图为勾选主合伙人合成 PNG/zip;城市合伙人页增加快链与单下/导出。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -58,6 +58,54 @@ export async function request<T>(path: string, options: RequestInit = {}): Promi
|
||||
return json.data as T;
|
||||
}
|
||||
|
||||
function parseDownloadFileName(header: string | null, fallback: string): string {
|
||||
if (!header) return fallback;
|
||||
const star = /filename\*=(?:UTF-8''|utf-8'')([^;]+)/i.exec(header);
|
||||
if (star?.[1]) {
|
||||
try {
|
||||
return decodeURIComponent(star[1].trim());
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
const quoted = /filename="([^"]+)"/i.exec(header);
|
||||
if (quoted?.[1]) return quoted[1];
|
||||
const plain = /filename=([^;]+)/i.exec(header);
|
||||
return plain?.[1]?.trim() || fallback;
|
||||
}
|
||||
|
||||
/** Binary download (PNG / zip). JSON error bodies are surfaced as Error. */
|
||||
export async function requestDownload(path: string, options: RequestInit = {}, fallbackName: string) {
|
||||
const headers: Record<string, string> = {
|
||||
'X-Client-App': CLIENT_APP,
|
||||
...(options.headers as Record<string, string>),
|
||||
};
|
||||
if (options.body && !headers['Content-Type']) headers['Content-Type'] = 'application/json';
|
||||
const token = getToken();
|
||||
if (token) headers.Authorization = `Bearer ${token}`;
|
||||
|
||||
const res = await fetch(`${apiBase}${path}`, { ...options, headers });
|
||||
const contentType = res.headers.get('content-type') || '';
|
||||
if (contentType.includes('application/json')) {
|
||||
const json = (await res.json()) as { code?: number; message?: string };
|
||||
if (json.code === 401) {
|
||||
clearAuth();
|
||||
window.location.href = '/login';
|
||||
throw new Error('未登录');
|
||||
}
|
||||
throw new Error(json.message || '下载失败');
|
||||
}
|
||||
if (!res.ok) throw new Error(`下载失败(HTTP ${res.status})`);
|
||||
const blob = await res.blob();
|
||||
const fileName = parseDownloadFileName(res.headers.get('content-disposition'), fallbackName);
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = fileName;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
export type Paginated<T> = {
|
||||
items: T[];
|
||||
total: number;
|
||||
|
||||
Reference in New Issue
Block a user