# Bug #439 分析报告 ## Bug描述 领用出库:选择领用药品后"总库存数量"列数据未显示 ## 数据流分析 1. 用户点击"添加行" → 新增一行,totalQuantity 初始化为空字符串 '' 2. 用户在"项目"列通过 PopoverList 选择药品 → 触发 `selectRow(rowValue, index)` 3. `selectRow` 设置药品基本信息,然后调用 `handleLocationClick(1, rowValue, index)` 4. `handleLocationClick` 调用 `getCount({ itemId, orgLocationId })` 获取库存 5. `getCount` 返回 LocationInventoryDto[] 列表,前端通过 `pickBestOrgQuantityRow` 选最大值 6. `applyFromDto` 设置 `r.totalQuantity = d.orgQuantity || 0` ## 根因定位 在 `selectRow` 函数中(第1022-1049行),选择药品后: ```javascript form.purchaseinventoryList[index].unitList = rowValue.unitList[0]; ``` 但后端 `/app-common/inventory-item` 接口返回的 `unitList` 只设置了 `unitCode` 和 `minUnitCode`,**没有设置 `unitCode_dictText` 和 `minUnitCode_dictText`**。 在 `handleLocationClick` → `applyFromDto` 中(第1099-1121行): ```javascript r.unitCode = r.unitList.minUnitCode; r.unitCode_dictText = r.unitList.minUnitCode_dictText; // ← undefined! if (r.unitCode == r.unitList.minUnitCode) { // ← 这个条件始终为 true r.price = d.price / r.partPercent || ''; r.price = r.price.toFixed(4); } ``` 关键问题:`r.unitCode` 刚被设为 `r.unitList.minUnitCode`,然后条件 `r.unitCode == r.unitList.minUnitCode` 始终为 true, 导致即使价格很小(如 0.05/1=0.05),也会进入这个分支。 但这不是总库存数量未显示的根本原因。 **真正根因:`handleLocationClick` 函数在调用 `getCount` 获取库存数据后,`applyFromDto` 中 `r.totalQuantity = d.orgQuantity || 0` 的赋值逻辑依赖 `d.orgQuantity > 0` 的前置判断。** 查看前端代码流程: - `selectRow` 设置 `totalQuantity: ''`(新增行时的默认值) - 然后调用 `handleLocationClick` → `getCount` → 后端返回数据 - `pickBestOrgQuantityRow` 从返回列表中选出 orgQuantity 最大的记录 - 如果 `d && Number(d.orgQuantity ?? 0) > 0` → 调用 `applyFromDto` → 设置 `r.totalQuantity = d.orgQuantity || 0` - 如果条件不满足(所有记录 orgQuantity 都为 0 或返回空列表)→ **`applyFromDto` 不被调用** → `r.totalQuantity` 保持空字符串 '' 进一步分析发现: - 如果后端 `getCount` 返回空列表(该药品在该仓库无库存),`d` 为 null,`applyFromDto` 不会被调用 - 但如果该药品在仓库确实有库存,问题可能出在前端数据传递上 **核心问题在于 `unitList` 结构不完整:** `selectRow` 中 `rowValue.unitList` 来自药品列表查询结果,其 `unitList` 由后端 `CommonServiceImpl.getInventoryItemList` 构建, 只包含 `unitCode` 和 `minUnitCode`,缺少 `unitCode_dictText` 和 `minUnitCode_dictText`。 在 `handleLocationClick` 的 `applyFromDto` 中,`r.unitCode` 和 `r.unitCode_dictText` 的赋值依赖于 `unitList` 中的字段。 如果 `r.unitList` 是从 `rowValue.unitList[0]` 赋值而来(在 `selectRow` 中),那它应该至少有 `unitCode` 和 `minUnitCode`。 **但是!** 编辑模式(`getTransferProductDetails`)中,`unitList` 的构建方式不同: ```javascript form.purchaseinventoryList[index].unitList = e.unitList[0]; // 编辑详情时 ``` 新增模式(`selectRow`)中: ```javascript form.purchaseinventoryList[index].unitList = rowValue.unitList[0]; ``` 两种方式获取的 `unitList` 结构可能不同。 **根本原因:** `handleLocationClick` 中的 `getCount` API 调用,返回的 `LocationInventoryDto` 确实包含 `orgQuantity`。 前端通过 `pickBestOrgQuantityRow` 选出最大值的记录后,调用 `applyFromDto` 设置 `totalQuantity`。 如果药品在仓库有库存但 `totalQuantity` 仍为空白,说明 `applyFromDto` 中的 `d.orgQuantity` 可能为 `null`/`undefined`。 经检查 `selectInventoryItemInfo` SQL: ```sql SUM(CASE WHEN T1.location_id = #{orgLocationId} THEN T1.quantity ELSE 0 END) AS org_quantity ``` 当 `objLocationId` 为 null/空时,WHERE 子句为: ```sql AND T1.location_id = #{orgLocationId} ``` 这意味着查询结果中的所有记录都来自 `orgLocationId` 对应的仓库。 此时 `org_quantity` 应该等于 `SUM(T1.quantity)`。 **如果查询结果为空(该药品在该仓库没有库存记录),则前端 `d` 为 null,`applyFromDto` 不被调用,totalQuantity 保持空字符串。** 但 Bug 的期望是"应实时检索并填充总库存数量"——如果仓库确实没有该药品的库存,那显示空白是合理的。 但如果仓库有库存却未显示,说明前端传递的参数(orgLocationId 或 itemId)有问题。 **最终根因:前端 `handleLocationClick` 函数中,`orgLocationId` 的取值可能为空字符串,** **导致后端查询时使用空字符串作为 location_id 条件,查不到任何记录。** ```javascript let orgLocationId = r.sourceLocationId || receiptHeaderForm.headerLocationId || ''; ``` 虽然 Bug 步骤中说先选了"西药库",但如果 `receiptHeaderForm.headerLocationId` 在 selectRow 时已正确设置, `r.sourceLocationId` 也应该被设置(在 selectRow 第1037行): ```javascript form.purchaseinventoryList[index].sourceLocationId = receiptHeaderForm.headerLocationId || form.purchaseinventoryList[index].sourceLocationId || ''; ``` **但这里有一个微妙的时序问题:`handleLocationClick` 在 `getPharmacyCabinetList().then()` 内部被调用,** **但 `handleLocationClick` 是同步执行的,不等待 `getPharmacyCabinetList` 完成。** **这本身不影响 `orgLocationId` 的取值,因为 `orgLocationId` 不依赖 `getPharmacyCabinetList`。** ## 修复方案 1. 确保 `applyFromDto` 即使在 `orgQuantity` 为 0 时也能被调用,正确显示"0"而不是空白 2. 确保 `unitList` 包含必要的字典文本字段 ## 影响范围 - 前端文件:openhis-ui-vue3/src/views/medicationmanagement/requisitionManagement/requisitionManagement/index.vue - 涉及函数:`selectRow`、`handleLocationClick`