[scode type="yellow"]公网或者内网ip使用需要配置ssl证书,否则无法调用摄像头获取视频流~[/scode]
[post url="https://www.hblyan.com/test/index.html" title="物料扫描统计" intro="用于测试扫码,预览请点击这里~" /]
[album]
[/album]
废话不多说直接上代码 = =
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="yhf" content="ZXing for JS">
<title>物料扫码识别</title>
<link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
<link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
href="https://unpkg.com/normalize.css@8.0.0/normalize.css">
<link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
href="https://unpkg.com/milligram@1.3.0/dist/milligram.min.css">
<!-- 引入 layui.css -->
<link rel="stylesheet" href="//unpkg.com/layui@2.6.8/dist/css/layui.css">
<style>
#show {
position: fixed;
width: 100%;
height: 100vh;
align-items: center;
justify-content: center;
background-color: #fff;
text-align: center;
top: -2000px;
left: 0;
}
li {
display: flex;
padding: 5px 10px;
align-items: center;
justify-content: space-between;
}
.btns {
padding: 20px 0;
position: fixed;
bottom: 0;
display: flex;
justify-content: space-around;
box-shadow: 0px 0px 5px 0px #efefef;
width: 100%;
background-color: #fff;
}
#cancel {
padding: 20px 0;
position: fixed;
bottom: 0;
display: none;
justify-content: space-around;
box-shadow: 0px 0px 5px 0px #efefef;
width: 100%;
background-color: #fff;
z-index: 9999;
}
#sourceSelectPanel {
position: fixed;
left: 3000px;
}
.layui-input {
display: inline-block;
width: 40px !important;
}
video {
width: 100%;
height: 100%;
margin-top: -100px;
}
.layui-table-cell {
padding: 0px 5px;
}
.layui-table-view{
margin-bottom: 100px;
}
</style>
</head>
<body>
<main class="wrapper" style="padding-top:2em">
<section class="container" id="demo-content">
<div class="layui-card">
<div class="layui-card-header">
<h3>基本信息</h1>
</div>
<div class="layui-card-body" id="baseInfo">
<label>料号:</label>
<label>名称:</label>
<label>批次号:</label>
</div>
</div>
<ul id="list">
</ul>
<table class="layui-hide" id="test"></table>
<div id="show">
<!-- </div> -->
<video id="video" width="300" height="200"></video>
</div>
<div id="sourceSelectPanel" style="display:none">
<label for="sourceSelect">Change video source:</label>
<select id="sourceSelect" style="max-width:400px">
</select>
</div>
<!-- <div style="display: table">
<label for="decoding-style"> Decoding Style:</label>
<select id="decoding-style" size="1">
<option value="continuously">Decode continuously</option>
<option value="once">Decode once</option>
</select>
</div>
<label>Result:</label>
<pre><code id="result"></code></pre> -->
</section>
<div class="btns" id="btns">
<button type="button" onClick="start(true)" class="layui-btn layui-btn-sm" id="startButton">散热器扫描</button>
<button type="button" onClick="start(false)" class="layui-btn layui-btn-sm">配件扫描</button>
<button type="button" onclick="submit()" class="layui-btn layui-btn-sm">提交</button>
</div>
<div id="cancel">
<button type="button" class="layui-btn layui-btn-sm" id="resetButton">取消扫描</button>
</div>
</main>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-xs" lay-event="del">减</a>
<!-- <input id={{d.value}} type="number" name={{d.value}} autocomplete='off' value={{d.count}} lay-event='tabInput' class="layui-input"> -->
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="add">加</a>
</script>
<!-- 引入 layui.js -->
<script src="https://unpkg.com/layui@2.8.0-rc.2/dist/layui.js"></script>
<script type="text/javascript" src="https://unpkg.com/@zxing/library@latest"></script>
<script type="text/javascript">
//列表数据
let list = [
]
//基本信息
let baseInfo = {}
//实例化BrowserQRCodeReader
const codeReader = new ZXing.BrowserQRCodeReader()
//扫码类型
let type = true
//初始化 开始扫码事件
let start = null;
//单次识别 回调结果 二维码信息
function decodeOnce(codeReader, selectedDeviceId) {
codeReader.decodeFromInputVideoDevice(selectedDeviceId, 'video').then((result) => {
console.log('Found QR code!', result.text)
//根据返回的result 编写 业务逻辑
if (type) {
if (result.text.includes('Supplier Code')) {
renderBaseInfo(result.text)
closeCamera()
}
} else {
if (result.text.includes('code')) {
handleList(result.text)
closeCamera()
}
}
}).catch((err) => {
console.error(err)
document.getElementById('result').textContent = err
})
}
//持续识别 回调结果 二维码信息
function decodeContinuously(codeReader, selectedDeviceId) {
codeReader.decodeFromInputVideoDeviceContinuously(selectedDeviceId, 'video', (result, err) => {
if (result) {
console.log('Found QR code!', result.text)
//根据返回的result 编写 业务逻辑
if (type) {
if (result.text.includes('Supplier Code')) {
renderBaseInfo(result.text)
closeCamera()
}
} else {
if (result.text.includes('code')) {
handleList(result.text)
closeCamera()
}
}
}
if (err) {
// As long as this error belongs into one of the following categories
// the code reader is going to continue as excepted. Any other error
// will stop the decoding loop.
//
// Excepted Exceptions:
//
// - NotFoundException
// - ChecksumException
// - FormatException
if (err instanceof ZXing.NotFoundException) {
console.log('No QR code found.')
}
if (err instanceof ZXing.ChecksumException) {
console.log('A code was found, but it\'s read value was not valid.')
}
if (err instanceof ZXing.FormatException) {
console.log('A code was found, but it was in a invalid format.')
}
}
})
}
//关闭摄像头 并移除摄像头显示
function closeCamera() {
codeReader.reset()
document.getElementById('show').style.top = '-2000px'
document.getElementById('cancel').style = 'none'
}
window.addEventListener('load', function () {
//初始化 列表demo数据
renderList()
let selectedDeviceId;
console.log('ZXing code reader initialized')
//获取视频流 异步
codeReader.getVideoInputDevices()
.then((videoInputDevices) => {
//选择摄像头设备来源
const sourceSelect = document.getElementById('sourceSelect')
selectedDeviceId = videoInputDevices[0].deviceId
if (videoInputDevices.length >= 1) {
videoInputDevices.forEach((element) => {
const sourceOption = document.createElement('option')
sourceOption.text = element.label
sourceOption.value = element.deviceId
sourceSelect.appendChild(sourceOption)
})
sourceSelect.onchange = () => {
selectedDeviceId = sourceSelect.value;
};
const sourceSelectPanel = document.getElementById('sourceSelectPanel')
sourceSelectPanel.style.display = 'block'
}
// 开始扫描二维码
start = function (data) {
type = data
document.getElementById('show').style.top = '0'
document.getElementById('cancel').style.display = 'flex'
//这里其实是配置项 被强制去除了 默认是连续识别二维码,上述html中decoding-style 可以取消注释获取 识别类型方式
const decodingStyle = null;
if (decodingStyle == "once") {
decodeOnce(codeReader, selectedDeviceId);
} else {
decodeContinuously(codeReader, selectedDeviceId);
}
console.log(`Started decode from camera with id ${selectedDeviceId}`)
}
//取消扫描界面并关闭摄像头
document.getElementById('resetButton').addEventListener('click', () => {
closeCamera()
})
})
.catch((err) => {
console.error(err)
})
})
//根据list 渲染列表
function renderList() {
console.log(list);
//layUI 的列表 可以使用其他ui组件 原理相同
layui.use('table', function () {
var table = layui.table;
table.render({
elem: '#test'
, data: list
, cellMinWidth: 80,
limit: 1000
, cols: [[
{ field: 'value', title: '料号', width: 100 },
{ field: 'name', title: '名称' },
{ field: 'count', title: '数量', with: 50, edit: 'number' },
{ field: 'options', title: '操作', toolbar: '#barDemo' }
]]
});
//监听行工具事件
table.on('tool(test)', function (obj) {
let data = obj.data;
let index = obj.tr.attr("data-index")
//console.log(obj)
if (obj.event === 'add') {
console.log(data);
list[index].count++
} else if (obj.event === 'del') {
console.log(data);
if (list[index].count === 1) {
list.splice(index, 1)
} else {
list[index].count--
}
}
renderList()
});
table.on('edit(test)', function (obj) {
var value = obj.value //得到修改后的值
, data = obj.data //得到所在行所有键值
, field = obj.field; //得到字段
let index = obj.tr.attr("data-index")
console.log(value, data, field);
list[index].count = value
renderList()
});
});
}
//根据baseInfo渲染基本信息
function renderBaseInfo(result) {
baseInfo = String2Json(result);
document.getElementById('baseInfo').innerHTML = `
<label>料号: ${baseInfo['Type']}</label>
<label>名称: ${baseInfo['Name']}</label>
<label>批次号: ${baseInfo['Batch No']}</label>
`
}
function submit() {
console.log(baseInfo, list);
}
// Name:Radiator,Type:1002915397,Batch No:221130004,Supplier Code:804C 字符串解析为JSon
function String2Json(string) {
let arr = string.split(',')
let obj = {}
arr.map(item => {
let KeyValueList = item.split(":")
obj[KeyValueList[0]] = KeyValueList[1]
})
return obj
}
// "code:16608052020,name:侧卸油缸~LGC50D-730000~装配图" 处理数据
function handleList(result) {
let item = String2Json(result)
let isExit = false
if (list && list.length > 0) {
for (let i = 0; i < list.length; i++) {
if (list[i].name === item['name']) {
list[i].count++
isExit = true
}
}
}
let obj = {}
obj['name'] = item.name
obj['value'] = item.code
obj['count'] = 1
if (!isExit) {
list.push(obj)
}
console.log(list);
renderList()
}
</script>
</body>
</html>
]]>