Files
his/openhis-ui-vue3/src/views/pharmacymanagement/westernmedicine/index.vue

1420 lines
44 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 class="app-container">
<div class="left">
<div class="form">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-position="right"
style="min-width: 500px"
>
<el-form-item label="患者信息" prop="searchKey">
<el-input
v-model="queryParams.searchKey"
placeholder="请输入姓名/证件号"
clearable
style="width: 160px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="发药状态" prop="departmentId" style="margin-left: 10px">
<el-select
v-model="queryParams.statusEnum"
placeholder="请选择发药状态"
clearable
style="width: 160px"
@change="handleQuery"
>
<el-option
v-for="item in dispenseStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="就诊日期">
<el-date-picker
v-model="dateRange"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 250px"
value-format="YYYY-MM-DD"
@change="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="科室" prop="departmentId">
<el-select
v-model="queryParams.departmentId"
placeholder="请选择科室"
clearable
style="width: 160px"
@change="handleQuery"
>
<el-option
v-for="item in departmentList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item> -->
<el-form-item style="margin-left: 15px">
<el-button type="primary" @click="handleQuery">搜索</el-button>
<el-button @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
<el-table
:data="patientList"
border
style="width: 100%; height: 60vh"
highlight-current-row
@row-click="handleCurrentChange"
>
<el-table-column prop="patientName" label="姓名" width="130" align="center"/>
<el-table-column
prop="genderEnum_enumText"
label="性别"
width="80"
align="center"
/>
<el-table-column prop="age" label="年龄" width="80" align="center"/>
<el-table-column prop="phone" label="电话" width="80" align="center"/>
<el-table-column prop="receptionTime" label="就诊日期" align="center">
<template #default="scope">
{{ scope.row.receptionTime ? formatDate(scope.row.receptionTime) : "-" }}
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
<div class="right">
<!-- <div class="select_wrapper_div">
<p style="margin-right: 60px; font-size: 19px">患者基本信息</p> -->
<!-- <el-button type="success" plain @click="print" icon="Printer" style="margin-left: 30px;">打印</el-button> -->
<!-- </div> -->
<div class="top">
<!-- <el-descriptions :column="4" title="患者基本信息">
<el-descriptions-item label="姓名:">{{ personInfo.patientName }}</el-descriptions-item>
<el-descriptions-item label="性别:">
{{ personInfo.genderEnum_enumText }}
</el-descriptions-item>
<el-descriptions-item label="年龄:">{{ personInfo.age }}</el-descriptions-item>
<el-descriptions-item label="合同类型:">
{{ personInfo.categoryEnum_enumText }}
</el-descriptions-item>
<el-descriptions-item label="就诊科室:">
{{ personInfo.organizationName }}
</el-descriptions-item>
<el-descriptions-item label="就诊日期:">
{{ personInfo.encounterDate }}
</el-descriptions-item>
<el-descriptions-item label="证件号:">{{ personInfo.idCard }}</el-descriptions-item>
<el-descriptions-item label="总金额:">
{{ personInfo.totalPrice ? personInfo.totalPrice.toFixed(2) : '0.00' }}
</el-descriptions-item>
</el-descriptions> -->
<!-- <el-row>
<el-col :span="4">姓名{{ personInfo.patientName }}</el-col>
<el-col :span="3">性别{{ personInfo.genderEnum_enumText }}</el-col>
<el-col :span="3">年龄{{ personInfo.age }}</el-col>
<el-col :span="5">合同类型{{ personInfo.categoryEnum_enumText }}</el-col> </el-row
><br />
<el-row>
<el-col :span="5">就诊科室{{ personInfo.organizationName }}</el-col>
<el-col :span="5">就诊日期{{ personInfo.encounterDate }}</el-col>
<el-col :span="7">证件号{{ personInfo.idCard }}</el-col>
</el-row
><br />
<el-row>
<el-col :span="4"
>总金额{{
personInfo.totalPrice ? personInfo.totalPrice.toFixed(2) : '0.00'
}}</el-col
>
</el-row> -->
<span
style="color: #606266; font-size: 14px; font-weight: 700; margin-right: 15px"
>
调配药师
</span>
<el-select v-model="preparerDoctor" placeholder="调配药师" style="width: 160px">
<el-option
v-for="item in preparerDoctorOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<span
style="color: #606266; font-size: 14px; font-weight: 700; margin-right: 15px"
>
药品分类
</span>
<el-select
v-model="tcmFlag"
placeholder="药品分类"
style="width: 160px"
@change="
() => {
if (currentRow.encounterId) {
getMedicineList(currentRow.encounterId);
}
}
"
>
<el-option
v-for="item in medCategoryCode"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<span
style="color: #606266; font-size: 14px; font-weight: 700; margin-right: 15px"
>
项目
</span>
<el-select
v-model="projectTypeCode"
placeholder="项目"
style="width: 160px"
:clearable="false"
@change="
() => {
getList();
if (currentRow) {
getMedicineList(currentRow?.encounterId);
}
}
"
>
<el-option label="全部" value="1"/>
<el-option label="药品" value="2"/>
<el-option label="耗材" value="3"/>
</el-select>
<el-button
:disabled="medicineInfoList && medicineInfoList.length == 0"
type="primary"
@click="handleBatch()"
style="margin-left: 30px"
>
批量发药
</el-button>
<el-button type="primary" @click="handleScan()" style="margin-left: 30px">
扫码
</el-button>
<el-button type="primary" @click="previewAndPrint()" style="margin-left: 30px">
处方打印
</el-button>
<div style="position: absolute; top: 30px; right: 25px">
总金额{{ medicineTotalPrice ? medicineTotalPrice.toFixed(2) : "0.00" }}
</div>
</div>
<el-table
:data="medicineInfoList"
border
style="width: 100%; height: 65vh; margin-top: 10px"
:span-method="spanMethod"
:cell-class-name="cellClassName"
@select="handleSelectionChange"
@cell-dblclick="handleCellDbClick"
v-loading="loading"
ref="tableRef"
>
<el-table-column type="selection" width="55" align="center" fixed="left"/>
<el-table-column prop="prescriptionNo" label="处方号" width="120" align="center"/>
<el-table-column prop="conditionName" label="诊断" width="120" align="center"/>
<el-table-column prop="medTypeCode_dictText" label="处方类型" width="120" align="center"/>
<el-table-column prop="itemName" label="项目名称" width="160" align="center"/>
<el-table-column prop="merchandiseName" label="商品名称" width="160" align="center"/>
<el-table-column prop="quantity" label="发药数量" width="130" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit" style="color: red">
{{ scope.row.quantity }}{{ scope.row.unitCode_dictText }}
</span>
<div class="lot-number-container" v-if="scope.row.isEdit">
<el-input-number
v-model="scope.row.quantity"
controls-position="right"
:controls="false"
>
<template #suffix>
<span>{{ scope.row.unitCode_dictText }}</span>
</template>
</el-input-number>
<el-icon
v-if="scope.row.isEdit"
class="editable-icon confirm-icon"
@click="
() => {
handleQuantity(scope.row);
}
"
>
<Select/>
</el-icon>
</div>
</template>
</el-table-column>
<el-table-column prop="lotNumber" label="批次号" width="160" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit">{{ scope.row.lotNumber }}</span>
<div class="lot-number-container" v-if="scope.row.isEdit">
<el-select
v-model="scope.row.lotNumber"
@change="
(value) => {
scope.row.lotNumber = value;
}
"
>
<el-option
v-for="item in scope.row.inventoryDetailList"
:key="item.inventoryId"
:label="formatLotNumberLabel(scope.row, item)"
:value="item.inventoryLotNumber"
@click="validInventory(scope.row, item)"
/>
</el-select>
<el-icon
v-if="getAdjustPriceSwitchState && scope.row.isEdit"
class="editable-icon confirm-icon"
@click="handleQuantity(scope.row)"
>
<Select/>
</el-icon>
</div>
</template>
</el-table-column>
<el-table-column prop="statusEnum_enumText" label="发药状态" width="100" align="center">
<template #default="scope">
<el-tag :type="tagType(scope.row.statusEnum)">
{{ scope.row.statusEnum_enumText }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="dispensePerDuration" label="天数" width="80" align="center"/>
<!-- <el-table-column prop="flag" label="组合" width="60" align="center" /> -->
<!-- <el-table-column prop="quantity" label="发药数量" width="100" align="center" /> -->
<el-table-column prop="totalVolume" label="规格" width="100" align="center"/>
<!-- <el-table-column prop="unitCode_dictText" label="单位" width="100" align="center" /> -->
<!-- <el-table-column
prop="doseUnitCode_dictText"
label="单次剂量"
width="80"
align="center"
v-if="tcmFlag == '0'"
>
<template #default="scope">
{{ scope.row.dose }}{{ scope.row.doseUnitCode_dictText }}
</template>
</el-table-column> -->
<el-table-column
prop="traceNo"
label="追溯码"
width="180"
align="center"
v-if="tcmFlag == '0'"
>
<template #default="scope">
<el-tooltip
:content="formatContent(scope.row.traceNo)"
placement="top"
popper-class="custom-tooltip"
>
<el-input
:ref="'traceNoRef' + scope.$index"
@input="handleTraceNoInput(scope.row, scope.$index)"
v-model="scope.row.traceNo"
placeholder="请输入追溯码"
/>
</el-tooltip>
</template>
</el-table-column>
<el-table-column
prop="totalPrice"
label="金额"
width="100"
:formatter="formatPrice"
align="right"
header-align="center"
/>
<el-table-column prop="locationName" label="发药药房" width="90" align="center"/>
<el-table-column
prop="manufacturerText"
label="生产厂家"
width="200"
align="center"
/>
<el-table-column prop="doctorName" label="开单医生" width="100" align="center"/>
<!-- <el-table-column prop="dose" label="剂量" width="100" align="center" /> -->
<el-table-column prop="rateCode" label="频次" width="100" align="center"/>
<el-table-column prop="methodCode_dictText" label="用法" width="100" align="center"/>
<el-table-column
label="操作"
align="center"
width="160"
fixed="right"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
link
type="primary"
:disabled="!(scope.row.statusEnum == 2 || scope.row.statusEnum == 14)"
icon="SuccessFilled"
@click="handleBatch(scope.row)"
>
发药
</el-button>
<el-button
link
type="primary"
:disabled="scope.row.statusEnum != 2"
@click="backMedicine(scope.row)"
icon="CircleClose"
>
作废
</el-button>
</template>
</el-table-column>
<!-- <el-table-column prop="performOrg_dictText" label="是否拆零" width="120">
<template #default="scope">
<el-select v-model="scope.row.performOrg_dictText" placeholder="请选择"
@change="handleSelectChange(scope.row)">
<el-option v-for="option in options" :key="option.value" :label="option.label"
:value="option.value"></el-option>
</el-select>
</template>
</el-table-column> -->
<!-- <el-table-column prop="medicationStatusEnum_enumText" label="追溯码" width="100" /> -->
<!-- <el-table-column
prop="unitPrice"
label="单价"
width="100"
:formatter="formatPrice"
align="right"
header-align="center"
/> -->
</el-table>
</div>
<el-dialog title="选择作废原因" v-model="showDialog" width="30%">
<!-- 下拉选择框 -->
<el-select v-model="notPerformedReasonEnum" placeholder="请选择作废原因">
<el-option
v-for="item in backReason"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<!-- 弹窗底部按钮 -->
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="handleConfirm"> </el-button>
<el-button @click="handleCancel"> </el-button>
</span>
</template>
</el-dialog>
<TraceNoDialog
:ypName="ypName"
:openDialog="openTraceNoDialog"
@submit="submit"
@cancel="openTraceNoDialog = false"
/>
</div>
</template>
<script setup name="westernmedicine">
import {onMounted, ref} from 'vue';
import {ElMessage} from 'element-plus';
import {
deviceDispense,
devicePatientList,
getDoctorSignature,
getReportRegisterInit,
itemTraceNo,
listInit,
listPatient,
listWesternmedicine,
prepareMedicion,
updateMedicion,
} from './components/api';
import {advicePrint, getAdjustPriceSwitchState, lotNumberMatch} from '@/api/public';
import {formatDate} from '@/utils/index';
import {debounce} from 'lodash-es';
import TraceNoDialog from '@/components/OpenHis/TraceNoDialog/index.vue';
import {hiprint} from 'vue-plugin-hiprint';
// import templateJson from './components/templateJson.json';
import templateJson from '@/components/Print/Pharmacy.json';
import chineseMedicineTemplateJson from '@/components/Print/ChineseMedicinePrescription.json';
import {formatInventory} from '../../../utils/his';
const {proxy} = getCurrentInstance();
const showSearch = ref(true);
const total = ref(0);
const markers = ref([]);
const patientList = ref([]);
const medicineInfoList = ref([]);
const departmentList = ref([]);
const dateRange = ref([
proxy.formatDateStr(new Date().setMonth(new Date().getMonth() - 1), 'YYYY-MM-DD'),
proxy.formatDateStr(new Date(), 'YYYY-MM-DD'),
]);
const personInfo = ref([]);
const dispenseStatusOptions = ref([]);
const preparerDoctorOptions = ref([]);
const diagnoses = ref("");
const preparerDoctor = ref();
const backReason = ref([]);
const selectedPrescriptionNo = ref("");
const showDialog = ref(false);
const notPerformedReasonEnum = ref();
const currentRow = ref(null);
const tableRef = ref(null);
const selectedGroupIds = ref(new Set());
const selectedItems = ref(new Set());
const traceNoList = ref([]);
const traceNo = ref("");
const traceNoTemp = ref("");
const tcmFlag = ref("0");
const openTraceNo = ref(false);
const isManualSelection = ref(false);
const couldSave = ref(true);
const groups = ref({});
const openTraceNoDialog = ref(false);
const loading = ref(false);
const adjustPriceSwitchState = ref(false);
const ypName = ref('');
const medicineTotalPrice = ref(0);
const projectTypeCode = ref("2");
const selectedRow = ref(null);
const medCategoryCode = ref([
{
label: "西药中成药",
value: "0",
},
{
label: "中药",
value: "1",
},
]);
const data = reactive({
form: {},
queryParams: {
pageNo: 1,
pageSize: 10,
condition: null,
searchKey: '',
departmentId: null,
statusEnum: 3,
classEnum: 2,
},
});
const {queryParams} = toRefs(data);
// 在组件挂载后调用 getList
onMounted(() => {
getList();
});
function handleScan() {
openTraceNoDialog.value = true;
}
function submit(value) {
let list = [];
if (value) {
list = value.split(",");
}
itemTraceNo(list).then((res) => {
if (res.code === 200) {
if (!res.data) {
proxy.$modal.msgWarning("未在库存中匹配到追溯码,请在发药列表中单独扫描");
openTraceNoDialog.value = false;
proxy.$refs["traceNoRef0"].focus();
return;
}
medicineInfoList.value.forEach((item, index) => {
if (
res.data[item.medicineId] &&
res.data[item.medicineId].split(",") > item.quantity
) {
proxy.$modal.msgWarning("操作失败");
return;
}
medicineInfoList.value[index].traceNo = res.data[item.medicineId];
});
openTraceNoDialog.value = false;
}
});
}
function getList() {
queryParams.value.receptionTimeSTime = dateRange.value[0] + ' 00:00:00';
queryParams.value.receptionTimeETime = dateRange.value[1] + ' 23:59:59';
if (projectTypeCode.value == 2) {
listPatient(queryParams.value).then((response) => {
patientList.value = response.data.records;
total.value = response.data.total;
});
} else if (projectTypeCode.value == 3) {
devicePatientList(queryParams.value).then((response) => {
patientList.value = response.data.records;
total.value = response.data.total;
});
} else {
Promise.all([listPatient(queryParams.value), devicePatientList(queryParams.value)]).then(
([patientRes, deviceRes]) => {
// 合并两个接口的数据
const patientRecords = patientRes.data.records || [];
const deviceRecords = deviceRes.data.records || [];
const combinedRecords = [...patientRecords, ...deviceRecords];
// 根据 encounterId 去重
const uniqueRecords = combinedRecords.filter(
(item, index, self) =>
index === self.findIndex((record) => record.encounterId === item.encounterId)
);
patientList.value = uniqueRecords;
// 合并总数量(如果需要精确数量,可能需要后端支持)
total.value = uniqueRecords.length;
}
);
}
listInit().then((response) => {
departmentList.value = [{value: null, label: '全部'}, ...response.data.departmentOptions];
backReason.value = response.data.notPerformedReasonOptions;
dispenseStatusOptions.value = response.data.dispenseStatusOptions;
preparerDoctorOptions.value = response.data.preparerDoctorOptions;
preparerDoctor.value = preparerDoctorOptions.value[0].value;
});
}
async function printPrescription() {
const selectedRows = tableRef.value.getSelectionRows();
if (selectedRows.length === 0) {
proxy.$modal.msgWarning("未选择要打印的项目,请重新选择,打印失败");
return;
}
let requestIds = selectedRows.map((item) => item.requestId).join(",");
const result = [];
advicePrint({requestIds: requestIds, isPrescription: "1"}).then(async (res) => {
const groupedRows = {};
res.data.adviceItemList.forEach((row) => {
const prescriptionNo = row.prescriptionNo;
if (!groupedRows[prescriptionNo]) {
groupedRows[prescriptionNo] = [];
}
row.contractName = res.data.contractName;
groupedRows[prescriptionNo].push(row);
});
// 获取所有唯一的doctorId
const uniqueDoctorIds = [...new Set(selectedRows.map((row) => row.doctorId).filter((id) => id))];
console.log('uniqueDoctorIds:', uniqueDoctorIds);
// 获取所有选择数据医生的签名信息
const doctorSignatures = {};
for (const doctorId of uniqueDoctorIds) {
const signatureResult = await getDoctorSignature({practitionerId: doctorId});
doctorSignatures[doctorId] = signatureResult?.data || '';
}
// 将adviceItemList中的chineseHerbsDoseQuantity字段合并到selectedRows中
if (res.data.adviceItemList && res.data.adviceItemList.length > 0) {
selectedRows.forEach((row) => {
// 查找匹配的adviceItem
const matchingItem = res.data.adviceItemList.find(
(item) =>
item.itemName === row.itemName &&
item.quantity === row.quantity &&
item.prescriptionNo === row.prescriptionNo
);
// 如果找到匹配项添加chineseHerbsDoseQuantity字段
if (matchingItem && matchingItem.chineseHerbsDoseQuantity !== undefined) {
row.chineseHerbsDoseQuantity = matchingItem.chineseHerbsDoseQuantity;
}
});
}
// 使用selectedRows重新分组因为前面使用的是adviceItemList
selectedRows.forEach((row) => {
const prescriptionNo = row.prescriptionNo;
if (!groupedRows[prescriptionNo]) {
groupedRows[prescriptionNo] = [];
}
row.contractName = res.data.contractName;
groupedRows[prescriptionNo].push(row);
});
// 转换为数组形式
const groupedArray = Object.values(groupedRows);
groupedArray.forEach((item, index) => {
const total = item.reduce((sum, item) => {
return sum + (item.totalPrice || 0);
}, 0);
// 获取该处方对应的医生签名使用处方中第一个项目的doctorId
const prescriptionDoctorId = item[0]?.doctorId;
const doctorSignature = prescriptionDoctorId
? doctorSignatures[prescriptionDoctorId] || ''
: '';
result.push({
...res.data,
medTotalAmount: '¥' + total.toFixed(2) + '元',
prescriptionList: item,
// 医生签名图片 - 确保使用处方对应的医生签名
doctorSignature: doctorSignature,
});
});
// 从patientList.value中根据encounterNo查询idCard
result.forEach((item) => {
const encounterNo = item.encounterNo;
const patient = patientList.value.find((p) => p.encounterNo === encounterNo);
if (patient) {
item.idCard = patient.idCard;
}
});
console.log('药房result', result);
// 根据药品分类选择对应的打印模板
const printElements = tcmFlag.value === '1' ? chineseMedicineTemplateJson : templateJson;
var hiprintTemplate = new hiprint.PrintTemplate({template: printElements}); // 定义模板
hiprintTemplate.print2(result, {
height: 210,
width: 148,
});
// 发送任务到打印机成功
hiprintTemplate.on('printSuccess', function (e) {
console.log('打印成功');
});
// 发送任务到打印机失败
hiprintTemplate.on('printError', function (e) {
console.log('打印失败');
});
});
}
// 取消打印机选择
function cancelPrinter() {
showPrinterDialog.value = false;
window.currentPrintData = null;
}
/** 重置按钮操作 */
function resetQuery() {
medicineInfoList.value = [];
personInfo.value = [];
proxy.resetForm("queryRef");
getList();
}
/** 搜索按钮操作 */
function handleQuery() {
if (dateRange.value) {
queryParams.value.receptionTimeSTime = dateRange.value[0] + " 00:00:00";
queryParams.value.receptionTimeETime = dateRange.value[1] + " 23:59:59";
} else {
queryParams.value.receptionTimeSTime = null;
queryParams.value.receptionTimeETime = null;
}
queryParams.value.pageNo = 1;
getList();
}
function formatLotNumberLabel(row, item) {
if (row.unitCode == item.maxUnitCode) {
return (
item.inventoryLotNumber +
' 剩余:' +
formatInventory(
item.inventoryQuantity,
item.partPercent,
item.maxUnitCode_dictText,
item.inventoryUnitCode_dictText
) +
' 有效期至:' +
proxy.formatDateStr(item.expirationDate, 'YYYY-MM-DD')
);
} else {
return (
item.inventoryLotNumber +
' ' +
item.inventoryQuantity +
' ' +
item.inventoryUnitCode_dictText +
' 有效期至:' +
proxy.formatDateStr(item.expirationDate, 'YYYY-MM-DD')
);
}
}
function countGroupRows(data) {
const groupCounts = new Map();
data.forEach((item, index) => {
if (!groupCounts.has(item.prescriptionNo)) {
groupCounts.set(item.prescriptionNo, {count: 0, indices: []});
}
const groupInfo = groupCounts.get(item.prescriptionNo);
groupInfo.count++;
groupInfo.indices.push(index);
});
return groupCounts;
}
function getRowMarkers(groupCounts, data) {
const markers = new Array(data.length).fill('');
groupCounts.forEach((groupInfo, prescriptionNo) => {
const {count, indices} = groupInfo;
if (count === 1) {
// 如果只有一行,不显示标记
return;
}
if (count === 2) {
// 如果有两行,分别显示左右括号
markers[indices[0]] = "┏";
markers[indices[1]] = "┗";
} else {
// 如果有两行以上,第一条显示左括号,中间用竖线,最后一条显示右括号
markers[indices[0]] = "┏";
for (let i = 1; i < indices.length - 1; i++) {
markers[indices[i]] = "┃";
}
markers[indices[indices.length - 1]] = "┗";
}
});
return markers;
}
function spanMethod({row, column, rowIndex, columnIndex}) {
// 定义需要合并的列范围前6列包括selection列
const columnsToMerge = [1, 2, 3, 17]; // 假设selection列是第0列其他列依次是1, 2, 3, 4, 5
// 检查当前列是否在需要合并的列范围内
if (row.prescriptionNo) {
if (columnsToMerge.includes(columnIndex)) {
const prescriptionNo = row.prescriptionNo;
// 查找当前处方号在列表中第一次出现的索引
const firstRowIndex = medicineInfoList.value.findIndex(
(item) => item.prescriptionNo === prescriptionNo
);
// 如果当前行是该处方号的首行则合并count行
if (rowIndex === firstRowIndex) {
// 计算该处方号的总行数
const count = medicineInfoList.value.filter(
(item) => item.prescriptionNo === prescriptionNo
).length;
return [count, 1]; // 合并count行1列
} else {
return [0, 0]; // 其他行不显示
}
}
}
// 其他列不进行合并
return [1, 1];
}
// 单元格类名设置
const cellClassName = ({row, column, rowIndex, columnIndex}) => {
if (columnIndex === 1) {
// 要合并的行数
const sameDeptRows = medicineInfoList.value.filter(
(item) => item.prescriptionNo === row.prescriptionNo
);
// 找到当前行在列表中第一次出现的索引
const firstIndex = medicineInfoList.value.findIndex(
(item) => item.prescriptionNo === row.prescriptionNo
);
// 如果是合并的单元格,添加特殊类名
if (rowIndex === firstIndex && sameDeptRows.length > 1) {
return 'merged-cell colored-cell';
}
}
return '';
};
function handleSelectionChange(selectedRows, currentRow) {
medicineInfoList.value
.filter((item) => {
return item.dispenseId == currentRow.dispenseId;
})
.forEach((item, index) => {
tableRef.value.toggleRowSelection(item, selectedRows.includes(currentRow));
});
}
function handleCellDbClick(row, column, cellValue, event) {
if (
adjustPriceSwitchState.value &&
(column.property == 'lotNumber' || column.property == 'quantity')
) {
row.isEdit = true;
}
}
function formatPrice(row, column, cellValue) {
if (cellValue === null || cellValue === undefined) {
return "0.00 元"; // 如果值为空返回0.00
}
return cellValue.toFixed(2) + " 元"; // 保留两位小数
}
function tagType(statusEnum) {
if (statusEnum == 2 || statusEnum == 2) {
return 'primary';
} else if (statusEnum == 4) {
return "success";
} else if (statusEnum == 5 || statusEnum == 6 || statusEnum == 7) {
return "warning";
} else if (statusEnum == 12) {
return "info";
}
}
function handleCurrentChange(row) {
loading.value = true;
currentRow.value = row; // 更新当前选中行的数据
currentRow.value.statusEnum = undefined;
currentRow.value.dispenseStatus = queryParams.value.statusEnum;
getAdjustPriceSwitchState().then((res) => {
adjustPriceSwitchState.value = res.data;
if (adjustPriceSwitchState.value) {
lotNumberMatch({encounterIdList: row.encounterId})
.then((res) => {
if (res.code == 200) {
getMedicineList(row.encounterId);
}
})
.catch(() => {
loading.value = false;
});
} else {
getMedicineList(row.encounterId);
}
});
}
function getMedicineList(encounterId) {
// 根据projectTypeCode的值决定调用哪些接口
if (projectTypeCode.value == 1) {
// 同时调用两个接口并将数据合并显示
Promise.all([
listWesternmedicine({
pageNo: 1,
pageSize: 100,
encounterId: encounterId,
statusEnum: queryParams.value.statusEnum,
tcmFlag: tcmFlag.value,
}),
getReportRegisterInit({
pageNo: 1,
pageSize: 100,
encounterId: encounterId,
statusEnum: queryParams.value.statusEnum,
tcmFlag: tcmFlag.value,
}),
])
.then(([westernRes, reportRes]) => {
// 合并两个接口的数据
let westernData = Array.isArray(westernRes.data.records)
? westernRes.data.records
: [westernRes.data.records];
let reportData = Array.isArray(reportRes.data.records)
? reportRes.data.records
: [reportRes.data.records];
// 合并数据
medicineInfoList.value = [...westernData, ...reportData];
// 处理合并后的数据
processMedicineListData();
loading.value = false;
})
.catch((error) => {
proxy.$modal.msgError('获取数据失败');
});
} else if (projectTypeCode.value == 2) {
// 只调用listWesternmedicine接口
listWesternmedicine({
pageNo: 1,
pageSize: 100,
encounterId: encounterId,
statusEnum: queryParams.value.statusEnum,
tcmFlag: tcmFlag.value,
}).then((response) => {
// personInfo.value = response.data.prescriptionPatientInfoDto;
medicineInfoList.value = Array.isArray(response.data.records)
? response.data.records
: [response.data.records];
// 处理数据
processMedicineListData();
loading.value = false;
});
} else if (projectTypeCode.value == 3) {
// 只调用getReportRegisterInit接口
getReportRegisterInit({
encounterId: encounterId,
statusEnum: queryParams.value.statusEnum,
tcmFlag: tcmFlag.value,
}).then((response) => {
medicineInfoList.value = Array.isArray(response.data.records)
? response.data.records
: [response.data.records];
// 处理数据
processMedicineListData();
loading.value = false;
});
}
}
// 提取公共的数据处理逻辑
function processMedicineListData() {
// 创建分组映射表
const groupMap = {};
medicineTotalPrice.value = 0;
medicineInfoList.value.forEach((item) => {
const groupId = item.groupId; // 确保属性名一致
medicineTotalPrice.value = medicineTotalPrice.value + item.totalPrice;
if (groupId != null) {
// 过滤掉null/undefined
groupMap[groupId] = groupMap[groupId] || [];
groupMap[groupId].push(item);
}
});
// 处理每个分组
Object.values(groupMap).forEach((group) => {
const count = group.length;
if (count === 2) {
group[0].flag = "┓";
group[1].flag = "┛";
} else if (count > 2) {
group[0].flag = "┓";
group.slice(1, -1).forEach((item) => (item.flag = "┃")); // 中间元素
group[group.length - 1].flag = "┛";
}
});
// 处理没有分组的项
medicineInfoList.value.forEach((item) => {
if (item.groupId == null) {
// 确保属性名一致
item.flag = "";
} else if (!item.flag) {
// 确保所有项都有flag属性
item.flag = "";
}
});
diagnoses.value = medicineInfoList.value.map((item) => item.诊断 || "无").join(", ");
}
function submitMedicine(saveList) {
if (projectTypeCode.value == 1) {
// 根据itemTable分类数据
const deviceList = saveList.filter(
(item) => item.itemTable === "adm_device_definition"
);
const medicineList = saveList.filter(
(item) => item.itemTable === "med_medication_definition"
);
// 并行处理两种类型的发药
const promises = [];
// 如果有耗材数据调用deviceDispense接口
if (deviceList.length > 0) {
promises.push(
deviceDispense(deviceList).then((res) => {
if (res.code != 200) {
throw new Error("耗材发药失败");
}
return res;
})
);
}
let preparationList = medicineList.filter((item) => {
return item.statusEnum == 2;
}); // 待配药列表
let preparedList = medicineList.filter((item) => {
return item.statusEnum == 14;
}); // 已配药列表
// 如果有药品数据调用prepareMedicion接口
if (preparationList.length > 0) {
promises.push(
prepareMedicion(preparationList).then((res) => {
if (res.code != 200) {
throw new Error('药品发药失败');
}
return res;
})
);
}
if (preparedList.length > 0) {
promises.push(
updateMedicion(preparedList).then((res) => {
if (res.code != 200) {
throw new Error("药品发药失败");
}
return res;
})
);
}
// 等待所有发药接口完成
Promise.all(promises)
.then(() => {
// 所有发药都成功后,调用更新接口
if (preparationList.length > 0) {
return updateMedicion(preparationList);
}
})
.then((response) => {
proxy.$modal.msgSuccess("发药成功");
// 重新获取数据
getMedicineList(currentRow.value.encounterId);
})
.catch((error) => {
proxy.$modal.msgError('发药失败: ' + error.message);
});
} else if (projectTypeCode.value == 2) {
let preparationList = saveList.filter((item) => {
return item.statusEnum == 2;
}); // 待配药列表
let preparedList = saveList.filter((item) => {
return item.statusEnum == 14;
}); // 已配药列表
if (preparedList.length > 0) {
updateMedicion(preparedList).then((response) => {
proxy.$modal.msgSuccess('发药成功');
getMedicineList(currentRow.value.encounterId);
});
} else {
prepareMedicion(preparationList).then((res) => {
if (res.code == 200) {
updateMedicion(preparationList).then((response) => {
proxy.$modal.msgSuccess('发药成功');
getMedicineList(currentRow.value.encounterId);
});
}
});
}
} else {
deviceDispense(saveList).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess("发药成功");
getMedicineList(currentRow.value.encounterId);
}
});
}
}
// 校验当前批次库存是否充足
function validInventory(row, item) {
// 统一成小单位数量
let quantity = row.quantity;
if (row.unitCode == item.maxUnitCode) {
quantity = quantity * item.partPercent;
}
if (quantity > item.inventoryQuantity) {
proxy.$modal.msgError('当前批次库存不足');
return;
}
}
// 校验输入发药数量是否大于总数量
function handleQuantity(row) {
// 遍历全部药品列表, 计算出与当前行requestId相同的发药数量总数
let totalQuantity = 0;
medicineInfoList.value.forEach((item) => {
if (item.requestId == row.requestId) {
totalQuantity += item.quantity;
}
});
if (totalQuantity > row.requestQuantity) {
couldSave.value = false;
proxy.$modal.msgError('发药数量不能大于总数量');
} else if (totalQuantity < row.requestQuantity) {
couldSave.value = false;
proxy.$modal.msgError('发药数量不能小于总数量');
} else {
couldSave.value = true;
}
if (couldSave.value) {
row.isEdit = false;
}
}
const throttledGetList = debounce(handelTraceNo, 500);
const traceNoInput = debounce(handleTraceNoInput, 500);
function formatContent(value) {
let content = "";
if (value && value.endsWith(",")) {
value = value.slice(0, -1);
}
if (value) {
value.split(",").forEach((item, index) => {
content += `[${index + 1}] ${item}\n`;
});
return content;
}
}
function handleTraceNoInput(row, index) {
if (row.traceNo) {
// 先移除所有逗号
let cleanStr = row.traceNo.replace(/,/g, "");
// 每20个字符插入一个逗号
let formattedStr = cleanStr.replace(/(.{20})/g, "$1,");
// 如果最后一个字符是逗号则移除
formattedStr = formattedStr.replace(/,$/, "");
row.traceNo = formattedStr;
// 保持输入焦点
proxy.$refs["traceNoRef" + index].focus();
}
}
let inputValue = "";
function handelTraceNo(value) {
traceNoList.value.push(value);
traceNo.value =
traceNo.value + "[" + traceNoList.value.length + "]" + " " + value + "\n";
traceNoTemp.value = "";
// let saveValue = value.substring(inputValue.length + 5, value.length);
// inputValue = value;
// traceNoList.value.push(saveValue);
// traceNo.value = value + '[' + (traceNoList.value.length + 1) + ']' + ' ';
}
function handleBatch(row) {
let saveList = [];
if (row) {
saveList = medicineInfoList.value
.filter((item) => {
return item.prescriptionNo === row.prescriptionNo;
})
.map((item) => {
return {
requestId: item.requestId,
dispenseId: item.dispenseId,
traceNo: item.traceNo,
prescriptionNo: item.prescriptionNo,
preparerId: preparerDoctor.value,
itemTable: item.itemTable,
statusEnum: item.statusEnum,
quantity: item.quantity,
lotNumber: item.lotNumber,
};
});
} else {
if (tableRef.value.getSelectionRows().length > 0) {
saveList = tableRef.value.getSelectionRows().map((item) => {
return {
requestId: item.requestId,
dispenseId: item.dispenseId,
traceNo: item.traceNo,
prescriptionNo: item.prescriptionNo,
preparerId: preparerDoctor.value,
itemTable: item.itemTable,
statusEnum: item.statusEnum,
quantity: item.quantity,
lotNumber: item.lotNumber,
};
});
} else {
proxy.$modal.msgWarning('未选择要发药的项目,请重新选择,发药失败');
return;
}
}
submitMedicine(saveList);
}
function backMedicine(row) {
showDialog.value = true;
selectedPrescriptionNo.value = row.dispenseId;
selectedRow.value = row;
console.log("作废原因:", selectedPrescriptionNo.value, row.prescriptionNo);
}
function handleCancel() {
showDialog.value = false;
notPerformedReasonEnum.value = ""; // 清空选择
}
// ✅ 更完善的版本
async function handleConfirm() {
// 统一验证
const validationResult = validate();
if (!validationResult.success) {
ElMessage.error(validationResult.message);
return;
}
const loading = ElLoading.service({text: "作废中..."});
try {
const params = buildParams();
await performInvalidOperation(params);
await handleSuccess();
} catch (error) {
handleError(error);
} finally {
loading.close();
}
}
// 分离验证逻辑
function validate() {
if (!notPerformedReasonEnum.value) {
return {success: false, message: "请选择作废原因"};
}
if (!selectedRow.value) {
return {success: false, message: "未选择数据"};
}
return {success: true};
}
</script>
<style lang="scss" scoped>
.app-container {
padding: 20px;
display: flex;
}
.left {
width: 25%;
.form {
width: 100%;
display: flex;
justify-content: space-between;
}
}
.right {
margin-left: 2%;
width: 74%;
}
/* 表格文字颜色改为纯黑色 */
:deep(.el-table) {
td,
th {
color: #000000 !important;
}
.el-table__cell {
color: #000000 !important;
}
tbody tr td {
color: #000000 !important;
}
thead tr th {
color: #000000 !important;
}
}
:deep(.el-table tbody tr:hover > td) {
background-color: inherit !important;
}
.el-form--inline .el-form-item {
margin-right: 0px;
}
:deep(.el-textarea .el-textarea__inner) {
resize: none !important;
}
/* 添加图标悬停样式 */
.editable-icon {
transition: color 0.3s ease;
}
.editable-icon:hover {
color: #409eff; /* Element Plus 主题色,可根据需要调整 */
cursor: pointer;
}
/* 批次号容器样式 */
.lot-number-container {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
/* 确认图标样式 */
.confirm-icon {
transition: color 0.3s ease;
margin-left: 5px;
}
.confirm-icon:hover {
color: #409eff;
cursor: pointer;
}
/* 合并单元格基础样式 */
:deep(.merged-cell) {
text-align: center;
font-weight: bold;
}
/* 变色样式 */
:deep(.colored-cell) {
background-color: #e6f7ff !important; /* 浅蓝色 */
border-left: 3px solid #1890ff !important;
}
:deep(.el-table--border::after),
:deep(.el-table--group::after),
:deep(.el-table::before) {
background-color: #dddde0;
}
:deep(.el-table td),
:deep(.el-table th.is-leaf) {
border-color: #dddde0;
}
:deep(.el-table--border th),
::v-deep .el-table--border th.gutter:last-of-type {
border-color: #dddde0;
}
</style>