gongxiangp2/标准模型素材类型逻辑梳理报告.md
chenpei 0ce59be34e 备份:组织架构设计方案讨论前的代码快照
- 包含所有当前修改和新功能
- 准备开始组织架构优化实施方案
2025-12-30 13:20:26 +08:00

15 KiB
Raw Blame History

标准模型素材类型逻辑梳理报告

📋 概述

标准模型是一种特殊的素材类型,用于以产品型号(SPU)为基准创建模型合集。上传时只需填写SPU和预览图,创建后可以在详情页添加各个SKU的模型文件。


🗂️ 数据库结构

Material 表(标准模型相关字段)

model Material {
  id                  String    @id @default(uuid())
  previewUrl          String    // S3 URL(预览图)- 必填
  productModel        String    // SPU型号 - 必填
  categoryName        String    // 使用店铺 - 自动填充为"通用"
  sceneName           String    // 场景类别 - 自动填充为"通用"
  productCategoryName String    // 品类分类 - 必填
  materialType        String    // 素材类型 = "标准模型"
  zipFileName         String    @default("") // 可选,标准模型主文件可选
  zipFilePath         String    @default("") // 可选
  zipFileSize         BigInt    @default(0) // 可选
  // ... 其他字段
  skus                MaterialSku[] // 关联的SKU列表
}

MaterialSku 表

model MaterialSku {
  id         String   @id @default(uuid())
  materialId String   @map("material_id")
  skuName    String   @map("sku_name")      // SKU名称(如:白色款)
  filePath   String   @map("file_path")      // 压缩包相对路径(如:skus/{materialId}/{fileName})
  fileSize   BigInt   @default(0) @map("file_size")
  sortOrder  Int      @default(0) @map("sort_order") // 排序字段
  createdAt  DateTime @default(now()) @map("created_at")
  updatedAt  DateTime @updatedAt @map("updated_at")
  
  material Material @relation(fields: [materialId], references: [id], onDelete: Cascade)
  
  @@index([materialId])
  @@index([sortOrder])
  @@map("material_skus")
}

⚠️ 发现的问题:

  • MaterialSku表缺少previewUrl字段,但前端组件(SkuList、SkuEditModal)都在使用该字段
  • 前端上传预览图到S3后,在创建SKU时传递了previewUrl,但后端API未接收和存储

📝 字段验证规则

上传时必填字段

字段 是否必填 说明
productModel ✅ 必填 SPU型号
productCategoryName ✅ 必填 品类分类
previewImages ✅ 必填 预览图(至少1张)
categoryName ❌ 自动填充 自动填充为"通用"
sceneName ❌ 自动填充 自动填充为"通用"
zipFile ❌ 可选 主文件可选(与模特类型相同)

SKU添加时必填字段

字段 是否必填 说明
skuName ✅ 必填 SKU名称
previewUrl ✅ 必填 预览图URL(前端上传到S3)
zipFile ✅ 必填 压缩包文件

🔄 完整流程

1. 标准模型上传流程

用户选择"标准模型"类型
    ↓
填写SPU型号(必填)
    ↓
选择品类(必填)
    ↓
上传预览图(必填,至少1张)
    ↓
上传主文件(可选)
    ↓
前端验证:
  - requiresProductCategoryName() → 检查品类
  - requiresCategoryAndScene() → 返回false(不需要店铺和场景)
  - shouldAutoFillGeneral() → 返回true(自动填充"通用")
    ↓
提交到 /api/materials/upload
    ↓
后端处理:
  - 验证productModel、productCategoryName
  - 验证previewImages(必填)
  - zipFile可选(不验证)
  - 自动填充categoryName="通用", sceneName="通用"
  - 上传预览图到S3
  - 如果上传了zipFile,保存到本地uploads/
  - 创建Material记录
    ↓
返回成功,跳转到详情页

