BodyBalanceEvaluation/document/前端生成PDF并上传后端技术方案.md

114 lines
4.5 KiB
Markdown
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.

# 前端生成 PDF 并上传后端技术方案
## 概述
- 目标:诊断报告页面在前端生成高保真 PDF上传到 Python 后端持久化,并把文件路径写入对应检测会话。
- 推荐:使用 Electron 主进程 `webContents.printToPDF` 生成 PDF忠实度高、分页与中文字体友好作为短期备选提供 `html2canvas` 截图转 PDF 的实现。
## 架构流程
- 前端渲染进程:用户在报告页面点击“生成报告”→ 发送 IPC 请求至主进程生成 PDF → 主进程返回 PDF Buffer 给渲染进程 → 渲染进程上传后端。
- Python 后端:接收 PDF 文件流,写入 `backend/static/reports/<YYYY-MM-DD>/<session_id>.pdf`,记录相对路径到 `detection_sessions` 的报告字段。
## 前端实现Electron 渲染)
### 报告页面打印版式
- 报告根容器,例如 `#report-root`
- 打印样式建议:
- `@page { size: A4; margin: 12mm }`
- 固定宽度设计为 A4 比例,非交互元素隐藏,保留背景。
- 通过添加类名(例如 `.print-mode`)切换打印样式。
### 渲染进程触发生成
```ts
// renderer: 诊断报告视图中
import { ipcRenderer } from 'electron'
async function generatePdf(sessionId: string) {
const pdfBuffer: ArrayBuffer = await ipcRenderer.invoke('generate-report-pdf', {
selector: '#report-root',
pageSize: 'A4',
printBackground: true
})
const blob = new Blob([pdfBuffer], { type: 'application/pdf' })
const form = new FormData()
form.append('file', blob, `${sessionId}.pdf`)
const res = await fetch(`${getBackendUrl()}/api/reports/${sessionId}/upload`, {
method: 'POST',
body: form
})
const json = await res.json()
if (!json.success) throw new Error(json.error || '上传失败')
}
```
### 主进程生成 PDF
```ts
// main: 注册 IPC 处理
import { ipcMain } from 'electron'
ipcMain.handle('generate-report-pdf', async (event, payload) => {
const win = event.sender.getOwnerBrowserWindow()
await win.webContents.executeJavaScript(`
(function(){
const root = document.querySelector('${payload.selector}')
if (!root) throw new Error('报告根节点缺失')
document.body.classList.add('print-mode')
return true
})()
`)
const pdf = await win.webContents.printToPDF({
pageSize: payload.pageSize || 'A4',
printBackground: payload.printBackground !== false,
marginsType: 0
})
await win.webContents.executeJavaScript(`
(function(){ document.body.classList.remove('print-mode'); return true })()
`)
return pdf
})
```
### 更新数据库记录
```py
# database.py 片段
def update_session_report_path(self, session_id: str, report_path: str):
conn = self.get_connection()
cursor = conn.cursor()
cursor.execute('UPDATE detection_sessions SET detection_report = ? WHERE id = ?', (report_path, session_id))
conn.commit()
```
## 接口设计
- 上传 PDF`POST /api/reports/<session_id>/upload`
- 请求体:`multipart/form-data`,字段 `file`
- 返回:`{ success, path }`
## 权限与安全
- 校验 `session_id` 存在且归属当前登录用户(医生)。
- 限制最大文件大小(例如 20MB拒绝超限上传。
- 文件名使用 `session_id.pdf`,避免任意文件名写盘。
## 版式与质量建议
- 中文字体:在渲染环境预装中文字体或通过 `@font-face` 引入。
- 分页:使用 `@page``page-break-before/after` 控制分页。
- 背景Electron 打印需开启 `printBackground: true`;确保 CSS 背景不被打印忽略。
## 错误与排查
- 空白 PDF确保打印前切入 `.print-mode` 并等待资源加载;检查选择器是否找到根节点。
- 字体方框:安装中文字体或嵌入字体文件。
- 资源丢失:使用相对路径或 base64`html2canvas` 时启用 `useCORS` 且服务器设置跨域头。
- 过大或截断:分页控制,或拆页生成。
## 测试用例
- 单页报告:生成并上传,后端返回路径;数据库记录更新;历史档案中可下载或预览。
- 多页报告:存在分页断点,打印后为多页;每页标题和页码正常。
- 异常:网络断开、文件超限、会话不存在;前端提示具体错误。
## 部署说明
- Electron 打包:已使用 `electron-builder`;生成 exe 后功能一致。
- 后端存储Windows 下路径统一使用 `/` 展示;静态文件由后端提供下载或前端拼接 `BACKEND_URL + '/' + path` 访问。
## 后续扩展
- 加页眉页脚(时间、患者信息、页码)。
- 报告水印与签章。
- 历史报告下载与比对视图。