feat(pl): implement public driver transport history list page
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
ea33e62eaa
commit
d01603f709
1 file changed
+267
-5
@@ -1,19 +1,281 @@
|
||||
<template>
|
||||
<PublicMobileShell>
|
||||
<van-nav-bar title="运输记录" left-arrow @click-left="goBack" />
|
||||
<van-empty description="加载中…" />
|
||||
<div class="public-pl-history-page">
|
||||
<van-nav-bar
|
||||
title="运输记录"
|
||||
left-arrow
|
||||
:border="false"
|
||||
class="transport-nav-bar"
|
||||
@click-left="goBack"
|
||||
/>
|
||||
|
||||
<van-loading v-if="loading" vertical class="page-loading">加载中...</van-loading>
|
||||
<van-empty v-else-if="errorMessage" :description="errorMessage" />
|
||||
<template v-else>
|
||||
<div class="filters">
|
||||
<div class="chips">
|
||||
<button
|
||||
v-for="q in quickOptions"
|
||||
:key="q.offset"
|
||||
type="button"
|
||||
class="chip"
|
||||
:class="{ on: pickDate === q.ymd }"
|
||||
@click="setQuick(q.offset)"
|
||||
>
|
||||
{{ q.label }}
|
||||
</button>
|
||||
</div>
|
||||
<input v-model="pickDate" type="date" class="date-input" @change="load" />
|
||||
<div class="hint">{{ filterHint }}</div>
|
||||
</div>
|
||||
|
||||
<van-empty v-if="!records.length" description="暂无运输记录" />
|
||||
<div
|
||||
v-for="row in records"
|
||||
:key="row.planId"
|
||||
class="record-card"
|
||||
role="button"
|
||||
@click="openRecord(row)"
|
||||
>
|
||||
<div class="record-top">
|
||||
<span class="plan-no">{{ row.planNo }}</span>
|
||||
<span class="tag" :class="tagClass(row)">{{ row.statusLabel || '进行中' }}</span>
|
||||
</div>
|
||||
<div class="meta">
|
||||
取货:{{ formatDay(row.pickupTime) }} · 送货:{{ formatDay(row.deliveryTime) }}
|
||||
</div>
|
||||
<div class="meta">
|
||||
线路:{{ row.pickupAddress || '—' }} → {{ row.destinationAddress || '—' }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</PublicMobileShell>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { showFailToast } from 'vant'
|
||||
import {
|
||||
publicTransportApi,
|
||||
type PublicTransportHistoryRecord
|
||||
} from '@/api/pl/public-transport'
|
||||
import PublicMobileShell from '@/layouts/PublicMobileShell.vue'
|
||||
|
||||
import 'vant/es/toast/style'
|
||||
import '@/styles/public-mobile-vant.scss'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const token = computed(() => String(route.params.token || ''))
|
||||
|
||||
const loading = ref(true)
|
||||
const errorMessage = ref('')
|
||||
const records = ref<PublicTransportHistoryRecord[]>([])
|
||||
const pickDate = ref(addDays(0))
|
||||
|
||||
const quickOptions = [
|
||||
{ label: '今天', offset: 0, ymd: addDays(0) },
|
||||
{ label: '明天', offset: 1, ymd: addDays(1) },
|
||||
{ label: '后天', offset: 2, ymd: addDays(2) }
|
||||
]
|
||||
|
||||
const filterHint = computed(() => `筛选日期:${pickDate.value}(取货或送货落在当天)`)
|
||||
|
||||
function formatYmd(d: Date) {
|
||||
const y = d.getFullYear()
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
return `${y}-${m}-${day}`
|
||||
}
|
||||
|
||||
function addDays(n: number) {
|
||||
const d = new Date()
|
||||
d.setHours(0, 0, 0, 0)
|
||||
d.setDate(d.getDate() + n)
|
||||
return formatYmd(d)
|
||||
}
|
||||
|
||||
function formatDay(value?: string) {
|
||||
if (!value) return '—'
|
||||
const normalized = value.replace('T', ' ')
|
||||
return normalized.length >= 10 ? normalized.slice(0, 10) : normalized
|
||||
}
|
||||
|
||||
function tagClass(row: PublicTransportHistoryRecord) {
|
||||
if (row.planVoided || row.statusLabel === '已作废') return 'tag--danger'
|
||||
if (row.planArchived || row.statusLabel === '已归档') return 'tag--muted'
|
||||
return 'tag--success'
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
const token = String(route.params.token || '')
|
||||
router.push({ name: 'PublicPlTransportDriver', params: { token } })
|
||||
router.push({ name: 'PublicPlTransportDriver', params: { token: token.value } })
|
||||
}
|
||||
|
||||
function setQuick(offset: number) {
|
||||
pickDate.value = addDays(offset)
|
||||
load()
|
||||
}
|
||||
|
||||
function openRecord(row: PublicTransportHistoryRecord) {
|
||||
const accessToken = (row.driverAccessToken || '').trim()
|
||||
if (!accessToken) {
|
||||
showFailToast('该记录暂无司机链接')
|
||||
return
|
||||
}
|
||||
router.push({ name: 'PublicPlTransportDriver', params: { token: accessToken } })
|
||||
}
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
errorMessage.value = ''
|
||||
try {
|
||||
const data = await publicTransportApi.getHistory(token.value, pickDate.value)
|
||||
records.value = data?.records || []
|
||||
} catch (e: any) {
|
||||
errorMessage.value = e?.message || '链接无效或已失效'
|
||||
records.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 48px 0;
|
||||
}
|
||||
|
||||
.transport-nav-bar {
|
||||
margin: -12px -16px 12px;
|
||||
border-radius: 0 0 12px 12px;
|
||||
overflow: hidden;
|
||||
|
||||
:deep(.van-nav-bar) {
|
||||
background: #059669;
|
||||
}
|
||||
|
||||
:deep(.van-nav-bar__title),
|
||||
:deep(.van-nav-bar__arrow) {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
:deep(.van-nav-bar__title) {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin-bottom: 12px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.chip {
|
||||
height: 30px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid #d1fae5;
|
||||
background: #ecfdf5;
|
||||
color: #047857;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.chip.on {
|
||||
background: #059669;
|
||||
border-color: #059669;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.date-input {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
color: #1e293b;
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.record-card {
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
border: 1px solid #e2e8f0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.record-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.plan-no {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.tag {
|
||||
flex-shrink: 0;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.tag--success {
|
||||
background: #059669;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.tag--danger {
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.tag--muted {
|
||||
background: #94a3b8;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.meta {
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
line-height: 1.45;
|
||||
word-break: break-all;
|
||||
|
||||
& + .meta {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user