feat: 任务轮询 + Token刷新容错 + 提交防抖 + 文件上传Hook (0.0.20)

### 任务状态轮询
- 新增 useTaskPolling hook:批量轮询非终态任务,递归 setTimeout + next_poll_ms 自适应间隔
- TaskHistory 集成批量轮询,OutputPreview 移除独立轮询改为状态转换监听
- batchTaskStatus 修复数组参数序列化(GET + 逗号拼接,避免 bracket 格式)
- 统一 POLLING_STATUSES 常量管理非终态状态

### Token 刷新容错
- 双轨刷新:主动续期(JWT exp 75% 时间点 setTimeout)+ 被动兜底(handle401)
- 刷新失败分级:永久失败(throw RefreshTokenExpiredError)→清token弹登录;临时失败(return null)→仅拒绝当前请求
- AppProvider 登录/自动登录/退出 启停主动刷新定时器

### 提交按钮防抖
- 2s 节流防抖("你点击的太快了")+ 二次确认弹窗("您已提交,确认要再次提交吗?")
- 修复 useAsyncMutation.execute 返回值判空(原 try/catch 死代码)

### 文件上传 Hook
- 新增 useFileUpload hook:封装 request.upload() 为 antd Upload 兼容 customRequest
- ImageInput/ImageListInput/AudioListInput 集成 customRequest
- uploadValidation beforeUpload 返回值修正(false→true)

### 其他
- AnnouncementDrawer 接入公告 API + EnumResolver
- billing/announcement/banner 服务模块完善
- CLAUDE.md 补充架构约定文档
This commit is contained in:
2026-06-12 19:03:36 +08:00
parent 4237dcbaf6
commit 9e8c5b7109
22 changed files with 787 additions and 149 deletions

View File

@@ -7,6 +7,7 @@ import { Upload } from 'antd';
import { InboxOutlined } from '@ant-design/icons';
import type { UploadFile } from 'antd/es/upload';
import type { WidgetProps } from './types';
import { useFileUpload } from '@/hooks/use-api';
const { Dragger } = Upload;
@@ -16,6 +17,8 @@ export function AudioListInput({ value, onChange, disabled, config }: WidgetProp
const maxCount = (config.maxFiles as number) || 10;
const filters = config.fileFilter as string[] | undefined;
const { customRequest } = useFileUpload();
return (
<Dragger
multiple
@@ -25,9 +28,10 @@ export function AudioListInput({ value, onChange, disabled, config }: WidgetProp
: '.wav,.mp3,.m4a,.flac'
}
fileList={fileList}
customRequest={customRequest}
onChange={({ fileList: newList }) => onChange?.(newList)}
disabled={disabled}
beforeUpload={() => false}
beforeUpload={() => true}
maxCount={maxCount}
>
<p className="ant-upload-drag-icon">