fix(#589): 请修复 Bug #589:[住院医生工作站-临床医嘱] 功能缺失与增加交互:缺少出院带药医嘱类型

根因:
- Bug #请修复 Bug #589 存在的问题

修复:
- ### 修改文件(3个)
- | `index.vue` | +67/-12 | 添加出院带药类型、强制临时锁定、保存映射、数据加载识别 |
- **1. 类型添加** — `adviceTypeList` 中新增 `{ label: '出院带药', value: 7, adviceType: 7 }`
This commit is contained in:
2026-05-29 00:20:30 +08:00
parent c399ef0853
commit ac26ac11ce
3 changed files with 199 additions and 12 deletions

View File

@@ -81,7 +81,7 @@ const tableColumns = computed<TableColumn[]>(() => [
/** /**
* 父组件主动调用此方法刷新列表 * 父组件主动调用此方法刷新列表
* @param adviceType 医嘱类型1=药品, 3=诊疗, 6=手术, ''=全部) * @param adviceType 医嘱类型1=药品, 3=诊疗, 6=手术, 7=出院带药, ''=全部)
* @param categoryCode 药品分类编码('1'=中成药, '2'=西药, '4'=中草药, ''=不限) * @param categoryCode 药品分类编码('1'=中成药, '2'=西药, '4'=中草药, ''=不限)
* @param searchKey 搜索关键词 * @param searchKey 搜索关键词
*/ */
@@ -89,6 +89,9 @@ function refresh(adviceType: any, categoryCode: string, searchKey: string) {
// 有搜索词时跨类型搜索,避免用户输入"级护理"但因当前adviceType为药品而搜不到诊疗类护理项目 // 有搜索词时跨类型搜索,避免用户输入"级护理"但因当前adviceType为药品而搜不到诊疗类护理项目
if (searchKey) { if (searchKey) {
queryParams.value.adviceTypes = [1, 2, 3, 6]; queryParams.value.adviceTypes = [1, 2, 3, 6];
} else if (adviceType == 7) {
// Bug #589: 出院带药仅检索西药和中成药
queryParams.value.adviceTypes = [1];
} else { } else {
queryParams.value.adviceTypes = queryParams.value.adviceTypes =
adviceType !== undefined && adviceType !== '' ? [parseInt(adviceType)] : [1, 2, 3, 6]; adviceType !== undefined && adviceType !== '' ? [parseInt(adviceType)] : [1, 2, 3, 6];
@@ -117,6 +120,13 @@ function getList() {
// 药品/耗材需要有库存才显示,诊疗/手术直接显示 // 药品/耗材需要有库存才显示,诊疗/手术直接显示
adviceBaseList.value = records.filter((item: any) => { adviceBaseList.value = records.filter((item: any) => {
// Bug #589: 出院带药仅显示西药(categoryCode='2')和中成药(categoryCode='1')
if (queryParams.value.adviceTypes.length === 1 && queryParams.value.adviceTypes[0] === 1 && !queryParams.value.categoryCode) {
if (item.adviceType == 1 && (item.categoryCode == '1' || item.categoryCode == '2')) {
return handleQuantity(item) !== '0';
}
return false;
}
if (item.adviceType == 1 || item.adviceType == 2) { if (item.adviceType == 1 || item.adviceType == 2) {
return handleQuantity(item) !== '0'; return handleQuantity(item) !== '0';
} }

View File

@@ -304,6 +304,119 @@
</div> </div>
</div> </div>
</template> </template>
<template v-else-if="row.adviceType == 7">
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
<span class="medicine-title">
{{
row.adviceName +
' ' +
row.volume +
' [' +
Number(row.unitPrice).toFixed(2) +
' 元' +
'/' +
row.unitCode_dictText +
']'
}}
</span>
<el-form-item label="开始时间:" prop="startTime">
<el-date-picker
v-model="row.startTime"
type="datetime"
placeholder="选择开始时间"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 190px; margin-right: 12px"
/>
</el-form-item>
<el-form-item prop="lotNumber" label="药房:">
<el-select
v-model="row.inventoryId"
style="width: 330px; margin-right: 20px"
placeholder="药房"
>
<el-option
v-for="item in row.stockList"
:key="item.inventoryId"
:value="item.inventoryId"
:label="`${item.locationName} 批次号: ${item.lotNumber ?? '-'} 库存:${stockFormat(row.partPercent, row.unitCodeList, item.quantity)}`"
@click="handleNumberClick(item)"
>
<div style="display: flex; gap: 8px; align-items: center">
<span>{{ item.locationName }}</span>
<span>批次号: {{ item.lotNumber ?? '-' }}</span>
<span>库存{{ stockFormat(row.partPercent, row.unitCodeList, item.quantity) }}</span>
</div>
</el-option>
</el-select>
</el-form-item>
<span class="medicine-info"> 诊断{{ config.diagnosisName }} </span>
<span class="total-amount">
总金额{{ row.totalPrice ? Number(row.totalPrice).toFixed(2) + ' 元' : '0.00 元' }}
</span>
</div>
<div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap">
<div class="form-group">
<el-form-item label="单次用量:" prop="doseQuantity" class="required-field" data-prop="doseQuantity">
<el-input-number
:min="0"
v-model="row.doseQuantity"
controls-position="right"
:controls="false"
style="width: 70px"
:ref="(el) => setInputRef('doseQuantity', el)"
@input="calculateTotalAmount"
@keyup.enter.prevent="handleEnter('doseQuantity')"
/>
</el-form-item>
<el-select v-model="row.minUnitCode" style="width: 70px; margin-right: 32px" placeholder=" ">
<template v-for="item in row.unitCodeList" :key="item.value">
<el-option v-if="item.type == config.unitMap['minUnit']" :value="item.value" :label="item.label" />
</template>
</el-select>
</div>
<div class="form-group">
<el-form-item label="给药途径:" prop="methodCode" class="required-field" data-prop="methodCode">
<el-select v-model="row.methodCode" placeholder="给药途径" clearable filterable style="width: 120px">
<el-option v-for="dict in config.methodCode" @click="() => (row.methodCode_dictText = dict.label)" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="用药频次:" prop="rateCode" class="required-field" data-prop="rateCode">
<el-select v-model="row.rateCode" placeholder="频次" style="width: 120px" filterable>
<el-option v-for="dict in config.rateCode" @click="() => (row.rateCode_dictText = dict.label)" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</div>
</div>
<div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 10px">
<div class="form-group">
<el-form-item label="用药天数:" prop="dispensePerDuration" class="required-field" data-prop="dispensePerDuration">
<el-input-number v-model="row.dispensePerDuration" style="width: 148px" :min="1" :max="30" controls-position="right" :controls="false" :ref="(el) => setInputRef('dispensePerDuration', el)" @input="calculateTotalAmount" @keyup.enter.prevent="handleEnter('dispensePerDuration')">
<template #suffix></template>
</el-input-number>
</el-form-item>
<el-form-item label="总量:" prop="quantity" class="required-field" data-prop="quantity" label-width="80">
<el-input-number v-model="row.quantity" style="width: 70px" controls-position="right" :controls="false" :ref="(el) => setInputRef('quantity', el)" @keyup.enter.prevent="handleEnter('quantity')" @input="calculateTotalAmount" />
</el-form-item>
<el-select v-model="row.unitCode" style="width: 70px" placeholder=" " @change="calculateTotalAmount">
<template v-for="item in row.unitCodeList" :key="item.value">
<el-option v-if="checkUnit(item)" :value="item.value" :label="item.label" @click="() => {
if (item.type == config.unitMap['minUnit']) {
row.unitPrice = row.minUnitPrice;
} else {
row.unitPrice = row.unitTempPrice;
}
row.unitCode_dictText = item.label;
}" />
</template>
</el-select>
</div>
<div class="form-actions">
<el-button type="primary" @click="handleSave">确定</el-button>
<el-button @click="handleCancel">取消</el-button>
</div>
</div>
</template>
<template v-else-if="row.adviceType == 2"> <template v-else-if="row.adviceType == 2">
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px"> <div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
<span style="font-size: 16px; font-weight: 600"> <span style="font-size: 16px; font-weight: 600">
@@ -537,7 +650,8 @@ onMounted(() => {
nextTick(() => { nextTick(() => {
registerFormRef(); registerFormRef();
}); });
if (props.row.therapyEnum == '2' && !props.row.rateCode) { // Bug #589: 出院带药不自动设置频次为ST由医生手动选择
if (props.row.therapyEnum == '2' && !props.row.rateCode && props.row.adviceType != 7) {
setRateCodeToST(); setRateCodeToST();
} }
}); });
@@ -545,7 +659,8 @@ onMounted(() => {
watch( watch(
() => props.row.therapyEnum, () => props.row.therapyEnum,
(newVal) => { (newVal) => {
if (newVal == '2') { // Bug #589: 出院带药不自动设置频次为ST由医生手动选择
if (newVal == '2' && props.row.adviceType != 7) {
setRateCodeToST(); setRateCodeToST();
} else if (newVal == '1') { } else if (newVal == '1') {
props.row.rateCode = ''; props.row.rateCode = '';
@@ -671,7 +786,12 @@ const calculateTotalPrice = () => props.handlers.calculateTotal('price', props.r
const calculateTotalAmount = () => { const calculateTotalAmount = () => {
nextTick(() => { nextTick(() => {
const row = props.row; const row = props.row;
const qty = new Decimal(row.doseQuantity || 0); // Bug #589: 出院带药自动计算总量 = 单次用量 × 用药天数频次留空时默认1次/天)
if (row.adviceType == 7 && row.doseQuantity && row.dispensePerDuration) {
const freq = row.rateCode ? 1 : 1; // 频次由医生手动选,总量仅依据单次用量×天数估算
row.quantity = new Decimal(row.doseQuantity || 0).mul(row.dispensePerDuration || 0).toNumber();
}
const qty = new Decimal(row.quantity || row.doseQuantity || 0);
// 根据首次用量单位类型决定使用哪个单价 // 根据首次用量单位类型决定使用哪个单价
const unitType = row.unitCodeList?.find((k) => k.value == row.doseUnitCode)?.type; const unitType = row.unitCodeList?.find((k) => k.value == row.doseUnitCode)?.type;
const price = unitType == 'unit' ? row.unitPrice : row.minUnitPrice; const price = unitType == 'unit' ? row.unitPrice : row.minUnitPrice;

View File

@@ -125,7 +125,7 @@
<el-radio-group <el-radio-group
v-model="scope.row.therapyEnum" v-model="scope.row.therapyEnum"
size="small" size="small"
v-if="getRowDisabled(scope.row)" v-if="getRowDisabled(scope.row) && !scope.row.dischargeFlag"
@change="(val) => handleTherapyChange(val, scope.row)" @change="(val) => handleTherapyChange(val, scope.row)"
> >
<el-radio-button label="1">长期</el-radio-button> <el-radio-button label="1">长期</el-radio-button>
@@ -133,9 +133,9 @@
</el-radio-group> </el-radio-group>
<span <span
v-else v-else
:style="scope.row.therapyEnum == '1' ? 'color: #a6745c' : 'color: #3787a5'" :style="scope.row.dischargeFlag ? 'color: #e6a23c' : (scope.row.therapyEnum == '1' ? 'color: #a6745c' : 'color: #3787a5')"
> >
{{ scope.row.therapyEnum === '1' ? '长期' : '临时' }} {{ scope.row.dischargeFlag ? '临时(出院带药)' : (scope.row.therapyEnum === '1' ? '长期' : '临时') }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
@@ -165,6 +165,13 @@
// 更新行的 adviceType数字和 categoryCode // 更新行的 adviceType数字和 categoryCode
filterPrescriptionList[scope.$index].adviceType = newAdviceType; filterPrescriptionList[scope.$index].adviceType = newAdviceType;
filterPrescriptionList[scope.$index].categoryCode = newCategoryCode; filterPrescriptionList[scope.$index].categoryCode = newCategoryCode;
// Bug #589: 出院带药强制为临时医嘱
if (newAdviceType == 7) {
filterPrescriptionList[scope.$index].therapyEnum = '2';
filterPrescriptionList[scope.$index].dischargeFlag = true;
} else {
filterPrescriptionList[scope.$index].dischargeFlag = false;
}
// 更新 adviceQueryParams备用 // 更新 adviceQueryParams备用
adviceQueryParams.value = { adviceQueryParams.value = {
adviceType: newAdviceType, adviceType: newAdviceType,
@@ -495,10 +502,11 @@ const adviceTypeList = computed(() => {
hasShownPharmacyConfigWarning.value = true; hasShownPharmacyConfigWarning.value = true;
} }
// 只返回不需要取药科室配置的类别(诊疗、手术) // 只返回不需要取药科室配置的类别(诊疗、手术、出院带药
return [ return [
{ label: '诊疗', value: 3, adviceType: 3, categoryCode: '' }, { label: '诊疗', value: 3, adviceType: 3, categoryCode: '' },
{ label: '手术', value: 6, adviceType: 6, categoryCode: '' }, { label: '手术', value: 6, adviceType: 6, categoryCode: '' },
{ label: '出院带药', value: 7, adviceType: 7, categoryCode: '' },
{ label: '全部', value: '', adviceType: '', categoryCode: '' }, { label: '全部', value: '', adviceType: '', categoryCode: '' },
]; ];
} }
@@ -526,6 +534,9 @@ const adviceTypeList = computed(() => {
typeList.push({ label: '诊疗', value: 3, adviceType: 3, categoryCode: '' }); typeList.push({ label: '诊疗', value: 3, adviceType: 3, categoryCode: '' });
typeList.push({ label: '手术', value: 6, adviceType: 6, categoryCode: '' }); typeList.push({ label: '手术', value: 6, adviceType: 6, categoryCode: '' });
// 始终添加"出院带药"选项(不需要取药科室配置)
typeList.push({ label: '出院带药', value: 7, adviceType: 7, categoryCode: '' });
// 添加全部选项 // 添加全部选项
typeList.push({ label: '全部', value: '', adviceType: '', categoryCode: '' }); typeList.push({ label: '全部', value: '', adviceType: '', categoryCode: '' });
@@ -656,6 +667,12 @@ function getListInfo(addNewRow) {
// 🔧 修复:同时保存 orgName当 orgId 在科室树中匹配不到时作为兜底显示 // 🔧 修复:同时保存 orgName当 orgId 在科室树中匹配不到时作为兜底显示
// 优先从科室树查找名称,其次用 positionName后端已保存的科室名最后用 contentJson 中的 orgName // 优先从科室树查找名称,其次用 positionName后端已保存的科室名最后用 contentJson 中的 orgName
orgName: findOrgName(item.positionId || parsedContent?.orgId || item.orgId) || item.positionName || parsedContent?.orgName || undefined, orgName: findOrgName(item.positionId || parsedContent?.orgId || item.orgId) || item.positionName || parsedContent?.orgName || undefined,
// Bug #589: 从contentJson检测出院带药标记恢复类型显示
// 后端存储时adviceType转为1药品通过prescriptionCategory=3标识出院带药
...(parsedContent?.prescriptionCategory == 3 ? {
adviceType: 7,
dischargeFlag: true,
} : {}),
}; };
}) })
.sort((a, b) => { .sort((a, b) => {
@@ -783,6 +800,9 @@ function getRowSelectValue(row) {
if (row.adviceType == 1 && row.categoryCode) { if (row.adviceType == 1 && row.categoryCode) {
return '1-' + row.categoryCode; return '1-' + row.categoryCode;
} }
if (row.adviceType == 7) {
return 7;
}
return row.adviceType; return row.adviceType;
} }
@@ -1002,13 +1022,21 @@ function selectAdviceBase(key, row) {
// 每次选择药品时,将当前行数据初始化为最初状态 // 每次选择药品时,将当前行数据初始化为最初状态
const currentUniqueKey = prescriptionList.value[rowIndex.value]?.uniqueKey || key; const currentUniqueKey = prescriptionList.value[rowIndex.value]?.uniqueKey || key;
const prevRow = prescriptionList.value[rowIndex.value] || {};
prescriptionList.value[rowIndex.value] = { prescriptionList.value[rowIndex.value] = {
uniqueKey: currentUniqueKey, uniqueKey: currentUniqueKey,
isEdit: true, isEdit: true,
statusEnum: 1, statusEnum: 1,
therapyEnum: prescriptionList.value[rowIndex.value]?.therapyEnum, therapyEnum: prevRow.therapyEnum,
// Bug #589: 出院带药需要保留类型和标志setValue中可能被API数据覆盖
adviceType: prevRow.adviceType || undefined,
dischargeFlag: prevRow.dischargeFlag || undefined,
}; };
setValue(row); setValue(row);
// Bug #589: 出院带药选择药品后恢复类型标志
if (prescriptionList.value[rowIndex.value]?.dischargeFlag) {
prescriptionList.value[rowIndex.value].adviceType = 7;
}
// 确保 uniqueKey 不被覆盖 // 确保 uniqueKey 不被覆盖
prescriptionList.value[rowIndex.value].uniqueKey = currentUniqueKey; prescriptionList.value[rowIndex.value].uniqueKey = currentUniqueKey;
// 先清空展开状态,然后在 nextTick 中设置,确保数据更新后再展开 // 先清空展开状态,然后在 nextTick 中设置,确保数据更新后再展开
@@ -1251,6 +1279,14 @@ function handleSave() {
item.encounterId = patientInfo.value.encounterId; item.encounterId = patientInfo.value.encounterId;
item.accountId = patientInfo.value.accountId; item.accountId = patientInfo.value.accountId;
item.dbOpType = '1'; item.dbOpType = '1';
// Bug #589: 出院带药保存时转为药品类型
if (item.adviceType == 7) {
item.adviceType = 1;
const parsed = item.contentJson ? JSON.parse(item.contentJson) : {};
parsed.adviceType = 1;
parsed.prescriptionCategory = 3; // 出院带药标记
item.contentJson = JSON.stringify(parsed);
}
}); });
// 此处签发处方和单行保存处方传参相同后台已经将传参存为JSON字符串此处直接转换为JSON即可 // 此处签发处方和单行保存处方传参相同后台已经将传参存为JSON字符串此处直接转换为JSON即可
loading.value = true; loading.value = true;
@@ -1387,8 +1423,9 @@ function handleSaveSign(row, index) {
if (!validateStartTime(row.startTime)) { if (!validateStartTime(row.startTime)) {
return; return;
} }
// Bug #589: 出院带药按药品逻辑处理绑设备检查
if (row.adviceType != 2) { if (row.adviceType != 2) {
let itemNo = row.adviceType == 1 ? row.methodCode : row.adviceDefinitionId; let itemNo = row.adviceType == 1 || row.adviceType == 7 ? row.methodCode : row.adviceDefinitionId;
if (!itemNo) { if (!itemNo) {
console.warn('绑定设备检查跳过itemNo为空adviceType=' + row.adviceType + ', adviceName=' + row.adviceName + ''); console.warn('绑定设备检查跳过itemNo为空adviceType=' + row.adviceType + ', adviceName=' + row.adviceName + '');
} else { } else {
@@ -1421,7 +1458,8 @@ function handleSaveSign(row, index) {
row.patientId = patientInfo.value.patientId; row.patientId = patientInfo.value.patientId;
row.encounterId = patientInfo.value.encounterId; row.encounterId = patientInfo.value.encounterId;
row.accountId = accountId.value; row.accountId = accountId.value;
if (row.adviceType == 1) { // Bug #589: 出院带药(adviceType=7)按药品(adviceType=1)逻辑保存
if (row.adviceType == 1 || row.adviceType == 7) {
row.minUnitQuantity = row.minUnitQuantity =
row.minUnitCode == row.unitCode ? row.quantity : row.quantity * row.partPercent; row.minUnitCode == row.unitCode ? row.quantity : row.quantity * row.partPercent;
row.quantity = row.therapyEnum === '1' ? row.doseQuantity || row.quantity : row.quantity; row.quantity = row.therapyEnum === '1' ? row.doseQuantity || row.quantity : row.quantity;
@@ -1429,8 +1467,14 @@ function handleSaveSign(row, index) {
} else { } else {
row.minUnitQuantity = row.quantity; row.minUnitQuantity = row.quantity;
} }
// Bug #589: 保存时将出院带药adviceType转为1药品兼容后端
const originalAdviceType = row.adviceType;
if (row.adviceType == 7) {
row.adviceType = 1;
}
row.conditionId = conditionId.value; row.conditionId = conditionId.value;
// 处理总量为小单位情况,需要把单价也保存成小单位的 // 处理总量为小单位情况,需要把单价也保存成小单位的
// Bug #589: 出院带药按药品逻辑处理单价
if (row.unitCodeList.find((item) => item.value == row.unitCode).type == 'unit') { if (row.unitCodeList.find((item) => item.value == row.unitCode).type == 'unit') {
if (row.adviceType != 3) { if (row.adviceType != 3) {
row.unitPrice = row.unitTempPrice; row.unitPrice = row.unitTempPrice;
@@ -1447,6 +1491,10 @@ function handleSaveSign(row, index) {
if (row.injectFlag == 1) { if (row.injectFlag == 1) {
row.sortNumber = row.sortNumber ? row.sortNumber : prescriptionList.value.length; row.sortNumber = row.sortNumber ? row.sortNumber : prescriptionList.value.length;
} }
// Bug #589: 出院带药标记到contentJson
if (originalAdviceType == 7) {
row.prescriptionCategory = 3;
}
row.contentJson = JSON.stringify(row); row.contentJson = JSON.stringify(row);
if (row.requestId) { if (row.requestId) {
row.dbOpType = '2'; row.dbOpType = '2';
@@ -1494,11 +1542,20 @@ function handleSaveBatch() {
.map((item) => { .map((item) => {
// 确保 therapyEnum 被正确传递,默认为长期医嘱('1') // 确保 therapyEnum 被正确传递,默认为长期医嘱('1')
const therapyEnum = item.therapyEnum || '1'; const therapyEnum = item.therapyEnum || '1';
return { const result = {
...item, ...item,
therapyEnum: therapyEnum, therapyEnum: therapyEnum,
dbOpType: item.requestId ? '2' : '1', dbOpType: item.requestId ? '2' : '1',
}; };
// Bug #589: 出院带药批量保存时转为药品类型
if (result.adviceType == 7) {
result.adviceType = 1;
const parsed = result.contentJson ? JSON.parse(result.contentJson) : {};
parsed.adviceType = 1;
parsed.prescriptionCategory = 3;
result.contentJson = JSON.stringify(parsed);
}
return result;
}); });
if (saveList.length == 0) { if (saveList.length == 0) {
proxy.$modal.msgWarning('当前没有可保存医嘱'); proxy.$modal.msgWarning('当前没有可保存医嘱');