# AGENTS.md — 手术图文病历报告系统（AI手术图文报告系统 V2.0）

> 本文档面向 AI 编程助手。如果你正在阅读本文件，说明你对本项目一无所知。以下内容全部基于项目实际代码与配置，请勿假设任何未在本文中显式说明的内容。

---

## 1. 项目概述

本项目是一个**纯前端**的医疗图文报告管理应用，面向医院手术记录场景。核心能力包括：

- 通过富文本编辑器撰写手术图文报告
- 上传手术视频并自动/手动截取关键帧插入报告
- 模板管理（创建、维护标准模板，新建报告时自动加载默认模板）
- 基于角色的权限控制（超级管理员 / 管理员 / 普通用户）
- AI 辅助撰写（支持 Kimi、DeepSeek、OpenAI 及自定义兼容接口）
- 报告批量操作（删除、导出 PDF / JSON）
- 讯飞语音输入（WebSocket 实时转写）

**重要前提**：本项目没有任何后端服务。所有数据（用户、报告、模板、视频帧、系统配置）全部持久化在浏览器 `localStorage` 中。认证与授权逻辑完全在客户端执行。

默认测试账号：
- `admin` / `123456`
- `manager` / `123456`
- `doctor` / `123456`

---

## 2. 技术栈

| 层级 | 技术 |
|------|------|
| 框架 | React 19 + TypeScript ~5.8.2 |
| 构建工具 | Vite 6.2.0（`@vitejs/plugin-react`） |
| 路由 | React Router DOM v7（`BrowserRouter`） |
| 样式 | Tailwind CSS v4.1.14（通过 `@tailwindcss/vite` 插件引入，非 PostCSS） |
| 图标 | `lucide-react` |
| 动画 | `motion`（Framer Motion 继任者） |
| AI SDK | `@google/genai`（依赖列表中，实际主要使用 OpenAI 兼容 API） |
| 其他关键依赖 | `diff`（字符级差异比对）、`crypto-js`（讯飞 HMAC-SHA256 鉴权） |

`package.json` 中虽然声明了 `express` 与 `@types/express`，但源码中未见服务端代码，推测为历史遗留或未使用的依赖。

---

## 3. 项目结构

```
src/
├── App.tsx                 # 根组件，定义所有路由
├── main.tsx                # 应用入口（React 19 + StrictMode）
├── types.ts                # 全局类型定义与默认值常量
├── index.css               # Tailwind v4 引入 + 自定义编辑器/打印/A4 样式
├── components/
│   └── Sidebar.tsx         # 全局侧边导航栏（带角色过滤、自动收起）
├── pages/                  # 所有页面均为大而整的单文件组件
│   ├── Login.tsx           # 登录 + 初始数据种子写入
│   ├── Dashboard.tsx       # 统计看板、SVG 趋势图、快捷入口
│   ├── ReportEditor.tsx    # 核心编辑器（~2900 行）：富文本、视频、AI、Diff、表单
│   ├── ReportManage.tsx    # 报告列表、检索、批量操作、历史版本恢复
│   ├── ReportView.tsx      # 只读报告展示 + 打印触发
│   ├── TemplateManage.tsx  # 模板编辑器（~1700 行）+ 字段库侧边栏
│   ├── UserManage.tsx      # RBAC 用户 CRUD + 电子签名
│   └── SystemSettings.tsx  # 抽帧配置、AI 服务商、讯飞语音参数
└── utils/
    ├── storage.ts          # localStorage/sessionStorage 封装（含 XOR 加密）
    ├── print.ts            # iframe 静默渲染 + window.print() 实现 A4 打印
    └── defaultContent.ts   # 默认手术报告 HTML 模板（含 data-bind 占位）
```

**架构特点**：
- 无外部状态管理库，全部使用 React 原生 `useState` / `useRef` / `useEffect`
- 无组件拆分策略，页面级组件体积巨大（`ReportEditor.tsx`、`TemplateManage.tsx` 均超 1500 行）
- 无懒加载，所有页面在 `App.tsx` 中直接静态导入
- 共享布局仅有 `Sidebar.tsx` 一处

---

## 4. 构建与运行命令

```bash
# 安装依赖
npm install

# 本地开发（端口 3000，监听 0.0.0.0）
npm run dev

# 类型检查（无单元测试）
npm run lint        # 等价于 tsc --noEmit

# 生产构建
npm run build

# 预览生产构建（端口 4173）
npm run preview

# 清理构建产物
npm run clean       # rm -rf dist
```

