Files
probably-rendering-one-more…/apps/waterfall-wiki/src/lib/studio-design-posts.ts
T
codex-bot 174a3ef266
studio CI and deployment / verify-and-deploy (pull_request) Failing after 3m51s
waterfall-wiki CI and deployment / verify-and-deploy (pull_request) Failing after 2m58s
Add versioned multi-page Studio artwork documents and native exports
2026-10-28 23:36:54 +08:00

26 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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};
}