175 lines
6.9 KiB
Markdown
175 lines
6.9 KiB
Markdown
# 手术图文病历报告系统 — 工程整体分析
|
||
|
||
> 版本:V1.3
|
||
> 最后更新:2026-04-19
|
||
> 分析维度:架构、数据流、核心模块、风险点、扩展方向
|
||
|
||
---
|
||
|
||
## 一、项目定位
|
||
|
||
**手术图文病历报告系统** 是一款面向医院手术室场景的纯前端单页应用(SPA),核心能力包括:
|
||
|
||
- 富文本编辑器撰写结构化手术图文报告
|
||
- 手术视频上传 + 自动/手动关键帧抽取,拖拽插入报告
|
||
- 报告模板管理、用户权限(RBAC)、系统设置
|
||
- 导出 PDF / JSON 格式报告与模板
|
||
|
||
**关键约束**:无后端服务器,所有数据持久化在浏览器 `localStorage`(约 5MB 容量上限)。
|
||
|
||
---
|
||
|
||
## 二、技术栈
|
||
|
||
| 层级 | 技术 |
|
||
|------|------|
|
||
| 框架 | React 19 + TypeScript 5.8 |
|
||
| 构建 | Vite 6 |
|
||
| 样式 | Tailwind CSS v4(`@theme` / `@import "tailwindcss"` 新语法) |
|
||
| 路由 | React Router DOM v7 |
|
||
| 图标 | lucide-react |
|
||
| 动画 | motion |
|
||
| AI SDK | `@google/genai`(已安装,业务代码中**未实际调用**) |
|
||
|
||
**无 ESLint、无 Prettier、无单元测试框架**,唯一类型检查为 `tsc --noEmit`。
|
||
|
||
---
|
||
|
||
## 三、项目结构
|
||
|
||
```
|
||
src/
|
||
├── components/
|
||
│ └── Sidebar.tsx # 左侧导航(角色过滤、自动折叠)
|
||
├── pages/
|
||
│ ├── Login.tsx # 登录页 + 全局 initData(默认用户/模板/字段/素材)
|
||
│ ├── Dashboard.tsx # 工作台(统计卡片、SVG 趋势图)
|
||
│ ├── ReportEditor.tsx # 核心:报告编辑器(2,200+ 行,最大文件)
|
||
│ ├── ReportManage.tsx # 报告列表(搜索、筛选、批量操作、历史回溯)
|
||
│ ├── ReportView.tsx # 报告只读查看 + 打印
|
||
│ ├── TemplateManage.tsx # 模板编辑器(1,600+ 行,自定义 Undo/Redo)
|
||
│ ├── UserManage.tsx # 用户管理(RBAC、签名上传、模板权限)
|
||
│ └── SystemSettings.tsx # 系统设置(抽帧配置、AI API、默认模板)
|
||
├── utils/
|
||
│ ├── storage.ts # localStorage / sessionStorage 封装
|
||
│ ├── print.ts # iframe 打印工具(A4 样式、@page 边距)
|
||
│ └── defaultContent.ts # 默认模板 HTML(腹腔镜胆囊切除术报告)
|
||
├── App.tsx # BrowserRouter + 路由表
|
||
├── main.tsx # React 根挂载(StrictMode)
|
||
├── types.ts # 核心 TypeScript 类型
|
||
└── index.css # Tailwind 入口 + @theme 变量 + 打印媒体查询
|
||
```
|
||
|
||
---
|
||
|
||
## 四、数据持久化架构
|
||
|
||
**无全局状态库**(无 Redux/Zustand/Context)。每个页面独立通过 `useState` + `useEffect` 管理状态,`localStorage` 即数据库。
|
||
|
||
| localStorage Key | 说明 |
|
||
|------------------|------|
|
||
| `users` | 用户列表 |
|
||
| `currentUser` | 当前登录用户 |
|
||
| `reports` | 报告列表 |
|
||
| `templates` | 模板列表 |
|
||
| `systemSettings` | 系统设置 |
|
||
| `formFieldsConfig` | 动态字段配置 |
|
||
| `imageAssets` | 系统素材库(Base64 图片) |
|
||
| `reportEditorDraft_${username}` | 每用户报告草稿 |
|
||
| `customTimeFormats` | 用户自定义时间格式缓存 |
|
||
|
||
**容量风险**:关键帧采用 Canvas 压缩(最大宽度 800px、JPEG 质量 0.6)以控制体积。`storage.ts` 异常已改为 `console.error` 输出,不再静默吞掉。
|
||
|
||
---
|
||
|
||
## 五、核心模块深度分析
|
||
|
||
### 5.1 富文本编辑器(ReportEditor / TemplateManage)
|
||
|
||
- **底层**:原生 `contentEditable` + `document.execCommand`
|
||
- **智能字段(Smart Field)三层嵌套**:
|
||
```html
|
||
<span class="smart-field-wrapper" contenteditable="false">
|
||
<span class="field-label">标签:</span>
|
||
<span class="field-value" contenteditable="true" data-bind="key"></span>
|
||
</span>​
|
||
```
|
||
- 外层 `contenteditable="false"` 保护标签不被逐字删除
|
||
- 输入层 `data-bind` 实现与右侧表单双向绑定
|
||
- 末尾追加 `​`(零宽空格)防止排版换行异常
|
||
- **图片占位符**:`<span class="image-placeholder">`,支持 `data-mode="frame|manual"` 分类隔离
|
||
- **自定义 Undo/Redo**(TemplateManage):基于 HTML 字符串快照的 `undoStack`/`redoStack`,完全接管撤销逻辑
|
||
|
||
### 5.2 视频分析(ReportEditor)
|
||
|
||
- 上传本地视频 → 生成 object URL
|
||
- 自动抽帧:按 `systemSettings.framePositions` 百分比位置逐帧截图
|
||
- 手动截图:点击按钮从当前播放时间捕获
|
||
- 图片压缩:Canvas 等比缩放至最大 800px 宽,JPEG 质量 0.6
|
||
- 非阻塞 `setTimeout` 队列式自动帧插入,避免阻塞抽帧循环
|
||
|
||
### 5.3 打印系统(utils/print.ts)
|
||
|
||
- 创建隐藏 iframe,写入带 A4 打印样式的 HTML
|
||
- `@page { margin: 15mm 10mm; }` 为**每一页**纸张独立分配边距
|
||
- `body { padding: 0 }` — 不可用 body padding 代替 @page margin
|
||
- 打印前临时设置 `document.title` 并注入 iframe `<title>`,确保 PDF 默认文件名正确
|
||
|
||
### 5.4 角色权限(RBAC)
|
||
|
||
| 角色 | 权限 |
|
||
|------|------|
|
||
| `super` | 全部页面、全部数据 |
|
||
| `admin` | 仅管理本科室用户;可管理模板;不能看系统设置中的 AI 配置 |
|
||
| `user` | 仅创建/查看/编辑自己的报告;可见被分配模板 |
|
||
|
||
---
|
||
|
||
## 六、高风险修改区域
|
||
|
||
以下模块**牵一发而动全身**,修改时必须同步检索所有相关文件:
|
||
|
||
1. **智能字段结构** → `types.ts`、`defaultContent.ts`、`ReportEditor.tsx`、`TemplateManage.tsx`、`index.css`、`print.ts`
|
||
2. **图片占位符(创建/填充/删除恢复)** → `defaultContent.ts`、`ReportEditor.tsx`、`TemplateManage.tsx`
|
||
3. **打印样式** → `print.ts`、`index.css`(`@media print`)
|
||
4. **时间/日期格式** → `types.ts`、`ReportEditor.tsx`、`TemplateManage.tsx`
|
||
5. **数据初始化/默认值** → `Login.tsx`、`SystemSettings.tsx`
|
||
6. **自动保存/草稿** → `ReportEditor.tsx` 中的 `saveDraftToStorage`、`stateRef`、`contentRef`
|
||
|
||
---
|
||
|
||
## 七、构建与部署
|
||
|
||
```bash
|
||
# 开发
|
||
npm run dev # vite --port=3000 --host=0.0.0.0
|
||
|
||
# 生产构建
|
||
npm run build # vite build → dist/
|
||
npm run preview # vite preview(默认端口 4173)
|
||
|
||
# 类型检查
|
||
npm run lint # tsc --noEmit
|
||
```
|
||
|
||
**当前部署状态**:通过 `npm run build && npm run preview -- --host` 在本机运行。
|
||
|
||
---
|
||
|
||
## 八、安全与限制
|
||
|
||
1. **密码明文存储**:`localStorage` 中 `users` 数组明文保存密码,纯前端架构固有限制
|
||
2. **XSS 风险**:报告/模板内容直接以 HTML 字符串存储并在 `innerHTML` 中渲染
|
||
3. **Gemini API Key**:通过 Vite `define` 注入客户端,构建后 key 暴露在静态 JS 中(当前源码未实际调用)
|
||
4. **无 HTTPS 强制**:Docker 部署默认 HTTP 80 端口
|
||
|
||
---
|
||
|
||
## 九、默认账号
|
||
|
||
| 账号 | 密码 | 角色 |
|
||
|------|------|------|
|
||
| admin | 123456 | super |
|
||
| manager | 123456 | admin |
|
||
| doctor / 0001 | 123456 | user |
|