WXL
3 天以前 2cc85c64f1c64a2dbaeae276a3e2ca8420de76b7
pages/case/transfer.vue
@@ -24,7 +24,7 @@
        <text
          v-for="(type, index) in transportTypes"
          :key="index"
          :class="{ active: currentType === type.value }"
          :class="{ active: currentType == type.value }"
          @tap="selectType(type.value)"
          >{{ type.label }}</text
        >
@@ -70,61 +70,68 @@
        <view class="header">
          <view class="case-info">
            <view class="info">
              <text class="case-no">{{ item.caseNo }}</text>
              <text class="case-no">{{ item.caseNo || item.reportId }}</text>
              <text class="patient"
                >{{ item.donorName }} | {{ item.gender }} |
                >{{ item.patName }} | {{ getGenderText(item.sex) }} |
                {{ item.age }}岁</text
              >
            </view>
          </view>
          <text class="status" :class="item.status">{{ item.statusText }}</text>
          <text class="status" :class="getStatusClass(item.transitStatus)">{{
            getStatusText(item.transitStatus)
          }}</text>
        </view>
        <view class="detail-info">
          <view class="info-item">
            <text class="label">疾病诊断</text>
            <text class="value">{{ item.diagnosis }}</text>
            <text class="value">{{ item.diagnosisname || "未填写" }}</text>
          </view>
          <view class="info-item">
            <text class="label">所在医疗机构</text>
            <text class="value">{{ item.hospitalName }}</text>
            <text class="value">{{
              item.treatmentHospitalName || "未填写"
            }}</text>
          </view>
          <view class="info-item">
            <text class="label">计划转运时间</text>
            <text class="value">{{ item.transportTime }}</text>
            <text class="value">{{ formatTime(item.transportStartTime) }}</text>
          </view>
          <view class="info-item">
            <text class="label">负责协调员</text>
            <text class="value">{{ item.coordinator }}</text>
            <text class="value">{{ item.contactPerson || "未指定" }}</text>
          </view>
          <view class="info-item">
            <text class="label">创建时间</text>
            <text class="value">{{ item.createTime }}</text>
            <text class="value">{{ formatTime(item.createTime) }}</text>
          </view>
        </view>
        <view class="footer">
          <view class="action-info">
            <text class="label">转运状态</text>
            <text class="transport-status">{{ item.statusText }}</text>
            <text class="transport-status">{{
              getStatusText(item.transitStatus)
            }}</text>
          </view>
          <view class="actions">
            <button
              class="action-btn"
              v-if="item.status === 'pending'"
              v-if="item.transitStatus === 1"
              @tap.stop="startTransport(item)"
            >
              开始转运
            </button>
            <button
              class="action-btn"
              v-if="item.status === 'transporting'"
              v-if="item.transitStatus === 2"
              @tap.stop="completeTransport(item)"
            >
              完成转运
            </button>
            <button
              class="action-btn secondary"
              v-if="item.transitStatus != 3"
              @tap.stop="editTransport(item)"
            >
              编辑
@@ -137,12 +144,20 @@
      </view>
      <!-- 加载更多 -->
      <view class="load-more" v-if="hasMore">
        <text>加载中...</text>
      <view class="load-more" v-if="loadingMore">
        <u-loading-icon text="加载中..."></u-loading-icon>
      </view>
      <!-- 无更多数据 -->
      <view class="no-more" v-if="!hasMore && filteredTransports.length > 0">
        <text>已加载全部数据</text>
      </view>
      <!-- 空状态 -->
      <view class="empty-state" v-if="filteredTransports.length === 0">
      <view
        class="empty-state"
        v-if="!loading && filteredTransports.length === 0"
      >
        <image src="/static/empty/no-transport.png" mode="aspectFit" />
        <text>暂无转运单记录</text>
      </view>
@@ -166,154 +181,210 @@
        </view>
      </view>
    </view>
    <!-- 加载状态 -->
    <u-loading-page v-if="initLoading" :loading="true" text="数据加载中..." />
    <!-- 浮动按钮 -->
    <!-- <view class="float-button" @tap="createTransport">
      <u-icon name="plus" color="#fff" size="24"></u-icon>
    </view> -->
  </view>
