Files
Mdeical_Sur_Report/docs/design.md
admin 014aca8619 Initialize backendized SurClaw report system
- Add React/Vite frontend for login, dashboard, reports, templates, users, settings, AI, speech, and media workflows.

- Add NestJS/Prisma/PostgreSQL backend with auth, dashboard stats, reports, templates, users, departments, settings, files, AI, speech, audit logs, and HTML sanitization.

- Add Prisma schema, migrations, seed data, persistent app sessions, Docker/Nginx deployment files, and upload volume configuration.

- Add Vitest, Playwright, backend integration tests, and project documentation for requirements, design, permissions, API contracts, testing, deployment, security, and progress.

- Configure production local fallback switch and remove unused Gemini direct dependency/env wiring.
2026-05-02 01:41:57 +08:00

106 lines
7.2 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.
# 设计文档
## 总体架构
应用是一个 Vite 构建的 React SPA。入口文件为 `src/main.tsx`,路由集中在 `src/App.tsx`。页面级功能位于 `src/pages`,公共侧边栏位于 `src/components/Sidebar.tsx`,数据类型集中在 `src/types.ts`,浏览器存储封装在 `src/utils/storage.ts`
```text
src/
App.tsx 路由定义
main.tsx React 挂载入口
index.css Tailwind 与全局样式
api/ 前端 API client
auth/ 登录态、后端用户兼容映射
types.ts 核心数据类型和默认配置
components/Sidebar.tsx 主导航与登出
pages/ 业务页面
utils/ 存储、打印、默认模板内容
```
## 路由设计
| 路由 | 页面 | 用途 |
| --- | --- | --- |
| `/` | `Login` | 登录和首次数据初始化。 |
| `/dashboard` | `Dashboard` | 工作台统计和快捷入口。 |
| `/report-editor` | `ReportEditor` | 新建报告,或通过 `?id=` 编辑报告。 |
| `/report-manage` | `ReportManage` | 报告检索、历史、导出和删除。 |
| `/report-view/:id` | `ReportView` | 报告只读查看和打印。 |
| `/template-manage` | `TemplateManage` | 模板和字段库维护。 |
| `/user-manage` | `UserManage` | 用户、角色、部门和模板权限管理。 |
| `/system-settings` | `SystemSettings` | 抽帧、AI、语音和默认模板设置。 |
未匹配路由会重定向到登录页。除登录页外,其余路由由 `RequireAuth` 包裹:优先等待 `AuthProvider` 从后端 `/api/auth/me` 恢复会话;没有后端会话和本地兼容缓存时回到 `/`
## 数据设计
核心类型在 `src/types.ts`
- `User`:用户账号、角色、部门、状态、模板权限和签名。
- `Report`报告元信息、患者信息、HTML 正文、视频、关键帧、作者、状态和历史版本。
- `Template`模板名称、描述、HTML 内容、作者和字段配置。
- `FormField`:表单字段定义,支持文本、单选、多选、日期、时间、签名、图片等类型。
- `SystemSettings`抽帧策略、默认模板、AI Provider、语音配置和自动插入设置。
登录认证、报告读写、报告媒体引用、模板读写、字段库、模板图片资源、视频/关键帧文件、用户管理、部门模板授权、系统设置和签名文件已有服务端校验。报告媒体通过 `ReportMedia` 关系表关联 `FileResource`,页面逻辑仍承担一部分迁移期回退约束。
## 状态与持久化
应用使用 React 本地状态管理页面交互。认证态由后端 Session Cookie 维持,前端 `AuthProvider` 会把当前用户同步到 `localStorage.currentUser` 作为迁移期兼容缓存。报告读写已优先走后端 Reports API并同步 `localStorage.reports` 作为开发/显式回退缓存;模板读写已优先走后端 Templates API并同步 `localStorage.templates` 作为开发/显式回退缓存;字段库已优先走 Library API并同步 `formFieldsConfig` 等兼容缓存;模板图片资源已优先走 Files API并同步 `imageAssets` 兼容缓存;用户和部门模板授权已优先走 Users/Departments API并同步 `localStorage.users` 作为兼容缓存;系统设置已优先走 Settings API并同步 `localStorage.systemSettings` 作为开发/显式回退缓存。`storage.get/set` 对常规键做 JSON 读写,对 `systemSettings` 做简单 XOR + Base64 存储;这不是安全加密,只能降低直接可读性。生产构建默认关闭本地回退。
报告编辑器额外使用 `reportEditorDraft_${username}` 保存未提交草稿,使用 `sessionStorage``restore_${reportId}` 暂存历史版本恢复内容。
## 权限设计
当前迁移期权限检查分两层:登录、报告、模板、用户和部门模板授权由后端校验;页面入口和部分业务按钮权限仍保留前端 UI 展示层:
- 未登录用户跳回 `/`
- 医生在报告管理和查看页只能访问本人报告。
- 模板管理不允许医生进入。
- 用户管理只允许超级管理员和管理员进入;后端再次校验可管理范围。
- 管理员只能管理同部门医生或自己,不能创建管理员或跨部门修改用户。
前端入口隐藏不能作为生产级安全边界,所有已后端化 API 都必须以服务端校验为准。
后端化后的目标权限模型以“角色 + 部门 + 模板授权”为主,详细规则见 [权限设计](./permissions.md)。当前已确定规则:
- 超级管理员拥有全权限,可以查看和修改所有用户、报告、模板、系统配置和权限配置。
- 管理员只能查看、编辑和删除本部门报告。
- 医生默认只能查看本人报告。
- 医生完成报告后仍允许修改,也可以删除本人已完成报告;完成后的每次修改必须保留历史版本并递增修订版本号。
- 模板按部门授权;管理员可以修改本部门模板;医生不可修改部门模板,但可以复制/新建个人模板。
- 一个部门只能有一个管理员,且只有超级管理员能创建或授权管理员。
- AI 只能接收当前报告内容作为上下文,不读取跨部门报告。
- 后端必须对每个 API 做强权限校验,前端菜单隐藏只作为体验优化。
后端查询层需要把权限规则落到数据过滤:
- 报告列表:超级管理员不加部门限制;管理员按 `department_id` 过滤;医生按 `author_id` 过滤。
- 报告详情/编辑/删除:读取报告后再次校验角色、部门和作者关系。
- 模板列表:超级管理员返回全部模板;管理员返回本部门模板和被授权模板;医生返回本部门授权模板和个人模板。
- 用户列表:超级管理员返回全部用户;管理员返回自己和本部门医生;医生只能读取自己。
- 部门模板授权:超级管理员维护部门可用/可管理模板;管理员和医生只读取本人部门。
## 报告编辑设计
报告正文是一个 `contentEditable` HTML 编辑器。模板中通过 `.field-value[data-bind="fieldKey"]` 标记智能字段,侧边表单更新时同步到正文;正文内字段被编辑时也会反向更新表单状态。
图片占位符通过 `.image-placeholder` 表示:
- `data-mode="frame"` 或无 `manual` 标记的占位符可接收关键帧。
- `data-mode="manual"` 用于 Logo、签名等静态图片不接收视频关键帧拖入。
AI 可编辑区域通过 `.ai-region[data-ai-id]` 和内部 `.ai-content` 定位。AI 返回 `updatedHtml` 后,系统先显示差异确认,再注入目标区域。
## 打印导出设计
`src/utils/print.ts` 通过隐藏 iframe 写入报告 HTML 和打印样式然后调用浏览器打印。PDF 导出依赖浏览器“另存为 PDF”不是服务端生成 PDF。
JSON 导出使用 Blob 下载,报告导出主要包含元信息和 `DEFAULT_FORM_FIELDS` 中定义的字段。
## 外部服务设计
- AI 服务通过后端 `/api/ai/chat``/api/ai/models` 代理到 OpenAI 兼容 `/chat/completions``/models` 接口。
- 语音听写通过后端 `/api/speech/iat` WebSocket 代理到讯飞 IAT 接口,前端只采集 PCM 音频并发送到本系统。
- 当前 AI Key 和讯飞语音密钥均由后端代理使用;普通用户读取系统设置时不会返回真实密钥。