<template>
|
<view class="container">
|
<!-- 导航栏 -->
|
<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="skeleton-row">
|
<view class="skeleton-label" />
|
<view class="skeleton-value" />
|
</view>
|
<view class="skeleton-row">
|
<view class="skeleton-label" />
|
<view class="skeleton-value medium" />
|
</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 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>
|
</view>
|
</template>
|
|
<script>
|
import { getAssignedItineraryLogList } from '@/common/history'
|
|
export default {
|
data() {
|
return {
|
historyList: [],
|
loading: false,
|
loadingMore: false,
|
isRefreshing: false,
|
pageNum: 1,
|
pageSize: 10,
|
hasMore: true
|
}
|
},
|
|
onLoad() {
|
this.loadData()
|
},
|
|
methods: {
|
goBack() {
|
uni.navigateBack({ delta: 1 })
|
},
|
|
// 加载数据
|
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 lang="scss" scoped>
|
// 变量定义
|
$primary-color: #409eff;
|
$text-primary: #303133;
|
$text-regular: #606266;
|
$text-secondary: #909399;
|
$border-color: #ebeef5;
|
$bg-color: #f5f7fa;
|
|
.container {
|
min-height: 100vh;
|
background-color: $bg-color;
|
}
|
|
// 骨架屏
|
.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 {
|
padding: 20rpx;
|
box-sizing: border-box;
|
}
|
|
// 空状态
|
.empty-state {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
height: 60vh;
|
}
|
|
// 列表内容
|
.list-content {
|
padding-bottom: 40rpx;
|
}
|
|
// 历史卡片
|
.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;
|
}
|
}
|
}
|
}
|
}
|
|
// 加载更多
|
.load-more {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
padding: 30rpx;
|
|
.no-more {
|
font-size: 24rpx;
|
color: $text-secondary;
|
}
|
}
|
</style>
|