</template>
<script setup>
import { ref, computed } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { ref, computed, onMounted } from "vue";
import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app";
import { useDict } from "@/utils/dict";
// 字典数据
const dict = ref({});
// 统计数据
const stats = ref({
  totalTransports: 12,
  pendingTransports: 4,
  completedTransports: 6,
  totalTransports: 0,
  pendingTransports: 0,
  completedTransports: 0,
});
// 转运单数据
const transports = ref([]);
const loading = ref(false);
const initLoading = ref(false);
const loadingMore = ref(false);
const refreshing = ref(false);
const hasMore = ref(true);
const pageNum = ref(1);
const pageSize = ref(10);
// 操作确认弹窗相关
const showActionModal = ref(false);
const currentTransport = ref({});
const modalTitle = ref("");
const modalAction = ref("");
onLoad(async (options) => {
  // 初始化数据
  loadTransports();
});
// 筛选相关
const transportTypes = [
  { label: "全部", value: "all" },
  { label: "待出发", value: "pending" },
  { label: "转运中", value: "transporting" },
  { label: "已完成", value: "completed" },
  { label: "已取消", value: "cancelled" },
  { label: "全部", value: "" },
  { label: "待转运", value: 1 },
  { label: "转运中", value: 2 },
  { label: "已完成", value: 3 },
  { label: "已取消", value: 4 },
  { label: "暂存", value: 5 },
];
const currentType = ref("all");
const currentType = ref("");
const startDate = ref("");
const endDate = ref("");
// 转运单数据
const transports = ref([
  {
    id: "T20241217001",
    caseNo: "DON20241216001",
    donorName: "张三",
    gender: "男",
    age: 38,
    diagnosis: "脑外伤导致脑死亡",
    hospitalName: "青岛镜湖医院",
    transportTime: "2024-12-17 14:30",
    coordinator: "张医生",
    createTime: "2024-12-16 09:30",
    status: "pending",
    statusText: "待出发",
    departureLocation: "青岛市立医院急诊科",
    destinationHospital: "青岛镜湖医院",
  },
  {
    id: "T20241217002",
    caseNo: "DON20241216002",
    donorName: "李四",
    gender: "女",
    age: 45,
    diagnosis: "脑梗死",
    hospitalName: "青岛大学附属医院",
    transportTime: "2024-12-17 16:00",
    coordinator: "李医生",
    createTime: "2024-12-16 11:20",
    status: "transporting",
    statusText: "转运中",
    departureLocation: "青岛大学附属医院ICU",
    destinationHospital: "青岛器官移植中心",
  },
  {
    id: "T20241216003",
    caseNo: "DON20241215001",
    donorName: "王五",
    gender: "男",
    age: 52,
    diagnosis: "心脏骤停",
    hospitalName: "青岛市立医院",
    transportTime: "2024-12-16 10:15",
    coordinator: "王医生",
    createTime: "2024-12-15 14:45",
    status: "completed",
    statusText: "已完成",
    departureLocation: "青岛市立医院心内科",
    destinationHospital: "青岛器官移植中心",
  },
  {
    id: "T20241216004",
    caseNo: "DON20241214001",
    donorName: "赵六",
    gender: "女",
    age: 29,
    diagnosis: "急性肝衰竭",
    hospitalName: "青岛科大医院",
    transportTime: "2024-12-16 08:30",
    coordinator: "赵医生",
    createTime: "2024-12-14 16:20",
    status: "cancelled",
    statusText: "已取消",
    departureLocation: "青岛科大医院消化科",
    destinationHospital: "青岛器官移植中心",
  },
]);
onLoad(async (options) => {
  // 获取字典数据
  dict.value = await useDict("sys_user_sex");
  // 初始化数据
  await loadInitialData();
});
// 筛选记录
onReachBottom(() => {
  if (hasMore.value && !loading.value && !loadingMore.value) {
    onLoadMore();
  }
});
onShow(() => {
  // 检查是否有转运状态更新
  const update = uni.getStorageSync("transportStatusUpdate");
  if (update) {
    handleStatusUpdate(update);
    uni.removeStorageSync("transportStatusUpdate");
  }
});
// 数据映射函数
const mapApiDataToTransportItem = (apiData) => {
  return {
    id: apiData.id,
    reportId: apiData.reportId,
    caseNo: apiData.caseNo,
    patName: apiData.patName,
    sex: apiData.sex,
    age: apiData.age,
    diagnosisname: apiData.diagnosisname,
    treatmentHospitalName: apiData.treatmentHospitalName,
    transportStartTime: apiData.transportStartTime,
    contactPerson: apiData.contactPerson,
    createTime: apiData.createTime,
    transitStatus: apiData.transitStatus,
    // 医护人员信息
    doctor: apiData.doctor,
    nurse: apiData.nurse,
    driver: apiData.driver,
    // 其他字段
    transportStartPlace: apiData.transportStartPlace,
    remark: apiData.remark,
  };
};
// 计算属性:筛选记录
const filteredTransports = computed(() => {
  let result = transports.value;
  // 状态筛选
  if (currentType.value !== "all") {
    result = result.filter((item) => item.status === currentType.value);
  // 前端状态筛选
  if (currentType.value !== "") {
    result = result.filter((item) => item.transitStatus === currentType.value);
  }
  // 日期筛选
  if (startDate.value && endDate.value) {
    result = result.filter((item) => {
      const transportDate = item.createTime.split(" ")[0];
      return transportDate >= startDate.value && transportDate <= endDate.value;
    });
  }
  return result;
});
// 分页相关
const hasMore = ref(true);
const refreshing = ref(false);
// 获取状态样式
const getStatusClass = (status) => {
  const map = {
    1: "pending", // 待转运
    2: "transporting", // 转运中
    3: "completed", // 已完成
    4: "cancelled", // 已取消
    5: "cancelled", // 暂存
  };
  return map[status] || "pending";
};
// 获取状态文本
const getStatusText = (status) => {
  const map = {
    1: "待出发",
    2: "转运中",
    3: "已完成",
    4: "已取消",
    5: "暂存",
  };
  return map[status] || "未知";
};
// 获取性别文本
const getGenderText = (gender) => {
  if (!gender) return "未知";
  if (!dict.value.sys_user_sex) return gender;
  const genderItem = dict.value.sys_user_sex.find(
    (item) => item.dictValue === gender,
  );
  return genderItem ? genderItem.dictLabel : gender;
};
// 格式化时间
const formatTime = (timeStr) => {
  if (!timeStr) return "未设置";
  return timeStr.replace("T", " ").substring(0, 16);
};
// 选择类型
const selectType = (type) => {
  currentType.value = type;
  // 重置分页,重新加载数据
  pageNum.value = 1;
  loadTransports(true);
};
// 日期选择
const onStartDateChange = (e) => {
  startDate.value = e.detail.value;
  // 如果结束日期已选择,立即触发筛选
  if (endDate.value) {
    pageNum.value = 1;
    loadTransports(true);
  }
};
const onEndDateChange = (e) => {
  endDate.value = e.detail.value;
  // 如果开始日期已选择,立即触发筛选
  if (startDate.value) {
    pageNum.value = 1;
    loadTransports(true);
  }
};
// 查看详情
const viewDetail = (item) => {
  viewDetails(item);
};
// 查看详情
const viewDetails = (item) => {
  uni.navigateTo({
    url: `/pages/transport/detail?id=${item.id}`,
    url: `/pages/case/transferinfo?id=${item.id}`,
  });
};
// 编辑转运单
const editTransport = (item) => {
  uni.navigateTo({
    url: `/pages/case/transferinfo?id=${item.id}&edit=true`,
  });
};
// 创建转运单
const createTransport = () => {
  uni.navigateTo({
    url: '/pages/transport/create'
  });
};
@@ -334,27 +405,27 @@
};
// 确认操作
const confirmAction = () => {
  const index = transports.value.findIndex(
    (item) => item.id === currentTransport.value.id
  );
  if (index !== -1) {
const confirmAction = async () => {
  try {
    if (modalAction.value === "开始") {
      transports.value[index].status = "transporting";
      transports.value[index].statusText = "转运中";
      stats.value.pendingTransports -= 1;
      await updateTransportStatus(2, "开始转运");
    } else if (modalAction.value === "完成") {
      transports.value[index].status = "completed";
      transports.value[index].statusText = "已完成";
      stats.value.completedTransports += 1;
      await updateTransportStatus(3, "完成转运");
    }
    uni.showToast({
      title: `${modalAction.value}成功`,
      icon: "success",
    });
  } catch (error) {
    console.error(`${modalAction.value}失败:`, error);
    uni.showToast({
      title: `${modalAction.value}失败,请重试`,
      icon: "none",
    });
  } finally {
    showActionModal.value = false;
  }
  showActionModal.value = false;
};
// 取消操作
@@ -362,42 +433,181 @@
  showActionModal.value = false;
};
// 查看详情
const viewDetails = (item) => {
  uni.navigateTo({
    url: `/pages/case/transferinfo?id=${item.id}`,
  });
};
// 编辑转运单
const editTransport = (item) => {
  uni.navigateTo({
    url: `/pages/case/transferinfo?id=${item.id}`,
  });
// 数据加载函数
const loadInitialData = async () => {
  initLoading.value = true;
  try {
    await Promise.all([loadTransports(true), loadStats()]);
  } catch (error) {
    console.error("初始化数据失败:", error);
  } finally {
    initLoading.value = false;
  }
};
// 下拉刷新
const onRefresh = () => {
const onRefresh = async () => {
  refreshing.value = true;
  loadTransports();
  pageNum.value = 1;
  await loadTransports(true);
  await loadStats();
  setTimeout(() => {
    refreshing.value = false;
  }, 1000);
};
// 加载更多
const onLoadMore = () => {
  if (!hasMore.value) return;
  loadTransports();
const onLoadMore = async () => {
  if (!hasMore.value || loading.value || loadingMore.value) return;
  await loadTransports();
};
// 加载记录
const loadTransports = async () => {
// 加载转运单列表
const loadTransports = async (reset = false) => {
  if (reset) {
    pageNum.value = 1;
    hasMore.value = true;
  }
  if (loading.value || loadingMore.value || !hasMore.value) return;
  if (reset) {
    loading.value = true;
  } else {
    loadingMore.value = true;
  }
  try {
    const params = {
      pageNum: pageNum.value,
      pageSize: pageSize.value,
    };
    // 筛选条件
    if (currentType.value !== "") {
      params.transitStatus = currentType.value;
    }
    // 时间筛选条件
    if (startDate.value && endDate.value) {
      params.startDate = startDate.value;
      params.endDate = endDate.value;
    }
    console.log("请求参数:", params);
    const res = await uni.$uapi.post("/project/transport/list", params);
    console.log("接口返回数据:", res);
    if (res && res.code === 200) {
      // 处理不同的数据结构
      let data = [];
      if (res.rows && Array.isArray(res.rows)) {
        data = res.rows;
      } else if (res.data && Array.isArray(res.data)) {
        data = res.data;
      } else if (Array.isArray(res)) {
        data = res;
      } else {
        console.error("接口返回格式不正确:", res);
        throw new Error("接口返回格式不正确");
      }
      const mappedData = data.map((item) => mapApiDataToTransportItem(item));
      if (reset || pageNum.value === 1) {
        transports.value = mappedData;
      } else {
        transports.value = [...transports.value, ...mappedData];
      }
      // 判断是否还有更多数据
      hasMore.value = data.length >= pageSize.value;
      // 如果有数据加载成功,增加页码
      if (data.length > 0) {
        pageNum.value++;
      }
    } else {
      throw new Error(res?.msg || "加载失败");
    }
  } catch (error) {
    console.error("加载转运单列表失败:", error);
    uni.showToast({
      title: "网络请求失败",
      icon: "none",
    });
  } finally {
    loading.value = false;
    loadingMore.value = false;
  }
};
  // 这里调用API加载数据
  setTimeout(() => {
    hasMore.value = false;
  }, 1000);
// 加载统计数据
const loadStats = async () => {
  try {
    const res = await uni.$uapi.post("/api/totalServiceTransportState");
    if (res.data) {
      stats.value = {
        totalTransports:
          res.data.reduce((sum, item) => sum + item.count, 0) || 0,
        pendingTransports: res.data[0].count || 0,
        completedTransports: res.data[3].count || 0,
      };
    }
  } catch (error) {
    console.error("加载统计失败:", error);
  }
};
// 更新转运状态
const updateTransportStatus = async (newStatus, actionName) => {
  try {
    const updateData = {
      id: currentTransport.value.id,
      transitStatus: newStatus,
    };
    const res = await uni.$uapi.post("/project/transport/edit", updateData);
    if (res && res.code === 200) {
      // 更新本地数据
      const index = transports.value.findIndex(
        (item) => item.id === currentTransport.value.id,
      );
      if (index !== -1) {
        transports.value[index].transitStatus = newStatus;
      }
      // 更新统计数据
      await loadStats();
      // 存储状态更新
      uni.setStorageSync("transportStatusUpdate", {
        orderId: currentTransport.value.id,
        status: newStatus,
      });
      return true;
    } else {
      throw new Error(res?.msg || `${actionName}失败`);
    }
  } catch (error) {
    console.error(`${actionName}失败:`, error);
    throw error;
  }
};
// 处理状态更新
const handleStatusUpdate = (update) => {
  const index = transports.value.findIndex(
    (item) => item.id === update.orderId,
  );
  if (index !== -1) {
    transports.value[index].transitStatus = update.status;
  }
};
</script>
@@ -405,6 +615,7 @@
.transport-record {
  min-height: 100vh;
  background: linear-gradient(135deg, #fafdff 0%, #e3f0ff 100%);
  padding-bottom: 100rpx;
  .stats-card {
    margin: 20rpx;
@@ -675,6 +886,13 @@
      }
    }
    .load-more, .no-more {
      text-align: center;
      padding: 40rpx 0;
      color: #86868b;
      font-size: 28rpx;
    }
    .empty-state {
      padding: 120rpx 0;
      text-align: center;
@@ -767,5 +985,27 @@
      }
    }
  }
  /* 浮动按钮 */
  .float-button {
    position: fixed;
    bottom: 100rpx;
    right: 40rpx;
    width: 100rpx;
    height: 100rpx;
    background: #0071e3;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 8rpx 20rpx rgba(0, 113, 227, 0.3);
    z-index: 100;
    transition: all 0.3s ease;
    &:active {
      opacity: 0.8;
      transform: scale(0.95);
    }
  }
}
</style>
</style>