feat(web-admin): add public pound QR page by inventory id

Drivers can open a standalone link that renders the shared weighbridge QR card.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-09-13 09:38:23 +08:00
1 parent d7dec04cb3
commit 5b4c1bc991
3 files changed
+162

No files matched your search

+15
View File
@@ -19,8 +19,23 @@ export interface PublicInventoryPage {
voided: boolean
}
export interface PublicPoundQr {
id: string
date?: string
businessType: string
vehicleNo: string
partnerCompany: string
product: string
specification?: string
quantity: number
quantityUnit?: string
remarks?: string
}
export const publicInventoryApi = {
getPage: (token: string) => publicPlGet<PublicInventoryPage>(`/public/db/inventory/${token}`),
getPoundQr: (inventoryId: string) =>
publicPlGet<PublicPoundQr>(`/public/db/inventory/${inventoryId}/pound-qr`),
saveFeedback: (
token: string,
data: { siteFeedbackRemark?: string; siteFeedbackImages?: string[] }
@@ -111,6 +111,12 @@ export const staticRoutes: AppRouteRecordRaw[] = [
component: () => import('@views/public/pl/outbound/index.vue'),
meta: { title: '出库单', isHideTab: true, isPublicMobile: true }
},
{
path: '/public/pl/pound-qrcode/:inventoryId',
name: 'PublicPlPoundQrcode',
component: () => import('@views/public/pl/pound-qrcode/index.vue'),
meta: { title: '磅单二维码', isHideTab: true, isPublicMobile: true }
},
{
path: '/public/db/inventory/:token',
name: 'PublicDbInventorySite',
@@ -0,0 +1,141 @@
<template>
<PublicMobileShell>
<div class="public-pl-pound-qrcode-page">
<van-loading v-if="loading" vertical class="page-loading">加载中...</van-loading>
<van-empty v-else-if="errorMessage" :description="errorMessage" />
<div v-else-if="row && qrObjectUrl" class="qr-stage">
<div class="qr-dialog-title">{{ pageTitle }}</div>
<PoundSlipQrcodeView
:vehicle-no="row.vehicleNo"
:partner-company="row.partnerCompany"
:product-line="productLine"
:remarks="row.remarks || ''"
:date-text="row.date || ''"
:business-type="row.businessType"
:inventory-id="row.id"
:qr-object-url="qrObjectUrl"
/>
</div>
</div>
</PublicMobileShell>
</template>
<script setup lang="ts">
import { publicInventoryApi, type PublicPoundQr } from '@/api/db/public-inventory'
import PoundSlipQrcodeView from '@/components/business/db/PoundSlipQrcodeView.vue'
import PublicMobileShell from '@/layouts/PublicMobileShell.vue'
import 'vant/es/toast/style'
import 'vant/es/empty/style'
import '@/styles/public-mobile-vant.scss'
const route = useRoute()
const inventoryId = computed(() => String(route.params.inventoryId || ''))
const loading = ref(true)
const errorMessage = ref('')
const row = ref<PublicPoundQr | null>(null)
const qrObjectUrl = ref('')
const pageTitle = computed(() => {
if (!row.value) return '磅单二维码'
return row.value.businessType === '出库' ? '出库磅单二维码' : '入库磅单二维码'
})
const quantityUnitLabel = computed(() => (row.value?.quantityUnit || '').trim() || '吨')
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}`
}
const productLine = computed(() => {
if (!row.value) return ''
return `${formatQrcodeProductLabel(row.value)}(${row.value.quantity} ${quantityUnitLabel.value})`
})
function getQrImageUrl(id: string) {
return `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(id)}`
}
function revokeQrObjectUrl() {
if (qrObjectUrl.value) {
URL.revokeObjectURL(qrObjectUrl.value)
qrObjectUrl.value = ''
}
}
async function loadPage() {
loading.value = true
errorMessage.value = ''
row.value = null
revokeQrObjectUrl()
const id = inventoryId.value
if (!id) {
errorMessage.value = '链接无效或单据不存在'
loading.value = false
return
}
try {
// publicPlGet 已解包 data;与其它公共页一致直接使用返回值
const data = await publicInventoryApi.getPoundQr(id)
row.value = data
const fetchRes = await fetch(getQrImageUrl(data.id), { mode: 'cors' })
if (!fetchRes.ok) throw new Error('二维码图片加载失败')
const blob = await fetchRes.blob()
qrObjectUrl.value = URL.createObjectURL(blob)
} catch (e: any) {
errorMessage.value = e?.message || '链接无效或单据不存在'
row.value = null
revokeQrObjectUrl()
} finally {
loading.value = false
}
}
onMounted(loadPage)
onBeforeUnmount(revokeQrObjectUrl)
</script>
<style scoped lang="scss">
.public-pl-pound-qrcode-page {
min-height: 100vh;
background: rgba(0, 0, 0, 0.92);
}
.page-loading {
display: flex;
justify-content: center;
padding: 48px 0;
color: #fff;
}
.qr-stage {
padding: 18px 14px 22px;
max-width: 400px;
margin: 0 auto;
}
.qr-dialog-title {
color: #fff;
font-size: 20px;
font-weight: 700;
text-align: center;
margin: 0 0 10px;
padding: 2px 10px 0;
}
:deep(.van-empty) {
padding-top: 80px;
}
:deep(.van-empty__description) {
color: #94a3b8;
}
</style>