import {randomUUID} from 'node:crypto'; import type {PoolClient} from 'pg'; import type {Parameters} from './layout-parameters'; export type DesignRow={document?:import('./series').Series;id:string;layout_id:string;name:string;parameters:Parameters;revision:number;post_id:string|null;archived?:boolean;created_at:Date;updated_at:Date}; export const studioPageUrl=(design:Pick)=>`/studio/template-layout?id=${design.id}`; function postDescription(design:DesignRow){if(design.document)return `${design.document.pages.length}页图文作品 · ${design.document.brief.intent}`;return `已保存的 ${design.layout_id} 排版结果,打开链接即显示图片与文字。`} /** Caller holds the design row lock. All writes share the design's transaction. */ export async function ensureDesignPost(client:PoolClient,design:DesignRow):Promise{ if(design.post_id){ // A manually edited Wiki note keeps its own title, body, tags and cover. await client.query('UPDATE posts SET title=$2,description=$3,updated_at=now() WHERE id=$1 AND edited_at IS NULL',[design.post_id,design.name,postDescription(design)]); return design; } const postId=randomUUID(),textId=randomUUID(),imageIds=[...new Set((design.document?design.document.pages.flatMap(p=>Object.values(p.parameters.images)):Object.values(design.parameters.images||{})).flatMap(image=>image.assetId?[image.assetId]:[]))]; const images=imageIds.length?(await client.query("SELECT id FROM assets WHERE id=ANY($1::uuid[]) AND kind='image'",[imageIds])).rows.map(row=>row.id as string):[]; const body=(design.document?`作品:${design.document.brief.topic}\n\n设计:${design.document.brief.designIntent}\n\n${design.document.pages.map((p,i)=>`${i+1}. ${p.role} · ${p.intent}`).join('\n')}\n\n`:'')+`[打开排版结果](${studioPageUrl(design)})\n\n排版:${design.layout_id}\n\n页面 ID:\`${design.id}\`\n\n此笔记关联 API 保存的模板、图片与文字;直接打开链接即可看到结果,无需选择排版或进入编辑器。`; await client.query("INSERT INTO posts(id,slug,kind,title,description,cover_asset_id) VALUES($1,$2,'article',$3,$4,$5)",[postId,'studio-design-'+design.id,design.name,postDescription(design),images[0]||null]); await client.query("INSERT INTO assets(id,kind,body) VALUES($1,'text',$2)",[textId,body]); await client.query("INSERT INTO post_assets(post_id,asset_id,position,role) VALUES($1,$2,0,'caption')",[postId,textId]); for(const [index,imageId] of images.entries())await client.query("INSERT INTO post_assets(post_id,asset_id,position,role) VALUES($1,$2,$3,'content')",[postId,imageId,index+1]); await client.query("INSERT INTO post_tags(post_id,tag_id) SELECT $1,id FROM tags WHERE name='高级感排版' AND kind='normal' ON CONFLICT DO NOTHING",[postId]); await client.query('UPDATE studio_designs SET post_id=$2 WHERE id=$1',[design.id,postId]); return {...design,post_id:postId}; }