fix: 添加时间过滤功能,自动过滤已过期的号源预约

This commit is contained in:
赵云
2026-04-09 09:27:47 +08:00
parent 8af6933a89
commit 82951fe941

View File

@@ -11,7 +11,7 @@
<div class="search-label">手机号</div> <div class="search-label">手机号</div>
<div class="search-label"></div> <!-- 为查询按钮预留空间 --> <div class="search-label"></div> <!-- 为查询按钮预留空间 -->
</div> </div>
<!-- 搜索输入行 --> <!-- 搜索输入行 -->
<div class="search-inputs"> <div class="search-inputs">
<!-- 移动端汉堡菜单按钮 --> <!-- 移动端汉堡菜单按钮 -->
@@ -94,7 +94,7 @@
<input id="doctor-search" class="search-input" placeholder="搜索医生姓名" v-model="searchQuery" @input="onDoctorSearch"> <input id="doctor-search" class="search-input" placeholder="搜索医生姓名" v-model="searchQuery" @input="onDoctorSearch">
<div class="doctor-list"> <div class="doctor-list">
<div class="doctor-item" v-for="doctor in filteredDoctors" :key="doctor.id" :class="{ selected: selectedDoctorId === doctor.id }" @click="selectDoctor(doctor.id)"> <div class="doctor-item" v-for="doctor in filteredDoctors" :key="doctor.id" :class="{ selected: selectedDoctorId === doctor.id }" @click="selectDoctor(doctor.id)">
<div class="doctor-name">{{ doctor.name }} <span class="doctor-available">余号{{ doctor.available }}</span></div> <div class="doctor-name">{{ doctor.name }} <span class="doctor-available">余号:{{ doctor.available }}</span></div>
</div> </div>
</div> </div>
</div> </div>
@@ -114,14 +114,14 @@
<span class="status-dot"></span> <span class="status-dot"></span>
{{ item.status }} {{ item.status }}
</div> </div>
<!-- 3. 医生姓名截断显示悬停展示完整信息 --> <!-- 3. 医生姓名(截断显示,悬停展示完整信息) -->
<div class="ticket-doctor" :title="item.doctor">{{ item.doctor }}</div> <div class="ticket-doctor" :title="item.doctor">{{ item.doctor }}</div>
<!-- 4. 科室名称 --> <!-- 4. 科室名称 -->
<div class="ticket-department" :title="item.department || '未知科室'"> <div class="ticket-department" :title="item.department || '未知科室'">
科室{{ item.department || '未知科室' }} 科室:{{ item.department || '未知科室' }}
</div> </div>
<!-- 5. 挂号费 --> <!-- 5. 挂号费 -->
<div class="ticket-fee">挂号费{{ item.fee }}</div> <div class="ticket-fee">挂号费:{{ item.fee }}</div>
<!-- 6. 号源类型 --> <!-- 6. 号源类型 -->
<div class="ticket-type">{{ item.ticketType === 'general' ? '普通' : '专家' }}</div> <div class="ticket-type">{{ item.ticketType === 'general' ? '普通' : '专家' }}</div>
<!-- 7. 已预约患者信息 --> <!-- 7. 已预约患者信息 -->
@@ -205,10 +205,10 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<!-- 无搜索结果提示 --> <!-- 无搜索结果提示 -->
<div v-else-if="hasSearchCriteria && !isLoading" class="no-results"> <div v-else-if="hasSearchCriteria && !isLoading" class="no-results">
未找到符合条件的患者请检查搜索条件 未找到符合条件的患者,请检查搜索条件
</div> </div>
</div> </div>
</div> </div>
@@ -332,6 +332,7 @@ export default {
return filtered; return filtered;
}, },
filteredTickets() { filteredTickets() {
// filteredTickets直接返回this.tickets因为handleTicketResponse中已经完成了时间过滤
return [...this.tickets]; return [...this.tickets];
}, },
hasSearchCriteria() { hasSearchCriteria() {
@@ -405,7 +406,7 @@ export default {
const rowKey = this.getPatientUniqueId(patient, index); const rowKey = this.getPatientUniqueId(patient, index);
return { return {
...patient, ...patient,
// 统一口径预约场景的就诊卡号使用患者标识表中的 identifierNo // 统一口径:预约场景的就诊卡号使用患者标识表中的 identifierNo
medicalCard: patient.identifierNo || patient.medicalCard || '', medicalCard: patient.identifierNo || patient.medicalCard || '',
_rowKey: rowKey _rowKey: rowKey
}; };
@@ -422,7 +423,7 @@ export default {
} }
}).catch(error => { }).catch(error => {
this.patients = []; this.patients = [];
ElMessage.error('获取患者列表失败' + (error.message || '未知错误')); ElMessage.error('获取患者列表失败:' + (error.message || '未知错误'));
}).finally(() => { }).finally(() => {
this.isLoading = false; this.isLoading = false;
}); });
@@ -441,9 +442,9 @@ export default {
this.patientKeyword = ''; this.patientKeyword = '';
this.selectedPatientId = null; this.selectedPatientId = null;
this.selectedPatient = null; this.selectedPatient = null;
// 先打开弹窗再加载患者数据避免等待 // 先打开弹窗,再加载患者数据,避免等待
this.showPatientModal = true; this.showPatientModal = true;
// 调用患者搜索接口加载患者列表 // 调用患者搜索接口,加载患者列表
this.searchPatients(); this.searchPatients();
} }
}, },
@@ -466,9 +467,9 @@ export default {
// 确认取消预约 // 确认取消预约
confirmCancelAppointment() { confirmCancelAppointment() {
if (this.selectedTicketForCancel) { if (this.selectedTicketForCancel) {
// 使用 ElMessageBox.confirm 进行二次确认显示患者姓名 // 使用 ElMessageBox.confirm 进行二次确认,显示患者姓名
ElMessageBox.confirm( ElMessageBox.confirm(
`确认取消患者${this.selectedTicketForCancel.patientName || ''}的预约`, `确认取消患者${this.selectedTicketForCancel.patientName || ''}的预约?`,
'系统提示', '系统提示',
{ {
confirmButtonText: '确定', confirmButtonText: '确定',
@@ -476,7 +477,7 @@ export default {
type: 'warning' type: 'warning'
} }
).then(() => { ).then(() => {
// 用户点击确定调用API取消预约 // 用户点击确定,调用API取消预约
this.cancelAppointment(this.selectedTicketForCancel); this.cancelAppointment(this.selectedTicketForCancel);
}).catch(() => { }).catch(() => {
// 用户取消操作 // 用户取消操作
@@ -488,18 +489,18 @@ export default {
// 取消预约API调用 // 取消预约API调用
cancelAppointment(ticket) { cancelAppointment(ticket) {
if (!ticket || !ticket.slot_id) { if (!ticket || !ticket.slot_id) {
ElMessage.error('取消预约失败缺少号源信息'); ElMessage.error('取消预约失败:缺少号源信息');
this.closeContextMenu(); this.closeContextMenu();
return; return;
} }
// 使用真实API调用取消预约传递slot_id // 使用真实API调用取消预约,传递slot_id
cancelTicket(ticket.slot_id).then(response => { cancelTicket(ticket.slot_id).then(response => {
// 根据后端返回判断是否成功 // 根据后端返回判断是否成功
if (response.code === 200 || response.msg === '取消成功' || response.message === '取消成功') { if (response.code === 200 || response.msg === '取消成功' || response.message === '取消成功') {
console.log('取消预约成功更新前端状态'); console.log('取消预约成功,更新前端状态');
// API调用成功后更新当前卡片状态 // API调用成功后,更新当前卡片状态
const ticketIndex = this.tickets.findIndex(t => t.slot_id === ticket.slot_id); const ticketIndex = this.tickets.findIndex(t => t.slot_id === ticket.slot_id);
if (ticketIndex !== -1) { if (ticketIndex !== -1) {
// 清除该号源关联的所有患者信息 // 清除该号源关联的所有患者信息
@@ -516,11 +517,11 @@ export default {
// 关闭上下文菜单 // 关闭上下文菜单
this.closeContextMenu(); this.closeContextMenu();
ElMessage.success('预约已取消号源已释放'); ElMessage.success('预约已取消,号源已释放');
} else { } else {
// 取消失败 // 取消失败
const errorMsg = response.msg || response.message || '取消预约失败'; const errorMsg = response.msg || response.message || '取消预约失败';
ElMessage.error(`取消预约失败${errorMsg}`); ElMessage.error(`取消预约失败:${errorMsg}`);
this.closeContextMenu(); this.closeContextMenu();
} }
}).catch(error => { }).catch(error => {
@@ -535,7 +536,7 @@ export default {
}, },
selectPatient(patientId) { selectPatient(patientId) {
if (this.patients.length === 0) { if (this.patients.length === 0) {
ElMessage.error('患者数据未加载请先搜索患者'); ElMessage.error('患者数据未加载,请先搜索患者');
return; return;
} }
this.selectedPatientId = patientId; this.selectedPatientId = patientId;
@@ -543,7 +544,7 @@ export default {
if (this.selectedPatient) { if (this.selectedPatient) {
ElMessage.success('已选中患者: ' + this.selectedPatient.name); ElMessage.success('已选中患者: ' + this.selectedPatient.name);
} else { } else {
ElMessage.error('未找到该患者请重新选择'); ElMessage.error('未找到该患者,请重新选择');
this.selectedPatientId = null; this.selectedPatientId = null;
} }
}, },
@@ -554,14 +555,14 @@ export default {
} }
if (!this.currentTicket) { if (!this.currentTicket) {
ElMessage.error('预约信息错误请重新选择号源'); ElMessage.error('预约信息错误,请重新选择号源');
this.closePatientSelectModal(); this.closePatientSelectModal();
return; return;
} }
// 再次验证号源是否仍处于可预约状态 // 再次验证号源是否仍处于可预约状态
if (this.currentTicket.status !== '未预约') { if (this.currentTicket.status !== '未预约') {
ElMessage.error('该号源已被预约请选择其他号源'); ElMessage.error('该号源已被预约,请选择其他号源');
this.closePatientSelectModal(); this.closePatientSelectModal();
return; return;
} }
@@ -571,11 +572,11 @@ export default {
const patientPrimaryId = this.selectedPatient.id || this.selectedPatient.patientId; const patientPrimaryId = this.selectedPatient.id || this.selectedPatient.patientId;
const medicalCard = this.selectedPatient.identifierNo || this.selectedPatient.medicalCard; const medicalCard = this.selectedPatient.identifierNo || this.selectedPatient.medicalCard;
if (!patientPrimaryId) { if (!patientPrimaryId) {
ElMessage.error('患者ID缺失无法预约请重新选择患者'); ElMessage.error('患者ID缺失,无法预约,请重新选择患者');
return; return;
} }
if (!medicalCard) { if (!medicalCard) {
ElMessage.error('就诊卡号缺失无法预约请先维护患者就诊卡号'); ElMessage.error('就诊卡号缺失,无法预约,请先维护患者就诊卡号');
return; return;
} }
const appointmentData = { const appointmentData = {
@@ -609,10 +610,10 @@ export default {
this.closePatientSelectModal(); this.closePatientSelectModal();
// 重新加载号源数据确保显示最新状态 // 重新加载号源数据,确保显示最新状态
this.onSearch(); this.onSearch();
ElMessage.success('预约成功号源已锁定。患者到院签到时需缴费取号。'); ElMessage.success('预约成功,号源已锁定。患者到院签到时需缴费取号。');
}).catch(error => { }).catch(error => {
console.error('预约失败:', error); console.error('预约失败:', error);
}); });
@@ -626,7 +627,7 @@ export default {
}, },
// 获取性别文本 // 获取性别文本
getGenderText(genderValue) { getGenderText(genderValue) {
// 如果值为null或undefined返回"未知" // 如果值为null或undefined,返回"未知"
if (genderValue === null || genderValue === undefined) { if (genderValue === null || genderValue === undefined) {
return '未知'; return '未知';
} }
@@ -648,7 +649,7 @@ export default {
return '女'; return '女';
} }
// 如果都不是返回"未知" // 如果都不是,返回"未知"
return '未知'; return '未知';
}, },
// 获取用于后端的性别值 // 获取用于后端的性别值
@@ -661,7 +662,7 @@ export default {
return patient.gender; return patient.gender;
} }
// 如果genderEnum_enumText是"男性"或"女性"转换为对应的数字 // 如果genderEnum_enumText是"男性"或"女性",转换为对应的数字
if (patient.genderEnum_enumText) { if (patient.genderEnum_enumText) {
const text = patient.genderEnum_enumText.toLowerCase(); const text = patient.genderEnum_enumText.toLowerCase();
if (text === '男性' || text === '男') { if (text === '男性' || text === '男') {
@@ -670,7 +671,7 @@ export default {
return 1; return 1;
} }
} }
// 默认返回0男性 // 默认返回0(男性)
return 0; return 0;
}, },
@@ -728,11 +729,20 @@ export default {
return; return;
} }
const records = payload.list || payload.records || []; const records = payload.list || payload.records || [];
const filteredRecords = this.applyStatusFilter(records);
// 先进行时间过滤(过滤掉已过期的号源)
const currentTime = new Date().getTime();
const timeFilteredRecords = records.filter(ticket => {
const ticketTime = new Date(ticket.dateTime).getTime();
return ticketTime > currentTime;
});
// 再进行状态过滤
const filteredRecords = this.applyStatusFilter(timeFilteredRecords);
const total = Number(payload.total); const total = Number(payload.total);
this.tickets = [...filteredRecords]; this.tickets = [...filteredRecords];
this.allTickets = [...filteredRecords]; this.allTickets = [...filteredRecords];
// 当按状态筛选时优先使用前端过滤后的数量避免后端状态未生效导致显示全部 // 当按状态筛选时,优先使用前端过滤后的数量,避免后端状态未生效导致"显示全部"
if (this.selectedStatus && this.selectedStatus !== 'all') { if (this.selectedStatus && this.selectedStatus !== 'all') {
this.totalTickets = this.tickets.length; this.totalTickets = this.tickets.length;
} else { } else {
@@ -953,7 +963,7 @@ export default {
align-items: center; align-items: center;
} }
/* 为输入行的每个容器设置flex-grow使其均匀分布 */ /* 为输入行的每个容器设置flex-grow,使其均匀分布 */
.search-inputs > div { .search-inputs > div {
flex-grow: 1; flex-grow: 1;
min-width: 100px; min-width: 100px;
@@ -1168,59 +1178,59 @@ export default {
width: 100%; width: 100%;
} }
} }
/* 确保卡片样式正确应用 */ /* 确保卡片样式正确应用 */
.ticket-card { .ticket-card {
box-shadow: var(--shadow); box-shadow: var(--shadow);
overflow: visible; overflow: visible;
transition: all 0.3s ease; transition: all 0.3s ease;
} }
/* 卡片悬停效果 */ /* 卡片悬停效果 */
.ticket-card:hover { .ticket-card:hover {
transform: translateY(-2px); transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(90, 141, 238, 0.12); box-shadow: 0 4px 16px rgba(90, 141, 238, 0.12);
} }
/* 按钮悬停效果 */ /* 按钮悬停效果 */
.search-btn, .search-btn,
.add-patient-btn { .add-patient-btn {
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.search-btn:hover, .search-btn:hover,
.add-patient-btn:hover { .add-patient-btn:hover {
transform: translateY(-1px); transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
} }
/* 输入框焦点效果 */ /* 输入框焦点效果 */
.search-input { .search-input {
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.search-input:focus { .search-input:focus {
border-color: var(--primary-color); border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
} }
/* 医生列表项悬停效果 */ /* 医生列表项悬停效果 */
.doctor-item { .doctor-item {
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.doctor-item:hover { .doctor-item:hover {
background-color: rgba(24, 144, 255, 0.05); background-color: rgba(24, 144, 255, 0.05);
cursor: pointer; cursor: pointer;
} }
/* 医生列表项选中效果 */ /* 医生列表项选中效果 */
.doctor-item.selected { .doctor-item.selected {
background-color: rgba(24, 144, 255, 0.2); background-color: rgba(24, 144, 255, 0.2);
border-left: 4px solid var(--primary-color); border-left: 4px solid var(--primary-color);
font-weight: 600; font-weight: 600;
} }
/* 加载动画 */ /* 加载动画 */
.loading-container { .loading-container {
display: flex; display: flex;
@@ -1230,7 +1240,7 @@ export default {
gap: 8px; gap: 8px;
color: var(--primary-color); color: var(--primary-color);
} }
.loading-spinner { .loading-spinner {
width: 16px; width: 16px;
height: 16px; height: 16px;
@@ -1239,7 +1249,7 @@ export default {
border-radius: 50%; border-radius: 50%;
animation: spin 0.8s linear infinite; animation: spin 0.8s linear infinite;
} }
@keyframes spin { @keyframes spin {
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
} }
@@ -1543,20 +1553,20 @@ export default {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 12px; gap: 12px;
} }
.ticket-card { .ticket-card {
padding: 12px; padding: 12px;
min-height: 190px; min-height: 190px;
} }
.ticket-doctor { .ticket-doctor {
font-size: 13px; font-size: 13px;
} }
.ticket-id-time { .ticket-id-time {
font-size: 13px; font-size: 13px;
} }
.ticket-index { .ticket-index {
font-size: 13px; font-size: 13px;
} }
@@ -1581,14 +1591,14 @@ export default {
border-radius: 8px; border-radius: 8px;
width: 80%; width: 80%;
max-width: 800px; max-width: 800px;
/* 使用固定高度计算确保footer始终可见 */ /* 使用固定高度计算,确保footer始终可见 */
height: 80vh; height: 80vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
/* 确保弹窗在视口中居中且不被遮挡 */ /* 确保弹窗在视口中居中且不被遮挡 */
margin: 20px; margin: 20px;
/* 相对定位为绝对定位的footer提供参考 */ /* 相对定位,为绝对定位的footer提供参考 */
position: relative; position: relative;
} }
@@ -1619,13 +1629,13 @@ export default {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: 20px; padding: 20px;
/* 给body添加底部内边距确保内容不被footer遮挡 */ /* 给body添加底部内边距,确保内容不被footer遮挡 */
padding-bottom: 100px; padding-bottom: 100px;
} }
.modal-footer { .modal-footer {
flex-shrink: 0; flex-shrink: 0;
/* 确保footer始终在底部可见不受其他元素影响 */ /* 确保footer始终在底部可见,不受其他元素影响 */
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
@@ -1637,7 +1647,7 @@ export default {
justify-content: flex-end; justify-content: flex-end;
gap: 12px; gap: 12px;
background-color: white; background-color: white;
/* 添加阴影增强视觉层次感 */ /* 添加阴影,增强视觉层次感 */
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05); box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
/* 确保footer不被body内容遮挡 */ /* 确保footer不被body内容遮挡 */
} }