关键代码位置:

  • 前端验证:components/UploadModal.tsx (lines 1292-1329)
  • 后端验证:app/api/materials/upload/route.ts (lines 80-102)
  • 自动填充逻辑:lib/material-validation.ts (lines 18-34)

2. SKU添加流程

用户在详情页点击"编辑SKU"
    ↓
打开SkuEditModal弹窗
    ↓
点击"添加SKU"
    ↓
填写SKU名称
    ↓
上传预览图 → /api/upload/preview → 返回S3 URL
    ↓
上传压缩包 → /api/materials/{id}/skus/upload → 保存到uploads/skus/{materialId}/
    ↓
点击"添加"按钮
    ↓
调用 POST /api/materials/{id}/skus
  Body: {
    skuName: string,
    previewUrl: string,  // ⚠️ 前端传递了,但后端未接收
    zipFileName: string,
    zipFilePath: string,
    zipFileSize: number
  }
    ↓
后端创建SKU记录(⚠️ 缺少previewUrl字段)
    ↓
刷新SKU列表

关键代码位置:

  • SKU上传:components/SkuEditModal.tsx (lines 78-211)
  • 预览图上传:components/SkuEditModal.tsx (lines 108-131)
  • 后端API:app/api/materials/[id]/skus/route.ts (lines 48-110)
  • 文件上传API:app/api/materials/[id]/skus/upload/route.ts

3. SKU列表展示流程

用户访问标准模型详情页
    ↓
检查materialType === '标准模型'
    ↓
渲染SkuList组件
    ↓
调用 GET /api/materials/{id}/skus
    ↓
后端返回SKU列表(按sortOrder排序)
    ↓
前端渲染SKU卡片:
  - 显示预览图(⚠️ 使用sku.previewUrl,但数据库中没有该字段)
  - 显示SKU名称
  - 显示文件大小
  - 显示下载按钮
    ↓
用户可以选择SKU并下载

关键代码位置:

  • 详情页:app/share/[id]/page.tsx (lines 519-528)
  • SKU列表组件:components/SkuList.tsx
  • SKU列表API:app/api/materials/[id]/skus/route.ts (lines 8-46)

4. SKU下载流程

用户点击SKU的"下载"按钮
    ↓
调用 GET /api/materials/{id}/skus/{skuId}/download
    ↓
后端验证:
  - 检查用户登录状态
  - 检查用户下载权限(canDownload)
  - 获取SKU信息
  - 构建文件路径:uploads/{sku.filePath}
  - 读取文件并返回
    ↓
前端接收文件流并触发下载

关键代码位置:

  • 下载API:app/api/materials/[id]/skus/[skuId]/download/route.ts
  • 前端下载:components/SkuList.tsx (lines 100-129)

🔧 API接口清单

标准模型上传

方法 路径 说明
POST /api/materials/upload 上传标准模型素材

请求参数:

  • productModel: string (必填)
  • productCategoryName: string (必填)
  • previewImage: File (必填,第一张预览图)
  • previewImages: File[] (可选,其他预览图)
  • zipFile: File (可选,主文件)
  • materialType: "标准模型"
  • categoryName: 自动填充为"通用"
  • sceneName: 自动填充为"通用"

SKU管理

方法 路径 说明
GET /api/materials/{id}/skus 获取SKU列表
POST /api/materials/{id}/skus 添加SKU
GET /api/materials/{id}/skus/{skuId} 获取SKU详情
PUT /api/materials/{id}/skus/{skuId} 更新SKU
DELETE /api/materials/{id}/skus/{skuId} 删除SKU
PUT /api/materials/{id}/skus/reorder 批量更新SKU排序
POST /api/materials/{id}/skus/upload 上传SKU文件

权限控制:

  • 只有素材上传者或管理员可以添加/编辑/删除SKU
  • 所有登录用户都可以查看和下载SKU

🎨 前端组件

1. UploadModal(上传弹窗)

文件位置: components/UploadModal.tsx

