Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -11,8 +11,8 @@
|
||||
:height="computedTableHeight"
|
||||
:row-config="{ keyField: rowKey || 'id', isHover: true }"
|
||||
:highlight-current-row="highlightCurrentRow"
|
||||
:show-overflow="true"
|
||||
:show-header-overflow="title"
|
||||
show-overflow="title"
|
||||
show-header-overflow="title"
|
||||
:auto-resize="true"
|
||||
:scroll-x="{ enabled: true, gt: 20 }"
|
||||
:scroll-y="{ enabled: true, gt: 50 }"
|
||||
|
||||
@@ -87,21 +87,21 @@
|
||||
title="单据号"
|
||||
align="center"
|
||||
min-width="90"
|
||||
show-overflow
|
||||
show-overflow="title"
|
||||
/>
|
||||
<vxe-column
|
||||
field="applicantName"
|
||||
title="申请人"
|
||||
align="center"
|
||||
min-width="65"
|
||||
show-overflow
|
||||
show-overflow="title"
|
||||
/>
|
||||
<vxe-column
|
||||
field="locationName"
|
||||
title="发药药房"
|
||||
align="center"
|
||||
min-width="75"
|
||||
show-overflow
|
||||
show-overflow="title"
|
||||
/>
|
||||
<vxe-column
|
||||
field="statusEnum_enumText"
|
||||
@@ -217,7 +217,7 @@
|
||||
field="manufacturerText"
|
||||
title="生产厂家"
|
||||
min-width="120"
|
||||
:show-overflow="true"
|
||||
show-overflow="title"
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ scope.row.manufacturerText || '-' }}
|
||||
|
||||
@@ -89,12 +89,15 @@ function refresh(adviceType: any, categoryCode: string, searchKey: string) {
|
||||
// 有搜索词时跨类型搜索,避免用户输入"级护理"但因当前adviceType为药品而搜不到诊疗类护理项目
|
||||
if (searchKey) {
|
||||
queryParams.value.adviceTypes = [1, 2, 3, 6];
|
||||
queryParams.value.dischargeFlag = undefined;
|
||||
} else if (adviceType == 7) {
|
||||
// Bug #589: 出院带药仅检索西药和中成药
|
||||
queryParams.value.adviceTypes = [1];
|
||||
queryParams.value.dischargeFlag = 1;
|
||||
} else {
|
||||
queryParams.value.adviceTypes =
|
||||
adviceType !== undefined && adviceType !== '' ? [parseInt(adviceType)] : [1, 2, 3, 6];
|
||||
queryParams.value.dischargeFlag = undefined;
|
||||
}
|
||||
queryParams.value.categoryCode = categoryCode || '';
|
||||
queryParams.value.searchKey = searchKey || '';
|
||||
@@ -120,8 +123,8 @@ function getList() {
|
||||
|
||||
// 药品/耗材需要有库存才显示,诊疗/手术直接显示
|
||||
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) {
|
||||
// Bug #589: 出院带药仅显示西药(categoryCode='2')和中成药(categoryCode='1'),后端已过滤注射类
|
||||
if (queryParams.value.dischargeFlag === 1) {
|
||||
if (item.adviceType == 1 && (item.categoryCode == '1' || item.categoryCode == '2')) {
|
||||
return handleQuantity(item) !== '0';
|
||||
}
|
||||
|
||||
@@ -111,33 +111,6 @@
|
||||
/>
|
||||
</template>
|
||||
</el-select>
|
||||
<span>=</span>
|
||||
<!-- 单次剂量 -->
|
||||
<el-form-item prop="dose" class="required-field" data-prop="dose" label-width="0">
|
||||
<el-input-number
|
||||
v-model="row.dose"
|
||||
controls-position="right"
|
||||
:controls="false"
|
||||
style="width: 70px; margin-left: 32px"
|
||||
:ref="(el) => setInputRef('dose', el)"
|
||||
@input="() => { convertDoseValues(); calculateTotalAmount(); }"
|
||||
@keyup.enter.prevent="handleEnter('dose')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- 全部单位 -->
|
||||
<el-select
|
||||
v-model="row.doseUnitCode"
|
||||
style="width: 70px"
|
||||
placeholder=" "
|
||||
@change="() => { convertValues(); calculateTotalAmount(); }"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in row.unitCodeList"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
:key="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<el-form-item
|
||||
@@ -409,6 +382,66 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 🔧 文字医嘱面板 (adviceType=8) -->
|
||||
<template v-else-if="row.adviceType == 8">
|
||||
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
|
||||
<span class="medicine-title">文字医嘱</span>
|
||||
<el-form-item label="开始时间:" prop="startTime" class="required-field" data-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 label="频次:" prop="rateCode">
|
||||
<el-select v-model="row.rateCode" placeholder="频次" style="width: 120px" filterable clearable>
|
||||
<el-option
|
||||
v-for="dict in config.rateCode"
|
||||
:key="dict.value"
|
||||
:label="dict.value + ' ' + dict.label"
|
||||
:value="dict.value"
|
||||
@click="() => (row.rateCode_dictText = dict.value + ' ' + dict.label)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="执行科室:" prop="orgId">
|
||||
<el-tree-select
|
||||
clearable
|
||||
v-model="row.orgId"
|
||||
style="width: 200px"
|
||||
:data="orgTreeData"
|
||||
:props="{ value: 'id', label: 'name', children: 'children' }"
|
||||
value-key="id"
|
||||
check-strictly
|
||||
default-expand-all
|
||||
:fallback-option="orgFallbackOption"
|
||||
@change="handleOrgChange"
|
||||
placeholder="请选择执行科室"
|
||||
/>
|
||||
</el-form-item>
|
||||
<span class="total-amount">-</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap">
|
||||
<el-form-item label="文字内容:" prop="adviceName" class="required-field" data-prop="adviceName" style="flex: 1; min-width: 400px">
|
||||
<el-input
|
||||
v-model="row.adviceName"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入文字医嘱内容(3~50字)"
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="form-actions" style="align-self: flex-end">
|
||||
<el-button type="primary" @click="handleSave">确定</el-button>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="row.adviceType == 2">
|
||||
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
@@ -650,6 +683,7 @@ onMounted(() => {
|
||||
registerFormRef();
|
||||
});
|
||||
// Bug #615: 临时医嘱频次默认改为 ONCE(临时一次),不再强制设为 ST
|
||||
// 文字医嘱(type=8)临时医嘱默认频次为 ST(立即)
|
||||
if (props.row.therapyEnum == '2' && !props.row.rateCode && props.row.adviceType != 7) {
|
||||
setDefaultRateCode();
|
||||
}
|
||||
@@ -659,6 +693,7 @@ watch(
|
||||
() => props.row.therapyEnum,
|
||||
(newVal) => {
|
||||
// Bug #615: 临时医嘱频次仅在字段为空时给默认值,允许医生自主修改
|
||||
// 文字医嘱(type=8)临时医嘱默认频次为 ST(立即)
|
||||
if (newVal == '2' && !props.row.rateCode && props.row.adviceType != 7) {
|
||||
setDefaultRateCode();
|
||||
} else if (newVal == '1') {
|
||||
@@ -668,8 +703,30 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
// 文字医嘱(type=8):选择类型后强制设置频次为 ST(立即),覆盖之前的默认值
|
||||
watch(
|
||||
() => props.row.adviceType,
|
||||
(newVal) => {
|
||||
if (newVal == 8 && props.row.therapyEnum == '2') {
|
||||
setDefaultRateCode();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const setDefaultRateCode = () => {
|
||||
if (Array.isArray(props.config.rateCode)) {
|
||||
// 文字医嘱(type=8):默认频次为 ST(立即)
|
||||
if (props.row.adviceType == 8) {
|
||||
const stOption = props.config.rateCode.find((item) => item.value === 'ST');
|
||||
if (stOption) {
|
||||
props.row.rateCode = 'ST';
|
||||
props.row.rateCode_dictText = 'ST ' + stOption.label;
|
||||
} else {
|
||||
props.row.rateCode = 'ST';
|
||||
props.row.rateCode_dictText = 'ST 立即';
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 临时医嘱默认频次:优先选 ONCE(临时一次),其次 ST(立即)
|
||||
const onceOption = props.config.rateCode.find((item) => item.value === 'ONCE');
|
||||
if (onceOption) {
|
||||
@@ -728,6 +785,15 @@ const handleSave = () => {
|
||||
console.error('Form ref not found');
|
||||
return;
|
||||
}
|
||||
// 出院带药用药天数校验(1-7天)
|
||||
if (props.row.adviceType == 7) {
|
||||
if (!props.row.dispensePerDuration || props.row.dispensePerDuration < 1 || props.row.dispensePerDuration > 7) {
|
||||
if (proxy?.$modal?.msgWarning) {
|
||||
proxy.$modal.msgWarning('出院带药用药天数需在1-7天内');
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
formRef.value.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
emit('save', props.row, props.index);
|
||||
@@ -807,9 +873,8 @@ const calculateTotalAmount = () => {
|
||||
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 price = unitType == 'unit' ? row.unitPrice : row.minUnitPrice;
|
||||
// 统一使用小单位单价计算
|
||||
const price = row.minUnitPrice;
|
||||
const roundedPrice = new Decimal(price || 0).toDecimalPlaces(2, Decimal.ROUND_HALF_UP);
|
||||
row.totalPrice = qty.mul(roundedPrice).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toString();
|
||||
});
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
height="100%"
|
||||
ref="prescriptionRef"
|
||||
:data="filterPrescriptionList"
|
||||
:row-config="{ keyField: 'uniqueKey' }" :expand-config="{ trigger: 'row', expandRowKeys: expandOrder }"
|
||||
:row-config="{ keyField: 'uniqueKey' }" :expand-config="{ expandRowKeys: expandOrder }"
|
||||
border
|
||||
@cell-click="clickRow"
|
||||
@cell-dblclick="clickRowDb"
|
||||
@@ -121,22 +121,24 @@
|
||||
<vxe-column type="checkbox" align="center" width="60" />
|
||||
<vxe-column title="组" align="center" width="60" field="groupIcon" />
|
||||
|
||||
<vxe-column title="类型" align="center" field="" width="120">
|
||||
<vxe-column title="类型" align="center" field="" width="140">
|
||||
<template #default="scope">
|
||||
<el-radio-group
|
||||
v-model="scope.row.therapyEnum"
|
||||
size="small"
|
||||
v-if="getRowDisabled(scope.row) && !scope.row.dischargeFlag"
|
||||
@change="(val) => handleTherapyChange(val, scope.row)"
|
||||
v-if="getRowDisabled(scope.row)"
|
||||
:disabled="scope.row.dischargeFlag"
|
||||
@click.stop
|
||||
style="white-space: nowrap"
|
||||
>
|
||||
<el-radio-button>长期</el-radio-button>
|
||||
<el-radio-button value="1">长期</el-radio-button>
|
||||
<el-radio-button value="2">临时</el-radio-button>
|
||||
</el-radio-group>
|
||||
<span
|
||||
v-else
|
||||
:style="scope.row.dischargeFlag ? 'color: #F59E0B' : (scope.row.therapyEnum == '1' ? 'color: #a6745c' : 'color: #3787a5')"
|
||||
:style="scope.row.therapyEnum == '1' ? 'color: #a6745c' : 'color: #3787a5'"
|
||||
>
|
||||
{{ scope.row.dischargeFlag ? '临时(出院带药)' : (scope.row.therapyEnum === '1' ? '长期' : '临时') }}
|
||||
{{ scope.row.therapyEnum === '1' ? '长期' : '临时' }}
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
@@ -145,9 +147,19 @@
|
||||
{{ scope.row.createdStaffName || '-' }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="开始时间" align="center" field="startTime" width="170">
|
||||
<vxe-column title="开始时间" align="center" field="startTime" width="200">
|
||||
<template #default="scope">
|
||||
<span v-if="!scope.row.isEdit">
|
||||
<el-date-picker
|
||||
v-if="scope.row.isEdit"
|
||||
v-model="scope.row.startTime"
|
||||
type="datetime"
|
||||
placeholder="选择开始时间"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<span v-else>
|
||||
{{ scope.row.startTime || '-' }}
|
||||
</span>
|
||||
</template>
|
||||
@@ -162,7 +174,6 @@
|
||||
:disabled="!isCategoryLoaded"
|
||||
@change="
|
||||
(value) => {
|
||||
expandOrder = [];
|
||||
filterPrescriptionList[scope.rowIndex].adviceName = undefined;
|
||||
// 根据选中的医嘱类型,设置对应的 categoryCode
|
||||
const selectedItem = adviceTypeList.find(item => item.value === value);
|
||||
@@ -182,13 +193,17 @@
|
||||
adviceQueryParams.value = {
|
||||
adviceType: newAdviceType,
|
||||
categoryCode: newCategoryCode,
|
||||
searchKey: adviceQueryParams.value.searchKey || '',
|
||||
searchKey: adviceQueryParams.value?.searchKey || '',
|
||||
};
|
||||
// 直接调用子组件 refresh 方法,立即刷新列表(用 scope.rowIndex 找到当前行的子组件)
|
||||
const tableRef = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[scope.rowIndex] : adviceTableRef.value;
|
||||
if (tableRef && tableRef.refresh) {
|
||||
tableRef.refresh(newAdviceType, newCategoryCode, '');
|
||||
}
|
||||
// 文字医嘱没有药品选择步骤,选类型后直接展开编辑行
|
||||
if (newAdviceType == 8) {
|
||||
expandTextRow(scope.rowIndex);
|
||||
}
|
||||
}
|
||||
"
|
||||
clearable
|
||||
@@ -341,7 +356,7 @@
|
||||
</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="备注" align="center" field="remark" width="150" show-overflow>
|
||||
<vxe-column title="备注" align="center" field="remark" width="150" show-overflow="title">
|
||||
<template #default="scope">
|
||||
<span v-if="!scope.row.isEdit">
|
||||
{{ scope.row.remark || '-' }}
|
||||
@@ -468,6 +483,8 @@ const encounterDiagnosisId = ref('');
|
||||
const diagnosisName = ref('');
|
||||
const diagnosisInfo = ref({});
|
||||
const loading = ref(false);
|
||||
// Bug #587: 标记弹窗刚被关闭的行uniqueKey,防止关闭弹窗时误触发行展开
|
||||
const popoverJustClosedByKey = ref(null);
|
||||
|
||||
// 停嘱弹窗
|
||||
const stopDialogVisible = ref(false);
|
||||
@@ -486,6 +503,11 @@ const rowRules = ref({
|
||||
rateCode: [{ required: true, message: '请选择频次', trigger: 'change' }],
|
||||
methodCode: [{ required: true, message: '请选择给药途径', trigger: 'change' }],
|
||||
orgId: [{ required: true, message: '请选择执行科室', trigger: 'change' }],
|
||||
adviceName: [
|
||||
{ required: true, message: '请输入文字医嘱内容', trigger: 'blur' },
|
||||
{ min: 3, max: 50, message: '文字医嘱内容长度为3~50个字符', trigger: 'blur' },
|
||||
],
|
||||
startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
|
||||
});
|
||||
const unitMap = ref({
|
||||
dose: 'dose',
|
||||
@@ -562,6 +584,7 @@ const adviceTypeList = computed(() => {
|
||||
{ label: '诊疗', value: 3, adviceType: 3, categoryCode: '' },
|
||||
{ label: '手术', value: 6, adviceType: 6, categoryCode: '' },
|
||||
{ label: '出院带药', value: 7, adviceType: 7, categoryCode: '' },
|
||||
{ label: '文字', value: 8, adviceType: 8, categoryCode: '' },
|
||||
{ label: '全部', value: '', adviceType: '', categoryCode: '' },
|
||||
];
|
||||
}
|
||||
@@ -592,6 +615,9 @@ const adviceTypeList = computed(() => {
|
||||
// 始终添加"出院带药"选项(不需要取药科室配置)
|
||||
typeList.push({ label: '出院带药', value: 7, adviceType: 7, categoryCode: '' });
|
||||
|
||||
// 始终添加"文字"选项(不需要取药科室配置)
|
||||
typeList.push({ label: '文字', value: 8, adviceType: 8, categoryCode: '' });
|
||||
|
||||
// 添加全部选项
|
||||
typeList.push({ label: '全部', value: '', adviceType: '', categoryCode: '' });
|
||||
|
||||
@@ -632,8 +658,7 @@ watch(
|
||||
nextTick(() => {
|
||||
const index = prescriptionList.value.findIndex((row) => row.uniqueKey === newValue[0]);
|
||||
const items = proxy.$refs['formRef' + index]?.$el?.querySelectorAll('[data-prop]');
|
||||
requiredProps.value = Array.from(items).map((item) => item.dataset.prop);
|
||||
console.log(requiredProps.value, 'requiredProps.value');
|
||||
requiredProps.value = items ? Array.from(items).map((item) => item.dataset.prop) : {};
|
||||
});
|
||||
} else {
|
||||
requiredProps.value = {};
|
||||
@@ -677,7 +702,7 @@ function getListInfo(addNewRow) {
|
||||
loadingInstance.close();
|
||||
}, 180);
|
||||
isAdding.value = false;
|
||||
expandOrder.value = [];
|
||||
collapseAllExpanded();
|
||||
// 🔧 修复:先加载科室树,再处理处方数据
|
||||
// 确保 resolveOrgId 在 organization 树已加载的情况下执行
|
||||
// 避免因树为空导致 orgId 无法匹配,从而显示数字 ID 而非中文名称
|
||||
@@ -886,7 +911,7 @@ function handleAddPrescription() {
|
||||
showPopover: false,
|
||||
isEdit: true,
|
||||
statusEnum: 1,
|
||||
therapyEnum: '1', // 默认为长期医嘱
|
||||
therapyEnum: '2', // 默认为临时医嘱
|
||||
startTime: defaultStartTime,
|
||||
});
|
||||
getGroupMarkers();
|
||||
@@ -946,6 +971,12 @@ function clickRowDb({ row, column, event }) {
|
||||
if (event && event.target.closest('.el-checkbox')) {
|
||||
return; // 如果是复选框点击,不执行行点击逻辑
|
||||
}
|
||||
// Bug #587: 关闭弹窗的同一点击不应触发行展开,标记仅生效一次
|
||||
if (popoverJustClosedByKey.value === row.uniqueKey) {
|
||||
popoverJustClosedByKey.value = null;
|
||||
return;
|
||||
}
|
||||
popoverJustClosedByKey.value = null;
|
||||
if (expandOrder.value.length > 0) {
|
||||
proxy.$modal.msgWarning('有医嘱处于编辑状态,请先保存,再编辑此条医嘱');
|
||||
return;
|
||||
@@ -1027,11 +1058,29 @@ function handleDiagnosisChange(item) {
|
||||
encounterDiagnosisId.value = item.encounterDiagnosisId;
|
||||
}
|
||||
|
||||
|
||||
// 文字医嘱选类型后展开编辑行(模板中无法直接用 nextTick)
|
||||
function expandTextRow(rowIndex) {
|
||||
const row = filterPrescriptionList.value[rowIndex];
|
||||
if (!row) return;
|
||||
expandOrder.value = [row.uniqueKey];
|
||||
nextTick(() => {
|
||||
if (prescriptionRef.value?.setRowExpand) {
|
||||
prescriptionRef.value.setRowExpand([row], true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleFocus(row, index) {
|
||||
rowIndex.value = index;
|
||||
// 文字医嘱(type=8)不弹药品搜索框,直接展开填写面板
|
||||
const adviceType = row.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType;
|
||||
if (adviceType == 8) {
|
||||
row.showPopover = false;
|
||||
return;
|
||||
}
|
||||
row.showPopover = true;
|
||||
// Bug #555: handleFocus 初始化查询参数并加载初始数据(searchKey 为空,无竞态风险)
|
||||
const adviceType = row.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType;
|
||||
let categoryCode = '';
|
||||
if (row.adviceType !== undefined) {
|
||||
const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||
@@ -1048,14 +1097,21 @@ function handleFocus(row, index) {
|
||||
|
||||
function handleBlur(row) {
|
||||
row.showPopover = false;
|
||||
// Bug #587: 标记弹窗刚关闭,防止点击空白处时触发行展开
|
||||
popoverJustClosedByKey.value = row.uniqueKey;
|
||||
}
|
||||
|
||||
function handleChange(value) {
|
||||
adviceQueryParams.value.searchKey = value;
|
||||
// @focus 已先于 @input 执行,rowIndex 必定有效
|
||||
// 文字医嘱(type=8)不触发药品搜索
|
||||
const currentIndex = rowIndex.value;
|
||||
if (currentIndex < 0) return;
|
||||
const row = filterPrescriptionList.value[currentIndex];
|
||||
const adviceType = row?.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType;
|
||||
if (adviceType == 8) {
|
||||
return;
|
||||
}
|
||||
adviceQueryParams.value.searchKey = value;
|
||||
// @focus 已先于 @input 执行,rowIndex 必定有效
|
||||
// popover 被 blur 关闭后,用户继续输入时自行打开
|
||||
if (!row.showPopover) {
|
||||
row.showPopover = true;
|
||||
@@ -1077,7 +1133,6 @@ function handleChange(value) {
|
||||
* 选择药品回调
|
||||
*/
|
||||
function selectAdviceBase(key, row) {
|
||||
console.log('row===========>', JSON.stringify(row));
|
||||
|
||||
// 每次选择药品时,将当前行数据初始化为最初状态
|
||||
const currentUniqueKey = prescriptionList.value[rowIndex.value]?.uniqueKey || key;
|
||||
@@ -1086,12 +1141,18 @@ function selectAdviceBase(key, row) {
|
||||
uniqueKey: currentUniqueKey,
|
||||
isEdit: true,
|
||||
statusEnum: 1,
|
||||
showPopover: false, // Bug #587: 选择药品后关闭弹窗
|
||||
therapyEnum: prevRow.therapyEnum,
|
||||
startTime: prevRow.startTime || defaultStartTimeFn(), // Bug #587: 保留开始时间
|
||||
// Bug #589: 出院带药需要保留类型和标志,setValue中可能被API数据覆盖
|
||||
adviceType: prevRow.adviceType || undefined,
|
||||
dischargeFlag: prevRow.dischargeFlag || undefined,
|
||||
};
|
||||
setValue(row);
|
||||
try {
|
||||
setValue(row);
|
||||
} catch (e) {
|
||||
console.warn('setValue error:', e);
|
||||
}
|
||||
// Bug #589: 出院带药选择药品后恢复类型标志
|
||||
if (prescriptionList.value[rowIndex.value]?.dischargeFlag) {
|
||||
prescriptionList.value[rowIndex.value].adviceType = 7;
|
||||
@@ -1132,7 +1193,13 @@ function selectAdviceBase(key, row) {
|
||||
expandOrderAndFocus(currentUniqueKey, row);
|
||||
});
|
||||
} else {
|
||||
// 不是皮试药品,直接展开订单
|
||||
// 选完药品后展开编辑区域,供医生编辑剂量等字段
|
||||
expandOrder.value = [currentUniqueKey];
|
||||
// 直接调 vxe-table 实例方法展开(expandRowKeys 仅在初始化时生效)
|
||||
const rowObj = filterPrescriptionList.value.find(item => item.uniqueKey === currentUniqueKey);
|
||||
if (rowObj && prescriptionRef.value?.setRowExpand) {
|
||||
prescriptionRef.value.setRowExpand([rowObj], true);
|
||||
}
|
||||
expandOrderAndFocus(currentUniqueKey, row);
|
||||
}
|
||||
}
|
||||
@@ -1141,25 +1208,18 @@ function selectAdviceBase(key, row) {
|
||||
* 展开订单并聚焦输入框
|
||||
*/
|
||||
function expandOrderAndFocus(key, row) {
|
||||
expandOrder.value = [];
|
||||
// 只聚焦,expandOrder 已在 selectAdviceBase 里设好
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
expandOrder.value = [key];
|
||||
const tableData = filterPrescriptionList.value;
|
||||
const targetRow = tableData.find((item) => item.uniqueKey === key);
|
||||
if (targetRow && prescriptionRef.value) {
|
||||
prescriptionRef.value.toggleRowExpansion(targetRow, true);
|
||||
}
|
||||
if (row.adviceType == 1) {
|
||||
if (row.injectFlag == 1) {
|
||||
inputRefs.value['executeNum']?.focus();
|
||||
} else {
|
||||
inputRefs.value['doseQuantity']?.focus();
|
||||
}
|
||||
// 聚焦第一个输入框
|
||||
if (row.adviceType == 1) {
|
||||
if (row.injectFlag == 1) {
|
||||
inputRefs.value['executeNum']?.focus();
|
||||
} else {
|
||||
inputRefs.value['quantity']?.focus();
|
||||
inputRefs.value['doseQuantity']?.focus();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
inputRefs.value['quantity']?.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1260,7 +1320,7 @@ function handleDelete() {
|
||||
});
|
||||
}
|
||||
}
|
||||
expandOrder.value = [];
|
||||
collapseAllExpanded();
|
||||
isAdding.value = false;
|
||||
adviceQueryParams.value.adviceType = undefined;
|
||||
if (sum === selectRows.length) {
|
||||
@@ -1322,7 +1382,7 @@ function handleSave() {
|
||||
if (filterPrescriptionList.value[0].isEdit && !filterPrescriptionList.value[0].adviceType) {
|
||||
prescriptionList.value.shift();
|
||||
isAdding.value = false;
|
||||
expandOrder.value = [];
|
||||
collapseAllExpanded();
|
||||
}
|
||||
|
||||
const selectedRows = prescriptionRef.value ? prescriptionRef.value.getCheckboxRecords() : [];
|
||||
@@ -1509,13 +1569,26 @@ function handleOrderBindInfo(bindIdInfo) {
|
||||
});
|
||||
}
|
||||
|
||||
function collapseAllExpanded() {
|
||||
expandOrder.value = [];
|
||||
// VXE Table v4: expandRowKeys 只在初始化生效,必须调实例方法收起行
|
||||
if (prescriptionRef.value?.clearRowExpand) {
|
||||
prescriptionRef.value.clearRowExpand();
|
||||
} else if (prescriptionRef.value?.setRowExpand) {
|
||||
const allRows = prescriptionRef.value.getData?.() || [];
|
||||
if (allRows.length > 0) {
|
||||
prescriptionRef.value.setRowExpand(allRows, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancelEdit(row, index) {
|
||||
if (isAdding.value && index === 0 && !row.requestId) {
|
||||
isAdding.value = false;
|
||||
} else {
|
||||
row.isEdit = false;
|
||||
}
|
||||
expandOrder.value = [];
|
||||
collapseAllExpanded();
|
||||
}
|
||||
|
||||
function handleSaveSign(row, index) {
|
||||
@@ -1523,8 +1596,16 @@ function handleSaveSign(row, index) {
|
||||
if (!validateStartTime(row.startTime)) {
|
||||
return;
|
||||
}
|
||||
// Bug #589: 出院带药用药天数校验(1-7天)
|
||||
if (row.adviceType == 7) {
|
||||
if (!row.dispensePerDuration || row.dispensePerDuration < 1 || row.dispensePerDuration > 7) {
|
||||
proxy.$modal.msgWarning('出院带药用药天数需在1-7天内');
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Bug #589: 出院带药按药品逻辑处理绑设备检查
|
||||
if (row.adviceType != 2) {
|
||||
// 文字医嘱(type=8)跳过绑设备检查和计费逻辑
|
||||
if (row.adviceType != 2 && row.adviceType != 8) {
|
||||
let itemNo = row.adviceType == 1 || row.adviceType == 7 ? row.methodCode : row.adviceDefinitionId;
|
||||
if (!itemNo) {
|
||||
console.warn('绑定设备检查跳过:itemNo为空(adviceType=' + row.adviceType + ', adviceName=' + row.adviceName + ')');
|
||||
@@ -1551,13 +1632,43 @@ function handleSaveSign(row, index) {
|
||||
// 更新UI状态
|
||||
row.isEdit = false;
|
||||
isAdding.value = false;
|
||||
expandOrder.value = [];
|
||||
collapseAllExpanded();
|
||||
|
||||
// 执行保存
|
||||
row.contentJson = undefined;
|
||||
row.patientId = patientInfo.value.patientId;
|
||||
row.encounterId = patientInfo.value.encounterId;
|
||||
row.accountId = accountId.value;
|
||||
|
||||
// 🔧 文字医嘱(type=8):跳过计费逻辑,总金额为0
|
||||
if (row.adviceType == 8) {
|
||||
row.totalPrice = 0;
|
||||
row.unitPrice = 0;
|
||||
row.quantity = 1;
|
||||
row.minUnitQuantity = 1;
|
||||
row.unitCode = row.unitCode || '次';
|
||||
row.categoryEnum = 8;
|
||||
row.conditionId = conditionId.value;
|
||||
row.encounterDiagnosisId = encounterDiagnosisId.value;
|
||||
row.diagnosisName = diagnosisName.value;
|
||||
row.therapyEnum = row.therapyEnum || '1';
|
||||
row.contentJson = JSON.stringify(row);
|
||||
row.dbOpType = row.requestId ? '2' : '1';
|
||||
savePrescription({ regAdviceSaveList: [row] }).then((res) => {
|
||||
if (res.code === 200) {
|
||||
proxy.$modal.msgSuccess('保存成功');
|
||||
row.isEdit = false;
|
||||
isAdding.value = false;
|
||||
collapseAllExpanded();
|
||||
if (!row.requestId && isAdding.value && prescriptionList.value[0].adviceName) {
|
||||
handleAddPrescription();
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Bug #589: 出院带药(adviceType=7)按药品(adviceType=1)逻辑保存
|
||||
if (row.adviceType == 1 || row.adviceType == 7) {
|
||||
row.minUnitQuantity =
|
||||
@@ -1633,7 +1744,7 @@ function handleSaveBatch() {
|
||||
if (filterPrescriptionList.value[0].isEdit && !filterPrescriptionList.value[0].adviceType) {
|
||||
prescriptionList.value.shift();
|
||||
isAdding.value = false;
|
||||
expandOrder.value = [];
|
||||
collapseAllExpanded();
|
||||
}
|
||||
// 过滤出未签发的保存
|
||||
let saveList = filterPrescriptionList.value
|
||||
@@ -1661,6 +1772,15 @@ function handleSaveBatch() {
|
||||
parsed.prescriptionCategory = 3;
|
||||
result.contentJson = JSON.stringify(parsed);
|
||||
}
|
||||
// 🔧 文字医嘱(type=8):跳过计费,总金额为0
|
||||
if (result.adviceType == 8) {
|
||||
result.totalPrice = 0;
|
||||
result.unitPrice = 0;
|
||||
result.quantity = result.quantity || 1;
|
||||
result.minUnitQuantity = result.minUnitQuantity || 1;
|
||||
result.unitCode = result.unitCode || '次';
|
||||
result.categoryEnum = 8;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
if (saveList.length == 0) {
|
||||
@@ -1721,12 +1841,13 @@ function setValue(row) {
|
||||
if (row.adviceType != 3) {
|
||||
// 🔧 Bug #144 修复:检查 inventoryList 是否存在,避免 undefined 错误
|
||||
if (!row.inventoryList || row.inventoryList.length == 0) {
|
||||
expandOrder.value = [];
|
||||
collapseAllExpanded();
|
||||
proxy.$modal.msgWarning(row.adviceName + '无库存');
|
||||
return;
|
||||
}
|
||||
const priceList = row.priceList || [];
|
||||
mergedStockList = row.inventoryList.map((item, index) => {
|
||||
return { ...item, ...row.priceList[index] };
|
||||
return { ...item, ...priceList[index] };
|
||||
});
|
||||
|
||||
// 获取默认批次号的库存,如果没有让医生重新选
|
||||
@@ -1978,7 +2099,7 @@ function escKeyListener(e) {
|
||||
index = prescriptionList.value.findIndex((item) => item.uniqueKey == expandOrder.value[0]);
|
||||
}
|
||||
if (index == 0) {
|
||||
expandOrder.value = [];
|
||||
collapseAllExpanded();
|
||||
}
|
||||
prescriptionList.value.shift();
|
||||
isAdding.value = false;
|
||||
@@ -2121,6 +2242,8 @@ function handleStopAdvice() {
|
||||
return {
|
||||
requestId: item.requestId,
|
||||
adviceType: item.adviceType,
|
||||
startTime: item.startTime,
|
||||
adviceName: item.adviceName,
|
||||
};
|
||||
});
|
||||
// 默认当前时间
|
||||
@@ -2144,6 +2267,29 @@ function confirmStopAdvice() {
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 校验:停嘱时间不能早于患者入院时间
|
||||
if (patientInfo.value?.inHospitalTime) {
|
||||
const stopDate = new Date(stopForm.stopTime);
|
||||
const inHospitalDate = new Date(patientInfo.value.inHospitalTime);
|
||||
if (stopDate < inHospitalDate) {
|
||||
const pad = (n) => String(n).padStart(2, '0');
|
||||
const d = inHospitalDate;
|
||||
const timeStr = d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
|
||||
ElMessage({ type: 'error', message: '停嘱时间不能早于患者入院时间(' + timeStr + ')' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 校验:停嘱时间不能早于医嘱开始时间
|
||||
const stopDate = new Date(stopForm.stopTime);
|
||||
for (const row of pendingStopRows.value) {
|
||||
if (row.startTime) {
|
||||
const startDate = new Date(row.startTime);
|
||||
if (stopDate < startDate) {
|
||||
ElMessage({ type: 'error', message: '停嘱时间不能早于医嘱【' + (row.adviceName || '') + '】的开始时间(' + row.startTime + ')' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
const requestIdList = pendingStopRows.value.map((item) => ({
|
||||
...item,
|
||||
stopTime: stopForm.stopTime,
|
||||
|
||||
Reference in New Issue
Block a user