爱简收旧衣按件回收前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
5.9 KiB

  1. <template>
  2. <view class="logistics-page">
  3. <!-- 顶部导航 -->
  4. <view class="nav-bar">
  5. <view class="back" @tap="goBack">
  6. <uni-icons type="left" size="20" color="#222" />
  7. </view>
  8. <text class="nav-title">物流轨迹</text>
  9. </view>
  10. <!-- 物流信息卡片 -->
  11. <view class="logistics-card">
  12. <view class="express-info">
  13. <view class="express-company">{{ expressCompany }}</view>
  14. <view class="express-number">运单号{{ wuliuNo }}</view>
  15. </view>
  16. </view>
  17. <!-- 物流轨迹列表 -->
  18. <view class="trace-list">
  19. <view
  20. v-for="(item, index) in traceList"
  21. :key="index"
  22. class="trace-item"
  23. :class="{ 'active': index === 0 }"
  24. >
  25. <view class="trace-dot">
  26. <view class="dot-inner"></view>
  27. </view>
  28. <view class="trace-line" v-if="index < traceList.length - 1"></view>
  29. <view class="trace-content">
  30. <view class="trace-desc">{{ item.description }}</view>
  31. <view class="trace-time">{{ item.time }}</view>
  32. <view class="trace-location">{{ item.site }}</view>
  33. </view>
  34. </view>
  35. </view>
  36. <!-- 加载状态 -->
  37. <view v-if="loading" class="loading">
  38. <uni-load-more status="loading" :content-text="loadingText"></uni-load-more>
  39. </view>
  40. <!-- 无数据状态 -->
  41. <view v-if="!loading && traceList.length === 0" class="empty-state">
  42. <image src="/static/empty-logistics.png" class="empty-icon" mode="aspectFit"></image>
  43. <text class="empty-text">暂无物流信息</text>
  44. </view>
  45. </view>
  46. </template>
  47. <script>
  48. export default {
  49. data() {
  50. return {
  51. wuliuNo: '',
  52. expressCompany: '',
  53. traceList: [],
  54. loading: false,
  55. loadingText: {
  56. contentdown: '上拉显示更多',
  57. contentrefresh: '正在加载...',
  58. contentnomore: '没有更多数据了'
  59. }
  60. }
  61. },
  62. onLoad(options) {
  63. if (options.wliuNo) {
  64. this.wuliuNo = options.wliuNo
  65. }
  66. if (options.expressCompany) {
  67. this.expressCompany = options.expressCompany
  68. }
  69. this.fetchLogisticsTrace()
  70. },
  71. methods: {
  72. goBack() {
  73. uni.navigateBack()
  74. },
  75. async fetchLogisticsTrace() {
  76. if (!this.wuliuNo) {
  77. uni.showToast({ title: '运单号不能为空', icon: 'none' })
  78. return
  79. }
  80. this.loading = true
  81. try {
  82. this.$api('queryTrace', {
  83. wuliuNo: this.wuliuNo
  84. }, res => {
  85. this.loading = false
  86. if (res && res.code === 200 && res.result && res.result.responseParam) {
  87. const traceData = res.result.responseParam
  88. this.traceList = traceData.trace_list || []
  89. if (this.traceList.length === 0) {
  90. uni.showToast({ title: '暂无物流信息', icon: 'none' })
  91. }
  92. } else {
  93. uni.showToast({ title: res?.message || '获取物流信息失败', icon: 'none' })
  94. }
  95. })
  96. } catch (error) {
  97. this.loading = false
  98. uni.showToast({ title: '网络错误,请重试', icon: 'none' })
  99. }
  100. }
  101. }
  102. }
  103. </script>
  104. <style lang="scss" scoped>
  105. .logistics-page {
  106. min-height: 100vh;
  107. background: #f8f8f8;
  108. padding-bottom: 40rpx;
  109. }
  110. .nav-bar {
  111. display: flex;
  112. align-items: center;
  113. height: calc(150rpx + var(--status-bar-height));
  114. padding: 0 32rpx;
  115. padding-top: var(--status-bar-height);
  116. background: #fff;
  117. position: fixed;
  118. top: 0;
  119. left: 0;
  120. right: 0;
  121. z-index: 999;
  122. box-sizing: border-box;
  123. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
  124. .back {
  125. padding: 20rpx;
  126. margin-left: -20rpx;
  127. }
  128. .nav-title {
  129. flex: 1;
  130. text-align: center;
  131. font-size: 32rpx;
  132. font-weight: 500;
  133. color: #222;
  134. }
  135. }
  136. .logistics-card {
  137. margin: calc(150rpx + var(--status-bar-height) + 24rpx) 24rpx 24rpx 24rpx;
  138. background: #fff;
  139. border-radius: 24rpx;
  140. padding: 32rpx;
  141. box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
  142. .express-info {
  143. .express-company {
  144. font-size: 32rpx;
  145. font-weight: bold;
  146. color: #222;
  147. margin-bottom: 12rpx;
  148. }
  149. .express-number {
  150. font-size: 28rpx;
  151. color: #666;
  152. }
  153. }
  154. }
  155. .trace-list {
  156. margin: 0 24rpx;
  157. background: #fff;
  158. border-radius: 24rpx;
  159. padding: 32rpx;
  160. box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
  161. position: relative;
  162. }
  163. .trace-item {
  164. display: flex;
  165. align-items: flex-start;
  166. position: relative;
  167. padding-bottom: 32rpx;
  168. &:last-child {
  169. padding-bottom: 0;
  170. }
  171. &.active {
  172. .trace-dot {
  173. background: #ff9c00;
  174. border-color: #ff9c00;
  175. }
  176. .trace-content {
  177. .trace-desc {
  178. color: #222;
  179. font-weight: bold;
  180. }
  181. .trace-time {
  182. color: #ff9c00;
  183. }
  184. }
  185. }
  186. .trace-dot {
  187. width: 24rpx;
  188. height: 24rpx;
  189. border-radius: 50%;
  190. background: #ddd;
  191. border: 4rpx solid #f0f0f0;
  192. margin-right: 24rpx;
  193. margin-top: 8rpx;
  194. flex-shrink: 0;
  195. position: relative;
  196. z-index: 2;
  197. .dot-inner {
  198. width: 8rpx;
  199. height: 8rpx;
  200. border-radius: 50%;
  201. background: #fff;
  202. position: absolute;
  203. top: 50%;
  204. left: 50%;
  205. transform: translate(-50%, -50%);
  206. }
  207. }
  208. .trace-line {
  209. position: absolute;
  210. left: 12rpx;
  211. top: 32rpx;
  212. width: 2rpx;
  213. height: calc(100% - 32rpx);
  214. background: #f0f0f0;
  215. z-index: 1;
  216. }
  217. .trace-content {
  218. flex: 1;
  219. min-width: 0;
  220. .trace-desc {
  221. font-size: 28rpx;
  222. color: #666;
  223. line-height: 1.5;
  224. margin-bottom: 8rpx;
  225. word-break: break-all;
  226. }
  227. .trace-time {
  228. font-size: 24rpx;
  229. color: #999;
  230. margin-bottom: 4rpx;
  231. }
  232. .trace-location {
  233. font-size: 24rpx;
  234. color: #bbb;
  235. }
  236. }
  237. }
  238. .loading {
  239. margin: 40rpx 24rpx;
  240. text-align: center;
  241. }
  242. .empty-state {
  243. margin: 120rpx 24rpx;
  244. text-align: center;
  245. .empty-icon {
  246. width: 200rpx;
  247. height: 200rpx;
  248. margin-bottom: 24rpx;
  249. }
  250. .empty-text {
  251. font-size: 28rpx;
  252. color: #999;
  253. }
  254. }
  255. </style>