feat: 实现业务首页(三栏布局 + 轮播图)

## 首页整体架构
  - 新增 src/pages/home/ — 完整首页模块(10 个组件)
    - HomePage / HomeContent:三栏弹性布局,拖动分隔条调整列宽
    - BannerCarousel:顶部轮播图(antd Carousel,2280×90 长条图片适配)
    - LeftPanel:模型选择器(Menu 分组) + 任务记录(Table 分页),纵向拖拽调整比例
    - CenterPanel / ModelInputForm:动态表单,根据模型 param_schema/ui_config 渲染控件
    - RightPanel / OutputPreview:任务输出预览(Image/Video)
  - 新增 Layout 组件:h-screen flex 布局,首页 Banner + NavBar + Outlet

  ## 数据层(数据与视图分离)
  - 新增 src/services/modules/ — API 模块(banner/models/task/auth)
    - TaskAPI 静态方法,TaskInfoItemResponseBody 判别联合类型
    - ModelAPI / BannerAPI,const 断言路由常量
  - 新增 src/hooks/use-async.ts — 通用异步 Hook
    - useAsyncData:竞态处理、条件请求(enabled)、自动错误日志
    - useAsyncMutation:数据变更,onSuccess/onError
    - getErrorMessage():RequestErrorType → 可读错误信息
  - 新增 src/hooks/use-api.ts — 业务 Hook
    - useBannerList / useModelList / useTaskList / useTaskDetail / useSubmitTask

  ## 主题与交互
  - 重写暗色令牌:科技感蓝紫(#080C24 底 / #0F1340 面板 / #2A3278 边框)
  - 三栏分隔线:token.colorBorderSecondary 常驻 + 手柄竖线 hover 高亮
  - 左面板纵向拖拽:模型区/任务区可调比例,ResizeObserver 自适应
  - 暗色/亮色同步:tokens.ts + antd-theme.ts + globals.css 三处一致

  ## 基础设施
  - EventBus 新增 TASK_SUBMITTED 事件(替代 Context 数字递增 hack)
  - HomeContext 状态管理(选中模型、任务分页、折叠状态)
  - 所有组件边框使用 token.colorBorderSecondary(主题自适应)
  - Table 滚动高度 ResizeObserver 动态计算(修复分页器遮挡)
This commit is contained in:
2026-06-05 16:24:17 +08:00
parent 6204c14b88
commit 1da95eaef3
31 changed files with 2639 additions and 470 deletions

View File

@@ -0,0 +1,87 @@
import {get} from '../request';
// ---------- 路由常量 ----------
const ModelsUrlObj = {
modelList: '/api/v1/models',
getModelInfo: '/api/v1/models/{model_id}',
estimateCost: '/api/v1/models/{model_id}/estimate'
} as const;
// ---------- 类型 ----------
/** 模型类别 */
export type ModelCategory = 'img2img' | 'txt2img' | 'img2video' | 'txt2audio';
/** 模型类别中文映射 */
export const MODEL_CATEGORY_LABELS: Record<ModelCategory, string> = {
img2img: '图生图',
txt2img: '文生图',
img2video: '图生视频',
txt2audio: '文生音频',
};
/**
* 查询可用模型的请求参数
*/
export interface ModelsListReqeustParams {
provider_name?: string;
category?: ModelCategory;
page: number;
page_size: number;
}
/**
* 查询可用模型的响应体
*/
export interface ModelsListResponseBody {
id: string;
name: string;
provider_name: string;
model_type: string;
category_name: string;
status: string;
priority: number;
response_mode: string;
pricing_config: Record<string, unknown>;
param_schema: string[];
quota_config: Record<string, unknown>;
ui_config: Record<string, unknown>;
meta_config: Record<string, unknown>;
constraints_config: Record<string, unknown>;
expires_at: string;
created_at: string;
updated_at: string;
}
/**
* 模型信息请求参数
*/
export interface ModelInfoRequestParams {
model_id: string;
}
/** 模型详情响应体(与列表项结构一致) */
export type ModelInfoResponseBody = ModelsListResponseBody;
// ---------- API ----------
export class ModelAPI {
/**
* 获取可用模型列表
* GET /api/v1/models
*/
static fetchModels(params: ModelsListReqeustParams): Promise<ModelsListResponseBody[]> {
return get<ModelsListResponseBody[]>(ModelsUrlObj.modelList, params as unknown as Record<string, unknown>);
}
/**
* 获取单个模型详情
* GET /api/v1/models/:id
*/
static fetchModelInfo(modelId: string): Promise<ModelInfoResponseBody> {
const url = ModelsUrlObj.getModelInfo.replace('{model_id}', modelId);
return get<ModelInfoResponseBody>(url);
}
}