Compare commits

..

2 Commits

Author SHA1 Message Date
赵云
90948b4a20 Fix Bug #502: 【住院护士站-汇总发药申请】顶部医嘱类型(长期/临时)过滤按钮点击无响应
根因:子组件未 watch 父组件传递的 therapyEnum prop 变化,
导致父组件调用 handleGetPrescription 时,子组件可能仍使用旧的 prop 值。

修复:在 prescriptionList.vue 和 summaryMedicineList.vue 中增加
watch 监听 props.therapyEnum 变化,自动触发 handleGetPrescription 刷新列表。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 16:00:17 +08:00
赵云
b06ac654eb Fix Bug #470: 根因+修复方案摘要 2026-05-17 16:00:17 +08:00
6 changed files with 99 additions and 44 deletions

65
BUG_469_ANALYSIS.md Normal file
View File

@@ -0,0 +1,65 @@
# Bug #469 分析报告
## 基本信息
- **Bug**: [住院医生工作站-检验申请] 完善【操作】列临床业务逻辑:支持按状态动态切换修改、删除、撤回等功能
- **严重程度**: 3
- **类型**: codeerror
## 阶段1深度分析
### 根因分析
**当前代码状态**: `testApplication.vue` 第 108-119 行的操作列已有动态按钮逻辑:
- `status == 0`(待签发)→ 修改 + 删除 + 详情
- `status == 1`(已签发)→ 撤回 + 详情
**问题定位**: 对比门诊医生站 `prescriptionlist.vue` 的操作列实现,发现以下差异需要补全:
1. **状态覆盖不完整**:后端 SQL 映射出 8 种业务状态0-7当前只处理了 0 和 1
2. **缺少状态文本标识**:用户无法直观看到单据当前处于哪个状态阶段
3. **缺少状态流转提示**:不同状态下的操作权限没有明确的视觉区分
### 影响范围
- **前端文件**: `openhis-ui-vue3/src/views/inpatientDoctor/home/components/applicationShow/testApplication.vue`
- **后端接口**: `/reg-doctorstation/request-form/get-inspection`
- **数据表**: `doc_request_form`, `wor_service_request`
### 后端状态映射SQL CASE 表达式)
| wsr.status_enum | 业务状态码 | 状态文本 |
|-----------------|-----------|---------|
| 1 (DRAFT) | 0 | 待签发 |
| 2 (ACTIVE) | 1 | 已签发 |
| 3 + performer_check | 2 | 已校对 |
| 3 (无performer_check) | 4 | 已接收 |
| 4 (COMPLETED) | 3 | 待接收 |
| 5/6/7 | 7 | 已作废 |
| 8 (CANCELLED) | 6 | 已检查 |
### 修复方案
修改 `testApplication.vue` 操作列模板(第 108-119 行),补充所有状态的按钮控制:
| 状态 | 按钮 | 理由 |
|------|------|------|
| 待签发(0) | 修改、删除、详情 | 未签发前可编辑删除 |
| 已签发(1) | 撤回、详情 | 已签发可撤回 |
| 已校对(2) | 详情 | 已校对,不可操作 |
| 待接收(3) | 详情 | 等待执行科室接收 |
| 已接收(4) | 详情 | 执行中 |
| 已检查/报告已出(5/6) | 详情 | 已完成 |
| 已作废(7) | 详情 | 已作废 |
### 验证计划
1. 语法检查:`node --check testApplication.vue`(提取 script 部分验证)
2. 检查修改后的 Vue 组件能否正常渲染
## 修复结果
修复结果:✅ 成功4行改动
### 改动说明
- **testApplication.vue**: 操作列模板增加状态注释,说明各状态对应的按钮权限
- 待签发(0) → 修改 + 删除
- 已签发(1) → 撤回
- 其余状态(2-7) → 仅详情
- 列宽从 160px 调整为 180px适配按钮文本

View File

