- 将所有组件中的 append-to-body 属性替换为 teleported - 为 el-radio 和 el-checkbox 组件添加正确的 value 属性 - 移除已弃用的 highlight-current-row 属性 - 为 vxe-table 添加 row-config 配置替代旧的高亮设置 - 更新 el-checkbox 的 true-value 属性值 - 修改 el-button 类型从 text 到 link 以匹配设计系统
1041 lines
31 KiB
Vue
Executable File
1041 lines
31 KiB
Vue
Executable File
<template>
|
||
<el-dialog
|
||
v-model="dialogVisible"
|
||
:title="dialogTitle"
|
||
width="1300px"
|
||
@close="handleDialogClose"
|
||
>
|
||
<el-form
|
||
ref="formRef"
|
||
:model="formData"
|
||
:rules="formRules"
|
||
label-width="80px"
|
||
>
|
||
<div class="dialog-top-row">
|
||
<el-form-item
|
||
label="名称"
|
||
prop="name"
|
||
>
|
||
<el-input
|
||
v-model="formData.name"
|
||
placeholder="请输入名称"
|
||
style="width: 220px"
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item
|
||
v-if="showRangeSelector && !isEdit"
|
||
label="使用范围"
|
||
>
|
||
<el-select
|
||
v-model="rangeSelectValue"
|
||
placeholder="个人/科室/全院"
|
||
style="width: 220px"
|
||
@change="handleRangeChange"
|
||
>
|
||
<el-option
|
||
label="个人"
|
||
value="personal"
|
||
/>
|
||
<el-option
|
||
label="科室"
|
||
value="department"
|
||
/>
|
||
<el-option
|
||
label="全院"
|
||
value="hospital"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item
|
||
v-if="currentTab === 'personal' && !isDoctorStation && !showRangeSelector"
|
||
label="参与者"
|
||
prop="practitionerId"
|
||
>
|
||
<el-select
|
||
v-model="formData.practitionerId"
|
||
placeholder="请选择参与者"
|
||
clearable
|
||
style="width: 220px"
|
||
>
|
||
<el-option
|
||
v-for="item in participantListOptions"
|
||
:key="item.practitionerId"
|
||
:label="item.practitionerName"
|
||
:value="item.practitionerId"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item
|
||
v-if="currentTab === 'department'"
|
||
label="科室"
|
||
prop="organizationId"
|
||
>
|
||
<el-tree-select
|
||
v-model="formData.organizationId"
|
||
clearable
|
||
:data="organization"
|
||
:props="{ value: 'id', label: 'name', children: 'children' }"
|
||
value-key="id"
|
||
check-strictly
|
||
default-expand-all
|
||
placeholder="请选择科室"
|
||
style="width: 220px"
|
||
:render-after-expand="false"
|
||
@change="handleOrgChange"
|
||
/>
|
||
</el-form-item>
|
||
</div>
|
||
</el-form>
|
||
|
||
<div style="margin-bottom: 10px">
|
||
<el-button
|
||
type="primary"
|
||
@click="handleAddRow"
|
||
>
|
||
新增
|
||
</el-button>
|
||
<el-button @click="handleCombineGroup">
|
||
组合
|
||
</el-button>
|
||
<el-button @click="handleSplitGroup">
|
||
拆组
|
||
</el-button>
|
||
</div>
|
||
|
||
<vxe-table
|
||
ref="prescriptionRef"
|
||
max-height="650"
|
||
:data="prescriptionList"
|
||
:row-config="{ keyField: 'uniqueKey', expandRowKeys: expandOrder }"
|
||
border
|
||
@cell-click="clickRow"
|
||
@checkbox-change="handleSelectionChange"
|
||
>
|
||
<vxe-column
|
||
type="checkbox"
|
||
width="55"
|
||
:selectable="isRowSelectable"
|
||
/>
|
||
<vxe-column
|
||
title="组"
|
||
align="center"
|
||
width="60"
|
||
>
|
||
<template #default="scope">
|
||
<span v-if="scope.row.groupId">{{ getGroupIcon(scope.row) }}</span>
|
||
</template>
|
||
</vxe-column>
|
||
<vxe-column
|
||
title="类型"
|
||
align="center"
|
||
width="120"
|
||
>
|
||
<template #default="scope">
|
||
<template v-if="!scope.row.groupPackageId">
|
||
<el-radio-group
|
||
v-model="scope.row.therapyEnum"
|
||
size="small"
|
||
>
|
||
<el-radio-button value="1">
|
||
长期
|
||
</el-radio-button>
|
||
<el-radio-button value="2">
|
||
临时
|
||
</el-radio-button>
|
||
</el-radio-group>
|
||
</template>
|
||
<span v-else>
|
||
{{
|
||
scope.row.therapyEnum == '1' ? '长期' : scope.row.therapyEnum == '2' ? '临时' : '-'
|
||
}}
|
||
</span>
|
||
</template>
|
||
</vxe-column>
|
||
<vxe-column
|
||
title="医嘱"
|
||
align="center"
|
||
field="productName"
|
||
width="300"
|
||
>
|
||
<template #default="scope">
|
||
<template v-if="getRowDisabled(scope.row)">
|
||
<el-popover
|
||
:popper-style="{ padding: '0' }"
|
||
placement="bottom-start"
|
||
:visible="scope.row.showPopover"
|
||
:width="1200"
|
||
>
|
||
<adviceBaseList
|
||
ref="adviceTableRef"
|
||
:popover-visible="scope.row.showPopover"
|
||
:advice-query-params="adviceQueryParams"
|
||
@select-advice-base="(row) => selectAdviceBase(scope.row.uniqueKey, row)"
|
||
/>
|
||
<template #reference>
|
||
<el-input
|
||
:ref="'adviceRef' + scope.rowIndex"
|
||
v-model="scope.row.adviceName"
|
||
style="width: 100%"
|
||
placeholder="请选择项目"
|
||
@input="(value) => handleInput(value, scope.row, scope.rowIndex)"
|
||
@click="handleFocus(scope.row, scope.rowIndex)"
|
||
@keyup.enter.stop="handleFocus(scope.row, scope.rowIndex)"
|
||
@keydown="
|
||
(e) => {
|
||
if (!scope.row.showPopover) return;
|
||
if (['ArrowUp', 'ArrowDown', 'Enter'].includes(e.key)) {
|
||
e.preventDefault();
|
||
adviceTableRef.handleKeyDown(e);
|
||
}
|
||
}
|
||
"
|
||
@blur="handleBlur(scope.row)"
|
||
/>
|
||
</template>
|
||
</el-popover>
|
||
</template>
|
||
<span v-else>{{ scope.row.adviceName }}</span>
|
||
</template>
|
||
</vxe-column>
|
||
|
||
<vxe-column
|
||
title="单次剂量"
|
||
align="center"
|
||
width="250"
|
||
field="sortNumber"
|
||
>
|
||
<template #default="scope">
|
||
<template v-if="!scope.row.groupPackageId">
|
||
<template v-if="scope.row.adviceType == 1 || !scope.row.adviceDefinitionId">
|
||
<!-- 新增/未保存行:统一按"数量 + 单位 = 剂量 + 单位"展示 -->
|
||
<el-input
|
||
v-model="scope.row.doseQuantity"
|
||
style="width: 70px; margin-right: 10px"
|
||
@input="
|
||
(value) => {
|
||
scope.row.dose = value * scope.row.unitConversionRatio;
|
||
}
|
||
"
|
||
/>
|
||
<span>
|
||
{{
|
||
scope.row.minUnitCode_dictText ||
|
||
scope.row.unitCodeName ||
|
||
scope.row.unitCode_dictText ||
|
||
''
|
||
}}
|
||
</span>
|
||
<span>{{ ' = ' }}</span>
|
||
<el-input
|
||
v-model="scope.row.dose"
|
||
style="width: 70px; margin-right: 10px"
|
||
@input="
|
||
(value) => {
|
||
scope.row.doseQuantity = value / scope.row.unitConversionRatio;
|
||
}
|
||
"
|
||
/>
|
||
<span>
|
||
{{
|
||
scope.row.doseUnitCode_dictText ||
|
||
scope.row.unitCodeName ||
|
||
scope.row.unitCode_dictText ||
|
||
''
|
||
}}
|
||
</span>
|
||
</template>
|
||
<span v-else>-</span>
|
||
</template>
|
||
<template v-else>
|
||
<span v-if="scope.row.adviceType == 1">{{ scope.row.dose }}</span>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</template>
|
||
</vxe-column>
|
||
|
||
<vxe-column
|
||
title="给药途径"
|
||
align="center"
|
||
width="150"
|
||
field="sortNumber"
|
||
>
|
||
<template #default="scope">
|
||
<template v-if="!scope.row.groupPackageId">
|
||
<template v-if="scope.row.adviceType == 1 || !scope.row.adviceDefinitionId">
|
||
<el-select
|
||
v-model="scope.row.methodCode"
|
||
placeholder="给药途径"
|
||
clearable
|
||
filterable
|
||
>
|
||
<el-option
|
||
v-for="dict in method_code"
|
||
:key="dict.value"
|
||
:label="dict.label"
|
||
:value="dict.value"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
<span v-else>-</span>
|
||
</template>
|
||
<template v-else>
|
||
<span v-if="scope.row.adviceType == 1">{{ scope.row.methodCode_dictText || scope.row.methodCode }}</span>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</template>
|
||
</vxe-column>
|
||
|
||
<vxe-column
|
||
title="用药频次"
|
||
align="center"
|
||
width="150"
|
||
field="sortNumber"
|
||
>
|
||
<template #default="scope">
|
||
<template v-if="!scope.row.groupPackageId">
|
||
<template v-if="scope.row.adviceType == 1 || !scope.row.adviceDefinitionId">
|
||
<el-select
|
||
v-model="scope.row.rateCode"
|
||
placeholder="频次"
|
||
style="width: 120px"
|
||
filterable
|
||
>
|
||
<el-option
|
||
v-for="dict in getRateOptions(scope.row)"
|
||
:key="dict.value"
|
||
:label="dict.label"
|
||
:value="dict.value"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
<span v-else>-</span>
|
||
</template>
|
||
<template v-else>
|
||
<span v-if="scope.row.adviceType == 1">{{ scope.row.rateCode_dictText }}</span>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</template>
|
||
</vxe-column>
|
||
|
||
<vxe-column
|
||
title="用药天数"
|
||
align="center"
|
||
width="100"
|
||
field="sortNumber"
|
||
>
|
||
<template #default="scope">
|
||
<template v-if="!scope.row.groupPackageId">
|
||
<template v-if="scope.row.adviceType == 1 || !scope.row.adviceDefinitionId">
|
||
<el-input
|
||
v-model="scope.row.dispensePerDuration"
|
||
@change="handleQuantityChange(scope.row)"
|
||
/>
|
||
</template>
|
||
<span v-else>-</span>
|
||
</template>
|
||
<template v-else>
|
||
<span v-if="scope.row.adviceType == 1">{{ scope.row.dispensePerDuration }}</span>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</template>
|
||
</vxe-column>
|
||
|
||
<vxe-column
|
||
title="总量/执行次数"
|
||
align="center"
|
||
width="150"
|
||
field="sortNumber"
|
||
>
|
||
<template #default="scope">
|
||
<template v-if="!scope.row.groupPackageId">
|
||
<el-input
|
||
v-model="scope.row.sortNumber"
|
||
type="number"
|
||
min="1"
|
||
@change="handleQuantityChange(scope.row)"
|
||
/>
|
||
</template>
|
||
<span v-else>{{ scope.row.sortNumber }}</span>
|
||
</template>
|
||
</vxe-column>
|
||
|
||
<vxe-column
|
||
title="单位"
|
||
align="center"
|
||
width="120"
|
||
field="unitCode"
|
||
>
|
||
<template #default="scope">
|
||
<template v-if="!scope.row.groupPackageId">
|
||
<el-select
|
||
v-model="scope.row.selectUnitCode"
|
||
placeholder="请选择单位"
|
||
@change="handleUnitChange(scope.row)"
|
||
>
|
||
<el-option
|
||
v-if="scope.row.minUnitCode"
|
||
:key="scope.row.minUnitCode"
|
||
:label="scope.row.minUnitCode_dictText || scope.row.minUnitCode"
|
||
:value="scope.row.minUnitCode"
|
||
/>
|
||
<el-option
|
||
v-if="scope.row.unitCode"
|
||
:key="scope.row.unitCode"
|
||
:label="scope.row.unitCode_dictText || scope.row.unitCode"
|
||
:value="scope.row.unitCode"
|
||
/>
|
||
</el-select>
|
||
</template>
|
||
<span>{{ scope.row.unitCodeName }}</span>
|
||
</template>
|
||
</vxe-column>
|
||
|
||
<vxe-column
|
||
title="操作"
|
||
align="center"
|
||
width="80"
|
||
>
|
||
<template #default="scope">
|
||
<el-button
|
||
type="danger"
|
||
icon="Delete"
|
||
circle
|
||
size="small"
|
||
@click="handleDeleteRow(scope.rowIndex, scope.row)"
|
||
/>
|
||
</template>
|
||
</vxe-column>
|
||
</vxe-table>
|
||
|
||
<template #footer>
|
||
<el-button @click="dialogVisible = false">
|
||
取 消
|
||
</el-button>
|
||
<el-button
|
||
type="primary"
|
||
:loading="submitLoading"
|
||
@click="submitForm"
|
||
>
|
||
确 定
|
||
</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, computed, onMounted, getCurrentInstance } from 'vue';
|
||
import adviceBaseList from './adviceBaseList';
|
||
import {
|
||
queryParticipantList,
|
||
queryGroupDetail,
|
||
getOrgTree,
|
||
} from './api.js';
|
||
import { saveOrderGroup } from '@/views/doctorstation/components/api.js';
|
||
import useUserStore from '@/store/modules/user';
|
||
import { ElMessage } from 'element-plus';
|
||
|
||
const props = defineProps({
|
||
// 是否在“医生站/住院医生站”场景复用:个人不选人(practitionerId 置空),科室可选科室
|
||
isDoctorStation: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
method_code: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
rate_code: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
// 顶部是否显示“个人/科室/全院”切换(用于住院医生站顶部【组套】按钮场景)
|
||
showRangeSelector: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
});
|
||
|
||
const emit = defineEmits(['saved']);
|
||
|
||
const { proxy } = getCurrentInstance();
|
||
const userStore = useUserStore();
|
||
|
||
const dialogVisible = ref(false);
|
||
const dialogTitle = ref('');
|
||
const currentTab = ref('personal'); // personal | department | hospital
|
||
const isEdit = ref(false);
|
||
const submitLoading = ref(false);
|
||
const rangeSelectValue = ref('personal');
|
||
|
||
const participantListOptions = ref([]);
|
||
const organization = ref([]);
|
||
const adviceQueryParams = reactive({});
|
||
|
||
const formData = reactive({
|
||
groupPackageId: undefined,
|
||
name: '',
|
||
practitionerId: undefined,
|
||
organizationId: undefined,
|
||
});
|
||
|
||
const prescriptionList = ref([]);
|
||
const expandOrder = ref([]);
|
||
const nextId = ref(1);
|
||
const rowIndex = ref(0);
|
||
const selectedRows = ref([]);
|
||
const groupIndex = ref(1);
|
||
|
||
const formRef = ref();
|
||
const prescriptionRef = ref();
|
||
const adviceTableRef = ref();
|
||
|
||
const formRules = computed(() => {
|
||
const rules = {
|
||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||
};
|
||
// 独立页面:个人必须选参与者;科室必须选科室
|
||
if (!props.isDoctorStation && currentTab.value === 'personal') {
|
||
rules.practitionerId = [{ required: true, message: '请选择参与者', trigger: 'change' }];
|
||
}
|
||
if (currentTab.value === 'department') {
|
||
rules.organizationId = [{ required: true, message: '请选择科室', trigger: 'change' }];
|
||
}
|
||
return rules;
|
||
});
|
||
|
||
onMounted(() => {
|
||
queryParticipantList().then((res) => {
|
||
participantListOptions.value = res.data || [];
|
||
});
|
||
getOrgTree().then((res) => {
|
||
organization.value = res.data?.records || [];
|
||
});
|
||
});
|
||
|
||
function openAdd(tab) {
|
||
currentTab.value = tab;
|
||
isEdit.value = false;
|
||
dialogTitle.value = '新增医嘱';
|
||
dialogVisible.value = true;
|
||
|
||
if (props.showRangeSelector) rangeSelectValue.value = tab;
|
||
|
||
prescriptionList.value = [];
|
||
expandOrder.value = [];
|
||
nextId.value = 1;
|
||
rowIndex.value = 0;
|
||
selectedRows.value = [];
|
||
groupIndex.value = 1;
|
||
|
||
formData.groupPackageId = undefined;
|
||
formData.name = '';
|
||
formData.practitionerId = undefined;
|
||
formData.organizationId = undefined;
|
||
|
||
Object.keys(adviceQueryParams).forEach((key) => {
|
||
delete adviceQueryParams[key];
|
||
});
|
||
|
||
prescriptionRef.value?.clearSelection?.();
|
||
|
||
if (tab === 'personal') {
|
||
// 医生站场景:个人组套需要关联当前医生才能查询到
|
||
formData.practitionerId = userStore.practitionerId;
|
||
} else if (tab === 'department') {
|
||
formData.organizationId = userStore.orgId;
|
||
}
|
||
|
||
addEmptyRow();
|
||
}
|
||
|
||
function handleRangeChange(tab) {
|
||
openAdd(tab);
|
||
}
|
||
|
||
/**
|
||
* 从外部选中的医嘱直接生成组套明细
|
||
* @param tab 使用范围:personal / department / hospital
|
||
* @param rows 选中的处方行列表
|
||
*/
|
||
function openFromSelection(tab, rows = []) {
|
||
currentTab.value = tab;
|
||
isEdit.value = false;
|
||
dialogTitle.value = '另存组套';
|
||
dialogVisible.value = true;
|
||
|
||
if (props.showRangeSelector) rangeSelectValue.value = tab;
|
||
|
||
// 重置表单
|
||
formData.groupPackageId = undefined;
|
||
formData.name = '';
|
||
formData.practitionerId = undefined;
|
||
formData.organizationId = undefined;
|
||
|
||
if (tab === 'personal') {
|
||
// 医生站场景:个人组套需要关联当前医生才能查询到
|
||
formData.practitionerId = userStore.practitionerId;
|
||
} else if (tab === 'department') {
|
||
formData.organizationId = userStore.orgId;
|
||
}
|
||
|
||
const validRows = (rows || []).filter((i) => i.adviceDefinitionId);
|
||
if (validRows.length === 0) {
|
||
proxy.$modal.msgWarning('所选医嘱中没有有效的医嘱项,请先选择医嘱后再另存组套');
|
||
dialogVisible.value = false;
|
||
return;
|
||
}
|
||
|
||
prescriptionList.value = validRows.map((row, index) => {
|
||
let therapyEnum = row.therapyEnum;
|
||
if (!therapyEnum && row.contentJson) {
|
||
try {
|
||
const content = JSON.parse(row.contentJson);
|
||
therapyEnum = content.therapyEnum;
|
||
} catch (e) {}
|
||
}
|
||
therapyEnum = therapyEnum != null ? String(therapyEnum) : '1';
|
||
|
||
return {
|
||
uniqueKey: index + 1,
|
||
showPopover: false,
|
||
check: false,
|
||
isEdit: false,
|
||
statusEnum: 1,
|
||
adviceDefinitionId: row.adviceDefinitionId,
|
||
adviceTableName: row.adviceTableName || 'advice_definition',
|
||
sortNumber: row.quantity ?? row.sortNumber ?? 1,
|
||
selectUnitCode: row.selectUnitCode || row.unitCode,
|
||
adviceName: row.adviceName || row.productName,
|
||
unitCodeName: row.unitCodeName || row.unitCode_dictText || '',
|
||
methodCode: row.methodCode,
|
||
rateCode: row.rateCode,
|
||
dispensePerDuration: row.dispensePerDuration,
|
||
dose: row.dose,
|
||
doseQuantity: row.doseQuantity,
|
||
minUnitCode: row.minUnitCode,
|
||
minUnitCode_dictText: row.minUnitCode_dictText,
|
||
unitCode: row.unitCode,
|
||
unitCode_dictText: row.unitCode_dictText,
|
||
groupId: row.groupId,
|
||
groupOrder: row.groupOrder,
|
||
therapyEnum: therapyEnum,
|
||
adviceType: row.adviceType,
|
||
};
|
||
});
|
||
|
||
expandOrder.value = [];
|
||
nextId.value = prescriptionList.value.length + 1;
|
||
}
|
||
|
||
function openEdit(tab, row) {
|
||
currentTab.value = tab;
|
||
isEdit.value = true;
|
||
dialogTitle.value = '编辑医嘱';
|
||
dialogVisible.value = true;
|
||
|
||
formData.groupPackageId = row.groupPackageId;
|
||
formData.name = row.name;
|
||
formData.practitionerId = row.practitionerId;
|
||
formData.organizationId = row.organizationId;
|
||
|
||
queryGroupDetail({ groupPackageId: row.groupPackageId }).then((res) => {
|
||
const detailList = res.data || [];
|
||
prescriptionList.value = detailList.map((item, index) => {
|
||
const therapyEnum = item.therapyEnum != null ? String(item.therapyEnum) : '1'; // 统一转成字符串
|
||
|
||
return {
|
||
uniqueKey: index + 1,
|
||
showPopover: false,
|
||
check: false,
|
||
isEdit: false,
|
||
statusEnum: 1,
|
||
groupPackageId: item.groupPackageId,
|
||
adviceDefinitionId: item.orderDefinitionId,
|
||
adviceTableName: item.orderDefinitionTable,
|
||
sortNumber: item.quantity,
|
||
selectUnitCode: item.unitCode,
|
||
adviceName: item.orderDefinitionName,
|
||
unitCodeName: item.unitCodeName,
|
||
groupId: item.groupId,
|
||
groupOrder: item.groupOrder,
|
||
therapyEnum, // 长期/临时类型:1-长期,2-临时
|
||
// 回显单次剂量/给药途径/用药频次/天数等字段
|
||
dispensePerDuration: item.dispensePerDuration,
|
||
dose: item.dose,
|
||
doseQuantity: item.doseQuantity,
|
||
methodCode: item.methodCode,
|
||
methodCode_dictText: item.methodCode_dictText,
|
||
rateCode: item.rateCode,
|
||
rateCode_dictText: item.rateCode_dictText,
|
||
// 医嘱类型(药品=1):没有则按表名推断(药品表 -> 药品)
|
||
adviceType:
|
||
item.adviceType !== undefined
|
||
? item.adviceType
|
||
: item.orderDefinitionTable === 'med_medication_definition'
|
||
? 1
|
||
: undefined,
|
||
};
|
||
});
|
||
nextId.value = prescriptionList.value.length + 1;
|
||
addEmptyRow();
|
||
});
|
||
}
|
||
|
||
function addEmptyRow() {
|
||
prescriptionList.value.unshift({
|
||
uniqueKey: nextId.value++,
|
||
showPopover: false,
|
||
check: false,
|
||
isEdit: true,
|
||
statusEnum: 1,
|
||
therapyEnum: '1', // 默认长期
|
||
});
|
||
}
|
||
|
||
function handleAddRow() {
|
||
addEmptyRow();
|
||
}
|
||
|
||
function handleSelectionChange(selection) {
|
||
selectedRows.value = selection || [];
|
||
}
|
||
|
||
function handleCombineGroup() {
|
||
const rows = selectedRows.value || [];
|
||
if (rows.length <= 1) {
|
||
proxy.$modal.msgWarning('至少选择两项');
|
||
return;
|
||
}
|
||
|
||
// 必须都已选择医嘱
|
||
if (rows.some((r) => !r.adviceDefinitionId)) {
|
||
proxy.$modal.msgWarning('请先完成医嘱选择');
|
||
return;
|
||
}
|
||
|
||
// 相同分组用法需要相同
|
||
const methodSet = new Set();
|
||
rows.forEach((r) => {
|
||
if (r.methodCode != null) methodSet.add(r.methodCode);
|
||
});
|
||
if (methodSet.size > 1) {
|
||
proxy.$modal.msgWarning('同一分组药品用法必须相同');
|
||
return;
|
||
}
|
||
|
||
// 相同分组频次需要相同
|
||
const rateSet = new Set();
|
||
rows.forEach((r) => {
|
||
if (r.rateCode != null) rateSet.add(r.rateCode);
|
||
});
|
||
if (rateSet.size > 1) {
|
||
proxy.$modal.msgWarning('同一分组药品频次必须相同');
|
||
return;
|
||
}
|
||
|
||
const timestamp = Date.now().toString();
|
||
const gid = timestamp + groupIndex.value;
|
||
|
||
const newList = [...prescriptionList.value];
|
||
rows.forEach((item, selectIndex) => {
|
||
const idx = newList.findIndex((r) => r.uniqueKey === item.uniqueKey);
|
||
if (idx !== -1) {
|
||
newList[idx].groupId = gid;
|
||
newList[idx].groupOrder = selectIndex + 1;
|
||
}
|
||
});
|
||
|
||
groupIndex.value += 1;
|
||
prescriptionList.value = newList;
|
||
prescriptionRef.value?.clearSelection?.();
|
||
proxy.$modal.msgSuccess('组套成功');
|
||
}
|
||
|
||
function isRowSelectable(row) {
|
||
return !!row.adviceDefinitionId;
|
||
}
|
||
|
||
function getGroupIcon(row) {
|
||
if (!row.groupId) return '';
|
||
const sameGroup = prescriptionList.value
|
||
.filter((item) => item.groupId === row.groupId)
|
||
.sort((a, b) => {
|
||
const aOrder = a.groupOrder ?? 0;
|
||
const bOrder = b.groupOrder ?? 0;
|
||
return aOrder - bOrder;
|
||
});
|
||
if (sameGroup.length === 0) return '';
|
||
const index = sameGroup.findIndex((item) => item.uniqueKey === row.uniqueKey);
|
||
if (index === 0) {
|
||
return '┏';
|
||
}
|
||
if (index === sameGroup.length - 1) {
|
||
return '┗';
|
||
}
|
||
return '┃';
|
||
}
|
||
|
||
function getRateOptions(row) {
|
||
const all = props.rate_code || [];
|
||
if (row?.therapyEnum == '2') {
|
||
return all.filter(
|
||
(dict) => dict.value === 'ST' || (dict.label && dict.label.indexOf('立即') !== -1)
|
||
);
|
||
}
|
||
return all;
|
||
}
|
||
|
||
function handleSplitGroup() {
|
||
const rows = selectedRows.value || [];
|
||
if (rows.length < 1) {
|
||
proxy.$modal.msgWarning('至少选择一项');
|
||
return;
|
||
}
|
||
if (rows.some((r) => !r.groupId)) {
|
||
proxy.$modal.msgWarning('包含非组合数据无法拆组');
|
||
return;
|
||
}
|
||
|
||
const newList = [...prescriptionList.value];
|
||
rows.forEach((item) => {
|
||
const idx = newList.findIndex((r) => r.uniqueKey === item.uniqueKey);
|
||
if (idx !== -1) {
|
||
newList[idx].groupId = undefined;
|
||
newList[idx].groupOrder = undefined;
|
||
}
|
||
});
|
||
|
||
prescriptionList.value = newList;
|
||
prescriptionRef.value?.clearSelection?.();
|
||
proxy.$modal.msgSuccess('拆组成功');
|
||
}
|
||
|
||
function submitForm() {
|
||
formRef.value.validate((valid) => {
|
||
if (!valid) return;
|
||
|
||
// 验证至少选择了一条医嘱
|
||
const detailList = prescriptionList.value.filter((item) => item.adviceDefinitionId);
|
||
if (detailList.length === 0) {
|
||
proxy?.$modal?.msgWarning?.('请至少选择一条医嘱');
|
||
return;
|
||
}
|
||
|
||
// 验证西药类医嘱的必填字段
|
||
const westernMedicineRows = detailList.filter((item) => item.adviceType == 1);
|
||
for (const row of westernMedicineRows) {
|
||
if (!row.dose && row.dose !== 0) {
|
||
proxy?.$modal?.msgWarning?.('单次剂量为必填项');
|
||
return;
|
||
}
|
||
if (!row.methodCode) {
|
||
proxy?.$modal?.msgWarning?.('给药途径为必填项');
|
||
return;
|
||
}
|
||
if (!row.rateCode) {
|
||
proxy?.$modal?.msgWarning?.('用药频次为必填项');
|
||
return;
|
||
}
|
||
if (!row.dispensePerDuration && row.dispensePerDuration !== 0) {
|
||
proxy?.$modal?.msgWarning?.('用药天数为必填项');
|
||
return;
|
||
}
|
||
if (!row.sortNumber && row.sortNumber !== 0) {
|
||
proxy?.$modal?.msgWarning?.('总量/执行次数为必填项');
|
||
return;
|
||
}
|
||
if (!row.selectUnitCode) {
|
||
proxy?.$modal?.msgWarning?.('单位为必填项');
|
||
return;
|
||
}
|
||
}
|
||
|
||
submitLoading.value = true;
|
||
setTimeout(() => {
|
||
console.log('[submitForm] 当前tab:', currentTab.value);
|
||
const params = { ...formData };
|
||
console.log('[submitForm] formData:', formData);
|
||
// 添加 rangeCode 字段,用于后端判断组套类型
|
||
if (currentTab.value === 'personal') {
|
||
params.rangeCode = 1;
|
||
} else if (currentTab.value === 'department') {
|
||
params.rangeCode = 2;
|
||
} else {
|
||
params.rangeCode = 3;
|
||
}
|
||
console.log('[submitForm] 设置后的rangeCode:', params.rangeCode);
|
||
// 医生站场景:个人组套需要设置 practitionerId 为当前医生,否则查询时查不到
|
||
console.log('[submitForm] isDoctorStation:', props.isDoctorStation, 'currentTab:', currentTab.value);
|
||
console.log('[submitForm] userStore.practitionerId:', userStore.practitionerId);
|
||
if (props.isDoctorStation && currentTab.value === 'personal') {
|
||
params.practitionerId = userStore.practitionerId;
|
||
console.log('[submitForm] 已设置 practitionerId:', params.practitionerId);
|
||
} else {
|
||
console.log('[submitForm] 未设置 practitionerId, 当前值:', params.practitionerId);
|
||
}
|
||
|
||
params.detailList = detailList.map((item) => ({
|
||
orderDefinitionId: item.adviceDefinitionId,
|
||
orderDefinitionTable: item.adviceTableName,
|
||
quantity: item.sortNumber,
|
||
unitCode: item.selectUnitCode,
|
||
methodCode: item.methodCode,
|
||
rateCode: item.rateCode,
|
||
dispensePerDuration: item.dispensePerDuration,
|
||
dose: item.dose,
|
||
doseQuantity: item.doseQuantity,
|
||
groupId: item.groupId,
|
||
groupOrder: item.groupOrder,
|
||
therapyEnum: item.therapyEnum || '1',
|
||
}));
|
||
|
||
console.log('[submitForm] 准备保存组套, params:', params);
|
||
// 使用 saveOrderGroup,它会根据 rangeCode 自动选择正确的API
|
||
saveOrderGroup(params)
|
||
.then((res) => {
|
||
console.log('[submitForm] 保存API返回:', res);
|
||
if (res.code === 200) {
|
||
ElMessage.success(res.message || '保存成功');
|
||
console.log('[submitForm] 准备触发 saved 事件');
|
||
emit('saved');
|
||
console.log('[submitForm] saved 事件已触发');
|
||
dialogVisible.value = false;
|
||
prescriptionList.value = [];
|
||
} else {
|
||
proxy?.$modal?.msgError?.(res.message || '保存失败');
|
||
}
|
||
})
|
||
.catch((err) => {
|
||
console.error('保存失败:', err);
|
||
proxy?.$modal?.msgError?.(err?.message || '保存失败,请检查网络或联系管理员');
|
||
})
|
||
.finally(() => {
|
||
submitLoading.value = false;
|
||
});
|
||
}, 200);
|
||
});
|
||
}
|
||
|
||
function selectAdviceBase(key, row) {
|
||
const currentRow = prescriptionList.value[rowIndex.value];
|
||
const preservedTherapyEnum = currentRow?.therapyEnum || row.therapyEnum || '1';
|
||
|
||
prescriptionList.value[rowIndex.value] = {
|
||
...prescriptionList.value[rowIndex.value],
|
||
...JSON.parse(JSON.stringify(row)),
|
||
};
|
||
prescriptionList.value[rowIndex.value].dose = undefined;
|
||
prescriptionList.value[rowIndex.value].doseQuantity = undefined;
|
||
prescriptionList.value[rowIndex.value].doseUnitCode = row.doseUnitCode;
|
||
prescriptionList.value[rowIndex.value].minUnitCode = row.minUnitCode;
|
||
prescriptionList.value[rowIndex.value].unitCode =
|
||
row.partAttributeEnum == 1 ? row.minUnitCode : row.unitCode;
|
||
prescriptionList.value[rowIndex.value].categoryEnum = row.categoryCode;
|
||
prescriptionList.value[rowIndex.value].isEdit = false;
|
||
prescriptionList.value[rowIndex.value].definitionId = JSON.parse(
|
||
JSON.stringify(row)
|
||
).chargeItemDefinitionId;
|
||
prescriptionList.value[rowIndex.value].therapyEnum = preservedTherapyEnum;
|
||
addEmptyRow();
|
||
expandOrder.value = [key];
|
||
}
|
||
|
||
function handleFocus(row, index) {
|
||
rowIndex.value = index;
|
||
row.showPopover = true;
|
||
adviceQueryParams.searchKey = row.adviceName || '';
|
||
// 设置 organizationId,否则 adviceBaseList 会跳过 API 调用
|
||
adviceQueryParams.organizationId = userStore.orgId;
|
||
}
|
||
|
||
function handleInput(value, row, index) {
|
||
adviceQueryParams.searchKey = value || '';
|
||
handleFocus(row, index);
|
||
}
|
||
|
||
function handleBlur(row) {
|
||
row.showPopover = false;
|
||
}
|
||
|
||
function clickRow() {}
|
||
|
||
function getRowDisabled(row) {
|
||
return row.isEdit;
|
||
}
|
||
|
||
function handleQuantityChange(row) {
|
||
if (row.sortNumber && row.sortNumber > 0) row.sortNumber = parseInt(row.sortNumber);
|
||
else row.sortNumber = 1;
|
||
prescriptionList.value = [...prescriptionList.value];
|
||
}
|
||
|
||
function handleUnitChange(row) {
|
||
prescriptionList.value = [...prescriptionList.value];
|
||
}
|
||
|
||
function handleDeleteRow(index) {
|
||
if (prescriptionList.value.length <= 1) {
|
||
proxy.$modal.msgWarning('至少保留一行');
|
||
return;
|
||
}
|
||
proxy.$modal
|
||
.confirm('确定要删除该行吗?')
|
||
.then(() => {
|
||
prescriptionList.value.splice(index, 1);
|
||
proxy.$modal.msgSuccess('删除成功');
|
||
})
|
||
.catch(() => {});
|
||
}
|
||
|
||
function isLeafNode(node) {
|
||
return !node.children || node.children.length === 0;
|
||
}
|
||
|
||
function handleDialogClose() {
|
||
formRef.value?.resetFields?.();
|
||
prescriptionList.value = [];
|
||
}
|
||
|
||
function handleOrgChange(value) {
|
||
if (!value) return;
|
||
const findNode = (nodes) => {
|
||
for (let node of nodes) {
|
||
if (node.id === value) return node;
|
||
if (node.children && node.children.length > 0) {
|
||
const found = findNode(node.children);
|
||
if (found) return found;
|
||
}
|
||
}
|
||
return null;
|
||
};
|
||
const selectedNode = findNode(organization.value);
|
||
if (selectedNode && !isLeafNode(selectedNode)) {
|
||
proxy.$modal.msgWarning('只能选择末级科室');
|
||
formData.organizationId = null;
|
||
}
|
||
}
|
||
|
||
defineExpose({
|
||
openAdd,
|
||
openEdit,
|
||
openFromSelection,
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.dialog-top-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.dialog-top-row :deep(.el-form-item) {
|
||
margin-bottom: 0;
|
||
}
|
||
</style>
|