追加文档
This commit is contained in:
parent
1e77e93d79
commit
b114ee6e0a
113
document/前端生成PDF并上传后端技术方案.md
Normal file
113
document/前端生成PDF并上传后端技术方案.md
Normal file
@ -0,0 +1,113 @@
|
||||
# 前端生成 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` 访问。
|
||||
|
||||
## 后续扩展
|
||||
- 加页眉页脚(时间、患者信息、页码)。
|
||||
- 报告水印与签章。
|
||||
- 历史报告下载与比对视图。
|
||||
Loading…
Reference in New Issue
Block a user