Files
users/lib/documentation/docx-generator.ts
v0 4ea8963ddc fix: resolve build errors and complete missing files
Fix CSS issues, add missing files, and optimize documentation page.

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2025-07-19 02:39:56 +00:00

211 lines
4.6 KiB
TypeScript

import { Document, Packer, Paragraph, ImageRun, TextRun, HeadingLevel } from "docx"
interface Screenshot {
id: string
name: string
url: string
dataUrl?: string
timestamp: Date
status: string
}
interface DocumentSettings {
title: string
author: string
description: string
includeTimestamp: boolean
includePageUrls: boolean
imageFormat: string
imageQuality: number
pageSize: string
orientation: string
}
export async function generateDocx(screenshots: Screenshot[], settings: DocumentSettings): Promise<ArrayBuffer> {
try {
const children: Paragraph[] = []
// 添加标题
children.push(
new Paragraph({
children: [
new TextRun({
text: settings.title,
bold: true,
size: 32,
}),
],
heading: HeadingLevel.TITLE,
}),
)
// 添加描述
if (settings.description) {
children.push(
new Paragraph({
children: [
new TextRun({
text: settings.description,
size: 24,
}),
],
}),
)
}
// 添加生成信息
if (settings.includeTimestamp) {
children.push(
new Paragraph({
children: [
new TextRun({
text: `生成时间: ${new Date().toLocaleString()}`,
size: 20,
italics: true,
}),
],
}),
)
}
children.push(
new Paragraph({
children: [
new TextRun({
text: `作者: ${settings.author}`,
size: 20,
italics: true,
}),
],
}),
)
// 添加分隔符
children.push(
new Paragraph({
children: [
new TextRun({
text: "─".repeat(50),
size: 20,
}),
],
}),
)
// 添加每个截图
for (const screenshot of screenshots) {
// 页面标题
children.push(
new Paragraph({
children: [
new TextRun({
text: screenshot.name,
bold: true,
size: 28,
}),
],
heading: HeadingLevel.HEADING_1,
}),
)
// 页面URL
if (settings.includePageUrls) {
children.push(
new Paragraph({
children: [
new TextRun({
text: `页面地址: ${screenshot.url}`,
size: 20,
color: "666666",
}),
],
}),
)
}
// 截图时间
if (settings.includeTimestamp) {
children.push(
new Paragraph({
children: [
new TextRun({
text: `截图时间: ${screenshot.timestamp.toLocaleString()}`,
size: 20,
color: "666666",
}),
],
}),
)
}
// 添加截图
if (screenshot.dataUrl) {
try {
// 将 dataUrl 转换为 ArrayBuffer
const base64Data = screenshot.dataUrl.split(",")[1]
const binaryString = atob(base64Data)
const bytes = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i)
}
children.push(
new Paragraph({
children: [
new ImageRun({
data: bytes,
transformation: {
width: 600,
height: 400,
},
}),
],
}),
)
} catch (error) {
console.error("添加图片失败:", error)
children.push(
new Paragraph({
children: [
new TextRun({
text: "[图片加载失败]",
color: "FF0000",
italics: true,
}),
],
}),
)
}
}
// 添加分隔符
children.push(
new Paragraph({
children: [
new TextRun({
text: "",
}),
],
}),
)
}
// 创建文档
const doc = new Document({
sections: [
{
properties: {},
children: children,
},
],
})
// 生成文档
const buffer = await Packer.toBuffer(doc)
return buffer
} catch (error) {
console.error("生成文档失败:", error)
throw new Error(`文档生成失败: ${error instanceof Error ? error.message : "未知错误"}`)
}
}