Files
his/MD/bugs/BUG_697_ANALYSIS.md

195 lines
8.0 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.

# Bug #697 诸葛亮分析报告
> **文档类型**: Bug分析
> **分析时间**: 2026-06-13 02:58:52
> **分析模型**: mimo-v2.5 (LLM深度分析)
---
## 基本信息
- **Bug #**: 697
- **标题**: [门诊管理-门诊挂号] 检索并选择患者后,信息未回填赋值至挂号表单,导致挂号阻断
- **模块**: 建档挂号管理
- **提出人**: 陈显精
---
Now I have a comprehensive understanding of the bug. Let me produce my analysis.
---
## 一、Bug 理解
### 禅道原文引用
**Bug 标题**[门诊管理-门诊挂号] 检索并选择患者后,信息未回填赋值至挂号表单,导致挂号阻断
**重现步骤**
> 【步骤】登录账号 admin/admin123进入【门诊管理】→【门诊挂号】。在"患者身份信息"输入框中输入关键字"随子赫"(或就诊卡号 2123123。系统自动弹出模糊匹配的待选患者悬浮列表。用鼠标左键双击或单击选中列表中的患者"随子赫"这一行数据。观察挂号主界面各患者信息输入框(姓名、性别、年龄、就诊卡号、证件号、电话等)的接收状态。
**期望结果**
> 选中列表中的患者后,该患者的所有基本信息(包括但不限于:姓名、性别、年龄、就诊卡号、证件号、电话等)应自动回填并正确渲染显示在挂号主界面的对应表单中。
**实际结果**
> 选中下拉列表后该列表消失,但主界面的姓名、性别、年龄、就诊卡号、证件号、电话等所有患者基本信息字段依然为空,未回显任何数据,导致整个挂号业务无法继续保存。
### 附图分析关键信息
- 截图中红色标注:**"点击选中患者,患者信息未实现赋值至主界面,实现不了挂号业务"**
- 截图中红色标注:**"未赋值"**(第二个截图中整个挂号表单区域为空白)
- 患者下拉列表正常显示,数据完整(姓名、就诊卡号、性别、证件号、联系电话、年龄),但选中后主表单所有字段为空
### 综合总结
用户在门诊挂号页面搜索患者后,下拉列表能正常弹出并显示匹配结果。但点击选中某一行后,**列表关闭了,主表单的姓名、性别、年龄、就诊卡号、证件号、电话等字段全部为空**,挂号流程被完全阻断。这是一个典型的**前端数据回填事件链断裂**问题——选中事件触发了列表关闭,但回填逻辑未成功执行。
---
## 二、根因分析
### 根因el-popover `trigger="manual"` + input `@blur` 导致事件链断裂
**完整事件链分析:**
1. 用户在搜索输入框输入关键字 → `handleFocus()` 显示 popover → `patientList` 组件通过 watcher 触发 `getList()` → API 返回患者列表正常 ✅
2. 用户**点击** popover 中的某一行 →
3. **关键断裂点**:点击 popover 内部内容时,浏览器先处理 input 的 **blur 事件**`handleBlur()` 立即执行 `showPopover.value = false`
4. Element Plus 的 `el-popover` 使用 `trigger="manual"` 模式,当 `:visible` 变为 `false` 时,**popover 内容从 DOM 中移除/隐藏**
5. 由于 popover 内容被移除vxe-table 的 `@cell-click="clickRow"` 事件**来不及触发**或触发时 DOM 已不可用
6. `clickRow``emit("selsectPatient", params.row)` **未被触发**
7. 父组件的 `selsectPatient(row)` **未被调用** → 表单字段未赋值
**事件时序图:**
```
mousedown (table row)
→ input blur fires (handleBlur)
→ showPopover = false
→ popover content removed from DOM
→ cell-click fires on vxe-table (TOO LATE, DOM gone)
```
**涉及文件:**
| 文件 | 作用 | 问题点 |
|------|------|--------|
| `healthlink-his-ui/src/views/charge/outpatientregistration/index.vue` (L116-137) | el-popover + input 模板 | `@blur="handleBlur"` 立即关闭 popover |
| `healthlink-his-ui/src/views/charge/outpatientregistration/index.vue` (L1996-1998) | `handleBlur` 函数 | 无延迟,立即 `showPopover = false` |
| `healthlink-his-ui/src/views/charge/outpatientregistration/index.vue` (L2228-2241) | `selsectPatient` 函数 | 逻辑正确但未被触发 |
| `healthlink-his-ui/src/views/charge/outpatientregistration/components/patientList.vue` (L96) | `@cell-click="clickRow"` | click 事件未能触发 |
| `healthlink-his-ui/src/views/charge/outpatientregistration/components/patientList.vue` (L54) | `@mousedown.prevent` | 绑在组件上,未阻止 input blur |
**为什么 `@mousedown.prevent` 没有阻止 blur**
`@mousedown.prevent` 是 Vue 事件修饰符,绑定在 `<patientList>` 组件上,会附加到组件的根元素 `<div>` 上。但 `mousedown` 事件的传播方向是**从目标元素向上冒泡**
- 表格单元格 `mousedown` → 表格 `mousedown``<div>` 的 Vue mousedown`preventDefault` 执行)
- 但 input 的 `blur` 是由浏览器的**焦点管理机制**触发的,不受 `preventDefault` 的完全控制
- 特别是当 el-popover 使用 Teleport 将内容渲染到 `document.body`popover 内容的 mousedown 事件可能不会冒泡到触发元素的父容器
---
## 三、修复方案
### 修复策略:在 popover 内容区域拦截 mousedown阻止 input 失焦
**修改文件**`healthlink-his-ui/src/views/charge/outpatientregistration/index.vue`
**修改内容**
#### 修改 1在 popover 内容区域添加 mousedown 阻止事件(约 L116-137
将模板中的 popover 内容区域修改为:
```vue
<!-- 修改前 -->
<el-popover
:popper-style="{ padding: '0' }"
placement="bottom-start"
:visible="showPopover"
trigger="manual"
:width="1200"
>
<patientList
:searchkey="patientSearchKey"
@selsect-patient="selsectPatient"
@mousedown.prevent
/>
...
</el-popover>
<!-- 修改后 -->
<el-popover
:popper-style="{ padding: '0' }"
placement="bottom-start"
:visible="showPopover"
trigger="manual"
:width="1200"
>
<div @mousedown.prevent>
<patientList
:searchkey="patientSearchKey"
@selsect-patient="selsectPatient"
/>
</div>
...
</el-popover>
```
关键变化:
- `@mousedown.prevent``<patientList>` 组件标签移到**包裹 popover 内容的 `<div>`** 上
- 确保 popover 内任何位置的 mousedown 都会被阻止默认行为,从而**阻止 input 失焦**
- input 不失焦 → popover 不关闭 → `cell-click` 正常触发 → `selsectPatient` 正常执行 → 表单正确赋值
#### 修改 2添加防御性保障 — 优化 `handleBlur`(约 L1996-1998
```javascript
// 修改前
function handleBlur() {
showPopover.value = false;
}
// 修改后
function handleBlur() {
setTimeout(() => {
showPopover.value = false;
}, 200);
}
```
双重保障:即使 `@mousedown.prevent` 在某些边界情况下未完全生效200ms 延迟也足以让 `cell-click` 事件完成、`selsectPatient` 执行,之后再关闭 popover。
#### 修改 3可选增加键盘关闭支持
由于 `@mousedown.prevent` 阻止了焦点转移,用户需要其他方式关闭 popover
```javascript
// 在 onMounted 中添加
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && showPopover.value) {
showPopover.value = false;
}
});
```
### 修改清单
| # | 文件 | 行号(约) | 修改内容 |
|---|------|-----------|---------|
| 1 | `outpatientregistration/index.vue` | L116-137 | popover 内容包裹 `<div @mousedown.prevent>` |
| 2 | `outpatientregistration/index.vue` | L1996-1998 | `handleBlur` 增加 200ms setTimeout |
| 3 | `outpatientregistration/index.vue` | L2228-2241 | `selsectPatient` 函数逻辑无需修改(已正确) |
---
## 四、路由决策
**FIXER**: zhaoyun
**REASON**: 纯前端 Bug——el-popover 事件链断裂导致患者信息回填失败,涉及 Vue 模板事件绑定和 el-popover 组件交互逻辑,属于前端 UI 修复范畴,无需数据库变更,不需要后端参与。
---
## 路由决策
- **FIXER_ID**: guanyu
- **修复 Agent**: guanyu后端
- **原因**: LLM 分析决策
> ⚠️ 修复人员请先验证以上分析是否正确,再执行修复。