feat(wordcloud): 贴纸持久化(决策#4)+ dispatchOrder/persistDesignMedia 辅助
This commit is contained in:
@@ -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}` })
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
Reference in New Issue
Block a user