标准模型相关逻辑:

  • 选择"标准模型"类型时,隐藏店铺和场景字段
  • 显示品类选择字段(必填)
  • 显示标准模型说明提示框
  • 验证:SPU、品类、预览图必填,主文件可选

关键代码:

// 验证品类(line 1292-1295)
if (requiresProductCategoryName(materialType) && !productCategoryName) {
  setError('标准模型类型必须选择品类')
  return
}

// 验证主文件(line 1302-1306)
if (materialType !== '模特' && materialType !== '标准模型' && !zipFile) {
  setError('请上传素材文件')
  return
}

// 验证预览图(line 1326-1329)
if (materialType === '标准模型' && previewImages.length === 0) {
  setError('标准模型必须上传预览图')
  return
}

2. UploadForm(上传表单字段)

文件位置: components/upload/UploadForm.tsx

标准模型相关逻辑:

  • 标准模型不显示店铺和场景字段(line 144-210, 212-278)
  • 标准模型显示品类字段(必填)(line 280-300)
  • 标准模型不显示平台字段(line 302-322)
  • 显示标准模型说明提示(line 343-356)

3. SkuList(SKU列表组件)

文件位置: components/SkuList.tsx

功能:

  • 显示SKU列表(按sortOrder排序)
  • 支持全选/单选SKU
  • 支持单个/批量下载SKU
  • 支持预览图点击放大
  • 显示SKU名称、文件大小

⚠️ 问题:

  • 使用sku.previewUrl字段(line 231),但数据库中没有该字段
  • API返回的SKU数据中没有previewUrl

4. SkuEditModal(SKU编辑弹窗)

文件位置: components/SkuEditModal.tsx

功能:

  • 显示SKU列表
  • 添加新SKU(名称、预览图、压缩包)
  • 删除SKU
  • 调整SKU排序(上移/下移)
  • 支持拖拽上传预览图和压缩包

⚠️ 问题:

  • 上传预览图到S3后,在创建SKU时传递了previewUrl(line 186)
  • 但后端API未接收和存储previewUrl字段

⚠️ 发现的问题

1. MaterialSku表缺少previewUrl字段

问题描述:

  • 前端组件(SkuList、SkuEditModal)都在使用sku.previewUrl字段
  • 但MaterialSku表结构中没有previewUrl字段
  • 前端上传预览图后,在创建SKU时传递了previewUrl,但后端未接收和存储

影响:

  • SKU列表无法显示预览图
  • SKU编辑弹窗中无法显示已上传的预览图

解决方案:

  1. 在MaterialSku表中添加previewUrl字段
  2. 修改后端API接收和存储previewUrl
  3. 更新Prisma schema并执行迁移

2. SKU上传API的字段不一致

问题描述:

  • SkuEditModal中上传压缩包后,调用POST /api/materials/{id}/skus时传递了:
    • skuName
    • previewUrl
    • zipFileName
    • zipFilePath
    • zipFileSize
  • 但后端API只接收了:
    • skuName
    • filePath(对应前端的zipFilePath)
    • fileSize(对应前端的zipFileSize)
  • 缺少previewUrl和zipFileName的接收

解决方案:

  1. 修改后端API接收previewUrl和zipFileName
  2. 在MaterialSku表中添加previewUrl和zipFileName字段(如果需要)

3. SKU文件路径存储方式不一致

问题描述:

  • POST /api/materials/{id}/skus/upload保存文件到uploads/skus/{materialId}/,返回相对路径skus/{materialId}/{fileName}
  • POST /api/materials/{id}/skus接收filePath,直接存储到数据库
  • 但前端传递的是zipFilePath,需要确认字段名是否一致

解决方案:

  • 统一字段命名:使用filePath存储相对路径,使用zipFileName存储文件名

📂 文件存储结构

标准模型主文件(可选)

uploads/
  {timestamp}-{random}.zip  # 如果上传了主文件

