| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- import { Notify, platformIsAIO, Toast } from '@/platform/index';
- import { useShowScanCode } from '@/composables/useShowScanCode';
- export interface DownloadFromUrlOptions {
- /** 保存时的文件名;不传则从响应头或 URL 路径推断 */
- filename?: string;
- /** 传给 fetch 的额外配置(如 credentials、headers) */
- fetchInit?: RequestInit;
- }
- function filenameFromContentDisposition(header: string | null): string | undefined {
- if (!header) return;
- const utf8 = /filename\*=UTF-8''([^;\s]+)/i.exec(header);
- if (utf8?.[1]) {
- try {
- return decodeURIComponent(utf8[1].replace(/['"]/g, ''));
- } catch {
- return utf8[1];
- }
- }
- const plain = /filename\s*=\s*("?)([^";\n]+)\1/i.exec(header);
- return plain?.[2];
- }
- function filenameFromUrl(url: string): string {
- try {
- const path = new URL(url, typeof location !== 'undefined' ? location.href : undefined).pathname;
- const seg = path.split('/').filter(Boolean).pop();
- return seg || 'download';
- } catch {
- return 'download';
- }
- }
- /**
- * 根据文件 URL 下载到本地(通过 fetch 取 Blob 后触发浏览器保存)。
- * 跨域资源需服务端允许 CORS,否则 fetch 会失败。
- */
- export function downloadFromUrl(url: string, options?: DownloadFromUrlOptions): Promise<void> {
- return (async () => {
- const res = await fetch(url, options?.fetchInit);
- if (!res.ok) throw new Error(`下载失败: ${res.status} ${res.statusText}`);
- const blob = await res.blob();
- const filename = options?.filename ?? filenameFromContentDisposition(res.headers.get('content-disposition')) ?? filenameFromUrl(url);
- const objectUrl = URL.createObjectURL(blob);
- try {
- const a = document.createElement('a');
- a.href = objectUrl;
- a.download = filename;
- a.rel = 'noopener';
- document.body.appendChild(a);
- a.click();
- a.remove();
- } finally {
- URL.revokeObjectURL(objectUrl);
- }
- })();
- }
- export async function printFromUrl(url: string, options?: { rollback?: boolean; title?: string }) {
- let closed = false;
- if (platformIsAIO()) {
- try {
- try {
- await Bridge.print({ url });
- } catch {
- window.AIO?.print?.(url);
- }
- } catch (e) {
- Notify.warning(`打印失败 (${e.message})`, { duration: 1500 });
- closed = true;
- }
- } else {
- try {
- const current = window.open(url, '_blank');
- closed = current.closed;
- current.location.href;
- } catch (e) {
- Notify.warning(`无法打开窗口 (${e.message})`, { duration: 1500 });
- closed = true;
- }
- }
- if (closed && options?.rollback) {
- Toast.close();
- await useShowScanCode().open({ url, title: options?.title });
- }
- }
|