import { BackendAsset, CanvasDocument, CanvasTemplate } from '../types'; import { apiUrl, ensureOk } from './api'; import { cloneDocument, normalizeDocument } from './canvasDocument'; export function templateId(template: CanvasTemplate) { return template.template_id || template.id || ''; } export function templateCreatedAt(template: CanvasTemplate) { return template.created_at || template.createdAt || ''; } export function templateUpdatedAt(template: CanvasTemplate) { return template.updated_at || template.updatedAt || ''; } export function templateReferenceIds(template: CanvasTemplate) { return template.reference_asset_ids || template.referenceAssetIds || []; } export function templateCoverId(template: CanvasTemplate) { return template.cover_asset_id || template.coverAssetId || templateReferenceIds(template)[0] || ''; } export async function listDesignTemplates(): Promise { const res = await ensureOk(await fetch(apiUrl('/api/design-templates')), '读取模板库失败'); const items = (await res.json()) as CanvasTemplate[]; return items.map(item => ({ ...item, document: normalizeDocument(item.document) })); } export async function createCanvasTemplate(input: { name: string; description: string; document: CanvasDocument; referenceAssetIds?: string[]; coverAssetId?: string; }): Promise { const fd = new FormData(); fd.append('name', input.name.trim() || '未命名模板'); fd.append('description', input.description.trim()); fd.append('document', JSON.stringify(normalizeDocument(input.document))); fd.append('reference_asset_ids', JSON.stringify(input.referenceAssetIds || [])); fd.append('cover_asset_id', input.coverAssetId || input.referenceAssetIds?.[0] || ''); const res = await ensureOk(await fetch(apiUrl('/api/design-templates'), { method: 'POST', body: fd }), '保存模板失败'); const template = (await res.json()) as CanvasTemplate; return { ...template, document: normalizeDocument(template.document) }; } export async function importCanvasTemplate( file: File, name = '', description = '', ): Promise { const fd = new FormData(); fd.append('file', file); if (name) fd.append('name', name.trim()); if (description) fd.append('description', description.trim()); const res = await ensureOk(await fetch(apiUrl('/api/design-templates/import'), { method: 'POST', body: fd }), '导入设计包失败'); const template = (await res.json()) as CanvasTemplate; return { ...template, document: normalizeDocument(template.document) }; } export async function updateCanvasTemplate( id: string, partial: { name?: string; description?: string; document?: CanvasDocument; referenceAssetIds?: string[]; coverAssetId?: string; }, ): Promise { const fd = new FormData(); if (partial.name !== undefined) fd.append('name', partial.name.trim() || '未命名模板'); if (partial.description !== undefined) fd.append('description', partial.description.trim()); if (partial.document) fd.append('document', JSON.stringify(normalizeDocument(partial.document))); if (partial.referenceAssetIds) fd.append('reference_asset_ids', JSON.stringify(partial.referenceAssetIds)); if (partial.coverAssetId !== undefined) fd.append('cover_asset_id', partial.coverAssetId); const res = await ensureOk(await fetch(apiUrl(`/api/design-templates/${id}`), { method: 'PATCH', body: fd }), '更新模板失败'); const template = (await res.json()) as CanvasTemplate; return { ...template, document: normalizeDocument(template.document) }; } export async function deleteCanvasTemplate(id: string) { await ensureOk(await fetch(apiUrl(`/api/design-templates/${id}`), { method: 'DELETE' }), '删除模板失败'); } export async function listAssets(type = ''): Promise { const query = type ? `?type=${encodeURIComponent(type)}` : ''; const res = await ensureOk(await fetch(apiUrl(`/api/assets${query}`)), '读取素材失败'); return (await res.json()) as BackendAsset[]; } export async function uploadAsset(file: File, type = 'reference'): Promise { const fd = new FormData(); fd.append('file', file); fd.append('name', file.name.replace(/\.(svg|png|jpe?g)$/i, '')); fd.append('type', type); const res = await ensureOk(await fetch(apiUrl('/api/assets'), { method: 'POST', body: fd }), '上传参考图失败'); return (await res.json()) as BackendAsset; } export function assetUrl(assetOrPath?: BackendAsset | string) { if (!assetOrPath) return ''; const raw = typeof assetOrPath === 'string' ? assetOrPath : assetOrPath.file_url; if (!raw) return ''; return apiUrl(raw); } export function duplicateDocument(document: CanvasDocument): CanvasDocument { return cloneDocument(document); }