feat(basicmanage): 新增医嘱组套对话框组件和相关API
- 实现 MedicalOrderSetDialog.vue 组件,支持医嘱组套的新增、编辑功能 - 添加中药医嘱基础列表组件 tcmMedicineList.vue,支持键盘导航选择 - 创建医嘱组套相关API接口文件,包含个人、科室、全院组套的增删改查功能 - 实现医嘱组套的组合拆组功能,支持批量操作 - 集成分页、搜索、缓存等优化功能提升用户体验 - 添加表单验证和数据校验机制确保数据完整性
This commit is contained in:
@@ -0,0 +1,885 @@
|
||||
<template>
|
||||
<el-dialog :title="dialogTitle" v-model="dialogVisible" 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 label="使用范围" v-if="showRangeSelector && !isEdit">
|
||||
<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
|
||||
label="参与者"
|
||||
prop="practitionerId"
|
||||
v-if="currentTab === 'personal' && !isDoctorStation && !showRangeSelector"
|
||||
>
|
||||
<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 label="科室" prop="organizationId" v-if="currentTab === 'department'">
|
||||
<el-tree-select
|
||||
clearable
|
||||
v-model="formData.organizationId"
|
||||
: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>
|
||||
|
||||
<el-table
|
||||
max-height="650"
|
||||
ref="prescriptionRef"
|
||||
:data="prescriptionList"
|
||||
row-key="uniqueKey"
|
||||
border
|
||||
@cell-click="clickRow"
|
||||
@selection-change="handleSelectionChange"
|
||||
:expand-row-keys="expandOrder"
|
||||
>
|
||||
<el-table-column type="selection" width="55" :selectable="isRowSelectable" />
|
||||
<el-table-column label="组" align="center" width="60">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.groupId">{{ getGroupIcon(scope.row) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" 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 label="1">长期</el-radio-button>
|
||||
<el-radio-button label="2">临时</el-radio-button>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<span v-else>
|
||||
{{
|
||||
scope.row.therapyEnum == '1' ? '长期' : scope.row.therapyEnum == '2' ? '临时' : '-'
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="医嘱" align="center" prop="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"
|
||||
:popoverVisible="scope.row.showPopover"
|
||||
:adviceQueryParams="adviceQueryParams"
|
||||
@selectAdviceBase="(row) => selectAdviceBase(scope.row.uniqueKey, row)"
|
||||
/>
|
||||
<template #reference>
|
||||
<el-input
|
||||
:ref="'adviceRef' + scope.$index"
|
||||
style="width: 100%"
|
||||
v-model="scope.row.adviceName"
|
||||
placeholder="请选择项目"
|
||||
@input="(value) => handleInput(value, scope.row, scope.$index)"
|
||||
@click="handleFocus(scope.row, scope.$index)"
|
||||
@keyup.enter.stop="handleFocus(scope.row, scope.$index)"
|
||||
@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>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="单次剂量" align="center" width="250" prop="sortNumber">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.adviceType == 1">
|
||||
<!-- 新增/未保存行:统一按“数量 + 单位 = 剂量 + 单位”展示 -->
|
||||
<template v-if="!scope.row.groupPackageId">
|
||||
<el-input
|
||||
style="width: 70px; margin-right: 10px"
|
||||
v-model="scope.row.doseQuantity"
|
||||
@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
|
||||
style="width: 70px; margin-right: 10px"
|
||||
v-model="scope.row.dose"
|
||||
@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>{{ scope.row.dose }}</span>
|
||||
</template>
|
||||
<span v-else>{{ '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="给药途径" align="center" width="150" prop="sortNumber">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.adviceType == 1">
|
||||
<template v-if="!scope.row.groupPackageId">
|
||||
<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>{{ scope.row.methodCode }}</span>
|
||||
</template>
|
||||
<span v-else>{{ '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="用药频次" align="center" width="150" prop="sortNumber">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.adviceType == 1">
|
||||
<template v-if="!scope.row.groupPackageId">
|
||||
<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>{{ scope.row.rateCode_dictText }}</span>
|
||||
</template>
|
||||
<span v-else>{{ '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="用药天数" align="center" width="100" prop="sortNumber">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.adviceType == 1">
|
||||
<template v-if="!scope.row.groupPackageId">
|
||||
<el-input
|
||||
v-model="scope.row.dispensePerDuration"
|
||||
@change="handleQuantityChange(scope.row)"
|
||||
/>
|
||||
</template>
|
||||
<span v-else>{{ scope.row.dispensePerDuration }}</span>
|
||||
</template>
|
||||
<span v-else>{{ '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="总量/执行次数" align="center" width="150" prop="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>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="单位" align="center" width="120" prop="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>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="Delete"
|
||||
circle
|
||||
size="small"
|
||||
@click="handleDeleteRow(scope.$index, scope.row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitForm" :loading="submitLoading">确 定</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,
|
||||
rateCode: item.rateCode,
|
||||
// 医嘱类型(药品=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;
|
||||
}
|
||||
|
||||
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>
|
||||
Reference in New Issue
Block a user