fix bug434:门诊手术安排:编辑弹窗中“切口类型”字段未正确回显数据

bug426:门诊医生站-检查开立:已选择列表应支持树形展开,显示套餐明细
bug439:领用出库:选择领用药品后“总库存数量”列数据未显示
bug457:门诊收费:已签发的手术类医嘱在门诊收费列表中不显示项目名称
This commit is contained in:
2026-05-14 11:48:22 +08:00
parent 3ad9ff85d4
commit 0d6f891b47
13 changed files with 689 additions and 247 deletions

View File

@@ -61,7 +61,11 @@ const props = defineProps({
type: String,
default: '',
},
/** 表头所选出库仓库:传入后药品列表只含该仓有库存的行,避免选到别仓批号导致 inventory-item-info 一直为 0 */
orgLocationId: {
type: [String, Number],
default: undefined,
},
});
const emit = defineEmits(['selectRow']);
const queryParams = ref({
@@ -89,11 +93,14 @@ watch(
queryParams.value.searchKey = newValue.searchKey;
queryParams.value.itemType = newValue.itemType;
queryParams.value.purchaseFlag = 0;
// queryParams.value.sourceLocationId = newValue.sourceLocationId;
// queryParams.value.purposeLocationId = newValue.purposeLocationId;
if (newValue.orgLocationId != null && newValue.orgLocationId !== '') {
queryParams.value.orgLocationId = newValue.orgLocationId;
} else {
delete queryParams.value.orgLocationId;
}
throttledGetList();
},
{ immdiate: true, deep: true }
{ immediate: true, deep: true }
);
getList();

View File

@@ -133,6 +133,7 @@
filterable
style="width: 200px"
:disabled="data.isEdit"
@change="onHeaderWarehouseChange"
>
<el-option
v-for="item in purposeTypeListOptions"
@@ -222,6 +223,7 @@
@selectRow="(row) => selectRow(row, scope.$index)"
:searchKey="medicineSearchKey"
:itemType="itemType"
:orgLocationId="receiptHeaderForm.headerLocationId"
/>
</template>
</PopoverList>
@@ -483,6 +485,46 @@ import {useStore} from '@/store/store';
import useTagsViewStore from '@/store/modules/tagsView';
import TraceNoDialog from '@/components/OpenHis/TraceNoDialog/index.vue'
/** 领用保存 IssueDto后端 Jackson 只认 yyyy-MM-dd HH:mm:ss库存接口可能回传 2025/4/2 00:00:00 等 */
function toIssueDateTimeStr(val) {
if (val == null || val === '') return undefined;
if (typeof val === 'string') {
const s = val.trim();
if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(s)) return s;
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return `${s} 00:00:00`;
}
const d = val instanceof Date ? val : new Date(val);
if (Number.isNaN(d.getTime())) return undefined;
return formatDate(d);
}
/** 总库存 totalQuantity 为最小单位;领用数量按当前计量单位折算成最小单位后再比较 */
function getRequisitionQtyInMinUnit(r) {
const q = Number(r.itemQuantity ?? 0);
if (!Number.isFinite(q) || q < 0) return NaN;
const minCode = r.unitList?.minUnitCode;
if (!minCode || r.unitCode === minCode) return q;
const part = Number(r.partPercent ?? 1);
return q * part;
}
function validateRequisitionQtyVsStock(r, lineNo) {
const cap = Number(r.totalQuantity ?? 0);
const reqMin = getRequisitionQtyInMinUnit(r);
if (!Number.isFinite(reqMin)) {
return `${lineNo}行:领用数量请输入有效数字`;
}
if (cap > 0 && reqMin > cap + 1e-9) {
const name = r.name || `${lineNo}`;
return `${name}:领用数量(折合最小单位)不能超过当前仓库可领库存 ${cap},请修改后再保存。`;
}
if (cap <= 0 && reqMin > 0) {
const name = r.name || `${lineNo}`;
return `${name}:当前仓库可领库存为 0不能填写正数领用数量。`;
}
return null;
}
const tagsViewStore = useTagsViewStore();
const store = useStore();
@@ -568,6 +610,8 @@ const data = reactive({
medicationType: [{ required: true, message: '请选择药品类型', trigger: 'change' }],
locationId: [{ required: true, message: '请选择领用部门', trigger: 'change' }],
practitionerId: [{ required: true, message: '请选择部门经手人', trigger: 'change' }],
// 领用出库按「表头仓库」查 /app-common/inventory-item-info未选仓库会查不到库存并误报「仓库数量为0」
headerLocationId: [{ required: true, message: '请先选择仓库(按仓库查询可领用库存)', trigger: 'change' }],
},
tableRules: {
name: [{ required: true, message: '项目不能为空', trigger: 'change' }],
@@ -988,10 +1032,9 @@ function selectRow(rowValue, index) {
form.purchaseinventoryList[index].unitList = rowValue.unitList[0];
form.purchaseinventoryList[index].lotNumber = rowValue.lotNumber;
form.purchaseinventoryList[index].ybNo = rowValue.ybNo;
// #439 fix: 不清空sourceLocationId保留handleAddRow设置的仓库ID
if (!form.purchaseinventoryList[index].sourceLocationId) {
form.purchaseinventoryList[index].sourceLocationId = receiptHeaderForm.headerLocationId || '';
}
// 出库仓库:优先表头当前所选仓库(避免先选药后选仓时行上一直为空)
form.purchaseinventoryList[index].sourceLocationId =
receiptHeaderForm.headerLocationId || form.purchaseinventoryList[index].sourceLocationId || '';
getPharmacyCabinetList().then((res) => {
purposeTypeListOptions.value = res.data;
handleLocationClick(1, rowValue, index)
@@ -1004,7 +1047,30 @@ function selectRow(rowValue, index) {
});
}
// 选择仓库
/** 多条库存记录时取可领数量最大的一条(避免仅取 res.data[0] 恰好为 0 */
function pickBestOrgQuantityRow(list) {
if (!Array.isArray(list) || list.length === 0) return null;
return list.reduce((best, cur) => {
const cq = Number(cur?.orgQuantity ?? 0);
const bq = Number(best?.orgQuantity ?? 0);
return cq > bq ? cur : best;
});
}
/** 表头「仓库」变化:同步每行 sourceLocationId 并重新拉库存(修复先选药品后选仓库行上仍无仓库 ID */
function onHeaderWarehouseChange() {
const hid = receiptHeaderForm.headerLocationId;
form.purchaseinventoryList.forEach((r) => {
r.sourceLocationId = hid || '';
});
form.purchaseinventoryList.forEach((r, idx) => {
if (hid && r.itemId) {
handleLocationClick(1, {}, idx);
}
});
}
// 选择仓库 / 选药品后拉取该仓库存
function handleLocationClick(item, row, index) {
getCount({
itemId: form.purchaseinventoryList[index].itemId,
@@ -1013,67 +1079,100 @@ function handleLocationClick(item, row, index) {
if (res.data && res.data.length > 0) {
form.purchaseinventoryList[index].itemTable = res.data[0].itemTable || '';
form.purchaseinventoryList[index].totalQuantity = res.data[0].orgQuantity || 0;
const r = form.purchaseinventoryList[index];
let orgLocationId = r.sourceLocationId || receiptHeaderForm.headerLocationId || '';
if (!orgLocationId) {
proxy.$message.warning('请先在表头选择「仓库」。库存按仓库维度查询,未选仓库无法匹配您看到的总库存。');
r.totalQuantity = 0;
r.price = 0;
return;
}
if (!r.sourceLocationId) {
r.sourceLocationId = orgLocationId;
}
if (res.data[0].price) {
form.purchaseinventoryList[index].price = res.data[0].price.toFixed(4);
} else {
form.purchaseinventoryList[index].price = 0;
}
// 获取供应商id
form.purchaseinventoryList[index].supplierId = res.data[0].supplierId || '';
// 生产日期
form.purchaseinventoryList[index].startTime = res.data[0].productionDate;
// 有效期
form.purchaseinventoryList[index].endTime = res.data[0].expirationDate;
form.purchaseinventoryList[index].unitCode =
form.purchaseinventoryList[index].unitList.minUnitCode;
form.purchaseinventoryList[index].unitCode_dictText =
form.purchaseinventoryList[index].unitList.minUnitCode_dictText;
// 单价 大单位单价
console.log(
form.purchaseinventoryList[index].unitCode ==
form.purchaseinventoryList[index].unitList.minUnitCode,
1212121
);
if (
form.purchaseinventoryList[index].unitCode ==
form.purchaseinventoryList[index].unitList.minUnitCode
) {
form.purchaseinventoryList[index].price =
res.data[0].price / form.purchaseinventoryList[index].partPercent || '';
form.purchaseinventoryList[index].price =
form.purchaseinventoryList[index].price.toFixed(4);
// parseFloat(form.purchaseinventoryList[index].price.toFixed(4))
} else {
console.log(
form.purchaseinventoryList[index].price > 1,
1212,
form.purchaseinventoryList[index].price
);
if (form.purchaseinventoryList[index].price > 1) {
form.purchaseinventoryList[index].price =
form.purchaseinventoryList[index].price.toFixed(4);
const lotTrimmed =
r.lotNumber != null && String(r.lotNumber).trim() !== '' ? String(r.lotNumber).trim() : null;
const runGet = (withLot) => {
const params = { itemId: r.itemId, orgLocationId };
if (withLot && lotTrimmed) {
params.lotNumber = lotTrimmed;
}
return getCount(params);
};
const applyFromDto = (d, syncLotFromPick) => {
if (syncLotFromPick && d.lotNumber != null && d.lotNumber !== '') {
r.lotNumber = d.lotNumber;
}
r.itemTable = d.itemTable || '';
r.totalQuantity = d.orgQuantity || 0;
if (d.price) {
r.price = d.price.toFixed(4);
} else {
r.price = 0;
}
r.supplierId = d.supplierId || '';
r.startTime = toIssueDateTimeStr(d.productionDate) || '';
r.endTime = toIssueDateTimeStr(d.expirationDate) || '';
r.unitCode = r.unitList.minUnitCode;
r.unitCode_dictText = r.unitList.minUnitCode_dictText;
if (r.unitCode == r.unitList.minUnitCode) {
r.price = d.price / r.partPercent || '';
r.price = r.price.toFixed(4);
} else if (r.price > 1) {
r.price = r.price.toFixed(4);
}
};
const persistStore = () => {
store.setCurrentDataLYCK({
purchaseinventoryList: form.purchaseinventoryList,
receiptHeaderForm: receiptHeaderForm,
});
};
runGet(true)
.then((res) => {
const list = res.data || [];
const d = pickBestOrgQuantityRow(list);
const strictOk = d && Number(d.orgQuantity ?? 0) > 0;
if (strictOk) {
applyFromDto(d, false);
if (Number(r.totalQuantity) <= 0) {
proxy.$message.warning('仓库数量为0无法调用');
}
}
if (form.purchaseinventoryList[index].totalQuantity == 0) {
proxy.$message.warning('仓库数量为0无法调用');
persistStore();
return;
}
} else {
form.purchaseinventoryList[index].totalQuantity = 0;
form.purchaseinventoryList[index].price = 0;
// if(form.purchaseinventoryList[index].totalQuantity==0){
if (lotTrimmed) {
return runGet(false).then((res2) => {
const list2 = res2.data || [];
const d2 = pickBestOrgQuantityRow(list2);
if (d2 && Number(d2.orgQuantity ?? 0) > 0) {
applyFromDto(d2, true);
proxy.$message.info(
'所选批号在本仓库无对应库存或批号不一致,已按仓库实物回显批号与可领数量,请核对。'
);
} else {
r.totalQuantity = 0;
r.price = 0;
proxy.$message.warning('仓库数量为0无法调用');
}
persistStore();
});
}
r.totalQuantity = 0;
r.price = 0;
proxy.$message.warning('仓库数量为0无法调用');
// }
}
}).catch(() => {
form.purchaseinventoryList[index].totalQuantity = 0;
form.purchaseinventoryList[index].price = 0;
});
store.setCurrentDataLYCK({
purchaseinventoryList: form.purchaseinventoryList,
receiptHeaderForm: receiptHeaderForm,
});
persistStore();
})
.catch(() => {
r.totalQuantity = 0;
r.price = 0;
persistStore();
});
}
// 切换仓库类型获取药房/药库列表
// function handleChangeLocationType(value) {
@@ -1230,20 +1329,19 @@ function getMaxCounts(row, index, counts) {
}
// 计算总价
function handleTotalPrice(index) {
form.purchaseinventoryList[index].olditemQuantity =
form.purchaseinventoryList[index].itemQuantity * row.partPercent;
form.purchaseinventoryList[index].itemMaxQuantity =
form.purchaseinventoryList[index].itemQuantity;
let purchaseItem = form.purchaseinventoryList[index];
const r = form.purchaseinventoryList[index];
r.olditemQuantity = r.itemQuantity * (r.partPercent ?? 1);
r.itemMaxQuantity = r.itemQuantity;
let purchaseItem = r;
if (purchaseItem.price > 0 && purchaseItem.itemQuantity > 0) {
form.purchaseinventoryList[index].totalPrice = purchaseItem.price * purchaseItem.itemQuantity;
form.purchaseinventoryList[index].totalPrice =
form.purchaseinventoryList[index].totalPrice.toFixed(4);
// parseFloat(form.purchaseinventoryList[index].totalPrice.toFixed(4))
r.totalPrice = purchaseItem.price * purchaseItem.itemQuantity;
r.totalPrice = r.totalPrice.toFixed(4);
}
if (form.purchaseinventoryList[index].itemQuantity == 0) {
form.purchaseinventoryList[index].totalPrice = 0;
if (r.itemQuantity == 0) {
r.totalPrice = 0;
}
const qtyErr = validateRequisitionQtyVsStock(r, index + 1);
r.error = !!qtyErr;
store.setCurrentDataLYCK({
purchaseinventoryList: form.purchaseinventoryList,
receiptHeaderForm: receiptHeaderForm,
@@ -1252,6 +1350,15 @@ function handleTotalPrice(index) {
// 保存
function handleSave(row, index) {
rowList.value = [];
for (let i = 0; i < form.purchaseinventoryList.length; i++) {
const line = form.purchaseinventoryList[i];
if (!line) continue;
const err = validateRequisitionQtyVsStock(line, i + 1);
if (err) {
proxy.$message.warning(err);
return;
}
}
form.purchaseinventoryList.map((row, index) => {
if (row) {
// 触发校验
@@ -1299,7 +1406,13 @@ function handleSave(row, index) {
});
}
function addTransferProducts(rowList) {
addTransferProduct(JSON.parse(JSON.stringify(rowList))).then((res) => {
const payload = (Array.isArray(rowList) ? rowList : []).map((item) => ({
...item,
startTime: toIssueDateTimeStr(item.startTime),
endTime: toIssueDateTimeStr(item.endTime),
occurrenceTime: toIssueDateTimeStr(item.occurrenceTime) ?? item.occurrenceTime,
}));
addTransferProduct(JSON.parse(JSON.stringify(payload))).then((res) => {
// 当前行没有id视为首次新增
// if (!row.id) {
// data.isAdding = false; // 允许新增下一行