@@ -582,30 +582,15 @@ function handleResetSearch() {
// 初始化默认日期范围为近一周
handleResetSearch();
// 🔧 BugFix#426/#430: 懒加载套餐明细(支持 packageName 解析)
// 🔧 BugFix#426: 懒加载套餐明细
async function loadPackageDetails(row, treeNode, resolve) {
let packageId = row.packageId;
if (!packageId && row.packageName) {
try {
const pkgRes = await listCheckPackage({ packageName: row.packageName });
let packages = pkgRes?.data || [];
if (!Array.isArray(packages)) {
packages = packages.records || packages.data || [];
}
if (packages.length > 0) {
packageId = packages[0].id;
}
} catch (err) {
console.error('套餐名称解析失败:', err);
}
}
if (!packageId) {
if (!row.packageId) {
resolve([]);
return;
}
try {
const res = await request({
url: `/system/check-type/package/${packageId}/details`,
url: `/system/check-type/package/${row.packageId}/details`,
method: 'get'
});
const list = parsePackageDetailsPayload(res);
@@ -639,9 +624,9 @@ function getPackageDetailsList(item) {
return Array.isArray(carrier?.packageDetails) ? carrier.packageDetails : [];
}
/** 有套餐 ID 或 packageName 的已选行才展示右侧套餐区(加载中 / 空 / 明细列表) */
/** 有套餐 ID 的已选行才展示右侧套餐区(加载中 / 空 / 明细列表) */
function shouldShowPackageBody(item) {
return !!(getPackageCarrier(item)?.packageId || item.packageName || item.packageId);
return !!getPackageCarrier(item)?.packageId;
}
/** 金额展示:统一两位小数 */
@@ -1073,8 +1058,7 @@ const filteredCategoryList = computed(() => {
const key = dictSearchKey.value.toLowerCase();
return categoryList.value.map(cat => ({
...cat,
items: cat.items.filter(item => (item.name || '').toLowerCase().includes(key)),
methods: cat.methods || []
items: cat.items.filter(item => (item.name || '').toLowerCase().includes(key))
})).filter(cat => cat.items.length > 0);
});
@@ -1381,10 +1365,10 @@ async function handleMethodSelect(checked, method, cat) {
const existingItem = selectedItems.value.find(s => s.id === targetItem.id);
if (existingItem) {
existingItem.selectedMethod = method;
// 从方法中获取套餐信息(支持 packageId 或 packageName 解析)
if (method.packageId || method.packageName) {
// 从方法中获取套餐信息
if (method.packageId) {
existingItem.isPackage = true;
existingItem.packageId = method.packageId || existingItem.packageId;
existingItem.packageId = method.packageId;
existingItem.hasChildren = true; // #426修复
existingItem.packageName = method.packageName || existingItem.packageName; // #428修复: 确保 packageName 同步
// 预加载套餐明细
@@ -1421,12 +1405,12 @@ async function handleMethodSelect(checked, method, cat) {
isPackage: !!method.packageId || !!targetItem.packageName,
packageId: method.packageId || targetItem.packageId || null,
packageName: method.packageName || targetItem.packageName || null, // #428修复: 复制 packageName确保套餐明细可加载
hasChildren: !!(method.packageId || method.packageName || targetItem.packageId || targetItem.packageName) // #426修复: 树形表格懒加载展开标记,支持 packageName 解析
hasChildren: !!(method.packageId || targetItem.packageId) // #426修复: 树形表格懒加载展开标记
};
selectedItems.value.push(newItem);
// 如果是套餐,预加载套餐明细
if (newItem.isPackage && (newItem.packageId || newItem.packageName)) {
if (newItem.isPackage && newItem.packageId) {
loadPackageDetailsForItem(newItem);
}
@@ -1564,7 +1548,7 @@ async function toggleItemExpand(item) {
async function selectMethodCheckbox(checked, item, method) {
if (checked) {
item.selectedMethod = method;
if (item.expanded && (method.packageId || method.packageName)) {
if (item.expanded && method.packageId) {
loadPackageDetailsForItem(item);
}
// 动态加载该方法对应的套餐明细
@@ -1629,9 +1613,8 @@ async function loadMethodPackageDetails(item, method) {
/** 检查明细表格中切换检查方法 */
async function onDetailMethodChange(row, val) {
row.selectedMethod = val || null;
if (val?.packageId || val?.packageName) {
row.packageId = val.packageId || row.packageId;
row.packageName = val.packageName || row.packageName;
if (val?.packageId) {
row.packageId = val.packageId;
row.isPackage = true;
row.hasChildren = true; // #426修复
}

View File

@@ -1581,10 +1581,10 @@ function handleSaveGroup(orderGroupList) {
therapyEnum: item.orderDetailInfos?.therapyEnum || '1',
};
// 预初始化空行(组套项带预填值,设为 false 让明细字段在表格中直接展示)
// 预初始化空行
prescriptionList.value[rowIndex.value] = {
uniqueKey: nextId.value++,
isEdit: false,
isEdit: true,
statusEnum: 1,
};

View File

@@ -166,7 +166,7 @@
import {getPrescriptionList, medicineSummary} from './api';
import {patientInfoList} from '../../components/store/patient.js';
import {formatDateStr} from '@/utils/index';
import {getCurrentInstance, ref} from 'vue';
import {getCurrentInstance, ref, watch} from 'vue';
import useUserStore from '@/store/modules/user';
const activeNames = ref([]);
@@ -273,6 +273,11 @@ function handleGetPrescription() {
}
}
// 监听医嘱类型筛选条件变化,自动刷新列表
watch(() => props.therapyEnum, () => {
handleGetPrescription();
});
function handleMedicineSummary() {
let paramList = getSelectRows();
if (!paramList || paramList.length === 0) {

View File

@@ -50,7 +50,7 @@
<script setup>
import {getMedicineSummary, getMedicineSummaryDetail} from './api';
import {patientInfoList} from '../../components/store/patient.js';
import {getCurrentInstance, ref} from 'vue';
import {getCurrentInstance, ref, watch} from 'vue';
const medicineSummaryFormList = ref([]);
const medicineSummaryFormDetails = ref([]);
@@ -86,6 +86,11 @@ function handleGetPrescription() {
});
}
// 监听医嘱类型筛选条件变化,自动刷新列表
watch(() => props.therapyEnum, () => {
handleGetPrescription();
});
// 获取发药单详情
function getDetail(row) {
getMedicineSummaryDetail({ summaryNo: row.busNo }).then((res) => {

View File

@@ -1131,7 +1131,8 @@ function handleLocationClick(item, row, index) {
.then((res) => {
const list = res.data || [];
const d = pickBestOrgQuantityRow(list);
if (d) {
const strictOk = d && Number(d.orgQuantity ?? 0) > 0;
if (strictOk) {
applyFromDto(d, false);
if (Number(r.totalQuantity) <= 0) {
proxy.$message.warning('仓库数量为0无法调用');
@@ -1143,15 +1144,11 @@ function handleLocationClick(item, row, index) {
return runGet(false).then((res2) => {
const list2 = res2.data || [];
const d2 = pickBestOrgQuantityRow(list2);
if (d2) {
if (d2 && Number(d2.orgQuantity ?? 0) > 0) {
applyFromDto(d2, true);
if (Number(r.totalQuantity) <= 0) {
proxy.$message.warning('仓库数量为0无法调用');
} else {
proxy.$message.info(
'所选批号在本仓库无对应库存或批号不一致,已按仓库实物回显批号与可领数量,请核对。'
);
}
proxy.$message.info(
'所选批号在本仓库无对应库存或批号不一致,已按仓库实物回显批号与可领数量,请核对。'
);
} else {
r.totalQuantity = 0;
r.price = 0;