diff --git a/docs/现存量数据下载流程.md b/docs/现存量数据下载流程.md
new file mode 100644
index 0000000..279173c
--- /dev/null
+++ b/docs/现存量数据下载流程.md
@@ -0,0 +1,390 @@
+# 登录及现存量数据下载完整流程
+
+本文档使用 Mermaid 流程图呈现从**登录系统**到**完成现存量数据下载**的全过程。
+
+> **⚠️ 重要提示**
+>
+> 1. **每个操作前必须等待目标元素加载完成** —— 网页反应速度有限,不可假设点击后立即可以操作下一步
+> 2. **下载步骤 9 只能用 HOVER 触发,点击无效** —— 用户特别强调 (4 个感叹号)
+> 3. **条件分支以用户实际观察为准** —— 不推测原因,只呈现现象
+> 4. **登录流程包含强制登录弹窗处理** —— 系统可能弹出"确定"确认框
+
+## 流程总览
+
+```mermaid
+sequenceDiagram
+ participant User as 用户
+ participant Page as 页面
+ participant System as 系统
+ participant HistoryPanel as 历史数据侧边栏
+
+ Note over User,HistoryPanel: 阶段 0: 登录系统
+ Page->>Page: 导航到登录 URL
+ Page->>Page: 等待#forwardFrame iframe 加载完成
+
+ User->>Page: 1. 填写用户名
+ Page->>Page: 等待密码框加载完成
+ User->>Page: 2. 填写密码
+ Page->>Page: 等待登录按钮加载完成
+ User->>Page: 3. 点击登录按钮
+
+ alt 出现强制登录确认框
+ Page->>Page: 弹出"确定"确认框
+ User->>Page: 4. 点击"确定"按钮
+ Note over User,HistoryPanel: 强制登录模式
+ else 无确认框
+ Note over User,HistoryPanel: 正常登录模式
+ end
+
+ Page->>Page: 等待登录完成
+ Page->>Page: 进入系统主页
+
+ Note over User,HistoryPanel: 阶段 1: 应用选择
+ Page->>Page: 等待应用菜单图标加载完成
+ User->>Page: 5. 点击应用菜单图标
+ Page->>Page: 展开应用列表
+
+ Page->>Page: 等待"现存量"应用项加载完成
+ User->>Page: 6. 点击"现存量"应用
+ Page->>Page: 打开新标签页
+
+ Note over User,HistoryPanel: 阶段 2: 查询方案选择
+ Page->>Page: 等待行操作下拉图标加载完成
+ User->>Page: 7. 点击行操作下拉图标
+ Page->>Page: 弹出查询方案列表
+
+ Page->>Page: 等待"现存量 - 总量"选项加载完成
+ User->>Page: 8. 点击"现存量 - 总量"
+
+ alt 出现"正在加载,请耐心等待"提示
+ Page->>Page: 显示全屏加载提示
+ Page->>Page: 等待加载完成
+ Page->>Page: 显示查询结果
+ else 页面无提示,仅短暂卡顿 (1-3 秒)
+ Page->>Page: 短暂卡顿
+ Page->>Page: 显示查询结果
+ end
+
+ Note over User,HistoryPanel: 阶段 3: 执行下载
+ Page->>Page: 等待查询结果数据加载完成
+ Page->>Page: 等待行操作下拉图标 (打印图标) 加载完成
+
+ rect rgb(255, 240, 200)
+ Note over User,Page: ⚠️ 只能使用 **HOVER**,点击无法触发!
+ User->>Page: 9. HOVER 触发行操作下拉图标
+ end
+ Page->>Page: 弹出操作菜单
+
+ Page->>Page: 等待"输出 xlsx 文件"选项加载完成
+ User->>Page: 10. 点击"输出 xlsx 文件"
+
+ alt 弹出确认对话框
+ Page->>Page: 显示确认对话框
+ Page->>Page: 记录点击"继续"的时间戳 T
+ User->>Page: 点击"继续"按钮
+
+ Note over User,HistoryPanel: 阶段 4: 等待数据准备
+ User->>HistoryPanel: 11. 点击"历史数据"图标
+ HistoryPanel->>HistoryPanel: 打开侧边栏
+
+ Page->>Page: 等待"实时分享"标签加载完成
+ User->>HistoryPanel: 点击"实时分享"标签
+ HistoryPanel->>HistoryPanel: 显示数据列表
+
+ loop 循环检查直到找到目标数据
+ HistoryPanel->>HistoryPanel: 获取所有记录的时间戳
+ HistoryPanel->>HistoryPanel: 检查:存在时间戳 > T 的记录?
+ alt 存在符合条件的记录
+ HistoryPanel->>HistoryPanel: 找到目标数据
+ else 不存在符合条件的记录
+ User->>HistoryPanel: 关闭侧边栏
+ Note over User,HistoryPanel: 等待片刻 (如 5 秒)
+ User->>HistoryPanel: 再次点击"历史数据"图标
+ end
+ end
+
+ Page->>Page: 等待下载图标加载完成
+ User->>HistoryPanel: 点击下载图标
+ HistoryPanel->>User: 触发下载
+ else 无对话框,直接下载
+ Page->>User: 直接触发下载
+ end
+
+ Note over User,HistoryPanel: ✅ 下载完成
+```
+
+## 详细步骤说明
+
+### 阶段 0: 登录系统
+
+| 步骤 | 操作 | 前置条件 | 元素选择器 / OuterHTML |
+|------|------|----------|----------------------|
+| 1 | 填写用户名 | 登录页面 #forwardFrame iframe 已加载完成 | `main_frame.get_by_role("textbox", name="用户名").fill(username)` |
+| 2 | 填写密码 | 用户名已填写完成 | `main_frame.get_by_role("textbox", name="密码").fill(password)` |
+| 3 | 点击登录按钮 | 密码已填写完成 | `main_frame.get_by_role("button", name="登录").click()` |
+| 4 | 处理强制登录确认框 (如出现) | 登录按钮已点击 | `main_frame.get_by_role("button", name="确定").click()` |
+
+**登录流程说明:**
+
+1. **导航到登录页面** - 使用完整 URL:
+ ```python
+ url = f"{base_url.rstrip('/')}/yonbip/resources/uap/rbac/login/main/index.html"
+ ```
+
+2. **定位 iframe** - 所有登录表单元素都在 `#forwardFrame` iframe 内:
+ ```python
+ main_frame = page.locator("#forwardFrame").content_frame
+ ```
+
+3. **填写凭据** - 使用 Playwright 的 role 定位器:
+ ```python
+ main_frame.get_by_role("textbox", name="用户名").fill(username)
+ main_frame.get_by_role("textbox", name="密码").fill(password)
+ ```
+
+4. **点击登录** - 登录按钮:
+ ```python
+ main_frame.get_by_role("button", name="登录").click()
+ ```
+
+5. **处理强制登录弹窗** - 系统可能弹出确认框:
+ ```python
+ confirm_btn = main_frame.get_by_role("button", name="确定")
+ if confirm_btn.count() > 0:
+ confirm_btn.click() # 强制登录模式
+ else:
+ pass # 正常登录模式
+ ```
+
+6. **等待登录完成** - 登录后进入系统主页,准备进行下一步操作
+
+---
+
+### 阶段 1: 应用选择
+
+| 步骤 | 操作 | 前置条件 | 元素 OuterHTML (完整) |
+|------|------|----------|----------------------|
+| 5 | 点击应用菜单图标 | 登录后的主页已加载完成 | `
` |
+| 6 | 点击"现存量"应用 | 应用列表已展开完成 | `` |
+
+### 阶段 2: 查询方案选择
+
+| 步骤 | 操作 | 前置条件 | 元素 OuterHTML (完整) |
+|------|------|----------|----------------------|
+| 7 | 点击行操作下拉图标 | 现存量页面已加载完成 | `` |
+| 8 | 点击"现存量 - 总量"方案 | 查询方案列表已弹出完成 | (列表项,通过文本"现存量 - 总量"定位) |
+
+**步骤 8 后的两种可能情况:**
+
+| 情况 | 现象 | OuterHTML | 处理 |
+|------|------|-----------|------|
+| 可能性 1 | 出现"正在加载,请耐心等待"全屏提示 | `` | 等待加载完成,直到该元素消失 |
+| 可能性 2 | 页面无提示,仅短暂卡顿 (1-3 秒) | 无额外元素出现 | 等待 1-3 秒即可 |
+
+### 阶段 3: 执行下载
+
+| 步骤 | 操作 | 前置条件 | 元素 OuterHTML (完整) |
+|------|------|----------|----------------------|
+| 9 | **HOVER** 触发行操作下拉图标 | 查询结果数据已显示完成 | `` |
+| 10 | 点击"输出 xlsx 文件" | 操作菜单已弹出完成 | `` |
+
+> **⚠️ 步骤 9 特别警告**
+>
+> - **必须使用 HOVER 动作,点击无法正确触发!**
+> - 用户用 4 个感叹号强调此点
+> - 实现代码示例:
+> ```typescript
+> // 正确方式
+> await dropdownTrigger.hover();
+> await page.waitForTimeout(1000); // 等待菜单展开
+>
+> // ❌ 错误方式:不要使用 click()
+> // await dropdownTrigger.click();
+> ```
+
+**步骤 10 后的两种可能情况:**
+
+| 情况 | 现象 | OuterHTML | 处理 |
+|------|------|-----------|------|
+| 可能性 1 | 弹出确认对话框 | `当前数据较多,系统在处理完成后会发送通知消息,是否继续?
`
`` | 点击"继续"按钮,然后进入阶段 4 |
+| 可能性 2 | 无对话框 | 无额外元素出现 | 直接触发下载,流程结束 |
+
+### 阶段 4: 等待数据准备 (仅当步骤 10 弹出确认对话框时)
+
+**确认对话框元素:**
+```html
+
+
+
当前数据较多,系统在处理完成后会发送通知消息,是否继续?
+
+
+
+```
+
+**数据等待子流程:**
+
+```mermaid
+flowchart TD
+ A[点击继续按钮] --> B[记录点击时间 T
格式:YYYY-MM-DD HH:mm:ss]
+ B --> C[点击历史数据图标]
+ C --> D[侧边栏打开]
+ D --> E[点击实时分享标签]
+ E --> F[获取数据列表]
+ F --> G{存在时间戳 > T 的记录?}
+ G -->|是 | H[找到目标数据
选择最新的一条]
+ G -->|否 | I[关闭侧边栏]
+ I --> J["等待片刻 (建议 5 秒)"]
+ J --> C
+
+ H --> K[点击下载图标]
+ K --> L[下载完成]
+```
+
+**历史数据元素结构 (完整 OuterHTML):**
+```html
+
+ 现存量
+ 2026-04-09 14:16:03
+
+ 发送人:彭强强
+ 未读
+
+
+```
+
+**时间判断逻辑:**
+1. 记录点击"继续"按钮的时间戳 `T` (格式:`YYYY-MM-DD HH:mm:ss`)
+2. 获取历史数据列表中所有记录的时间戳 (从 `` 提取)
+3. 遍历检查:`record_timestamp > T`
+4. 如果存在符合条件的记录 → 选择**最新的一条** (第一条通常是最新的)
+5. 如果不存在 → 关闭侧边栏,等待 5 秒后重试
+
+---
+
+## 元素加载等待机制
+
+**这是用户特别强调的核心机制** —— 每次操作前必须确认目标元素已加载完成。
+
+### 等待函数实现
+
+```typescript
+/**
+ * 等待元素加载完成
+ * @param locator - Playwright locator
+ * @param options - 配置选项
+ * - timeout: 超时时间 (毫秒),默认 30000
+ * - state: 等待状态 ('visible' | 'attached' | 'hidden'),默认 'visible'
+ * - extraDelay: 额外等待时间 (毫秒),默认 500,确保元素完全可交互
+ */
+async function waitForElement(locator: Locator, options: {
+ timeout?: number;
+ state?: 'visible' | 'attached' | 'hidden';
+ extraDelay?: number;
+} = {}): Promise {
+ const { timeout = 30000, state = 'visible', extraDelay = 500 } = options;
+
+ // 等待元素达到指定状态
+ await locator.waitFor({ state, timeout });
+
+ // 额外等待,确保元素完全可交互
+ if (extraDelay > 0) {
+ await page.waitForTimeout(extraDelay);
+ }
+}
+```
+
+### 在主流程中的应用
+
+每个步骤的标准操作模式:
+
+```typescript
+// 登录阶段:填写用户名
+const usernameInput = main_frame.getByRole('textbox', { name: '用户名' });
+await waitForElement(usernameInput);
+await usernameInput.fill(username);
+
+// 登录阶段:填写密码
+const passwordInput = main_frame.getByRole('textbox', { name: '密码' });
+await waitForElement(passwordInput);
+await passwordInput.fill(password);
+
+// 登录阶段:点击登录按钮
+const loginButton = main_frame.getByRole('button', { name: '登录' });
+await waitForElement(loginButton);
+await loginButton.click();
+
+// 登录阶段:处理强制登录确认框 (如出现)
+const confirmButton = main_frame.getByRole('button', { name: '确定' });
+if (await confirmButton.count() > 0) {
+ await confirmButton.click();
+}
+
+// 步骤 5: 点击应用菜单
+const menuIcon = page.locator('.nc-workbench-icon');
+await waitForElement(menuIcon);
+await menuIcon.click();
+
+// 步骤 6: 点击"现存量"应用
+const currentItem = page.locator('.item-app[title="现存量"]');
+await waitForElement(currentItem);
+await currentItem.click();
+
+// 步骤 9: HOVER 触发 (特殊)
+const dropdownTrigger = page.locator('span.wui-button-text-wrap i.icon-hangcaozuoxiala1.nc-button-area-print-icon');
+await waitForElement(dropdownTrigger);
+await dropdownTrigger.hover(); // ⚠️ 必须 HOVER,不能 click
+await page.waitForTimeout(1000); // 等待菜单展开
+
+// 步骤 8 后的加载等待
+const loadingBackdrop = page.locator('.wui-spin-backdrop.wui-spin-full-screen');
+if (await loadingBackdrop.isVisible()) {
+ await loadingBackdrop.waitFor({ state: 'hidden', timeout: 60000 });
+} else {
+ await page.waitForTimeout(3000); // 无提示时等待 1-3 秒
+}
+```
+
+---
+
+## 元素选择器参考表
+
+### 主流程元素
+
+| 阶段 | 步骤 | 元素 | 选择器 (精简) | 完整 OuterHTML 参考 |
+|------|------|------|--------------|-------------------|
+| 0 (登录) | 1 | 用户名输入框 | `getByRole("textbox", name="用户名")` | 见阶段 0 表格 |
+| 0 (登录) | 2 | 密码输入框 | `getByRole("textbox", name="密码")` | 见阶段 0 表格 |
+| 0 (登录) | 3 | 登录按钮 | `getByRole("button", name="登录")` | 见阶段 0 表格 |
+| 0 (登录) | 4 | 强制登录确认按钮 | `getByRole("button", name="确定")` | 见阶段 0 表格 |
+| 1 | 5 | 应用菜单图标 | `.nc-workbench-icon` | 见阶段 1 表格 |
+| 1 | 6 | "现存量"应用 | `.item-app[title="现存量"]` | 见阶段 1 表格 |
+| 2 | 7 | 查询方案下拉 | `i.icon-hangcaozuoxiala1` | 见阶段 2 表格 |
+| 2 | 8 | "现存量 - 总量" | 文本定位 | 见阶段 2 表格 |
+| 3 | 9 | 行操作下拉 (HOVER) | `span.wui-button-text-wrap i.icon-hangcaozuoxiala1.nc-button-area-print-icon` | 见阶段 3 表格 |
+| 3 | 10 | "输出 xlsx 文件" | `li.wui-menu-item[btn-code="xlsx"]` | 见阶段 3 表格 |
+| 4 | 11 | "历史数据"图标 | `button.nc-button-wrapper i.icon-fenxianglishi` | - |
+| 4 | 11 | "实时分享"标签 | `div[role="tab"][nodekey="current"]` | - |
+| 4 | 11 | 下载图标 | `span.icon-xiazai1` | 见阶段 4 历史数据元素 |
+
+### 弹窗元素
+
+| 元素 | 选择器 | 用途 |
+|------|--------|------|
+| 加载提示 | `.wui-spin-backdrop.wui-spin-full-screen` | 等待加载完成 |
+| 确认对话框 `.wui-modal-body` (含文本判断) | 识别确认对话框 |
+| "继续"按钮 | `button.sure-button` | 确认继续 |
+
+---
+
+## 实现注意事项
+
+1. **时间戳格式必须一致** —— 点击"继续"按钮记录的时间 T 必须与页面显示的时间戳格式相同 (`YYYY-MM-DD HH:mm:ss`)
+
+2. **循环等待需设置最大次数** —— 避免无限循环,建议设置最大重试次数 (如 10 次)
+
+3. **侧边栏关闭后需等待** —— 关闭侧边栏后至少等待 5 秒再重新打开,给系统处理数据的时间
+
+4. **HOVER 后需等待菜单展开** —— HOVER 动作后至少等待 1 秒再执行下一步点击