此方法可以在PC端调试,但是需要设置https:true (vue.config.js中)
但是vue-qrcode-reader只可以支持二维码扫描,对于条形码没有反应,应该是不支持,从实际扫描效果来看确实如此。
<template>
<div>
<p class="error">{{ error }}</p>
<!--错误信息-->
<van-cell-group inset>
<van-cell
v-if='error.length > 0'
center
title="错误信息"
value-class="error-style"
:value="error">
</van-cell>
<van-cell
v-if="!isDingDing"
center
title="扫码打卡-开启摄像头">
<template #default>
<van-switch v-model="openCamera"></van-switch>
</template>
</van-cell>
<van-cell
v-if="openCamera"
center
title="翻转摄像头">
<template #default>
<van-switch v-model="camera" active-value="front" inactive-value="rear" inactive-color="green"/>
</template>
</van-cell>
<van-cell title="查看打卡记录" is-link to="/clockInfo" />
</van-cell-group>
<p class="decode-result">
扫描结果:
<b>{{ result }}</b>
</p>
<!-- <p class="decode-result">-->
<!-- 扫描结果:-->
<!-- <b>{{ result }}</b>-->
<!-- </p>-->
<!--扫描结果-->
<van-divider></van-divider>
<qrcode-stream @decode="onDecode" @init="onInit" style="height: 300px;width: 300px;">
<div>
<div class="qr-scanner">
<div class="box">
<div class="line"></div>
<div class="angle"></div>
</div>
</div>
</div>
</qrcode-stream>
<van-cell-group inset>
<van-field
v-if="result.length>0"
v-model="result"
rows="1"
autosize
label="扫码结果"
type="textarea"
readonly
placeholder="扫码结果"
/>
</van-cell-group>
<div style="height: 300px;width: 300px;margin: auto;padding-top: 20px">
<qrcode-stream v-if="!isDingDing && openCamera" :camera="camera" @decode="onDecode" @init="onInit">
<div>
<div class="qr-scanner">
<div class="box">
<div class="line"></div>
<div class="angle"></div>
</div>
</div>
</div>
</qrcode-stream>
</div>
</div>
</template>
<script>
import { QrcodeStream } from 'vue-qrcode-reader'
import {toOrOffCheck} from '@/api/employeeAttend'
import bus from '@/utils/bus'
export default {
name: "clockIn",
// 要注册的组件
components: {
QrcodeStream
},
// 父传子 数据传递
props: {},
// 定义属性
data() {
return {
userLoginInfo: {},
camera: 'rear',
isDingDing: false,
openCamera: false,
result: '', // 扫码结果信息
error: '' // 错误信息
}
},
// 计算属性,类似于过滤器,对绑定到view的数据进行处理
computed: {},
// 监听数据
watch: {},
// 在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图
created() {
this.userLoginInfo = this.$ls.get('userLoginInfo')
try {
dd.postMessage({ active: 'scan' })
this.isDingDing = true
}catch (error){
this.isDingDing = false
console.log('非钉钉环境,模拟用户')
}
bus.$on('getDingDingScan',(msg) => {this.dingDingScan(msg)});
},
// 每次进入页面后调用
activated() {
},
// 在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
mounted() {
// 仅在渲染整个视图之后运行的代码
// this.$/nextTick(function () {})
},
// 定义函数
methods: {
onDecode(result) {
alert(result)
this.result = result
this.$notify({ type: 'success', message: '扫码成功' })
this.openCamera = false
},
async onInit(promise) {
try {
await promise
} catch (error) {
if (error.name === 'NotAllowedError') {
this.error = 'ERROR: 您需要授予相机访问权限'
} else if (error.name === 'NotFoundError') {
this.error = 'ERROR: 这个设备上没有摄像头'
} else if (error.name === 'NotSupportedError') {
this.error = 'ERROR: 所需的安全上下文(HTTPS、本地主机)'
} else if (error.name === 'NotReadableError') {
this.error = 'ERROR: 相机被占用'
} else if (error.name === 'OverconstrainedError') {
this.error = 'ERROR: 安装摄像头不合适'
} else if (error.name === 'StreamApiNotSupportedError') {
this.error = 'ERROR: 此浏览器不支持流API'
}
}
},
dingDingScan(data){
console.log('1111111111111')
console.log(data)
if (!data || data===''){return}
const that = this
const scanObj = JSON.parse(data)
this.result = data
switch (scanObj.operation){
case 'clock':{
toOrOffCheck(null, Object.assign(scanObj.data, {employeeId: that.userLoginInfo.employeeId})).then(res => {
that.$notify({ type: 'success', message: '打卡成功' })
})
break;
}
}
}
}
}
</script>
<style scoped>
.error-style{
color: red;
}
.scan{
border-color: #585858;
position: fixed;
top: 0;
left: 0;
}
.qrcode-stream-camera{
width: 100%;
height: 100%;
display: block;
-o-object-fit: cover;
object-fit: cover;
position: absolute;
top: 0%;
left: 0%;
}
.qr-scanner {
background-image:
linear-gradient(0deg,
transparent 24%,
rgba(32, 255, 77, 0.1) 25%,
rgba(32, 255, 77, 0.1) 26%,
transparent 27%,
transparent 74%,
rgba(32, 255, 77, 0.1) 75%,
rgba(32, 255, 77, 0.1) 76%,
transparent 77%,
transparent),
linear-gradient(90deg,
transparent 24%,
rgba(32, 255, 77, 0.1) 25%,
rgba(32, 255, 77, 0.1) 26%,
transparent 27%,
transparent 74%,
rgba(32, 255, 77, 0.1) 75%,
rgba(32, 255, 77, 0.1) 76%,
transparent 77%,
transparent);
background-size: 3rem 3rem;
background-position: -1rem -1rem;
width: 100%;
/* height: 100%; */
/*height: 100vh;*/
/*position: relative;*/
background-color: #1110;
/* background-color: #111; */
}
.qr-scanner .box {
width: 213px;
height: 213px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
border: 0.1rem solid rgba(0, 255, 51, 0.2);
/* background: url('http://resource.beige.world/imgs/gongconghao.png') no-repeat center center; */
}
.qr-scanner .line {
height: calc(100% - 2px);
width: 100%;
background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
border-bottom: 3px solid #00ff33;
transform: translateY(-100%);
animation: radar-beam 2s infinite alternate;
animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
animation-delay: 1.4s;
}
.qr-scanner .box:after,
.qr-scanner .box:before,
.qr-scanner .angle:after,
.qr-scanner .angle:before {
content: '';
display: block;
position: absolute;
width: 3vw;
height: 3vw;
border: 0.2rem solid transparent;
}
.qr-scanner .box:after,
.qr-scanner .box:before {
top: 0;
border-top-color: #00ff33;
}
.qr-scanner .angle:after,
.qr-scanner .angle:before {
bottom: 0;
border-bottom-color: #00ff33;
}
.qr-scanner .box:before,
.qr-scanner .angle:before {
left: 0;
border-left-color: #00ff33;
}
.qr-scanner .box:after,
.qr-scanner .angle:after {
right: 0;
border-right-color: #00ff33;
}
@keyframes radar-beam {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0);
}
}
</style>