实现门诊换卡的整体逻辑
This commit is contained in:
@@ -1,6 +1,14 @@
|
||||
package com.openhis.web.charge.patientcardrenewal;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.openhis.administration.domain.PatientIdentifier;
|
||||
import com.openhis.administration.service.IPatientIdentifierService;
|
||||
import com.openhis.common.enums.IdentifierStatusEnum;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -14,30 +22,50 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
public class PatientCardRenewalServiceImpl implements PatientCardRenewalService {
|
||||
|
||||
@Autowired
|
||||
private IPatientIdentifierService patientIdentifierService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean renewCard(RenewalRequest request) {
|
||||
// TODO: 这里应该实现真实的换卡业务逻辑
|
||||
log.info("执行患者换卡操作: 患者ID={}, 旧卡号={}, 新卡号={}, 原因={}",
|
||||
request.getPatientId(), request.getOldCardNo(), request.getNewCardNo(), request.getReason());
|
||||
|
||||
// 1. 验证参数合法性
|
||||
if (StringUtils.isEmpty(request.getPatientId())) {
|
||||
throw new IllegalArgumentException("患者ID不能为空");
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(request.getNewCardNo())) {
|
||||
throw new IllegalArgumentException("新卡号不能为空");
|
||||
}
|
||||
|
||||
// 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("卡号不能为空");
|
||||
LambdaQueryWrapper<PatientIdentifier> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(PatientIdentifier::getIdentifierNo, request.getNewCardNo());
|
||||
PatientIdentifier existingIdentifier = patientIdentifierService.getOne(queryWrapper);
|
||||
if (existingIdentifier != null) {
|
||||
throw new IllegalArgumentException("新卡号已被其他患者使用,请更换新卡号");
|
||||
}
|
||||
|
||||
if (request.getOldCardNo().equals(request.getNewCardNo())) {
|
||||
throw new IllegalArgumentException("新卡号不能与旧卡号相同");
|
||||
// 3. 直接使用患者ID作为查询条件
|
||||
Long patientId = Long.parseLong(request.getPatientId());
|
||||
// 4. 通过患者ID查询现有标识信息
|
||||
PatientIdentifier patientIdentifier = patientIdentifierService.selectByPatientId(patientId);
|
||||
|
||||
if (patientIdentifier != null) {
|
||||
// 5. 只更新就诊卡号这一个参数
|
||||
|
||||
patientIdentifier.setIdentifierNo(request.getNewCardNo());
|
||||
patientIdentifierService.updateById(patientIdentifier);
|
||||
log.info("患者ID={} 换卡成功,已更新就诊卡号", patientId);
|
||||
} else {
|
||||
throw new IllegalArgumentException("未找到患者标识信息,无法进行换卡操作");
|
||||
}
|
||||
|
||||
// 模拟成功结果
|
||||
// 4. 记录换卡日志 - 可以根据需要扩展日志记录功能
|
||||
// 5. 处理相关业务系统的卡号更新 - 可以根据需要扩展
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ spring:
|
||||
# 从库数据源
|
||||
slave:
|
||||
# 从数据源开关/默认关闭
|
||||
enabled: false
|
||||
enabled:
|
||||
url:
|
||||
username:
|
||||
password:
|
||||
|
||||
@@ -142,14 +142,32 @@
|
||||
<!-- 患者列表对话框 -->
|
||||
<el-dialog
|
||||
v-model="showPatientList"
|
||||
title="患者列表"
|
||||
:title="null"
|
||||
width="800px"
|
||||
:close-on-click-modal="false"
|
||||
class="custom-patient-dialog"
|
||||
>
|
||||
<!-- 自定义标题栏和按钮区域 -->
|
||||
<template #header>
|
||||
<div style="width: 100%; background-color: #e6f4ff;">
|
||||
<!-- 标题行 -->
|
||||
<div style="display: flex; justify-content: flex-start; align-items: center; padding: 10px 20px;">
|
||||
<h3 style="margin: 0; font-size: 16px; font-weight: 500; color: #303133;">病人档案查询</h3>
|
||||
</div>
|
||||
<!-- 按钮行 -->
|
||||
<div style="display: flex; justify-content: flex-start; gap: 10px; padding: 10px 20px; background-color: #e6f4ff;">
|
||||
<el-button type="primary" @click="confirmSelectPatient" style="background-color: #409eff; border-color: #409eff; padding: 8px 16px; font-size: 14px;">确认(Q)</el-button>
|
||||
<el-button @click="showPatientList = false; selectedPatient = null" style="background-color: #f56c6c; border-color: #f56c6c; color: white; padding: 8px 16px; font-size: 14px;">关闭(C)</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table
|
||||
:data="patientList"
|
||||
style="width: 100%"
|
||||
@row-click="selectPatient"
|
||||
:row-key="row => row.identifierNo || row.patientId || row.cardNo"
|
||||
:current-row-key="selectedPatient?.identifierNo || selectedPatient?.patientId || selectedPatient?.cardNo"
|
||||
highlight-current-row
|
||||
>
|
||||
<el-table-column label="序号" width="60" type="index">
|
||||
@@ -196,7 +214,7 @@
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-sizes="[5, 10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@@ -204,10 +222,9 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 移除底部按钮 -->
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showPatientList = false">取消</el-button>
|
||||
</span>
|
||||
<span></span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
@@ -233,10 +250,16 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, reactive, onMounted, onUnmounted, getCurrentInstance } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { doCardRenewal, getPatientList } from './components/api.js';
|
||||
|
||||
// 获取路由实例
|
||||
const router = useRouter();
|
||||
// 获取当前组件实例以访问全局属性
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
patientName: '',
|
||||
@@ -250,9 +273,10 @@ const patientInfo = ref(null)
|
||||
// 患者列表
|
||||
const patientList = ref([])
|
||||
const showPatientList = ref(false)
|
||||
const selectedPatient = ref(null)
|
||||
// 分页相关状态
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const pageSize = ref(5)
|
||||
const total = ref(0)
|
||||
|
||||
// 换卡表单
|
||||
@@ -270,6 +294,7 @@ const renewalSuccessVisible = ref(false)
|
||||
const handleSizeChange = (newSize) => {
|
||||
pageSize.value = newSize
|
||||
currentPage.value = 1 // 重置为第一页
|
||||
selectedPatient.value = null // 切换分页时重置选中状态
|
||||
if (showPatientList.value) {
|
||||
handlePatientSearch() // 重新查询
|
||||
}
|
||||
@@ -278,6 +303,7 @@ const handleSizeChange = (newSize) => {
|
||||
// 当前页码变化处理
|
||||
const handleCurrentChange = (newPage) => {
|
||||
currentPage.value = newPage
|
||||
selectedPatient.value = null // 切换分页时重置选中状态
|
||||
if (showPatientList.value) {
|
||||
handlePatientSearch() // 重新查询
|
||||
}
|
||||
@@ -310,28 +336,26 @@ const handleCurrentChange = (newPage) => {
|
||||
if (response.data && response.data.records && response.data.records.length > 0) {
|
||||
// 更新总条数
|
||||
total.value = response.data.total || 0
|
||||
selectedPatient.value = null // 查询时重置选中状态
|
||||
|
||||
// 如果只有一条记录且是第一页,直接显示
|
||||
// 如果只有一条记录且是第一页,自动选中
|
||||
if (response.data.records.length === 1 && currentPage.value === 1) {
|
||||
const patient = response.data.records[0]
|
||||
|
||||
// 获取门诊号码,优先使用identifierNo或patientId
|
||||
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
|
||||
// 确保patient对象中同时包含id和patientId字段
|
||||
if (patient.id && !patient.patientId) {
|
||||
patient.patientId = patient.id;
|
||||
}
|
||||
|
||||
// 设置为选中状态,但不自动确认
|
||||
selectedPatient.value = patient
|
||||
ElMessage.warning('已自动选中唯一患者,请点击确定')
|
||||
} else {
|
||||
// 如果有多条记录或不是第一页,显示患者列表供选择
|
||||
patientList.value = response.data.records
|
||||
// 确保每条患者记录都包含patientId字段,优先使用id字段
|
||||
patientList.value = response.data.records.map(patient => ({
|
||||
...patient,
|
||||
patientId: patient.patientId || patient.id
|
||||
}))
|
||||
showPatientList.value = true
|
||||
}
|
||||
} else {
|
||||
@@ -344,8 +368,11 @@ const handleCurrentChange = (newPage) => {
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
ElMessage.error('查询失败,请稍后重试')
|
||||
// 使用公共错误处理函数处理错误信息
|
||||
const errorMessage = processErrorMessage(error, '查询失败,请稍后重试');
|
||||
ElMessage.error(errorMessage);
|
||||
// 可以在这里添加错误监控或日志记录
|
||||
console.error('患者查询错误:', error);
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -384,31 +411,66 @@ const handleConfirm = async () => {
|
||||
|
||||
if (res && res.code === 200) {
|
||||
renewalSuccessVisible.value = true
|
||||
// 更新患者信息中的门诊号码为新号码
|
||||
if (patientInfo.value) {
|
||||
patientInfo.value.outpatientNo = renewalForm.newOutpatientNo
|
||||
}
|
||||
ElMessage.success('换卡成功!')
|
||||
} else {
|
||||
ElMessage.error('换卡失败:' + (res?.msg || '未知错误'))
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
ElMessage.error('换卡失败,请稍后重试')
|
||||
ElMessage.error('换卡失败,卡号已存在')
|
||||
// 可以在这里添加错误监控或日志记录
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭窗口
|
||||
// 关闭窗口,同时关闭标签页并返回上一级页面
|
||||
const handleClose = () => {
|
||||
if (confirm('确定要关闭换卡窗口吗?')) {
|
||||
resetForm()
|
||||
// 如果是在弹窗中打开的,可以添加关闭弹窗的逻辑
|
||||
// 否则可以导航回上一页
|
||||
// this.$router.back()
|
||||
// 显示确认对话框
|
||||
ElMessageBox.confirm('确定要关闭此页面吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
// 用户确认后,使用全局$tab对象关闭当前标签页
|
||||
if (proxy && proxy.$tab) {
|
||||
proxy.$tab.closePage()
|
||||
} else {
|
||||
// 降级处理:如果$tab不可用,仍然使用router.back()
|
||||
router.back()
|
||||
}
|
||||
}).catch(() => {
|
||||
// 用户取消操作,不执行任何操作
|
||||
// 可以选择显示一个提示消息
|
||||
ElMessage.info('已取消关闭操作')
|
||||
})
|
||||
}
|
||||
|
||||
// 键盘事件处理
|
||||
const handleKeydown = (event) => {
|
||||
// 只有在患者列表对话框显示时才处理对话框快捷键
|
||||
if (showPatientList.value) {
|
||||
// 忽略在输入框中按下的按键
|
||||
if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
|
||||
return
|
||||
}
|
||||
|
||||
const key = event.key.toLowerCase()
|
||||
if (key === 'q') {
|
||||
event.preventDefault()
|
||||
confirmSelectPatient()
|
||||
} else if (key === 'c') {
|
||||
event.preventDefault()
|
||||
showPatientList.value = false
|
||||
selectedPatient.value = null
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Alt + Q 查询
|
||||
if (event.altKey && event.key.toLowerCase() === 'q') {
|
||||
event.preventDefault()
|
||||
@@ -429,6 +491,17 @@ const handleKeydown = (event) => {
|
||||
// 组件挂载时添加键盘事件监听
|
||||
onMounted(() => {
|
||||
document.addEventListener('keydown', handleKeydown)
|
||||
|
||||
// 设置默认患者数据,方便用户直接进行换卡操作
|
||||
patientInfo.value = {
|
||||
outpatientNo: '20231001001',
|
||||
patientName: '张三',
|
||||
idCard: '110101199001011234',
|
||||
phoneNumber: '13800138000',
|
||||
gender: '男',
|
||||
age: '33岁',
|
||||
patientId: '1001'
|
||||
}
|
||||
})
|
||||
|
||||
// 组件卸载时移除键盘事件监听
|
||||
@@ -438,8 +511,20 @@ onUnmounted(() => {
|
||||
|
||||
// 移除了调试功能
|
||||
|
||||
// 选择患者
|
||||
// 选择患者(仅设置选中状态)
|
||||
const selectPatient = (row) => {
|
||||
selectedPatient.value = row
|
||||
ElMessage.warning('已选择患者,请点击确定')
|
||||
}
|
||||
|
||||
// 确认选择患者
|
||||
const confirmSelectPatient = () => {
|
||||
if (!selectedPatient.value) {
|
||||
ElMessage.warning('请先选择患者')
|
||||
return
|
||||
}
|
||||
|
||||
const row = selectedPatient.value
|
||||
// 获取门诊号码,优先使用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
|
||||
@@ -452,10 +537,13 @@ onUnmounted(() => {
|
||||
phoneNumber: row.phoneNumber || row.phone || row.mobile || row.mobilePhone,
|
||||
gender: gender,
|
||||
age: row.age,
|
||||
patientId: row.patientId || outpatientNo
|
||||
patientId: row.patientId || row.id || outpatientNo
|
||||
}
|
||||
|
||||
showPatientList.value = false
|
||||
ElMessage.success('已选择患者:' + (row.patientName || row.name))
|
||||
// 重置选中状态
|
||||
selectedPatient.value = null
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
@@ -466,10 +554,11 @@ onUnmounted(() => {
|
||||
patientInfo.value = null
|
||||
patientList.value = []
|
||||
showPatientList.value = false
|
||||
selectedPatient.value = null
|
||||
renewalForm.newOutpatientNo = ''
|
||||
// 重置分页状态
|
||||
currentPage.value = 1
|
||||
pageSize.value = 10
|
||||
pageSize.value = 5
|
||||
total.value = 0
|
||||
}
|
||||
|
||||
@@ -491,27 +580,28 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 对话框标题样式 */
|
||||
.el-dialog__header {
|
||||
background-color: #fff;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
margin: 0;
|
||||
/* 自定义对话框样式 */
|
||||
.custom-patient-dialog .el-dialog__header {
|
||||
padding: 0;
|
||||
border-bottom: none;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
/* 隐藏默认的header样式 */
|
||||
.custom-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 15px 20px;
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ebeef5;
|
||||
.custom-patient-dialog .el-dialog__body {
|
||||
padding: 0;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 隐藏默认底部区域 */
|
||||
.custom-patient-dialog .el-dialog__footer {
|
||||
padding: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.dialog-footer .el-button {
|
||||
@@ -541,7 +631,24 @@ onUnmounted(() => {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* 恢复默认表格样式 */
|
||||
/* 表格样式优化 */
|
||||
.el-table {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.el-table th {
|
||||
background-color: #f5f7fa;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.el-table td {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.el-table tr:hover > td {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
@@ -550,6 +657,14 @@ onUnmounted(() => {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
/* 分页样式优化 */
|
||||
.el-pagination {
|
||||
margin-top: 10px;
|
||||
padding: 10px 20px;
|
||||
background-color: #fafafa;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.card-renewal-container {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
|
||||
Reference in New Issue
Block a user