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:
1 parent
ab3a90c3f5
commit
ee8bf14eb5
2 files changed
+200
-14
No files matched your search
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user