维护换卡处理的查询

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,53 @@
package com.openhis.web.charge.patientcardrenewal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.core.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
/**
* 患者换卡控制器
*
* @author system
* @date 2024-01-01
*/
@RestController
@RequestMapping("/charge/patientCardRenewal")
@Slf4j
public class PatientCardRenewalController {
@Autowired
private PatientCardRenewalService patientCardRenewalService;
/**
* 执行患者换卡操作
*
* @param request 换卡请求参数
* @return 换卡结果
*/
@PostMapping("/renewCard")
public R<?> renewCard(@RequestBody RenewalRequest request) {
try {
log.info("患者换卡请求: 旧卡号={}, 新卡号={}, 患者ID={}",
request.getOldCardNo(), request.getNewCardNo(), request.getPatientId());
// 执行换卡操作
boolean success = patientCardRenewalService.renewCard(request);
if (success) {
log.info("患者换卡成功: 旧卡号={} -> 新卡号={}",
request.getOldCardNo(), request.getNewCardNo());
return R.ok("换卡成功");
} else {
return R.fail("换卡失败");
}
} catch (Exception e) {
log.error("患者换卡异常: ", e);
return R.fail("换卡操作异常: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,18 @@
package com.openhis.web.charge.patientcardrenewal;
/**
* 患者换卡服务接口
*
* @author system
* @date 2024-01-01
*/
public interface PatientCardRenewalService {
/**
* 执行患者换卡操作
*
* @param request 换卡请求参数
* @return 是否换卡成功
*/
boolean renewCard(RenewalRequest request);
}

View File

@@ -0,0 +1,43 @@
package com.openhis.web.charge.patientcardrenewal;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
/**
* 患者换卡服务实现类
*
* @author system
* @date 2024-01-01
*/
@Service
@Slf4j
public class PatientCardRenewalServiceImpl implements PatientCardRenewalService {
@Override
public boolean renewCard(RenewalRequest request) {
// TODO: 这里应该实现真实的换卡业务逻辑
// 1. 验证参数合法性
// 2. 检查新卡号是否已被使用
// 3. 更新患者主表中的卡号信息
// 4. 记录换卡日志
// 5. 处理相关业务系统的卡号更新
// 目前返回模拟结果
log.info("模拟执行患者换卡操作: 旧卡号={}, 新卡号={}, 原因={}",
request.getOldCardNo(), request.getNewCardNo(), request.getReason());
// 简单验证:确保旧卡号和新卡号不为空且不相同
if (request.getOldCardNo() == null || request.getNewCardNo() == null ||
request.getOldCardNo().isEmpty() || request.getNewCardNo().isEmpty()) {
throw new IllegalArgumentException("卡号不能为空");
}
if (request.getOldCardNo().equals(request.getNewCardNo())) {
throw new IllegalArgumentException("新卡号不能与旧卡号相同");
}
// 模拟成功结果
return true;
}
}

View File

@@ -0,0 +1,38 @@
package com.openhis.web.charge.patientcardrenewal;
import lombok.Data;
/**
* 换卡请求参数类
*
* @author system
* @date 2024-01-01
*/
@Data
public class RenewalRequest {
/**
* 旧门诊号码
*/
private String oldCardNo;
/**
* 新门诊号码
*/
private String newCardNo;
/**
* 患者ID
*/
private String patientId;
/**
* 换卡原因
*/
private String reason;
/**
* 备注信息
*/
private String remark;
}

View File

@@ -91,9 +91,9 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
*/ */
@Override @Override
public Page<PatientMetadata> getPatientMetadataBySearchKey(String searchKey, Integer pageNo, Integer pageSize) { public Page<PatientMetadata> getPatientMetadataBySearchKey(String searchKey, Integer pageNo, Integer pageSize) {
// 构建查询条件 // 构建查询条件添加phone字段支持手机号搜索
QueryWrapper<Patient> queryWrapper = HisQueryUtils.buildQueryWrapper(null, searchKey, QueryWrapper<Patient> queryWrapper = HisQueryUtils.buildQueryWrapper(null, searchKey,
new HashSet<>(Arrays.asList("id_card", "name", "py_str", "wb_str")), null); new HashSet<>(Arrays.asList("id_card", "name", "py_str", "wb_str", "phone")), null);
// 设置排序 // 设置排序
queryWrapper.orderByDesc("update_time"); queryWrapper.orderByDesc("update_time");
// 通过证件号匹配 patient // 通过证件号匹配 patient

View File

@@ -128,10 +128,11 @@ public class PatientInformationServiceImpl implements IPatientInformationService
public IPage<PatientInformationDto> getPatientInfo(PatientInfoSearchParam patientInfoSearchParam, String searchKey, public IPage<PatientInformationDto> getPatientInfo(PatientInfoSearchParam patientInfoSearchParam, String searchKey,
Integer pageNo, Integer pageSize, HttpServletRequest request) { Integer pageNo, Integer pageSize, HttpServletRequest request) {
// 构建查询条件 // 构建查询条件 - 添加phone字段到搜索条件中
QueryWrapper<PatientInformationDto> queryWrapper = HisQueryUtils.buildQueryWrapper( QueryWrapper<PatientInformationDto> queryWrapper = HisQueryUtils.buildQueryWrapper(
patientInfoSearchParam, searchKey, new HashSet<>(Arrays.asList(CommonConstants.FieldName.Name, patientInfoSearchParam, searchKey, new HashSet<>(Arrays.asList(CommonConstants.FieldName.Name,
CommonConstants.FieldName.BusNo, CommonConstants.FieldName.PyStr, CommonConstants.FieldName.WbStr)), CommonConstants.FieldName.BusNo, CommonConstants.FieldName.PyStr, CommonConstants.FieldName.WbStr,
CommonConstants.FieldName.Phone)), // 添加phone字段支持手机号搜索
request); request);
IPage<PatientInformationDto> patientInformationPage = IPage<PatientInformationDto> patientInformationPage =

View File

@@ -142,6 +142,11 @@ public class CommonConstants {
*/ */
public interface FieldName { public interface FieldName {
/**
* 手机号
*/
String Phone = "phone";
/** /**
* 单据号 * 单据号
*/ */

View File

@@ -0,0 +1,94 @@
import request from '@/utils/request';
// 查询患者列表 - 更新为匹配后端实际路径
export function getPatientList(query) {
console.log('查询患者列表API被调用参数:', query);
// 调整参数以匹配后端控制器的要求
const backendParams = {
patientName: query.patientName || '',
idCard: query.idCard || '',
phoneNumber: query.phoneNumber || '', // 添加phoneNumber参数
cardNo: '' // 后端控制器中有cardNo参数但前端没有可以传空字符串
};
console.log('调整后的后端参数:', backendParams);
// 实际API调用代码 - 使用后端实际路径
return request({
url: '/openhis/charge/patientCardRenewal/getPatientInfo',
method: 'get',
params: backendParams
}).then(response => {
console.log('API返回结果:', response);
// 转换后端返回格式以适应前端组件
if (response && response.code === 200) {
// 检查后端返回的数据结构
if (Array.isArray(response.data)) {
// 如果是数组,直接使用
return {
code: 200,
msg: 'success',
rows: response.data,
total: response.data.length
};
} else if (response.data) {
// 如果是单个对象,包装成数组
return {
code: 200,
msg: 'success',
rows: [response.data],
total: 1
};
}
}
// 默认返回空数据
return {
code: response?.code || 500,
msg: response?.msg || '查询失败',
rows: [],
total: 0
};
}).catch(error => {
console.error('查询患者列表API调用失败:', error);
// API调用失败时返回空数据
return {
code: 500,
msg: 'API调用失败',
rows: [],
total: 0
};
});
}
// 执行患者换卡
export function renewPatientCard(data) {
return request({
url: '/cardRenewal/card/renewal',
method: 'post',
data: data
}).catch(error => {
console.error('换卡操作API调用失败:', error);
return {
code: 500,
msg: 'API调用失败'
};
});
}
// 获取患者详细信息
export function getPatientInfo(patientId) {
return request({
url: '/cardRenewal/patient/info/' + patientId,
method: 'get'
}).catch(error => {
console.error('获取患者详细信息API调用失败:', error);
return {
code: 500,
msg: 'API调用失败',
data: {}
};
});
}

View File

@@ -0,0 +1,19 @@
import request from '@/utils/request'
/**
* 执行患者换卡操作
* @param {Object} params - 换卡参数
* @param {string} params.oldCardNo - 旧门诊号码
* @param {string} params.newCardNo - 新门诊号码
* @param {string} params.patientId - 患者ID
* @param {string} params.reason - 换卡原因
* @param {string} params.remark - 备注信息
* @returns {Promise} 请求结果
*/
export const doCardRenewal = (params) => {
return request({
url: '/charge/patientCardRenewal/renewCard',
method: 'post',
data: params
})
}

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>

View File

@@ -0,0 +1,342 @@
<template>
<div class="patient-search-container">
<!-- 标题栏 -->
<div class="title-bar">
<h2>病人档案查询</h2>
<div class="button-bar">
<el-button
type="primary"
@click="handleQuery"
:loading="loading"
size="large"
icon="el-icon-check"
>
确认(Q)
</el-button>
<el-button
type="danger"
@click="handleClose"
size="large"
icon="el-icon-close"
>
关闭(C)
</el-button>
</div>
</div>
<!-- 查询表单 -->
<div class="search-form">
<el-row :gutter="20">
<el-col :span="8">
<div class="form-item">
<label>病人姓名:</label>
<el-input
v-model="searchForm.patientName"
placeholder="请输入病人姓名"
clearable
@keyup.enter="handleQuery"
/>
</div>
</el-col>
<el-col :span="8">
<div class="form-item">
<label>身份证号码:</label>
<el-input
v-model="searchForm.idCard"
placeholder="请输入身份证号码"
clearable
@keyup.enter="handleQuery"
/>
</div>
</el-col>
<el-col :span="8">
<div class="form-item">
<label>手机号码:</label>
<el-input
v-model="searchForm.phoneNumber"
placeholder="请输入手机号码"
clearable
@keyup.enter="handleQuery"
/>
</div>
</el-col>
</el-row>
</div>
<!-- 查询结果表格 -->
<div class="result-table">
<el-table
:data="patientList"
style="width: 100%"
stripe
@row-click="handleRowClick"
highlight-current-row
row-key="id"
:current-row-key="selectedPatient?.id"
>
<el-table-column label="序号" type="index" width="80" align="center">
</el-table-column>
<el-table-column label="病人姓名" width="120" align="center">
<template #default="scope">
{{ scope.row.patientName }}
</template>
</el-table-column>
<el-table-column label="门诊号码" width="150" align="center">
<template #default="scope">
{{ scope.row.outpatientNo || '-' }}
</template>
</el-table-column>
<el-table-column label="身份证号码" width="200" align="center">
<template #default="scope">
{{ scope.row.idCard || '-' }}
</template>
</el-table-column>
<el-table-column label="手机号码" width="120" align="center">
<template #default="scope">
{{ scope.row.phoneNumber || '-' }}
</template>
</el-table-column>
<el-table-column label="性别" width="80" align="center">
<template #default="scope">
{{ scope.row.gender }}
</template>
</el-table-column>
<el-table-column label="年龄" width="80" align="center">
<template #default="scope">
{{ scope.row.age }}
</template>
</el-table-column>
<el-table-column label="出生年月" width="120" align="center">
<template #default="scope">
{{ scope.row.birthDate }}
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { getOutpatientRegistrationList } from '../outpatientregistration/components/outpatientregistration'
// 搜索表单
const searchForm = reactive({
patientName: '',
idCard: '',
phoneNumber: ''
})
// 患者列表
const patientList = ref([])
// 加载状态
const loading = ref(false)
// API调用相关变量
const queryParams = ref({
pageNum: 1,
pageSize: 50
})
// 当前选中的患者
const selectedPatient = ref(null)
// 定义事件
const emit = defineEmits(['selectPatient', 'close'])
// 计算搜索关键字合并三个字段为一个searchKey
const searchKey = computed(() => {
return searchForm.patientName || searchForm.idCard || searchForm.phoneNumber
})
// 监听搜索关键字变化,自动查询
watch(searchKey, (newValue) => {
// 当搜索关键字变化时,延迟查询,避免频繁请求
const timer = setTimeout(() => {
if (newValue) {
queryParams.value.searchKey = newValue
handleQuery()
}
}, 300)
return () => clearTimeout(timer)
})
// 处理行点击
const handleRowClick = (row) => {
selectedPatient.value = row
ElMessage.success(`已选择患者:${row.patientName}`)
}
// 查询患者信息和确认选择
const handleQuery = async () => {
// 如果已经选中了患者,则确认选择
if (selectedPatient.value) {
// 发射选择患者事件
emit('selectPatient', selectedPatient.value)
ElMessage.success(`已确认选择患者:${selectedPatient.value.patientName}`)
return
}
// 检查是否至少填写了一个查询条件
if (!searchKey.value) {
ElMessage.warning('请至少输入一个查询条件')
return
}
loading.value = true
try {
// 调用门诊挂号的API获取患者列表
const response = await getOutpatientRegistrationList(queryParams.value)
if (response.data && response.data.records) {
// 映射字段,使其与表格展示需求匹配
patientList.value = response.data.records.map(record => ({
id: record.id,
patientName: record.name,
outpatientNo: record.identifierNo,
idCard: record.idCard,
phoneNumber: record.phone,
gender: record.genderEnum_enumText || '-',
age: record.age || '-',
birthDate: record.birthDate || '-' // 如果后端没有提供,需要计算或显示为'-'
}))
if (patientList.value.length === 0) {
ElMessage.warning('未找到符合条件的患者信息')
}
} else {
ElMessage.error('查询失败')
patientList.value = []
}
} catch (error) {
ElMessage.error('查询失败,请稍后重试')
console.error('查询失败:', error)
patientList.value = []
} finally {
loading.value = false
}
}
// 关闭窗口
const handleClose = () => {
// 发射关闭事件
emit('close')
}
// 键盘事件处理
const handleKeydown = (event) => {
// Alt + Q 查询
if (event.altKey && event.key.toLowerCase() === 'q') {
event.preventDefault()
handleQuery()
}
// Alt + C 关闭
if (event.altKey && event.key.toLowerCase() === 'c') {
event.preventDefault()
handleClose()
}
}
// 组件挂载时添加键盘事件监听
onMounted(() => {
document.addEventListener('keydown', handleKeydown)
})
// 组件卸载时移除键盘事件监听
onUnmounted(() => {
document.removeEventListener('keydown', handleKeydown)
})
</script>
<style scoped>
.patient-search-container {
width: 100%;
background-color: #fff;
border: 1px solid #b3d4ff;
border-radius: 4px;
overflow: hidden;
}
.title-bar {
background-color: #d6e9ff;
padding: 10px 20px;
border-bottom: 1px solid #b3d4ff;
display: flex;
justify-content: space-between;
align-items: center;
}
.title-bar h2 {
margin: 0;
font-size: 18px;
color: #303133;
font-weight: 500;
}
.button-bar {
padding: 10px 20px;
display: flex;
gap: 10px;
}
.button-bar .el-button {
padding: 12px 24px;
font-size: 16px;
}
.search-form {
padding: 20px;
border-bottom: 1px solid #dcdfe6;
}
.form-item {
margin-bottom: 15px;
display: flex;
align-items: center;
}
.form-item label {
display: inline-block;
width: 100px;
text-align: right;
margin-right: 10px;
font-weight: 500;
color: #303133;
}
.form-item .el-input {
width: 250px;
}
.result-table {
padding: 10px;
}
.el-table {
border: 1px solid #dcdfe6;
border-radius: 4px;
}
.el-table th {
background-color: #f2f6fc;
font-weight: 600;
color: #303133;
border-bottom: 1px solid #e6e8eb;
}
.el-table td {
padding: 10px 0;
font-size: 14px;
border-bottom: 1px solid #ebeef5;
}
.el-table--striped .el-table__body tr:nth-child(2n) {
background-color: #f8f9fa;
}
.el-table__row:hover {
background-color: #f5f7fa;
}
</style>

View File

@@ -0,0 +1,48 @@
import request from '@/utils/request'
/**
* 获取门诊患者信息列表
* 复用门诊挂号的API来查询患者信息
*/
export const getOutpatientRegistrationList = (params) => {
// 调用门诊挂号的API获取患者信息
return request({
url: '/api/outpatient/registration/list',
method: 'get',
params
})
}
/**
* 根据ID获取患者详情
*/
export const getPatientById = (id) => {
return request({
url: `/api/outpatient/registration/${id}`,
method: 'get'
})
}
/**
* 根据条件查询患者信息
* 复用门诊挂号API进行查询
*/
export const getPatientList = (params) => {
// 复用门诊挂号的API
return request({
url: '/api/outpatient/registration/list',
method: 'get',
params
})
}
/**
* 根据门诊号码获取患者详细信息
*/
export const getPatientByOutpatientNo = (outpatientNo) => {
return request({
url: '/api/outpatient/registration/list',
method: 'get',
params: { identifierNo: outpatientNo }
})
}