SKU文件

uploads/
  skus/
    {materialId}/
      {skuName}_{timestamp}.zip
      {skuName}_{timestamp}.zip
      ...

预览图(S3存储)

  • Material预览图:s3://bucket/preview-{timestamp}-{random}.{ext}
  • SKU预览图:s3://bucket/preview-{timestamp}-{random}.{ext}(如果添加了previewUrl字段)

🔍 验证逻辑代码位置

前端验证

文件: lib/material-validation.ts

// 标准模型不需要店铺和场景
export function requiresCategoryAndScene(materialType: string): boolean {
  return !AUTO_GENERAL_TYPES.includes(materialType) && materialType !== '标准模型';
}

// 标准模型需要品类
export function requiresProductCategoryName(materialType: string): boolean {
  return materialType === '标准模型';
}

// 标准模型自动填充"通用"
export function shouldAutoFillGeneral(materialType: string): boolean {
  return AUTO_GENERAL_TYPES.includes(materialType) || materialType === '标准模型';
}

后端验证

文件: app/api/materials/upload/route.ts

// 验证主文件(line 94-102)
const requiresMainFile = !['模特', '标准模型', '买家秀图片', '小红书种草'].includes(materialType);
const hasMainFile = !!zipFile || !!existingFilePath;
if (requiresMainFile && !hasMainFile) {
  return NextResponse.json({ error: '请上传素材文件' }, { status: 400 });
}

📊 数据流图

┌─────────────────┐
│   用户上传       │
│   标准模型       │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  UploadModal    │
│  - 验证字段     │
│  - 上传预览图   │
│  - 上传主文件   │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  /api/materials │
│  /upload        │
│  - 创建Material │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  详情页展示     │
│  - 显示预览图   │
│  - 显示SKU列表  │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  用户添加SKU    │
│  - 上传预览图   │
│  - 上传压缩包   │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  /api/materials │
│  /{id}/skus    │
│  - 创建SKU     │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  SKU列表更新    │
│  - 显示预览图   │
│  - 支持下载     │
└─────────────────┘

🎯 待完成工作

高优先级

  1. 修复MaterialSku表缺少previewUrl字段

    • 在Prisma schema中添加previewUrl字段
    • 执行数据库迁移
    • 修改后端API接收和存储previewUrl
    • 更新前端组件使用新的字段
  2. 统一SKU字段命名

    • 确认zipFileName是否需要存储
    • 统一使用filePath存储相对路径
    • 更新前端传递的字段名
  3. 完善SKU上传流程

    • 确保预览图上传后URL正确传递
    • 确保压缩包上传后路径正确传递
    • 添加错误处理和用户提示

中优先级

  1. 优化SKU列表展示

    • 添加加载状态
    • 添加空状态提示
    • 优化预览图显示(如果修复了previewUrl字段)
  2. 添加SKU编辑功能

    • 支持修改SKU名称
    • 支持更换预览图
    • 支持更换压缩包

低优先级

  1. 批量操作优化
    • 支持批量删除SKU
    • 支持批量下载SKU(已实现,但可以优化)
    • 支持拖拽排序

📚 相关文档

  • 项目文档.md - 项目整体架构和配置
  • docs/upload-spec-from-decompiled.md - 上传规范说明
  • 批量上传流程完整检查报告.md - 批量上传逻辑检查

✅ 总结

标准模型素材类型的基本逻辑已经实现,包括:

  • ✅ 上传时的字段验证和自动填充
  • ✅ SKU的添加、删除、排序功能
  • ✅ SKU的下载功能
  • ✅ 详情页SKU列表展示

但存在以下问题需要修复:

  • ❌ MaterialSku表缺少previewUrl字段
  • ❌ 后端API未接收和存储previewUrl
  • ❌ 字段命名不一致(zipFilePath vs filePath)

修复这些问题后,标准模型功能将完全可用。