| | |
| | | <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> |
| | |
| | | </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> |