40 lines
1.9 KiB
TypeScript
40 lines
1.9 KiB
TypeScript
import { DETAIL_FONT_FAMILY, type DetailConfig, type DetailDocument } from '@/lib/detail-generator/types'
|
|
|
|
export class DetailClientError extends Error {
|
|
constructor(message: string, readonly status: number) { super(message) }
|
|
}
|
|
|
|
export async function detailRequest<T>(path: string, init: RequestInit = {}): Promise<T> {
|
|
const response = await fetch(`/api/detail-generator${path}`, {
|
|
...init,
|
|
cache: 'no-store',
|
|
headers: init.body instanceof FormData ? init.headers : { 'Content-Type': 'application/json', ...init.headers },
|
|
})
|
|
const data = await response.json().catch(() => ({}))
|
|
if (!response.ok) throw new DetailClientError(data.error || '操作未完成,请稍后重试', response.status)
|
|
return data as T
|
|
}
|
|
|
|
export function newDetailDocument(defaults?: DetailDocument['models']): DetailDocument {
|
|
return {
|
|
version: 1,
|
|
name: '',
|
|
product: { identifierType: 'sku', identifier: '', variant: '', name: '', facts: '', assetIds: [], referenceAssetIds: [], documentAssetIds: [] },
|
|
brand: { name: '', tone: '', primaryColor: '#1677ff', backgroundColor: '#ffffff', textColor: '#101828', fontFamily: DETAIL_FONT_FAMILY, status: 'draft' },
|
|
models: defaults ? { ...defaults } : { analysis: '', copy: '', image: '' },
|
|
analysis: null,
|
|
approvedAt: null,
|
|
screens: [],
|
|
}
|
|
}
|
|
|
|
export function detailModelsAvailable(config: DetailConfig | null, selected: DetailDocument['models'], stages: Array<keyof DetailDocument['models']>): boolean {
|
|
return config?.configured === true && stages.every((stage) => !!selected[stage] && (config.models[stage].includes(selected[stage]) || config.legacyModels?.[stage]?.includes(selected[stage])))
|
|
}
|
|
|
|
export function assetUrl(id: string) { return `/api/detail-generator/assets/${encodeURIComponent(id)}` }
|
|
|
|
export function actionKey(): string {
|
|
return globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
}
|