Files
opendance-web/web-server/admin/README.md
T

134 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenDance Studio 管理端(opendance-admin)
基于 **React 18 + TypeScript + Vite** 的管理后台,对接 `web-server` 的 NestJS API。
接口契约以 [`../contracts/rest-api.yaml`](../contracts/rest-api.yaml)(rest-api 0.1.0)为准,
字段语义见 [`../contracts/data-models.md`](../contracts/data-models.md)。
界面语言为简体中文;无任何 UI 组件框架,全部样式集中在 `src/styles.css`。
## 快速开始
```bash
npm install # 或 pnpm install
npm run dev # 开发服务器 http://localhost:5173
npm run build # 生产构建(tsc -b && vite build)→ dist/
npm run preview # 本地预览 dist/
npm run typecheck # 只做类型检查(tsc --noEmit)
```
> 管理端请求的是**同源**的 `/api/**` 与 `/health`,不含任何硬编码域名。
## 开发代理(dev proxy)
`vite.config.ts` 已把 `/api` 与 `/health` 代理到 `http://localhost:3000`:
```ts
server: {
port: 5173,
proxy: {
'/api': { target: 'http://localhost:3000', changeOrigin: true },
'/health': { target: 'http://localhost:3000', changeOrigin: true },
},
}
```
因此本地只需先启动服务端,再 `npm run dev` 即可,无需配置 CORS。
## `VITE_API_BASE`
`src/api/client.ts` 的基址取自:
```ts
const BASE_URL = import.meta.env.VITE_API_BASE ?? '';
```
- **不设置(默认,空串)**:同源请求 —— 开发期走上面的 vite 代理,生产期走 nginx 反代。**推荐**。
- **设置**:例如服务端在另一台机器上:
```bash
# .env.local(不要提交)
VITE_API_BASE=http://192.168.1.10:3000
```
此时浏览器会直接跨域请求该地址,需要服务端开启 CORS。
构建期注入:`VITE_API_BASE=https://api.example.com npm run build`。
## 生产构建与部署
```bash
npm run build # 产物在 dist/
```
`vite.config.ts` 使用 `base: './'`,产物使用相对路径引用,可挂在任意子路径下。
**生产部署(Linux 原生站点,不使用 Docker)**
构建产物 `dist/` 由同一站点的 nginx 直接托管,API 由 nginx 反向代理到本机 Node 进程。
整个过程由仓库根目录的 `deploy/install.sh` 一键完成:
```bash
# 仓库根目录
sudo bash deploy/install.sh
```
对应的 nginx 站点配置见 `deploy/nginx/opendance.conf`:
- `root` 指向安装后的 `admin/` 目录,`try_files $uri $uri/ /index.html` 支持 SPA 路由;
- `/api/`、`/health`、`/static/` 反向代理到 `127.0.0.1:3000`(Node 只监听回环);
- `client_max_body_size 512m` 与后端 `UPLOAD_MAX_BYTES` 保持一致。
本目录下的 `nginx.conf` 仅用于「把管理端单独托管到另一个 nginx 实例」的场景,
其中的 `proxy_pass http://api:3000` 需要按实际情况改成后端地址。
## 目录结构
```
src/
main.tsx 入口(BrowserRouter)
App.tsx 路由表
styles.css 全部样式
api/
client.ts fetch 封装(ApiError / 分页 / multipart)
types.ts 契约类型(与 rest-api.yaml 一一对应)
endpoints.ts 契约端点封装
components/
Layout.tsx 左侧导航骨架
ui.tsx 通用组件(表格/弹窗/分页/来源五元组展示与表单…)
VrmPreview.tsx three + @pixiv/three-vrm 的 3D 预览(懒加载分包)
lib/
labels.ts 枚举中文文案
format.ts 时间/字节/时长格式化
validation.ts 客户端校验(来源五元组等)
useAsync.ts 加载/错误/重试 hook
pages/
Dashboard.tsx 概览
Songs.tsx 歌曲管理 T-WEB-008
Models.tsx 模型管理 T-WEB-009
Motions.tsx 动作管理 T-WEB-004/006
Reviews.tsx 审核 T-WEB-007
```
## 页面与任务对照
| 路由 | 说明 | 任务 |
|---|---|---|
| `/` | 概览:三类资产按状态计数、契约版本与目录指纹、健康检查、API 不可达告警 | — |
| `/songs` | 歌曲管理:分页/搜索/筛选、来源五元组必填、音频上传、软删除 | T-WEB-008 |
| `/models` | 模型管理:VRM 优先、来源五元组完整展示、设为默认、3D 预览 | T-WEB-009 |
| `/motions` | 动作管理:上传、预处理、关键点 NDJSON 下载 | T-WEB-004/006 |
| `/reviews` | 审核:待审列表 + 审核流水,通过/驳回(驳回必填意见) | T-WEB-007 |
所有页面都显式处理**加载中 / 空数据 / 请求失败**三种状态,请求失败不会白屏。
## 3D 预览说明
`src/components/VrmPreview.tsx`:`GLTFLoader` + `VRMLoaderPlugin`(来自 `@pixiv/three-vrm`),
- 依据 `vrm.meta.metaVersion` 区分 VRM 0.x / 1.0,0.x 自动执行 `VRMUtils.rotateVRM0`;
- 自实现鼠标拖拽旋转与滚轮缩放(未引入 OrbitControls);
- `requestAnimationFrame` 循环内调用 `vrm.update(delta)`,并按包围盒自动取景;
- 卸载时取消 RAF、断开 ResizeObserver、释放 renderer / geometry / material / texture;
- 无 WebGL 上下文时降级为错误提示,不会让页面崩溃。
`three` + `@pixiv/three-vrm`(约 750 kB)通过 `React.lazy` 单独分包,仅进入模型页时加载。