- 通知中心改为游标分页 + 加载更多,历史通知不再被 50 条上限截断; 加载失败显示错误态与重试 - AI 流式请求 401 被登出时,登录页提示"登录已过期",不再无声踢出 - AI 附件/引用来源打开失败时给出明确错误提示,不再"点了没反应" - 新增 useDownload hook:统一导出/下载的防重复、loading 与成功/失败反馈; 接入学生/账单/房间/入住/费用五个页面的模板下载与导出按钮 - 学生页移除不检查响应状态的私有下载实现,统一走 downloadBlob
47 lines
1.3 KiB
TypeScript
47 lines
1.3 KiB
TypeScript
import { useCallback, useRef, useState } from 'react';
|
|
import { downloadBlob } from '../utils/download';
|
|
import { message } from '../ui/app-message';
|
|
|
|
export interface DownloadOptions {
|
|
/** 成功提示文案;默认「下载成功」 */
|
|
successMsg?: string;
|
|
/** 失败提示文案;默认使用接口返回的错误信息 */
|
|
errorMsg?: string;
|
|
}
|
|
|
|
/**
|
|
* 统一下载/导出状态:防重复点击 + 成功/失败反馈。
|
|
*
|
|
* 用法:
|
|
* const { downloading, run } = useDownload();
|
|
* <Button loading={downloading} onClick={() => run('/students/export', '名单.xlsx')}>
|
|
*/
|
|
export function useDownload() {
|
|
const [downloading, setDownloading] = useState(false);
|
|
const busyRef = useRef(false);
|
|
|
|
const run = useCallback(
|
|
async (endpoint: string, filename: string, options?: DownloadOptions) => {
|
|
if (busyRef.current) return;
|
|
busyRef.current = true;
|
|
setDownloading(true);
|
|
try {
|
|
await downloadBlob(endpoint, filename);
|
|
message.success(options?.successMsg ?? '下载成功');
|
|
} catch (error: unknown) {
|
|
message.error(
|
|
options?.errorMsg ?? (error instanceof Error ? error.message : '下载失败,请重试'),
|
|
);
|
|
} finally {
|
|
busyRef.current = false;
|
|
setDownloading(false);
|
|
}
|
|
},
|
|
[],
|
|
);
|
|
|
|
return { downloading, run };
|
|
}
|
|
|
|
export default useDownload;
|