feat: 结果页添加帧预览、GIF动画和导出选项

- 后端: GetAssets 返回素材级别 metadata,区分 frame/preview/spritesheet 类型
- 后端: 上传时区分素材类型标签,GIF URL 独立追踪
- 前端: 结果详情页默认展示拆分后的单帧网格
- 前端: 添加动作帧 GIF 预览弹窗
- 前端: 添加导出下拉菜单(整张精灵表/自动切分帧)
- 前端: 失败任务展示错误信息和重试次数
This commit is contained in:
2026-05-25 19:41:55 +08:00
parent ab2b72e746
commit a518168762
6 changed files with 301 additions and 106 deletions
+13 -10
View File
@@ -47,8 +47,8 @@ type GenerateResponse struct {
// AssetsResponse 素材列表响应。
type AssetsResponse struct {
Assets []model.AssetResponse `json:"assets"`
Metadata service.AssetMetadata `json:"metadata"`
Assets []model.AssetResponse `json:"assets"`
Metadata service.AssetMetadata `json:"metadata"`
}
// Generate 素材生成接口(异步)。
@@ -136,7 +136,7 @@ func runPipelineBg(ctx context.Context, projectID, taskID string, req GenerateRe
updateTaskInDB(ctx, taskID, "saving", "format_adapter", "", 90)
// 上传素材并保存到数据库
var lastCDNURL string
var lastGIFCDNURL string
for i, a := range output.Assets {
key := fmt.Sprintf("generation/%s/%s/%d.%s", projectID, taskID, i, a.Format)
cdnURL, err := storageSvc.Upload(ctx, key, a.Data)
@@ -145,13 +145,15 @@ func runPipelineBg(ctx context.Context, projectID, taskID string, req GenerateRe
updateTaskInDB(ctx, taskID, "failed", "", "上传素材失败: "+err.Error(), 0)
return
}
lastCDNURL = cdnURL
var assetMeta map[string]interface{}
if a.Format == "gif" {
assetMeta = map[string]interface{}{"index": i, "type": "preview"}
lastGIFCDNURL = cdnURL
} else if strings.Contains(a.URL, "spritesheet") {
assetMeta = map[string]interface{}{"index": i, "type": "spritesheet"}
} else {
assetMeta = map[string]interface{}{"index": i}
assetMeta = map[string]interface{}{"index": i, "type": "frame"}
}
metadataJSON, _ := json.Marshal(assetMeta)
@@ -169,8 +171,8 @@ func runPipelineBg(ctx context.Context, projectID, taskID string, req GenerateRe
}
// GIF URL 替换为实际上传后的 CDN 地址
if output.Metadata.GIFURL != "" && lastCDNURL != "" {
output.Metadata.GIFURL = lastCDNURL
if output.Metadata.GIFURL != "" && lastGIFCDNURL != "" {
output.Metadata.GIFURL = lastGIFCDNURL
}
var fullMetadata string
@@ -232,9 +234,10 @@ func GetAssets(c *gin.Context) {
response := []model.AssetResponse{}
for _, a := range assets {
response = append(response, model.AssetResponse{
Key: a.Key,
URL: storageSvc.GetSignedURL(a.Key),
Format: a.Format,
Key: a.Key,
URL: storageSvc.GetSignedURL(a.Key),
Format: a.Format,
Metadata: a.Metadata,
})
}