| @ -0,0 +1,288 @@ | |||
| <template> | |||
| <view class="logistics-page"> | |||
| <!-- 顶部导航 --> | |||
| <view class="nav-bar"> | |||
| <view class="back" @tap="goBack"> | |||
| <uni-icons type="left" size="20" color="#222" /> | |||
| </view> | |||
| <text class="nav-title">物流轨迹</text> | |||
| </view> | |||
| <!-- 物流信息卡片 --> | |||
| <view class="logistics-card"> | |||
| <view class="express-info"> | |||
| <view class="express-company">{{ expressCompany }}</view> | |||
| <view class="express-number">运单号:{{ wuliuNo }}</view> | |||
| </view> | |||
| </view> | |||
| <!-- 物流轨迹列表 --> | |||
| <view class="trace-list"> | |||
| <view | |||
| v-for="(item, index) in traceList" | |||
| :key="index" | |||
| class="trace-item" | |||
| :class="{ 'active': index === 0 }" | |||
| > | |||
| <view class="trace-dot"> | |||
| <view class="dot-inner"></view> | |||
| </view> | |||
| <view class="trace-line" v-if="index < traceList.length - 1"></view> | |||
| <view class="trace-content"> | |||
| <view class="trace-desc">{{ item.description }}</view> | |||
| <view class="trace-time">{{ item.time }}</view> | |||
| <view class="trace-location">{{ item.site }}</view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 加载状态 --> | |||
| <view v-if="loading" class="loading"> | |||
| <uni-load-more status="loading" :content-text="loadingText"></uni-load-more> | |||
| </view> | |||
| <!-- 无数据状态 --> | |||
| <view v-if="!loading && traceList.length === 0" class="empty-state"> | |||
| <image src="/static/empty-logistics.png" class="empty-icon" mode="aspectFit"></image> | |||
| <text class="empty-text">暂无物流信息</text> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| data() { | |||
| return { | |||
| wuliuNo: '', | |||
| expressCompany: '', | |||
| traceList: [], | |||
| loading: false, | |||
| loadingText: { | |||
| contentdown: '上拉显示更多', | |||
| contentrefresh: '正在加载...', | |||
| contentnomore: '没有更多数据了' | |||
| } | |||
| } | |||
| }, | |||
| onLoad(options) { | |||
| if (options.wliuNo) { | |||
| this.wuliuNo = options.wliuNo | |||
| } | |||
| if (options.expressCompany) { | |||
| this.expressCompany = options.expressCompany | |||
| } | |||
| this.fetchLogisticsTrace() | |||
| }, | |||
| methods: { | |||
| goBack() { | |||
| uni.navigateBack() | |||
| }, | |||
| async fetchLogisticsTrace() { | |||
| if (!this.wuliuNo) { | |||
| uni.showToast({ title: '运单号不能为空', icon: 'none' }) | |||
| return | |||
| } | |||
| this.loading = true | |||
| try { | |||
| this.$api('queryTrace', { | |||
| wuliuNo: this.wuliuNo | |||
| }, res => { | |||
| this.loading = false | |||
| if (res && res.code === 200 && res.result && res.result.responseParam) { | |||
| const traceData = res.result.responseParam | |||
| this.traceList = traceData.trace_list || [] | |||
| if (this.traceList.length === 0) { | |||
| uni.showToast({ title: '暂无物流信息', icon: 'none' }) | |||
| } | |||
| } else { | |||
| uni.showToast({ title: res?.message || '获取物流信息失败', icon: 'none' }) | |||
| } | |||
| }) | |||
| } catch (error) { | |||
| this.loading = false | |||
| uni.showToast({ title: '网络错误,请重试', icon: 'none' }) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .logistics-page { | |||
| min-height: 100vh; | |||
| background: #f8f8f8; | |||
| padding-bottom: 40rpx; | |||
| } | |||
| .nav-bar { | |||
| display: flex; | |||
| align-items: center; | |||
| height: calc(150rpx + var(--status-bar-height)); | |||
| padding: 0 32rpx; | |||
| padding-top: var(--status-bar-height); | |||
| background: #fff; | |||
| position: fixed; | |||
| top: 0; | |||
| left: 0; | |||
| right: 0; | |||
| z-index: 999; | |||
| box-sizing: border-box; | |||
| box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03); | |||
| .back { | |||
| padding: 20rpx; | |||
| margin-left: -20rpx; | |||
| } | |||
| .nav-title { | |||
| flex: 1; | |||
| text-align: center; | |||
| font-size: 32rpx; | |||
| font-weight: 500; | |||
| color: #222; | |||
| } | |||
| } | |||
| .logistics-card { | |||
| margin: calc(150rpx + var(--status-bar-height) + 24rpx) 24rpx 24rpx 24rpx; | |||
| background: #fff; | |||
| border-radius: 24rpx; | |||
| padding: 32rpx; | |||
| box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04); | |||
| .express-info { | |||
| .express-company { | |||
| font-size: 32rpx; | |||
| font-weight: bold; | |||
| color: #222; | |||
| margin-bottom: 12rpx; | |||
| } | |||
| .express-number { | |||
| font-size: 28rpx; | |||
| color: #666; | |||
| } | |||
| } | |||
| } | |||
| .trace-list { | |||
| margin: 0 24rpx; | |||
| background: #fff; | |||
| border-radius: 24rpx; | |||
| padding: 32rpx; | |||
| box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04); | |||
| position: relative; | |||
| } | |||
| .trace-item { | |||
| display: flex; | |||
| align-items: flex-start; | |||
| position: relative; | |||
| padding-bottom: 32rpx; | |||
| &:last-child { | |||
| padding-bottom: 0; | |||
| } | |||
| &.active { | |||
| .trace-dot { | |||
| background: #ff9c00; | |||
| border-color: #ff9c00; | |||
| } | |||
| .trace-content { | |||
| .trace-desc { | |||
| color: #222; | |||
| font-weight: bold; | |||
| } | |||
| .trace-time { | |||
| color: #ff9c00; | |||
| } | |||
| } | |||
| } | |||
| .trace-dot { | |||
| width: 24rpx; | |||
| height: 24rpx; | |||
| border-radius: 50%; | |||
| background: #ddd; | |||
| border: 4rpx solid #f0f0f0; | |||
| margin-right: 24rpx; | |||
| margin-top: 8rpx; | |||
| flex-shrink: 0; | |||
| position: relative; | |||
| z-index: 2; | |||
| .dot-inner { | |||
| width: 8rpx; | |||
| height: 8rpx; | |||
| border-radius: 50%; | |||
| background: #fff; | |||
| position: absolute; | |||
| top: 50%; | |||
| left: 50%; | |||
| transform: translate(-50%, -50%); | |||
| } | |||
| } | |||
| .trace-line { | |||
| position: absolute; | |||
| left: 12rpx; | |||
| top: 32rpx; | |||
| width: 2rpx; | |||
| height: calc(100% - 32rpx); | |||
| background: #f0f0f0; | |||
| z-index: 1; | |||
| } | |||
| .trace-content { | |||
| flex: 1; | |||
| min-width: 0; | |||
| .trace-desc { | |||
| font-size: 28rpx; | |||
| color: #666; | |||
| line-height: 1.5; | |||
| margin-bottom: 8rpx; | |||
| word-break: break-all; | |||
| } | |||
| .trace-time { | |||
| font-size: 24rpx; | |||
| color: #999; | |||
| margin-bottom: 4rpx; | |||
| } | |||
| .trace-location { | |||
| font-size: 24rpx; | |||
| color: #bbb; | |||
| } | |||
| } | |||
| } | |||
| .loading { | |||
| margin: 40rpx 24rpx; | |||
| text-align: center; | |||
| } | |||
| .empty-state { | |||
| margin: 120rpx 24rpx; | |||
| text-align: center; | |||
| .empty-icon { | |||
| width: 200rpx; | |||
| height: 200rpx; | |||
| margin-bottom: 24rpx; | |||
| } | |||
| .empty-text { | |||
| font-size: 28rpx; | |||
| color: #999; | |||
| } | |||
| } | |||
| </style> | |||