feat: 报告生成扩展 PPT/Word/Excel 多格式导出

- 新增 ExportReportDOCX 导出 Word 文档(纯标准库)
- 新增 ExportReportPPTX 导出 PPT 演示文稿(纯标准库)
- 新增 ExportReportXLSX 导出 Excel 表格(纯标准库)
- 新增 /api/report/export/{docx,pptx,xlsx} 路由
- 前端增加多格式导出下拉菜单(PDF/Word/PPT/Excel)
- 前端导出函数按格式名提示成功信息
- 零网络依赖,纯 Go 标准库实现
This commit is contained in:
eaiadmin
2026-09-13 22:09:19 +08:00
parent c8781bfe90
commit 8c33dde2d6
8 changed files with 319 additions and 17 deletions
+12
View File
@@ -8,6 +8,18 @@ export function exportReportPDF(data) {
return http.post('/report/export/pdf', data, { responseType: 'blob' })
}
export function exportReportDOCX(data) {
return http.post('/report/export/docx', data, { responseType: 'blob' })
}
export function exportReportPPTX(data) {
return http.post('/report/export/pptx', data, { responseType: 'blob' })
}
export function exportReportXLSX(data) {
return http.post('/report/export/xlsx', data, { responseType: 'blob' })
}
export function previewReport(data) {
return http.post('/report/preview', data)
}
@@ -97,10 +97,20 @@
</span>
</div>
<div class="card-actions" v-if="reportContent">
<el-button size="small" :loading="exporting" @click="exportToPDF">
<el-icon><Download /></el-icon>
导出 PDF
</el-button>
<el-dropdown trigger="click" @command="exportReport">
<el-button size="small" :loading="exporting">
<el-icon><Download /></el-icon>
导出 <el-icon><ArrowDown /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="pdf"><el-icon><Document /></el-icon> PDF 文档</el-dropdown-item>
<el-dropdown-item command="docx"><el-icon><Reading /></el-icon> Word 文档</el-dropdown-item>
<el-dropdown-item command="pptx"><el-icon><Grid /></el-icon> PPT 演示文稿</el-dropdown-item>
<el-dropdown-item command="xlsx"><el-icon><Reading /></el-icon> Excel 表格</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button size="small" @click="resetReport">
清除
</el-button>
@@ -148,8 +158,8 @@
<script setup>
import { onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { Edit, Download } from '@element-plus/icons-vue'
import { generateReport, exportReportPDF } from '@/api/report'
import { Edit, Download, Document, Reading, ArrowDown, Grid } from '@element-plus/icons-vue'
import { generateReport as apiGenerateReport, exportReportPDF, exportReportDOCX, exportReportPPTX, exportReportXLSX } from '@/api/report'
import { listKnowledgeSpaces } from '@/api/knowledge'
const generating = ref(false)
@@ -173,7 +183,7 @@ async function generateReport() {
generating.value = true
try {
const res = await generateReport({
const res = await apiGenerateReport({
topic: form.value.topic.trim(),
summary: form.value.summary,
sections: form.value.sections,
@@ -197,28 +207,44 @@ async function generateReport() {
}
}
async function exportToPDF() {
async function exportReport(command) {
if (!reportContent.value) return
exporting.value = true
try {
const blob = await exportReportPDF({
report: reportContent.value,
})
// 下载 PDF
const formatNames = { pdf: 'PDF', docx: 'Word', pptx: 'PPT', xlsx: 'Excel' }
const exts = { pdf: '.pdf', docx: '.docx', pptx: '.pptx', xlsx: '.xlsx' }
const formatName = formatNames[command] || '文件'
const ext = exts[command] || '.pdf'
let blob
switch (command) {
case 'pdf':
blob = await exportReportPDF({ report: reportContent.value })
break
case 'docx':
blob = await exportReportDOCX({ report: reportContent.value })
break
case 'pptx':
blob = await exportReportPPTX({ report: reportContent.value })
break
case 'xlsx':
blob = await exportReportXLSX({ report: reportContent.value })
break
default:
return
}
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
const filename = (reportContent.value.topic || 'report') + '.pdf'
a.download = filename.replace(/[^a-zA-Z一-龥 -￿]/g, '_')
const filename = (reportContent.value.topic || 'report') + ext
a.download = filename.replace(/[^a-zA-Z一-龥龥 -￿]/g, '_')
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
ElMessage.success('PDF 已下载')
ElMessage.success(`${formatName} 已下载`)
} catch (error) {
ElMessage.error('PDF 导出失败')
ElMessage.error(`${formatName} 导出失败`)
} finally {
exporting.value = false
}