Files
his/openhis-ui-vue3/src/views/doctorstation/components/tcm/tcmAdvice.vue

1504 lines
49 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div style="max-height: 750px; overflow-y: auto">
<div
class="prescription-section"
v-for="(prescription, pIndex) in tcmPrescriptionList"
:key="pIndex"
>
<div class="section-header">
<div class="title first-prescription">
<i class="el-icon-notebook-2"></i>
<span>{{ '处方' + (pIndex + 1) }}</span>
<el-icon
class="add-icon"
title="新增处方"
@click="addNewPrescription()"
style="font-size: 26px !important; margin-left: 10px; color: #409eff"
>
<plus />
</el-icon>
<el-icon
class="delete-icon"
title="删除处方单"
@click="handleDeletePrescriptionClick(pIndex)"
:class="{ 'disabled-icon': isPrescriptionDeletable(pIndex) !== true }"
style="font-size: 20px !important; margin-left: 10px; color: #f56c6c"
>
<minus />
</el-icon>
</div>
<div class="summary">
<span class="summary-item">药品数: {{ getPrescriptionMedicineCount(pIndex) }}</span>
<span class="summary-item">总价: ¥ {{ getPrescriptionTotalPrice(pIndex) }}</span>
</div>
</div>
<div>
<div style="margin-top: 10px">
<el-button type="primary" @click="handleAddMedicine(pIndex)" plain> 添加药品 </el-button>
<el-button type="primary" @click="handleSaveBatch(pIndex)" plain> 保存 </el-button>
<el-button type="primary" @click="handleSave(pIndex)" plain> 签发 </el-button>
<el-button type="warning" plain @click="handleSingOut(pIndex)"> 撤回 </el-button>
<el-button type="danger" plain @click="handleDelete(pIndex)" :disabled="false">
删除
</el-button>
</div>
<div
class="doctor-station"
style="padding: 10px 10px 10px 0; margin-left: 0; font-size: 15px"
>
<span class="doctor-station" style="margin-left: 0"> 诊断 </span>
<el-select
v-model="prescription.conditionDefinitionId"
placeholder="诊断"
style="width: 180px"
>
<el-option
v-for="item in diagnosisList"
:key="item.definitionId"
:label="item.name"
:value="item.definitionId"
@click="handleDiagnosisChange(item, pIndex)"
/>
</el-select>
<span class="doctor-station"> 费用性质 </span>
<el-select v-model="prescription.accountId" placeholder="费用性质" style="width: 120px">
<el-option
v-for="item in contractList"
:key="item.accountId"
:label="item.contractName"
:value="item.accountId"
/>
</el-select>
<span class="doctor-station"> 配方名称 </span>
<el-input v-model="formulaName" placeholder=" " style="width: 100px" />
<span class="doctor-station"> 用药途径 </span>
<el-select v-model="methodCode" placeholder="费用性质" style="width: 120px">
<el-option
v-for="dict in method_code"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
<span class="doctor-station"> 煎药方式 </span>
<el-select v-model="decoctionMethod" placeholder="" style="width: 120px">
<el-option
v-for="dict in method_of_decocting_medicine"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
<span class="doctor-station"> 频次 </span>
<el-select v-model="prescription.rateCode" placeholder="频次" style="width: 120px">
<el-option
v-for="dict in rate_code"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
<span class="doctor-station"> 用药天数 </span>
<el-input
v-model="prescription.dispensePerDuration"
placeholder=" "
style="width: 70px"
/>
<span class="doctor-station"> 付数 </span>
<el-input
v-model="prescription.chineseHerbsDoseQuantity"
placeholder=" "
style="width: 70px"
@input="
(value) => {
let price = 0;
prescription.prescriptionList.forEach((item) => {
price += item.totalPrice;
});
prescription.totalAmount = prescription.dispensePerDuration * value * price;
}
"
/>
<span class="doctor-station"> 是否代煎 </span>
<el-checkbox
v-model="prescription.sufferingFlag"
:true-value="'1'"
:false-value="'0'"
placeholder=" "
@change="
(value) => {
console.log(value, prescription.sufferingFlag, 123456789);
}
"
/>
<span class="doctor-station" style="float: right"> </span>
</div>
<el-table
max-height="650"
ref="prescriptionRef"
:data="prescription.prescriptionList"
row-key="uniqueKey"
border
@cell-click="clickRow"
@row-dblclick="(row) => clickRowDb(row, pIndex)"
v-loading="loading"
:expand-row-keys="prescription.expandOrder"
>
<el-table-column type="expand" width="1" style="width: 0">
<template #default="scope">
<el-form
:model="scope.row"
:rules="rowRules"
:ref="'formRef' + pIndex + '-' + scope.$index"
>
<div
class="expend_div"
style="padding: 16px; background: #f8f9fa; border-radius: 8px"
>
<template v-if="scope.row.adviceType == 1">
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 8px">
<span class="medicine-title">
{{
scope.row.adviceName +
' ' +
' [' +
Number(scope.row.unitPrice).toFixed(2) +
' 元' +
'/' +
scope.row.unitCode_dictText +
']'
}}
</span>
<el-form-item prop="lotNumber" label="药房">
<el-select
v-model="scope.row.inventoryId"
style="width: 380px; margin-right: 20px"
placeholder="药房"
>
<el-option
v-for="item in scope.row.stockList"
:key="item.inventoryId"
:value="item.inventoryId"
:label="
item.locationName +
' ' +
'批次号: ' +
item.lotNumber +
' ' +
' 库存:' +
item.quantity / scope.row.partPercent +
item.unitCode_dictText +
' 单价:' +
item.price.toFixed(2) +
'/' +
item.unitCode_dictText
"
@click="handleNumberClick(item, scope.$index, pIndex)"
/>
</el-select>
</el-form-item>
<div class="form-group">
<!-- 单次剂量 -->
<el-form-item
label="数量"
prop="minUnitQuantity"
class="required-field"
data-prop="minUnitQuantity"
>
<el-input-number
:min="0"
v-model="scope.row.minUnitQuantity"
controls-position="right"
:controls="false"
style="width: 70px; margin-right: 20px"
:ref="(el) => (inputRefs.minUnitQuantity = el)"
@input="
() => {
nextTick(() => {
scope.row.totalPrice =
scope.row.minUnitQuantity * scope.row.unitPrice;
});
}
"
@keyup.enter.prevent="
handleEnter('minUnitQuantity', scope.row, scope.$index, pIndex)
"
/>
</el-form-item>
<!-- 剂量单位 -->
<el-select
v-model="scope.row.minUnitCode"
style="width: 80px; margin-right: 20px"
placeholder=" "
>
<template v-for="item in scope.row.unitCodeList" :key="item.value">
<el-option
v-if="
scope.row.unitCodeList.length == 3
? item.type == unitMap['minUnit']
: item.type == unitMap['unit']
"
:value="item.value"
:label="item.label"
/>
</template>
</el-select>
<span class="doctor-station"> 脚注: </span>
<el-select
v-model="footNote"
filterable
allow-create
default-first-option
style="width: 120px; margin-right: 20px"
placeholder="">
<el-option
v-for="dict in hjerbal_footnotes"
:key="dict.value"
:label="dict.label"
:value="dict.value">
</el-option>
</el-select>
</div>
<span class="total-amount">
总金额:{{
scope.row.totalPrice ? scope.row.totalPrice + ' 元' : '0.00 元'
}}
</span>
<el-button
type="primary"
@click="handleSaveSign(scope.row, scope.$index, pIndex)"
>
确定
</el-button>
</div>
</template>
</div>
</el-form>
</template>
</el-table-column>
<el-table-column label="" align="center" prop="groupId" width="60">
<template #header>
<el-checkbox
v-model="prescription.checkAll"
@change="
(value) => {
prescription.prescriptionList.forEach((item, index) => {
prescription.groupIndexList.push(index);
item.check = value;
});
}
"
/>
</template>
<template #default="scope">
<el-checkbox
v-model="scope.row.check"
@dblclick.stop=""
placeholder=""
@change="(value) => handleCheckBoxChange(value, scope.$index, scope.row, pIndex)"
/>
</template>
</el-table-column>
<el-table-column label="医嘱" align="center" prop="productName" width="400">
<template #default="scope">
<template v-if="getRowDisabled(scope.row)">
<el-popover
:popper-style="{ padding: '0' }"
placement="bottom-start"
:visible="scope.row.showPopover"
:width="1200"
>
<tcmMedicineList
ref="adviceTableRef"
:popoverVisible="scope.row.showPopover"
:adviceQueryParams="adviceQueryParams"
:patientInfo="props.patientInfo"
@selectAdviceBase="(row) => selectAdviceBase(scope.row.uniqueKey, row, pIndex)"
/>
<template #reference>
<el-input
:ref="'adviceRef' + pIndex + '-' + scope.$index"
style="width: 50%"
v-model="scope.row.adviceName"
placeholder="请选择项目"
@input="handleChange"
@click="handleFocus(scope.row, scope.$index, pIndex)"
@keyup.enter.stop="handleFocus(scope.row, scope.$index, pIndex)"
@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" prop="" width="90">
<template #default="scope">
<el-tag v-if="scope.row.statusEnum == 2" type="success">已签发</el-tag>
<el-tag v-else-if="!scope.row.requestId && scope.row.statusEnum == 1" type="warning">
待保存
</el-tag>
<el-tag v-else-if="scope.row.statusEnum == 1" type="primary">待签发</el-tag>
</template>
</el-table-column>
<el-table-column label="数量" align="center" prop="">
<template #default="scope">
<span v-if="!scope.row.isEdit">
{{
scope.row.quantity
? formatNumber(scope.row.quantity) +
' ' +
scope.row.doseUnitCode_dictText +
' (' +
scope.row.chineseHerbsDoseQuantity +
'付)'
: ''
}}
</span>
</template>
</el-table-column>
<el-table-column label="总金额" align="right" prop="" header-align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit" style="text-align: right">
{{ scope.row.totalPrice ? Number(scope.row.totalPrice).toFixed(2) + ' 元' : '-' }}
</span>
</template>
</el-table-column>
<el-table-column label="特殊煎法" align="right" prop="" header-align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit" style="text-align: right">
{{
scope.row.dosageInstruction_dictText ? scope.row.dosageInstruction_dictText : '-'
}}
</span>
</template>
</el-table-column>
<el-table-column label="药房/科室" align="center" prop="" width="240">
<template #default="scope">
<span v-if="!scope.row.isEdit">
{{ scope.row.positionName }}
</span>
</template>
</el-table-column>
<el-table-column label="诊断" align="center" prop="diagnosisName" width="200">
<template #default="scope">
<span v-if="!scope.row.isEdit">
{{ scope.row.diagnosisName || scope.row.conditionDefinitionName }}
</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
<tcmdiagnosisDialog ref="tcmDianosis" :patientInfo="props.patientInfo" @flush="getListInfo()" />
</div>
</template>
<script setup>
import {
getDiagnosisDefinitionList,
getEncounterDiagnosis,
saveTcmAdvice,
getTcmAdviceList,
getOrgTree,
signTcmAdvice,
getTcmDiagnosis,
signOutTcmAdvice,
updateGroupId,
getContract,
getAdviceBaseInfo,
savePrescription,
} from '@/views/doctorstation/components/api';
import tcmMedicineList from './tcmMedicineList';
import { computed, getCurrentInstance, nextTick, watch } from 'vue';
import { calculateQuantityByDays, formatNumber } from '@/utils/his';
import Decimal from 'decimal.js';
import tcmdiagnosisDialog from './tcmdiagnosisDialog';
import { Delete, Minus } from '@element-plus/icons-vue';
const emit = defineEmits(['selectDiagnosis']);
const total = ref(0);
const queryParams = ref({});
const form = ref({});
const adviceQueryParams = ref({});
const rowIndex = ref(-1);
const groupIndex = ref(1);
const diagnosisList = ref([]);
const patientId = ref('');
const encounterId = ref('');
const accountId = ref('');
const encounterDiagnosisId = ref('');
const tcmPrescriptionList = ref([
{
prescriptionList: [],
conditionDefinitionId: '',
accountId: '',
methodCode: '',
rateCode: '',
dispensePerDuration: '',
chineseHerbsDoseQuantity: '',
sufferingFlag: '0',
checkAll: false,
groupIndexList: [],
expandOrder: [],
totalAmount: 0,
nextId: 1,
isAdding: false,
},
]);
const unitCodeList = ref([]);
const adviceTableRef = ref([]);
const organization = ref([]);
const conditionDefinitionId = ref('');
const diagnosisName = ref('');
const diagnosisInfo = ref({});
const rateCode = ref('');
const footNote = ref('');
const decoctionMethod = ref('');
const chineseHerbsDoseQuantity = ref('');
const dispensePerDuration = ref('');
const formulaName = ref('');
const sufferingFlag = ref(false);
const methodCode = ref('');
const loading = ref(false);
const rowRules = ref({
conditionDefinitionId: [{ required: true, message: '请选择诊断', trigger: 'change' }],
minUnitQuantity: [{ required: true, message: '请输入单次剂量', trigger: 'change' }],
doseQuantity: [{ required: true, message: '请输入单次剂量单位', trigger: 'change' }],
quantity: [{ required: true, message: '请输入数量', trigger: 'change' }],
dispensePerDuration: [{ required: true, message: '请输入用药天数', trigger: 'change' }],
formulaName: [{ required: true, message: '请输入配方名称', trigger: 'change' }],
executeNum: [{ required: true, message: '请输入执行次数', trigger: 'change' }],
rateCode: [{ required: true, message: '请选择频次', trigger: 'change' }],
methodCode: [{ required: true, message: '请选择给药途径', trigger: 'change' }],
orgId: [{ required: true, message: '请选择执行科室', trigger: 'change' }],
});
const unitMap = ref({
dose: 'dose',
minUnit: 'minUnit',
unit: 'unit',
});
const buttonDisabled = computed(() => {
return !props.patientInfo;
});
const props = defineProps({
patientInfo: {
type: Object,
required: true,
},
activeTab: {
type: String,
},
});
const prescriptionRef = ref();
const stockList = ref([]);
const contractList = ref([]);
const tcmDiagnosisList = ref([]);
const conditionId = ref('');
const checkAll = ref(false);
const { proxy } = getCurrentInstance();
const inputRefs = ref({}); // 存储输入框实例
const requiredProps = ref([]); // 存储必填项 prop 顺序
const totalAmount = ref(0);
const tcmDianosis = ref();
const { method_code, unit_code, rate_code, method_of_decocting_medicine,hjerbal_footnotes,distribution_category_code } = proxy.useDict(
'method_code',
'unit_code',
'rate_code',
'method_of_decocting_medicine',
'hjerbal_footnotes',
'distribution_category_code'
);
const adviceTypeList = ref([
{
label: '西药',
value: 1,
},
{
label: '中成药',
value: 2,
},
{
label: '耗材',
value: 3,
},
{
label: '诊疗',
value: 4,
},
{
label: '全部',
value: '',
},
]);
onMounted(() => {
document.addEventListener('keydown', escKeyListener);
});
onBeforeUnmount(() => {
document.removeEventListener('keydown', escKeyListener);
});
function calculatePrescriptionTotal(pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
if (!prescription.prescriptionList) return 0;
return prescription.prescriptionList
.reduce((total, item) => {
return total + (Number(item.totalPrice) || 0);
}, 0)
.toFixed(2);
}
function getList() {
getDiagnosisDefinitionList(queryParams.value).then((res) => {
total.value = res.data.total;
});
}
function getListInfo(addNewRow) {
// 确保isAdding变量存在
if (typeof isAdding !== 'undefined') {
isAdding.value = false;
}
// 确保有患者信息
if (!props.patientInfo || !props.patientInfo.encounterId) {
console.error('患者信息不完整');
return;
}
getTcmAdviceList({ encounterId: props.patientInfo.encounterId }).then((res) => {
if (res && res.data && Array.isArray(res.data)) {
// 处理返回的数据
if (res.data.length > 0) {
// 如果有数据,清空当前列表并重新添加
tcmPrescriptionList.value = [];
res.data.forEach((item) => {
try {
// 解析contentJson获取完整的医嘱数据
const contentData = item.contentJson ? JSON.parse(item.contentJson) : {};
// 创建一个新的处方对象
const newPrescription = {
...item,
...contentData,
// 确保关键显示字段存在
adviceName: contentData.adviceName || item.adviceName || '',
quantity: contentData.quantity || item.quantity || '',
totalPrice: contentData.totalPrice || item.totalPrice || '',
diagnosisName: contentData.diagnosisName || item.diagnosisName || '',
positionName: contentData.positionName || item.positionName || '',
doseUnitCode_dictText: contentData.doseUnitCode_dictText || item.doseUnitCode_dictText || '',
chineseHerbsDoseQuantity: contentData.chineseHerbsDoseQuantity || item.chineseHerbsDoseQuantity || '',
prescriptionList: [contentData]
};
// 添加到处方列表
tcmPrescriptionList.value.push(newPrescription);
} catch (error) {
console.error('解析医嘱数据失败:', error, '数据项:', item);
}
});
}
// 重新计算总金额
handleTotalAmount();
if (props.activeTab == 'prescription' && addNewRow) {
handleAddMedicine();
}
} else {
console.error('获取医嘱列表失败或数据格式错误:', res);
// 保持当前列表不变,不要清空
}
}).catch(error => {
console.error('获取医嘱列表异常:', error);
// 保持当前列表不变,不要清空
});
tcmDiagnosisList.value = getFromDiagnosis(props.patientInfo.encounterId);
getContract({ encounterId: props.patientInfo.encounterId }).then((res) => {
contractList.value = res?.data || [];
}).catch(error => {
console.error('获取合同信息失败:', error);
});
accountId.value = props.patientInfo.accountId || '';
}
function getDiagnosisInfo() {
diagnosisList.value = [];
getTcmDiagnosis({ encounterId: props.patientInfo.encounterId }).then((res) => {
if (res.data.illness.length > 0) {
res.data.illness.forEach((item, index) => {
diagnosisList.value.push({
name: item.name + '-' + res.data.symptom[index].name,
definitionId: item.definitionId,
encounterDiagnosisId: item.encounterDiagnosisId,
conditionId: item.conditionId,
});
});
}
// 默认选择第一个诊断
if (diagnosisList.value.length > 0) {
const firstDiagnosis = diagnosisList.value[0];
tcmPrescriptionList.value.forEach((prescription) => {
prescription.diagnosisName = firstDiagnosis.name;
prescription.conditionId = firstDiagnosis.conditionId;
prescription.encounterDiagnosisId = firstDiagnosis.encounterDiagnosisId;
prescription.conditionDefinitionId = firstDiagnosis.definitionId;
});
}
});
}
function getRowDisabled(row) {
return row.isEdit;
}
// 新增医嘱
function handleAddMedicine(pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
if (!prescription.conditionId) {
proxy.$modal.msgWarning('请选择诊断');
return;
}
if (prescription.isAdding) {
proxy.$modal.msgWarning('请先保存当前医嘱');
return;
}
prescription.isAdding = true;
let groupId = '';
if (prescription.prescriptionList.length > 0) {
groupId = prescription.prescriptionList[0].groupId;
}
// 在数组最前方添加一行,让新增行显示在最上边
prescription.prescriptionList.unshift({
uniqueKey: prescription.nextId++,
showPopover: false,
check: false,
isEdit: true,
statusEnum: 1,
groupId: groupId,
});
nextTick(() => {
const refName = 'adviceRef' + pIndex + '-0';
if (proxy.$refs[refName] && proxy.$refs[refName][0]) {
proxy.$refs[refName][0].focus();
}
});
}
/**
* 点击行赋值
*/
function clickRow(row) {
emit('selectDiagnosis', row);
}
// 行双击打开编辑块,仅待发送的可编辑
function clickRowDb(row, pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
if (row.statusEnum == 1) {
row = { ...row, ...JSON.parse(row.contentJson), uniqueKey: row.uniqueKey };
row.isEdit = true;
row.doseUnitCode == JSON.parse(JSON.stringify(row.minUnitCode));
const index = prescription.prescriptionList.findIndex(
(item) => item.uniqueKey === row.uniqueKey
);
prescription.prescriptionList[index] = row;
prescription.expandOrder = [row.uniqueKey];
}
}
function handleDiagnosisChange(item, pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
prescription.diagnosisName = item.name;
prescription.conditionId = item.conditionId;
prescription.encounterDiagnosisId = item.encounterDiagnosisId;
}
function handleFocus(row, index, pIndex) {
rowIndex.value = index;
row.showPopover = true;
}
function handleBlur(row) {
row.showPopover = false;
}
function handleChange(value) {
adviceQueryParams.value.searchKey = value;
}
function openDialog() {
tcmDianosis.value.openDialog();
}
function deleteDiagnosisBind(id) {
const data = localStorage.getItem(`tcmDiagnosisList_${props.patientInfo.encounterId}`);
let list = [];
list = JSON.parse(data);
// 添加到列表
const index = list.findIndex((item) => item.id === id);
if (index === -1) return;
list.splice(index, 1);
localStorage.removeItem(`tcmDiagnosisList_${props.patientInfo.encounterId}`);
// 保存到本地缓存
localStorage.setItem(`tcmDiagnosisList_${props.patientInfo.encounterId}`, JSON.stringify(list));
getListInfo();
}
function addNewPrescription(){
tcmPrescriptionList.value.push({})
}
// 删除处方单
function handleDeletePrescriptionClick(prescriptionIndex) {
if (!isPrescriptionDeletable(prescriptionIndex)) {
const medicineCount = getPrescriptionMedicineCount(prescriptionIndex);
if (medicineCount > 0) {
proxy.$modal.msgWarning('该处方单还有药品,请先删除所有药品后再删除处方单');
return;
}
// 检查是否有已签发的药品
const prescription = tcmPrescriptionList.value[prescriptionIndex];
const hasChargedItems = prescription.prescriptionList.some(item => item.statusEnum === 2);
if (hasChargedItems) {
proxy.$modal.msgWarning('该处方单已收费,不能删除');
return;
}
}
// 确认删除
proxy.$modal.confirm('确定要删除这个处方单吗?').then(() => {
tcmPrescriptionList.value.splice(prescriptionIndex, 1);
proxy.$modal.msgSuccess('处方单删除成功');
}).catch(() => {
// 用户取消删除
});
}
// 检查处方是否可删除
function isPrescriptionDeletable(prescriptionIndex) {
const medicineCount = getPrescriptionMedicineCount(prescriptionIndex);
if (medicineCount > 0) {
return false;
}
// 检查是否有已签发的药品
const hasChargedItems = tcmPrescriptionList.value.some(item =>
item.prescriptionList && item.prescriptionList.some(med => med.statusEnum === 2)
);
return !hasChargedItems;
}
// 计算处方总价
function getPrescriptionTotalPrice(prescriptionIndex) {
const prescription = tcmPrescriptionList.value[prescriptionIndex];
let totalPrice = 0;
if (prescription && prescription.prescriptionList) {
prescription.prescriptionList.forEach(item => {
// 使用decimal.js确保精度计算
const quantity = new Decimal(item.minUnitQuantity || 0);
const unitPrice = new Decimal(item.unitPrice || 0);
totalPrice += quantity.mul(unitPrice).toNumber();
});
}
return totalPrice;
}
// 获取处方中的药品数量
function getPrescriptionMedicineCount(prescriptionIndex) {
const prescription = tcmPrescriptionList.value[prescriptionIndex];
if (prescription && prescription.prescriptionList) {
return prescription.prescriptionList.length;
}
return 0;
}
/**
* 选择药品回调
*/
function selectAdviceBase(key, row, pIndex) {
// ... 保持原有逻辑,但使用对应处方的数据 ...
const prescription = tcmPrescriptionList.value[pIndex];
getOrgList();
unitCodeList.value = [];
unitCodeList.value.push({ value: row.unitCode, label: row.unitCode_dictText, type: 'unit' });
if (row.doseUnitCode != row.minUnitCode) {
unitCodeList.value.push({
value: row.doseUnitCode,
label: row.doseUnitCode_dictText,
type: 'dose',
});
}
if (
(row.partAttributeEnum == 1 || row.partAttributeEnum == 3) &&
row.minUnitCode != row.unitCode
) {
unitCodeList.value.push({
value: row.minUnitCode,
label: row.minUnitCode_dictText,
type: 'minUnit',
});
}
if (row.adviceType == 2 && row.minUnitCode != row.unitCode) {
unitCodeList.value.push({
value: row.minUnitCode,
label: row.minUnitCode_dictText,
type: 'minUnit',
});
}
prescription.prescriptionList[rowIndex.value] = {
...prescription.prescriptionList[rowIndex.value],
...JSON.parse(JSON.stringify(row)),
};
prescription.prescriptionList[rowIndex.value].orgId = undefined;
prescription.prescriptionList[rowIndex.value].dose = undefined;
prescription.prescriptionList[rowIndex.value].unitCodeList = unitCodeList.value;
prescription.prescriptionList[rowIndex.value].doseUnitCode = row.doseUnitCode;
prescription.prescriptionList[rowIndex.value].minUnitCode = row.minUnitCode;
prescription.prescriptionList[rowIndex.value].unitCode =
row.partAttributeEnum == 1 ? row.minUnitCode : row.unitCode;
prescription.prescriptionList[rowIndex.value].definitionId = JSON.parse(
JSON.stringify(row)
).chargeItemDefinitionId;
// 库存列表 + 价格列表拼成批次号的下拉框
if (row.adviceType != 3) {
if (row.inventoryList && row.inventoryList.length == 0) {
prescription.expandOrder = [];
proxy.$modal.msgWarning('该项目无库存');
return;
}
stockList.value = row.inventoryList.map((item, index) => {
return { ...item, ...row.priceList[index] };
});
prescription.prescriptionList[rowIndex.value].stockList = stockList.value;
// 获取默认批次号的库存,如果没有让医生重新选
let stock = stockList.value.filter((item) => {
return item.lotNumber == row.defaultLotNumber;
})[0];
if (stock != {} && stock != undefined) {
if (stock.quantity <= 0) {
proxy.$modal.msgWarning('该项目库存不足,请选择其它库房');
// return;
}
prescription.prescriptionList[rowIndex.value].lotNumber = stock.lotNumber;
prescription.prescriptionList[rowIndex.value].inventoryId = stock.inventoryId;
prescription.prescriptionList[rowIndex.value].locationId = stock.locationId;
prescription.prescriptionList[rowIndex.value].unitPrice = stock.price;
prescription.prescriptionList[rowIndex.value].positionName = stock.locationName;
}
} else {
prescription.prescriptionList[rowIndex.value].orgId = JSON.parse(
JSON.stringify(row)
).positionId;
prescription.prescriptionList[rowIndex.value].unitPrice = row.priceList[0].price;
}
prescription.expandOrder = [key];
nextTick(() => {
if (row.adviceType == 1) {
if (row.injectFlag == 1) {
inputRefs.value['executeNum']?.focus();
} else {
inputRefs.value['dose']?.focus();
}
} else {
inputRefs.value['quantity']?.focus();
}
});
}
function getOrgList() {
getOrgTree().then((res) => {
organization.value = res.data.records;
});
}
function handleDelete(pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
let selectRow = prescription.prescriptionList.filter((item) => {
return item.check;
});
if (selectRow.length == 0) {
proxy.$modal.msgWarning('请选择要删除的医嘱');
return;
}
let deleteList = [];
for (let i = prescription.prescriptionList.length - 1; i >= 0; i--) {
let deleteItem = prescription.prescriptionList[i];
// 通过requestId判断是否已保存如果选中项未保存 直接从数组中移除,如果已保存,调接口删除
if (deleteItem.check && deleteItem.statusEnum == 1 && !deleteItem.requestId) {
prescription.prescriptionList.splice(i, 1);
} else if (deleteItem.check && deleteItem.statusEnum == 1 && deleteItem.requestId) {
deleteList.push({
requestId: deleteItem.requestId,
prescriptionNo: deleteItem.prescriptionNo,
dbOpType: '3',
adviceType: deleteItem.adviceType,
});
}
}
if (deleteList.length > 0) {
savePrescription({ adviceSaveList: deleteList }).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('操作成功');
getListInfo(false);
}
});
getListInfo();
} else {
proxy.$modal.msgWarning('所选医嘱不可删除,请先撤回后再删除');
return;
}
prescription.expandOrder = [];
prescription.isAdding = false;
adviceQueryParams.value.adviceType = undefined;
// 删除行会出现组号混乱的情况,所以这里重新更新标记
const allPrescriptions = tcmPrescriptionList.value.flatMap(p => p.prescriptionList);
groupMarkers.value = getGroupMarkers(allPrescriptions);
}
function handleNumberClick(item, index, pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
prescription.prescriptionList[index].unitPrice = item.price;
prescription.prescriptionList[index].locationId = item.locationId;
prescription.prescriptionList[index].positionId = item.locationId;
prescription.prescriptionList[index].positionName = item.locationName;
}
/**
* 签发处方
*/
function handleSave(pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
if (prescription.expandOrder.length > 0) {
proxy.$modal.msgWarning('请先保存当前医嘱');
return;
}
if (
prescription.prescriptionList[0] &&
prescription.prescriptionList[0].isEdit &&
!prescription.prescriptionList[0].adviceType
) {
prescription.prescriptionList.shift();
prescription.isAdding = false;
prescription.expandOrder = [];
}
let saveList = prescription.prescriptionList.filter((item) => {
return item.statusEnum == 1;
});
let validList = saveList.filter((item) => {
return !item.requestId;
});
if (validList.length > 0) {
proxy.$modal.msgWarning('存在未保存的医嘱,请先点击保存按钮后再执行签发');
return;
}
if (saveList.length == 0) {
proxy.$modal.msgWarning('当前无可签发处方');
return;
}
if (!validateGroups(saveList)) {
return;
}
let list = saveList.map((item) => {
return {
...item,
adviceType: item.adviceType,
requestId: item.requestId,
groupId: item.groupId,
patientId: props.patientInfo.patientId,
encounterId: props.patientInfo.encounterId,
accountId: accountId.value,
conditionId: prescription.conditionId,
encounterDiagnosisId: prescription.encounterDiagnosisId,
diagnosisName: prescription.diagnosisName,
dbOpType: '1',
uniqueKey: undefined,
statusEnum: 2,
};
});
signTcmAdvice({
organizationId: props.patientInfo.orgId,
sufferingFlag: prescription.sufferingFlag,
adviceSaveList: list,
})
.then((res) => {
if (res.code === 200) {
proxy.$modal.msgSuccess('保存成功');
getListInfo(false);
prescription.nextId = 1;
}
})
.finally(() => {
loading.value = false;
});
}
// 单行处方保存
function handleSaveSign(row, index) {
try {
// 直接执行保存逻辑,不再进行表单验证
row.isEdit = false;
isAdding.value = false;
expandOrder.value = [];
// 确保必要的字段有值
if (props.patientInfo) {
row.patientId = props.patientInfo.patientId;
row.encounterId = props.patientInfo.encounterId;
}
row.accountId = accountId.value || '';
row.quantity = row.minUnitQuantity || 1; // 确保数量有值
row.conditionId = conditionId.value || '';
row.conditionDefinitionId = conditionDefinitionId.value || '';
row.encounterDiagnosisId = encounterDiagnosisId.value || '';
row.diagnosisName = diagnosisName.value || '';
// 计算单价
if (row.unitCodeList && row.unitCode) {
const unitItem = row.unitCodeList.find((item) => item.value === row.unitCode);
if (unitItem?.type !== 'unit' && row.unitPrice) {
row.unitPrice = new Decimal(row.unitPrice).div(row.partPercent || 1).toFixed(2);
}
}
// 计算总金额
if (row.minUnitQuantity && row.unitPrice) {
row.totalPrice = new Decimal(row.minUnitQuantity).mul(row.unitPrice).toFixed(2);
}
// 确保显示所需的字段都有值
row.adviceName = row.adviceName || '未命名药品';
row.positionName = row.positionName || '默认药房';
// 创建要保存的数据对象,避免循环引用
const saveData = {
...row,
// 排除可能导致循环引用的复杂对象
unitCodeList: undefined,
stockList: undefined,
contentJson: undefined
};
// 序列化数据用于存储
saveData.contentJson = JSON.stringify(saveData);
// 只保存当前行的数据,而不是整个列表
savePrescription({ adviceSaveList: [saveData] }).then((res) => {
if (res && res.code === 200) {
proxy.$modal.msgSuccess('保存成功');
// 此处错误调用getListInfo导致医嘱信息被覆盖从而不显示。
// getListInfo(true);
nextId.value = 1;
} else {
proxy.$modal.msgError('保存失败,请重试');
console.error('保存失败响应:', res);
}
}).catch(error => {
console.error('保存处方失败:', error);
proxy.$modal.msgError('保存失败,请检查网络或联系管理员');
});
} catch (error) {
console.error('处理保存时出错:', error);
proxy.$modal.msgError('操作异常,请重试');
}
}
function handleSaveBatch() {
// 收集所有需要保存的处方项目
let saveList = [];
// 遍历所有处方
for (const prescription of tcmPrescriptionList.value) {
if (prescription.prescriptionList) {
// 检查处方是否有必填的付数
if (!prescription.chineseHerbsDoseQuantity || prescription.chineseHerbsDoseQuantity == 0) {
proxy.$modal.msgWarning('请输入付数');
return;
}
// 收集该处方下需要保存的项目
const itemsToSave = prescription.prescriptionList
.filter((item) => item.statusEnum == 1)
.map((item, index) => {
return {
...item,
accountId: accountId.value,
conditionId: prescription.conditionId,
encounterDiagnosisId: prescription.encounterDiagnosisId,
conditionDefinitionId: prescription.conditionDefinitionId,
encounterId: props.patientInfo.encounterId,
patientId: props.patientInfo.patientId,
requestId: item.requestId,
groupId: item.groupId ? item.groupId : timestamp.toString(),
chineseHerbsDoseQuantity: prescription.chineseHerbsDoseQuantity,
dbOpType: item.requestId ? '2' : '1',
};
});
// 将项目添加到保存列表
saveList = saveList.concat(itemsToSave);
}
}
// 检查是否有可保存的项目
if (saveList.length == 0) {
proxy.$modal.msgWarning('当前没有可保存医嘱');
return;
}
// 保存处方
saveTcmAdvice({ adviceSaveList: saveList }).then((res) => {
if (res.code === 200) {
proxy.$modal.msgSuccess('保存成功');
getListInfo(true);
// 重置所有处方的nextId
tcmPrescriptionList.value.forEach(prescription => {
if (prescription.nextId) {
prescription.nextId = 1;
}
});
}
});
}
// 获取诊断列表
function getFromDiagnosis(encounterId) {
try {
const storageKey = `tcmDiagnosisList_${encounterId}`;
const data = localStorage.getItem(storageKey);
return data ? JSON.parse(data) : null;
} catch (error) {
console.error('从本地缓存读取失败:', error);
return null;
}
}
// 处理回车事件
const handleEnter = (currentProp, row, rowIndex, pIndex) => {
const formRefName = 'formRef' + pIndex + '-' + rowIndex;
proxy.$refs[formRefName].validateField(currentProp, (valid) => {
if (valid) {
const index = requiredProps.value.indexOf(currentProp);
if (index === -1) return;
// 跳转下一个或提交
const nextIndex = index + 1;
if (nextIndex < requiredProps.value.length) {
setTimeout(() => {
const nextProp = requiredProps.value[nextIndex];
inputRefs.value[nextProp]?.focus(); // 直接调用 Element 的 focus 方法
}, 100);
} else {
handleSaveSign(row, rowIndex, pIndex);
}
}
});
};
function escKeyListener(e) {
if (e.key === 'Escape') {
// 查找正在添加的处方
const addingPrescriptionIndex = tcmPrescriptionList.value.findIndex((p) => p.isAdding);
if (addingPrescriptionIndex !== -1) {
const prescription = tcmPrescriptionList.value[addingPrescriptionIndex];
let index;
if (prescription.expandOrder.length > 0) {
index = prescription.prescriptionList.findIndex(
(item) => item.uniqueKey == prescription.expandOrder[0]
);
}
if (index == 0) {
prescription.expandOrder = [];
}
prescription.prescriptionList.shift();
prescription.isAdding = false;
}
}
}
// 签退
function handleSingOut(pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
let requestIdList = prescription.prescriptionList
.filter((item) => {
return item.check && item.statusEnum == 2;
})
.map((item) => {
return item.requestId;
});
if (requestIdList.length == 0) {
proxy.$modal.msgWarning('请选择已签发医嘱撤回');
}
signOutTcmAdvice(requestIdList).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('操作成功');
getListInfo(false);
}
});
}
// 处理行checkbox选中
function handleCheckBoxChange(value, index, row, pIndex) {
const prescription = tcmPrescriptionList.value[pIndex];
// 选中将当前行索引记录下来,取消将当前行索引删除
if (value) {
prescription.groupIndexList.push(index);
} else {
prescription.groupIndexList.splice(prescription.groupIndexList.indexOf(index), 1);
}
// 如果选中或取消行有组号,将全部相同组号的行全部选中,并记录或删除这些行的索引
if (row.groupId) {
// 获取组号相同行
let sameGroupIdList = prescription.prescriptionList.filter((item) => {
return item.groupId == row.groupId;
});
// 如果只有一个组号的情况不做处理
if (sameGroupIdList.length == 1) {
return;
} else {
sameGroupIdList.forEach((item) => {
// 排除掉当前选中行
if (row.uniqueKey != item.uniqueKey) {
// 同步选中状态
let currentIndex = prescription.prescriptionList.findIndex(
(k) => k.uniqueKey == item.uniqueKey
);
prescription.prescriptionList[currentIndex].check = value;
if (value) {
prescription.groupIndexList.push(currentIndex); // 或使用索引或唯一标识
} else if (!value) {
prescription.groupIndexList.splice(
prescription.groupIndexList.indexOf(currentIndex),
1
);
}
}
});
}
}
}
// 校验每个组号数量是否大于5和对应分组金额是否大于500
function validateGroups(saveList) {
// 获取到全部组号和对应的金额
const groups = saveList
.filter((item) => item.groupId != null && item.groupId !== '') // 过滤掉 groupId 为空或空字符串的项
.map((item) => ({
groupId: item.groupId,
totalPrice: item.totalPrice,
}));
// 计算每个组号数量,以及每组金额
const counts = {};
groups.forEach((item) => {
const groupId = item.groupId;
const totalPrice = Number(item.totalPrice);
if (!counts[groupId]) {
counts[groupId] = {
count: 0,
totalPrice: 0,
};
}
counts[groupId].groupId = groupId;
counts[groupId].count++;
counts[groupId].totalPrice += totalPrice;
});
// 获取组数大于5的组号
const countStr = Object.values(counts)
.filter((group) => {
return group.count > 5;
})
.map((group) => group.groupId);
// 获取总金额大于500的组号
const totalStr = Object.values(counts)
.filter((group) => {
return group.totalPrice > 500;
})
.map((group) => group.groupId);
if (countStr.length > 0) {
proxy.$modal.msgWarning('分组"' + countStr + '"数量超出限制');
return false;
} else if (totalStr.length > 0) {
proxy.$modal.msgWarning('分组"' + totalStr + '"金额总和超出限制');
return false;
}
return true;
}
defineExpose({ getListInfo, getDiagnosisInfo });
</script>
<style lang="scss" scoped>
:deep(.el-table__expand-icon) {
display: none !important;
}
.medicine-title {
font-size: 16px;
font-weight: 600;
min-width: 160px;
display: inline-block;
}
.total-amount {
font-size: 16px;
font-weight: 600;
color: #409eff;
white-space: nowrap;
}
.medicine-info {
font-size: 15px;
font-weight: 600;
color: #606266;
white-space: nowrap;
}
.form-group {
display: flex;
align-items: center;
gap: 8px;
background: #fff;
padding: 6px 10px;
border-radius: 4px;
border: 1px solid #ebeef5;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
}
/* 调整element组件默认间距 */
// .el-select,
// .el-input-number {
// margin-right: 0 !important;
// }
.el-input-number .el-input__inner {
text-align: center;
}
.el-table__cell .el-form-item--default {
margin-bottom: 0px;
}
.doctor-station {
color: #606266;
font-size: 14px;
font-weight: 700;
margin-left: 15px;
}
.prescription-section {
background: white;
padding: 0 10px 10px 10px;
margin-bottom: 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.first-prescription {
border-left: 2px solid #409eff;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
}
.section-header .title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
color: #1a2b6d;
}
.section-header .title i {
margin-right: 10px;
font-size: 24px;
}
.summary {
display: flex;
gap: 25px;
}
.summary-item {
background: #f8f9fa;
padding: 8px 15px;
border-radius: 20px;
font-size: 15px;
color: #555;
}
.add-icon {
cursor: pointer;
border-radius: 50%;
padding: 4px;
transition: background-color 0.3s ease;
}
.add-icon:hover {
background-color: #ecf5ff;
}
.delete-icon {
cursor: pointer;
border-radius: 50%;
padding: 4px;
transition: all 0.3s ease;
}
.delete-icon:hover {
background-color: #fef0f0;
}
.delete-icon.disabled-icon {
cursor: not-allowed;
color: #c0c4cc !important;
opacity: 0.6;
}
.delete-icon.disabled-icon:hover {
background-color: transparent;
}
</style>