- Extract AI region scanning into a reusable utility with unit coverage. - Refresh AI region dropdown state after drafts, reports, default templates, and selected templates write HTML into the editor. - Keep the existing MutationObserver path for later DOM edits and inserted AI regions. - Add E2E coverage for existing template AI regions appearing on initial report editor load. - Update README, AGENTS, report editor, progress, and testing docs for AI region synchronization behavior.
385 lines
19 KiB
Markdown
385 lines
19 KiB
Markdown
# AI 编码助手项目说明
|
||
|
||
本文件面向 AI 编码助手。阅读者应假设对该项目一无所知。以下信息基于当前仓库实际文件、脚本和源码;不要把早期设计目标当作已实现事实。任何代码和功能修改都要落实到文档和测试上。如果生成 git commit 信息,要逐个列点把所有修改都列上,重要的、大的修改放前面,不重要的、小的修改列在后面。
|
||
|
||
## 项目一句话
|
||
|
||
这是一个“手术图文病历报告系统”。当前登录认证已接入 NestJS Session API、PostgreSQL 用户表和数据库 Session Store;工作台统计、报告、报告媒体、模板、字段库、模板图片资源、视频/关键帧文件、用户、部门权限、系统设置、签名文件、AI 对话和讯飞语音听写已优先接入后端 API/代理。开发模式仍保留本地兼容回退,不能把前端权限和本地缓存当作生产安全边界。
|
||
|
||
## 当前技术栈
|
||
|
||
- React 19
|
||
- TypeScript 5.8
|
||
- Vite 6
|
||
- Tailwind CSS 4
|
||
- React Router DOM 7
|
||
- Lucide React
|
||
- Vitest + jsdom + Testing Library
|
||
- Playwright
|
||
- NestJS + Prisma + PostgreSQL 后端骨架
|
||
- Docker + Nginx
|
||
|
||
## 运行脚本
|
||
|
||
```bash
|
||
npm install
|
||
npm run dev # Vite dev server, 0.0.0.0:3001
|
||
npm run server:dev # build and start NestJS API, 0.0.0.0:3100
|
||
npm run server:build # tsc -p server/tsconfig.json
|
||
npm run lint # tsc --noEmit
|
||
npm run test # vitest run
|
||
npm run test:e2e # playwright test
|
||
npm run build # vite build
|
||
npm run prisma:generate
|
||
npm run prisma:migrate
|
||
npm run prisma:seed
|
||
```
|
||
|
||
修改代码后至少运行:
|
||
|
||
```bash
|
||
npm run lint
|
||
npm run test
|
||
```
|
||
|
||
如果改动构建、依赖、路由、样式或部署相关内容,也运行:
|
||
|
||
```bash
|
||
npm run build
|
||
```
|
||
|
||
如果改动后端源码、Prisma schema、认证、权限或 API 契约,也运行:
|
||
|
||
```bash
|
||
npm run server:build
|
||
npm run prisma:generate
|
||
```
|
||
|
||
后端化、权限或关键用户流程变更时也运行:
|
||
|
||
```bash
|
||
npm run test:e2e
|
||
```
|
||
|
||
## 默认账号
|
||
|
||
| 用户ID | 密码 | 角色 |
|
||
| --- | --- | --- |
|
||
| `admin` | `123456` | 超级管理员 |
|
||
| `manager` | `123456` | 管理员 |
|
||
| `0001` | `123456` | 医生 |
|
||
|
||
默认数据由 `src/pages/Login.tsx` 首次进入时初始化。
|
||
|
||
## 主要业务脉络
|
||
|
||
1. 用户进入 `/` 登录页。
|
||
2. 登录页初始化默认用户、模板、字段、图片资源和系统设置。
|
||
3. 登录页通过 `AuthContext` 调用后端 `/api/auth/login`,后端写入 HttpOnly Session Cookie。
|
||
4. 登录成功后前端把后端安全用户 DTO 映射成兼容 `User`,写入 `localStorage.currentUser`,跳转到 `/dashboard`。
|
||
5. `AuthProvider` 启动时通过 `/api/auth/me` 恢复会话;侧边栏优先读取 Auth Context,回退 `currentUser.role` 展示不同菜单。
|
||
6. 报告编辑器使用模板 HTML 生成报告正文,通过 `data-bind` 字段把侧边表单和正文智能字段同步。
|
||
7. 视频上传后使用浏览器 `<video>` 和 `<canvas>` 预览/抽帧,同时优先通过 `/api/files` 上传视频和关键帧文件,关键帧可插入报告图片占位符。
|
||
8. AI 面板把消息和图片上下文发送到 `/api/ai/chat`,后端读取系统设置中的共用 OpenAI 兼容 Provider 并代理调用 `/chat/completions`,返回内容可注入 AI 可编辑区域。
|
||
9. 语音听写把麦克风音频发送到 `/api/speech/iat` WebSocket,后端读取系统设置中的讯飞配置、生成鉴权 URL 并转发讯飞 IAT 结果。
|
||
10. 报告保存优先调用 `POST/PATCH /api/reports`,后端保存到 PostgreSQL;仅开发/显式回退模式下 API 不可用时回退 `localStorage.reports`。
|
||
11. 报告管理页优先调用 `GET /api/reports`,后端按角色过滤报告;前端支持搜索、筛选、历史恢复和浏览器打印/PDF 导出。
|
||
12. 模板管理页优先调用 `GET/POST/PATCH/DELETE /api/templates` 管理模板 HTML,调用 `/api/library/fields` 维护字段库,并通过 `/api/files` 上传模板图片资源。
|
||
13. 用户管理页优先调用 `GET/PATCH /api/users` 等接口维护用户、角色、部门和模板授权;签名图片通过 `/api/users/:id/signature` 上传为后端文件资源。
|
||
14. 系统设置页优先调用 `GET/PATCH /api/settings/system` 维护抽帧策略、默认模板、AI Provider 和讯飞语音配置。
|
||
|
||
## 功能真实性判断
|
||
|
||
详细清单见 `docs/features.md`。处理需求时应区分:
|
||
|
||
- 真实可用:本地初始化、字段绑定、浏览器打印/PDF 导出等。
|
||
- 真实集成:后端 Session 登录、Dashboard API、报告 API、模板 API、用户/部门 API、设置 API、签名文件 API、审计日志 API、AI 代理、讯飞语音代理、浏览器打印/PDF、视频抽帧。它们有真实代码路径,但依赖后端服务、浏览器能力、权限、有效密钥、网络或人工保存。
|
||
- 前端体验控制:页面级角色守卫和菜单隐藏已接入 Auth Context,但不能替代后端 API 权限。
|
||
|
||
## 当前安全边界
|
||
|
||
本项目不能按生产安全系统理解:
|
||
|
||
- 后端账号使用 Argon2 哈希;开发回退模式下 `localStorage.users` 仍保留兼容缓存和旧演示密码字段。
|
||
- 页面级权限在前端用于体验控制,不能抵御绕过;生产安全边界以后端 API 权限校验为准。
|
||
- 报告和模板 HTML 保存时已做服务端白名单清洗;前端仍使用 HTML 渲染,继续修改时要留意 XSS 和打印兼容。
|
||
- AI Key 和讯飞语音密钥已由后端代理使用,普通用户读取系统设置时不会返回真实密钥。
|
||
- 当前 demo mode 后端默认值包含演示用第三方服务凭据,生产化前必须替换或移除,并轮换曾经暴露过的密钥。
|
||
- 视频和关键帧文件已优先进入后端文件资源;报告保存时通过 `ReportMedia` 关系表关联,新建报告保存前仍依赖浏览器对象 URL 预览。
|
||
- `VITE_ENABLE_LOCAL_FALLBACK` 控制生产构建是否允许本地兼容回退;开发模式默认允许,生产默认关闭。
|
||
|
||
涉及生产化、后端化、用户化时,优先阅读 `docs/backendization-plan.md` 和 `docs/security.md`。
|
||
|
||
## 文件结构
|
||
|
||
```text
|
||
.
|
||
├── AGENTS.md # AI 编码助手上下文和协作约定
|
||
├── README.md # 面向开发者的项目说明
|
||
├── package.json # 依赖与 npm scripts
|
||
├── package-lock.json # npm 锁文件
|
||
├── prisma.config.ts # Prisma 7 CLI 配置
|
||
├── vite.config.ts # Vite/Tailwind/React/Vitest 配置
|
||
├── playwright.config.ts # Playwright E2E 配置,启动/复用 3001 前端和 3100 测试 API
|
||
├── tsconfig.json # TypeScript 配置
|
||
├── index.html # Vite HTML 入口
|
||
├── e2e/
|
||
│ ├── helpers.ts # E2E 真实 API 登录和造数工具
|
||
│ ├── audit-and-route-guards.spec.ts
|
||
│ ├── login.spec.ts
|
||
│ ├── report-permissions.spec.ts
|
||
│ ├── report-revision.spec.ts
|
||
│ └── personal-template.spec.ts
|
||
├── public/
|
||
│ ├── favicon.ico
|
||
│ └── logo_square.png
|
||
├── src/
|
||
│ ├── App.tsx # 路由表
|
||
│ ├── main.tsx # React 挂载入口
|
||
│ ├── index.css # 全局样式、Tailwind 主题和组件类
|
||
│ ├── types.ts # User/Report/Template/SystemSettings/FormField 等类型和默认配置
|
||
│ ├── api/
|
||
│ │ ├── audit.ts # 审计日志 API 封装
|
||
│ │ ├── client.ts # 前端 API client,统一 envelope/错误/Cookie
|
||
│ │ ├── dashboard.ts # 工作台统计 API 封装
|
||
│ │ ├── reports.ts # 报告列表、详情、保存、删除 API 封装
|
||
│ │ ├── templates.ts # 模板列表、详情、保存、删除 API 封装
|
||
│ │ ├── users.ts # 用户、部门和模板授权 API 封装
|
||
│ │ ├── settings.ts # 系统设置 API 封装
|
||
│ │ ├── files.ts # 签名文件 API 封装
|
||
│ │ ├── library.ts # 字段库 API 封装
|
||
│ │ ├── ai.ts # AI 模型列表和对话代理 API 封装
|
||
│ │ ├── speech.ts # 讯飞语音 WebSocket 代理地址封装
|
||
│ │ └── client.test.ts
|
||
│ ├── auth/
|
||
│ │ ├── AuthContext.tsx # 登录态、login/logout/me、currentUser 兼容同步
|
||
│ │ ├── backendUser.ts # 后端安全用户 DTO 到前端 User 的映射
|
||
│ │ └── backendUser.test.ts
|
||
│ ├── config/
|
||
│ │ └── runtime.ts # 本地兼容回退开关
|
||
│ ├── components/
|
||
│ │ ├── Sidebar.tsx
|
||
│ │ └── Sidebar.test.tsx
|
||
│ ├── pages/
|
||
│ │ ├── Login.tsx # 登录和默认数据初始化
|
||
│ │ ├── AuditLogs.tsx # 审计日志查看
|
||
│ │ ├── Dashboard.tsx # 工作台统计和快捷入口
|
||
│ │ ├── ReportEditor.tsx # 核心报告编辑器、抽帧、AI、语音、保存
|
||
│ │ ├── ReportManage.tsx # 报告列表、筛选、历史、导出、删除
|
||
│ │ ├── ReportView.tsx # 报告查看和打印
|
||
│ │ ├── TemplateManage.tsx# 模板、字段库、图片资源、导入导出
|
||
│ │ ├── UserManage.tsx # 用户、角色、部门、模板权限、签名
|
||
│ │ ├── SystemSettings.tsx# 抽帧、AI、语音、默认模板设置
|
||
│ │ ├── Login.test.tsx
|
||
│ │ └── ReportManage.test.tsx
|
||
│ ├── utils/
|
||
│ │ ├── storage.ts # localStorage/sessionStorage 封装
|
||
│ │ ├── permissions.ts # 前端角色/报告/模板可见性判断
|
||
│ │ ├── defaultContent.ts # 默认手术记录 HTML 模板
|
||
│ │ ├── print.ts # iframe 打印工具
|
||
│ │ ├── storage.test.ts
|
||
│ │ ├── permissions.test.ts
|
||
│ │ ├── defaultContent.test.ts
|
||
│ │ └── print.test.ts
|
||
│ └── test/
|
||
│ └── setup.ts # Vitest/jsdom 全局 mock
|
||
├── server/
|
||
│ ├── prisma/
|
||
│ │ ├── schema.prisma # PostgreSQL 数据模型
|
||
│ │ └── seed.ts # 默认医院、部门和账号 seed
|
||
│ ├── src/
|
||
│ │ ├── main.ts # NestJS API 启动入口
|
||
│ │ ├── app.module.ts
|
||
│ │ ├── audit/ # 审计日志写入和查询 API
|
||
│ │ ├── auth/ # 登录、me、logout 接口
|
||
│ │ ├── dashboard/ # 工作台统计 API
|
||
│ │ ├── demo/ # 演示模式默认模板、AI 和语音配置
|
||
│ │ ├── reports/ # 报告 API、DTO、metadata 映射和测试
|
||
│ │ ├── templates/ # 模板 API、DTO、权限映射和测试
|
||
│ │ ├── users/ # 用户、部门和模板授权 API、DTO 映射和测试
|
||
│ │ ├── settings/ # 系统设置 API 和 schema 测试
|
||
│ │ ├── files/ # 签名文件上传和受控读取 API
|
||
│ │ ├── library/ # 字段库 API、schema 和测试
|
||
│ │ ├── ai/ # OpenAI 兼容模型列表和对话代理 API
|
||
│ │ ├── speech/ # 讯飞 IAT WebSocket 代理和帧处理测试
|
||
│ │ ├── health/ # GET /api/health
|
||
│ │ ├── permissions/ # 后端权限策略和测试
|
||
│ │ ├── prisma/ # PrismaService
|
||
│ │ └── session/ # express-session 的 Prisma Store
|
||
│ └── tsconfig.json
|
||
├── docs/
|
||
│ ├── README.md
|
||
│ ├── installation.md
|
||
│ ├── requirements.md
|
||
│ ├── design.md
|
||
│ ├── component-structure.md
|
||
│ ├── permissions.md
|
||
│ ├── api-contract.md
|
||
│ ├── features.md
|
||
│ ├── testing.md
|
||
│ ├── data-storage.md
|
||
│ ├── deployment.md
|
||
│ ├── security.md
|
||
│ ├── progress.md
|
||
│ ├── backendization-plan.md
|
||
│ └── modules/
|
||
│ ├── auth-and-users.md
|
||
│ ├── report-editor.md
|
||
│ ├── report-management.md
|
||
│ ├── template-management.md
|
||
│ └── system-settings.md
|
||
├── Dockerfile
|
||
├── Dockerfile.server
|
||
├── docker-compose.yaml
|
||
└── nginx.conf
|
||
```
|
||
|
||
`node_modules/`、`dist/` 是生成物或依赖目录,不应作为源码结构维护。
|
||
|
||
## 关键源码说明
|
||
|
||
### `src/types.ts`
|
||
|
||
定义核心数据结构:
|
||
|
||
- `User`
|
||
- `Report`
|
||
- `CapturedFrame`
|
||
- `Template`
|
||
- `SystemSettings`
|
||
- `AiProviderConfig`
|
||
- `XfSpeechConfig`
|
||
- `FormField`
|
||
|
||
也包含默认字段、默认 AI Provider 和默认讯飞配置。
|
||
|
||
### `src/utils/storage.ts`
|
||
|
||
封装浏览器存储。常规键使用 JSON;`systemSettings` 做 XOR + Base64 混淆并兼容历史明文 JSON。注意:这不是安全加密。
|
||
|
||
### `src/utils/permissions.ts`
|
||
|
||
集中封装当前前端权限判断。报告范围规则为:医生看本人报告,管理员看本部门报告,超级管理员和超时管理员看全部报告。模板范围规则为:超级管理员/超时管理员可见全部模板,医生和管理员可见本部门模板以及本人个人模板。
|
||
|
||
### `src/utils/defaultContent.ts`
|
||
|
||
默认报告模板 HTML。包含:
|
||
|
||
- `.field-value[data-bind]` 智能字段
|
||
- `.image-placeholder` 图片占位符
|
||
- `.ai-region[data-ai-id]` AI 可编辑区域
|
||
|
||
### `src/pages/ReportEditor.tsx`
|
||
|
||
最大、最复杂的文件。包含:
|
||
|
||
- 报告表单状态
|
||
- `contentEditable` 富文本正文
|
||
- 字段双向同步
|
||
- 图片占位符填充
|
||
- 视频上传、自动抽帧、手动截帧
|
||
- AI 对话和 AI 区域改写
|
||
- 讯飞语音听写
|
||
- 草稿保存和恢复
|
||
- 报告保存、完成、历史记录
|
||
- 打印和导出
|
||
|
||
修改它时要非常小心,优先补测试或文档说明。
|
||
|
||
### `src/api/client.ts`
|
||
|
||
统一前端 API 请求封装:
|
||
|
||
- 默认请求相对路径 `/api/...`。
|
||
- Vite 开发模式通过 `VITE_API_PROXY_TARGET` 代理 API,默认 `http://localhost:3100`。
|
||
- 请求带 `credentials: 'include'`,用于后端 HttpOnly Session Cookie。
|
||
- 解包后端 `{ data }` 响应,错误时抛出 `ApiError`。
|
||
|
||
### `src/auth/AuthContext.tsx` 和 `src/auth/backendUser.ts`
|
||
|
||
前端认证入口。`AuthProvider` 提供 `login`、`logout`、`refresh`,并在登录或恢复会话后把后端用户同步成当前前端 `User`:
|
||
|
||
- 后端 `doctor` 映射为前端 `user`。
|
||
- 后端 `departmentName` 映射为前端 `department`。
|
||
- 保留本地签名等迁移期字段;模板授权优先来自后端部门权限。
|
||
|
||
### `server/src`
|
||
|
||
后端第一阶段骨架。当前已实现健康检查、认证接口、报告 API、报告媒体关系、模板 API、字段库 API、用户/部门 API、设置 API、通用文件/签名文件 API、AI 代理、讯飞语音代理、PrismaService 和权限策略;前端登录、报告、模板、字段库、模板图片资源、用户管理、系统设置、签名上传、AI 对话和语音听写已接入后端接口/代理。新增后端功能时优先按模块拆分:`auth`、`reports`、`templates`、`library`、`users`、`files`、`settings`、`ai`、`speech`。
|
||
|
||
API 默认 JSON/urlencoded 请求体上限为 `100mb`,由 `API_BODY_LIMIT` 控制;Nginx 同步配置了 `client_max_body_size 100m`,用于承载迁移期报告 HTML、图片/关键帧和通用文件 Data URL 上传。
|
||
|
||
Docker 前端默认暴露 `http://localhost:4002`,并额外暴露自签名 HTTPS 演示入口 `https://localhost:4443`。浏览器麦克风 API 不能在普通局域网 HTTP 页面中由应用代码强行开启;语音听写演示优先使用 HTTPS 入口,或用 Chrome/Edge 的 `--unsafely-treat-insecure-origin-as-secure` 临时标记 HTTP 来源。
|
||
|
||
### `server/prisma/schema.prisma`
|
||
|
||
PostgreSQL 数据模型。当前覆盖 `Tenant`、`Department`、`User`、`UserSession`、`AppSession`、`Report`、`ReportMedia`、`ReportHistory`、`Template`、模板部门授权、`FileResource`、`SystemSetting` 和 `AuditLog`。Prisma 7 连接配置在根目录 `prisma.config.ts` 中。
|
||
|
||
## 数据存储键
|
||
|
||
详见 `docs/data-storage.md`。常见键:
|
||
|
||
- `currentUser`
|
||
- `users`
|
||
- `templates`
|
||
- `reports`
|
||
- `systemSettings`
|
||
- `formFieldsConfig`
|
||
- `imageAssets`
|
||
- `customTimeFormats`
|
||
- `multiSelectOptions`
|
||
- `anesthesiaOptions`
|
||
- `reportEditorDraft_${username}`
|
||
- `sessionStorage.restore_${reportId}`
|
||
|
||
## 测试现状
|
||
|
||
当前测试覆盖:
|
||
|
||
- 登录默认初始化和后端禁用账号错误展示
|
||
- 前端 API client 响应/错误处理、Dashboard API 封装和语音代理地址生成
|
||
- 后端用户 DTO 到前端兼容用户映射
|
||
- 角色菜单过滤
|
||
- 报告管理按角色过滤
|
||
- 管理员本部门报告范围和医生本人报告范围
|
||
- 模板可用范围,含部门模板和医生个人模板
|
||
- Playwright E2E 通过真实后端 API seed 覆盖登录、报告权限、报告修订版本、报告 AI 区域同步、医生个人模板、模板管理新增保存、路由守卫和审计日志
|
||
- 后端权限策略覆盖报告、模板、用户管理和管理员创建规则
|
||
- 后端 Dashboard 统计按角色范围过滤
|
||
- 后端报告 metadata 兼容映射和 `ReportMedia` 视频/关键帧组装
|
||
- 后端报告 schema 区分草稿和完成状态,草稿可暂缺患者姓名/住院号,完成报告必须填写
|
||
- 后端模板 DTO 和权限资源映射
|
||
- 模板列表合并工具,防止新增模板被旧 `localStorage.templates` 覆盖
|
||
- 模板导入导出工具,覆盖 HTML 模板包生成、字段库元数据回导和旧 JSON 导入兼容
|
||
- AI 区域扫描工具,覆盖从报告正文 HTML 识别 `.ai-region`
|
||
- 后端用户 DTO 和部门模板授权映射
|
||
- 后端系统设置 schema 校验
|
||
- 后端 AI 入参和讯飞语音代理帧处理
|
||
- 后端 HTTP 集成测试覆盖 API prefix、登录 session、受保护 API actor 传递
|
||
- 后端真实 PostgreSQL 集成测试覆盖 Auth、Dashboard、Reports、ReportMedia、Templates、Files、HTML 清洗、审计写入和审计查询权限
|
||
- 存储封装
|
||
- 默认模板结构和字段契约
|
||
- 打印入口
|
||
|
||
测试文档见 `docs/testing.md`。
|
||
|
||
## 文档维护规则
|
||
|
||
如果改动功能、数据结构、脚本、部署、安全边界或测试:
|
||
|
||
- 更新对应 `docs/` 文档。
|
||
- 如功能真实性变化,更新 `docs/features.md`。
|
||
- 如后端化方向变化,更新 `docs/backendization-plan.md`。
|
||
- 如新增/修改测试,更新 `docs/testing.md`。
|
||
- 如运行方式、端口、账号、部署变化,更新 `README.md`。
|
||
|
||
## 开发注意事项
|
||
|
||
- 优先使用现有风格和现有工具,不要引入大框架替换,除非任务明确需要。
|
||
- 不要把前端权限当作安全边界。
|
||
- 不要继续扩大前端内置密钥的使用面。
|
||
- 不要把大量 Base64 图片或视频数据长期作为生产方案。
|
||
- 报告/模板 HTML 改动要考虑 XSS、打印样式、字段绑定和历史兼容。
|
||
- 当前 `document.execCommand` 虽然过时,但编辑器依赖它;替换编辑器需要单独规划。
|
||
- 生成物 `dist/` 和依赖目录 `node_modules/` 不要手工维护。
|