chore: 文档更新 + 代码去重 + ESLint 修复,准备 0.0.16
- CHANGELOG: 新增 0.0.16 版本条目(模型输入栏重构/统一页面调度/依赖联动) - TODO: 标记账户信息页为已完成,拆分未完成页面项 - ARCHITECTURE: 新增 PageDispatcher 叠加层说明 + OPEN_PAGE 事件 - 代码去重:runFieldChecks(validators) + createImageBeforeUpload(uploadValidation) - ESLint: DependentFormItem 中 Form.useWatch 移到组件顶层(修复 rules-of-hooks) - ESLint: message.success / async handleSubmit 加 void(修复 no-floating-promises) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// 可拖拽调整三栏宽度,所有数据请求在登录后发送
|
||||
// ============================================================
|
||||
|
||||
import { createContext, useContext, useState, useCallback, useRef, useEffect, useMemo } from 'react';
|
||||
import React, { createContext, useContext, useState, useCallback, useRef, useEffect, useMemo } from 'react';
|
||||
import { theme as antTheme, Empty } from 'antd';
|
||||
|
||||
import { useAppContext } from '@/components/AppProvider';
|
||||
|
||||
@@ -75,12 +75,17 @@ function DependentFormItem({
|
||||
onChange?: (value: unknown) => void;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
const depValues = (field.dependsOn || []).map((depName) =>
|
||||
Form.useWatch(depName, form),
|
||||
);
|
||||
// Form.useWatch 必须在组件顶层无条件调用(不能放 .map() 或条件分支中)。
|
||||
// dependsOn 长度由 param_schema 约束(当前 API 最多 2 个),
|
||||
// 预留 3 个固定槽位覆盖未来扩展;无依赖时 watch 空串 → 返回 undefined。
|
||||
const deps = field.dependsOn || [];
|
||||
const d0 = Form.useWatch(deps[0] || '', form);
|
||||
const d1 = Form.useWatch(deps[1] || '', form);
|
||||
const d2 = Form.useWatch(deps[2] || '', form);
|
||||
const depValues = [d0, d1, d2].slice(0, deps.length);
|
||||
|
||||
const isDepDisabled =
|
||||
field.dependsOn?.some((_, i) => isValueEmpty(depValues[i])) ?? false;
|
||||
deps.some((_, i) => isValueEmpty(depValues[i]));
|
||||
|
||||
const effectiveDisabled = formItemDisabled || isDepDisabled;
|
||||
const effectiveConfig = effectiveDisabled
|
||||
@@ -115,7 +120,7 @@ export function ModelInputForm() {
|
||||
// 提交突变 Hook
|
||||
const { execute: submitTask, loading: submitting, errorMessage } = useSubmitTask({
|
||||
onSuccess: useCallback((_data: TaskInfoItemResponseBody) => {
|
||||
message.success('任务已提交');
|
||||
void message.success('任务已提交');
|
||||
emit(EVENTS.TASK_SUBMITTED);
|
||||
}, []),
|
||||
});
|
||||
@@ -147,7 +152,7 @@ export function ModelInputForm() {
|
||||
form.setFieldsValue(initialValues);
|
||||
setTaskTag('');
|
||||
}
|
||||
}, [selectedModel?.id, initialValues]);
|
||||
}, [selectedModel?.id, initialValues, selectedModel, form]);
|
||||
|
||||
// 重置参数(回到默认值 + 清空标签)
|
||||
const handleReset = useCallback(() => {
|
||||
@@ -384,7 +389,7 @@ export function ModelInputForm() {
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<SendOutlined />}
|
||||
onClick={handleSubmit}
|
||||
onClick={() => void handleSubmit()}
|
||||
loading={submitting}
|
||||
disabled={!isLoggedIn || !selectedModel}
|
||||
size="large"
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
// ============================================================
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { Upload, Switch, Space, Typography, message } from 'antd';
|
||||
import { Upload, Switch, Space, Typography } from 'antd';
|
||||
import { UploadOutlined } from '@ant-design/icons';
|
||||
import type { UploadFile } from 'antd/es/upload';
|
||||
import type { WidgetProps } from './types';
|
||||
import { createImageBeforeUpload } from './uploadValidation';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
@@ -81,18 +82,7 @@ export function ImageInput({ value, onChange, disabled, config }: WidgetProps) {
|
||||
}
|
||||
}}
|
||||
disabled={isUploadDisabled}
|
||||
beforeUpload={(file) => {
|
||||
const isImage = file.type.startsWith('image/');
|
||||
if (!isImage) {
|
||||
message.error('只能上传图片文件');
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
if (file.size / 1024 / 1024 >= maxSizeMb) {
|
||||
message.error(`图片大小不能超过 ${maxSizeMb}MB`);
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
return false;
|
||||
}}
|
||||
beforeUpload={createImageBeforeUpload(maxSizeMb)}
|
||||
>
|
||||
{fileList.length < 1 && (
|
||||
<div style={{ opacity: isUploadDisabled ? 0.4 : 1 }}>
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
// 用于图生图模型的多图输入场景
|
||||
// ============================================================
|
||||
|
||||
import { Upload, message } from 'antd';
|
||||
import { Upload } from 'antd';
|
||||
import { InboxOutlined } from '@ant-design/icons';
|
||||
import type { UploadFile } from 'antd/es/upload';
|
||||
import type { WidgetProps } from './types';
|
||||
import { createImageBeforeUpload } from './uploadValidation';
|
||||
|
||||
const { Dragger } = Upload;
|
||||
|
||||
@@ -28,18 +29,7 @@ export function ImageListInput({ value, onChange, disabled, config }: WidgetProp
|
||||
fileList={fileList}
|
||||
onChange={({ fileList: newList }) => onChange?.(newList)}
|
||||
disabled={disabled}
|
||||
beforeUpload={(file) => {
|
||||
const isImage = file.type.startsWith('image/');
|
||||
if (!isImage) {
|
||||
message.error('只能上传图片文件');
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
if (file.size / 1024 / 1024 >= maxSizeMb) {
|
||||
message.error(`图片大小不能超过 ${maxSizeMb}MB`);
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
return false;
|
||||
}}
|
||||
beforeUpload={createImageBeforeUpload(maxSizeMb)}
|
||||
maxCount={maxCount}
|
||||
>
|
||||
<p className="ant-upload-drag-icon">
|
||||
|
||||
26
src/pages/home/components/useUI/uploadValidation.ts
Normal file
26
src/pages/home/components/useUI/uploadValidation.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
// ============================================================
|
||||
// uploadValidation — 文件上传前校验工具
|
||||
// ImageInput / ImageListInput 共用
|
||||
// ============================================================
|
||||
|
||||
import { Upload, message } from 'antd';
|
||||
import type { RcFile } from 'antd/es/upload';
|
||||
|
||||
/**
|
||||
* 创建图片上传前的类型 & 大小校验函数
|
||||
* @param maxSizeMb 最大文件大小(MB),默认 10
|
||||
*/
|
||||
export function createImageBeforeUpload(maxSizeMb: number = 10) {
|
||||
return (file: RcFile) => {
|
||||
const isImage = file.type.startsWith('image/');
|
||||
if (!isImage) {
|
||||
message.error('只能上传图片文件');
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
if (file.size / 1024 / 1024 >= maxSizeMb) {
|
||||
message.error(`图片大小不能超过 ${maxSizeMb}MB`);
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user