Redesign navigation, home overview, user portrait, and valuation pages with improved functionality and responsive design. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
177 lines
5.7 KiB
TypeScript
177 lines
5.7 KiB
TypeScript
"use client"
|
||
|
||
import { useState, useEffect } from "react"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Card, CardContent } from "@/components/ui/card"
|
||
import { Textarea } from "@/components/ui/textarea"
|
||
import { Label } from "@/components/ui/label"
|
||
import { Alert, AlertDescription } from "@/components/ui/alert"
|
||
import { Loader2, FileText, AlertTriangle } from "lucide-react"
|
||
import { generateDocx } from "@/lib/documentation/docx-generator"
|
||
|
||
interface DocumentSection {
|
||
title: string
|
||
path: string
|
||
description: string
|
||
screenshot: string
|
||
}
|
||
|
||
interface DocumentGeneratorProps {
|
||
pages: Array<{ path: string; title: string; description: string }>
|
||
screenshots: Record<string, string>
|
||
onDocumentGenerated: (url: string) => void
|
||
}
|
||
|
||
export default function DocumentGenerator({ pages, screenshots, onDocumentGenerated }: DocumentGeneratorProps) {
|
||
const [isGenerating, setIsGenerating] = useState(false)
|
||
const [error, setError] = useState<string | null>(null)
|
||
const [sections, setSections] = useState<DocumentSection[]>([])
|
||
const [descriptions, setDescriptions] = useState<Record<string, string>>({})
|
||
|
||
// 初始化页面描述
|
||
useEffect(() => {
|
||
const initialDescriptions: Record<string, string> = {}
|
||
pages.forEach((page) => {
|
||
initialDescriptions[page.path] = page.description || ""
|
||
})
|
||
setDescriptions(initialDescriptions)
|
||
}, [pages])
|
||
|
||
// 更新页面描述
|
||
const updateDescription = (path: string, description: string) => {
|
||
setDescriptions((prev) => ({
|
||
...prev,
|
||
[path]: description,
|
||
}))
|
||
}
|
||
|
||
// 准备文档部分
|
||
useEffect(() => {
|
||
const newSections = pages
|
||
.filter((page) => screenshots[page.path])
|
||
.map((page) => ({
|
||
title: page.title,
|
||
path: page.path,
|
||
description: descriptions[page.path] || page.description || "",
|
||
screenshot: screenshots[page.path],
|
||
}))
|
||
|
||
setSections(newSections)
|
||
}, [pages, screenshots, descriptions])
|
||
|
||
// 生成文档
|
||
const generateDocument = async () => {
|
||
if (sections.length === 0) {
|
||
setError("没有可用的截图,请先捕获页面截图")
|
||
return
|
||
}
|
||
|
||
setIsGenerating(true)
|
||
setError(null)
|
||
|
||
try {
|
||
console.log("开始生成文档...")
|
||
console.log("文档部分数量:", sections.length)
|
||
|
||
// 准备文档数据
|
||
const documentData = {
|
||
title: "用户数据资产中台使用手册",
|
||
author: "系统管理员",
|
||
date: new Date().toLocaleDateString("zh-CN"),
|
||
sections: sections,
|
||
}
|
||
|
||
console.log("文档数据准备完成")
|
||
|
||
// 生成Word文档
|
||
const docxUrl = await generateDocx(documentData)
|
||
console.log("文档生成成功:", docxUrl)
|
||
|
||
// 调用回调函数
|
||
onDocumentGenerated(docxUrl)
|
||
} catch (error) {
|
||
console.error("生成文档时出错:", error)
|
||
setError(`生成文档时出错: ${error instanceof Error ? error.message : String(error)}`)
|
||
} finally {
|
||
setIsGenerating(false)
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<div className="flex justify-between items-center">
|
||
<h2 className="text-xl font-semibold">文档内容编辑</h2>
|
||
<Button
|
||
onClick={generateDocument}
|
||
disabled={isGenerating || sections.length === 0}
|
||
className="flex items-center gap-2"
|
||
>
|
||
{isGenerating ? (
|
||
<>
|
||
<Loader2 className="h-4 w-4 animate-spin" />
|
||
生成中...
|
||
</>
|
||
) : (
|
||
<>
|
||
<FileText className="h-4 w-4" />
|
||
生成文档
|
||
</>
|
||
)}
|
||
</Button>
|
||
</div>
|
||
|
||
{error && (
|
||
<Alert variant="destructive">
|
||
<AlertTriangle className="h-4 w-4" />
|
||
<AlertDescription>{error}</AlertDescription>
|
||
</Alert>
|
||
)}
|
||
|
||
{sections.length === 0 ? (
|
||
<div className="text-center py-8">
|
||
<p className="text-gray-500">没有可用的截图</p>
|
||
<p className="text-sm text-gray-400 mt-1">请先捕获页面截图</p>
|
||
</div>
|
||
) : (
|
||
<div className="space-y-4">
|
||
<p className="text-sm text-gray-500">
|
||
已捕获 {sections.length} 个页面的截图。您可以编辑每个页面的描述,然后生成文档。
|
||
</p>
|
||
|
||
{sections.map((section) => (
|
||
<Card key={section.path} className="overflow-hidden">
|
||
<CardContent className="p-4">
|
||
<div className="flex flex-col md:flex-row gap-4">
|
||
<div className="md:w-1/3">
|
||
<div className="border rounded-md overflow-hidden">
|
||
<img
|
||
src={section.screenshot || "/placeholder.svg"}
|
||
alt={section.title}
|
||
className="w-full h-auto object-contain"
|
||
/>
|
||
</div>
|
||
<p className="text-sm font-medium mt-2">{section.title}</p>
|
||
<p className="text-xs text-gray-500">{section.path}</p>
|
||
</div>
|
||
<div className="md:w-2/3">
|
||
<div className="space-y-2">
|
||
<Label htmlFor={`desc-${section.path}`}>页面描述</Label>
|
||
<Textarea
|
||
id={`desc-${section.path}`}
|
||
value={descriptions[section.path] || ""}
|
||
onChange={(e) => updateDescription(section.path, e.target.value)}
|
||
placeholder="输入此页面的详细描述"
|
||
rows={6}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|