2026-01-15 15:05:29 +08:00

559 lines
14 KiB
JavaScript
Raw Permalink 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.

// pages/surgery/index.js
const { surgeryApi } = require("../../utils/api");
const dayjs = require("../../miniprogram_npm/dayjs/index");
const Toast = require("../../miniprogram_npm/tdesign-miniprogram/toast/index");
Page({
/**
* 页面的初始数据
*/
data: {
surgeries: [], // 手术列表数据
surgeriesList: [],
// 分页参数
page: 1,
pageSize: 10,
total: 0,
// 状态控制
loading: true, // 初始加载状态
refreshing: false, // 下拉刷新状态
loadingMore: false, // 加载更多状态
loadError: false, // 加载错误状态
noMoreData: false, // 没有更多数据状态
isFinish: false, // 是否选中未完成
confirmDialogVisible: false, // 确认删除对话框可见性
currentSurgeryId: null, // 当前操作的手术ID
// 数据变更状态管理
dataHasChanged: false, // 标记数据是否已变更(从编辑/创建页面返回时)
lastShowTime: 0, // 上次显示页面的时间戳
showTimeout: null, // 防抖定时器
// TDesign 组件配置
loadingProps: {
theme: 'circular',
size: '40rpx',
layout: 'horizontal'
},
loadingTexts: [
'下拉刷新',
'松手刷新',
'正在刷新...',
'刷新完成'
]
// 不再在这里全局定义swipeButtons而是为每个手术项动态生成
},
/**
* 生命周期函数--监听页面加载
*/
onLoad() {
this.loadSurgeries();
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
const currentTime = Date.now();
// 清除之前的定时器(防抖)
if (this.data.showTimeout) {
clearTimeout(this.data.showTimeout);
}
// 检查是否需要刷新数据
const shouldRefresh = this.shouldRefreshData(currentTime);
if (shouldRefresh) {
// 设置新的定时器延迟500ms执行刷新避免快速切换页面导致的重复请求
const timeoutId = setTimeout(() => {
this.performSmartRefresh();
}, 500);
this.setData({
showTimeout: timeoutId,
lastShowTime: currentTime,
dataHasChanged: false
});
} else {
// 更新最后显示时间
this.setData({ lastShowTime: currentTime });
}
},
/**
* 点击未完成
*/
clickunfinished ({detail}) {
this.setData({isFinish: detail.checked})
this.filterSurgeriesList()
},
/**
* 过滤手术未完成
*/
filterSurgeriesList(arr = []) {
if (arr.length > 0) this.data.surgeriesList.push(...arr)
let list = []
if (this.data.isFinish) {
list = this.data.surgeries.filter((item) => {
if (item.surgerySubDevices && item.surgerySubDevices.length > 0){
if (item.surgerySubDevices.some(subDevice => !subDevice.end_time)) {
return item
}
}
})
this.setData({
surgeries: list
})
} else {
this.setData({
surgeries: this.data.surgeriesList
})
}
},
/**
* 判断是否需要刷新数据
*/
shouldRefreshData(currentTime) {
// 如果正在加载或刷新,则不执行
if (this.data.loading || this.data.refreshing || this.data.loadingMore) {
return false;
}
// 如果数据已变更(从编辑页面返回的标记),则需要刷新
if (this.data.dataHasChanged) {
return true;
}
// 如果还没有加载过数据,则需要加载
if (this.data.surgeries.length === 0 && !this.data.loadError) {
return true;
}
// 如果距离上次显示超过5分钟考虑刷新防止数据过期
const timeSinceLastShow = currentTime - this.data.lastShowTime;
if (timeSinceLastShow > 5 * 60 * 1000) { // 5分钟
return true;
}
return false;
},
/**
* 执行智能刷新策略
*/
async performSmartRefresh() {
try {
// 1. 首先尝试增量更新(只刷新第一页,检查是否有新数据)
const freshData = await this.fetchSurgeriesData(1, this.data.pageSize);
const freshFirstPage = freshData.formattedSurgeries;
// 2. 比较数据是否有变化
const hasChanges = this.detectChanges(this.data.surgeries, freshFirstPage);
if (hasChanges) {
console.log('📋 检测到数据变化,执行增量更新');
await this.performIncrementalUpdate(freshData);
} else {
console.log('📋 数据无变化,保持当前状态');
}
} catch (error) {
console.error('📋 智能刷新失败,回退到完整刷新:', error);
// 如果智能刷新失败,回退到完整的刷新
this.loadSurgeries();
}
},
/**
* 检测数据是否有变化
*/
detectChanges(currentData, freshData) {
// 如果数据数量不同,肯定有变化
if (currentData.length !== freshData.length) {
return true;
}
// 如果当前没有数据,而新数据有,则有变化
if (currentData.length === 0 && freshData.length > 0) {
return true;
}
// 比较前几个项目的ID和时间戳
const compareCount = Math.min(currentData.length, freshData.length, 3);
for (let i = 0; i < compareCount; i++) {
const currentItem = currentData[i];
const freshItem = freshData[i];
// 比较ID
if (currentItem.id !== freshItem.id) {
return true;
}
// 比较更新时间(如果有的话)
if (currentItem.updated_at !== freshItem.updated_at) {
return true;
}
// 比较手术时间
if (currentItem.surgery_time !== freshItem.surgery_time) {
return true;
}
}
return false;
},
/**
* 执行增量更新
*/
async performIncrementalUpdate(freshFirstPage) {
// 只在第1页时自动更新其他页面不进行任何操作
if (this.data.page === 1) {
this.setData({
surgeries: freshFirstPage.formattedSurgeries,
total: freshFirstPage.total,
noMoreData: freshFirstPage.formattedSurgeries.length < this.data.pageSize
});
// 简单的数据更新提示
wx.showToast({
title: '数据已更新',
icon: 'success',
duration: 1000
});
}
// 如果用户在第2页+,不做任何操作,让用户自己选择是否下拉刷新
},
/**
* 设置数据变更标记(从其他页面调用)
*/
markDataChanged() {
this.setData({ dataHasChanged: true });
},
/**
* 初始加载手术数据
*/
async loadSurgeries() {
this.setData({
loading: true,
loadError: false,
page: 1,
noMoreData: false
});
try {
const res = await this.fetchSurgeriesData(1, this.data.pageSize);
this.setData({
surgeries: res.formattedSurgeries,
surgeriesList: res.formattedSurgeries,
total: res.total,
page: 1,
noMoreData: res.formattedSurgeries.length < this.data.pageSize,
loading: false
});
} catch (error) {
this.setData({
loading: false,
loadError: true,
});
wx.showToast({
title: "获取手术列表失败",
icon: "error",
});
}
},
/**
* 下拉刷新
*/
async onRefresh() {
if (this.data.refreshing || this.data.loadingMore) return;
this.setData({
refreshing: true,
page: 1,
noMoreData: false
});
try {
const res = await this.fetchSurgeriesData(1, this.data.pageSize);
this.setData({
surgeries: res.formattedSurgeries,
total: res.total,
page: 1,
noMoreData: res.formattedSurgeries.length < this.data.pageSize
});
wx.showToast({
title: '刷新成功',
icon: 'success',
duration: 1500
});
} catch (error) {
wx.showToast({
title: '刷新失败',
icon: 'error'
});
} finally {
this.setData({ refreshing: false });
}
},
/**
* 滑动底部加载更多
*/
async onScrollToLower() {
// 如果正在加载或没有更多数据,则返回
if (this.data.loadingMore || this.data.noMoreData || this.data.refreshing) {
return;
}
this.setData({
loadingMore: true,
page: this.data.page + 1
});
try {
const res = await this.fetchSurgeriesData(this.data.page, this.data.pageSize);
this.filterSurgeriesList(res.formattedSurgeries)
// 合并数据
this.setData({
// surgeries: this.data.surgeries.concat(res.formattedSurgeries),
total: res.total,
noMoreData: res.formattedSurgeries.length < this.data.pageSize
});
} catch (error) {
// 恢复页码
this.setData({
page: this.data.page - 1
});
wx.showToast({
title: '加载更多失败',
icon: 'error'
});
} finally {
this.setData({ loadingMore: false });
}
},
/**
* 获取手术数据的核心方法
*/
async fetchSurgeriesData(page, pageSize) {
const res = await surgeryApi.getSurgeries({
page: page,
pageSize: pageSize
});
// 处理手术数据,格式化日期并确保医生和科室数据存在
// 后端返回的是分页格式:{list: [...], total: ...}
const surgeryList = res.data.list || res.data || [];
const formattedSurgeries = surgeryList.map((surgery) => {
// 诊断医生信息缺失问题
const hasDoctor = !!surgery.doctor;
const hasDepartment = !!surgery.doctor?.department;
// 确保医生和科室信息存在并设置默认值
const doctorName = hasDoctor ? surgery.doctor.name : "未知医生";
const departmentName = hasDepartment ? surgery.doctor.department.name : "未知科室";
// 计算使用的设备数量
const deviceCount = surgery.surgerySubDevices ? surgery.surgerySubDevices.length : 0;
// 检查是否有未设置结束时间的设备
let hasUnfinishedDevice = false;
if (surgery.surgerySubDevices && surgery.surgerySubDevices.length > 0) {
hasUnfinishedDevice = surgery.surgerySubDevices.some(subDevice => !subDevice.end_time);
}
// 为每个手术记录添加专属的侧滑按钮配置
const surgerySwipeButtons = [
{
text: "编辑",
style: "background-color: #0052d9; color: white; width: 120rpx; height: 100%; display: flex; align-items: center; justify-content: center;",
data: { id: surgery.id, type: "edit" },
},
{
text: "删除",
style: "background-color: #e34d59; color: white; width: 120rpx; height: 100%; display: flex; align-items: center; justify-content: center;",
data: { id: surgery.id, type: "delete" },
},
];
return {
...surgery,
formattedTime: dayjs(surgery.surgery_time).format("YYYY年MM月DD日 HH:mm"),
// 添加独立的属性,确保即使嵌套对象不存在也能显示
doctorName: doctorName,
departmentName: departmentName,
// 添加设备数量
deviceCount: deviceCount,
// 添加样式状态标记
hasUnfinishedDevice: hasUnfinishedDevice,
// 添加侧滑按钮配置
swipeButtons: surgerySwipeButtons,
};
});
return {
formattedSurgeries,
total: res.data.total || surgeryList.length
};
},
/**
* 查看手术详情
*/
viewSurgeryDetail(e) {
const surgeryId = e.currentTarget.dataset.id;
// 跳转到手术详情页
wx.navigateTo({
url: `/pages/surgery/detail/index?id=${surgeryId}`,
});
},
/**
* 侧滑单元格点击事件处理
*/
onSwipeCellClick(e) {
const { index } = e.detail;
const btnData = e.detail.data;
if (!btnData || !btnData.id) {
Toast({
message: "操作失败,请重试",
theme: "error",
});
return;
}
const surgeryId = btnData.id;
const actionType = btnData.type;
// 查找对应的手术记录数据
const surgery = this.data.surgeries.find((item) => item.id === surgeryId);
if (!surgery) {
Toast({
message: "找不到对应的手术记录",
theme: "error",
});
return;
}
// 根据操作类型执行相应的动作
if (actionType === "edit" || index === 0) {
// 编辑操作
this.handleEdit(surgery);
} else if (actionType === "delete" || index === 1) {
// 删除操作
this.handleDelete(surgery);
}
},
/**
* 处理编辑操作
*/
handleEdit(surgery) {
// 跳转到编辑页面,实际上是复用创建页面
wx.navigateTo({
url: `/pages/surgery/create/index?id=${surgery.id}&mode=edit`,
success: () => {
},
fail: (err) => {
Toast({
message: "页面跳转失败",
theme: "error",
});
},
});
},
/**
* 处理删除操作
*/
handleDelete(surgery) {
// 显示确认对话框
this.setData({
currentSurgeryId: surgery.id,
confirmDialogVisible: true,
});
},
/**
* 确认删除
*/
async confirmDelete() {
const surgeryId = this.data.currentSurgeryId;
try {
await surgeryApi.deleteSurgery(surgeryId);
// 删除成功,刷新列表
wx.showToast({
title: "删除成功",
icon: "success",
});
// 重新加载数据
this.loadSurgeries();
} catch (error) {
wx.showToast({
title: "删除失败",
icon: "error",
});
} finally {
// 关闭对话框
this.setData({
confirmDialogVisible: false,
currentSurgeryId: null,
});
}
},
/**
* 取消删除
*/
cancelDelete() {
this.setData({
confirmDialogVisible: false,
currentSurgeryId: null,
});
},
/**
* 浮动按钮点击事件处理函数
*/
handleClick() {
// 跳转到手术创建页面
wx.navigateTo({
url: "/pages/surgery/create/index",
success: () => {
},
fail: (err) => {
wx.showToast({
title: "页面跳转失败",
icon: "error",
});
},
});
},
/**
* 页面卸载时清理资源
*/
onUnload() {
// 清除定时器,避免内存泄漏
if (this.data.showTimeout) {
clearTimeout(this.data.showTimeout);
}
},
});