152 lines
7.5 KiB
Vue
152 lines
7.5 KiB
Vue
<template>
|
|
<view v-if="user" class="page-shell portal-page scanner-test-page">
|
|
<PortalHeader title="广播扫码测试" :user="user" />
|
|
<view class="scanner-test-content">
|
|
<view class="scanner-status" :class="`scanner-status-${status}`" role="status">
|
|
<view class="scanner-status-dot"></view>
|
|
<view>
|
|
<text class="scanner-status-title">{{ statusTitle }}</text>
|
|
<text class="scanner-status-detail">{{ statusDetail }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="scanner-result" :class="{ 'scanner-result-received': lastValue }">
|
|
<text class="scanner-result-label">最近收到</text>
|
|
<text class="scanner-result-value">{{ lastValue || '等待扫描' }}</text>
|
|
<text class="scanner-result-meta">{{ lastValue ? `${lastTime} · 本页第 ${scanCount} 次` : '按下 PDA 硬件扫描键' }}</text>
|
|
</view>
|
|
|
|
<view class="scanner-config">
|
|
<view class="scanner-config-row"><text class="scanner-config-label">Action</text><text class="scanner-config-value">{{ action }}</text></view>
|
|
<view class="scanner-config-row"><text class="scanner-config-label">Extra 标签</text><text class="scanner-config-value">{{ extra }}</text></view>
|
|
</view>
|
|
|
|
<view class="scanner-history-head">
|
|
<text class="scanner-history-title">接收记录</text>
|
|
<button class="scanner-clear" :disabled="!history.length" @tap="clearHistory">清空</button>
|
|
</view>
|
|
<view v-if="history.length" class="scanner-history">
|
|
<view v-for="item in history" :key="item.id" class="scanner-history-item">
|
|
<text class="scanner-history-index">{{ item.index }}</text>
|
|
<view class="scanner-history-main"><text class="scanner-history-value">{{ item.value }}</text><text class="scanner-history-time">{{ item.time }}</text></view>
|
|
</view>
|
|
</view>
|
|
<view v-else class="scanner-empty"><text>暂无广播数据</text></view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import PortalHeader from '@/components/PortalHeader.vue'
|
|
import { session, requireSession } from '@/stores/session.js'
|
|
import { SCAN_BROADCAST_ACTION, SCAN_BROADCAST_EXTRA, startScanBroadcast } from '@/utils/scan-broadcast.js'
|
|
|
|
export default {
|
|
components: { PortalHeader },
|
|
data() {
|
|
return {
|
|
user: session.currentUser,
|
|
action: SCAN_BROADCAST_ACTION,
|
|
extra: SCAN_BROADCAST_EXTRA,
|
|
status: 'waiting',
|
|
lastValue: '',
|
|
lastTime: '',
|
|
scanCount: 0,
|
|
history: []
|
|
}
|
|
},
|
|
computed: {
|
|
statusTitle() {
|
|
if (this.status === 'error') return '接收器启动失败'
|
|
if (this.status === 'unsupported') return '当前环境不支持广播'
|
|
return this.lastValue ? '已收到扫描广播' : '接收器已启动'
|
|
},
|
|
statusDetail() {
|
|
if (this.status === 'error') return '请检查 PDA 扫描服务设置后重新进入页面'
|
|
if (this.status === 'unsupported') return '请在 Android App 真机中测试'
|
|
return this.lastValue ? '继续扫描可验证连续接收' : '正在等待硬件扫描结果'
|
|
}
|
|
},
|
|
onShow() {
|
|
if (!requireSession()) return
|
|
this.user = session.currentUser
|
|
this.startScanner()
|
|
},
|
|
onHide() { this.stopScanner() },
|
|
onUnload() { this.stopScanner() },
|
|
beforeUnmount() { this.stopScanner() },
|
|
methods: {
|
|
startScanner() {
|
|
this.stopScanner()
|
|
this.status = 'waiting'
|
|
// #ifndef APP-PLUS
|
|
this.status = 'unsupported'
|
|
// #endif
|
|
this._stopScanner = startScanBroadcast({
|
|
onScan: (value) => this.recordScan(value),
|
|
onError: () => { this.status = 'error' }
|
|
})
|
|
},
|
|
stopScanner() {
|
|
if (typeof this._stopScanner !== 'function') return
|
|
this._stopScanner()
|
|
this._stopScanner = null
|
|
},
|
|
recordScan(value) {
|
|
const now = new Date()
|
|
const time = [now.getHours(), now.getMinutes(), now.getSeconds()].map((part) => String(part).padStart(2, '0')).join(':')
|
|
this.scanCount += 1
|
|
this.lastValue = value
|
|
this.lastTime = time
|
|
this.status = 'received'
|
|
this.history = [{ id: `${Date.now()}-${this.scanCount}`, index: this.scanCount, value, time }, ...this.history].slice(0, 20)
|
|
},
|
|
clearHistory() {
|
|
this.lastValue = ''
|
|
this.lastTime = ''
|
|
this.scanCount = 0
|
|
this.history = []
|
|
this.status = 'waiting'
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.scanner-test-content { padding: 16px 14px calc(24px + env(safe-area-inset-bottom)); }
|
|
.scanner-status { display: flex; align-items: center; min-height: 64px; padding: 12px 14px; border-radius: 8px; color: #20405f; background: #e7f1ff; }
|
|
.scanner-status-dot { width: 12px; height: 12px; margin-right: 12px; border-radius: 50%; background: #1769e8; }
|
|
.scanner-status-title, .scanner-status-detail, .scanner-result-label, .scanner-result-value, .scanner-result-meta, .scanner-config-label, .scanner-config-value, .scanner-history-title, .scanner-history-value, .scanner-history-time { display: block; }
|
|
.scanner-status-title { font-size: 15px; font-weight: 700; }
|
|
.scanner-status-detail { margin-top: 3px; font-size: 12px; line-height: 18px; }
|
|
.scanner-status-received { color: #145c38; background: #ddf5e8; }
|
|
.scanner-status-received .scanner-status-dot { background: #168552; }
|
|
.scanner-status-error { color: #912018; background: #fee7e5; }
|
|
.scanner-status-error .scanner-status-dot { background: #d92d20; }
|
|
.scanner-status-unsupported { color: #664d10; background: #fff1c7; }
|
|
.scanner-status-unsupported .scanner-status-dot { background: #b7791f; }
|
|
.scanner-result { min-height: 168px; margin-top: 14px; padding: 18px 16px; border: 2px dashed #aebdce; border-radius: 8px; background: #ffffff; }
|
|
.scanner-result-received { border-style: solid; border-color: #168552; }
|
|
.scanner-result-label { color: #63758a; font-size: 12px; font-weight: 700; }
|
|
.scanner-result-value { margin-top: 26px; color: #27384d; font-size: 24px; font-weight: 800; line-height: 32px; overflow-wrap: anywhere; text-align: center; }
|
|
.scanner-result-received .scanner-result-value { color: #11643c; }
|
|
.scanner-result-meta { margin-top: 15px; color: #63758a; font-size: 12px; text-align: center; }
|
|
.scanner-config { margin-top: 14px; border-radius: 8px; background: #ffffff; }
|
|
.scanner-config-row { padding: 13px 14px; border-bottom: 1px solid #e4e9ef; }
|
|
.scanner-config-row:last-child { border-bottom: 0; }
|
|
.scanner-config-label { margin-bottom: 5px; color: #63758a; font-size: 11px; font-weight: 700; }
|
|
.scanner-config-value { color: #27384d; font-size: 13px; line-height: 19px; overflow-wrap: anywhere; }
|
|
.scanner-history-head { display: flex; align-items: center; justify-content: space-between; margin-top: 22px; }
|
|
.scanner-history-title { font-size: 16px; font-weight: 800; }
|
|
.scanner-clear { width: 64px; height: 48px; margin: 0; padding: 0; color: #1769e8; font-size: 13px; line-height: 48px; background: transparent; }
|
|
.scanner-clear[disabled] { color: #9ba8b7; }
|
|
.scanner-history { margin-top: 8px; border-radius: 8px; background: #ffffff; }
|
|
.scanner-history-item { display: flex; align-items: center; min-height: 62px; padding: 9px 13px; border-bottom: 1px solid #e4e9ef; }
|
|
.scanner-history-item:last-child { border-bottom: 0; }
|
|
.scanner-history-index { display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; margin-right: 11px; border-radius: 50%; color: #ffffff; font-size: 12px; font-weight: 700; background: #1769e8; }
|
|
.scanner-history-main { min-width: 0; flex: 1; }
|
|
.scanner-history-value { color: #27384d; font-size: 15px; font-weight: 700; overflow-wrap: anywhere; }
|
|
.scanner-history-time { margin-top: 3px; color: #718095; font-size: 11px; }
|
|
.scanner-empty { display: flex; align-items: center; justify-content: center; height: 96px; margin-top: 8px; border-radius: 8px; color: #718095; font-size: 13px; background: #ffffff; }
|
|
</style>
|