276 lines
7.6 KiB
JavaScript
276 lines
7.6 KiB
JavaScript
/**
|
|
* 铸爱 — 统一「Thinking → 选择 → 详情确认 → 铸造」路由与 Storage
|
|
*/
|
|
|
|
import {
|
|
LENTICULAR_STUDIO_STORAGE_KEY,
|
|
CASTLOVE_LASER_ENTRY_KEY,
|
|
} from '@/utils/castloveMintForm.js'
|
|
|
|
export const GENERATION_FLOW_KEY = 'generation_flow_payload'
|
|
export const GENERATION_REQUEST_KEY = 'generation_request_data'
|
|
export const GENERATED_IMAGES_KEY = 'generated_images'
|
|
export const GENERATION_RESULT_META_KEY = 'generation_result_meta'
|
|
export const CASTLOVE_FORM_KEY = 'castlove_form_data'
|
|
export const CRAFT_SELECTED_IMAGE_KEY = 'craft_selected_image'
|
|
export const CRAFT_SELECTED_INDEX_KEY = 'craft_selected_index'
|
|
|
|
export const FLOW_MODE_API = 'api'
|
|
export const FLOW_MODE_PREFILLED = 'prefilled'
|
|
export const FLOW_MODE_LENTICULAR = 'lenticular'
|
|
export const FLOW_MODE_LASER = 'laser'
|
|
|
|
export const AFTER_SELECT_MINT = 'mint'
|
|
export const AFTER_SELECT_DETAIL = 'detail'
|
|
|
|
export const STUDIO_LENTICULAR = 'lenticular'
|
|
export const STUDIO_LASER = 'laser'
|
|
|
|
const LOADING_URL = '/pages/discover/generation-loading'
|
|
const RESULT_URL = '/pages/discover/generation-result'
|
|
const ASSET_DETAIL_URL = '/pages/asset-detail/asset-detail'
|
|
|
|
export function padImagesForSelection(images, minCount = 4) {
|
|
if (!Array.isArray(images) || images.length === 0) {
|
|
return []
|
|
}
|
|
if (images.length >= minCount) {
|
|
return images.slice(0, minCount)
|
|
}
|
|
const out = [...images]
|
|
while (out.length < minCount) {
|
|
out.push(images[out.length % images.length])
|
|
}
|
|
return out
|
|
}
|
|
|
|
function persistFormData(formData) {
|
|
if (formData != null) {
|
|
uni.setStorageSync(CASTLOVE_FORM_KEY, JSON.stringify(formData))
|
|
}
|
|
}
|
|
|
|
function enrichFormData(formData, { afterSelect, studioKind } = {}) {
|
|
const next = { ...(formData || {}) }
|
|
if (afterSelect) {
|
|
next.generation_after = afterSelect
|
|
}
|
|
if (studioKind) {
|
|
next.studio_kind = studioKind
|
|
}
|
|
return next
|
|
}
|
|
|
|
export function materializeImageRef(src) {
|
|
const s = String(src || '').trim()
|
|
if (!s) {
|
|
return Promise.resolve({ path: '', base64: '' })
|
|
}
|
|
if (s.startsWith('data:')) {
|
|
return Promise.resolve({ path: '', base64: s })
|
|
}
|
|
if (s.startsWith('http://') || s.startsWith('https://')) {
|
|
return new Promise((resolve, reject) => {
|
|
uni.downloadFile({
|
|
url: s,
|
|
success: (res) => {
|
|
if (res.statusCode === 200 && res.tempFilePath) {
|
|
resolve({ path: res.tempFilePath, base64: '' })
|
|
} else {
|
|
reject(new Error('图片下载失败'))
|
|
}
|
|
},
|
|
fail: (err) => reject(err || new Error('图片下载失败')),
|
|
})
|
|
})
|
|
}
|
|
return Promise.resolve({ path: s, base64: '' })
|
|
}
|
|
|
|
function navigateToLoading() {
|
|
uni.navigateTo({ url: LOADING_URL })
|
|
}
|
|
|
|
export function startAiImageGenerationFlow({
|
|
prompt,
|
|
formData,
|
|
n = 4,
|
|
model = 'image-01',
|
|
aspectRatio = '16:9',
|
|
afterSelect = AFTER_SELECT_MINT,
|
|
studioKind = '',
|
|
}) {
|
|
const requestData = {
|
|
prompt,
|
|
model,
|
|
aspect_ratio: aspectRatio,
|
|
subject_reference: [{ type: 'character', image_file: '' }],
|
|
n,
|
|
}
|
|
const merged = enrichFormData(formData, { afterSelect, studioKind })
|
|
persistFormData(merged)
|
|
uni.setStorageSync(GENERATION_REQUEST_KEY, JSON.stringify(requestData))
|
|
uni.setStorageSync(
|
|
GENERATION_FLOW_KEY,
|
|
JSON.stringify({
|
|
mode: FLOW_MODE_API,
|
|
craft: merged?.craft_name || merged?.typeName || '',
|
|
afterSelect,
|
|
studioKind,
|
|
})
|
|
)
|
|
navigateToLoading()
|
|
}
|
|
|
|
/** 光栅 / 镭射:工作台生成预览,不走通用 AI 四图 */
|
|
export function startCraftGenerationFlow({ formData, studioKind }) {
|
|
const merged = enrichFormData(formData, {
|
|
afterSelect: AFTER_SELECT_DETAIL,
|
|
studioKind,
|
|
})
|
|
persistFormData(merged)
|
|
uni.removeStorageSync(GENERATION_REQUEST_KEY)
|
|
const mode =
|
|
studioKind === STUDIO_LENTICULAR ? FLOW_MODE_LENTICULAR : FLOW_MODE_LASER
|
|
uni.setStorageSync(
|
|
GENERATION_FLOW_KEY,
|
|
JSON.stringify({
|
|
mode,
|
|
studioKind,
|
|
afterSelect: AFTER_SELECT_DETAIL,
|
|
craft: merged?.craft_name || merged?.typeName || '',
|
|
minDurationMs: 1600,
|
|
})
|
|
)
|
|
navigateToLoading()
|
|
}
|
|
|
|
export function startPrefilledSelectionFlow({
|
|
images,
|
|
formData,
|
|
minDurationMs = 1400,
|
|
padToFour = true,
|
|
afterSelect = AFTER_SELECT_MINT,
|
|
studioKind = '',
|
|
}) {
|
|
const list = padToFour ? padImagesForSelection(images) : images
|
|
if (!list.length) {
|
|
throw new Error('startPrefilledSelectionFlow: images 不能为空')
|
|
}
|
|
const merged = enrichFormData(formData, { afterSelect, studioKind })
|
|
persistFormData(merged)
|
|
uni.removeStorageSync(GENERATION_REQUEST_KEY)
|
|
uni.setStorageSync(
|
|
GENERATION_FLOW_KEY,
|
|
JSON.stringify({
|
|
mode: FLOW_MODE_PREFILLED,
|
|
images: list,
|
|
minDurationMs,
|
|
craft: merged?.craft_name || merged?.typeName || '',
|
|
afterSelect,
|
|
studioKind,
|
|
})
|
|
)
|
|
navigateToLoading()
|
|
}
|
|
|
|
export function persistLenticularPreviewMeta(formData) {
|
|
uni.setStorageSync(
|
|
LENTICULAR_STUDIO_STORAGE_KEY,
|
|
JSON.stringify({
|
|
bgPath: formData.lenticularBgImage || '',
|
|
subjectPath: formData.lenticularSubjectImage || '',
|
|
bgBase64: formData.lenticularBgBase64 || '',
|
|
subjectBase64: formData.lenticularSubjectBase64 || '',
|
|
nftInfo: formData.info || formData.nftInfo || '',
|
|
materialTypeIndex: formData.materialTypeIndex ?? 0,
|
|
aiDescription: formData.aiDescription || '',
|
|
})
|
|
)
|
|
uni.setStorageSync(
|
|
GENERATION_RESULT_META_KEY,
|
|
JSON.stringify({ displayMode: STUDIO_LENTICULAR, imageCount: 1 })
|
|
)
|
|
uni.setStorageSync(GENERATED_IMAGES_KEY, JSON.stringify([{ type: 'lenticular' }]))
|
|
}
|
|
|
|
export function persistLaserPreviewImages(paths) {
|
|
uni.setStorageSync(
|
|
GENERATION_RESULT_META_KEY,
|
|
JSON.stringify({ displayMode: STUDIO_LASER, imageCount: paths.length })
|
|
)
|
|
uni.setStorageSync(GENERATED_IMAGES_KEY, JSON.stringify(paths))
|
|
}
|
|
|
|
export async function completeSelectionAndOpenDetail({
|
|
selectedImage,
|
|
selectedIndex,
|
|
formData,
|
|
}) {
|
|
const img = await materializeImageRef(selectedImage)
|
|
const storedImage = img.path || img.base64 || selectedImage
|
|
uni.setStorageSync(CRAFT_SELECTED_IMAGE_KEY, storedImage)
|
|
uni.setStorageSync(CRAFT_SELECTED_INDEX_KEY, String(selectedIndex ?? 0))
|
|
|
|
if (formData?.studio_kind === STUDIO_LENTICULAR) {
|
|
const subjectRef = storedImage
|
|
uni.setStorageSync(
|
|
LENTICULAR_STUDIO_STORAGE_KEY,
|
|
JSON.stringify({
|
|
bgPath: formData.lenticularBgImage || '',
|
|
subjectPath: subjectRef,
|
|
bgBase64: formData.lenticularBgBase64 || '',
|
|
subjectBase64: img.base64 || formData.lenticularSubjectBase64 || '',
|
|
nftInfo: formData.info || formData.nftInfo || '',
|
|
materialTypeIndex: formData.materialTypeIndex ?? 0,
|
|
aiDescription: formData.aiDescription || '',
|
|
})
|
|
)
|
|
} else if (formData?.studio_kind === STUDIO_LASER) {
|
|
uni.setStorageSync(
|
|
CASTLOVE_LASER_ENTRY_KEY,
|
|
JSON.stringify({
|
|
nftInfo: formData.info || formData.nftInfo || '',
|
|
materialTypes: formData.materialTypes || [],
|
|
materialTypeIndex: formData.materialTypeIndex ?? 0,
|
|
pageName: formData.craft_name || formData.typeName || '',
|
|
uploadedImage: storedImage,
|
|
uploadedImageBase64: img.base64 || formData.uploadedImageBase64 || '',
|
|
})
|
|
)
|
|
}
|
|
|
|
const kind = formData?.studio_kind || ''
|
|
uni.navigateTo({
|
|
url: `${ASSET_DETAIL_URL}?from=craft_confirm&studio_kind=${encodeURIComponent(kind)}`,
|
|
})
|
|
}
|
|
|
|
export function isDetailAfterSelect(formData) {
|
|
return formData?.generation_after === AFTER_SELECT_DETAIL
|
|
}
|
|
|
|
export function isLenticularKind(formData) {
|
|
return formData?.studio_kind === STUDIO_LENTICULAR
|
|
}
|
|
|
|
export function isLaserKind(formData) {
|
|
return formData?.studio_kind === STUDIO_LASER
|
|
}
|
|
|
|
export function consumeGenerationFlowPayload() {
|
|
try {
|
|
const raw = uni.getStorageSync(GENERATION_FLOW_KEY)
|
|
uni.removeStorageSync(GENERATION_FLOW_KEY)
|
|
if (!raw) {
|
|
return null
|
|
}
|
|
return JSON.parse(raw)
|
|
} catch (e) {
|
|
console.error('[castloveGenerationFlow] consume payload', e)
|
|
return null
|
|
}
|
|
}
|
|
|
|
export { RESULT_URL }
|