Compare commits
7 Commits
荀彧
...
bugfix-403
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2a213da8b | ||
| 51ae3aad29 | |||
| d984b89967 | |||
|
|
b9aabd53ce | ||
|
|
73ed5e1d33 | ||
|
|
d3cd122656 | ||
|
|
0930fbae93 |
66
.analysis/bug403_analysis.md
Normal file
66
.analysis/bug403_analysis.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Bug #403 分析报告
|
||||||
|
|
||||||
|
## 根因分析
|
||||||
|
|
||||||
|
**Bug现象**:住院医生工作站应用医嘱组套后,药品明细字段(单次剂量、总量、总金额、药房/科室)丢失。
|
||||||
|
|
||||||
|
**数据流追踪**:
|
||||||
|
|
||||||
|
1. **后端 `getGroupPackageForOrder`** (OrdersGroupPackageAppServiceImpl.java:168)
|
||||||
|
- 查询组套明细 SQL(OrdersGroupPackageAppMapper.xml:37-82)返回:`dose`, `quantity`, `doseQuantity`, `rateCode`, `methodCode`, `dispensePerDuration` 等字段
|
||||||
|
- 通过 `getAdviceBaseInfo` 获取 `AdviceBaseDto` 赋值给 `detail.setOrderDetailInfos()`,包含:`doseUnitCode`, `doseUnitCode_dictText`, `positionId`, `inventoryList`, `priceList`, `partPercent` 等
|
||||||
|
|
||||||
|
2. **前端 `orderGroupDrawer.vue`** `handleUseOrderGroup` (line 568-694)
|
||||||
|
- 对每个组套明细项进行预处理,合并组套字段和医嘱库字段
|
||||||
|
- 通过 `emit('useOrderGroup', processedDetailList)` 发送到父组件
|
||||||
|
|
||||||
|
3. **前端 `inpatientDoctor/home/components/order/index.vue`** `handleSaveGroup` (line 1546-1639)
|
||||||
|
- 接收 `orderGroupList`,对每个 item 调用 `setValue(mergedDetail)` 填充行数据
|
||||||
|
- 然后用 `item` 的字段显式覆盖创建 `newRow`
|
||||||
|
|
||||||
|
**根因定位**:`handleSaveGroup` 在构建 `newRow` 时(line 1594-1617),从 `item` 直接取值覆盖了 `setValue` 设置的值。问题在于:
|
||||||
|
|
||||||
|
1. **`item.unitCodeName` 可能为 undefined**:组套明细 SQL 中 `unitCodeName` 来自字典关联 `sys_dict_data`,如果字典匹配不上则为 null。`newRow` 的 `unitCode_dictText` 直接使用 `item.unitCodeName || ''`,导致显示为空。
|
||||||
|
|
||||||
|
2. **`positionName` 未在 `orderGroupDrawer` 处理项中显式设置**:虽然 `setValue` 会通过库存查询设置 `positionName`,但 `orderGroupDrawer.vue` 的 `handleUseOrderGroup` 没有将 `positionName`(或至少 `orderDetail.positionName`)包含在 processed item 中,导致 `setValue` 的库存查找依赖 `inventoryList`,而 `inventoryList` 来自后端 `AdviceBaseDto`。
|
||||||
|
|
||||||
|
3. **`doseUnitCode_dictText` 依赖 `setValue` 的 `unitCodeList`**:`orderGroupDrawer` 的处理项中没有显式包含 `doseUnitCode_dictText`,完全依赖 `mergedDetail` 中 spread 的 `orderDetail` 字段。
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
|
||||||
|
- 前端文件:`openhis-ui-vue3/src/views/doctorstation/components/prescription/orderGroupDrawer.vue`
|
||||||
|
- 前端文件:`openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue`
|
||||||
|
- 影响场景:住院医生工作站和门诊医生工作站应用医嘱组套
|
||||||
|
|
||||||
|
## 修复方案
|
||||||
|
|
||||||
|
**修改 `orderGroupDrawer.vue` 的 `handleUseOrderGroup` 函数**(line 630-688):
|
||||||
|
|
||||||
|
在 processed item 的 return 对象中显式添加缺失的字段:
|
||||||
|
- `doseUnitCode_dictText`:从 orderDetail 获取剂量单位显示文本
|
||||||
|
- `positionName`:从 orderDetail 获取执行科室/药房名称
|
||||||
|
- `injectFlag` / `injectFlag_enumText`:注射标识
|
||||||
|
- `skinTestFlag` / `skinTestFlag_enumText`:皮试标识
|
||||||
|
- `partPercent`、`partAttributeEnum`、`unitConversionRatio`:用于价格计算的关键字段
|
||||||
|
|
||||||
|
这些字段在 `orderDetail`(AdviceBaseDto)中都有,只是没有在 processed item 的顶层显式设置。`handleSaveGroup` 的 `newRow` 通过 `...prescriptionList.value[rowIndex.value]` spread 能获取到 `setValue` 设置的值,但显式在顶层包含可以确保数据流的完整性。
|
||||||
|
|
||||||
|
## 验证计划
|
||||||
|
|
||||||
|
1. 修改代码后,用 `node --check` 验证语法
|
||||||
|
2. 在住院医生工作站测试:选择患者 → 点击组套 → 预览组套 → 应用到当前患者
|
||||||
|
3. 验证表格中显示的字段:单次剂量、总量、总金额、药房/科室均有值
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 修复结果:✅ 成功,10行改动
|
||||||
|
|
||||||
|
**修改文件**:`openhis-ui-vue3/src/views/doctorstation/components/prescription/orderGroupDrawer.vue`
|
||||||
|
|
||||||
|
**改动说明**:在 `handleUseOrderGroup` 函数的 processed item 中显式添加了以下缺失字段:
|
||||||
|
- `doseUnitCode_dictText`:剂量单位显示文本(如"mg"),用于"单次剂量"列的后缀显示
|
||||||
|
- `positionName`:药房/科室名称,用于"药房/科室"列显示
|
||||||
|
- `injectFlag` / `injectFlag_enumText`:注射药品标识及文本
|
||||||
|
- `skinTestFlag` / `skinTestFlag_enumText`:皮试标识及文本
|
||||||
|
|
||||||
|
**策略**:策略A(直接修复代码逻辑)—— 组套应用时数据预处理缺失部分关键字段,导致父组件 `handleSaveGroup` 构建行数据时无法获取完整信息。补充字段后,`setValue` 和 `newRow` 构造均能正确传递这些数据到表格。
|
||||||
@@ -83,6 +83,9 @@ public class InfectiousCardDto {
|
|||||||
/** 病例分类 */
|
/** 病例分类 */
|
||||||
private String diseaseType;
|
private String diseaseType;
|
||||||
|
|
||||||
|
/** 病例分类 */
|
||||||
|
private Integer caseClass;
|
||||||
|
|
||||||
/** 发病日期 */
|
/** 发病日期 */
|
||||||
private LocalDate onsetDate;
|
private LocalDate onsetDate;
|
||||||
|
|
||||||
|
|||||||
@@ -112,12 +112,15 @@ public class InfectiousDiseaseReportDto {
|
|||||||
private Integer caseClass;
|
private Integer caseClass;
|
||||||
|
|
||||||
/** 发病日期(默认诊断时间,病原携带者填初检日期) */
|
/** 发病日期(默认诊断时间,病原携带者填初检日期) */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
private LocalDate onsetDate;
|
private LocalDate onsetDate;
|
||||||
|
|
||||||
/** 诊断日期(精确到小时) */
|
/** 诊断日期(精确到小时) */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
|
||||||
private LocalDateTime diagDate;
|
private LocalDateTime diagDate;
|
||||||
|
|
||||||
/** 死亡日期(死亡病例必填) */
|
/** 死亡日期(死亡病例必填) */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
private LocalDate deathDate;
|
private LocalDate deathDate;
|
||||||
|
|
||||||
/** 订正病名(订正报告必填) */
|
/** 订正病名(订正报告必填) */
|
||||||
@@ -136,6 +139,7 @@ public class InfectiousDiseaseReportDto {
|
|||||||
private String reportDoc;
|
private String reportDoc;
|
||||||
|
|
||||||
/** 填卡日期 */
|
/** 填卡日期 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
private LocalDate reportDate;
|
private LocalDate reportDate;
|
||||||
|
|
||||||
/** 报卡名称代码 1-中华人民共和国传染病报告卡 */
|
/** 报卡名称代码 1-中华人民共和国传染病报告卡 */
|
||||||
|
|||||||
@@ -178,8 +178,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
|||||||
inpatientAdviceParam.setEncounterIds(null);
|
inpatientAdviceParam.setEncounterIds(null);
|
||||||
Integer exeStatus = inpatientAdviceParam.getExeStatus();
|
Integer exeStatus = inpatientAdviceParam.getExeStatus();
|
||||||
inpatientAdviceParam.setExeStatus(null);
|
inpatientAdviceParam.setExeStatus(null);
|
||||||
// requestStatus由前端tab控制,后端SQL已通过CASE条件处理校对状态过滤,无需再作为SQL条件
|
// requestStatus由前端tab传入,通过QueryWrapper自动添加到SQL外层WHERE过滤
|
||||||
inpatientAdviceParam.setRequestStatus(null);
|
|
||||||
// 构建查询条件
|
// 构建查询条件
|
||||||
QueryWrapper<InpatientAdviceParam> queryWrapper
|
QueryWrapper<InpatientAdviceParam> queryWrapper
|
||||||
= HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null, null, null);
|
= HisQueryUtils.buildQueryWrapper(inpatientAdviceParam, null, null, null);
|
||||||
@@ -368,7 +367,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
|||||||
.in(MedicationDispense::getMedReqId, medReqIds)
|
.in(MedicationDispense::getMedReqId, medReqIds)
|
||||||
.eq(MedicationDispense::getStatusEnum, DispenseStatus.COMPLETED.getValue()));
|
.eq(MedicationDispense::getStatusEnum, DispenseStatus.COMPLETED.getValue()));
|
||||||
if (!dispenseList.isEmpty()) {
|
if (!dispenseList.isEmpty()) {
|
||||||
return R.fail("该医嘱已发药,无法退回");
|
return R.fail("该药品已由药房发放,请先执行退药处理,不可直接退回");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
|
Long practitionerId = SecurityUtils.getLoginUser().getPractitionerId();
|
||||||
|
|||||||
@@ -1046,8 +1046,10 @@ function handleSave() {
|
|||||||
chargeItemId: item.chargeItemId,
|
chargeItemId: item.chargeItemId,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
// 确保 organizationId 不为 undefined(手术计费场景下可能缺失 orgId)
|
||||||
|
const orgId = props.patientInfo.orgId || props.patientInfo.effectiveOrgId || 1;
|
||||||
savePrescriptionSign({
|
savePrescriptionSign({
|
||||||
organizationId: props.patientInfo.orgId,
|
organizationId: orgId,
|
||||||
adviceSaveList: list,
|
adviceSaveList: list,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@@ -1064,6 +1066,7 @@ function handleSave() {
|
|||||||
}
|
}
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error('签发失败:', error);
|
console.error('签发失败:', error);
|
||||||
|
console.warn('签发操作失败(可能无权限或后端异常):', error?.response?.data?.msg || error?.message);
|
||||||
proxy.$modal.msgError(error?.response?.data?.msg || error?.message || '签发失败,请重试');
|
proxy.$modal.msgError(error?.response?.data?.msg || error?.message || '签发失败,请重试');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1025,7 +1025,11 @@ function parseBirthDate(birthDate) {
|
|||||||
|
|
||||||
function normalizeDate(value) {
|
function normalizeDate(value) {
|
||||||
if (!value) return '';
|
if (!value) return '';
|
||||||
return String(value).split(/[T ]/)[0];
|
const datePart = String(value).split(/[T ]/)[0].replace(/\//g, '-');
|
||||||
|
const parts = datePart.split('-');
|
||||||
|
if (parts.length !== 3) return datePart;
|
||||||
|
const [year, month, day] = parts;
|
||||||
|
return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeSex(value) {
|
function normalizeSex(value) {
|
||||||
@@ -1116,7 +1120,7 @@ function showReport(reportData = {}, readOnly = true) {
|
|||||||
addressHouse: reportData.addressHouse || '',
|
addressHouse: reportData.addressHouse || '',
|
||||||
patientBelong: reportData.patientBelong || 1,
|
patientBelong: reportData.patientBelong || 1,
|
||||||
occupation: reportData.occupation || '',
|
occupation: reportData.occupation || '',
|
||||||
caseClass: reportData.diseaseType != null ? String(reportData.diseaseType) : '',
|
caseClass: reportData.caseClass != null ? String(reportData.caseClass) : '',
|
||||||
onsetDate: normalizeDate(reportData.onsetDate),
|
onsetDate: normalizeDate(reportData.onsetDate),
|
||||||
diagDate: normalizeDate(reportData.diagDate),
|
diagDate: normalizeDate(reportData.diagDate),
|
||||||
deathDate: normalizeDate(reportData.deathDate),
|
deathDate: normalizeDate(reportData.deathDate),
|
||||||
@@ -1125,7 +1129,7 @@ function showReport(reportData = {}, readOnly = true) {
|
|||||||
selectedClassB: diseaseSelection.selectedClassB,
|
selectedClassB: diseaseSelection.selectedClassB,
|
||||||
selectedClassC: diseaseSelection.selectedClassC,
|
selectedClassC: diseaseSelection.selectedClassC,
|
||||||
otherDisease: reportData.otherDisease || (diseaseCode === 'OTHER' ? reportData.diseaseName || '' : ''),
|
otherDisease: reportData.otherDisease || (diseaseCode === 'OTHER' ? reportData.diseaseName || '' : ''),
|
||||||
diseaseType: reportData.diseaseSubtype || '',
|
diseaseType: reportData.diseaseSubtype || reportData.diseaseType || '',
|
||||||
reportOrg: reportData.reportOrg || '',
|
reportOrg: reportData.reportOrg || '',
|
||||||
reportOrgPhone: reportData.reportOrgPhone || '',
|
reportOrgPhone: reportData.reportOrgPhone || '',
|
||||||
reportDoc: reportData.reportDoc || '',
|
reportDoc: reportData.reportDoc || '',
|
||||||
@@ -1466,7 +1470,7 @@ async function buildSubmitData() {
|
|||||||
reportDate: formData.reportDate || null,
|
reportDate: formData.reportDate || null,
|
||||||
cardNameCode: 1, // 默认中华人民共和国传染病报告卡
|
cardNameCode: 1, // 默认中华人民共和国传染病报告卡
|
||||||
registrationSource: 1, // 默认门诊
|
registrationSource: 1, // 默认门诊
|
||||||
status: '',
|
status: null,
|
||||||
deptId: props.deptId || null,
|
deptId: props.deptId || null,
|
||||||
doctorId: props.doctorId || null,
|
doctorId: props.doctorId || null,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -653,6 +653,16 @@ async function handleUseOrderGroup(row) {
|
|||||||
unitCodeName: item.unitCodeName || orderDetail.unitCode_dictText,
|
unitCodeName: item.unitCodeName || orderDetail.unitCode_dictText,
|
||||||
minUnitCode: orderDetail.minUnitCode,
|
minUnitCode: orderDetail.minUnitCode,
|
||||||
doseUnitCode: orderDetail.doseUnitCode,
|
doseUnitCode: orderDetail.doseUnitCode,
|
||||||
|
doseUnitCode_dictText: orderDetail.doseUnitCode_dictText || '',
|
||||||
|
|
||||||
|
// 药房/科室名称(setValue 通过库存查找设置,但需确保 orderDetail 中有)
|
||||||
|
positionName: orderDetail.positionName || '',
|
||||||
|
|
||||||
|
// 注射/皮试标识(表格列显示依赖这些字段)
|
||||||
|
injectFlag: orderDetail.injectFlag,
|
||||||
|
injectFlag_enumText: orderDetail.injectFlag_enumText || '',
|
||||||
|
skinTestFlag: orderDetail.skinTestFlag,
|
||||||
|
skinTestFlag_enumText: orderDetail.skinTestFlag_enumText || '',
|
||||||
|
|
||||||
// 字典文本(传递到 item 层级,避免后续代码依赖 mergedDetail 再查一次)
|
// 字典文本(传递到 item 层级,避免后续代码依赖 mergedDetail 再查一次)
|
||||||
methodCode_dictText: methodCodeDictText,
|
methodCode_dictText: methodCodeDictText,
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ const form = ref({
|
|||||||
prescriptionList: prescriptionList.value,
|
prescriptionList: prescriptionList.value,
|
||||||
});
|
});
|
||||||
const adviceQueryParams = ref({
|
const adviceQueryParams = ref({
|
||||||
adviceType: '',
|
adviceType: 1,
|
||||||
categoryCode: '', // 初始为空,等待加载配置后动态设置
|
categoryCode: '', // 初始为空,等待加载配置后动态设置
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
});
|
});
|
||||||
@@ -533,7 +533,6 @@ const statusOption = [
|
|||||||
let loadingInstance = undefined;
|
let loadingInstance = undefined;
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('keydown', escKeyListener);
|
document.addEventListener('keydown', escKeyListener);
|
||||||
getList();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@@ -574,6 +573,7 @@ function handleTotalAmount() {
|
|||||||
}
|
}
|
||||||
}, new Decimal(0));
|
}, new Decimal(0));
|
||||||
}
|
}
|
||||||
|
getList();
|
||||||
function getList() {
|
function getList() {
|
||||||
getDiagnosisDefinitionList(queryParams.value).then((res) => {
|
getDiagnosisDefinitionList(queryParams.value).then((res) => {
|
||||||
// prescriptionList.value = res.data.records;
|
// prescriptionList.value = res.data.records;
|
||||||
@@ -585,11 +585,6 @@ function refresh() {
|
|||||||
}
|
}
|
||||||
// 获取列表信息
|
// 获取列表信息
|
||||||
function getListInfo(addNewRow) {
|
function getListInfo(addNewRow) {
|
||||||
// 守护:未选择患者时不发起 API 请求,避免页面加载时循环报错
|
|
||||||
if (!patientInfo.value || !patientInfo.value.encounterId) {
|
|
||||||
console.warn('⚠️ getListInfo 跳过:未选择患者');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loadingInstance = ElLoading.service({ fullscreen: true });
|
loadingInstance = ElLoading.service({ fullscreen: true });
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loadingInstance.close();
|
loadingInstance.close();
|
||||||
@@ -691,7 +686,7 @@ function loadConfiguredCategories() {
|
|||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
// 创建新对象触发响应式更新
|
// 创建新对象触发响应式更新
|
||||||
adviceQueryParams.value = {
|
adviceQueryParams.value = {
|
||||||
adviceType: '',
|
adviceType: 1,
|
||||||
categoryCode: defaultCategoryCode,
|
categoryCode: defaultCategoryCode,
|
||||||
searchKey: '',
|
searchKey: '',
|
||||||
};
|
};
|
||||||
@@ -715,17 +710,9 @@ function loadConfiguredCategories() {
|
|||||||
// 数据过滤
|
// 数据过滤
|
||||||
const filterPrescriptionList = computed(() => {
|
const filterPrescriptionList = computed(() => {
|
||||||
const pList = prescriptionList.value.filter((item) => {
|
const pList = prescriptionList.value.filter((item) => {
|
||||||
// 修复 Bug #488:orderClassCode 可能是复合值 '1-2',需提取 adviceType 部分进行比较
|
|
||||||
let matchAdviceType = true;
|
|
||||||
if (orderClassCode.value) {
|
|
||||||
const filterAdviceType = String(orderClassCode.value).includes('-')
|
|
||||||
? parseInt(String(orderClassCode.value).split('-')[0])
|
|
||||||
: orderClassCode.value;
|
|
||||||
matchAdviceType = filterAdviceType == item.adviceType;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
(!therapyEnum.value || therapyEnum.value == item.therapyEnum) &&
|
(!therapyEnum.value || therapyEnum.value == item.therapyEnum) &&
|
||||||
matchAdviceType &&
|
(!orderClassCode.value || orderClassCode.value == item.adviceType) &&
|
||||||
(!orderStatus.value || (orderStatus.value == item.statusEnum && item.requestId))
|
(!orderStatus.value || (orderStatus.value == item.statusEnum && item.requestId))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -753,28 +740,12 @@ function getRowDisabled(row) {
|
|||||||
/**
|
/**
|
||||||
* 将行的 adviceType + categoryCode 映射为 el-select 的选中值
|
* 将行的 adviceType + categoryCode 映射为 el-select 的选中值
|
||||||
* 药品子分类使用复合值如 '1-2'(adviceType-categoryCode),诊疗/手术/全部使用原始值
|
* 药品子分类使用复合值如 '1-2'(adviceType-categoryCode),诊疗/手术/全部使用原始值
|
||||||
* 修复 Bug #488:当行的 adviceType 在当前配置中找不到匹配选项时,返回最接近的可用值,避免回显为纯数字
|
|
||||||
*/
|
*/
|
||||||
function getRowSelectValue(row) {
|
function getRowSelectValue(row) {
|
||||||
if (row.adviceType == 1 && row.categoryCode) {
|
if (row.adviceType == 1 && row.categoryCode) {
|
||||||
const compositeValue = '1-' + row.categoryCode;
|
return '1-' + row.categoryCode;
|
||||||
// 检查复合值是否在选项列表中
|
|
||||||
if (adviceTypeList.value.some(item => item.value === compositeValue)) {
|
|
||||||
return compositeValue;
|
|
||||||
}
|
|
||||||
// 配置的 categoryCode 已变更,回退到第一个药品选项
|
|
||||||
const firstPharmacy = adviceTypeList.value.find(item => String(item.value).startsWith('1-'));
|
|
||||||
if (firstPharmacy) {
|
|
||||||
return firstPharmacy.value;
|
|
||||||
}
|
|
||||||
return row.adviceType;
|
|
||||||
}
|
}
|
||||||
// 诊疗/手术等非药品类型,检查其值是否在选项列表中
|
return row.adviceType;
|
||||||
if (adviceTypeList.value.some(item => item.value === row.adviceType)) {
|
|
||||||
return row.adviceType;
|
|
||||||
}
|
|
||||||
// 不在选项中的值(如已废弃的 adviceType),返回 undefined 让 el-select 显示为空
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增医嘱
|
// 新增医嘱
|
||||||
@@ -831,8 +802,8 @@ function clickRowDb(row, column, event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
row.showPopover = false;
|
row.showPopover = false;
|
||||||
// 仅”待签发(statusEnum==1)”允许编辑;”已签发(statusEnum==2)”及之后状态不允许编辑
|
// “待签发(已保存 requestId存在)”不允许再编辑;仅“待保存(无requestId)”允许编辑
|
||||||
if (row.statusEnum == 1) {
|
if (row.statusEnum == 1 && !row.requestId) {
|
||||||
// 确保治疗类型为字符串,方便与单选框 label 对齐,默认为长期医嘱('1')
|
// 确保治疗类型为字符串,方便与单选框 label 对齐,默认为长期医嘱('1')
|
||||||
row.therapyEnum = String(row.therapyEnum ?? '1');
|
row.therapyEnum = String(row.therapyEnum ?? '1');
|
||||||
row.isEdit = true;
|
row.isEdit = true;
|
||||||
@@ -910,9 +881,9 @@ function handleFocus(row, index) {
|
|||||||
// 用 adviceType + categoryCode 组合查找匹配的选项
|
// 用 adviceType + categoryCode 组合查找匹配的选项
|
||||||
const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||||
// 修复Bug #486:当行没有显式选择医嘱类型时(row.adviceType为undefined),
|
// If the row has an explicit adviceType (saved/existing row), use its own categoryCode.
|
||||||
// 不传categoryCode,让搜索在全药库中进行;只有行已选择类型时才用对应categoryCode过滤
|
// If no type is selected (new row), use empty string for global search across all categories.
|
||||||
const categoryCode = row.adviceType !== undefined ? (selectedItem ? selectedItem.categoryCode : '') : '';
|
const categoryCode = selectedItem ? selectedItem.categoryCode : (row.adviceType != null ? (row.categoryCode || '') : '');
|
||||||
const searchKey = row.adviceName || '';
|
const searchKey = row.adviceName || '';
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@@ -949,12 +920,9 @@ function handleChange(value) {
|
|||||||
// 用 adviceType + categoryCode 组合查找匹配的选项
|
// 用 adviceType + categoryCode 组合查找匹配的选项
|
||||||
const selectValue = (adviceType == 1 && row?.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
const selectValue = (adviceType == 1 && row?.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||||
// 修复Bug #486:当行没有显式选择医嘱类型时(row?.adviceType为undefined),
|
// 修复Bug #486:当行没有显式选择医嘱类型时,不传categoryCode,让搜索在全药库中进行
|
||||||
// 不传categoryCode,让搜索在全药库中进行;只有行已选择类型时才用对应categoryCode过滤
|
const categoryCode = selectedItem ? selectedItem.categoryCode : (row?.adviceType !== undefined ? (adviceQueryParams.value.categoryCode || '') : '');
|
||||||
const categoryCode = row?.adviceType !== undefined ? (selectedItem ? selectedItem.categoryCode : '') : '';
|
tableRef.refresh(adviceType, categoryCode, value);
|
||||||
// 修复Bug #453:当adviceType为空字符串或NaN时,不传具体类型,让refresh函数根据searchKey决定搜索范围
|
|
||||||
const effectiveAdviceType = (adviceType && !isNaN(Number(adviceType))) ? adviceType : '';
|
|
||||||
tableRef.refresh(effectiveAdviceType, categoryCode, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1213,27 +1181,19 @@ function handleSave() {
|
|||||||
});
|
});
|
||||||
// 此处签发处方和单行保存处方传参相同,后台已经将传参存为JSON字符串,此处直接转换为JSON即可
|
// 此处签发处方和单行保存处方传参相同,后台已经将传参存为JSON字符串,此处直接转换为JSON即可
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
let list = [];
|
let list = saveList.map((item) => {
|
||||||
try {
|
const parsedContent = JSON.parse(item.contentJson);
|
||||||
list = saveList.map((item) => {
|
return {
|
||||||
const parsedContent = item.contentJson ? JSON.parse(item.contentJson) || {} : {};
|
...parsedContent,
|
||||||
return {
|
adviceType: item.adviceType,
|
||||||
...parsedContent,
|
requestId: item.requestId,
|
||||||
adviceType: item.adviceType,
|
dbOpType: '1',
|
||||||
requestId: item.requestId,
|
groupId: item.groupId,
|
||||||
dbOpType: '1',
|
uniqueKey: undefined,
|
||||||
groupId: item.groupId,
|
// 确保 therapyEnum 被正确传递
|
||||||
uniqueKey: undefined,
|
therapyEnum: parsedContent.therapyEnum || item.therapyEnum || '1',
|
||||||
// 确保 therapyEnum 被正确传递
|
};
|
||||||
therapyEnum: parsedContent?.therapyEnum || item.therapyEnum || '1',
|
});
|
||||||
};
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
loading.value = false;
|
|
||||||
isSaving.value = false;
|
|
||||||
proxy.$modal.msgError('医嘱内容解析失败,请检查待签发医嘱');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 保存签发按钮
|
// 保存签发按钮
|
||||||
isSaving.value = true;
|
isSaving.value = true;
|
||||||
console.log('签发处方参数:', {
|
console.log('签发处方参数:', {
|
||||||
@@ -1248,16 +1208,9 @@ function handleSave() {
|
|||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy.$modal.msgSuccess('签发成功');
|
proxy.$modal.msgSuccess('签发成功');
|
||||||
isSaving.value = false;
|
isSaving.value = false;
|
||||||
// 乐观更新:立即将已签发医嘱的状态设为"已签发",确保列表实时刷新
|
|
||||||
saveList.forEach((item) => {
|
|
||||||
const row = prescriptionList.value.find((r) => r.requestId && r.requestId === item.requestId);
|
|
||||||
if (row) {
|
|
||||||
row.statusEnum = 2;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
getListInfo(false);
|
getListInfo(false);
|
||||||
bindMethod.value = {};
|
bindMethod.value = {};
|
||||||
nextId.value = 1;
|
nextId.value == 1;
|
||||||
} else {
|
} else {
|
||||||
proxy.$modal.msgError(res.message);
|
proxy.$modal.msgError(res.message);
|
||||||
isSaving.value = false;
|
isSaving.value = false;
|
||||||
@@ -1358,12 +1311,11 @@ function handleCancelEdit(row, index) {
|
|||||||
|
|
||||||
function handleSaveSign(row, index) {
|
function handleSaveSign(row, index) {
|
||||||
if (row.adviceType != 2) {
|
if (row.adviceType != 2) {
|
||||||
// 修复 Bug #488:严格校验 itemNo,确保非空且为有效字符串才发起请求
|
|
||||||
let itemNo = row.adviceType == 1 ? row.methodCode : row.adviceDefinitionId;
|
let itemNo = row.adviceType == 1 ? row.methodCode : row.adviceDefinitionId;
|
||||||
if (!itemNo || String(itemNo).trim() === '') {
|
if (!itemNo) {
|
||||||
console.warn('绑定设备检查跳过:itemNo为空(adviceType=' + row.adviceType + ', adviceName=' + row.adviceName + ')');
|
console.warn('绑定设备检查跳过:itemNo为空(adviceType=' + row.adviceType + ', adviceName=' + row.adviceName + ')');
|
||||||
} else {
|
} else {
|
||||||
getBindDevice({ typeCode: row.adviceType, itemNo: String(itemNo) }).then((res) => {
|
getBindDevice({ typeCode: row.adviceType, itemNo: itemNo }).then((res) => {
|
||||||
if (res.data.length == 0) {
|
if (res.data.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1424,21 +1376,13 @@ function handleSaveSign(row, index) {
|
|||||||
savePrescription({ regAdviceSaveList: [row] }).then((res) => {
|
savePrescription({ regAdviceSaveList: [row] }).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy.$modal.msgSuccess('保存成功');
|
proxy.$modal.msgSuccess('保存成功');
|
||||||
nextId.value = 1;
|
nextId.value == 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 新增行:调用保存接口将数据持久化到后端
|
if (prescriptionList.value[0].adviceName) {
|
||||||
row.dbOpType = '1';
|
handleAddPrescription();
|
||||||
savePrescription({ regAdviceSaveList: [row] }).then((res) => {
|
}
|
||||||
if (res.code === 200) {
|
|
||||||
proxy.$modal.msgSuccess('保存成功');
|
|
||||||
nextId.value = 1;
|
|
||||||
// 保存成功后刷新列表,确保后端返回的数据带 requestId
|
|
||||||
getListInfo(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 不需要再添加空行,保存成功后由 getListInfo 处理
|
|
||||||
}
|
}
|
||||||
adviceQueryParams.value.adviceType = undefined;
|
adviceQueryParams.value.adviceType = undefined;
|
||||||
}
|
}
|
||||||
@@ -1479,40 +1423,32 @@ function handleSaveBatch() {
|
|||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
proxy.$modal.msgSuccess('保存成功');
|
proxy.$modal.msgSuccess('保存成功');
|
||||||
// 修复 Bug #405:保存成功后锁定所有待保存行,避免医嘱条目仍处于可编辑状态
|
// 修复【#405】:保存成功后重置所有待保存行的 isEdit 为 false,锁定医嘱不再编辑
|
||||||
// saveList 中的 item 与 prescriptionList 是同一对象引用,直接修改即可
|
|
||||||
saveList.forEach(item => {
|
saveList.forEach(item => {
|
||||||
item.isEdit = false;
|
const row = prescriptionList.value.find(r => r.uniqueKey === item.uniqueKey);
|
||||||
|
if (row) row.isEdit = false;
|
||||||
});
|
});
|
||||||
// 兜底:锁定所有 statusEnum == 1 的行,确保没有遗漏
|
|
||||||
prescriptionList.value.forEach(row => {
|
|
||||||
if (row.statusEnum == 1) {
|
|
||||||
row.isEdit = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expandOrder.value = [];
|
|
||||||
getListInfo(false);
|
getListInfo(false);
|
||||||
nextId.value = 1;
|
nextId.value == 1;
|
||||||
isSaving.value = false;
|
isSaving.value = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
isSaving.value = false;
|
isSaving.value = false;
|
||||||
proxy.$modal.msgError(error?.msg || '保存失败,请重试');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setValue(row) {
|
function setValue(row) {
|
||||||
// 构造单位列表,确保 value 始终为 String 类型,避免 el-select 值类型不匹配
|
// 构造单位列表
|
||||||
unitCodeList.value = [
|
unitCodeList.value = [
|
||||||
{ value: String(row.unitCode ?? ''), label: row.unitCode_dictText, type: 'unit' },
|
{ value: row.unitCode, label: row.unitCode_dictText, type: 'unit' },
|
||||||
{
|
{
|
||||||
value: String(row.doseUnitCode ?? ''),
|
value: row.doseUnitCode,
|
||||||
label: row.doseUnitCode_dictText,
|
label: row.doseUnitCode_dictText,
|
||||||
type: 'dose',
|
type: 'dose',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: String(row.minUnitCode ?? ''),
|
value: row.minUnitCode,
|
||||||
label: row.minUnitCode_dictText,
|
label: row.minUnitCode_dictText,
|
||||||
type: 'minUnit',
|
type: 'minUnit',
|
||||||
},
|
},
|
||||||
@@ -1577,9 +1513,9 @@ function setValue(row) {
|
|||||||
orgName: row.adviceType != 3 ? undefined : (findOrgName(row.orgId || row.positionId || patientInfo.value?.inHospitalOrgId) || row.orgName || patientInfo.value?.inHospitalOrgName || ''),
|
orgName: row.adviceType != 3 ? undefined : (findOrgName(row.orgId || row.positionId || patientInfo.value?.inHospitalOrgId) || row.orgName || patientInfo.value?.inHospitalOrgName || ''),
|
||||||
// dose: undefined, Removed to preserve dose value from group package
|
// dose: undefined, Removed to preserve dose value from group package
|
||||||
unitCodeList: unitCodeList.value,
|
unitCodeList: unitCodeList.value,
|
||||||
doseUnitCode: String(row.doseUnitCode ?? ''),
|
doseUnitCode: row.doseUnitCode,
|
||||||
minUnitCode: String(row.minUnitCode ?? ''),
|
minUnitCode: row.minUnitCode,
|
||||||
unitCode: row.partAttributeEnum == 1 ? String(row.minUnitCode ?? '') : String(row.unitCode ?? ''),
|
unitCode: row.partAttributeEnum == 1 ? row.minUnitCode : row.unitCode,
|
||||||
categoryEnum: row.categoryCode,
|
categoryEnum: row.categoryCode,
|
||||||
definitionId: row.chargeItemDefinitionId,
|
definitionId: row.chargeItemDefinitionId,
|
||||||
executeNum: 1,
|
executeNum: 1,
|
||||||
@@ -1595,10 +1531,6 @@ function setValue(row) {
|
|||||||
? new Decimal(selectedStock.price).div(row.partPercent).toFixed(6)
|
? new Decimal(selectedStock.price).div(row.partPercent).toFixed(6)
|
||||||
: prevRow.minUnitPrice,
|
: prevRow.minUnitPrice,
|
||||||
positionName: selectedStock?.locationName,
|
positionName: selectedStock?.locationName,
|
||||||
// 🔧 Bug #523 修复:初始化 totalPrice 为 0,避免总金额列显示为横杠
|
|
||||||
totalPrice: row.quantity
|
|
||||||
? new Decimal(row.quantity).mul(selectedStock?.price ?? 0).toFixed(6)
|
|
||||||
: '0',
|
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
@@ -1630,21 +1562,17 @@ function handleSaveGroup(orderGroupList) {
|
|||||||
// 🔥 新版组件已经预处理了数据,优先使用 mergedDetail
|
// 🔥 新版组件已经预处理了数据,优先使用 mergedDetail
|
||||||
const mergedDetail = item.mergedDetail || {
|
const mergedDetail = item.mergedDetail || {
|
||||||
...(item.orderDetailInfos || {}),
|
...(item.orderDetailInfos || {}),
|
||||||
adviceName: item.orderDefinitionName || item.orderDetailInfos?.adviceName || '未知项目',
|
adviceName: item.orderDetailInfos?.adviceName || item.orderDefinitionName || '未知项目',
|
||||||
adviceType: item.orderDetailInfos?.adviceType,
|
adviceType: item.orderDetailInfos?.adviceType,
|
||||||
adviceDefinitionId: item.orderDefinitionId || item.orderDetailInfos?.adviceDefinitionId,
|
adviceDefinitionId: item.orderDefinitionId || item.orderDetailInfos?.adviceDefinitionId,
|
||||||
quantity: item.quantity,
|
quantity: item.quantity,
|
||||||
unitCode: item.unitCode || item.orderDetailInfos?.unitCode,
|
unitCode: item.unitCode || item.orderDetailInfos?.unitCode,
|
||||||
unitCodeName: item.unitCodeName,
|
unitCodeName: item.unitCodeName,
|
||||||
// 🔧 Bug #403 修复:dose/doseQuantity/dispensePerDuration 需用 null 检查,
|
dose: item.dose || item.orderDetailInfos?.dose,
|
||||||
// 避免组套中值为 null 时回退到医嘱库的 orderDetailInfos
|
|
||||||
dose: item.dose !== undefined && item.dose !== null ? item.dose : item.orderDetailInfos?.dose,
|
|
||||||
rateCode: item.rateCode || item.orderDetailInfos?.rateCode,
|
rateCode: item.rateCode || item.orderDetailInfos?.rateCode,
|
||||||
methodCode: item.methodCode || item.orderDetailInfos?.methodCode,
|
methodCode: item.methodCode || item.orderDetailInfos?.methodCode,
|
||||||
dispensePerDuration: item.dispensePerDuration !== undefined && item.dispensePerDuration !== null
|
dispensePerDuration: item.dispensePerDuration || item.orderDetailInfos?.dispensePerDuration,
|
||||||
? item.dispensePerDuration : item.orderDetailInfos?.dispensePerDuration,
|
doseQuantity: item.doseQuantity,
|
||||||
doseQuantity: item.doseQuantity !== undefined && item.doseQuantity !== null
|
|
||||||
? item.doseQuantity : item.orderDetailInfos?.doseQuantity,
|
|
||||||
inventoryList: item.orderDetailInfos?.inventoryList || [],
|
inventoryList: item.orderDetailInfos?.inventoryList || [],
|
||||||
priceList: item.orderDetailInfos?.priceList || [],
|
priceList: item.orderDetailInfos?.priceList || [],
|
||||||
partPercent: item.orderDetailInfos?.partPercent || 1,
|
partPercent: item.orderDetailInfos?.partPercent || 1,
|
||||||
@@ -1663,69 +1591,41 @@ function handleSaveGroup(orderGroupList) {
|
|||||||
setValue(mergedDetail);
|
setValue(mergedDetail);
|
||||||
|
|
||||||
// 创建新的处方项目
|
// 创建新的处方项目
|
||||||
// 🔧 Bug #403 修复:关键字段使用 null-safe 回退到 mergedDetail(已由 setValue 填充完整数据)
|
|
||||||
// 先取 setValue 填充的行数据作为基础
|
|
||||||
const baseRow = prescriptionList.value[rowIndex.value];
|
|
||||||
const newRow = {
|
const newRow = {
|
||||||
...baseRow,
|
...prescriptionList.value[rowIndex.value],
|
||||||
isEdit: false,
|
|
||||||
patientId: patientInfo.value.patientId,
|
patientId: patientInfo.value.patientId,
|
||||||
encounterId: patientInfo.value.encounterId,
|
encounterId: patientInfo.value.encounterId,
|
||||||
accountId: accountId.value,
|
accountId: accountId.value,
|
||||||
|
quantity: item.quantity,
|
||||||
|
methodCode: item.methodCode,
|
||||||
|
rateCode: item.rateCode,
|
||||||
|
dispensePerDuration: item.dispensePerDuration,
|
||||||
|
dose: item.dose,
|
||||||
|
doseQuantity: item.doseQuantity,
|
||||||
executeNum: 1,
|
executeNum: 1,
|
||||||
|
unitCode: item.unitCode,
|
||||||
|
unitCode_dictText: item.unitCodeName || '',
|
||||||
statusEnum: 1,
|
statusEnum: 1,
|
||||||
orgId: resolveOrgId(
|
orgId: resolveOrgId(item.orderDetailInfos?.orgId || mergedDetail.orgId || patientInfo.value?.inHospitalOrgId) || '',
|
||||||
(item.orderDetailInfos?.orgId || mergedDetail.orgId)
|
// 🔧 修复:同时保存 orgName,确保树匹配不到时仍有中文名称可显示
|
||||||
? (item.orderDetailInfos?.orgId || mergedDetail.orgId)
|
orgName: findOrgName(item.orderDetailInfos?.orgId || mergedDetail.orgId || patientInfo.value?.inHospitalOrgId) || item.orderDetailInfos?.orgName || mergedDetail.orgName || patientInfo.value?.inHospitalOrgName || '',
|
||||||
: patientInfo.value?.inHospitalOrgId
|
|
||||||
) || '',
|
|
||||||
orgName: findOrgName(
|
|
||||||
(item.orderDetailInfos?.orgId || mergedDetail.orgId)
|
|
||||||
? (item.orderDetailInfos?.orgId || mergedDetail.orgId)
|
|
||||||
: patientInfo.value?.inHospitalOrgId
|
|
||||||
) || item.orderDetailInfos?.orgName || mergedDetail.orgName || patientInfo.value?.inHospitalOrgName || '',
|
|
||||||
dbOpType: prescriptionList.value[rowIndex.value].requestId ? '2' : '1',
|
dbOpType: prescriptionList.value[rowIndex.value].requestId ? '2' : '1',
|
||||||
conditionId: conditionId.value,
|
conditionId: conditionId.value,
|
||||||
conditionDefinitionId: conditionDefinitionId.value,
|
conditionDefinitionId: conditionDefinitionId.value,
|
||||||
encounterDiagnosisId: encounterDiagnosisId.value,
|
encounterDiagnosisId: encounterDiagnosisId.value,
|
||||||
diagnosisName: diagnosisName.value,
|
therapyEnum: prescriptionList.value[rowIndex.value]?.therapyEnum || '1',
|
||||||
therapyEnum: baseRow?.therapyEnum || '1',
|
|
||||||
};
|
};
|
||||||
// 覆盖关键字段:优先使用 item 的值,其次 mergedDetail(已由 setValue 填充),最后 baseRow
|
|
||||||
newRow.quantity = item.quantity ?? mergedDetail.quantity ?? baseRow.quantity;
|
|
||||||
newRow.methodCode = item.methodCode ?? mergedDetail.methodCode ?? baseRow.methodCode;
|
|
||||||
newRow.rateCode = item.rateCode ?? mergedDetail.rateCode ?? baseRow.rateCode;
|
|
||||||
newRow.dispensePerDuration = item.dispensePerDuration ?? mergedDetail.dispensePerDuration ?? baseRow.dispensePerDuration;
|
|
||||||
newRow.dose = item.dose ?? mergedDetail.dose ?? baseRow.dose;
|
|
||||||
newRow.doseQuantity = item.doseQuantity ?? mergedDetail.doseQuantity ?? baseRow.doseQuantity;
|
|
||||||
newRow.unitCode = item.unitCode ?? mergedDetail.unitCode ?? baseRow.unitCode;
|
|
||||||
newRow.unitCode_dictText = item.unitCodeName || mergedDetail.unitCodeName || baseRow.unitCode_dictText || '';
|
|
||||||
// 确保价格字段有兜底值(setValue 可能因库存不足提前 return 导致未设置)
|
|
||||||
newRow.unitPrice = baseRow.unitPrice ?? mergedDetail.unitPrice ?? 0;
|
|
||||||
newRow.minUnitPrice = baseRow.minUnitPrice ?? mergedDetail.minUnitPrice ?? 0;
|
|
||||||
newRow.unitTempPrice = newRow.unitPrice;
|
|
||||||
newRow.methodCode_dictText = mergedDetail.methodCode_dictText || item.methodCode_dictText || '';
|
|
||||||
newRow.rateCode_dictText = mergedDetail.rateCode_dictText || item.rateCode_dictText || '';
|
|
||||||
newRow.doseUnitCode = mergedDetail.doseUnitCode || item.doseUnitCode || baseRow.doseUnitCode;
|
|
||||||
newRow.doseUnitCode_dictText = mergedDetail.doseUnitCode_dictText || item.doseUnitCode_dictText || '';
|
|
||||||
newRow.orgId = mergedDetail.orgId || mergedDetail.positionId || baseRow.orgId || '';
|
|
||||||
newRow.positionName = mergedDetail.orgName || mergedDetail.positionName || baseRow.positionName || '';
|
|
||||||
|
|
||||||
// 计算价格和总量
|
// 计算价格和总量
|
||||||
// 🔧 Bug #403 修复:使用 newRow.unitCode(已由 setValue 填充)而非 item.unitCode
|
const unitInfo = unitCodeList.value.find((k) => k.value == item.unitCode);
|
||||||
// 使用 ?? 替代 || 计算 partPercent,确保值为 0 时不会被错误替换
|
|
||||||
const finalUnitCode = newRow.unitCode;
|
|
||||||
const unitInfo = unitCodeList.value.find((k) => k.value == finalUnitCode);
|
|
||||||
const finalQuantity = newRow.quantity;
|
|
||||||
const partPercent = item.orderDetailInfos?.partPercent ?? mergedDetail.partPercent ?? baseRow.partPercent ?? 1;
|
|
||||||
if (unitInfo && unitInfo.type == 'minUnit') {
|
if (unitInfo && unitInfo.type == 'minUnit') {
|
||||||
newRow.price = newRow.minUnitPrice;
|
newRow.price = newRow.minUnitPrice;
|
||||||
newRow.totalPrice = ((finalQuantity || 0) * newRow.minUnitPrice).toFixed(6);
|
newRow.totalPrice = (item.quantity * newRow.minUnitPrice).toFixed(6);
|
||||||
newRow.minUnitQuantity = finalQuantity || 0;
|
newRow.minUnitQuantity = item.quantity;
|
||||||
} else {
|
} else {
|
||||||
newRow.price = newRow.unitPrice;
|
newRow.price = newRow.unitPrice;
|
||||||
newRow.totalPrice = ((finalQuantity || 0) * newRow.unitPrice).toFixed(6);
|
newRow.totalPrice = (item.quantity * newRow.unitPrice).toFixed(6);
|
||||||
newRow.minUnitQuantity = (finalQuantity || 0) * partPercent;
|
newRow.minUnitQuantity = item.quantity * (item.orderDetailInfos?.partPercent || mergedDetail.partPercent || 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
newRow.contentJson = JSON.stringify(newRow);
|
newRow.contentJson = JSON.stringify(newRow);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<span class="descriptions-item-label">全选:</span>
|
<span class="descriptions-item-label">全选:</span>
|
||||||
<el-switch v-model="chooseAll" @change="handelSwitchChange" />
|
<el-switch v-model="chooseAll" @change="handelSwitchChange" />
|
||||||
<el-button class="ml20" type="primary" @click="handleCheck"> 核对通过 </el-button>
|
<el-button class="ml20" type="primary" @click="handleCheck"> 核对通过 </el-button>
|
||||||
<el-button class="ml20 mr20" type="danger" @click="handleCancel"> 退回 </el-button>
|
<el-button class="ml20 mr20" type="danger" :disabled="hasDispensedSelected" @click="handleCancel"> 退回 </el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -152,6 +152,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import {ref, computed} from 'vue';
|
||||||
import {adviceVerify, cancel, getPrescriptionList} from './api';
|
import {adviceVerify, cancel, getPrescriptionList} from './api';
|
||||||
import {patientInfoList} from '../../components/store/patient.js';
|
import {patientInfoList} from '../../components/store/patient.js';
|
||||||
import {formatDateStr} from '@/utils/index';
|
import {formatDateStr} from '@/utils/index';
|
||||||
@@ -163,6 +164,11 @@ const type = ref(null);
|
|||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const chooseAll = ref(false);
|
const chooseAll = ref(false);
|
||||||
|
const selectionTrigger = ref(0);
|
||||||
|
const hasDispensedSelected = computed(() => {
|
||||||
|
selectionTrigger.value;
|
||||||
|
return getSelectRows().some(item => item.dispenseStatus === 4);
|
||||||
|
});
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
requestStatus: {
|
requestStatus: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -262,7 +268,9 @@ function getGroupMarkers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 选择框改变时的处理
|
// 选择框改变时的处理
|
||||||
function handleSelectionChange(selection, row) {}
|
function handleSelectionChange(selection, row) {
|
||||||
|
selectionTrigger.value++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 核对通过
|
* 核对通过
|
||||||
@@ -291,7 +299,7 @@ function handleCancel() {
|
|||||||
// 校验已发药的医嘱不允许退回
|
// 校验已发药的医嘱不允许退回
|
||||||
let dispensedItems = list.filter(item => item.dispenseStatus === 4);
|
let dispensedItems = list.filter(item => item.dispenseStatus === 4);
|
||||||
if (dispensedItems.length > 0) {
|
if (dispensedItems.length > 0) {
|
||||||
proxy.$message.error('该医嘱已发药,无法退回');
|
proxy.$message.error('该药品已由药房发放,请先执行退药处理,不可直接退回');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cancel(list).then((res) => {
|
cancel(list).then((res) => {
|
||||||
@@ -310,12 +318,16 @@ function getSelectRows() {
|
|||||||
// 获取选中的医嘱信息
|
// 获取选中的医嘱信息
|
||||||
let list = [];
|
let list = [];
|
||||||
prescriptionList.value.forEach((item, index) => {
|
prescriptionList.value.forEach((item, index) => {
|
||||||
list = [...list, ...proxy.$refs['tableRef' + index][0].getSelectionRows()];
|
const ref = proxy.$refs['tableRef' + index];
|
||||||
|
if (ref && ref[0]) {
|
||||||
|
list = [...list, ...ref[0].getSelectionRows()];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return list.map((item) => {
|
return list.map((item) => {
|
||||||
return {
|
return {
|
||||||
requestId: item.requestId,
|
requestId: item.requestId,
|
||||||
requestTable: item.adviceTable,
|
requestTable: item.adviceTable,
|
||||||
|
dispenseStatus: item.dispenseStatus,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -546,7 +546,7 @@
|
|||||||
v-model="form.admissionTime"
|
v-model="form.admissionTime"
|
||||||
type="datetime"
|
type="datetime"
|
||||||
placeholder="选择入室时间"
|
placeholder="选择入室时间"
|
||||||
value-format="YYYY-MM-DDTHH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
@@ -558,7 +558,7 @@
|
|||||||
v-model="form.entryTime"
|
v-model="form.entryTime"
|
||||||
type="datetime"
|
type="datetime"
|
||||||
placeholder="选择进室时间"
|
placeholder="选择进室时间"
|
||||||
value-format="YYYY-MM-DDTHH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
@@ -570,7 +570,7 @@
|
|||||||
v-model="form.anesStart"
|
v-model="form.anesStart"
|
||||||
type="datetime"
|
type="datetime"
|
||||||
placeholder="选择麻醉开始时间"
|
placeholder="选择麻醉开始时间"
|
||||||
value-format="YYYY-MM-DDTHH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
@@ -584,7 +584,7 @@
|
|||||||
v-model="form.startTime"
|
v-model="form.startTime"
|
||||||
type="datetime"
|
type="datetime"
|
||||||
placeholder="选择切开时间"
|
placeholder="选择切开时间"
|
||||||
value-format="YYYY-MM-DDTHH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
@@ -596,7 +596,7 @@
|
|||||||
v-model="form.endTime"
|
v-model="form.endTime"
|
||||||
type="datetime"
|
type="datetime"
|
||||||
placeholder="选择手术结束时间"
|
placeholder="选择手术结束时间"
|
||||||
value-format="YYYY-MM-DDTHH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
@@ -608,7 +608,7 @@
|
|||||||
v-model="form.anesEnd"
|
v-model="form.anesEnd"
|
||||||
type="datetime"
|
type="datetime"
|
||||||
placeholder="选择麻醉结束时间"
|
placeholder="选择麻醉结束时间"
|
||||||
value-format="YYYY-MM-DDTHH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
@@ -689,7 +689,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 手术申请查询弹窗 -->
|
<!-- 手术申请查询弹窗 -->
|
||||||
<el-dialog :title="'手术申请查询'" v-model="showApplyDialog" width="1200px" @close="cancelApplyDialog">
|
<el-dialog :title="'手术申请查询'" v-model="showApplyDialog" width="1200px" @close="cancelApplyDialog" class="surgery-apply-dialog">
|
||||||
<!-- 查询条件区 -->
|
<!-- 查询条件区 -->
|
||||||
<el-form :model="applyQueryParams" ref="applyQueryRef" :inline="true" class="query-form">
|
<el-form :model="applyQueryParams" ref="applyQueryRef" :inline="true" class="query-form">
|
||||||
<el-form-item label="手术单号" prop="surgeryNo">
|
<el-form-item label="手术单号" prop="surgeryNo">
|
||||||
@@ -749,8 +749,8 @@
|
|||||||
@row-click="handleApplyRowClick"
|
@row-click="handleApplyRowClick"
|
||||||
:row-class-name="tableRowClassName"
|
:row-class-name="tableRowClassName"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
max-height="400"
|
max-height="340"
|
||||||
:scroll="{ y: 400 }"
|
:scroll="{ y: 340 }"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" :selectable="handleSelectable" />
|
<el-table-column type="selection" width="55" :selectable="handleSelectable" />
|
||||||
<el-table-column label="ID" align="center" width="80" fixed>
|
<el-table-column label="ID" align="center" width="80" fixed>
|
||||||
@@ -781,7 +781,7 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 底部分页区 -->
|
<!-- 底部分页区 -->
|
||||||
<div class="pagination-container" style="margin-top: 10px; padding-bottom: 10px">
|
<div class="pagination-container apply-pagination" style="margin-top: 10px; padding-bottom: 20px">
|
||||||
<pagination
|
<pagination
|
||||||
v-show="applyTotal > 0"
|
v-show="applyTotal > 0"
|
||||||
:total="applyTotal"
|
:total="applyTotal"
|
||||||
@@ -792,10 +792,12 @@
|
|||||||
@pagination="getSurgicalScheduleList"
|
@pagination="getSurgicalScheduleList"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 分页与底部操作区之间的间隔 -->
|
||||||
|
<div style="height: 48px"></div>
|
||||||
|
|
||||||
<!-- 底部操作区 -->
|
<!-- 底部操作区 -->
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer" style="margin-top: 24px; padding-top: 12px; border-top: 1px solid #ebeef5">
|
||||||
<el-button @click="cancelApplyDialog">取消</el-button>
|
<el-button @click="cancelApplyDialog">取消</el-button>
|
||||||
<el-button type="primary" @click="confirmApply">确认</el-button>
|
<el-button type="primary" @click="confirmApply">确认</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -830,6 +832,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="padding: 10px">
|
<div style="padding: 10px">
|
||||||
<prescriptionlist :patientInfo="chargePatientInfo" ref="prescriptionRef"
|
<prescriptionlist :patientInfo="chargePatientInfo" ref="prescriptionRef"
|
||||||
|
:generateSourceEnum="1"
|
||||||
:sourceBillNo="chargePatientInfo.sourceBillNo" />
|
:sourceBillNo="chargePatientInfo.sourceBillNo" />
|
||||||
<div class="overlay" v-if="disabled"></div>
|
<div class="overlay" v-if="disabled"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2349,6 +2352,22 @@ function getRowClassName({ row, rowIndex }) {
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 手术申请查询弹窗 — 分页与footer间距 */
|
||||||
|
.surgery-apply-dialog :deep(.el-dialog__body) {
|
||||||
|
padding-bottom: 32px;
|
||||||
|
}
|
||||||
|
.surgery-apply-dialog :deep(.el-dialog__footer) {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.surgery-apply-dialog :deep(.apply-pagination) {
|
||||||
|
padding-bottom: 24px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
.surgery-apply-dialog :deep(.apply-pagination .el-pagination) {
|
||||||
|
margin-right: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
/* 选中行样式 */
|
/* 选中行样式 */
|
||||||
:deep(.el-table .selected-row) {
|
:deep(.el-table .selected-row) {
|
||||||
background-color: #ecf5ff !important;
|
background-color: #ecf5ff !important;
|
||||||
@@ -2359,3 +2378,21 @@ function getRowClassName({ row, rowIndex }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 手术申请查询弹窗 — 非 scoped 确保穿透 teleport */
|
||||||
|
.surgery-apply-dialog .apply-pagination {
|
||||||
|
padding-bottom: 24px !important;
|
||||||
|
margin-bottom: 16px !important;
|
||||||
|
border-bottom: 1px solid #ebeef5 !important;
|
||||||
|
}
|
||||||
|
.surgery-apply-dialog .apply-pagination .el-pagination {
|
||||||
|
margin-right: 80px !important;
|
||||||
|
}
|
||||||
|
.surgery-apply-dialog .el-dialog__body {
|
||||||
|
padding-bottom: 32px !important;
|
||||||
|
}
|
||||||
|
.surgery-apply-dialog .el-dialog__footer {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user