zhangback
2026-03-30 0bafa6aa253c9ef6f5cb24e9a24c5282860e4c59
ui/car_wx_app/pages/history/index.vue
@@ -1,29 +1,85 @@
<template>
  <view class="container">
    <!-- 标题栏 -->
    <Nav title="历史调度单" customBack="pages/beReferred/index" customType="navigateBack"></Nav>
    <!-- 历史调度单列表-可下拉滚动 -->
    <scroll-view class="history-scroll" scroll-y="true" style="height: calc(100vh - 80rpx);">
      <view class="history-item" v-for="(item, index) in historyList" @click="historyClick(item)" :key="index">
        <view class="item-field">
          <view class="field-label">调度单号</view>
          <view class="field-value">{{ item.dispatchNo }}</view>
    <!-- 导航栏 -->
    <Nav title="历史调度单" @back="goBack" />
    <!-- 骨架屏 -->
    <view v-if="loading && !historyList.length" class="skeleton-list">
      <view v-for="i in 5" :key="i" class="skeleton-item">
        <view class="skeleton-row">
          <view class="skeleton-label" />
          <view class="skeleton-value short" />
        </view>
        <view class="item-field">
          <view class="field-label">运输工具号码</view>
          <view class="field-value">{{ item.licensePlate }}</view>
        <view class="skeleton-row">
          <view class="skeleton-label" />
          <view class="skeleton-value" />
        </view>
        <view class="item-field">
          <view class="field-label">路线</view>
          <view class="field-value">{{ item.transportLine }}</view>
        <view class="skeleton-row">
          <view class="skeleton-label" />
          <view class="skeleton-value medium" />
        </view>
        <view class="item-field">
          <view class="field-label">客户</view>
          <view class="field-value">{{ item.customerName }}</view>
      </view>
    </view>
    <!-- 列表区域 -->
    <scroll-view
      v-else
      class="history-scroll"
      scroll-y
      :refresher-enabled="true"
      :refresher-triggered="isRefreshing"
      @refresherrefresh="onRefresh"
      @scrolltolower="onLoadMore"
      :style="{ height: 'calc(100vh - 88rpx)' }"
    >
      <!-- 空状态 -->
      <view v-if="!historyList.length" class="empty-state">
        <u-empty mode="history" text="暂无历史调度单" />
      </view>
      <!-- 列表内容 -->
      <view v-else class="list-content">
        <view
          v-for="item in historyList"
          :key="item.dispatchId"
          class="history-card"
          @tap="handleItemClick(item)"
        >
          <!-- 头部:单号和状态 -->
          <view class="card-header">
            <view class="dispatch-no">{{ item.dispatchNo }}</view>
            <u-icon name="arrow-right" size="14" color="#c0c4cc" />
          </view>
          <!-- 内容区域 -->
          <view class="card-body">
            <view class="info-row">
              <u-icon name="car" size="14" color="#909399" />
              <text class="info-label">车牌号</text>
              <text class="info-value">{{ item.licensePlate || '-' }}</text>
            </view>
            <view class="info-row">
              <u-icon name="map" size="14" color="#909399" />
              <text class="info-label">路线</text>
              <text class="info-value">{{ item.transportLine || '-' }}</text>
            </view>
            <view class="info-row">
              <u-icon name="account" size="14" color="#909399" />
              <text class="info-label">客户</text>
              <text class="info-value">{{ item.customerName || '-' }}</text>
            </view>
            <view class="info-row">
              <u-icon name="clock" size="14" color="#909399" />
              <text class="info-label">完成时间</text>
              <text class="info-value time">{{ formatTime(item.okTime) }}</text>
            </view>
          </view>
        </view>
        <view class="item-field">
          <view class="field-label">完成时间</view>
          <view class="field-value">{{ item.okTime }}</view>
        <!-- 加载更多状态 -->
        <view v-if="historyList.length" class="load-more">
          <u-loading-icon v-if="loadingMore" size="16" text="加载中..." />
          <text v-else-if="!hasMore" class="no-more">没有更多了</text>
        </view>
      </view>
    </scroll-view>
