Files
shanxia2.0/miniprogram/components/db-ui/db-pound-qrcode-popup.vue
T

293 lines
7.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view v-if="show" class="pound-qr-mask" @click="close">
<view class="pound-qr-panel" @click.stop>
<view class="pound-qr-panel__title">{{ title }}</view>
<view v-if="loading" class="pound-qr-panel__loading">加载中...</view>
<view v-else-if="row" class="pound-slip-capture-inline">
<view class="capture-card">
<view class="capture-row capture-row-plate">
<view class="vehicle-plate">
<view class="vehicle-plate-dot vehicle-plate-dot-lt" />
<view class="vehicle-plate-dot vehicle-plate-dot-lb" />
<text class="vehicle-plate-text">{{ row.vehicleNo || '未填车牌' }}</text>
<view class="vehicle-plate-dot vehicle-plate-dot-rt" />
<view class="vehicle-plate-dot vehicle-plate-dot-rb" />
</view>
</view>
<view class="capture-row capture-row-large">
<text class="label">往来单位:</text>
<text class="value">{{ row.partnerCompany || '--' }}</text>
</view>
<view class="capture-row capture-row-large">
<text class="label">物料名称:</text>
<text class="value">{{ productLine }}</text>
</view>
<view v-if="remarksText" class="capture-row">
<text class="label">备注:</text>
<text class="value">{{ remarksText }}</text>
</view>
</view>
<view class="capture-card capture-qrcode">
<view class="capture-id">
{{ row.date || '' }}
{{ row.businessType === '出库' ? '出库单ID:' : '入库单ID:' }}{{ row.id }}
</view>
<view class="capture-qr-wrap">
<image v-if="qrPath" class="capture-qr-img" :src="qrPath" mode="aspectFit" />
</view>
<view class="capture-desc">出入库单标识(扫码核验)</view>
</view>
</view>
<!-- 隐藏 canvas,供 uqrcodejs 绘制 -->
<canvas
canvas-id="poundQrCanvas"
id="poundQrCanvas"
class="pound-qr-canvas"
:style="{ width: canvasSize + 'px', height: canvasSize + 'px' }"
/>
</view>
</view>
</template>
<script setup>
import { computed, getCurrentInstance, ref, watch } from 'vue'
import { inventoryApi } from '@/pages/db/api/db'
import {
formatPoundQrProductLine,
normalizePoundQrRemarks,
poundQrDialogTitle
} from '@/utils/dbPoundQr'
import { makeQrTempFile } from '@/utils/makeQrTempFile'
const props = defineProps({
show: Boolean,
inventoryId: { type: String, default: '' },
/** 列表行快照(可选);仍会按需 get 补全 */
snapshot: { type: Object, default: null }
})
const emit = defineEmits(['close', 'update:show'])
const loading = ref(false)
const row = ref(null)
const qrPath = ref('')
let loadSeq = 0
const canvasSize = 200
const instance = getCurrentInstance()
const title = computed(() => poundQrDialogTitle(row.value?.businessType))
const productLine = computed(() =>
row.value ? formatPoundQrProductLine(row.value, '吨') : ''
)
const remarksText = computed(() => (row.value ? normalizePoundQrRemarks(row.value) : ''))
function close() {
emit('update:show', false)
emit('close')
}
function reset() {
loadSeq += 1
row.value = null
qrPath.value = ''
loading.value = false
}
async function load() {
const seq = ++loadSeq
const id = String(props.inventoryId || '').trim()
if (!id) {
uni.showToast({ title: '缺少单据ID', icon: 'none' })
close()
return
}
loading.value = true
row.value = null
qrPath.value = ''
try {
let data = props.snapshot && props.snapshot.id === id ? { ...props.snapshot } : null
if (!data || data.quantity == null || !data.partnerCompany) {
const res = await inventoryApi.get(id)
data = res?.data ?? res
}
if (!data || !data.id) throw new Error('单据不存在')
if (seq !== loadSeq) return
row.value = data
await new Promise((r) => setTimeout(r, 50))
const proxy = instance?.proxy
const path = await makeQrTempFile({
text: data.id,
canvasId: 'poundQrCanvas',
componentInstance: proxy,
size: canvasSize
})
if (seq !== loadSeq) return
qrPath.value = path
} catch (e) {
if (seq !== loadSeq) return
uni.showToast({ title: e?.message || '加载二维码失败', icon: 'none' })
close()
} finally {
if (seq === loadSeq) loading.value = false
}
}
watch(
() => [props.show, props.inventoryId],
([show]) => {
if (show) load()
else reset()
}
)
</script>
<style scoped lang="scss">
.pound-qr-mask {
position: fixed;
inset: 0;
z-index: 1100;
background: rgba(0, 0, 0, 0.92);
display: flex;
align-items: center;
justify-content: center;
padding: 24px 16px;
box-sizing: border-box;
}
.pound-qr-panel {
width: 100%;
max-width: 360px;
max-height: 90vh;
overflow: auto;
background: #f5f7fa;
border-radius: 12px;
position: relative;
}
.pound-qr-panel__title {
text-align: center;
font-size: 17px;
font-weight: 700;
color: #1e293b;
padding: 14px 12px 6px;
}
.pound-qr-panel__loading {
text-align: center;
color: #9ca3af;
padding: 40px 0;
font-size: 14px;
}
.pound-qr-canvas {
position: fixed;
left: -9999px;
top: 0;
width: 200px;
height: 200px;
}
.pound-slip-capture-inline {
background: #f5f7fa;
padding: 4px 8px 12px;
margin: 0 6px 10px;
}
.capture-card {
background: #fff;
border-radius: 8px;
margin: 10px;
padding: 6px 8px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}
.capture-row {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 4px;
font-size: 13px;
}
.capture-row .label {
color: #1e293b;
min-width: 82px;
font-size: 12px;
font-weight: 400;
}
.capture-row .value {
color: #1e293b;
flex: 1;
font-size: 13px;
}
.capture-row-large .value {
font-size: 15px;
font-weight: 600;
}
.capture-row-plate {
width: 100%;
margin-bottom: 8px;
}
.vehicle-plate {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 10px 32px;
box-sizing: border-box;
background: #f5d000;
border: 3px solid #fff;
border-radius: 8px;
box-shadow: 0 0 0 2px #fff;
}
.vehicle-plate-text {
font-size: 24px;
font-weight: 700;
color: #000;
letter-spacing: 1px;
}
.vehicle-plate-dot {
position: absolute;
width: 8px;
height: 8px;
border-radius: 50%;
background: #fff;
}
.vehicle-plate-dot-lt {
left: 6px;
top: 8px;
}
.vehicle-plate-dot-lb {
left: 6px;
bottom: 8px;
}
.vehicle-plate-dot-rt {
right: 6px;
top: 8px;
}
.vehicle-plate-dot-rb {
right: 6px;
bottom: 8px;
}
.capture-qrcode {
text-align: center;
}
.capture-id {
font-size: 16px;
font-weight: 700;
color: #1e293b;
margin-bottom: 6px;
word-break: break-all;
padding: 0 4px;
}
.capture-qr-wrap {
padding: 8px 0;
min-height: 200px;
}
.capture-qr-img {
width: 200px;
height: 200px;
display: inline-block;
}
.capture-desc {
font-size: 11px;
font-weight: 500;
color: #64748b;
margin-top: 4px;
padding-bottom: 8px;
}
</style>