Files
his/openhis-ui-vue3/src/views/surgicalschedule/index.vue
zhaoyun 22b47fcc95 fix: 修复前端Bug#431 #433 #434 #435
#431 会诊申请单:标签文案修改「需要病员及会诊目的」为「简要病史及会诊目的」
#433 手术安排编辑:麻醉方法回显为代码 - 添加Number类型转换
#434 手术安排编辑:切口类型未回显 - 添加Number类型转换
#435 手术安排编辑:费用类别未回显 - 确保字段正确赋值
2026-04-24 14:39:49 +08:00

2243 lines
86 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">
<!-- 顶部筛选区 -->
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" class="query-form">
<el-form-item label="手术单号" prop="operCode">
<el-input
v-model="queryParams.operCode"
placeholder="请输入手术单号"
clearable
@keyup.enter="handleQuery"
style="width: 200px"
/>
</el-form-item>
<el-form-item label="安排时间" prop="scheduleDateRange">
<el-date-picker
v-model="queryParams.scheduleDateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 240px"
/>
</el-form-item>
<el-form-item label="卫生机构" prop="tenantId">
<el-select v-model="queryParams.tenantId" placeholder="请选择卫生机构" style="width: 200px">
<el-option
v-for="item in orgList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="申请科室" prop="applyDeptId">
<el-select v-model="queryParams.applyDeptId" placeholder="请选择申请科室" style="width: 200px">
<el-option
v-for="item in deptList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="姓名/拼音码" prop="patientName">
<el-input
v-model="queryParams.patientName"
placeholder="请输入姓名/拼音码"
clearable
@keyup.enter="handleQuery"
style="width: 200px"
/>
</el-form-item>
<el-form-item class="search-buttons">
<el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"> 新增手术安排 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Money" @click="handleChargeCharge(selectedRow)" :disabled="!selectedRow"> 计费 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Document" @click="handleMedicalAdvice(selectedRow)" :disabled="!selectedRow"> 医嘱 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Download" @click="handleExport">导出表格</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 中部表格区 -->
<el-table v-loading="loading" :data="surgeryList" row-key="scheduleId" :row-class-name="getRowClassName" @current-change="handleCurrentChange">
<el-table-column label="手术单号" align="center" prop="operCode" width="180" show-overflow-tooltip>
<template #default="scope">
<el-link type="primary" :underline="false" @click="handleView(scope.row)">
{{ scope.row.operCode }}
</el-link>
</template>
</el-table-column>
<el-table-column label="ID" align="center" width="80">
<template #default="{ $index }">
{{ (applyQueryParams.pageNo - 1) * applyQueryParams.pageSize + $index + 1 }}
</template>
</el-table-column>
<el-table-column label="卫生机构" align="center" prop="orgName" width="120" show-overflow-tooltip />
<el-table-column label="姓名" align="center" prop="patientName" width="100" />
<el-table-column label="就诊卡号" align="center" prop="identifierNo" width="120" />
<el-table-column label="手术名称" align="center" prop="operName" min-width="140" show-overflow-tooltip />
<el-table-column label="申请科室" align="center" prop="applyDeptName" width="100" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.applyDeptName || '-' }}
</template>
</el-table-column>
<el-table-column label="手术类型" align="center" width="100">
<template #default="scope">
{{ getSurgeryTypeName(scope.row.surgeryNature) }}
</template>
</el-table-column>
<el-table-column label="手术性质" align="center" width="100">
<template #default="scope">
{{ getSurgeryTypeName(scope.row.surgeryNature) }}
</template>
</el-table-column>
<el-table-column label="主刀医生" align="center" width="100" prop="surgeonName"/>
<el-table-column label="麻醉方法" align="center" width="120">
<template #default="scope">
{{ getAnesthesiaName(scope.row.anesMethod) }}
</template>
</el-table-column>
<el-table-column label="安排时间" align="center" prop="scheduleDate" width="140">
<template #default="scope">
{{ parseTime(scope.row.scheduleDate, '{y}-{m}-{d} {h}:{i}:{s}') }}
</template>
</el-table-column>
<el-table-column label="操作人" align="center" width="100" prop="createByName" />
<el-table-column label="操作" align="center" width="240" fixed="right">
<template #default="scope">
<el-button link type="primary" @click="handleView(scope.row)">查看</el-button>
<el-button link type="primary" @click="handleEdit(scope.row)">编辑</el-button>
<el-button link type="danger" @click="handleDelete(scope.row)" v-hasPermi="['surgicalSchedule:delete']">取消</el-button>
</template>
</el-table-column>
</el-table>
<!-- 底部分页区 -->
<div class="pagination-container">
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getPageList"
/>
</div>
<!-- 手术安排弹窗 -->
<el-dialog :title="title" v-model="open" width="1200px" @close="cancel" append-to-body :close-on-click-modal="false">
<!-- 弹窗头部操作按钮 -->
<div class="dialog-header-buttons" v-if="!isViewMode && !isEditMode">
<el-button @click="handleFindApply">查找</el-button>
<el-button class="refresh-btn" @click="handleRefresh">刷新</el-button>
<el-button @click="cancel">返回</el-button>
<el-button type="primary" :disabled="isViewMode" @click="submitForm">保存</el-button>
</div>
<!-- 表单内容区 -->
<el-form ref="surgeryRef" :model="form" :rules="rules" label-width="120px" :disabled="isViewMode">
<!-- 病人基本信息组 -->
<el-divider content-position="left">病人基本信息</el-divider>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="患者id" prop="patientId">
<el-tooltip :content="form.patientId" placement="top" :disabled="!form.patientId">
<el-input v-model="form.patientId" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="就诊卡号" prop="identifierNo">
<el-tooltip :content="form.identifierNo" placement="top" :disabled="!form.identifierNo">
<el-input v-model="form.identifierNo" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="姓名" prop="patientName">
<el-tooltip :content="form.patientName" placement="top" :disabled="!form.patientName">
<el-input v-model="form.patientName" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="性别" width="80">
<el-tooltip :content="form.gender == 0 ? '男' : form.gender == 1 ? '女' : ''" placement="top" :disabled="!form.gender">
<el-input :value="form.gender == 0 ? '男' : form.gender == 1 ? '女' : form.gender=='男'?'男': form.gender=='女'?'女':''" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="年龄" prop="age">
<el-tooltip :content="form.age" placement="top" :disabled="!form.age">
<el-input v-model="form.age" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="病人体重" prop="patientWeight">
<el-input v-model="form.patientWeight" placeholder="请输入病人体重kg" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="病人身高" prop="patientHeight">
<el-input v-model="form.patientHeight" placeholder="请输入病人身高cm" />
</el-form-item>
</el-col>
</el-row>
<!-- 手术申请信息组 -->
<el-divider content-position="left">手术申请信息</el-divider>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="手术单号" prop="surgeryNo">
<el-tooltip :content="form.surgeryNo" placement="top" :disabled="!form.surgeryNo">
<el-input v-model="form.surgeryNo" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="手术类型" prop="surgeryType">
<el-select v-model="form.surgeryType" placeholder="请选择手术类型" style="width: 100%">
<el-option
v-for="item in surgery_type"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="费用类别" prop="feeType">
<el-tooltip :content="form.feeType" placement="top" :disabled="!form.feeType">
<el-input v-model="form.feeType" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申请时间" prop="applyTime">
<el-tooltip :content="formattedApplyTime" placement="top" :disabled="!form.applyTime">
<el-input v-model="formattedApplyTime" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申请医生" prop="applyDoctorName">
<el-tooltip :content="form.applyDoctorName" placement="top" :disabled="!form.applyDoctorName">
<el-input v-model="form.applyDoctorName" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="手术名称" prop="operName">
<el-tooltip :content="form.operName" placement="top" :disabled="!form.operName">
<el-input v-model="form.operName" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申请科室" prop="applyDeptName">
<el-tooltip :content="form.applyDeptName" placement="top" :disabled="!form.applyDeptName">
<el-input v-model="form.applyDeptName" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
</el-row>
<!-- 手术安排组 -->
<el-divider content-position="left">手术安排</el-divider>
<el-row :gutter="20">
<el-col :span="10">
<el-form-item label="安排时间" prop="scheduleDate">
<el-date-picker
v-model="form.scheduleDate"
type="datetime"
placeholder="选择安排时间"
value-format="YYYY-MM-DD HH:mm:ss"
format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="手术台次" prop="sequenceNo">
<el-input v-model.number="form.sequenceNo" placeholder="请输入手术台次" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="手术间号" prop="roomCode">
<el-select v-model="form.roomCode" placeholder="请选择手术间号" style="width: 100%">
<el-option
v-for="item in operatingRoomList"
:key="item.roomCode"
:label="item.roomCode"
:value="item.roomCode"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="10">
<el-form-item label="手术台" prop="tableNo">
<el-input v-model.number="form.tableNo" placeholder="请输入手术台" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="是否首次手术" prop="isFirstSurgery" >
<el-radio-group v-model="form.isFirstSurgery">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<!-- 手术性质和部位 -->
<el-divider content-position="left">手术性质和部位</el-divider>
<el-row :gutter="20">
<el-col :span="10">
<el-form-item label="手术性质" prop="surgeryNature">
<el-select v-model="form.surgeryNature" placeholder="请选择手术性质" style="width: 100%">
<el-option
v-for="item in surgery_type"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="手术部位" prop="surgerySite">
<el-select v-model="form.surgerySite" placeholder="请选择手术部位" style="width: 100%">
<el-option
v-for="item in surgerySiteList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="过敏药物" prop="isAllergyMedication">
<el-radio-group v-model="form.isAllergyMedication">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="过敏药物备注" prop="allergyRemark">
<el-input v-model="form.allergyRemark" type="textarea" placeholder="请输入过敏药物备注" :rows="3" />
</el-form-item>
</el-col>
</el-row>
<!-- 医护人员组 -->
<el-divider content-position="left">医护人员</el-divider>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="主刀医生" prop="surgeonCode">
<el-tooltip :content="form.surgeonName" placement="top" :disabled="!form.surgeonName">
<el-input v-model="form.surgeonName" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="助手1" prop="assistant1Code">
<el-select v-model="form.assistant1Code" placeholder="请选择助手1" filterable style="width: 100%">
<el-option
v-for="item in doctorList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="助手2" prop="assistant2Code">
<el-select v-model="form.assistant2Code" placeholder="请选择助手2" filterable style="width: 100%">
<el-option
v-for="item in doctorList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="助手3" prop="assistant3Code">
<el-select v-model="form.assistant3Code" placeholder="请选择助手3" filterable style="width: 100%">
<el-option
v-for="item in doctorList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="洗手护士" prop="scrubNurseCode">
<el-select v-model="form.scrubNurseCode" placeholder="请选择洗手护士" filterable style="width: 100%">
<el-option
v-for="item in nurseList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="器械护士1" prop="scrubNurse1Code">
<el-select v-model="form.scrubNurse1Code" placeholder="请选择器械护士1" filterable style="width: 100%">
<el-option
v-for="item in nurseList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="器械护士2" prop="scrubNurse2Code">
<el-select v-model="form.scrubNurse2Code" placeholder="请选择器械护士2" filterable style="width: 100%">
<el-option
v-for="item in nurseList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="巡回护士1" prop="circuNurse1Code">
<el-select v-model="form.circuNurse1Code" placeholder="请选择巡回护士1" filterable style="width: 100%">
<el-option
v-for="item in nurseList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="麻醉方法" prop="anesMethod">
<el-select v-model="form.anesMethod" placeholder="请选择麻醉方法" style="width: 100%">
<el-option
v-for="item in anesthesiaList"
:key="item.value"
:label="item.label"
:value="Number(item.value)"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="巡回护士2" prop="circuNurse2Code">
<el-select v-model="form.circuNurse2Code" placeholder="请选择巡回护士2" filterable style="width: 100%">
<el-option
v-for="item in nurseList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="外请专家" prop="isExternalExpert">
<el-radio-group v-model="form.isExternalExpert">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="外请专家姓名" prop="externalExpertName">
<el-input v-model="form.externalExpertName" placeholder="请输入外请专家姓名" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="10">
<el-form-item label="麻醉医师1" prop="anesDoctor1Code">
<el-select v-model="form.anesDoctor1Code" placeholder="请选择麻醉医师1" filterable style="width: 100%">
<el-option
v-for="item in doctorList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="麻醉医师2" prop="anesDoctor2Code">
<el-select v-model="form.anesDoctor2Code" placeholder="请选择麻醉医师2" filterable style="width: 100%">
<el-option
v-for="item in doctorList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="麻醉医师3" prop="anesDoctor3Code">
<el-select v-model="form.anesDoctor3Code" placeholder="请选择麻醉医师3" filterable style="width: 100%">
<el-option
v-for="item in doctorList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="术前诊断" prop="preoperativeDiagnosis">
<el-input v-model="form.preoperativeDiagnosis" placeholder="请输入术前诊断" />
</el-form-item>
<el-form-item label="术后诊断" prop="postoperativeDiagnosis">
<el-input v-model="form.postoperativeDiagnosis" placeholder="请输入术后诊断" />
</el-form-item>
<!-- 手术过程组 -->
<el-divider content-position="left">手术过程</el-divider>
<el-row :gutter="20">
<el-col :span="10">
<el-form-item label="入室时间" prop="admissionTime">
<el-date-picker
v-model="form.admissionTime"
type="datetime"
placeholder="选择入室时间"
value-format="YYYY-MM-DDTHH:mm:ss"
format="YYYY-MM-DD HH:mm"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="进室时间" prop="entryTime">
<el-date-picker
v-model="form.entryTime"
type="datetime"
placeholder="选择进室时间"
value-format="YYYY-MM-DDTHH:mm:ss"
format="YYYY-MM-DD HH:mm"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="麻醉开始时间" prop="anesStart">
<el-date-picker
v-model="form.anesStart"
type="datetime"
placeholder="选择麻醉开始时间"
value-format="YYYY-MM-DDTHH:mm:ss"
format="YYYY-MM-DD HH:mm"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="10">
<el-form-item label="切开时间" prop="startTime">
<el-date-picker
v-model="form.startTime"
type="datetime"
placeholder="选择切开时间"
value-format="YYYY-MM-DDTHH:mm:ss"
format="YYYY-MM-DD HH:mm"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="手术结束时间" prop="endTime">
<el-date-picker
v-model="form.endTime"
type="datetime"
placeholder="选择手术结束时间"
value-format="YYYY-MM-DDTHH:mm:ss"
format="YYYY-MM-DD HH:mm"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="麻醉结束时间" prop="anesEnd">
<el-date-picker
v-model="form.anesEnd"
type="datetime"
placeholder="选择麻醉结束时间"
value-format="YYYY-MM-DDTHH:mm:ss"
format="YYYY-MM-DD HH:mm"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="切口类型" prop="incisionType">
<el-select v-model="form.incisionType" placeholder="请选择切口类型" style="width: 100%">
<el-option
v-for="item in incisionTypeList"
:key="item.value"
:label="item.label"
:value="Number(item.value)"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="感染诊断" prop="infectionDiagnosis">
<el-input v-model="form.infectionDiagnosis" placeholder="请输入感染诊断" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="隔离种类" prop="isolationType">
<el-input v-model="form.isolationType" placeholder="请输入隔离种类" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="是否植入标志" prop="implantFlag">
<el-radio-group v-model="form.implantFlag">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="植入物序列号/批号" prop="implantSerial">
<el-input v-model="form.implantSerial" placeholder="请输入植入物序列号/批号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出血量" prop="bloodLoss">
<el-input v-model="form.bloodLoss" placeholder="请输入出血量" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="输血量" prop="bloodTrans">
<el-input v-model="form.bloodTrans" placeholder="请输入输血量" />
</el-form-item>
</el-col>
</el-row>
<!-- 备注信息组 -->
<el-divider content-position="left">备注信息</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="手术相关对话信息" prop="communicationInfo">
<el-input v-model="form.communicationInfo" type="textarea" placeholder="请输入手术相关对话信息" :rows="3" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手术相关备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入手术相关备注" :rows="3" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 底部操作区 -->
<template #footer>
<div class="dialog-footer" v-if="!isViewMode">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="submitForm">保存</el-button>
</div>
</template>
</el-dialog>
<!-- 手术申请查询弹窗 -->
<el-dialog :title="'手术申请查询'" v-model="showApplyDialog" width="1200px" @close="cancelApplyDialog">
<!-- 查询条件区 -->
<el-form :model="applyQueryParams" ref="applyQueryRef" :inline="true" class="query-form">
<el-form-item label="手术单号" prop="surgeryNo">
<el-input
v-model="applyQueryParams.surgeryNo"
placeholder="请输入手术单号"
clearable
@keyup.enter="handleApplyQuery"
style="width: 200px"
/>
</el-form-item>
<el-form-item label="申请时间范围" prop="applyTimeRange">
<el-tooltip :content="applyQueryParams.applyTimeRange ? applyQueryParams.applyTimeRange.join(' 至 ') : ''" placement="top" :disabled="!applyQueryParams.applyTimeRange || applyQueryParams.applyTimeRange.length === 0">
<el-date-picker
v-model="applyQueryParams.applyTimeRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 240px"
/>
</el-tooltip>
</el-form-item>
<el-form-item label="申请科室" prop="applyDeptId">
<el-select v-model="applyQueryParams.applyDeptId" placeholder="请选择申请科室" style="width: 150px">
<el-option
v-for="item in deptList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="主刀医生" prop="mainDoctorId">
<el-select v-model="applyQueryParams.mainDoctorId" placeholder="请选择主刀医生" style="width: 150px">
<el-option
v-for="item in doctorList"
:key="item.code"
:label="item.name"
:value="item.code"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleApplyQuery">查询</el-button>
<el-button icon="Refresh" @click="resetApplyQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 结果表格区 -->
<el-table
ref="applyTableRef"
v-loading="applyLoading"
:data="applyList"
row-key="surgeryNo"
@row-click="handleApplyRowClick"
:row-class-name="tableRowClassName"
style="width: 100%"
max-height="400"
:scroll="{ y: 400 }"
>
<el-table-column type="selection" width="55" :selectable="handleSelectable" />
<el-table-column label="ID" align="center" width="80" fixed>
<template #default="{ $index }">
{{ (applyQueryParams.pageNo - 1) * applyQueryParams.pageSize + $index + 1 }}
</template>
</el-table-column>
<el-table-column label="姓名" align="center" prop="name" width="100" />
<el-table-column label="手术单号" align="center" prop="surgeryNo" width="120" />
<el-table-column label="手术名称" align="center" prop="descJson.surgeryName" min-width="140" show-overflow-tooltip />
<el-table-column label="申请科室" align="center" width="100" prop="applyDeptName" />
<el-table-column label="手术类型" align="center" width="90">
<template #default="scope">
{{ getSurgeryTypeName(scope.row.surgeryType) }}
</template>
</el-table-column>
<el-table-column label="手术等级" align="center" width="90">
<template #default="scope">
{{ getSurgeryLevelName(scope.row.surgeryLevel || scope.row.descJson?.surgeryLevel) }}
</template>
</el-table-column>
<el-table-column label="麻醉方式" align="center" width="90">
<template #default="scope">
{{ getAnesthesiaName(scope.row.anesthesiaTypeEnum) }}
</template>
</el-table-column>
<el-table-column label="主刀医生" align="center" width="100" prop="mainSurgeonName" />
</el-table>
<!-- 底部分页区 -->
<div class="pagination-container" style="margin-top: 10px; padding-bottom: 10px">
<pagination
v-show="applyTotal > 0"
:total="applyTotal"
:page="applyQueryParams.pageNo"
:limit="applyQueryParams.pageSize"
@update:page="val => applyQueryParams.pageNo = val"
@update:limit="val => applyQueryParams.pageSize = val"
@pagination="getSurgicalScheduleList"
/>
</div>
<!-- 底部操作区 -->
<template #footer>
<div class="dialog-footer">
<el-button @click="cancelApplyDialog">取消</el-button>
<el-button type="primary" @click="confirmApply">确认</el-button>
</div>
</template>
</el-dialog>
<!-- 手术计费弹窗 -->
<el-dialog :title="chargeDialogTitle" v-model="showChargeDialog" width="1400px" @close="closeChargeDialog" append-to-body>
<div style="display: flex; justify-content: space-between; height: 80vh">
<div style="width: 100%; border: 1px solid #eee; position: relative">
<div style="padding: 10px; border: 1px solid #eee; height: 50px; border-left: 0">
<el-descriptions :column="4">
<el-descriptions-item label="患者信息:" width="150">
{{
Object.keys(chargePatientInfo).length !== 0
? chargePatientInfo.patientName +
' / ' +
chargePatientInfo.age +
' / ' +
chargePatientInfo.genderEnum_enumText +
' / ' +
chargePatientInfo.typeCode_dictText
: '-'
}}
</el-descriptions-item>
<el-descriptions-item label="安排时间" width="150">
{{ Object.keys(chargePatientInfo).length !== 0 ? formatChargeDate(chargePatientInfo.registerTime) : '-' }}
</el-descriptions-item>
<el-descriptions-item label="计费账号" width="150">{{ userStore.name }}</el-descriptions-item>
<el-descriptions-item label="手术名称" width="150">{{ chargeSurgeryInfo.surgeryName }}</el-descriptions-item>
</el-descriptions>
</div>
<div style="padding: 10px">
<prescriptionlist :patientInfo="chargePatientInfo" ref="prescriptionRef" />
<div class="overlay" v-if="disabled"></div>
</div>
</div>
</div>
</el-dialog>
<!-- 临时医嘱弹窗 -->
<el-dialog title="" v-model="showTemporaryMedical" width="80%" append-to-body :close-on-click-modal="false">
<!-- 🔧 新增加载状态提示 -->
<div v-if="temporaryMedicalLoading" class="loading-container">
<el-icon class="is-loading"><loading /></el-icon>
<span>正在加载医嘱数据请稍候...</span>
</div>
<temporary-medical
v-else
:patient-info="temporaryPatientInfo"
:billing-medicines="temporaryBillingMedicines"
v-model:temporary-advices="temporaryAdvices"
@submit="handleTemporaryMedicalSubmit"
@cancel="handleTemporaryMedicalCancel"
@refresh="handleTemporaryMedicalRefresh"
@quote-billing="handleQuoteBilling"
/>
</el-dialog>
</div>
</template>
<script setup name="SurgicalSchedule">
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue'
import { getCurrentInstance } from 'vue'
import { parseTime } from '@/utils/openhis'
import { useDict } from '@/utils/dict'
import download from '@/plugins/download'
import Prescriptionlist from '@/views/clinicmanagement/bargain/component/prescriptionlist.vue'
import useUserStore from '@/store/modules/user'
import { ElMessage } from 'element-plus'
import { Loading } from '@element-plus/icons-vue' // 🔧 新增:导入 Loading 图标
// 导入计费相关接口
import { getPrescriptionList } from '@/views/clinicmanagement/bargain/component/api'
// API 导入
import { getSurgerySchedulePage, addSurgerySchedule, updateSurgerySchedule, deleteSurgerySchedule, getSurgeryScheduleDetail } from '@/api/surgicalschedule'
import { listUser } from '@/api/system/user'
import { deptTreeSelect } from '@/api/system/user'
import { listOperatingRoom } from '@/api/operatingroom'
import { getTestResultPage} from '@/views/inpatientDoctor/home/components/applicationShow/api.js'
import { getTenantPage } from '@/api/system/tenant'
import { getContract } from '@/views/inpatientDoctor/home/components/api.js'
import SurgeryCharge from '../charge/surgerycharge/index.vue'
import TemporaryMedical from './temporaryMedical.vue'
const { proxy } = getCurrentInstance()
const userStore = useUserStore()
const loading = ref(true)
const showSearch = ref(true)
const surgeryList = ref([])
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
scheduleDateRange: [],
scheduleDateStart: undefined,
scheduleDateEnd: undefined,
tenantId: undefined,
applyDeptId: undefined,
patientName: undefined,
operCode: undefined
})
const open = ref(false)
const isEditMode = ref(false)
const isViewMode = ref(false)
// 选中行状态管理
const selectedRow = ref(null)
const selectedRowIndex = ref(-1)
const form = reactive({
scheduleId:undefined,
applyId: undefined,
patientId: undefined,
visitId: undefined,
identifierNo: undefined,
operCode: undefined,
operName: undefined,
preoperativeDiagnosis: undefined,
postoperativeDiagnosis: undefined,
scheduleDate: undefined,
sequenceNo: undefined,
isFirstSurgery: 0,
isAllergyMedication: 0,
allergyRemark: undefined,
surgeryNature: undefined,
surgerySite: undefined,
incisionLevel: undefined,
surgeryLevel: undefined,
admissionTime: undefined,
entryTime: undefined,
roomCode: undefined,
tableNo: undefined,
anesMethod: undefined,
anesDoctor1Code: undefined,
anesDoctor2Code: undefined,
anesDoctor3Code: undefined,
scrubNurseCode: undefined,
circuNurse1Code: undefined,
circuNurse2Code: undefined,
scrubNurse1Code: undefined,
scrubNurse2Code: undefined,
surgeonCode: undefined,
assistant1Code: undefined,
assistant2Code: undefined,
assistant3Code: undefined,
startTime: undefined,
endTime: undefined,
anesStart: undefined,
anesEnd: undefined,
operStatus: 0,
implantFlag: 0,
implantSerial: undefined,
bloodLoss: undefined,
bloodTrans: undefined,
infectionDiagnosis: undefined,
isolationType: undefined,
patientWeight: undefined,
patientHeight: undefined,
communicationInfo: undefined,
remark: undefined,
createTime: undefined,
creatorId: undefined,
patientName: undefined,
gender: undefined,
birthDay: undefined,
orgName: undefined,
applyDeptName: undefined,
surgeonName: undefined,
isExternalExpert: 0,
externalExpertName: undefined
})
const surgeryRef = ref()
const total = ref(0)
const title = ref('')
// 表单验证规则
const rules = reactive({
scheduleDate: [
{ required: true, message: '请选择安排时间', trigger: 'change' }
],
sequenceNo: [
{ required: true, message: '请输入手术台次', trigger: 'blur' },
{ type: 'number', message: '手术台次必须为数字', trigger: 'blur' }
],
roomCode: [
{ required: true, message: '请选择手术间号', trigger: 'change' }
],
tableNo: [
{ required: true, message: '请选择手术台', trigger: 'change' }
],
surgeryNature: [
{ required: true, message: '请选择手术性质', trigger: 'change' }
],
surgerySite: [
{ required: true, message: '请选择手术部位', trigger: 'change' }
],
anesMethod: [
{ required: true, message: '请选择麻醉方法', trigger: 'change' }
],
surgeonCode: [
{ required: true, message: '请选择主刀医生', trigger: 'change' }
]
})
// 手术申请查询弹窗
const showApplyDialog = ref(false)
const applyLoading = ref(false)
const applyList = ref([])
const applyTotal = ref(0)
const applyTableRef = ref()
// 手术计费弹窗
const showChargeDialog = ref(false)
const chargeDialogTitle = ref('')
const chargePatientInfo = ref({})
const chargeSurgeryInfo = ref({})
const prescriptionRef = ref()
// 临时医嘱弹窗
const showTemporaryMedical = ref(false)
const temporaryMedicalTitle = ref('门诊术中临时医嘱')
const temporaryPatientInfo = ref({})
const temporaryBillingMedicines = ref([])
const temporaryAdvices = ref([])
// 🔧 新增:监听 temporaryAdvices 的变化,用于调试
watch(temporaryAdvices, (newVal, oldVal) => {
console.log('=== temporaryAdvices 变化 ===')
console.log('=== 新值 ===', newVal)
console.log('=== 新值[1]?.dosage ===', newVal[1]?.dosage)
console.log('=== 旧值 ===', oldVal)
console.log('=== 旧值[1]?.dosage ===', oldVal[1]?.dosage)
}, { deep: true })
const temporaryMedicalLoading = ref(false) // 🔧 新增:临时医嘱加载状态
// 下拉列表数据
const orgList = ref([])
const deptList = ref([])
const doctorList = ref([])
const nurseList = ref([])
const operatingRoomList = ref([])
function flattenOrgTree(tree = []) {
const result = []
const stack = Array.isArray(tree) ? [...tree] : []
while (stack.length) {
const node = stack.shift()
if (!node) continue
const id = node.id ?? node.orgId ?? node.deptId
const name = node.name ?? node.label ?? node.deptName ?? node.orgName
if (id !== undefined && id !== null && name) {
result.push({ id, name })
}
const children = node.children || node.childList
if (Array.isArray(children) && children.length) {
stack.unshift(...children)
}
}
// 去重
const seen = new Set()
return result.filter(it => {
const key = String(it.id)
if (seen.has(key)) return false
seen.add(key)
return true
})
}
function mapPractitionerToOption(item) {
// user-practitioner-page 常见字段practitionerId / nickName / orgId 等
const code = item.code ?? item.practitionerId ?? item.userId ?? item.id
const name = item.name ?? item.nickName ?? item.userName ?? item.userNickName
return { code, name }
}
function mapOperatingRoomToOption(item) {
const roomCode = item.roomCode ?? item.code ?? item.no ?? item.name
return { ...item, roomCode }
}
// 字典数据
// 字典返回的字段名就是字典 key 本身(参照 surgerymanageconst { surgical_site } = useDict('surgical_site')
const {
surgical_site: surgerySiteList,
anesthesia_type: anesthesiaList,
incision_level: incisionTypeList,
isolation_type: isolationTypeList,
surgery_type,
surgery_level,
surgery_nature: surgeryNatureList,
method_code
} = useDict('surgical_site', 'anesthesia_type', 'incision_level', 'isolation_type', 'surgery_type', 'surgery_level', 'surgery_nature', 'method_code')
// 加载数据
onMounted(() => {
const anesthesiaType = sessionStorage.getItem('anesthesiaType')
if (anesthesiaType) {
form.anesMethod = anesthesiaType
sessionStorage.removeItem('anesthesiaType')
}
getPageList()
loadOrgList()
loadDeptList()
loadDoctorList()
loadNurseList()
loadOperatingRoomList()
})
// 加载卫生机构列表
function loadOrgList() {
getTenantPage({ pageNo: 1, pageSize: 1000 })
.then(res => {
if (res.code === 200) {
const records = res.data?.records || res.data || []
orgList.value = records.map(item => ({ id: item.id, name: item.tenantName || item.name }))
} else {
proxy.$modal.msgError('获取卫生机构列表失败')
orgList.value = []
}
})
.catch(() => {
proxy.$modal.msgError('获取卫生机构列表失败')
orgList.value = []
})
}
// 加载科室列表
function loadDeptList() {
deptTreeSelect()
.then(res => {
if (res.code === 200) {
const tree = res.data?.records || res.data || []
deptList.value = flattenOrgTree(tree)
} else {
proxy.$modal.msgError('获取科室列表失败')
deptList.value = []
}
})
.catch(error => {
proxy.$modal.msgError('获取科室列表失败')
deptList.value = []
})
}
// 加载医生列表
function loadDoctorList() {
listUser({ pageNo: 1, pageSize: 1000 })
.then(res => {
if (res.code === 200) {
const records = res.data?.records || []
doctorList.value = records.map(mapPractitionerToOption).filter(it => it.code && it.name)
} else {
proxy.$modal.msgError('获取医生列表失败')
doctorList.value = []
}
})
.catch(error => {
proxy.$modal.msgError('获取医生列表失败')
doctorList.value = []
})
}
// 加载护士列表
function loadNurseList() {
listUser({ pageNo: 1, pageSize: 1000 })
.then(res => {
if (res.code === 200) {
const records = res.data?.records || []
nurseList.value = records.map(mapPractitionerToOption).filter(it => it.code && it.name)
} else {
proxy.$modal.msgError('获取护士列表失败')
nurseList.value = []
}
})
.catch(error => {
proxy.$modal.msgError('获取护士列表失败')
nurseList.value = []
})
}
// 加载手术室列表
function loadOperatingRoomList() {
listOperatingRoom({ pageNo: 1, pageSize: 1000, statusEnum: 1 })
.then(res => {
if (res.code === 200) {
const records = res.data?.records || []
operatingRoomList.value = records.map(mapOperatingRoomToOption).filter(it => it.roomCode)
} else {
proxy.$modal.msgError('获取手术室列表失败')
operatingRoomList.value = []
}
})
.catch(error => {
proxy.$modal.msgError('获取手术室列表失败')
operatingRoomList.value = []
})
}
// 获取手术安排列表
function getList() {
loading.value = true
// 处理日期范围
const params = { ...queryParams }
if (params.scheduleDateRange && params.scheduleDateRange.length === 2) {
params.scheduleDateStart = params.scheduleDateRange[0]
params.scheduleDateEnd = params.scheduleDateRange[1]
} else {
params.scheduleDateStart = undefined
params.scheduleDateEnd = undefined
}
delete params.scheduleDateRange
getSurgerySchedulePage(params).then((res) => {
surgeryList.value = res.data.records
total.value = res.data.total
}).catch(error => {
proxy.$modal.msgError('获取手术安排列表失败,请稍后重试')
surgeryList.value = []
total.value = 0
}).finally(() => {
loading.value = false
})
}
function getPageList() {
getList()
}
function handleQuery() {
queryParams.pageNo = 1
getList()
}
function resetQuery() {
proxy.resetForm('queryRef')
Object.assign(queryParams, {
pageNo: 1,
pageSize: 10,
scheduleDateRange: [],
scheduleDateStart: undefined,
scheduleDateEnd: undefined,
tenantId: undefined,
applyDeptId: undefined,
patientName: undefined,
operCode: undefined
})
getList()
}
// 新增手术安排
function handleAdd() {
title.value = '新增手术安排'
isEditMode.value = false
isViewMode.value = false
resetForm()
open.value = true
}
// 编辑手术安排
function handleEdit(row) {
title.value = '编辑手术安排'
isEditMode.value = true
isViewMode.value = false
resetForm()
getSurgeryScheduleDetail(row.scheduleId).then(res => {
if (res.code === 200) {
const data = res.data
Object.assign(form, data)
// 修复#433 #434 #435确保字典字段类型与下拉选项一致Number类型
if (data.anesthesiaTypeEnum != null) form.anesMethod = Number(data.anesthesiaTypeEnum)
if (data.incisionLevel != null) form.incisionType = Number(data.incisionLevel)
if (data.feeType != null) form.feeType = data.feeType
} else {
proxy.$modal.msgError('获取手术安排详情失败')
}
}).catch(() => {
proxy.$modal.msgError('获取手术安排详情失败')
})
open.value = true
}
// 查看手术安排
function handleView(row) {
title.value = '查看手术安排'
isEditMode.value = false
isViewMode.value = true
resetForm()
getSurgeryScheduleDetail(row.scheduleId).then(res => {
if (res.code === 200) {
const data = res.data
Object.assign(form, data)
// 修复#433 #434 #435确保字典字段类型与下拉选项一致Number类型
if (data.anesthesiaTypeEnum != null) form.anesMethod = Number(data.anesthesiaTypeEnum)
if (data.incisionLevel != null) form.incisionType = Number(data.incisionLevel)
if (data.feeType != null) form.feeType = data.feeType
} else {
proxy.$modal.msgError('获取手术安排详情失败')
}
}).catch(() => {
proxy.$modal.msgError('获取手术安排详情失败')
})
open.value = true
}
// 行选中事件处理
function handleCurrentChange(currentRow, oldRow) {
if (currentRow) {
selectedRow.value = currentRow
selectedRowIndex.value = surgeryList.value.findIndex(row => row.scheduleId === currentRow.scheduleId)
} else {
selectedRow.value = null
selectedRowIndex.value = -1
}
}
// 删除手术安排
function handleDelete(row) {
proxy.$modal.confirm('是否确认取消手术安排"' + row.operName + '"?').then(() => {
return deleteSurgerySchedule(row.scheduleId)
}).then(() => {
getPageList()
proxy.$modal.msgSuccess('手术安排已取消')
}).catch(() => {
return
})
}
// 手术计费
async function handleChargeCharge(row) {
// 如果没有传入行数据,使用选中的行
if (!row && selectedRow.value) {
row = selectedRow.value
}
// 如果还是没有行数据,显示提示
if (!row) {
proxy.$modal.msgWarning('请先选择要计费的手术安排')
return
}
// 调用接口获取账户信息
let accountId = null
try {
const contractResult = await getContract({ encounterId: row.visitId })
if (contractResult.code === 200 && contractResult.data && contractResult.data.length > 0) {
// 从返回数据中提取accountId - data是数组取第一个元素的accountId
accountId = contractResult.data[0].accountId || contractResult.data[0].id
} else {
proxy.$modal.msgError('获取账户信息失败')
}
} catch (error) {
return
}
// 设置计费弹窗数据 - 直接复制划价页面的逻辑
chargeDialogTitle.value = '手术计费 - ' + row.patientName + ' - ' + row.operName
// 构建患者信息传递encounterId和机构ID
chargePatientInfo.value = {
encounterId: row.visitId, // 就诊ID
patientId: row.patientId,
patientName: row.patientName,
genderEnum: row.gender,
age: row.age,
organizationName: row.applyDeptName,
registerTime: row.scheduleDate,
typeCode_dictText: row.applyDeptName,
genderEnum_enumText: row.gender === 0 ? '男' : row.gender === 1 ? '女' : '未知',
// 添加机构ID
orgId: userStore.organizationId || userStore.orgId || userStore.tenantId || 1,
// 添加账户ID
accountId: accountId,
// 添加手术申请单号用于追溯
sourceBillNo: row.applyId,
//添加计费标志手术计费
generateSourceEnum: 6
}
chargeSurgeryInfo.value = {
surgeryName: row.operName,
surgeryNo: row.operCode
}
// 打开计费弹窗
showChargeDialog.value = true
// 延迟加载处方列表,确保组件已经渲染
nextTick(() => {
if (prescriptionRef.value && prescriptionRef.value.getListInfo) {
prescriptionRef.value.getListInfo()
}
})
}
// 关闭计费弹窗
function closeChargeDialog() {
showChargeDialog.value = false
chargePatientInfo.value = {}
chargeSurgeryInfo.value = {}
}
// 🔧 新增:标志位,用于区分是"打开"还是"刷新"
const isRefreshAction = ref(false)
// 处理医嘱按钮点击事件
function handleMedicalAdvice(row) {
// 如果没有传入行数据,使用选中的行
if (!row && selectedRow.value) {
row = selectedRow.value
}
// 如果还是没有行数据,显示提示
if (!row) {
proxy.$modal.msgWarning('请先选择要开具医嘱的手术安排')
return
}
// 设置临时医嘱弹窗数据
temporaryPatientInfo.value = {
patientName: row.patientName,
visitId: row.visitId,
operCode: row.operCode,
roomCode: row.roomCode,
doctorName: userStore.nickName,
role: userStore.roles[0],
effectiveOrgId : row.effectiveOrgId,
orgId: userStore.orgId,
positionId: userStore.orgId
}
// 🔧 关键修复:如果已有提交的医嘱数据,并且是同一个患者的就诊,则使用保存的数据
// 这样可以保留 requestId避免重复创建医嘱记录
console.log('=== 检查是否使用已保存的医嘱数据 ===')
console.log('=== temporaryAdvices.value.length ===', temporaryAdvices.value.length)
console.log('=== temporaryAdvices.value[0]?.originalMedicine?.encounterId ===', temporaryAdvices.value[0]?.originalMedicine?.encounterId)
console.log('=== row.visitId ===', row.visitId)
console.log('=== isRefreshAction.value ===', isRefreshAction.value)
const isSameEncounter = temporaryAdvices.value.length > 0 &&
temporaryAdvices.value[0]?.originalMedicine?.encounterId === row.visitId &&
!isRefreshAction.value
console.log('=== isSameEncounter ===', isSameEncounter)
if (isSameEncounter) {
console.log('=== 使用已保存的医嘱数据,避免重复创建 ===')
console.log('=== temporaryAdvices.value[0]?.originalMedicine?.requestId ===', temporaryAdvices.value[0]?.originalMedicine?.requestId)
// 直接打开弹窗,使用已保存的数据
showTemporaryMedical.value = true
temporaryMedicalLoading.value = false
isRefreshAction.value = false // 重置标志位
return
}
// 🔧 修复:每次打开临时医嘱时都重新加载数据,避免使用缓存数据导致数据重复
// 先清空旧数据
temporaryBillingMedicines.value = []
temporaryAdvices.value = []
temporaryMedicalLoading.value = true // 🔧 新增:开始加载
// 调用计费接口获取数据
getPrescriptionList(row.visitId).then((res) => {
console.log('=== 拉取计费数据返回结果 ===', res)
if (res.code === 200 && res.data) {
// 🔧 修复:显示所有药品请求数据,不管有没有计费项目
// 根据用户需求:已引用计费药品(待生成医嘱)和临时医嘱预览(已生成)显示的数据应该相同
// 在提交医嘱之前状态应该是"待签发",提交之后变为"已签发"
// 再次打开医嘱界面的时候能看到这两个状态的药品
const seenIds = new Set();
const filteredItems = res.data.filter(item => {
// 匹配 encounterId
if (item.encounterId !== row.visitId) return false;
// 过滤掉名称为空的项目
const medicineName = item.adviceName || item.advice_name;
if (!medicineName || medicineName.trim() === '') return false;
// 根据药品请求ID去重避免重复显示
const itemId = item.requestId || item.id;
if (itemId && seenIds.has(itemId)) return false;
if (itemId) seenIds.add(itemId);
return true;
})
// 🔧 修复限制返回数量最多显示前100条避免数据过多导致页面卡死
const maxItems = 100
if (filteredItems.length > maxItems) {
ElMessage.warning(`待签发医嘱数量过多(${filteredItems.length}条),仅显示前${maxItems}`)
filteredItems.length = maxItems
}
// 将过滤后的数据转换为临时医嘱需要的格式 - 兼容驼峰和下划线命名
// 对于从 adm_charge_item计费项目表查询来的项目特殊处理
temporaryBillingMedicines.value = filteredItems.map(item => {
try {
// 从 contentJson 或 content_json 中解析详细数据 - 兼容下划线和驼峰命名
const jsonContent = item.contentJson || item.content_json;
const contentData = jsonContent ? JSON.parse(jsonContent) : {};
return {
medicineName: contentData.adviceName || contentData.advice_name || item.adviceName || item.advice_name || '',
specification: contentData.volume || contentData.specification || item.volume || item.specification || '',
quantity: contentData.quantity || item.quantity || 0,
batchNumber: contentData.lotNumber || contentData.lot_number || item.lotNumber || item.lot_number || '',
unitPrice: contentData.unitPrice || contentData.unit_price || item.unitPrice || item.unit_price || 0,
subtotal: contentData.totalPrice || contentData.total_price || item.totalPrice || item.total_price ||
(contentData.unitPrice || contentData.unit_price || item.unitPrice || item.unit_price || 0) *
(contentData.quantity || item.quantity || 0),
insuranceType: (contentData.insuranceType || contentData.insurance_type) === 1 ? '医保' : (item.insuranceType === 1 || item.insurance_type === 1) ? '医保' : '自费',
// 添加医嘱定义ID和表名用于库存匹配
adviceDefinitionId: item.adviceDefinitionId || contentData.adviceDefinitionId || item.advice_definition_id || null,
adviceTableName: item.adviceTableName || contentData.adviceTableName || item.advice_table_name || null,
// 添加关键字段医嘱类型、费用项目ID、定价ID用于后端正确分类和保存
adviceType: item.adviceType || contentData.adviceType || item.advice_type || null,
chargeItemId: item.chargeItemId || contentData.chargeItemId || item.charge_item_id || null,
definitionId: item.definitionId || contentData.definitionId || item.definition_id || null,
definitionDetailId: item.definitionDetailId || contentData.definitionDetailId || item.definition_detail_id || null
};
} catch (e) {
// 如果解析失败,使用顶层数据 - 兼容 snake_case 和 camelCase 以及后端不同字段名
return {
medicineName: item.adviceName || item.advice_name || item.chargeName || '',
specification: item.specification || item.specification || item.volume || '',
quantity: item.quantity || item.quantity_value || item.quantityValue || 0,
batchNumber: item.lotNumber || item.lot_number || '',
unitPrice: item.unitPrice || item.unit_price || 0,
subtotal: item.totalPrice || item.total_price ||
(item.unitPrice || item.unit_price || 0) *
(item.quantity || item.quantity_value || item.quantityValue || 0),
insuranceType: (item.insuranceType || item.insurance_type) === 1 ? '医保' : '自费',
// 添加医嘱定义ID和表名用于库存匹配
adviceDefinitionId: item.adviceDefinitionId || item.advice_definition_id || null,
adviceTableName: item.adviceTableName || item.advice_table_name || null,
// 添加关键字段医嘱类型、费用项目ID、定价ID用于后端正确分类和保存
adviceType: item.adviceType || item.advice_type || null,
chargeItemId: item.chargeItemId || item.charge_item_id || null,
definitionId: item.definitionId || item.definition_id || null,
definitionDetailId: item.definitionDetailId || item.definition_detail_id || null
};
}
});
} else {
// 如果没有数据或接口调用失败,初始化空列表
temporaryBillingMedicines.value = []
}
// 将计费药品转换为临时医嘱数据
temporaryAdvices.value = temporaryBillingMedicines.value.map((medicine, index) => {
// 解析规格中的数值和单位
const specMatch = medicine.specification ? medicine.specification.match(/(\d+)(\D+)/) : null
const specValue = specMatch ? parseInt(specMatch[1]) : 1
const specUnit = specMatch ? specMatch[2] : 'ml'
// 计算剂量 = 规格数值 × 数量
const dosage = specValue * (medicine.quantity || 1)
// 🔧 修复:优先从 contentJson 中读取已有的用法,如果没有则根据药品名称判断
let usageCode = 'iv' // 默认静脉注射编码
let usageLabel = '静脉注射' // 默认显示名称
// 尝试从 contentJson 中读取用法
try {
const jsonContent = medicine.contentJson || medicine.content_json;
if (jsonContent) {
const contentData = JSON.parse(jsonContent);
if (contentData.methodCode) {
usageCode = contentData.methodCode;
usageLabel = getUsageLabel(contentData.methodCode);
}
}
} catch (e) {
// 解析失败,继续使用默认值
}
// 如果没有从 contentJson 中读取到用法,根据药品名称判断
if (!usageCode || usageCode === 'iv') {
if (medicine.medicineName && medicine.medicineName.includes('注射液')) {
usageCode = 'iv'
usageLabel = '静脉注射'
} else if (medicine.medicineName && medicine.medicineName.includes('片')) {
usageCode = 'po'
usageLabel = '口服'
} else if (medicine.medicineName && medicine.medicineName.includes('胶囊')) {
usageCode = 'po'
usageLabel = '口服'
}
}
return {
id: index + 1,
adviceName: medicine.medicineName || '',
dosage: dosage,
unit: specUnit,
usage: usageCode, // 🔧 修复:保存的是编码
usageLabel: usageLabel, // 🔧 新增:保存显示名称
frequency: '临时',
executeTime: new Date().toLocaleString('zh-CN'),
// 🔧 关键修复:确保 originalMedicine 中包含 encounterId以便后续判断是否为同一患者
originalMedicine: {
...medicine,
encounterId: row.visitId // 添加 encounterId 字段
}
}
})
// 打开临时医嘱弹窗
showTemporaryMedical.value = true
temporaryMedicalLoading.value = false // 🔧 新增:加载完成
}).catch((error) => {
temporaryBillingMedicines.value = []
temporaryAdvices.value = []
temporaryMedicalLoading.value = false // 🔧 新增:加载完成(即使失败也要关闭加载状态)
proxy.$modal.msgError('刷新数据失败,请重试')
console.error('Failed to refresh prescription list', error)
showTemporaryMedical.value = true
})
}
// 关闭临时医嘱弹窗
// 🔧 修复:清空数据,避免下次打开时使用缓存数据导致数据重复
function closeTemporaryMedical() {
showTemporaryMedical.value = false
// 🔧 修复:关闭弹窗时不清空数据,保留用户可能已经修改过的数据
// 只有当用户点击"取消"按钮时才应该清空数据
}
// 处理临时医嘱提交
// 🔧 修复:提交成功后,更新 temporaryAdvices 中的 requestId以便下次提交时执行更新操作
function handleTemporaryMedicalSubmit(data) {
console.log('=== handleTemporaryMedicalSubmit 被调用 ===')
console.log('=== data ===', data)
console.log('=== data.temporaryAdvices ===', data.temporaryAdvices)
console.log('=== data.temporaryAdvices[1]?.dosage ===', data.temporaryAdvices[1]?.dosage)
// 🔧 修复:使用用户修改后的数据,而不是重新加载数据
// 这样可以确保用户修改的内容(如剂量)在保存后仍然正确显示
if (data.temporaryAdvices && data.temporaryAdvices.length > 0) {
// 🔧 关键修复:更新 temporaryAdvices 中的数据,保留用户的修改
// 但是需要从后端返回的数据中获取 requestId以便下次提交时执行更新操作
// 如果后端返回了医嘱IDrequestId我们需要更新到 temporaryAdvices 中
temporaryAdvices.value = data.temporaryAdvices.map((advice, index) => {
const originalMedicine = advice.originalMedicine || {}
// 🔧 关键修复:从后端返回的数据中获取 requestId如果有
// 后端返回的医嘱ID可能需要通过某个字段获取这里暂时假设后端会返回
// 如果后端返回的 response 中包含医嘱ID需要更新到 originalMedicine 中
// 这里暂时保留原逻辑,等待用户提供后端返回的具体数据结构
return {
...advice,
// 确保 originalMedicine 包含所有必要字段
originalMedicine: {
...originalMedicine,
// 保留用户的修改
contentJson: originalMedicine.contentJson || JSON.stringify({
dose: advice.dosage,
methodCode: advice.usage,
rateCode: advice.frequency,
quantity: advice.quantity,
totalPrice: advice.totalPrice
})
}
}
})
// 同步更新计费药品列表,保持数据一致性
temporaryBillingMedicines.value = data.billingMedicines || []
console.log('=== 使用用户修改后的临时医嘱数据 ===', temporaryAdvices.value)
console.log('=== temporaryAdvices.value[1]?.dosage ===', temporaryAdvices.value[1]?.dosage)
} else {
// 如果没有传递数据,则清空
temporaryAdvices.value = []
temporaryBillingMedicines.value = []
}
// 关闭弹窗
showTemporaryMedical.value = false
}
// 处理临时医嘱取消
function handleTemporaryMedicalCancel() {
// 🔧 修复:用户点击取消时才清空数据,因为用户可能要放弃修改
temporaryPatientInfo.value = {}
temporaryBillingMedicines.value = []
temporaryAdvices.value = []
closeTemporaryMedical()
}
// 处理删除临时医嘱 - 将删除的医嘱放回已引用计费药品列表
function handleDeleteTemporaryAdvice(index) {
const deletedAdvice = temporaryAdvices.value[index]
// 如果有原始药品数据,放回到计费药品列表
if (deletedAdvice.originalMedicine) {
temporaryBillingMedicines.value.push(deletedAdvice.originalMedicine)
}
temporaryAdvices.value.splice(index, 1)
proxy.$modal.msgSuccess('临时医嘱已删除,已放回待生成列表')
}
// 处理刷新按钮点击
function handleTemporaryMedicalRefresh() {
// 重新拉取计费药品数据
if (temporaryPatientInfo.value.visitId) {
handleMedicalAdvice(temporaryPatientInfo.value)
} else {
proxy.$modal.msgWarning('患者信息不完整,请关闭弹窗重新打开')
}
}
// 处理引用计费按钮点击
function handleQuoteBilling() {
// 重新拉取计费药品数据
if (temporaryPatientInfo.value.visitId) {
temporaryMedicalLoading.value = true // 🔧 新增:开始加载
getPrescriptionList(temporaryPatientInfo.value.visitId).then((res) => {
if (res.code === 200 && res.data) {
// 🔧 修复:先清空旧数据,避免数据累积
temporaryBillingMedicines.value = []
temporaryAdvices.value = []
// 🔧 修复:显示所有药品请求数据,不管有没有计费项目
const filteredItems = res.data.filter(item => {
// 匹配 encounterId
if (item.encounterId !== temporaryPatientInfo.value.visitId) return false;
// 过滤掉名称为空的项目
const medicineName = item.adviceName || item.advice_name;
return medicineName && medicineName.trim() !== '';
})
// 🔧 修复限制返回数量最多显示前100条避免数据过多导致页面卡死
const maxItems = 100
if (filteredItems.length > maxItems) {
ElMessage.warning(`待签发医嘱数量过多(${filteredItems.length}条),仅显示前${maxItems}`)
filteredItems.length = maxItems
}
// 将过滤后的数据转换为临时医嘱需要的格式
temporaryBillingMedicines.value = filteredItems.map(item => {
try {
// 从 contentJson 或 content_json 中解析详细数据 - 兼容下划线和驼峰命名
const jsonContent = item.contentJson || item.content_json;
const contentData = jsonContent ? JSON.parse(jsonContent) : {};
return {
medicineName: contentData.adviceName || contentData.advice_name || item.adviceName || item.advice_name || item.chargeName || '',
specification: contentData.volume || contentData.specification || item.volume || item.specification || '',
quantity: contentData.quantity || item.quantity || item.quantity_value || item.quantityValue || 0,
batchNumber: contentData.lotNumber || contentData.lot_number || item.lotNumber || item.lot_number || '',
unitPrice: contentData.unitPrice || contentData.unit_price || item.unitPrice || item.unit_price || 0,
subtotal: contentData.totalPrice || contentData.total_price || item.totalPrice || item.total_price ||
(contentData.unitPrice || contentData.unit_price || item.unitPrice || item.unit_price || 0) *
(contentData.quantity || item.quantity || item.quantity_value || item.quantityValue || 0),
insuranceType: (contentData.insuranceType || contentData.insurance_type) === 1 ? '医保' : (item.insuranceType === 1 || item.insurance_type === 1) ? '医保' : '自费',
orgId: contentData.orgId || item.orgId || contentData.positionId || item.positionId || userStore.orgId,
positionId: contentData.positionId || item.positionId || userStore.orgId,
definitionId: contentData.definitionId || item.definitionId,
definitionDetailId: contentData.definitionDetailId || item.definitionDetailId
}
} catch (e) {
// 如果解析失败,使用顶层数据 - 兼容 snake_case 和 camelCase
return {
medicineName: item.adviceName || item.advice_name || '',
specification: item.specification || item.specification || item.volume || '',
quantity: item.quantity || item.quantity_value || 0,
batchNumber: item.lotNumber || item.lot_number || '',
unitPrice: item.unitPrice || item.unit_price || 0,
subtotal: item.totalPrice || item.total_price ||
(item.unitPrice || item.unit_price || 0) *
(item.quantity || item.quantity_value || 0),
insuranceType: (item.insuranceType || item.insurance_type) === 1 ? '医保' : '自费',
orgId: item.orgId || item.positionId || userStore.orgId,
positionId: item.positionId || userStore.orgId,
definitionId: item.definitionId,
definitionDetailId: item.definitionDetailId
}
}
})
// 将计费药品转换为临时医嘱数据
temporaryAdvices.value = temporaryBillingMedicines.value.map((medicine, index) => {
// 解析规格中的数值和单位
const specMatch = medicine.specification ? medicine.specification.match(/(\d+)(\D+)/) : null
const specValue = specMatch ? parseInt(specMatch[1]) : 1
const specUnit = specMatch ? specMatch[2] : 'ml'
// 计算剂量 = 规格数值 × 数量
const dosage = specValue * (medicine.quantity || 1)
// 🔧 修复:优先从 contentJson 中读取已有的用法,如果没有则根据药品名称判断
let usageCode = 'iv' // 默认静脉注射编码
let usageLabel = '静脉注射' // 默认显示名称
// 尝试从 contentJson 中读取用法
try {
const jsonContent = medicine.contentJson || medicine.content_json;
if (jsonContent) {
const contentData = JSON.parse(jsonContent);
if (contentData.methodCode) {
usageCode = contentData.methodCode;
usageLabel = getUsageLabel(contentData.methodCode);
}
}
} catch (e) {
// 解析失败,继续使用默认值
}
// 如果没有从 contentJson 中读取到用法,根据药品名称判断
if (!usageCode || usageCode === 'iv') {
if (medicine.medicineName && medicine.medicineName.includes('注射液')) {
usageCode = 'iv'
usageLabel = '静脉注射'
} else if (medicine.medicineName && medicine.medicineName.includes('片')) {
usageCode = 'po'
usageLabel = '口服'
} else if (medicine.medicineName && medicine.medicineName.includes('胶囊')) {
usageCode = 'po'
usageLabel = '口服'
}
}
return {
id: index + 1,
adviceName: medicine.medicineName || '',
dosage: dosage,
unit: specUnit,
usage: usageCode, // 🔧 修复:保存的是编码
usageLabel: usageLabel, // 🔧 新增:保存显示名称
frequency: '临时',
executeTime: new Date().toLocaleString('zh-CN'),
// 🔧 关键修复:确保 originalMedicine 中包含 encounterId以便后续判断是否为同一患者
originalMedicine: {
...medicine,
encounterId: temporaryPatientInfo.value.visitId // 添加 encounterId 字段
}
}
})
temporaryMedicalLoading.value = false // 🔧 新增:加载完成
ElMessage.success('已成功引用最新计费药品信息!')
} else {
// 如果没有数据或接口调用失败,初始化空列表
temporaryBillingMedicines.value = []
temporaryAdvices.value = []
temporaryMedicalLoading.value = false // 🔧 新增:加载完成(即使失败也要关闭加载状态)
ElMessage.error('获取计费数据失败,请重试')
}
}).catch(() => {
temporaryBillingMedicines.value = []
temporaryAdvices.value = []
temporaryMedicalLoading.value = false // 🔧 新增:加载完成(即使失败也要关闭加载状态)
ElMessage.error('获取计费数据失败,请重试')
})
} else {
proxy.$modal.msgWarning('患者信息不完整,请关闭弹窗重新打开')
}
}
// 🔧 新增:根据用法编码获取对应的显示名称
function getUsageLabel(usageCode) {
if (!usageCode) return '-'
const dictItem = method_code.value?.find(item => item.value === usageCode)
return dictItem ? dictItem.label : usageCode
}
// 格式化计费弹窗中的日期
function formatChargeDate(date) {
if (!date) return '-'
return new Date(date).toLocaleString()
}
// 计算是否禁用
const disabled = computed(() => {
return Object.keys(chargePatientInfo.value).length === 0
})
// 重置表单
function resetForm() {
Object.assign(form, {
scheduleId: undefined,
applyId: undefined,
patientId: undefined,
visitId: undefined,
operCode: undefined,
operName: undefined,
preoperativeDiagnosis: undefined,
postoperativeDiagnosis: undefined,
scheduleDate: undefined,
sequenceNo: undefined,
isFirstSurgery: 0,
isAllergyMedication: 0,
allergyRemark: undefined,
surgeryNature: undefined,
surgerySite: undefined,
admissionTime: undefined,
entryTime: undefined,
roomCode: undefined,
tableNo: undefined,
anesMethod: undefined,
anesDoctor1Code: undefined,
anesDoctor2Code: undefined,
anesDoctor3Code: undefined,
scrubNurseCode: undefined,
circuNurse1Code: undefined,
circuNurse2Code: undefined,
scrubNurse1Code: undefined,
scrubNurse2Code: undefined,
surgeonCode: undefined,
assistant1Code: undefined,
assistant2Code: undefined,
assistant3Code: undefined,
startTime: undefined,
endTime: undefined,
anesStart: undefined,
anesEnd: undefined,
operStatus: 0,
implantFlag: 0,
implantSerial: undefined,
bloodLoss: undefined,
bloodTrans: undefined,
infectionDiagnosis: undefined,
isolationType: undefined,
patientWeight: undefined,
patientHeight: undefined,
communicationInfo: undefined,
remark: undefined,
patientName: undefined,
gender: undefined,
age: undefined,
orgName: undefined,
applyDeptName: undefined,
surgeonName: undefined,
isExternalExpert: 0,
externalExpertName: undefined
})
if (surgeryRef.value) {
surgeryRef.value.resetFields()
}
}
// 提交表单
function submitForm() {
proxy.$refs['surgeryRef'].validate((valid) => {
if (valid) {
const submitData = { ...form, orgId: userStore.orgId }
if (!form.scheduleId) {
// 新增手术安排
addSurgerySchedule(submitData).then((res) => {
proxy.$modal.msgSuccess('新增成功')
open.value = false
getPageList()
}).catch(() => {
proxy.$message.error('新增手术安排失败,请检查表单信息')
})
} else {
// 修改手术安排
updateSurgerySchedule(submitData).then((res) => {
proxy.$modal.msgSuccess('修改成功')
open.value = false
getPageList()
}).catch(() => {
proxy.$message.error('更新手术安排失败,请检查表单信息')
})
}
} else {
proxy.$message.error('请检查表单信息,标红字段为必填项')
}
})
}
// 取消
function cancel() {
open.value = false
isViewMode.value = false
resetForm()
}
// 刷新
function handleRefresh() {
resetForm()
}
// 查找手术申请
function handleFindApply() {
showApplyDialog.value = true
applyQueryParams.pageNo = 1
getSurgicalScheduleList()
}
// 获取手术申请列表(用于“查找”弹窗)
function getSurgicalScheduleList() {
applyLoading.value = true
const params = { ...applyQueryParams }
if (params.applyTimeRange && params.applyTimeRange.length === 2) {
params.applyTimeStart = params.applyTimeRange[0]
params.applyTimeEnd = params.applyTimeRange[1]
delete params.applyTimeRange
}
getTestResultPage(params).then((res) => {
// Check if data is nested under data.data or directly under data
const responseData = res.data.data || res.data
applyList.value = responseData.records || []
applyTotal.value = responseData.total || 0
}).catch(() => {
proxy.$modal.msgError('获取手术申请列表失败,请稍后重试')
applyList.value = []
applyTotal.value = 0
})
.finally(() => {
applyLoading.value = false
})
}
const applyQueryParams = reactive({
pageNo: 1,
pageSize: 10,
applyTimeRange: undefined,
applyDeptId: undefined,
mainDoctorId: undefined,
})
// 手术申请查询
function handleApplyQuery() {
applyQueryParams.pageNo = 1
getSurgicalScheduleList()
}
// 重置手术申请查询条件
function resetApplyQuery() {
Object.assign(applyQueryParams, {
pageNo: 1,
pageSize: 10,
applyTimeRange: undefined,
applyDeptId: undefined,
mainDoctorId: undefined,
})
getSurgicalScheduleList()
}
// 取消手术申请查询
function cancelApplyDialog() {
showApplyDialog.value = false
Object.assign(applyQueryParams, {
pageNo: 1,
pageSize: 10,
applyTimeRange: undefined,
applyDeptId: undefined,
mainDoctorId: undefined,
})
applyList.value = []
applyTotal.value = 0
}
// 行点击事件处理
function handleApplyRowClick(row) {
const selectedRows = applyTableRef.value?.getSelectionRows ? applyTableRef.value.getSelectionRows() : []
// 如果已经有选中的行,先清除所有选择
if (selectedRows.length > 0) {
applyTableRef.value.clearSelection()
}
// 然后选择当前行
applyTableRef.value.toggleRowSelection(row)
}
// 表格行样式
function tableRowClassName({ row, rowIndex }) {
// 检查当前行是否被选中
const selectedRows = applyTableRef.value?.getSelectionRows ? applyTableRef.value.getSelectionRows() : []
const isSelected = selectedRows.some(selectedRow => selectedRow.surgeryNo === row.surgeryNo)
return isSelected ? 'selected-row' : ''
}
// 控制表格只能单选
function handleSelectable(row, rowIndex) {
const selectedRows = applyTableRef.value?.getSelectionRows ? applyTableRef.value.getSelectionRows() : []
// 如果还没有选中的行,或者当前行就是已经选中的行,则允许选择
return selectedRows.length === 0 || selectedRows.some(selectedRow => selectedRow.surgeryNo === row.surgeryNo)
}
// 获取手术类型名称
function getSurgeryTypeName(surgeryType) {
if (!surgeryType) return ''
const type = surgery_type.value.find(item => String(item.value) === String(surgeryType))
return type ? type.label : String(surgeryType)
}
// 获取手术等级名称
function getSurgeryLevelName(surgeryLevel) {
if (!surgeryLevel) return ''
const level = surgery_level.value.find(item => String(item.value) === String(surgeryLevel))
return level ? level.label : ''
}
// 获取麻醉方法名称
function getAnesthesiaName(anesMethod) {
if (!anesMethod) return ''
const anesthesia = anesthesiaList.value.find(item => String(item.value) === String(anesMethod))
return anesthesia ? anesthesia.label : ''
}
// 根据出生日期计算年龄
function calculateAge(birthDay) {
if (!birthDay) return ''
const birthDate = new Date(birthDay)
const today = new Date()
let age = today.getFullYear() - birthDate.getFullYear()
const monthDiff = today.getMonth() - birthDate.getMonth()
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
age--
}
return age
}
// 计算属性:格式化申请时间为年月日时分秒
const formattedApplyTime = computed(() => {
if (!form.applyTime) return ''
try {
const date = new Date(form.applyTime)
if (isNaN(date.getTime())) return form.applyTime
return parseTime(date, '{y}-{m}-{d} {h}:{i}:{s}')
} catch (error) {
return form.applyTime
}
})
// 确认手术申请
function confirmApply() {
const selectedRows = applyTableRef.value?.getSelectionRows ? applyTableRef.value.getSelectionRows() : []
if (!selectedRows || selectedRows.length === 0) {
proxy.$modal.msgWarning('请先选择一条手术申请记录')
return
}
const selectedRow = selectedRows[0]
// 填充手术申请信息到表单
form.surgeryNo = selectedRow.surgeryNo // 手术单号对应填入手术单号
form.applyId=selectedRow.applyId// 手术申请id
form.patientId = selectedRow.patientId// 患者id
form.visitId = selectedRow.encounterId // id对应填入就诊id
form.identifierNo = selectedRow.identifierNo || '' // 就诊卡号
form.operCode = selectedRow.surgeryNo // 手术单号作为手术编码
form.operName = selectedRow.descJson?.surgeryName//手术名称
form.preoperativeDiagnosis = selectedRow.preoperativeDiagnosis || selectedRow.descJson?.preoperativeDiagnosis
form.patientName = selectedRow.name// 患者姓名对应填入患者姓名
form.gender = selectedRow.gender//患者性别
form.birthDay = selectedRow.birthDay//患者出生日期
form.age = calculateAge(selectedRow.birthDay)//计算患者年龄
form.applyDeptName = selectedRow.applyDeptName//申请部门名称
form.applyDoctorName = selectedRow.applyDoctorName//申请医生
form.applyTime = selectedRow.applyTime//申请时间
form.surgeryType = selectedRow.surgeryTypeEnum//手术类型
form.surgeryNature = selectedRow.surgeryTypeEnum//手术性质
form.surgeonCode = selectedRow.mainSurgeonId//主刀医生id
form.surgeonName = selectedRow.mainSurgeonName//主刀医生姓名
form.feeType = selectedRow.feeType//费用类别
form.anesMethod = selectedRow.anesthesiaTypeEnum != null ? Number(selectedRow.anesthesiaTypeEnum) : undefined //麻醉方法
form.incisionType = selectedRow.incisionLevel != null ? Number(selectedRow.incisionLevel) : undefined //切口类型
form.surgeryLevel = selectedRow.surgeryLevel != null ? Number(selectedRow.surgeryLevel) : (selectedRow.descJson?.surgeryLevel != null ? Number(selectedRow.descJson.surgeryLevel) : undefined) //手术等级
form.surgerySite = selectedRow.descJson?.surgerySite //手术部位
form.isolationType = selectedRow.descJson?.isolationType //隔离类型
showApplyDialog.value = false
}
// 导出手术安排列表
function handleExport() {
proxy.$modal.confirm('确定要导出当前筛选条件下的手术安排列表吗?').then(() => {
download.downloadGet('/clinical-manage/surgery-schedule/export', queryParams, '手术安排列表.csv')
}).catch(() => {
// 取消导出,不做任何操作
})
}
// 获取行样式
function getRowClassName({ row, rowIndex }) {
if (selectedRow.value && row.scheduleId === selectedRow.value.scheduleId) {
return 'selected-row'
}
return ''
}
</script>
<style scoped>
/* 🔧 新增:临时医嘱加载状态样式 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100px 0;
color: #409eff;
font-size: 16px;
}
.loading-container .el-icon {
font-size: 32px;
margin-bottom: 16px;
}
.loading-container span {
font-weight: 500;
}
.app-container {
padding: 20px;
}
.query-form {
margin-bottom: 20px;
}
.search-buttons {
margin-left: 10px;
}
.mb8 {
margin-bottom: 8px;
}
.pagination-container {
margin-top: 20px;
text-align: right;
}
.dialog-header-buttons {
display: flex;
justify-content: flex-end;
margin-bottom: 20px;
}
.dialog-header-buttons .el-button {
margin-left: 10px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
}
.dialog-footer .el-button {
margin-left: 10px;
}
/* 选中行样式 */
:deep(.el-table .selected-row) {
background-color: #ecf5ff !important;
}
:deep(.el-table .selected-row > td) {
border-bottom: 1px solid #d9ecff !important;
}
</style>