| | |
| | | <cover-view class="frame-corner corner-tl"></cover-view><cover-view class="frame-corner corner-tr"></cover-view><cover-view class="frame-corner corner-bl"></cover-view><cover-view class="frame-corner corner-br"></cover-view> |
| | | </cover-view> |
| | | <cover-view v-if="scanState == 'scanning'" class="scan-tip">将取景框对准二维码,即可自动扫描</cover-view> |
| | | <!-- 相机不好用或屏幕反光时的兜底:顾客屏幕上的 6 位数字码可以手输。 --> |
| | | <cover-view v-if="scanState == 'scanning'" class="manual-entry" @tap.stop="openManualEntry">手输 6 位核销码</cover-view> |
| | | |
| | | <cover-view v-if="scanState != 'scanning'" class="status-panel"> |
| | | <cover-view v-if="scanState == 'verifying'" class="loading-spinner"></cover-view> |
| | |
| | | let openedManualConsumption = false |
| | | let openedConfirmation = false |
| | | let openedVerificationFailure = false |
| | | let openedManualEntry = false |
| | | let cancelVerificationRequest: (() => void) | null = null |
| | | |
| | | const cancelPendingRequest = () => { |
| | |
| | | }) |
| | | } |
| | | |
| | | // 手输 6 位数字码:扫码机上放不下普通 view(会被原生相机压住),所以入口做成 cover-view, |
| | | // 输入本身放到一个独立页面里(cover-view 里不能放 input)。 |
| | | const openManualEntry = () => { |
| | | openedManualEntry = true |
| | | uni.navigateTo({ |
| | | url: '/pages/verification-code-input/verification-code-input', |
| | | fail: () => { openedManualEntry = false } |
| | | }) |
| | | } |
| | | |
| | | onUnload(() => { |
| | | cancelPendingRequest() |
| | | lastScanResult = '' |
| | | }) |
| | | |
| | | onShow(() => { |
| | | if (!openedManualConsumption && !openedConfirmation && !openedVerificationFailure) return |
| | | if (!openedManualConsumption && !openedConfirmation && !openedVerificationFailure && !openedManualEntry) return |
| | | openedManualConsumption = false |
| | | openedConfirmation = false |
| | | openedVerificationFailure = false |
| | | openedManualEntry = false |
| | | resetScanning() |
| | | }) |
| | | </script> |
| | |
| | | .corner-br { right: 0; bottom: 0; border-right-width: 7rpx; border-bottom-width: 7rpx; } |
| | | .scan-line { width: 100%; height: 3rpx; position: absolute; top: 0; left: 0; background-color: rgba(133, 255, 192, 0.9); box-shadow: 0 0 15rpx rgba(111, 241, 170, 0.8); animation: scan-line-move 1800ms ease-in-out infinite alternate; } |
| | | .scan-tip { width: 100%; position: absolute; top: 975rpx; left: 0; z-index: 10; color: #FFFFFF; font-size: 27rpx; line-height: 38rpx; text-align: center; } |
| | | .manual-entry { display: flex; width: 320rpx; height: 76rpx; position: absolute; top: 1060rpx; left: 215rpx; z-index: 10; justify-content: center; align-items: center; border-width: 2rpx; border-style: solid; border-color: rgba(255, 255, 255, 0.65); border-radius: 38rpx; color: #FFFFFF; font-size: 27rpx; line-height: 38rpx; } |
| | | .status-panel { display: none; } |
| | | .loading-spinner { width: 58rpx; height: 58rpx; border-width: 6rpx; border-style: solid; border-color: #FFD5BF; border-top-color: #FF6B2C; border-radius: 50%; animation: loading-rotate 800ms linear infinite; } |
| | | .status-mark { display: flex; width: 64rpx; height: 64rpx; justify-content: center; align-items: center; border-radius: 32rpx; color: #FFFFFF; font-size: 38rpx; line-height: 64rpx; font-weight: 700; text-align: center; } |