feat(web-admin): add pound QR button on public driver transport page

Show a third footer action that opens the shared weighbridge QR card popup.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-09-13 09:42:57 +08:00
1 parent ab3a90c3f5
commit ee8bf14eb5
2 files changed
+200 -14

No files matched your search

+6
View File
@@ -96,6 +96,12 @@ export interface PublicTransportPage {
feedbackTime?: string
planVoided?: boolean
planArchived?: boolean
poundQrcodeItems?: {
inventoryId: string
businessType: string
partnerCompany: string
label: string
}[]
}
export interface PublicUploadResult {
+194 -14
View File
@@ -320,32 +320,71 @@
</template>
<footer v-if="page && !errorMessage && !loading" class="page-footer">
<div v-if="!page.planVoided && !page.planArchived" class="btn-row">
<div
v-if="!page.planVoided && !page.planArchived"
class="btn-row"
:class="{ 'btn-row--three': hasPoundQr }"
>
<van-button block round type="primary" class="history-btn" @click="goHistory">
运输记录
</van-button>
<van-button
v-if="hasPoundQr"
block
round
plain
type="primary"
@click="handleOpenPoundQr"
>
磅单二维码
</van-button>
<van-button type="primary" block round :loading="saving" @click="handleSave">
保存回执
</van-button>
</div>
<van-button
v-else
block
round
type="primary"
class="history-btn"
@click="goHistory"
>
运输记录
</van-button>
<div v-else class="btn-row" :class="{ 'btn-row--three': hasPoundQr }">
<van-button block round type="primary" class="history-btn" @click="goHistory">
运输记录
</van-button>
<van-button
v-if="hasPoundQr"
block
round
plain
type="primary"
@click="handleOpenPoundQr"
>
磅单二维码
</van-button>
</div>
</footer>
<van-popup
v-model:show="poundPopupVisible"
position="center"
round
:style="{ width: '92%', background: 'transparent' }"
class="pound-qr-popup"
@closed="handlePoundPopupClosed"
>
<div class="pound-qr-popup__mask">
<van-loading v-if="poundLoading" vertical class="pound-qr-popup__loading">
加载中...
</van-loading>
<template v-else-if="poundView">
<div class="pound-qr-popup__title">{{ poundTitle }}</div>
<PoundSlipQrcodeView v-bind="poundView" />
</template>
</div>
</van-popup>
</div>
</PublicMobileShell>
</template>
<script setup lang="ts">
import type { UploaderFileListItem } from 'vant'
import { showFailToast, showSuccessToast } from 'vant'
import { showActionSheet, showFailToast, showSuccessToast } from 'vant'
import { publicInventoryApi, type PublicPoundQr } from '@/api/db/public-inventory'
import {
publicTransportApi,
type BrandQtyItem,
@@ -356,6 +395,7 @@
type PublicTransportStopProduct
} from '@/api/pl/public-transport'
import BrandQtyChipsField from '@/components/business/brand-qty-chips-field/index.vue'
import PoundSlipQrcodeView from '@/components/business/db/PoundSlipQrcodeView.vue'
import PublicMobileShell from '@/layouts/PublicMobileShell.vue'
import PublicPlStopSectionTitle from '@/views/public/pl/_shared/PublicPlStopSectionTitle.vue'
import {
@@ -364,6 +404,8 @@
import { formatPlPersonnelNameWithRole, resolvePlanBrandDisplayLabel } from '@/utils/pl-display'
import 'vant/es/toast/style'
import 'vant/es/action-sheet/style'
import 'vant/es/popup/style'
import '@/styles/public-mobile-vant.scss'
/** 司机链接是否展示各段产品回传数量(暂时关闭,保留模板与提交逻辑) */
@@ -385,6 +427,17 @@
editableProducts: EditableStopProduct[]
}
type PoundViewProps = {
vehicleNo: string
partnerCompany: string
productLine: string
remarks: string
dateText: string
businessType: string
inventoryId: string
qrObjectUrl: string
}
const route = useRoute()
const router = useRouter()
const token = computed(() => String(route.params.token || ''))
@@ -403,6 +456,13 @@
const editableProducts = ref<EditableTransportProduct[]>([])
const stopStates = ref<StopState[]>([])
const poundPopupVisible = ref(false)
const poundLoading = ref(false)
const poundView = ref<PoundViewProps | null>(null)
const poundTitle = ref('磅单二维码')
const hasPoundQr = computed(() => (page.value?.poundQrcodeItems?.length || 0) > 0)
const useMultiStop = computed(() => (page.value?.stops?.length || 0) > 0)
const totalFeedbackQty = computed(() => {
@@ -774,7 +834,94 @@
}
}
function formatQrcodeProductLabel(item: PublicPoundQr) {
const product = (item.product || '').trim()
const specification = (item.specification || '').trim()
if (!specification) return product
if (product.endsWith(specification)) {
const base = product.slice(0, -specification.length).trimEnd()
return base ? `${base} ${specification}` : specification
}
return `${product} ${specification}`
}
function getQrImageUrl(id: string) {
return `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(id)}`
}
function revokePoundQrObjectUrl() {
if (poundView.value?.qrObjectUrl) {
URL.revokeObjectURL(poundView.value.qrObjectUrl)
}
}
function handlePoundPopupClosed() {
revokePoundQrObjectUrl()
poundView.value = null
poundLoading.value = false
}
async function openPoundForId(inventoryId: string) {
poundLoading.value = true
poundPopupVisible.value = true
revokePoundQrObjectUrl()
poundView.value = null
try {
const data = await publicInventoryApi.getPoundQr(inventoryId)
const quantityUnit = (data.quantityUnit || '').trim() || '吨'
const productLine = `${formatQrcodeProductLabel(data)}(${data.quantity} ${quantityUnit})`
const fetchRes = await fetch(getQrImageUrl(data.id), { mode: 'cors' })
if (!fetchRes.ok) throw new Error('二维码图片加载失败')
const blob = await fetchRes.blob()
const qrObjectUrl = URL.createObjectURL(blob)
poundTitle.value = data.businessType === '出库' ? '出库磅单二维码' : '入库磅单二维码'
poundView.value = {
vehicleNo: data.vehicleNo,
partnerCompany: data.partnerCompany,
productLine,
remarks: data.remarks || '',
dateText: data.date || '',
businessType: data.businessType,
inventoryId: data.id,
qrObjectUrl
}
} catch (e: any) {
showFailToast(e?.message || '加载二维码失败')
poundPopupVisible.value = false
revokePoundQrObjectUrl()
poundView.value = null
} finally {
poundLoading.value = false
}
}
async function handleOpenPoundQr() {
const items = page.value?.poundQrcodeItems || []
if (!items.length) return
if (items.length === 1) {
await openPoundForId(items[0].inventoryId)
return
}
try {
const action = await showActionSheet({
actions: items.map((item) => ({
name: item.label,
inventoryId: item.inventoryId
})),
cancelText: '取消'
})
const selectedId = (action as { inventoryId?: string })?.inventoryId
if (!selectedId) return
await openPoundForId(selectedId)
} catch {
// 用户取消 ActionSheet
}
}
onMounted(loadPage)
onBeforeUnmount(() => {
revokePoundQrObjectUrl()
})
</script>
<style scoped lang="scss">
@@ -1030,15 +1177,48 @@
}
.btn-row {
display: grid;
grid-template-columns: 1fr 1fr;
display: flex;
gap: 8px;
:deep(.van-button) {
flex: 1;
}
}
.btn-row--three {
:deep(.van-button) {
font-size: 13px;
padding-left: 8px;
padding-right: 8px;
}
}
.history-btn {
color: #fff !important;
}
.pound-qr-popup__mask {
padding: 18px 14px 22px;
background: rgba(0, 0, 0, 0.92);
border-radius: 16px;
}
.pound-qr-popup__title {
color: #fff;
font-size: 20px;
font-weight: 700;
text-align: center;
margin: 0 0 10px;
padding: 2px 10px 0;
}
.pound-qr-popup__loading {
display: flex;
justify-content: center;
padding: 48px 0;
color: #fff;
}
.stop-uploader-wrap {
padding: 8px 16px 12px;
}