跳转至

Infinite Canvas 前台(用户端)

源码:src/infinitecanvas/ 产品域名:canvas.harness.local(ACK)/ canvas.localhost(K3s) 本地开发:make canvas-dev → http://127.0.0.1:5174

面向终端用户的图现 AI 前台:首页营销、无限二创画布、各 AI 工作台生图、我的资产库与账号中心。

技术栈

选型
框架 React + TypeScript + Vite
路由 react-router-domsrc/App.tsx
无限画布 @xyflow/reactCanvasPage / CanvasFlow
图片交互编辑 konva + react-konva(裁剪 / 标注 / 画笔弹层)
HTTP shared/api/backendHttpClient.tsfetch + JWT)
包管理 pnpm(目录内 package.json
质量门禁 make canvas-check:typecheck / build / test

目录结构(要点)

src/infinitecanvas/
├── src/
│   ├── App.tsx                 # 路由表
│   ├── pages/                  # 页面入口
│   ├── components/
│   │   ├── site/               # 顶栏导航
│   │   ├── canvas/             # 无限二创画布控件
│   │   ├── ai-workspace/       # AI 工作区共用壳
│   │   ├── layout/             # LeftNav / AddNodePanel 等
│   │   └── <feature>/          # 各业务侧栏(虚拟影棚、模特生成等)
│   ├── context/                # Auth / CanvasProvider
│   ├── shared/api/             # backend / 任务 / 计费 / 存储
│   ├── constants/backend-api.ts
│   └── styles/
├── vite.config.ts              # 端口 5174;/api 同源代理到 :8001
└── .env.example

产品导航与路由

路由定义:src/App.tsx。导航文案:src/components/site/site-nav-config.ts

/ 首页外,功能页均经 ProtectedRoute + 懒加载。

分组 路径 页面 说明
公开 / HomePage 营销首页
顶栏 /canvas CanvasPage 无限二创(无限画布)
我的工作台 /hot-shoot HotShootPage 虚拟影棚
/main-image MainImagePage 电商主图
/detail-image DetailImagePage 电商详情图
/model-gen ModelGenPage 真人模特生成
爆款工厂 /hot-template HotTemplatePage 爆款模板
/scene-replace SceneReplacePage 场景替换
/hot-replicate HotReplicatePage 爆款复刻
其他 /single-model / /double-model 换模特单人 / 双人
用户 /assets-library AssetsLibraryPage 我的资产库
/account AccountPage 账号中心(配额 / 充值 / 订单)
flowchart LR
  Home["/"] --> Canvas["/canvas 无限二创"]
  Home --> Workbench["工作台 / 爆款工厂"]
  Workbench --> AiShell["AiWorkspacePage 壳"]
  Canvas --> Flow["CanvasFlow + LeftNav"]
  Workbench --> Tasks["POST /api/user/tasks/generate"]
  Flow --> CanvasAPI["/api/canvas 等"]

两类 UI 模式

1. 无限二创(画布)

  • 入口:pages/CanvasPage.tsxCanvasProvider + CanvasFlow
  • 首页「开始复刻」HomePage 无限二创区块先打开 CanvasEntryModal(文件夹 → 项目选择/新建),再跳转 /canvas?projectId=…;画布 hydration 后由 OpenProjectFromQuery 调用 openProject(一项目=一画布,不另建画布实体)
  • 本地冒烟路径:未登录点「开始复刻」→ 登录弹窗 → 登录成功后出现选择器 → 新建文件夹/项目或点已有项目 → 进入画布且 URL 短暂带 projectId(随后 replace 清除)→ 画布加载对应云端文档;失败时 alert,仍可继续用本地草稿
  • 左侧挂件:components/layout/LeftNav.tsx(「+」打开 AddNodePanel
  • 节点 / 边 / AI 输入框:components/canvas/*context/canvas/*
  • 与站点顶栏并存:SiteHeaderactiveLabel="无限二创"
  • 图片节点工具:见下方「图片节点工具」与 画布图片工具设计

2. AI 工作区(功能页)

  • 共用壳:components/ai-workspace/AiWorkspacePage.tsx (左侧配置栏 + 右侧预览 / 结果)
  • 各业务侧栏:VirtualStudioSidePanelModelGenSidePanelSceneReplaceSidePanel
  • 生图统一走 shared/api/userTaskApi.tsrunUserGenerateTask()
  • 响应含 image_urls → 同步展示
  • 响应含 job_id → 轮询 GET /api/user/batch-jobs/{job_id}

调用后端 API

基地址

src/constants/backend-api.tsgetBackendApiBase()

场景 行为
设置了 VITE_BACKEND_API_URL(或兼容名 VITE_IMAGE_API_URL 使用该根地址(直连,需 CORS)
未配置 / 留空 同源:请求 {origin}/api/...

默认走同源反代,与 agent / admin / demo 一致:

  • 本地 Vite:vite.config.ts/api(及 /wepayapi)代理到 https://tuxianai.com(经 Ingress → backend);本机 backend 可设 VITE_DEV_PROXY_TARGET=http://127.0.0.1:8001
  • ACK / K3s:Ingress 将 /api → backend,/api/storage → storage,/wepayapi → backend(微信 Native 回调)

Docker 构建默认不注入远端 URL(DockerfileVITE_BACKEND_API_URL 默认为空)。切勿构建时注入 https://backend.tuxianai.com,否则浏览器会跨域直连子域。

HTTP 客户端

shared/api/backendHttpClient.ts

  • 请求:{base}/api{path}base 为空时即为 /api{path}),附带 Authorization: Bearer <token>
  • 解析包络:{ code, message, data }code !== 200 抛错

常用模块:

模块 用途
authApi.ts 登录 / 短信
userTaskApi.ts 任务类型、生图、batch-jobs、预览 Prompt
productCatalogApi.ts 品类 / 模板目录等
billingApi.ts 计费 / 套餐
storageApi.ts 上传(经 backend /api/user/storage

与 Ingress 的关系(ACK / K3s)

画布站点(canvas.tuxianai.com / tuxianai.com / www.tuxianai.com / canvas.localhost):

  • / → infinitecanvas 静态资源
  • /api/storage → storage
  • /api → backend(含 /api/canvas/api/auth 等)

本地开发前端(:5174)默认请求 /api/...,经 Vite 代理到本机 backend。

认证

  • AuthProvider + localStorage Token(见 shared/types/api.tsAUTH_TOKEN_KEY
  • 未登录访问保护路由时走 ProtectedRoute / 登录引导(LoginPromptProvider

图片节点工具

选中图片节点后,顶部 ImageNodeToolbar 提供两类能力(不是 xyflow 内置功能):

工具 实现 说明
裁剪 / 标注 / 画笔 Konva 弹层 完成后上传并新建结果节点(源图不变)
抠图 / 去水印 / 扩图 画布生图 API mode=single + 固定提示词;结果进新建节点
下载 / 放大预览 浏览器直链 不经编辑管线
加入 Agent 引用写入 AI 输入框 打开 Agent 面板

调度入口:context/canvas/hooks/useImageToolActions.ts。 跨域读像素:远程图经 POST /api/canvas/assets/proxy-image 代拉(utils/image-tool-processor.tsresolveEditableImageUrl)。

flowchart LR
  toolbar[ImageNodeToolbar]
  toolbar -->|crop annotate brush| konva[ImageKonvaEditorModal]
  konva --> newNode[新建结果图片节点]
  toolbar -->|cutout watermark outpaint| gen["POST /api/canvas/generate"]
  gen --> newNode
  source[源图片节点] -.->|不变| source

详细设计见 canvas-image-tools.md

质量与约束

  • 有效行数:与仓库统一口径(check_file_length.py / ESLint,见 质量门禁技术债
  • 勿在组件内直接 fetch 到任意域名;新增接口优先落在 shared/api/
  • 无 agent/admin 的 features import 限制,但仍建议按业务目录拆分,避免超大单文件

相关文档