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

@@ -19,6 +19,7 @@ import { UploadOutlined } from '@ant-design/icons';
import type { UploadFile } from 'antd/es/upload';
import type { WidgetProps } from './types';
import { createImageBeforeUpload } from './uploadValidation';
import { useFileUpload } from '@/hooks/use-api';
const { Text } = Typography;
@@ -36,6 +37,9 @@ export function ImageInput({ value, onChange, disabled, config }: WidgetProps) {
const maxSizeMb = (config.maxFileSizeMb as number) || 10;
const hasEnableSwitch = (config.enableSwitch as boolean) || false;
// 文件上传 Hook提供 customRequest → antd Upload 集成)
const { customRequest } = useFileUpload();
// 有 enable_switch 时默认禁用,需手动开启
const [switchOn, setSwitchOn] = useState(!hasEnableSwitch);
const isUploadDisabled = disabled || !switchOn;
@@ -75,6 +79,7 @@ export function ImageInput({ value, onChange, disabled, config }: WidgetProps) {
maxCount={1}
accept={buildAccept(config.fileFilter as string[] | undefined)}
fileList={fileList}
customRequest={customRequest}
onChange={({ fileList: newList }) => {
// 仅当开关开启时上报文件变化
if (switchOn || !hasEnableSwitch) {