feat(wordcloud): 贴纸持久化(决策#4)+ dispatchOrder/persistDesignMedia 辅助

This commit is contained in:
2026-08-13 01:39:00 +08:00
parent 73fac0cb9c
commit c49ff72f1e
2 changed files with 53 additions and 7 deletions
+5 -7
View File
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react'
import './index.scss' import './index.scss'
import { getProductById } from '../../utils/productConfig' import { getProductById } from '../../utils/productConfig'
import { getDesignList, setDesignList, updateDesign, type DesignItem, type StickerItem } from '../../utils/store' import { getDesignList, setDesignList, updateDesign, type DesignItem, type StickerItem } from '../../utils/store'
import { persistDesignMedia } from '../../utils/api'
import { useThemeContext } from '../../context/ThemeContext' import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea' import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar' import { useStatusBar } from '../../hooks/useStatusBar'
@@ -241,18 +242,15 @@ export default function DIYPage() {
return base return base
} }
const handleComplete = () => { const handleComplete = async () => {
if (hasOverlap) { if (hasOverlap) {
Taro.showToast({ title: '贴纸不能重叠', icon: 'none' }) Taro.showToast({ title: '贴纸不能重叠', icon: 'none' })
return return
} }
if (designId) { if (designId) {
updateDesign(designId, { // 贴纸/底图持久化(决策#4,R4 负责):本地图 → COS 持久 URL,保证后端 WCD 打包可下载素材
designData: { const data = await persistDesignMedia({ stickers, category, version: 1 })
stickers, updateDesign(designId, { designData: data })
category
}
})
} }
setPreviewMode(false) setPreviewMode(false)
Taro.navigateTo({ url: `/pages/checkout/index?designId=${designId}` }) Taro.navigateTo({ url: `/pages/checkout/index?designId=${designId}` })
+48
View File
@@ -2,7 +2,10 @@ import Taro from '@tarojs/taro'
import http, { BASE_URL, getToken } from '../request' import http, { BASE_URL, getToken } from '../request'
import type { import type {
CosCredentials, CosCredentials,
DesignDataV1,
SketchResult, SketchResult,
StickerItem,
WordCloudDispatchResult,
WordCloudJob, WordCloudJob,
WordCloudStatus, WordCloudStatus,
} from '../../types' } from '../../types'
@@ -101,4 +104,49 @@ export function getWordCloudResult(jobId: string): Promise<{ imageUrl: string; s
return http.get<{ imageUrl: string; svgUrl?: string }>(`/api/wordcloud/jobs/${jobId}/result`) return http.get<{ imageUrl: string; svgUrl?: string }>(`/api/wordcloud/jobs/${jobId}/result`)
} }
/** 是否为设备本地临时路径(后端/wordcloud 无法消费,需先转 COS 持久 URL) */
function isLocalPath(url?: string): boolean {
return !!url && /^(wxfile:|http:\/\/tmp\/|tmp\/)/i.test(url)
}
/** 单张本地图 → COS 持久 URL;COS 未配置等失败时保留原路径,不阻断保存 */
async function persistLocalImage(localPath: string): Promise<string> {
try {
const key = `uploads/sticker/${Date.now()}_${Math.floor(Math.random() * 1e6)}.jpg`
const cred = await getUploadCredentials(key)
return await uploadToCos(localPath, cred)
} catch {
return localPath
}
}
/**
* 设计媒体持久化(契约 design-data-contract-v1.md 决策#4:贴纸持久化由 R4 完成)。
* 保存/下单前调用,把 designData 里的本地贴纸/底图上传为 COS 持久 URL 写回 src
* 保证 WCD 打包时后端能下载到素材字节。
*/
export async function persistDesignMedia(designData: DesignDataV1): Promise<DesignDataV1> {
if (!designData) return designData
const next: DesignDataV1 = { ...designData }
if (designData.background && isLocalPath(designData.background.src)) {
next.background = {
...designData.background,
src: await persistLocalImage(designData.background.src),
}
}
if (designData.stickers && designData.stickers.length) {
const list: StickerItem[] = []
for (const s of designData.stickers) {
list.push(isLocalPath(s.src) ? { ...s, src: await persistLocalImage(s.src) } : s)
}
next.stickers = list
}
return next
}
/** 下单后 WCD 派单(幂等触发;WORDCLOUD 未配置返回 not_configured,见 api-contract §8 */
export function dispatchOrder(orderId: string): Promise<WordCloudDispatchResult> {
return http.post<WordCloudDispatchResult>(`/api/orders/${orderId}/dispatch`)
}
export type { WordCloudStatus } export type { WordCloudStatus }