**环境变量**（复制 `.env.example` 为 `.env.local`）：
- `GEMINI_API_KEY`：Gemini AI API 密钥（构建时通过 Vite `define` 注入为 `process.env.GEMINI_API_KEY`）
- `APP_URL`：部署后的访问地址，用于自引用链接

**Windows 特别注意**：重新部署前若使用 `npm run preview`，需手动终止旧的 `vite preview` 进程，避免端口冲突。

---

## 5. 开发规范与代码风格

以下规范全部来自 `过往经验/` 中的踩坑记录，**必须遵守**：

### 5.1 contentEditable 编辑器规范
- **插入 HTML 时，模板字符串必须为紧凑单行**，禁止多行缩进/换行，否则浏览器会解析出额外文本节点破坏排版。
- **删除特殊节点**优先使用 `Range.selectNode(target) + document.execCommand('delete')`，而非直接 `target.remove()`，以保留浏览器原生撤销栈。
- **所有工具栏/侧边栏按钮**必须加 `onMouseDown={(e) => e.preventDefault()}`，防止点击时编辑器失焦导致光标位置丢失。
- **自定义 Undo/Redo**：结构性变更（插入/删除智能字段、表格等）应基于 `innerHTML` 快照实现自定义历史栈（`undoStack` / `redoStack`），并在操作前执行 `pushHistory()`。
- **键盘事件拦截**：对 `contenteditable="false"` 的内联控件，若处于块级边界，必须拦截 Backspace/Delete（以及 Ctrl+Z/Ctrl+Y），防止浏览器误删父级 `<p>`。
- **防换行技巧**：在 `inline-block` / `inline-flex` 控件后追加 `&#8203;`（零宽空格）作为行内锚点。

### 5.2 自动保存与草稿机制（高频踩坑区）
- **禁止单独依赖 `useRef` 作为自动保存的唯一数据源**。React 18 `StrictMode` 的模拟卸载会导致 ref 仍保持初始空值，从而用空数据覆盖有效的 `localStorage` 草稿。
- 在 `ReportEditor.tsx` 中新增任何 `useState` 时，必须三问：
  1. 是否需要持久化到 draft？
  2. 是否已加入 `stateRef` 初始化？
  3. 是否已在 `saveDraftToStorage`、所有恢复分支、以及 state→ref 同步 effect 中补齐？
- `contentRef.current = editorRef.current.innerHTML` 必须紧跟在任何直接操作 DOM 修改编辑器内容的代码之后。

### 5.3 图片与视频处理
- **LocalStorage 容量预警**：视频抽帧必须使用 Canvas 等比压缩（最大宽度 800px，JPEG 质量 0.6），单张控制在 30KB~80KB，避免 5MB 上限静默失败。
- **存储层异常捕获绝不应静默吞掉**，至少输出 `console.error`。
- **占位符体系**：所有 `.image-placeholder` 必须携带 `data-mode="frame|manual"` 属性。修改占位符的创建/填充/删除逻辑时，必须同步检索所有入口：`fillPlaceholderSrc`、`fillPlaceholder`、`autoCaptureFrames`、拖拽填充、`TemplateManage.tsx`，以及 `defaultContent.ts` 中的预置模板。
- 填充图片后需将占位符外壳的固定 `width/height` 改为 `auto`，同时保留 `max-width/max-height` 作为硬限制。

### 5.4 智能字段与动态表单
- **DOM 三层结构**：`<span class="smart-field-wrapper" contenteditable="false">` → `<span class="field-label">` → `<span class="field-value" contenteditable="true" data-bind="xxx">`。
- **双向绑定**：富文本→表单通过 `handleEditorInput` 中 `e.target.hasAttribute('data-bind')` 实时更新；表单→富文本通过 `useEffect` 监听 `reportData`，仅在 `el.innerText !== newValue` 时才重写 DOM，防止光标跳动。
- **时间/日期字段**：显示格式与存储格式必须分离，且同时实现正向格式化与反向解析；12h/24h 判断使用 `includes('hh') || includes('A')` 等包含性判断，兼容自定义格式。

### 5.5 AI 功能开发规范
- **模型兼容性**：调用 OpenAI 兼容 API 时，必须根据「是否有图片附件」动态决定 `content` 类型（`string` vs `array`），纯文本模型发送数组会 400。
- **System Prompt 设计**：
  - 条件应只依赖用户意图开关（如 `aiModifyEnabled`），不应依赖具体 UI 状态。
  - 向大模型发送局部修改请求时，必须提供全局上下文，但同时设置**严格的内容边界（Fencing）**，明确声明"全局参考仅供理解，严禁输出"其他模块内容。
  - 对关键输出字段（如 `updatedHtml`）使用「绝对强制」「绝对不允许」等最强措辞，并在前端增加缺失校验兜底。
