Files
his/openhis-ui-vue3/src/views/surgicalschedule/index.vue
chenqi f9d897c081 refactor(surgicalschedule): 更新手术排程页面中的组件导入路径
- 将 SurgeryCharge 组件的导入路径从相对路径 ../../charge/surgerycharge/index.vue 修改为 ../charge/surgerycharge/index.vue
- 修正了因目录结构调整导致的模块解析错误
- 优化了组件间的依赖关系,确保项目结构的一致性
2026-02-06 13:51:41 +08:00

1541 lines
54 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="scheduleDate">
<el-tooltip :content="queryParams.scheduleDate" placement="top" :disabled="!queryParams.scheduleDate">
<el-date-picker
v-model="queryParams.scheduleDate"
type="date"
placeholder="请选择安排时间"
value-format="YYYY-MM-DD"
style="width: 200px"
/>
</el-tooltip>
</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="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">
<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="visitId" width="120" />
<el-table-column label="手术单号" align="center" prop="operCode" width="120" show-overflow-tooltip />
<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 />
<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}') }}
</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="success" @click="handleChargeCharge(scope.row)">计费</el-button>
<el-button link type="danger" @click="handleDelete(scope.row)" v-has="['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 @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="visitId">
<el-tooltip :content="form.visitId" placement="top" :disabled="!form.visitId">
<el-input v-model="form.visitId" :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"
format="YYYY-MM-DD"
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="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="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="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.descJson?.surgeryLevel) }}
</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>
</div>
</template>
<script setup name="SurgicalSchedule">
import { ref, reactive, onMounted } from 'vue'
import { getCurrentInstance } from 'vue'
import { parseTime } from '@/utils/openhis'
import { useDict } from '@/utils/dict'
import download from '@/plugins/download'
// API 导入
import { getSurgerySchedulePage, addSurgerySchedule, updateSurgerySchedule, deleteSurgerySchedule, getSurgeryScheduleDetail } from '@/api/surgicalschedule'
import { listUser } from '@/api/system/user'
import { deptTreeSelectSelect } 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 SurgeryCharge from '../charge/surgerycharge/index.vue'
const { proxy } = getCurrentInstance()
const loading = ref(true)
const showSearch = ref(true)
const surgeryList = ref([])
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
scheduleDate: undefined,
tenantId: undefined,
applyDeptId: undefined,
patientName: undefined
})
const open = ref(false)
const isEditMode = ref(false)
const isViewMode = ref(false)
const form = reactive({
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,
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 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_type: incisionTypeList,
isolation_type: isolationTypeList,
surgery_type,
surgery_level,
surgery_nature: surgeryNatureList
} = useDict('surgical_site', 'anesthesia_type', 'incision_type', 'isolation_type', 'surgery_type', 'surgery_level', 'surgery_nature')
// 加载数据
onMounted(() => {
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(error => {
console.error('加载卫生机构列表失败:', error)
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 => {
console.error('加载科室列表失败:', 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 => {
console.error('加载医生列表失败:', 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 => {
console.error('加载护士列表失败:', 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 => {
console.error('加载手术室列表失败:', error)
proxy.$modal.msgError('获取手术室列表失败')
operatingRoomList.value = []
})
}
// 获取手术安排列表
function getList() {
loading.value = true
getSurgerySchedulePage(queryParams).then((res) => {
surgeryList.value = res.data.records
total.value = res.data.total
}).catch(error => {
console.error('获取手术安排列表失败:', error)
proxy.$modal.msgError('获取手术安排列表失败,请稍后重试')
surgeryList.value = []
total.value = 0
}).finally(() => {
loading.value = false
})
}
function getPageList() {
queryParams.pageNo = 1
getList()
}
function handleQuery() {
queryParams.pageNo = 1
getList()
}
function resetQuery() {
proxy.resetForm('queryRef')
Object.assign(queryParams, {
pageNo: 1,
pageSize: 10,
scheduleDate: undefined,
tenantId: undefined,
applyDeptId: undefined,
patientName: 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)
} else {
proxy.$modal.msgError('获取手术安排详情失败')
}
}).catch(error => {
console.error('获取手术安排详情失败:', error)
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)
} else {
proxy.$modal.msgError('获取手术安排详情失败')
}
}).catch(error => {
console.error('获取手术安排详情失败:', error)
proxy.$modal.msgError('获取手术安排详情失败')
})
open.value = true
}
// 删除手术安排
function handleDelete(row) {
proxy.$modal.confirm('是否确认取消手术安排"' + row.operName + '"?').then(() => {
return deleteSurgerySchedule(row.scheduleId)
}).then(() => {
getPageList()
proxy.$modal.msgSuccess('手术安排已取消')
}).catch(error => {
})
}
// 手术计费
function handleChargeCharge(row) {
// 打开手术计费对话框
// 传递患者信息和手术信息
const patientInfo = {
encounterId: row.patientId, // 就诊ID
patientId: row.patientId,
patientName: row.patientName,
genderEnum: row.gender,
age: row.age,
organizationName: row.applyDeptName,
receptionTime: row.scheduleDate,
encounterBusNo: row.visitId,
categoryEnum: 1, // 门诊
};
const surgeryInfo = {
surgeryNo: row.operCode, // 手术单号
surgeryName: row.operName, // 手术名称
};
// 使用el-dialog显示手术计费组件
proxy.$modal.open({
title: '手术计费',
component: SurgeryCharge,
props: {
patientInfo,
surgeryInfo
},
width: '1400px',
fullscreen: false,
});
}
// 重置表单
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 }
console.log("scheduleId:", form.scheduleId)
if (!form.scheduleId) {
// 新增手术安排
addSurgerySchedule(submitData).then((res) => {
proxy.$modal.msgSuccess('新增成功')
open.value = false
getPageList()
}).catch(error => {
console.error('新增手术安排失败:', error)
proxy.$message.error('新增手术安排失败,请检查表单信息')
})
} else {
// 修改手术安排
updateSurgerySchedule(submitData).then((res) => {
proxy.$modal.msgSuccess('修改成功')
open.value = false
getPageList()
}).catch(error => {
console.error('更新手术安排失败:', error)
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(error => {
console.error('获取手术申请列表失败:', error)
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.operCode = selectedRow.descJson.surgeryCode//手术编码
form.operName = selectedRow.descJson.surgeryName//手术名称
form.preoperativeDiagnosis = selectedRow.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//主刀医生姓名
showApplyDialog.value = false
}
// 导出手术安排列表
function handleExport() {
proxy.$modal.confirm('确定要导出当前筛选条件下的手术安排列表吗?').then(() => {
download.downloadGet('/clinical-manage/surgery-schedule/export', queryParams, '手术安排列表.csv')
}).catch(() => {
// 取消导出,不做任何操作
})
}
// 获取行样式
function getRowClassName({ row, rowIndex }) {
return ''
}
</script>
<style scoped>
.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>