26 lines
2.9 KiB
TypeScript
26 lines
2.9 KiB
TypeScript
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<DesignRow,'id'|'layout_id'>)=>`/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<DesignRow>{
|
||
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};
|
||
}
|