SmartParks_uniapp/pages/sys/home/scan.vue
2025-08-19 14:35:12 +08:00

504 lines
10 KiB
Vue
Raw Permalink 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 class="scan-container">
<view class="scan-header">
<view class="back-btn" @click="goBack">
<u-icon name="arrow-left" color="#fff" size="20"></u-icon>
</view>
<text class="scan-title">扫码</text>
</view>
<!-- 扫码区域 -->
<view class="scan-content">
<view class="scan-area">
<!-- #ifdef APP-PLUS -->
<view class="scanner" id="scannerId"></view>
<!-- #endif -->
<!-- H5和小程序平台使用通用提示 -->
<!-- #ifndef APP-PLUS -->
<view class="scan-placeholder">
<text class="placeholder-text">点击下方按钮开始扫码</text>
</view>
<!-- #endif -->
<view class="scan-frame">
<view class="corner top-left"></view>
<view class="corner top-right"></view>
<view class="corner bottom-left"></view>
<view class="corner bottom-right"></view>
</view>
</view>
<text class="scan-tip">将二维码/条码放入框内即可自动扫描</text>
</view>
<view class="scan-footer">
<view class="album-btn" @click="selectFromAlbum">
<u-icon name="photo" color="#fff" size="24"></u-icon>
<text class="btn-text">相册</text>
</view>
<view class="scan-btn" @click="startScanCode">
<u-icon name="scan" color="#fff" size="24"></u-icon>
<text class="btn-text">扫码</text>
</view>
<view class="flashlight-btn" @click="toggleFlashlight">
<u-icon :name="flashlightOn ? 'light-fill' : 'light'" color="#fff" size="24"></u-icon>
<text class="btn-text">{{ flashlightOn ? '关闭' : '开启' }}手电筒</text>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'Scan',
data() {
return {
flashlightOn: false,
barcodeObj: null
}
},
methods: {
goBack() {
// 关闭手电筒
if (this.flashlightOn) {
// #ifdef APP-PLUS
plus.device.flashlight(false)
// #endif
}
uni.navigateBack()
},
// 从相册选择二维码
selectFromAlbum() {
// #ifdef APP-PLUS
plus.gallery.pick((e) => {
this.scanImage(e.files[0])
}, (e) => {
console.log('取消选择图片')
}, {
filter: 'none',
multiple: false,
maximum: 1,
system: false
})
// #endif
// H5和小程序平台使用uni.chooseImage
// #ifndef APP-PLUS
uni.chooseImage({
count: 1,
success: (res) => {
// 在H5和小程序平台相册选择后无法直接识别二维码
uni.showToast({
title: '请选择扫码功能直接扫描二维码',
icon: 'none'
})
}
})
// #endif
},
// 扫描图片中的二维码 (仅App)
scanImage(path) {
// #ifdef APP-PLUS
plus.barcode.scan(path, (type, code) => {
this.handleScanResult(type, code)
}, (error) => {
uni.showToast({
title: '未识别到二维码',
icon: 'none'
})
})
// #endif
},
// 打开/关闭手电筒 (仅App)
toggleFlashlight() {
// #ifdef APP-PLUS
this.flashlightOn = !this.flashlightOn
plus.device.flashlight(this.flashlightOn)
// #endif
// #ifndef APP-PLUS
uni.showToast({
title: '该功能仅在App中可用',
icon: 'none'
})
// #endif
},
// 处理扫码结果
handleScanResult(type, code) {
uni.showModal({
title: '扫码结果',
content: code,
showCancel: true,
confirmText: '确定',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
console.log('用户点击确定')
// 可以在这里处理扫码结果,比如跳转页面
// uni.redirectTo({
// url: '/pages/somepage?code=' + code
// })
} else if (res.cancel) {
// 用户取消,继续扫码
// #ifdef APP-PLUS
this.startScan()
// #endif
}
}
})
},
// 开始扫码 (仅App)
startScan() {
// #ifdef APP-PLUS
if (this.barcodeObj) {
this.barcodeObj.start()
}
// #endif
},
// 停止扫码 (仅App)
stopScan() {
// #ifdef APP-PLUS
if (this.barcodeObj) {
this.barcodeObj.cancel()
}
// #endif
},
// 使用uni.scanCode进行扫码 (H5和小程序平台)
startScanCode() {
// #ifndef APP-PLUS
uni.scanCode({
success: (res) => {
this.handleScanResult(res.scanType, res.result)
},
fail: (err) => {
console.log('扫码失败', err)
uni.showToast({
title: '扫码失败,请重试',
icon: 'none'
})
}
})
// #endif
// #ifdef APP-PLUS
// App平台仍然使用原生扫码
this.startScan()
// #endif
},
// 初始化扫码功能 (仅App)
initScanner() {
// #ifdef APP-PLUS
const scanner = plus.barcode.Barcode
this.barcodeObj = new scanner('scannerId',
[scanner.QR, scanner.EAN13, scanner.EAN8, scanner.CODE128],
{
top: '0px',
left: '0px',
width: '100%',
height: '100%',
position: 'static'
}
)
// 设置扫码成功回调
this.barcodeObj.onmarked = (type, result) => {
let code = result
switch(type) {
case scanner.QR:
type = 'QR'
break
case scanner.EAN13:
type = 'EAN13'
break
case scanner.EAN8:
type = 'EAN8'
break
case scanner.CODE128:
type = 'CODE128'
break
default:
type = '其他'
break
}
this.handleScanResult(type, code)
}
// 开始扫码
this.barcodeObj.start()
// #endif
},
// 检查并请求摄像头权限 (仅App)
checkPermission() {
// #ifdef APP-PLUS
return new Promise((resolve, reject) => {
// 判断是否已经授权
plus.android.requestPermissions(['android.permission.CAMERA'],
(resultObj) => {
let result = 0;
for (var i = 0; i < resultObj.granted.length; i++) {
if (resultObj.granted[i] === 'android.permission.CAMERA') {
result = 1
}
}
for (var i = 0; i < resultObj.denied.length; i++) {
if (resultObj.denied[i] === 'android.permission.CAMERA') {
result = 0
}
}
for (var i = 0; i < resultObj.alwaysDenied.length; i++) {
if (resultObj.alwaysDenied[i] === 'android.permission.CAMERA') {
result = -1
}
}
if (result == 1) {
resolve(true)
} else {
resolve(false)
}
},
(error) => {
resolve(false)
}
);
})
// #endif
// #ifndef APP-PLUS
return Promise.resolve(true)
// #endif
}
},
onLoad() {
// #ifdef APP-PLUS
// 页面加载时检查权限并初始化扫码功能
this.checkPermission().then((authorized) => {
if (authorized) {
this.$nextTick(() => {
// 使用定时器确保DOM渲染完成后再初始化扫码组件
setTimeout(() => {
this.initScanner()
}, 100)
})
} else {
uni.showModal({
title: '权限申请',
content: '需要摄像头权限才能使用扫码功能,是否前往设置开启权限?',
success: (res) => {
if (res.confirm) {
// 跳转到系统设置页面
if (plus.os.name === 'Android') {
var Intent = plus.android.importClass("android.content.Intent");
var Settings = plus.android.importClass("android.provider.Settings");
var main = plus.android.runtimeMainActivity();
var intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
var uri = plus.android.invoke("android.net.Uri", "fromParts", "package", main.getPackageName(), null);
intent.setData(uri);
main.startActivity(intent);
} else {
plus.runtime.openURL("app-settings://");
}
} else {
uni.navigateBack()
}
}
})
}
})
// #endif
},
onUnload() {
// 页面卸载时关闭扫码和手电筒
this.stopScan()
if (this.flashlightOn) {
// #ifdef APP-PLUS
plus.device.flashlight(false)
// #endif
}
},
onHide() {
// 页面隐藏时停止扫码
this.stopScan()
},
onShow() {
// 页面显示时重新开始扫码
// #ifdef APP-PLUS
this.$nextTick(() => {
setTimeout(() => {
this.startScan()
}, 100)
})
// #endif
}
}
</script>
<style scoped>
.scan-container {
width: 100%;
height: 100vh;
background: #000;
position: relative;
}
.scan-header {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 80rpx;
padding: 60rpx 30rpx 30rpx;
display: flex;
align-items: center;
z-index: 100;
}
.back-btn {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}
.scan-title {
flex: 1;
text-align: center;
color: #fff;
font-size: 36rpx;
margin-right: 60rpx;
}
.scan-content {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 120rpx;
box-sizing: border-box;
}
.scan-area {
width: 480rpx;
height: 480rpx;
position: relative;
overflow: hidden;
}
/* #ifdef APP-PLUS */
.scanner {
width: 480rpx;
height: 480rpx;
position: absolute;
top: 0;
left: 0;
z-index: 10;
background: transparent;
}
/* #endif */
.scan-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #333;
}
.placeholder-text {
color: #fff;
font-size: 28rpx;
text-align: center;
}
.scan-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 20;
}
.corner {
position: absolute;
width: 40rpx;
height: 40rpx;
border: 4rpx solid #00ff00;
}
.top-left {
top: 0;
left: 0;
border-right: none;
border-bottom: none;
}
.top-right {
top: 0;
right: 0;
border-left: none;
border-bottom: none;
}
.bottom-left {
bottom: 0;
left: 0;
border-right: none;
border-top: none;
}
.bottom-right {
bottom: 0;
right: 0;
border-left: none;
border-top: none;
}
.scan-tip {
color: #fff;
font-size: 28rpx;
margin-top: 60rpx;
}
.scan-footer {
position: absolute;
bottom: 100rpx;
left: 0;
width: 100%;
display: flex;
justify-content: space-around;
z-index: 100;
}
.album-btn, .flashlight-btn, .scan-btn {
display: flex;
flex-direction: column;
align-items: center;
color: #fff;
}
.btn-text {
margin-top: 10rpx;
font-size: 24rpx;
color: #fff;
}
</style>