feat(miniprogram): add centered pound QR popup component.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
35563e9709
commit
be0764779c
1 file changed
+285
@@ -0,0 +1,285 @@
|
||||
<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('')
|
||||
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() {
|
||||
row.value = null
|
||||
qrPath.value = ''
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function load() {
|
||||
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('单据不存在')
|
||||
row.value = data
|
||||
await new Promise((r) => setTimeout(r, 50))
|
||||
const proxy = instance?.proxy
|
||||
qrPath.value = await makeQrTempFile({
|
||||
text: data.id,
|
||||
canvasId: 'poundQrCanvas',
|
||||
componentInstance: proxy,
|
||||
size: canvasSize
|
||||
})
|
||||
} catch (e) {
|
||||
uni.showToast({ title: e?.message || '加载二维码失败', icon: 'none' })
|
||||
close()
|
||||
} finally {
|
||||
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>
|
||||
Reference in new issue
Block a user