# uipad **Repository Path**: coderzhouyu/uipad ## Basic Information - **Project Name**: uipad - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-11 - **Last Updated**: 2026-07-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # UIPad 产品设计工具:管理页面与版本控制,AI 生成 UI 截图,拖拽排列到 Excalidraw 画板上。 ## 功能特性 - **文档管理**:PRD / 场景文档 / 外部链接,支持富文本编辑 - **页面管理**:版本控制,支持多版本切换 - **AI 生成**:基于 Prompt 自动生成 UI 截图(OpenAI 兼容 API) - **画板编辑**:Excalidraw 画布,拖拽排列页面截图 - **参考图**:上传或引用已有版本作为生成参考 - **访问密码**:首次访问需输入密码,验证后 60 天内免再次输入 ## 开发环境 ```bash # 安装依赖 npm install # 启动开发服务器(同时启动 client + server) npm run dev ``` - Client: http://localhost:5173 - Server: http://localhost:3001 ## 数据库初始化 项目使用 MySQL 8.0,首次使用需初始化数据库。 ### Docker Compose 部署(自动初始化) ```bash docker compose up -d ``` 首次启动 MySQL 容器时会自动执行 `schema.sql` 创建表结构,无需手动操作。 ### 手动初始化 ```bash # 1. 创建数据库 mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS uipad CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" # 2. 执行建表脚本 mysql -u root -p uipad < server-spring/src/main/resources/schema.sql ``` ### MySQL 环境变量 | 变量 | 默认值 | 说明 | |------|--------|------| | `MYSQL_HOST` | `localhost` | MySQL 主机地址 | | `MYSQL_PORT` | `3306` | MySQL 端口 | | `MYSQL_DATABASE` | `uipad` | 数据库名 | | `MYSQL_USER` | `root` | 数据库用户 | | `MYSQL_PASSWORD` | `root` | 数据库密码 | | `MYSQL_ROOT_PASSWORD` | `root123` | MySQL root 密码(仅 Docker Compose) | ## Docker 部署 ### 环境变量 | 变量 | 默认值 | 说明 | |------|--------|------| | `ACCESS_PASSWORD` | `123456` | 全局访问密码,保护项目列表页 | | `MYSQL_HOST` | `mysql` | MySQL 主机(容器内自动设为 `mysql`) | | `MYSQL_PORT` | `3306` | MySQL 端口 | | `MYSQL_DATABASE` | `uipad` | 数据库名 | | `MYSQL_USER` | `uipad` | 数据库用户 | | `MYSQL_PASSWORD` | `uipad123` | 数据库密码 | | `MYSQL_ROOT_PASSWORD` | `root123` | MySQL root 密码(首次启动创建用户用) | | `AI_BASE_URL` | `https://api.openai-hk.com` | AI API 地址 | | `AI_API_KEY` | - | AI API Key | | `AI_MODEL` | `gpt-4o` | AI 模型 | | `IMAGE_BASE_URL` | 同 AI | 图片生成 API 地址 | | `IMAGE_API_KEY` | 同 AI | 图片生成 API Key | | `IMAGE_MODEL` | `gpt-image-2` | 图片生成模型 | ### 构建镜像 ```bash docker build -t uipad . ``` ### docker-compose(推荐) ```bash # 启动全部服务(MySQL + UIPad) docker compose up -d # 自定义环境变量 MYSQL_PASSWORD=mysecret ACCESS_PASSWORD=mypass docker compose up -d ``` 访问 http://localhost:3000 ### 数据持久化 Docker Compose 使用两个命名卷: | 卷名 | 挂载路径 | 内容 | |------|----------|------| | `mysql_data` | `/var/lib/mysql` | MySQL 数据库文件 | | `upload_data` | `/app/data` | 上传的图片文件 | ### 一键推送部署仓库 将 Docker 配置和构建产物推送到独立的部署仓库,一条命令搞定: ```bash DEPLOY_REPO_URL=https://gitee.com/your-user/your-deploy-repo.git ./deploy.sh ``` 脚本自动完成:构建前端/后端 → 收集产物 → 提交 → 推送。 部署服务器上只需: ```bash git clone <部署仓库地址> cd uipad-deploy docker compose up -d ``` ### 外部 Nginx 反向代理 当使用外部 Nginx 反向代理时,配置示例: ```nginx server { listen 80; server_name canvas.example.com; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` 容器内已配置正确的请求头传递(`X-Forwarded-For`、`X-Forwarded-Proto`、`Host`),外部代理域名会自动生效。 ## 架构 ### 核心概念 ``` Project (项目) ─── Group (分组) ─── Document (PRD/场景/外部链接) │ └── Canvas (画板) └── Page (页面) ─── PageVersion (版本) ─── AI 生成截图 ``` ### 前端架构 ``` App ├── pages/ │ ├── ProjectList # 项目列表 │ ├── ProjectDetail # 项目详情(布局编排 + 状态分发) │ └── DocumentEdit # 文档编辑页 ├── components/ │ ├── GroupTree # 左侧树形导航(分组+文档+画板) │ ├── CanvasEditor # Excalidraw 画布编辑器(核心组件) │ │ └── CanvasToolbar # 画布工具栏 │ ├── PageDetailModal # 页面详情抽屉 │ ├── VersionFormModal # 版本新建/编辑弹窗 │ └── ... # 其他 Modal / 辅助组件 ├── services/ │ ├── dataLayer.ts # 单数据源(缓存 + 发布/订阅) │ ├── pageBlockService.ts # PageBlock CRUD(画布上页面的统一操作接口) │ ├── imageCache.ts # 图片 URL→dataURL 缓存层 │ ├── canvasSyncService.ts # 画布同步工具函数 │ └── api.ts # 后端 API 封装 └── types/ └── index.ts # 全部 TypeScript 类型定义 ``` **数据流**:DataLayer 为单数据源,组件订阅数据变化而非通过 props 层层传递。PageBlock 通过 `pageBlockService` 统一操作,外部不接触 Excalidraw scene elements 内部细节。 ### 后端架构 ``` server-spring/src/main/java/com/uipad/ ├── UipadApplication.java # Spring Boot 入口 ├── controller/ # REST 控制器 ├── service/ # 业务逻辑 ├── mapper/ # MyBatis-Plus Mapper ├── entity/ # 数据实体 ├── dto/ # 请求/响应 DTO ├── config/ # Spring 配置(CORS、MyBatis-Plus、异常处理) ├── interceptor/ # 认证拦截器 └── annotation/ # 自定义注解 ``` **数据关系**: ``` projects ─┬─ groups (自引用树) ─┬─ documents │ └─ canvases ── canvas_elements ── pages ├─ pages ── page_versions ├─ project_generation_defaults └─ settings (KV) ``` ### PageBlock 结构(画布上页面的原子组件) ``` PageBlock { elementId: string # canvas_elements 表主键 groupElementId: "pb_group_{elementId}" # Excalidraw frame(名称容器) imageElementId: "pb_image_{elementId}" # Excalidraw image(图片) imageFileId: "canvas_img_{elementId}" # fileId,永不变化 } ``` 画布上的每个页面由固定的 2 个 Excalidraw 元素构成,通过 `pageBlockService` 统一 CRUD,结构不可变。 ## 项目结构 ``` uipad/ ├── client/ # React 18 + Vite + Ant Design 5 + Excalidraw │ └── src/ │ ├── pages/ # 页面级组件 │ ├── components/ # UI 组件 │ ├── services/ # 数据层 + API 封装 │ ├── hooks/ # 自定义 hooks │ └── types/ # TypeScript 类型 ├── server-spring/ # Spring Boot 3 + MyBatis-Plus + MySQL │ └── src/main/ │ ├── java/com/uipad/ │ │ ├── controller/ # REST 控制器 │ │ ├── service/ # 业务逻辑 │ │ ├── mapper/ # Mapper 接口 + XML │ │ ├── entity/ # 实体类 │ │ ├── dto/ # DTO │ │ ├── config/ # 配置 │ │ └── interceptor/ # 拦截器 │ └── resources/ │ ├── application.yml # 应用配置 │ └── schema.sql # 建表脚本 ├── Dockerfile # 多阶段构建(Client + Spring Boot) ├── Dockerfile.deploy # 部署专用(预构建产物) ├── docker-compose.yml # 本地/开发部署 ├── docker-compose.deploy.yml # 生产部署 ├── docker-entrypoint.sh # 容器启动脚本 ├── nginx.conf # 容器内 Nginx ├── deploy.sh # 一键推送部署仓库 └── build.sh # 本地构建 Docker 镜像 ``` ## 技术栈 **Client:** - React 18 + TypeScript - Vite - Ant Design 5 - Excalidraw(画板) - TipTap(富文本编辑器) - @dnd-kit(拖拽排序) **Server:** - Spring Boot 3.4 + Java 21 - MyBatis-Plus 3.5 - MySQL 8.0 - SpringDoc OpenAPI(Swagger) ## License Private