维护换卡处理的查询

This commit is contained in:
2025-11-12 09:38:47 +08:00
parent 618fb1e340
commit fe8fb3d321
13 changed files with 1271 additions and 4 deletions

View File

@@ -0,0 +1,606 @@
<template>
<div class="card-renewal-container">
<!-- 标题栏 -->
<div class="title-bar">
<h2>换卡处理</h2>
</div>
<!-- 按钮栏 - 修改为水平排放 -->
<div class="button-bar">
<el-button
type="primary"
size="large"
@click="handlePatientSearch"
:loading="loading"
icon="el-icon-search"
style="min-width: 140px;"
>
病人查询(Q)
</el-button>
<el-button
type="success"
size="large"
@click="handleConfirm"
:loading="loading"
:disabled="!patientInfo"
style="min-width: 140px;"
>
确定 (O)
</el-button>
<el-button
type="danger"
size="large"
@click="handleClose"
:disabled="loading"
style="min-width: 140px;"
>
关闭 (C)
</el-button>
</div>
<!-- 查询条件 -->
<div class="search-section">
<el-row :gutter="20">
<el-col :span="8">
<div class="input-item">
<label>病人姓名:</label>
<el-input
v-model="searchForm.patientName"
placeholder="请输入"
@keyup.enter="handlePatientSearch"
clearable
/>
</div>
</el-col>
<el-col :span="8">
<div class="input-item">
<label>身份证号码:</label>
<el-input
v-model="searchForm.idCard"
placeholder="请输入"
@keyup.enter="handlePatientSearch"
clearable
/>
</div>
</el-col>
<el-col :span="8">
<div class="input-item">
<label>手机号码:</label>
<el-input
v-model="searchForm.phoneNumber"
placeholder="请输入"
@keyup.enter="handlePatientSearch"
clearable
/>
</div>
</el-col>
</el-row>
</div>
<!-- 患者信息显示 -->
<div class="patient-info-section">
<el-row :gutter="20">
<el-col :span="8">
<div class="info-item">
<label>门诊号码</label>
<div class="info-value">{{ patientInfo?.outpatientNo || '' }}</div>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
<label>病人姓名</label>
<div class="info-value">{{ patientInfo?.patientName || '' }}</div>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
<label>身份证号码</label>
<div class="info-value">{{ patientInfo?.idCard || '' }}</div>
</div>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 15px;">
<el-col :span="8">
<div class="info-item">
<label>手机号码</label>
<div class="info-value">{{ patientInfo?.phoneNumber || '' }}</div>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
<label>性别</label>
<div class="info-value">{{ patientInfo?.gender || '' }}</div>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
<label>年龄</label>
<div class="info-value">{{ patientInfo?.age || '' }}</div>
</div>
</el-col>
</el-row>
</div>
<!-- 新门诊号码输入 -->
<div class="new-number-section">
<div class="input-item">
<label>新门诊号码:</label>
<el-input
v-model="renewalForm.newOutpatientNo"
placeholder="请输入新门诊号码"
@keyup.enter="handleConfirm"
style="width: 250px;"
/>
</div>
</div>
<!-- 按钮区域已移除 -->
<!-- 患者列表对话框 -->
<el-dialog
v-model="showPatientList"
title="患者列表"
width="800px"
:close-on-click-modal="false"
>
<el-table
:data="patientList"
style="width: 100%"
@row-click="selectPatient"
highlight-current-row
>
<el-table-column label="序号" width="60" type="index">
</el-table-column>
<el-table-column label="病人姓名" width="120">
<template #default="scope">
{{ scope.row.patientName || scope.row.name || '-' }}
</template>
</el-table-column>
<el-table-column label="门诊号码" width="120">
<template #default="scope">
{{ scope.row.identifierNo || scope.row.cardNo || scope.row.card_number || scope.row.就诊卡号 || scope.row.outpatientNumber || scope.row.outpatientNo || scope.row.门诊号码 || scope.row.卡号 || scope.row.card || scope.row.patientNo || scope.row.patient_id || '-' }}
</template>
</el-table-column>
<el-table-column label="身份证号码" width="200">
<template #default="scope">
{{ scope.row.idCard || scope.row.id_card || scope.row.idNo || '-' }}
</template>
</el-table-column>
<el-table-column label="手机号码" width="120">
<template #default="scope">
{{ scope.row.phoneNumber || scope.row.phone || scope.row.mobile || scope.row.mobilePhone || '-' }}
</template>
</el-table-column>
<el-table-column label="性别" width="80">
<template #default="scope">
{{ scope.row.genderEnum_enumText || scope.row.gender || scope.row.sex || scope.row.性别 || scope.row.xb || scope.row.sexCode || scope.row.GENDER || scope.row.SEX || '-' }}
</template>
</el-table-column>
<el-table-column label="年龄" width="80">
<template #default="scope">
{{ scope.row.age || '-' }}
</template>
</el-table-column>
<el-table-column label="出生年月" width="120">
<template #default="scope">
{{ formatDate(scope.row.birthDate || scope.row.birthday || scope.row.出生日期) || '-' }}
</template>
</el-table-column>
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button @click="showPatientList = false">取消</el-button>
</span>
</template>
</el-dialog>
<!-- 换卡成功提示 -->
<el-dialog
v-model="renewalSuccessVisible"
title="换卡成功"
width="400px"
:close-on-click-modal="false"
>
<div style="text-align: center; padding: 20px;">
<div class="success-icon"></div>
<p style="margin-top: 15px; font-size: 16px;">患者换卡操作已成功完成</p>
<p style="margin-top: 10px;">新门诊号码{{ renewalForm.newOutpatientNo }}</p>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="renewalSuccessVisible = false; resetForm">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getPatientList, doCardRenewal } from '@/api/cardRenewal/api.js'
// 搜索表单
const searchForm = reactive({
patientName: '',
idCard: '',
phoneNumber: ''
})
// 患者信息
const patientInfo = ref(null)
// 患者列表
const patientList = ref([])
const showPatientList = ref(false)
// 换卡表单
const renewalForm = reactive({
newOutpatientNo: ''
})
// 加载状态
const loading = ref(false)
// 成功弹窗显示状态
const renewalSuccessVisible = ref(false)
// 查询患者信息
const handlePatientSearch = async () => {
// 检查是否至少填写了一个查询条件
if (!searchForm.patientName && !searchForm.idCard && !searchForm.phoneNumber) {
ElMessage.warning('请至少输入一个查询条件')
return
}
loading.value = true
try {
// 构建查询参数使用专门的换卡API
const queryParams = {
patientName: searchForm.patientName || '',
idCard: searchForm.idCard || '',
phoneNumber: searchForm.phoneNumber || ''
}
// 调用专门的换卡API获取患者列表
const response = await getPatientList(queryParams)
// 查询患者数据
if (response && response.code === 200) {
// 检查是否有查询结果
if (response.rows && response.rows.length > 0) {
// 如果只有一条记录,直接显示
if (response.rows.length === 1) {
const patient = response.rows[0]
// 获取门诊号码优先使用identifierNo
const outpatientNo = patient.identifierNo || patient.cardNo || patient.card_number || patient.就诊卡号 || patient.outpatientNumber || patient.outpatientNo || patient.门诊号码 || patient.卡号 || patient.card || patient.patientNo || patient.patient_id;
// 获取性别优先使用genderEnum_enumText
const gender = patient.genderEnum_enumText || patient.gender || patient.sex || patient.性别 || patient.xb || patient.sexCode || patient.GENDER || patient.SEX;
patientInfo.value = {
outpatientNo: outpatientNo,
patientName: patient.patientName || patient.name,
idCard: patient.idCard || patient.id_card || patient.idNo,
phoneNumber: patient.phoneNumber || patient.phone || patient.mobile || patient.mobilePhone,
gender: gender,
age: patient.age,
patientId: patient.patientId || outpatientNo
}
} else {
// 有多条记录时,显示患者列表供选择
showPatientList.value = true
patientList.value = response.rows
}
} else {
ElMessage.warning('未找到符合条件的患者信息')
}
} else {
ElMessage.error('查询失败:' + (response?.msg || '未知错误'))
}
} catch (error) {
ElMessage.error('查询失败,请稍后重试')
console.error('查询患者信息失败:', error)
} finally {
loading.value = false
}
}
// 确定换卡
const handleConfirm = async () => {
if (!patientInfo.value) {
ElMessage.warning('请先查询患者信息')
return
}
if (!renewalForm.newOutpatientNo) {
ElMessage.warning('请输入新门诊号码')
return
}
if (renewalForm.newOutpatientNo === patientInfo.value.outpatientNo) {
ElMessage.warning('新门诊号码不能与原号码相同')
return
}
loading.value = true
try {
// 构建换卡请求参数注意参数名称与API接口保持一致
const params = {
oldCardNo: patientInfo.value.outpatientNo,
newCardNo: renewalForm.newOutpatientNo,
patientId: patientInfo.value.patientId,
reason: '患者换卡',
remark: `${patientInfo.value.outpatientNo}更换到${renewalForm.newOutpatientNo}`
}
// 调用真实的换卡接口
const res = await doCardRenewal(params)
if (res && res.code === 200) {
renewalSuccessVisible.value = true
ElMessage.success('换卡成功!')
} else {
ElMessage.error('换卡失败:' + (res?.msg || '未知错误'))
}
} catch (error) {
ElMessage.error('换卡失败,请稍后重试')
console.error('换卡失败:', error)
} finally {
loading.value = false
}
}
// 关闭窗口
const handleClose = () => {
if (confirm('确定要关闭换卡窗口吗?')) {
resetForm()
// 如果是在弹窗中打开的,可以添加关闭弹窗的逻辑
// 否则可以导航回上一页
// this.$router.back()
}
}
// 键盘事件处理
const handleKeydown = (event) => {
// Alt + Q 查询
if (event.altKey && event.key.toLowerCase() === 'q') {
event.preventDefault()
handlePatientSearch()
}
// Alt + O 确定
if (event.altKey && event.key.toLowerCase() === 'o') {
event.preventDefault()
handleConfirm()
}
// Alt + C 关闭
if (event.altKey && event.key.toLowerCase() === 'c') {
event.preventDefault()
handleClose()
}
}
// 组件挂载时添加键盘事件监听
onMounted(() => {
document.addEventListener('keydown', handleKeydown)
})
// 组件卸载时移除键盘事件监听
onUnmounted(() => {
document.removeEventListener('keydown', handleKeydown)
})
// 移除了调试功能
// 选择患者
const selectPatient = (row) => {
// 获取门诊号码优先使用identifierNo
const outpatientNo = row.identifierNo || row.cardNo || row.card_number || row.就诊卡号 || row.outpatientNumber || row.outpatientNo || row.门诊号码 || row.卡号 || row.card || row.patientNo || row.patient_id;
// 获取性别优先使用genderEnum_enumText
const gender = row.genderEnum_enumText || row.gender || row.sex || row.性别 || row.xb || row.sexCode || row.GENDER || row.SEX;
patientInfo.value = {
outpatientNo: outpatientNo,
patientName: row.patientName || row.name,
idCard: row.idCard || row.id_card || row.idNo,
phoneNumber: row.phoneNumber || row.phone || row.mobile || row.mobilePhone,
gender: gender,
age: row.age,
patientId: row.patientId || outpatientNo
}
showPatientList.value = false
ElMessage.success('已选择患者:' + (row.patientName || row.name))
}
// 重置表单
const resetForm = () => {
searchForm.patientName = ''
searchForm.idCard = ''
searchForm.phoneNumber = ''
patientInfo.value = null
patientList.value = []
showPatientList.value = false
renewalForm.newOutpatientNo = ''
}
// 格式化日期为YYYY-MM-DD格式
const formatDate = (date) => {
if (!date) return ''
// 如果已经是YYYY-MM-DD格式直接返回
if (typeof date === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
return date
}
// 处理日期对象或其他格式
const d = new Date(date)
if (isNaN(d.getTime())) return ''
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
</script>
<style scoped>
/* 对话框标题样式 */
.el-dialog__header {
background-color: #fff;
padding: 15px 20px;
border-bottom: 1px solid #ebeef5;
margin: 0;
}
.el-dialog__title {
font-size: 16px;
color: #303133;
font-weight: 500;
}
/* 按钮样式 */
.dialog-footer {
display: flex;
justify-content: center;
padding: 15px 20px;
background-color: #fff;
border-top: 1px solid #ebeef5;
}
.dialog-footer .el-button {
min-width: 80px;
background-color: #f56c6c;
border-color: #f56c6c;
color: white;
}
/* 表格样式 */
.el-dialog__body {
padding: 0;
overflow: hidden;
}
.el-table {
margin: 0;
}
.el-table th {
background-color: #f5f7fa;
font-weight: 500;
color: #303133;
}
.el-table td {
text-align: left;
}
/* 恢复默认表格样式 */
.el-table tr:hover > td {
background-color: #f5f7fa;
}
.el-table--striped .el-table__body tr:nth-child(2n) {
background-color: #fafafa;
}
.card-renewal-container {
width: 100%;
max-width: 800px;
margin: 0 auto;
padding: 10px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background: #fff;
}
.title-bar {
background: #409eff;
color: white;
padding: 10px 15px;
margin: -10px -10px 15px -10px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.title-bar h2 {
margin: 0;
font-size: 16px;
font-weight: normal;
}
.button-bar {
display: flex;
gap: 15px;
padding: 15px;
background-color: #f5f7fa;
border: 1px solid #ebeef5;
margin-bottom: 20px;
}
.button-bar .el-button {
font-weight: 500;
transition: all 0.3s ease;
}
.button-bar .el-button:hover {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.search-section {
margin-bottom: 20px;
}
.input-item {
margin-bottom: 15px;
}
.input-item label {
display: inline-block;
width: 100px;
text-align: right;
margin-right: 10px;
font-weight: 500;
}
.patient-info-section {
background: #f5f7fa;
padding: 15px;
border-radius: 4px;
margin-bottom: 20px;
}
.info-item label {
display: block;
color: #606266;
font-size: 14px;
margin-bottom: 5px;
}
.info-value {
color: #303133;
font-weight: 500;
}
.new-number-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #ebeef5;
}
.success-icon {
width: 50px;
height: 50px;
background: #67c23a;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
margin: 0 auto;
}
</style>