- **降级机制**：目标区域注入必须配备降级方案（如光标处 `execCommand('insertHTML')`）；修改模式开启后应自动兜底锁定第一个可用 AI 区域。
- **DOM 结构修复**：在读取 `.ai-content` 数据前，必须将因用户回车而溢出为兄弟节点的 `<p>` 重新移回容器内。
- **样式与撤销**：AI 内容注入必须使用 `Range.selectNodeContents + execCommand('insertHTML')` 以保留撤销栈；返回的 HTML 需在后处理阶段统一注入内联字体样式（`font-family: SimSun; font-size: 12pt;`）；注入前需清洗（去掉 `<br>`、段落间空白）。
- **Diff 对比**：使用 `diff` 库做字符级差异比对，并在注入前去掉 diff 高亮标签。

### 5.6 数据迁移与类型安全
- 任何涉及 `localStorage` 数据结构变更的重构，必须在初始化入口提供**自动迁移逻辑**，使用 `(obj as any).oldField` 安全访问旧字段，避免类型污染和配置丢失。
- 从持久化存储读取的数组类型数据，渲染前务必做 `Array.isArray` 校验，防止历史脏数据导致整页崩溃。
- 当将格式简写迁移为标准 token 时，必须全局搜索所有硬编码默认值，并在初始化时建立无效值清理机制。

### 5.7 UI/UX 通用规范
- **禁用原生 `prompt`/`confirm`/`alert`**，统一使用项目风格的自定义 Modal 组件。
- **URL 拼接**：必须对基础路径做尾部斜杠移除 `.replace(/\/+$/, '')`。
- **打印边距**：使用 `@page { margin: ... }` 为每一页物理纸张独立分配边距，切勿依赖 `body { padding: ... }`。
- **滚动容器内展开**：点击展开/折叠的交互组件，应考虑增加 `scrollIntoView` 兜底，防止布局突变导致点击失效。
- **表格列变更**：保持 `<thead>` 与 `<tbody>` 列顺序严格一致。
- **大文件修改策略**：对于超过 1500 行的单文件组件，采用「Grep 定位 → 精确读取 → 最小化替换」的三段式策略，避免盲目滚动。

---

## 6. 测试说明

**本项目没有任何测试框架或测试用例**。

- `npm run lint`（`tsc --noEmit`）是唯一的自动化质量门禁。
- 确保 `tsconfig.json` 已正确 `exclude` 非源码目录（如 `参考信息`、`dist`、`node_modules`），否则参考文件会导致类型检查失败。
- 由于无后端、无测试，所有功能验证依赖手动端到端测试。

---

## 7. 部署流程

### 7.1 Docker 部署（推荐）

```bash
docker-compose up -d --build
```

- 构建阶段：`node:20-alpine` 执行 `npm ci` + `npm run build`
- 运行阶段：`nginx:alpine` 托管静态产物，暴露容器端口 `80`
- 宿主机端口映射：`4002` → `80`
- 服务名：`tuwen_system`，重启策略：`unless-stopped`

### 7.2 无 Docker 静态部署

```bash
npm run build
npm run preview
```

构建产物输出到 `dist/` 目录，可直接作为静态站点托管到任意 Web 服务器。

### 7.3 Nginx 配置要点（`nginx.conf`）

- **SPA 路由**：`try_files $uri $uri/ /index.html`，确保客户端路由正常工作。
- **Gzip 压缩**：对文本、CSS、JS、XML、JSON 启用。
- **静态资源缓存**：JS、CSS、图片、字体等设置 `immutable` 1 年缓存。

---

## 8. 安全注意事项

**本项目为纯前端应用，不存在服务端安全层。以下风险必须在部署前被充分理解：**

1. **用户密码以明文形式保存在浏览器 `localStorage` 中**，无后端哈希处理。
2. **API 密钥与凭证通过源码混淆存放**（字符码数组、XOR 加密），但仍在客户端可还原。
3. **所有认证与授权逻辑在客户端执行**，可通过开发者工具绕过。
4. **若用于生产环境，必须部署在内网或受信任环境中**，严禁直接暴露于公网。
5. `storage.ts` 中对 `systemSettings` 使用 XOR 加密，密钥硬编码于源码，仅提供最低限度的防窥视保护。

