Compare commits
3 Commits
f9ad7cba30
...
057af2a717
| Author | SHA1 | Date | |
|---|---|---|---|
| 057af2a717 | |||
| 99b3154fc5 | |||
| face9a6ef2 |
78
BUG_526_ANALYSIS.md
Normal file
78
BUG_526_ANALYSIS.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Bug #526 分析报告
|
||||
|
||||
## Bug 描述
|
||||
[手术管理-门诊手术安排-计费] 勾选待签发状态的项目后上方签发按钮仍置灰不可用
|
||||
|
||||
## 根因定位
|
||||
|
||||
**文件**: `openhis-ui-vue3/src/views/clinicmanagement/bargain/component/prescriptionlist.vue`
|
||||
|
||||
### 签发按钮控制逻辑
|
||||
```vue
|
||||
<el-button type="primary" @click="handleSave()" :disabled="handleSaveDisabled"> 签发 </el-button>
|
||||
```
|
||||
`handleSaveDisabled` 是一个 `ref(false)`(第408行)。
|
||||
|
||||
### 两个更新机制都存在缺陷
|
||||
|
||||
**机制1:watcher(第458-475行)**
|
||||
```js
|
||||
watch(() => prescriptionList.value, (newValue) => {
|
||||
let saveList = prescriptionList.value.filter(item =>
|
||||
item.check && item.statusEnum == 1 && (Number(item.bizRequestFlag)==1 || !item.bizRequestFlag)
|
||||
)
|
||||
handleSaveDisabled.value = saveList.length == 0
|
||||
}, { immediate: true, deep: false }); // ← deep: false!
|
||||
```
|
||||
`deep: false` 意味着 watcher 只能检测到数组引用变化(push/splice),**无法检测到数组元素的 `check` 属性变化**。用户勾选/取消勾选checkbox时,watcher 不会触发。
|
||||
|
||||
**机制2:changeCheck 函数(第986-1019行)**
|
||||
```js
|
||||
groupList.value.map(k => {
|
||||
if(k.check) {
|
||||
if(k.statusEnum == 1) {
|
||||
// 待签发:设置 handleSaveDisabled = false
|
||||
}
|
||||
if(k.statusEnum == 2) {
|
||||
// 已签发:设置 handleSaveDisabled = true
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
问题:
|
||||
1. **用 `.map()` 遍历逐个设置按钮状态**,后面的项会覆盖前面项的设置
|
||||
2. 如果列表中先有"待签发"项(设置 `handleSaveDisabled = false`),后面遍历时碰到一个不满足 `bizRequestFlag` 条件的项,会被覆盖为 `true`
|
||||
3. 当取消勾选最后一个项目时,`groupList` 为空,`.map()` 不执行任何操作,按钮状态保持原样
|
||||
|
||||
### 数据流
|
||||
1. `getListInfo()` 从后端加载数据 → `prescriptionList.value` 被赋值
|
||||
2. 用户勾选checkbox → `scope.row.check` 变为 true(v-model 自动)
|
||||
3. `@change` 触发 `changeCheck()` → 更新 `groupIndexList` 和 `groupList`
|
||||
4. **但 `changeCheck` 中逐个遍历设置按钮状态的逻辑不可靠** → 签发按钮可能仍为 disabled
|
||||
|
||||
## 修复方案
|
||||
|
||||
将 `handleSaveDisabled` 和 `handleSingOutDisabled` 从 `ref` + 手动管理改为 **`computed` 属性**,直接从 `prescriptionList.value` 实时计算按钮状态:
|
||||
|
||||
```js
|
||||
const handleSaveDisabled = computed(() => {
|
||||
return !prescriptionList.value.some(item =>
|
||||
item.check && item.statusEnum == 1 && (Number(item.bizRequestFlag) === 1 || !item.bizRequestFlag)
|
||||
)
|
||||
})
|
||||
|
||||
const handleSingOutDisabled = computed(() => {
|
||||
return !prescriptionList.value.some(item =>
|
||||
item.check && item.statusEnum == 2 && item.chargeStatus != 5 &&
|
||||
(Number(item.bizRequestFlag) === 1 || !item.bizRequestFlag)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- 响应式自动计算,任何 `check`、`statusEnum` 变化都会触发重新计算
|
||||
- 不需要 watcher(删除 deep: false 的那个)
|
||||
- 不需要在 changeCheck 中手动管理按钮状态
|
||||
- 逻辑与 `handleSave` 和 `handleSingOut` 中的筛选条件一致
|
||||
|
||||
同时从 `changeCheck` 函数中移除按钮状态管理代码(第986-1019行的 `.map()` 部分)。
|
||||
@@ -548,6 +548,8 @@ const dialogReadOnly = ref(false);
|
||||
const formRef = ref(null);
|
||||
// 保存按钮加载状态,防止重复提交
|
||||
const submitLoading = ref(false);
|
||||
// 数据加载中标志,防止 showReport 加载已有数据时 watch 清空分型字段
|
||||
const loadingData = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
@@ -940,7 +942,8 @@ const showSubtypeSelect = computed(() => {
|
||||
// 监听疾病选择变化,自动清空分型选择
|
||||
watch(() => [form.value.selectedClassA, form.value.selectedClassB, form.value.selectedClassC], (newVal, oldVal) => {
|
||||
// 如果疾病选择发生变化,清空分型选择
|
||||
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
|
||||
// 数据加载中时不清空,避免 showReport 加载已有数据时被错误清空
|
||||
if (JSON.stringify(newVal) !== JSON.stringify(oldVal) && !loadingData.value) {
|
||||
form.value.diseaseType = '';
|
||||
}
|
||||
}, { deep: true });
|
||||
@@ -1092,6 +1095,9 @@ function showReport(reportData = {}, readOnly = true) {
|
||||
dialogVisible.value = true;
|
||||
dialogReadOnly.value = readOnly;
|
||||
|
||||
// 标记数据加载中,防止 watch 清空 diseaseType 分型字段
|
||||
loadingData.value = true;
|
||||
|
||||
resetAddressSelector();
|
||||
initProvinceOptions();
|
||||
|
||||
@@ -1149,6 +1155,9 @@ function showReport(reportData = {}, readOnly = true) {
|
||||
form.value.addressCounty,
|
||||
form.value.addressTown
|
||||
);
|
||||
|
||||
// 数据加载完成,恢复 watch 监听
|
||||
loadingData.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1441,14 +1441,14 @@ function handleSaveBatch() {
|
||||
function setValue(row) {
|
||||
// 构造单位列表
|
||||
unitCodeList.value = [
|
||||
{ value: row.unitCode, label: row.unitCode_dictText, type: 'unit' },
|
||||
{ value: String(row.unitCode), label: row.unitCode_dictText, type: 'unit' },
|
||||
{
|
||||
value: row.doseUnitCode,
|
||||
value: String(row.doseUnitCode),
|
||||
label: row.doseUnitCode_dictText,
|
||||
type: 'dose',
|
||||
},
|
||||
{
|
||||
value: row.minUnitCode,
|
||||
value: String(row.minUnitCode),
|
||||
label: row.minUnitCode_dictText,
|
||||
type: 'minUnit',
|
||||
},
|
||||
@@ -1514,8 +1514,8 @@ function setValue(row) {
|
||||
// dose: undefined, Removed to preserve dose value from group package
|
||||
unitCodeList: unitCodeList.value,
|
||||
doseUnitCode: row.doseUnitCode,
|
||||
minUnitCode: row.minUnitCode,
|
||||
unitCode: row.partAttributeEnum == 1 ? row.minUnitCode : row.unitCode,
|
||||
minUnitCode: String(row.minUnitCode),
|
||||
unitCode: row.partAttributeEnum == 1 ? String(row.minUnitCode) : String(row.unitCode),
|
||||
categoryEnum: row.categoryCode,
|
||||
definitionId: row.chargeItemDefinitionId,
|
||||
executeNum: 1,
|
||||
@@ -1531,6 +1531,13 @@ function setValue(row) {
|
||||
? new Decimal(selectedStock.price).div(row.partPercent).toFixed(6)
|
||||
: prevRow.minUnitPrice,
|
||||
positionName: selectedStock?.locationName,
|
||||
totalPrice: row.quantity
|
||||
? (String(row.unitCode) == String(row.minUnitCode)
|
||||
? (row.quantity * (selectedStock
|
||||
? new Decimal(selectedStock.price).div(row.partPercent).toFixed(6)
|
||||
: prevRow.minUnitPrice)).toFixed(6)
|
||||
: (row.quantity * (selectedStock?.price ?? 0)).toFixed(6))
|
||||
: undefined,
|
||||
}
|
||||
: {
|
||||
quantity: 1,
|
||||
|
||||
Reference in New Issue
Block a user