gongxiangp2/TEST-UPLOAD-FIX.md
chenpei 4dba93c4e5 feat: 完成任务-详情素材迁移到新逻辑
- 迁移57个老素材到新逻辑(本地zip + S3预览图)
- 优化文件命名:SPU_作者_店铺_类型.zip
- PSD文件单独存储,不打包进all.zip
- 修复下载接口,优先使用本地zip文件
- 修复预览图重复问题
- 添加迁移脚本和验证脚本
- 更新文档和迁移计划

迁移统计:
- 总素材数:77个
- 成功迁移:57个
- 新逻辑上传:18个
- 空记录:2个
2026-01-21 10:16:28 +08:00

5.1 KiB
Raw Blame History

任务-详情上传修复验证

修复内容

1. 进度条超过100%问题 ✅

问题原因:onProgress 回调在每个分片上传时都触发,导致 uploadedCount 多次增加

修复位置:components/upload/ProductPackageUploader.tsx 第329-331行

const uploadId = await uploadFileWithChunks(asset.file);
// 只在上传完成时更新进度
updateProgress();

验证方式:

  • 上传35个文件(5主图 + 10SKU + 20详情)
  • 观察进度条,应该在100%时停止
  • 不应该超过100%

2. 62个资产问题 ✅

问题原因:文件路径查找逻辑错误,使用文件名匹配导致重复生成预览图

修复位置:app/api/materials/upload/product-package/complete/route.ts 第256-265行

修复前:

const filePath = mainFiles.find(f => f.name === asset.fileName)?.path ||
                 skuFiles.find(f => f.name === asset.fileName)?.path ||
                 detailFiles.find(f => f.name === asset.fileName)?.path;

修复后:

const filePath = await getUploadedFile(asset.uploadId);

预期结果:

  • 5个主图 → 5个 main-preview 预览图
  • 10个SKU → 10个 sku-preview 预览图
  • 20个详情 → 20个 detail-preview 预览图
  • 1个主图zip(main)
  • 1个SKU zip(sku)
  • 1个详情zip(detail)
  • 1个总zip(all)
  • 1个PSD(psd)
  • 总计:40个资产

验证方式:

SELECT assetType, COUNT(*) as count
FROM "MaterialAsset"
WHERE materialId = 'xxx'
GROUP BY assetType
ORDER BY assetType;

应该看到:

main-preview    5
sku-preview    10
detail-preview 20
main            1
sku             1
detail          1
all             1
psd             1

3. PSD fileUrl undefined问题 ✅

问题原因:PsdAsset 接口不支持 uploadId,导致PSD文件无法正确处理

修复位置:

  1. app/api/materials/upload/product-package/complete/route.ts 第31-36行

    interface PsdAsset {
      uploadId?: string;  // 分片上传的uploadId
      fileUrl?: string;   // 直接上传到S3的URL
      fileName: string;
      fileSize: number;
    }
    
  2. 第387-400行:使用 uploadId 获取PSD文件路径

    if (assets.psd && assets.psd.length > 0) {
      for (const psd of assets.psd) {
        if (psd.uploadId) {
          const filePath = await getUploadedFile(psd.uploadId);
          if (filePath) {
            psdFilesForAll.push({ path: filePath, name: psd.fileName });
            tempFiles.push(filePath);
          }
        }
      }
    }
    

验证方式:

  • 上传包含PSD文件的素材
  • 检查all.zip中是否包含PSD文件
  • 检查数据库中 assetType='psd' 的记录是否正确

测试步骤

测试1:基础上传(不含PSD)

  1. 上传5个主图、10个SKU、20个详情
  2. 观察进度条,应该在100%停止
  3. 检查数据库资产数量(应该是39个,不含PSD)

测试2:包含PSD的上传

  1. 上传5个主图、10个SKU、20个详情、1个PSD
  2. 观察进度条,应该在100%停止
  3. 检查数据库资产数量(应该是40个)
  4. 下载all.zip,检查是否包含PSD文件

测试3:下载功能

  1. 下载"全部"
  2. 解压后检查结构:
    主图_XXXX.zip
    SKU图_XXXX.zip
    详情图_XXXX.zip
    psd/6.psd
    
  3. 不应该包含任何预览文件

关键数据流

前端上传流程

用户选择文件
  ↓
uploadFileWithChunks(file)
  ↓
chunkUpload(file, metadata, { skipComplete: true })
  ↓
分片上传到 /api/materials/upload/chunk
  ↓
保存到临时目录 uploads/temp/{uploadId}/chunk-{index}
  ↓
返回 { uploadId, chunksUploaded: true }
  ↓
传递给 /api/materials/upload/product-package/complete

后端处理流程

接收 uploadId
  ↓
getUploadedFile(uploadId) → 组装文件 → uploads/assembled/{uploadId}-{fileName}
  ↓
从组装的文件生成预览图 → 上传到S3 → previewUrl
  ↓
打包原始文件成zip → main.zip, sku.zip, detail.zip
  ↓
打包总zip(包含分类zip + PSD)→ all.zip
  ↓
保存到数据库(previewUrls + zipPaths + psdPaths)

常见问题排查

问题:进度条超过100%

排查:

// 检查 updateProgress 是否被多次调用
const updateProgress = () => {
  console.log('uploadedCount:', uploadedCount, 'totalFiles:', totalFiles);  // 添加日志
  uploadedCount++;
  setUploadProgress(Math.round((uploadedCount / totalFiles) * 100));
};

问题:资产数量不正确

排查:

-- 查看所有资产类型
SELECT assetType, fileUrl, fileName, "sortOrder"
FROM "MaterialAsset"
WHERE materialId = 'xxx'
ORDER BY assetType, "sortOrder";

问题:PSD文件不在all.zip中

排查:

// 检查psdFilesForAll是否正确添加
console.log('[Product Package] PSD files for all:', psdFilesForAll);

部署检查清单

  • 代码已修复并本地测试通过
  • 没有TypeScript错误
  • 运行 lint 检查通过
  • 部署到影子系统
  • 在浏览器中测试上传功能
  • 检查数据库资产数量
  • 检查下载功能
  • 确认没有引入新bug