---

## 9. 关键架构决策

| 决策 | 说明 |
|------|------|
| 纯前端 / 无后端 | 所有数据存 `localStorage`，零服务端依赖，开箱即用 |
| 原生 `contentEditable` | 不使用第三方富文本库，通过 `document.execCommand` 和自定义 DOM 操作实现 |
| 单文件大组件 | 页面逻辑、状态、副作用全部内聚在同一文件中，无细粒度组件拆分 |
| localStorage 即数据库 | 用户、报告、模板、配置、视频帧全部序列化后存入浏览器本地存储 |
| iframe 打印 | 通过隐藏 iframe 独立渲染 A4 尺寸 HTML，隔离打印样式与交互样式 |
| OpenAI 兼容 API | AI 功能不绑定特定厂商，通过统一接口支持多服务商切换 |

---

*最后更新：基于当前代码库实际内容生成。若项目结构或依赖发生变更，请同步更新本文件。*


---

## 10. 代码编纂工作流（强制执行）

> 以下工作流由项目所有者定义，**所有涉及项目代码修改的需求必须严格执行**，不允许跳过任何步骤。

### 工作流触发条件
- 用户提出任何与项目修改相关的需求（功能新增、Bug 修复、重构、优化等）
- 用户明确说"按照工作流执行"或类似指令

### 工作流 7 步骤

#### Step 0：记录开始时间
在对话开头记录时间戳：`{Year}-{Mon}-{Day}-{Hour}-{Min}-{Sec}`。

#### Step 1：阅读工程分析
- 阅读 `.\工程分析\` 文件夹下所有已有文档（需求分析、实现方案、测试方案、经验记录）。
- 若文件夹为空，基于当前代码库做一次整体工程分析并写入 `.\工程分析\` 留存。

#### Step 2：整理需求
- 将用户原始需求结构化拆解。
- 写入 `.\工程分析\需求分析-{Year}-{Mon}-{Day}-{Hour}-{Min}-{Sec}.md`。
- 模板见 `.\工程分析\需求分析-模板.md`。

#### Step 3：制定实现方案
- 基于需求分析和代码理解，制定详细实现方案。
- 写入 `.\工程分析\实现方案-{Year}-{Mon}-{Day}-{Hour}-{Min}-{Sec}.md`。
- 模板见 `.\工程分析\实现方案-模板.md`。
- **⚠️ 写完后必须停止，等待用户二次人工审核确认，严禁擅自继续。**

#### Step 4：制定测试方案
- 基于实现方案，制定可执行的测试验证方案。
- 写入 `.\工程分析\测试方案-{Year}-{Mon}-{Day}-{Hour}-{Min}-{Sec}.md`。
- 模板见 `.\工程分析\测试方案-模板.md`。
- **⚠️ 写完后必须停止，等待用户二次人工审核确认，严禁擅自继续。**

#### Step 5：执行前检查 + 经验沉淀
1. **执行前必读** `.\工程分析\经验记录.md`，避免重复踩坑。
2. 严格按照已审核的实现方案执行代码修改。
3. 按已审核的测试方案执行验证。
4. 若执行过程中遇到任何问题，在 `.\工程分析\经验记录.md` 中以四段式追加：
   - **A. 具体问题**
   - **B. 产生问题原因**
   - **C. 解决问题方案**
   - **D. 后续如何避免问题**

#### Step 6：Git 备份
```bash
git add .
git commit -m "{Year}-{Mon}-{Day}-{Hour}-{Min}-{Sec} - 本次修改简要描述"
git push origin main
```
- 完成后向用户报告："已完成对文档的备份 commit。"

#### Step 7：重新部署
```bash
npm install   # 如需
npm run lint
npm run build
npm run preview   # 如需预览
```
- 确保构建成功无错误，向用户报告部署完成。

### 不可跳过的硬性要求

| 要求 | 说明 |
|------|------|
| 时间戳贯穿 | 同一需求的所有文档使用同一时间戳 |
| 用户审核卡点 | 实现方案、测试方案文档写完后必须人工确认 |
| 经验沉淀 | 遇到问题必须写入经验记录.md，四段式格式 |
| Git 备份 | 每次修改完成后必须 commit + push |
| 构建验证 | 必须执行 `npm run build` 并确保成功 |
| 规范兼容 | 实现方案必须自检 AGENTS.md 第 5 章规范清单 |
