# T-WEB-005 模型上传 + VRM 优先 + 来源字段 - **状态**:done - **依赖**:T-WEB-002 ## 目标 上传角色模型,**VRM 优先**,识别 VRM 版本,并维护全局默认模型。 ## load ``` DSH.md contracts/rest-api.yaml # 锚点:#/paths/~1api~1models contracts/data-models.md # 锚点:§4 Model、§4.1 VRM 优先规则 contracts/model-formats.md # 锚点:§1 角色模型 web-server/src/models/* web-server/src/models/vrm-inspector.ts ``` ## 端点 | 方法 | 路径 | 说明 | |---|---|---| | GET | `/api/models` | 分页 + `q`/`format`/`status`/`primaryOnly` | | POST | `/api/models` | multipart 上传(`file` + 名称 + 来源五元组 + `isPrimary`) | | GET | `/api/models/:id` | 详情 | | PATCH | `/api/models/:id` | 更新 | | DELETE | `/api/models/:id` | 软删除 | | POST | `/api/models/:id/primary` | 设为全局默认模型 | ## VRM 优先规则(`contracts/data-models.md` §4.1,已实现于 `resolveDefaultModelId()`) ``` 1. 显式 modelId(客户端侧) 2. format='vrm' 且 published 且 is_primary=1 3. format='vrm' 且 published,按 id 升序取第一个 4. published,按 (format='vrm' DESC, id ASC) 取第一个 5. 无 → 客户端使用内置占位模型 ``` `POST /:id/primary` 在**同一事务**内先清零其余 `is_primary`,保证互斥。 ## VRM 版本识别 `vrm-inspector.ts` 直接读取 GLB 头部 JSON chunk,不依赖完整 3D 库: - `extensions.VRMC_vrm` → VRM **1.0**(取 `specVersion`) - `extensions.VRM` → VRM **0.x** - 两者皆无 → `null`(普通 GLB) ## 验收 ```bash npm run test # test/vrm-inspector.spec.ts,6 例 npm run test:smoke # 冒烟 [4] 段落 ``` 覆盖:真实 GLB 构造下识别 1.0 / 0.0 / null、文本 glTF 不误判、过小文件报错、 非 JSON 首 chunk 报错、上传 201、`isPrimary` 置位、缺来源 400、按格式过滤列表、 列表含来源信息(管理端展示用)。