list.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <template>
  2. <view class="bx-page pl-driver-plan-page">
  3. <view class="topbar" :style="safeAreaStyle">
  4. <view class="topbar-left">
  5. <text class="topbar-back" @click="goBack">←</text>
  6. <text class="topbar-title">司机运输计划单</text>
  7. </view>
  8. <view class="topbar-right" />
  9. </view>
  10. <view class="filters">
  11. <uni-calendar
  12. :insert="true"
  13. :date="selectedDate"
  14. :showMonth="false"
  15. @change="onCalendarChange"
  16. />
  17. </view>
  18. <view class="list-body">
  19. <view v-if="loading" class="page-loading">加载中...</view>
  20. <view v-else-if="!records.length" class="empty-hint">暂无运输记录</view>
  21. <view
  22. v-for="(row, index) in records"
  23. :key="row.planId || index"
  24. class="record-card"
  25. @click="openRecord(row)"
  26. >
  27. <text class="index-tag">{{ index + 1 }}</text>
  28. <view class="record-top">
  29. <text class="card-title">{{ cardTitle(row) }}</text>
  30. <text class="tag" :class="tagClass(row)">{{ row.statusLabel || '进行中' }}</text>
  31. </view>
  32. <view class="meta">
  33. 车牌:<text class="plate-hl">{{ row.licensePlate || '—' }}</text>
  34. </view>
  35. <template v-if="(row.stops || []).length">
  36. <view
  37. v-for="(stop, sIndex) in row.stops"
  38. :key="`${stop.stopType}-${stop.seq ?? sIndex}`"
  39. class="stop-block"
  40. >
  41. <view class="stop-block__title"
  42. >{{ stop.label }} · {{ stop.customerName || '—' }}</view
  43. >
  44. <view class="meta">时间:{{ formatDay(stop.stopTime) }}</view>
  45. <view class="meta">地址:{{ stop.address || '—' }}</view>
  46. <template v-if="!(stop.products || []).length">
  47. <view class="meta">产品:—</view>
  48. </template>
  49. <template v-for="(prod, pIndex) in stop.products || []" :key="pIndex">
  50. <view class="meta">产品:{{ prod.productName || '—' }}</view>
  51. <view class="meta">规格型号:{{ prod.model || '—' }}</view>
  52. <view class="meta">包装规格:{{ prod.packageSpec || '—' }}</view>
  53. <view class="meta"
  54. >数量:{{ formatQty(prod.quantity) }} · 单位:{{ prod.unit || '—' }}</view
  55. >
  56. </template>
  57. </view>
  58. </template>
  59. <view class="meta">运输计划号:{{ row.planNo || '—' }}</view>
  60. </view>
  61. </view>
  62. </view>
  63. </template>
  64. <script setup>
  65. import { ref } from 'vue'
  66. import { onShow } from '@dcloudio/uni-app'
  67. import { PAGE_PATHS } from '@/config/api'
  68. import { driverPlanApi } from '@/api/pl'
  69. import { getSafeAreaStyle } from '@/utils/safeArea'
  70. const safeAreaStyle = getSafeAreaStyle()
  71. function todayStr() {
  72. const d = new Date()
  73. const m = `${d.getMonth() + 1}`.padStart(2, '0')
  74. const day = `${d.getDate()}`.padStart(2, '0')
  75. return `${d.getFullYear()}-${m}-${day}`
  76. }
  77. const selectedDate = ref(todayStr())
  78. const records = ref([])
  79. const loading = ref(false)
  80. function formatDay(value) {
  81. if (!value) return '—'
  82. const normalized = String(value).replace('T', ' ')
  83. return normalized.length >= 10 ? normalized.slice(0, 10) : normalized
  84. }
  85. function formatQty(value) {
  86. if (value == null || value === '') return '—'
  87. return String(value)
  88. }
  89. function cardTitleDate(row) {
  90. const stopTimes = (row.stops || [])
  91. .map((stop) => formatDay(stop.stopTime))
  92. .filter((value) => value !== '—')
  93. if (stopTimes.length) return stopTimes[0]
  94. const fromPickup = formatDay(row.pickupTime)
  95. if (fromPickup !== '—') return fromPickup
  96. const fromDelivery = formatDay(row.deliveryTime)
  97. if (fromDelivery !== '—') return fromDelivery
  98. return selectedDate.value
  99. }
  100. function cardTitle(row) {
  101. return cardTitleDate(row)
  102. }
  103. function tagClass(row) {
  104. if (row.planVoided || row.statusLabel === '已作废') return 'tag--danger'
  105. if (row.planArchived || row.statusLabel === '已归档') return 'tag--muted'
  106. return 'tag--success'
  107. }
  108. async function loadList() {
  109. loading.value = true
  110. try {
  111. const res = await driverPlanApi.history({ date: selectedDate.value })
  112. records.value = res.records || []
  113. } catch (e) {
  114. records.value = []
  115. } finally {
  116. loading.value = false
  117. }
  118. }
  119. function onCalendarChange(e) {
  120. const v = e?.fulldate || e?.date || (typeof e === 'string' ? e : '')
  121. if (typeof v === 'string' && /^\d{4}-\d{2}-\d{2}/.test(v)) {
  122. selectedDate.value = v.slice(0, 10)
  123. loadList()
  124. }
  125. }
  126. function openRecord(row) {
  127. const id = row.planId || row.plan_id
  128. if (!id) {
  129. uni.showToast({ title: '计划无效', icon: 'none' })
  130. return
  131. }
  132. uni.navigateTo({ url: `${PAGE_PATHS.plDriverPlanDetail}?planId=${id}` })
  133. }
  134. function goBack() {
  135. uni.navigateBack({ fail: () => uni.reLaunch({ url: PAGE_PATHS.workbench }) })
  136. }
  137. onShow(() => {
  138. loadList()
  139. })
  140. </script>
  141. <!-- 微信端:scss 须在 style 中 @import;script 里 import 只会生成空 js,H5 有样式而小程序无样式 -->
  142. <style lang="scss">
  143. @import '@/styles/bx-theme.scss';
  144. @import '@/styles/pl-driver-plan.scss';
  145. </style>
  146. <style lang="scss" scoped>
  147. :deep(.uni-calendar__backtoday) {
  148. display: none;
  149. }
  150. :deep(.uni-calendar-item--checked),
  151. :deep(.uni-calendar-item--isDay),
  152. :deep(.uni-calendar-item--multiple) {
  153. background-color: #0a9f6d !important;
  154. color: #fff !important;
  155. }
  156. :deep(.uni-calendar-item--isDay-text) {
  157. color: #0a9f6d !important;
  158. }
  159. :deep(.uni-calendar-item--checked.uni-calendar-item--isDay-text),
  160. :deep(.uni-calendar-item--isDay.uni-calendar-item--isDay-text) {
  161. color: #fff !important;
  162. }
  163. </style>