| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- <template>
- <view class="bx-page pl-driver-plan-page">
- <view class="topbar" :style="safeAreaStyle">
- <view class="topbar-left">
- <text class="topbar-back" @click="goBack">←</text>
- <text class="topbar-title">司机运输计划单</text>
- </view>
- <view class="topbar-right" />
- </view>
- <view class="filters">
- <uni-calendar
- :insert="true"
- :date="selectedDate"
- :selected="calendarSelected"
- :showMonth="false"
- @change="onCalendarChange"
- @monthSwitch="onMonthSwitch"
- />
- </view>
- <view class="list-body">
- <view v-if="loading" class="page-loading">加载中...</view>
- <view v-else-if="!records.length" class="empty-hint">暂无运输记录</view>
- <view
- v-for="(row, index) in records"
- :key="row.planId || index"
- class="record-card"
- @click="openRecord(row)"
- >
- <text class="index-tag">{{ index + 1 }}</text>
- <view class="record-top">
- <text class="card-title">{{ cardTitle(row) }}</text>
- <view class="record-top-actions" @click.stop>
- <view class="pound-qr-btn" @click="openPoundQr(row)">磅单二维码</view>
- <text class="tag" :class="tagClass(row)">{{ row.statusLabel || '进行中' }}</text>
- </view>
- </view>
- <view class="meta">
- 车牌:<text class="plate-hl">{{ row.licensePlate || '—' }}</text>
- </view>
- <template v-if="(row.stops || []).length">
- <view
- v-for="(stop, sIndex) in row.stops"
- :key="`${stop.stopType}-${stop.seq ?? sIndex}`"
- class="stop-block"
- >
- <view class="stop-block__title"
- >{{ stop.label }} · {{ stop.customerName || '—' }}</view
- >
- <view class="meta">时间:{{ formatDay(stop.stopTime) }}</view>
- <view class="meta">地址:{{ stop.address || '—' }}</view>
- <template v-if="!(stop.products || []).length">
- <view class="meta">产品:—</view>
- </template>
- <template v-for="(prod, pIndex) in stop.products || []" :key="pIndex">
- <view class="meta">产品:{{ prod.productName || '—' }}</view>
- <view class="meta">规格型号:{{ prod.model || '—' }}</view>
- <view class="meta">包装规格:{{ prod.packageSpec || '—' }}</view>
- <view class="meta"
- >数量:{{ formatQty(prod.quantity) }} · 单位:{{ prod.unit || '—' }}</view
- >
- </template>
- </view>
- </template>
- <view class="meta">运输计划号:{{ row.planNo || '—' }}</view>
- <view class="card-actions" @click.stop>
- <button class="btn btn-sm btn-ghost" @click="handleCopy(row)">复制发群</button>
- </view>
- </view>
- </view>
- <db-pound-qrcode-popup
- :show="poundQrOpen"
- :inventory-id="poundQrId"
- :snapshot="poundQrSnapshot"
- @close="poundQrOpen = false"
- @update:show="(v) => (poundQrOpen = v)"
- />
- </view>
- </template>
- <script setup>
- import { ref } from 'vue'
- import { onShow } from '@dcloudio/uni-app'
- import { PAGE_PATHS } from '@/config/api'
- import { driverPlanApi } from '@/api/pl'
- import { getSafeAreaStyle } from '@/utils/safeArea'
- import { copyDriverPlanToClipboard } from '@/utils/plDriverPlanCopy'
- import DbPoundQrcodePopup from '@/components/db-ui/db-pound-qrcode-popup.vue'
- const safeAreaStyle = getSafeAreaStyle()
- const poundQrOpen = ref(false)
- const poundQrId = ref('')
- const poundQrSnapshot = ref(null)
- function todayStr() {
- const d = new Date()
- const m = `${d.getMonth() + 1}`.padStart(2, '0')
- const day = `${d.getDate()}`.padStart(2, '0')
- return `${d.getFullYear()}-${m}-${day}`
- }
- const selectedDate = ref(todayStr())
- const records = ref([])
- const loading = ref(false)
- const calendarSelected = ref([])
- let calendarMonth = selectedDate.value.slice(0, 7)
- function formatDay(value) {
- if (!value) return '—'
- const normalized = String(value).replace('T', ' ')
- return normalized.length >= 10 ? normalized.slice(0, 10) : normalized
- }
- function formatQty(value) {
- if (value == null || value === '') return '—'
- return String(value)
- }
- function cardTitleDate(row) {
- const stopTimes = (row.stops || [])
- .map((stop) => formatDay(stop.stopTime))
- .filter((value) => value !== '—')
- if (stopTimes.length) return stopTimes[0]
- const fromPickup = formatDay(row.pickupTime)
- if (fromPickup !== '—') return fromPickup
- const fromDelivery = formatDay(row.deliveryTime)
- if (fromDelivery !== '—') return fromDelivery
- return selectedDate.value
- }
- function cardTitle(row) {
- return cardTitleDate(row)
- }
- function tagClass(row) {
- if (row.planVoided || row.statusLabel === '已作废') return 'tag--danger'
- if (row.planArchived || row.statusLabel === '已归档') return 'tag--muted'
- return 'tag--success'
- }
- async function loadList() {
- loading.value = true
- try {
- const res = await driverPlanApi.history({ date: selectedDate.value })
- records.value = res.records || []
- } catch (e) {
- records.value = []
- } finally {
- loading.value = false
- }
- }
- async function loadCalendarCounts(month) {
- const m = String(month || '').slice(0, 7)
- if (!/^\d{4}-\d{2}$/.test(m)) return
- calendarMonth = m
- const today = todayStr()
- try {
- const counts = await driverPlanApi.calendarCounts(m)
- calendarSelected.value = Object.keys(counts || {})
- .filter((date) => Number(counts[date]) > 0 && date >= today)
- .map((date) => ({ date, info: String(counts[date]) }))
- } catch (e) {
- calendarSelected.value = []
- }
- }
- function onCalendarChange(e) {
- const v = e?.fulldate || e?.date || (typeof e === 'string' ? e : '')
- if (typeof v === 'string' && /^\d{4}-\d{2}-\d{2}/.test(v)) {
- selectedDate.value = v.slice(0, 10)
- const month = selectedDate.value.slice(0, 7)
- if (month !== calendarMonth) {
- loadCalendarCounts(month)
- }
- loadList()
- }
- }
- function onMonthSwitch(e) {
- const year = e?.year
- const month = e?.month
- if (year == null || month == null) return
- const m = `${year}-${`${month}`.padStart(2, '0')}`
- loadCalendarCounts(m)
- }
- function openRecord(row) {
- const id = row.planId || row.plan_id
- if (!id) {
- uni.showToast({ title: '计划无效', icon: 'none' })
- return
- }
- uni.navigateTo({ url: `${PAGE_PATHS.plDriverPlanDetail}?planId=${id}` })
- }
- function poundItemsOf(row) {
- const items = row?.poundQrcodeItems || row?.pound_qrcode_items || []
- return Array.isArray(items) ? items : []
- }
- function openPoundForInventoryId(inventoryId) {
- const id = String(inventoryId || '').trim()
- if (!id) {
- uni.showToast({ title: '缺少出入库单', icon: 'none' })
- return
- }
- poundQrId.value = id
- poundQrSnapshot.value = null
- poundQrOpen.value = true
- }
- function openPoundQr(row) {
- const items = poundItemsOf(row)
- if (!items.length) {
- uni.showToast({ title: '暂无磅单二维码', icon: 'none' })
- return
- }
- if (items.length === 1) {
- openPoundForInventoryId(items[0].inventoryId || items[0].inventory_id)
- return
- }
- uni.showActionSheet({
- itemList: items.map((item) => item.label || item.partnerCompany || '磅单'),
- success: (res) => {
- const picked = items[res.tapIndex]
- if (!picked) return
- openPoundForInventoryId(picked.inventoryId || picked.inventory_id)
- }
- })
- }
- async function handleCopy(row) {
- const id = row?.planId || row?.plan_id
- if (!id) {
- uni.showToast({ title: '计划无效', icon: 'none' })
- return
- }
- uni.showLoading({ title: '加载中...', mask: true })
- try {
- const page = (await driverPlanApi.get(id)) || {}
- const ensured = await driverPlanApi.ensureCopySeq(id)
- const copySeqNo = ensured?.copySeqNo ?? ensured?.copy_seq_no
- if (copySeqNo == null || copySeqNo === '') {
- throw new Error('no seq')
- }
- uni.hideLoading()
- await copyDriverPlanToClipboard({ ...page, copySeqNo })
- } catch (e) {
- uni.hideLoading()
- uni.showToast({ title: '复制失败', icon: 'none' })
- }
- }
- function goBack() {
- uni.navigateBack({ fail: () => uni.reLaunch({ url: PAGE_PATHS.workbench }) })
- }
- onShow(() => {
- loadCalendarCounts(calendarMonth || selectedDate.value.slice(0, 7))
- loadList()
- })
- </script>
- <!-- 微信端:scss 须在 style 中 @import;script 里 import 只会生成空 js,H5 有样式而小程序无样式 -->
- <style lang="scss">
- @import '@/styles/bx-theme.scss';
- @import '@/styles/pl-driver-plan.scss';
- </style>
- <style lang="scss" scoped>
- :deep(.uni-calendar__backtoday) {
- display: none;
- }
- :deep(.uni-calendar),
- :deep(.uni-calendar__content),
- :deep(.uni-calendar__box) {
- box-shadow: none !important;
- border: none !important;
- background: transparent !important;
- }
- :deep(.uni-calendar-item--checked),
- :deep(.uni-calendar-item--isDay),
- :deep(.uni-calendar-item--multiple) {
- background-color: #0a9f6d !important;
- color: #fff !important;
- }
- :deep(.uni-calendar-item--isDay-text) {
- color: #0a9f6d !important;
- }
- :deep(.uni-calendar-item--checked.uni-calendar-item--isDay-text),
- :deep(.uni-calendar-item--isDay.uni-calendar-item--isDay-text) {
- color: #fff !important;
- }
- </style>
|