@@ -31,91 +87,255 @@
</template>
<script>
import { getAssignedItineraryLogList } from '@/common/history'
import { getAssignedItineraryLogList } from "@/common/history";
export default {
  data() {
    return {
      historyList: [
      historyList: [],
      loading: false,
      loadingMore: false,
      isRefreshing: false,
      pageNum: 1,
      pageSize: 10,
      hasMore: true
    }
  },
      ]
    };
  onLoad() {
    this.loadData()
  },
  created() {
    this.getList();
  },
  methods: {
    historyClick(item) {
      wx.navigateTo({
        url: '/pages/examine/index?id=' + item.dispatchId + '&name=' + '查看行程历史' + '&router=' + 'pages/history/index'
      });
    goBack() {
      uni.navigateBack({ delta: 1 })
    },
    getList() {
      getAssignedItineraryLogList().then((res) => {
        this.historyList = res;
        // uni.$u.toast(res.message);
      })
    // 加载数据
    async loadData(isRefresh = false) {
      if (this.loading) return
      this.loading = true
      try {
        const params = {
          pageNum: this.pageNum,
          pageSize: this.pageSize
        }
        const res = await getAssignedItineraryLogList(params)
        const list = res?.rows || res?.list || res || []
        const total = res?.total || list.length
        if (isRefresh) {
          this.historyList = list
        } else {
          this.historyList = [...this.historyList, ...list]
        }
        this.hasMore = this.historyList.length < total
      } catch (err) {
        uni.$u.toast(err.message || '加载失败')
      } finally {
        this.loading = false
        this.loadingMore = false
        this.isRefreshing = false
      }
    },
  },
};
    // 下拉刷新
    onRefresh() {
      this.isRefreshing = true
      this.pageNum = 1
      this.hasMore = true
      this.loadData(true)
    },
    // 上拉加载更多
    onLoadMore() {
      if (!this.hasMore || this.loadingMore) return
      this.loadingMore = true
      this.pageNum++
      this.loadData()
    },
    // 点击卡片 - 直接跳转到详情页
    handleItemClick(item) {
      const url = `/pages/examine/detail?id=${encodeURIComponent(item.dispatchId)}&name=${encodeURIComponent('查看行程历史')}&router=${encodeURIComponent('pages/history/index')}`
      uni.redirectTo({ url })
    },
    // 格式化时间
    formatTime(timeStr) {
      if (!timeStr) return '-'
      const m = timeStr.match(/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/)
      return m ? `${m[1]}-${m[2]}-${m[3]} ${m[4]}:${m[5]}:${m[6]}` : timeStr
    }
  }
}
</script>
<style scoped>
<style lang="scss" scoped>
// 变量定义
$primary-color: #409eff;
$text-primary: #303133;
$text-regular: #606266;
$text-secondary: #909399;
$border-color: #ebeef5;
$bg-color: #f5f7fa;
.container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #f7f7f7;
  min-height: 100vh;
  background-color: $bg-color;
}
/* 标题栏 */
.title-bar {
  height: 80rpx;
  line-height: 80rpx;
  text-align: center;
  font-size: 32rpx;
  font-weight: 500;
  background-color: #fff;
  border-bottom: 1rpx solid #ccc;
  /* 标题栏底部边框 */
// 骨架屏
.skeleton-list {
  padding: 20rpx;
  .skeleton-item {
    background: #fff;
    border-radius: 12rpx;
    padding: 24rpx;
    margin-bottom: 20rpx;
    .skeleton-row {
      display: flex;
      align-items: center;
      margin-bottom: 16rpx;
      &:last-child {
        margin-bottom: 0;
      }
    }
    .skeleton-label {
      width: 140rpx;
      height: 28rpx;
      background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
      background-size: 200% 100%;
      animation: shimmer 1.5s infinite;
      border-radius: 4rpx;
      margin-right: 20rpx;
    }
    .skeleton-value {
      flex: 1;
      height: 28rpx;
      background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
      background-size: 200% 100%;
      animation: shimmer 1.5s infinite;
      border-radius: 4rpx;
      &.short {
        flex: 0.3;
      }
      &.medium {
        flex: 0.6;
      }
    }
  }
}
/* 历史调度单滚动区域 */
@keyframes shimmer {
  0% {
    background-position: 200% 0;
  }
  100% {
    background-position: -200% 0;
  }
}
// 滚动区域
.history-scroll {
  flex: 1;
  padding: 20rpx;
  box-sizing: border-box;
}
/* 历史调度单项 */
.history-item {
  background-color: #fff;
  border: 1rpx solid #ccc;
  /* 每个条目边框 */
  border-radius: 6rpx;
  padding: 20rpx;
  margin-bottom: 20rpx;
}
/* 字段行 */
.item-field {
// 空状态
.empty-state {
  display: flex;
  margin-bottom: 16rpx;
  justify-content: center;
  align-items: center;
  height: 60vh;
}
/* 字段标签 */
.field-label {
  width: 170rpx;
  color: #666;
  font-size: 28rpx;
// 列表内容
.list-content {
  padding-bottom: 40rpx;
}
/* 字段值 */
.field-value {
  flex: 1;
  color: #333;
  font-size: 28rpx;
// 历史卡片
.history-card {
  background: #fff;
  border-radius: 12rpx;
  padding: 24rpx;
  margin-bottom: 20rpx;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
  transition: transform 0.2s;
  &:active {
    transform: scale(0.98);
  }
  .card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 20rpx;
    margin-bottom: 20rpx;
    border-bottom: 1rpx solid $border-color;
    .dispatch-no {
      font-size: 30rpx;
      font-weight: 600;
      color: $primary-color;
    }
  }
  .card-body {
    .info-row {
      display: flex;
      align-items: center;
      margin-bottom: 16rpx;
      &:last-child {
        margin-bottom: 0;
      }
      .info-label {
        width: 120rpx;
        font-size: 26rpx;
        color: $text-secondary;
        margin-left: 12rpx;
        margin-right: 16rpx;
      }
      .info-value {
        flex: 1;
        font-size: 26rpx;
        color: $text-regular;
        word-break: break-all;
        &.time {
          color: $text-secondary;
          font-size: 24rpx;
        }
      }
    }
  }
}
</style>
// 加载更多
.load-more {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 30rpx;
  .no-more {
    font-size: 24rpx;
    color: $text-secondary;
  }
}
</style>