arrange.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <script setup>
  2. import { ref, computed } from 'vue'
  3. import { onLoad } from '@dcloudio/uni-app'
  4. import { getPlan, arrangeTransport, listVehicles, listPersonnel } from '@/api/pl'
  5. import { dash, planCardSub } from '@/utils/plLabels'
  6. import { PAGE_PATHS } from '@/config/api'
  7. const id = ref('')
  8. const detail = ref(null)
  9. const vehicles = ref([])
  10. const drivers = ref([])
  11. const vehicleIndex = ref(-1)
  12. const driverIndex = ref(-1)
  13. const freightTypeIndex = ref(0)
  14. const freightPrice = ref('')
  15. const freightAmount = ref('')
  16. const distanceKm = ref('')
  17. const acting = ref(false)
  18. const freightTypes = [
  19. { value: 'by_weight', label: '按重量' },
  20. { value: 'by_trip', label: '按趟次' }
  21. ]
  22. const vehicleLabels = computed(() =>
  23. vehicles.value.map((v) => v.licensePlate || v.plateNo || v.id)
  24. )
  25. const driverLabels = computed(() =>
  26. drivers.value.map((d) => `${d.personnelName || d.name || ''}${d.phoneNo ? ` ${d.phoneNo}` : ''}`)
  27. )
  28. const freightTypeLabels = computed(() => freightTypes.map((t) => t.label))
  29. const goBack = () => {
  30. uni.navigateBack({
  31. fail: () => uni.navigateTo({ url: `${PAGE_PATHS.plPlanDetail}?id=${id.value}` })
  32. })
  33. }
  34. const loadOptions = async () => {
  35. try {
  36. const [vRes, pRes] = await Promise.all([
  37. listVehicles({ page: 1, pageSize: 100, vehicleStatus: 'active' }),
  38. listPersonnel({ page: 1, pageSize: 100, personnelType: 'driver' })
  39. ])
  40. vehicles.value = vRes.rows || []
  41. drivers.value = pRes.rows || []
  42. // 若无 driver 类型,再拉全量人员
  43. if (!drivers.value.length) {
  44. const all = await listPersonnel({ page: 1, pageSize: 100 })
  45. drivers.value = all.rows || []
  46. }
  47. } catch (e) {
  48. uni.showToast({ title: e.message || '加载车辆/司机失败', icon: 'none' })
  49. }
  50. }
  51. const load = async () => {
  52. if (!id.value) return
  53. try {
  54. detail.value = await getPlan(id.value)
  55. await loadOptions()
  56. } catch (e) {
  57. uni.showToast({ title: e.message || '加载失败', icon: 'none' })
  58. }
  59. }
  60. const onVehicleChange = (e) => {
  61. vehicleIndex.value = Number(e.detail.value)
  62. }
  63. const onDriverChange = (e) => {
  64. driverIndex.value = Number(e.detail.value)
  65. }
  66. const onFreightTypeChange = (e) => {
  67. freightTypeIndex.value = Number(e.detail.value)
  68. }
  69. const submit = async () => {
  70. if (vehicleIndex.value < 0 || !vehicles.value[vehicleIndex.value]) {
  71. uni.showToast({ title: '请选择车辆', icon: 'none' })
  72. return
  73. }
  74. if (driverIndex.value < 0 || !drivers.value[driverIndex.value]) {
  75. uni.showToast({ title: '请选择司机', icon: 'none' })
  76. return
  77. }
  78. const vehicle = vehicles.value[vehicleIndex.value]
  79. const driver = drivers.value[driverIndex.value]
  80. const body = {
  81. vehicleId: String(vehicle.id),
  82. driverId: String(driver.id),
  83. carrierId: vehicle.carrierId || undefined,
  84. freightType: freightTypes[freightTypeIndex.value].value,
  85. pickupAddress: detail.value?.pickupAddress || undefined,
  86. destinationAddress: detail.value?.destinationAddress || undefined
  87. }
  88. if (freightPrice.value !== '') body.freightPrice = Number(freightPrice.value)
  89. if (freightAmount.value !== '') body.freightAmount = Number(freightAmount.value)
  90. if (distanceKm.value !== '') body.distanceKm = Number(distanceKm.value)
  91. acting.value = true
  92. try {
  93. await arrangeTransport(id.value, body)
  94. uni.showToast({ title: '已安排运输', icon: 'success' })
  95. setTimeout(() => {
  96. uni.redirectTo({ url: `${PAGE_PATHS.plPlanDetail}?id=${id.value}` })
  97. }, 500)
  98. } catch (e) {
  99. uni.showToast({ title: e.message || '安排失败', icon: 'none' })
  100. } finally {
  101. acting.value = false
  102. }
  103. }
  104. onLoad((q) => {
  105. id.value = q?.id || ''
  106. load()
  107. })
  108. </script>
  109. <template>
  110. <view class="mp-page mp-page--sub mp-page--with-bottom">
  111. <view class="mp-header mp-header--pl">
  112. <text class="mp-subpage-back" @click="goBack">← 返回</text>
  113. <text class="mp-header__title" style="margin-top: 16rpx">安排运输</text>
  114. <text v-if="detail" class="mp-header__meta">{{ dash(detail.planNo) }} · {{ planCardSub(detail) }}</text>
  115. </view>
  116. <view class="mp-block">
  117. <text class="mp-block__title">选择资源</text>
  118. <view class="mp-form">
  119. <view class="mp-form-item">
  120. <text class="mp-form-label">车辆</text>
  121. <picker :range="vehicleLabels" @change="onVehicleChange">
  122. <view class="mp-form-picker">
  123. {{ vehicleIndex >= 0 ? vehicleLabels[vehicleIndex] : '请选择车辆' }}
  124. </view>
  125. </picker>
  126. </view>
  127. <view class="mp-form-item">
  128. <text class="mp-form-label">司机</text>
  129. <picker :range="driverLabels" @change="onDriverChange">
  130. <view class="mp-form-picker">
  131. {{ driverIndex >= 0 ? driverLabels[driverIndex] : '请选择司机' }}
  132. </view>
  133. </picker>
  134. </view>
  135. <view class="mp-form-item">
  136. <text class="mp-form-label">运费方式</text>
  137. <picker :range="freightTypeLabels" :value="freightTypeIndex" @change="onFreightTypeChange">
  138. <view class="mp-form-picker">{{ freightTypeLabels[freightTypeIndex] }}</view>
  139. </picker>
  140. </view>
  141. <view class="mp-form-item">
  142. <text class="mp-form-label">运费单价</text>
  143. <input v-model="freightPrice" class="mp-form-input" type="digit" placeholder="可选" />
  144. </view>
  145. <view class="mp-form-item">
  146. <text class="mp-form-label">运费金额</text>
  147. <input v-model="freightAmount" class="mp-form-input" type="digit" placeholder="可选" />
  148. </view>
  149. <view class="mp-form-item">
  150. <text class="mp-form-label">公里数</text>
  151. <input v-model="distanceKm" class="mp-form-input" type="digit" placeholder="可选" />
  152. </view>
  153. </view>
  154. </view>
  155. <view class="mp-bottom-bar">
  156. <button class="mp-btn mp-btn--primary mp-btn--block" :disabled="acting" @click="submit">
  157. {{ acting ? '提交中…' : '确认安排' }}
  158. </button>
  159. </view>
  160. </view>
  161. </template>