返回 oh-my-ppt
template-manifest.ts
根目录 / src / main / templates / template-manifest.ts
1 import {
2 requirePersistedSlideSize,
3 type SlideSizePresetId
4 } from '@shared/slide-size'
5
6 export type TemplateSource = 'user'
7
8 export interface TemplateManifestPage {
9 pageNumber: number
10 pageId: string
11 title: string
12 htmlPath: string
13 }
14
15 export interface TemplateManifest {
16 schemaVersion: 1
17 id: string
18 name: string
19 description: string
20 sourceSessionId?: string
21 createdAt: number
22 updatedAt: number
23 pageCount: number
24 tags: string[]
25 styleId?: string | null
26 slideSizeId: SlideSizePresetId
27 slideWidth: number
28 slideHeight: number
29 designContract?: unknown
30 pages: TemplateManifestPage[]
31 }
32
33 export interface TemplateListItem {
34 id: string
35 name: string
36 description: string
37 source: TemplateSource
38 pageCount: number
39 tags: string[]
40 slideSizeId: SlideSizePresetId
41 slideWidth: number
42 slideHeight: number
43 previewHtmlPath: string | null
44 thumbnailPath: string | null
45 previewPages: Array<{
46 pageNumber: number
47 pageId: string
48 title: string
49 htmlPath: string
50 }>
51 createdAt: number
52 updatedAt: number
53 }
54
55 const asString = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')
56
57 const asNumber = (value: unknown): number =>
58 typeof value === 'number' && Number.isFinite(value) ? value : 0
59
60 export function parseTemplateManifest(raw: unknown): TemplateManifest {
61 const record = raw && typeof raw === 'object' ? (raw as Record<string, unknown>) : {}
62 const id = asString(record.id)
63 const name = asString(record.name)
64 if (!id) throw new Error('模板 manifest 缺少 id')
65 if (!name) throw new Error('模板 manifest 缺少 name')
66 const slideSize = requirePersistedSlideSize({
67 id: asString(record.slideSizeId),
68 width: asNumber(record.slideWidth),
69 height: asNumber(record.slideHeight)
70 })
71
72 const rawPages = Array.isArray(record.pages) ? record.pages : []
73 const pages = rawPages
74 .map((item, index): TemplateManifestPage => {
75 const page = item && typeof item === 'object' ? (item as Record<string, unknown>) : {}
76 const pageNumber = Math.max(1, Math.floor(asNumber(page.pageNumber) || index + 1))
77 const pageId = asString(page.pageId) || `page-${pageNumber}`
78 return {
79 pageNumber,
80 pageId,
81 title: asString(page.title) || `第 ${pageNumber} 页`,
82 htmlPath: asString(page.htmlPath) || `pages/${pageId}.html`
83 }
84 })
85 .sort((a, b) => a.pageNumber - b.pageNumber)
86
87 return {
88 schemaVersion: 1,
89 id,
90 name,
91 description: asString(record.description),
92 sourceSessionId: asString(record.sourceSessionId) || undefined,
93 createdAt: asNumber(record.createdAt) || Date.now(),
94 updatedAt: asNumber(record.updatedAt) || Date.now(),
95 pageCount: Math.max(0, Math.floor(asNumber(record.pageCount) || pages.length)),
96 tags: Array.isArray(record.tags)
97 ? record.tags.map((tag) => asString(tag)).filter(Boolean).slice(0, 12)
98 : [],
99 styleId: asString(record.styleId) || null,
100 slideSizeId: slideSize.id,
101 slideWidth: slideSize.width,
102 slideHeight: slideSize.height,
103 designContract: record.designContract,
104 pages
105 }
106 }
107
108 export function manifestToListItem(
109 manifest: TemplateManifest,
110 paths: {
111 previewHtmlPath: string | null
112 previewPages: TemplateListItem['previewPages']
113 }
114 ): TemplateListItem {
115 return {
116 id: manifest.id,
117 name: manifest.name,
118 description: manifest.description,
119 source: 'user',
120 pageCount: manifest.pageCount || manifest.pages.length,
121 tags: manifest.tags,
122 slideSizeId: manifest.slideSizeId,
123 slideWidth: manifest.slideWidth,
124 slideHeight: manifest.slideHeight,
125 previewHtmlPath: paths.previewHtmlPath,
126 thumbnailPath: null,
127 previewPages: paths.previewPages,
128 createdAt: manifest.createdAt,
129 updatedAt: manifest.updatedAt
130 }
131 }
132
132 lines TYPESCRIPT