This commit is contained in:
@@ -18,7 +18,8 @@
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {
|
||||
"Barcode" : {}
|
||||
"Barcode" : {},
|
||||
"Camera" : {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
|
||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"clipboard": "^2.0.11",
|
||||
"dayjs": "^1.11.19",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"jsqr": "^1.4.0",
|
||||
"uview-plus": "^3.6.29",
|
||||
"vue": "^3.4.0"
|
||||
},
|
||||
@@ -5103,6 +5104,12 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsqr": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/jsqr/-/jsqr-1.4.0.tgz",
|
||||
"integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/lcid": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/lcid/-/lcid-3.1.1.tgz",
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
"@dcloudio/uni-app": "3.0.0-4080720251210001",
|
||||
"@dcloudio/uni-components": "3.0.0-4080720251210001",
|
||||
"@dcloudio/uni-h5": "3.0.0-4080720251210001",
|
||||
"vue": "^3.4.0",
|
||||
"clipboard": "^2.0.11",
|
||||
"dayjs": "^1.11.19",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"uview-plus": "^3.6.29"
|
||||
"jsqr": "^1.4.0",
|
||||
"uview-plus": "^3.6.29",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,25 +62,32 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="showScanner" class="scanner-overlay">
|
||||
<view class="scanner-container">
|
||||
<view class="scanner-header">
|
||||
<text>扫一扫</text>
|
||||
<text class="close-btn" @tap="closeScanner">×</text>
|
||||
<view v-if="showScanner" class="scanner-overlay">
|
||||
<view class="scanner-container">
|
||||
<view class="scanner-header">
|
||||
<text>扫一扫</text>
|
||||
<text class="close-btn" @tap="closeScanner">×</text>
|
||||
</view>
|
||||
<view class="scanner-body">
|
||||
<input type="file" accept="image/*" capture="environment" @change="onFileSelected" class="file-input" id="file-input" />
|
||||
<view class="scan-prompt">
|
||||
<image src="/static/scan-code.png" mode="aspectFit" class="scan-icon-large"></image>
|
||||
<text class="tip">点击下方按钮选择相机拍照</text>
|
||||
<label for="file-input" class="btn-take-photo">拍照/选择图片</label>
|
||||
</view>
|
||||
</view>
|
||||
<view class="scanner-tip">将二维码放入框内即可自动扫描</view>
|
||||
</view>
|
||||
<view id="scanner-region" class="scanner-region"></view>
|
||||
<view class="scanner-tip">将二维码放入框内即可自动扫描</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { authApi } from '@/api/index.js';
|
||||
import { useUserStore } from '@/store/index.js';
|
||||
import { APP_ID, USE_WECHAT_AUTH } from '@/utils/env.js';
|
||||
import { Html5Qrcode } from 'html5-qrcode';
|
||||
import jsQR from 'jsqr';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -93,19 +100,12 @@
|
||||
getPathDeviceId();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (html5QrCode) {
|
||||
html5QrCode.stop().catch(() => {});
|
||||
}
|
||||
});
|
||||
|
||||
const identifier = ref('');
|
||||
const loading = ref(false);
|
||||
const agreed = ref(true);
|
||||
const inputFocus = ref(false);
|
||||
const showError = ref(false);
|
||||
const showScanner = ref(false);
|
||||
let html5QrCode = null;
|
||||
|
||||
const getCode = () => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
@@ -147,17 +147,26 @@
|
||||
|
||||
const handleScanLogin = async () => {
|
||||
showScanner.value = true;
|
||||
};
|
||||
|
||||
try {
|
||||
html5QrCode = new Html5Qrcode('scanner-region');
|
||||
await html5QrCode.start(
|
||||
{ facingMode: 'environment' },
|
||||
{
|
||||
fps: 10,
|
||||
qrbox: { width: 250, height: 250 }
|
||||
},
|
||||
(decodedText) => {
|
||||
const match = decodedText.match(/=([^=]+)$/);
|
||||
const onFileSelected = async (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
const code = jsQR(imageData.data, imageData.width, imageData.height);
|
||||
|
||||
if (code) {
|
||||
const match = code.data.match(/=([^=]+)$/);
|
||||
if (match && match[1]) {
|
||||
identifier.value = match[1];
|
||||
closeScanner();
|
||||
@@ -165,24 +174,18 @@
|
||||
} else {
|
||||
uni.showToast({ title: '无效的二维码', icon: 'none' });
|
||||
}
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('扫码失败', err);
|
||||
uni.showToast({ title: '无法访问摄像头', icon: 'none' });
|
||||
closeScanner();
|
||||
}
|
||||
} else {
|
||||
uni.showToast({ title: '无法识别二维码', icon: 'none' });
|
||||
}
|
||||
};
|
||||
img.src = event.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
const closeScanner = async () => {
|
||||
showScanner.value = false;
|
||||
if (html5QrCode) {
|
||||
try {
|
||||
await html5QrCode.stop();
|
||||
} catch (e) {}
|
||||
html5QrCode = null;
|
||||
}
|
||||
document.getElementById('file-input').value = '';
|
||||
};
|
||||
|
||||
const getPathDeviceId = () => {
|
||||
@@ -546,4 +549,43 @@
|
||||
font-size: 26rpx;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.scanner-body {
|
||||
padding: 60rpx 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scan-prompt {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.scan-icon-large {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.btn-take-photo {
|
||||
padding: 24rpx 48rpx;
|
||||
background: var(--primary);
|
||||
color: var(--text-inverse);
|
||||
border-radius: var(--radius-medium);
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user