drop camera-4.0

This commit is contained in:
Fam Zheng 2025-08-14 22:35:21 +01:00
parent fff1ac4af6
commit 28cdbf1720
19 changed files with 0 additions and 6550 deletions

View File

@ -1,2 +0,0 @@
deploy:
rsync -zrP * oci:/data/emblem-camera/

View File

@ -1,85 +0,0 @@
.lds-roller {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-roller div {
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
transform-origin: 40px 40px;
}
.lds-roller div:after {
content: " ";
display: block;
position: absolute;
width: 7px;
height: 7px;
border-radius: 50%;
background: #666;
margin: -4px 0 0 -4px;
}
.lds-roller div:nth-child(1) {
animation-delay: -0.036s;
}
.lds-roller div:nth-child(1):after {
top: 63px;
left: 63px;
}
.lds-roller div:nth-child(2) {
animation-delay: -0.072s;
}
.lds-roller div:nth-child(2):after {
top: 68px;
left: 56px;
}
.lds-roller div:nth-child(3) {
animation-delay: -0.108s;
}
.lds-roller div:nth-child(3):after {
top: 71px;
left: 48px;
}
.lds-roller div:nth-child(4) {
animation-delay: -0.144s;
}
.lds-roller div:nth-child(4):after {
top: 72px;
left: 40px;
}
.lds-roller div:nth-child(5) {
animation-delay: -0.18s;
}
.lds-roller div:nth-child(5):after {
top: 71px;
left: 32px;
}
.lds-roller div:nth-child(6) {
animation-delay: -0.216s;
}
.lds-roller div:nth-child(6):after {
top: 68px;
left: 24px;
}
.lds-roller div:nth-child(7) {
animation-delay: -0.252s;
}
.lds-roller div:nth-child(7):after {
top: 63px;
left: 17px;
}
.lds-roller div:nth-child(8) {
animation-delay: -0.288s;
}
.lds-roller div:nth-child(8):after {
top: 56px;
left: 12px;
}
@keyframes lds-roller {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

View File

@ -1,464 +0,0 @@
body {
margin: 0;
padding: 0;
font-family:Tahoma,Verdana,STHeiTi,simsun,sans-serif;
}
div.debug {
position: absolute;
left: 5px;
bottom: 5px;
width: 80%;
height: 50%;
border-radius: 10px;
border: 2px dashed rgba(50, 255, 50, 0.5);
background-color: rgba(0, 50, 0, 0.7);
padding: 1rem;
color: #fff;
font-size: 12px;
word-break: break-all;
}
.hidden {
display: none !important;
}
video.preview {
object-fit: cover;
position: fixed;
top: -1%;
left: -1%;
width: 102%;
height: 102%;
z-index: -1000;
border: 1px solid yellow;
box-sizing: border-box;
}
div.debug canvas {
display: inline-block;
width: 100px;
height: 100px;
}
div.bottomfixed {
position: absolute;
width: 100%;
bottom: 0;
height: 90px;
background-color: #171616;
text-align: center;
border-top: 1px solid #ef4823;
}
.play.button {
display: inline-block;
padding: 0.1rem 1.2rem 0.1rem 1.4rem;
margin-right: 0.2rem;
border-radius: 6px;
background-color: #707070;
color: #444;
}
div.bottomfixed .action.highlight .play.button {
background-color: #ccc;
}
div.bottomfixed .action img {
height: 14px;
width: 36px;
}
div.bottomfixed .action {
margin-top: 20px;
font-size: 1rem;
color: #707070;
width: 49%;
display: inline-block;
}
div.bottomfixed .action.highlight {
color: #ccc;
}
div.camoverlay {
position: fixed;
top: 0;
clear: both;
font-size: 0;
width: 100%;
aspect-ratio: 1;
top: 18vw;
}
div.camoverlay img.qrmarkers {
position: absolute;
left: 0;
margin: 0;
width: 100%;
height: 100%;
}
div.lower.text {
top: 4%;
text-align: center;
}
div.progress {
width: 70%;
margin: 0.2rem 0 0 0;
height: 20px;
border-radius: 10px;
background-color: #eee;
font-size: 18px;
color: black;
display: inline-block;
position: relative;
overflow: hidden;
}
div.progress-text {
color: #333;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
div.progress-bar {
border-radius: 10px;
background-color: #ef4823;
width: 0%;
height: 100%;
top: 0;
}
div.upper.overlay {
position: relative;
height: 100vmin;
text-align: center;
}
div.lower.overlay {
position: relative;
width: 100%;
text-align: center;
}
div.debug .buttons {
margin: 0 0 0.3rem 0;
}
div.debug .buttons button {
height: 2rem;
margin: 0 5px 5px 0;
}
div#loading {
width: 100%;
height: 100%;
position: absolute;
background-color: white;
z-index: 10000;
text-align: center;
padding-top: 30%;
}
canvas#output_img {
position: absolute;
right: 5px;
top: 5px;
}
div.bordered {
padding: 0.2rem;
border: 1px dashed yellow;
border-radius: 4px;
margin: 0.2rem 0;
}
div.output {
position: relative;
}
.tooltip {
position: absolute;
width: 100vmin;
display: block;
margin: 0 auto;
animation: bounce 1s ease-in-out infinite; /* Adjust the duration as needed */
top: -60px;
}
.tooltip .tooltiptext {
display: block;
margin: 0 auto;
width: 110px;
background-color: #ef4823;
color: #fff;
padding: 12px 0;
border-radius: 10px;
z-index: 1;
opacity: 0.75;
}
.tooltip:hover .tooltiptext {
}
.tooltip .tooltiptext::after {
content: " ";
position: absolute;
top: 100%; /* At the bottom of the tooltip */
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #ef4823 transparent transparent transparent;
}
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(10px); /* Adjust the bounce height as needed */
}
}
.modal {
display: block;
width: 100%;
height: 100%;
position: fixed;
background-color: rgba(0, 0, 0, 0.9);
z-index: 100;
}
.modal .panel {
position: relative;
width: 80vmin;
height: 80%;
margin: 10vmin auto;
background-image: linear-gradient(0deg, #8b8986 0%, #414141 36%, #414141 92%, #515151 100%);
border-radius: 20px;
}
.modal .actions {
position: absolute;
display: block;
width: 100%;
height: 100px;
bottom: 0;
text-align: center;
}
.actions button {
display: inline-block;
width: 35%;
border-radius: 10px;
box-sizing: border-box;
font-size: 0.8rem;
border-radius: 20rpx;
padding: 0.4rem 1.5rem;
}
button.service {
margin-right: 0.5rem;
border: 1px solid #676767;
background-color: #858585;
color: #a7a7a7;
}
button.back {
border: 1px solid rgba(239, 72, 35, 0.7);
color: rgba(239, 72, 35, 0.7);
margin-left: 0.5rem;
}
button.back img.return {
width: 10px;
height: 10px;
}
.serviceqr {
position: relative;
width: 100%;
padding-top: 80px;
}
.serviceqr .imgbox {
display: block;
margin: auto;
width: 60vmin;
height: 60vmin;
padding: 3vmin;
background-color: #eee;
border-radius: 10px;
}
.serviceqr .title {
position: absolute;
display: inline-block;
width: 100%;
color: #eee;
margin: 30px auto;
text-align: center;
padding: 0;
}
.serviceqr img {
width: 100%;
height: 100%;
}
.verifyfailed {
text-align: center;
color: #eee;
}
.verifyfailed .title {
font-size: 1.1rem;
}
.verifyfailed .hints {
margin-top: 80px;
color: #ccc;
}
.verifyfailed .hints div {
margin-bottom: 0.3rem;
}
.verifyfailed .circle {
height: 20vmin;
width: 20vmin;
color: #666;
font-size: 15vmin;
margin: 10vmin auto 1rem;;
background-color: #ddd;
border-radius: 50%;
display: inline-block;
}
.verifyspin {
position: absolute;
overflow: hidden;
z-index: 101;
width: 100vmin;
height: 100vmax;
background-color: rgba(0, 0, 0, 0.9);
}
.verifyspin .spinner {
position: absolute; /* Position the image absolutely */
width: 100vmin;
height: 100vmin;
margin: 0 auto;
text-align: center;
display: block;
}
.verifyspin img {
display: block;
width: 100%;
height: 100%;
}
.spin-and-shrink {
animation: spin-and-shrink 3s linear forwards;
}
@keyframes spin-and-shrink {
0% {
transform: rotate(-90deg) scale(5.5)
}
10% {
transform: rotate(0deg) scale(2.0)
}
33% {
transform: rotate(90deg) scale(1.0);
}
66% {
transform: rotate(2000deg) scale(0.5);
}
99% {
transform: rotate(3600deg) scale(0.2);
}
100% {
transform: rotate(3600deg) scale(0.2);
}
}
.spin-only {
animation: spin-only 0.3s linear infinite;
}
@keyframes spin-only {
0% {
transform: rotate(0deg) scale(0.2);
}
100% {
transform: rotate(360deg) scale(0.2);
}
}
.verifyspin .loading {
color: #ccc;
font-size: 1.4rem;
display: block;
width: 100%;
margin: 110vmin auto;
text-align: center;
}
div.scanguide {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#hint {
display: inline-block;
margin: 10px auto;
padding: 12px 40px;
border-radius: 10px;
background-color: rgba(0, 0, 0, 0.7);
color: #eee;
font-size: 20px;
}
div.qrarc {
position: absolute;
box-sizing: border-box;
width: 76vw;
height: 76vw;
margin: 20vw 12vw;
animation: qrarc-anime 1.2s ease-in-out infinite;
}
div.qrarc img.arc {
position: absolute;
width: 15%;
height: 15%;
opacity: 0.9;
display: block;
}
div.qrarc img.arc.topright {
right: 0;
transform: rotate(90deg);
}
div.qrarc img.arc.bottomleft {
bottom: 0;
transform: rotate(-90deg);
}
div.qrarc img.arc.bottomright {
bottom: 0;
right: 0;
transform: rotate(180deg);
}
@keyframes qrarc-anime {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

View File

@ -1,139 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="WebRTC code samples">
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<base target="_blank">
<title>AI验真</title>
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="css/loading.css">
</head>
<body>
<div class="loading" id="loading">
<div>
<div class="lds-roller"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>
</div>
<div>
AI摄像头加载中...
</div>
</div>
<div id="container">
<div>
<div class="camoverlay">
<div class="upper overlay">
<div>
<div class="qrarc">
<img class="topleft arc" src="images/arc.png" />
<img class="topright arc" src="images/arc.png" />
<img class="bottomleft arc" src="images/arc.png" />
<img class="bottomright arc" src="images/arc.png" />
</div>
<img class="qrmarkers" src="images/qrmarkers.png" alt=""/>
</div>
<div class="hint wrapper">
<div id="hint" class="upper text" onclick="debug_countdown()">
对齐定位点
</div>
</div>
</div>
</div>
<video class="preview" id="video" autoplay muted playsinline></video>
</div>
<div class="bottomfixed">
<div class="play action" onclick="show_modal('scanguide')">
<img
class="play"
src="images/play-button.png"
/>
验证演示
</div>
<div class="torch action" onclick="toggle_torch()">
<img
class="torch"
src="images/flash-button.png"
/>
开启补光
</div>
<div class="hidden tooltip"><span class="tooltiptext">遇到困难?</span></div>
</div>
<div class="hidden debug" id="debug_div">
<div class="buttons">
<button onclick="location.reload()">reload</button>
<button onclick="set_zoom(4)">4x zoom</button>
<button onclick="set_zoom(2)">2x zoom</button>
<button onclick="wx_submit('debug')">WX OK</button>
<button onclick="torch_onoff()">Torch</button>
<button onclick="hide_debug()">Hide</button>
</div>
<div>
<canvas class="hidden" id="original" width="2000" height="2000">
</canvas>
<canvas class="hidden" id="grayscale" width="2000" height="2000">
</canvas>
</div>
<div id="logs" class="bordered">
</div>
<div class="bordered">
Caps: <span id="caps"></span>
</div>
<div class="bordered">
Constraints: <span id="cons"></span>
</div>
</div>
<div class="modal hidden">
<div class="panel">
<div class="scanguide hidden">
<div id="scanguide">
</div>
</div>
<div class="serviceqr hidden">
<div class="imgbox">
<img id="service_img" src="https://emblem-resources.oss-accelerate.aliyuncs.com/service-qr2.png" alt=""/>
</div>
<div class="title">
长按识别二维码,添加人工客服
</div>
</div>
<div class="verifyfailed hidden">
<div class="circle">
!
</div>
<div class="title">验证未通过</div>
<div class="hints">
<div>
请按照验证指引
</div>
<div>重新验证</div>
<div>
-
</div>
<div>如反复验证仍无法通过</div>
<div>请联系人工客服</div>
</div>
</div>
<div class="actions">
<button onclick="show_modal('serviceqr')" class="service">人工客服</button>
<button onclick="hide_modal()" class="back">
<img class="return" src="images/return.png" alt=""/>
采集</button>
</div>
</div>
</div>
</div>
<div class="verifyspin hidden">
<div class="spinner">
<img src="images/spinner.png" class="spin-image spin-and-shrink">
</div>
<div class="loading">
Loading
</div>
</div>
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
<script type="text/javascript" src="js/lottie.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript" src="js/qrtool.web.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1,407 +0,0 @@
var debug_taps = 0;
var debug_logs = [];
var track;
var frame_width;
var frame_height;
var scanguide_anime;
var busy = false;
const max_inflight = 5;
var should_check_auto_torch = true;
var done_checking_auto_torch = false;
var camera_sensitivity = 1.0;
var camera_capabilities = null;
var Module = {
onRuntimeInitialized: start,
};
function get_query(key) {
const qs = window.location.search;
const params = new URLSearchParams(qs);
return params.get(key) || "";
}
function show_debug() {
const debug_div = document.getElementById("debug_div");
debug_div.classList.remove("hidden");
}
function hide_debug() {
const debug_div = document.getElementById("debug_div");
debug_div.classList.add("hidden");
}
function debug_countdown() {
debug_taps += 1;
if (debug_taps > 10) {
show_debug();
}
}
function hide_loading() {
const loading = document.getElementById("loading");
loading.classList.add("hidden");
}
function handle_stream(stream) {
const video = document.querySelector('video');
const videoTracks = stream.getVideoTracks();
debug_log(`total video tracks: ${videoTracks.length} Using video device: ${videoTracks[0].label}`);
window.stream = stream; // make variable available to browser console
video.srcObject = stream;
video.play();
track = videoTracks[0];
camera_capabilities = track.getCapabilities();
const caps = document.getElementById("caps");
caps.innerHTML = JSON.stringify(camera_capabilities);
const settings = track.getSettings();
console.log(settings);
const canvas = document.getElementById("original");
frame_width = settings.width;
frame_height = settings.height;
video.width = frame_width;
video.height = frame_height;
canvas.width = frame_width;
canvas.height = frame_height;
}
function handleError(error) {
debug_log(error);
console.log(error);
}
function debug_log(msg) {
debug_logs.push(Date.now() / 1000 + ": " + msg);
const nentries = 20;
while (debug_logs.length > nentries) {
debug_logs.shift();
}
var output = "";
for (var l of debug_logs) {
output = `<div>${l}</div>` + output;
}
console.log(msg);
const di = document.getElementById("logs");
di.innerHTML = output;
}
async function start_camera(e) {
try {
const constraints = window.constraints = {
audio: false,
video: {
facingMode: "environment",
focusDistance: 0.12,
focusMode: "manual",
width: { ideal: 2000 },
},
};
const supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
const cons = document.getElementById("cons");
cons.innerHTML = JSON.stringify(supportedConstraints);
debug_log(navigator.userAgent);
const stream = await navigator.mediaDevices.getUserMedia(constraints);
handle_stream(stream);
const zoom = get_query("zoom");
if (zoom) {
set_zoom(zoom);
}
} catch (e) {
handleError(e);
}
}
function is_emblem_qr_pattern(p)
{
if (p.search(/code=[0-9a-zA-Z]+/) >= 0) return true;
if (p.search(/c=[0-9a-zA-Z]+/) >= 0) return true;
if (p.search(/https:\/\/xy.ltd\/v\/[0-9a-zA-Z]+/) >= 0) return true;
return false;
}
function make_hint_text(r) {
var qr_is_valid = false;
if (r.qrcode && r.qrcode.length > 0) {
qr_is_valid = is_emblem_qr_pattern(r.qrcode);
if (!qr_is_valid) {
return "无效编码";
}
}
if (qr_is_valid) {
var err = r.err || "";
if (err.includes("margin too small")) {
return "对齐定位点";
} else if (err.includes("energy check failed") || err.includes("cannot detect angle")) {
return "移近一点";
}
}
return "对齐定位点";
}
function handle_frame() {
try {
do_handle_frame();
} catch (e) {
debug_log("handle frame exception: " + e);
}
setTimeout(handle_frame, 20);
}
function do_handle_frame() {
if (busy) return;
const canvas = document.getElementById("original");
const video = document.getElementById("video");
canvas.width = video.width;
canvas.height = video.height;
canvas.style.width = video.width / 4 + "px";
canvas.style.height = video.height / 4 + "px";
const ctx = canvas.getContext("2d");
ctx.drawImage(video, 0, 0);
const id = ctx.getImageData(0, 0, canvas.width, canvas.height);
console.log(Module);
var buf = Module._malloc(id.data.length * id.data.BYTES_PER_ELEMENT);
Module.HEAPU8.set(id.data, buf);
var r = Module.ccall('qrtool_angle', 'string', ['number', 'number', 'number', 'number', 'number'], [buf, id.width, id.height, 0, camera_sensitivity]);
Module._free(buf);
debug_log(r);
const res = JSON.parse(r);
const is_valid_pattern = res.qrcode && res.qrcode.length && is_emblem_qr_pattern(res.qrcode);
if (res.qrcode && should_check_auto_torch) {
start_check_auto_torch(res.qrcode);
}
if (done_checking_auto_torch && is_valid_pattern && res.ok) {
var data_url = canvas.toDataURL("image/jpeg", 1.0);
submit_image(res.qrcode, res.angle, data_url);
} else {
pending_hint = make_hint_text(res);
}
}
async function start_check_auto_torch(qrcode)
{
should_check_auto_torch = false;
var r = await fetch("https://themblem.com/api/v1/check-auto-torch/?qrcode=" + encodeURIComponent(qrcode), {
method: "GET",
});
var d = await r.json();
debug_log(JSON.stringify(d));
if (d.enable_auto_torch && !torch) {
toggle_torch();
}
camera_sensitivity = d.camera_sensitivity || 1.0;
setTimeout(() => {
done_checking_auto_torch = true;
}, 200);
}
function set_zoom(zoom) {
if (camera_capabilities.zoom) {
debug_log("set zoom by applying constraints");
track.applyConstraints({advanced: [ {zoom} ]});
} else {
debug_log("set zoom by scaling video element");
add_style_by_query("video.preview", "transform", `scale(${zoom})`);
}
}
let torch = false;
function toggle_torch() {
torch = !torch;
track.applyConstraints({advanced: [ {torch: torch} ]});
if (torch) {
add_class_by_query(".bottomfixed .torch.action", "highlight");
} else {
remove_class_by_query(".bottomfixed .torch.action", "highlight");
}
}
function show_spinner() {
remove_class_by_query('.verifyspin', 'hidden');
remove_class_by_query('.spin-image', 'spin-only');
remove_class_by_query('.spin-image', 'spin-and-shrink');
setTimeout(() => {
add_class_by_query('.spin-image', 'spin-and-shrink');
setTimeout(() => {
remove_class_by_query('.spin-image', 'spin-and-shrink');
add_class_by_query('.spin-image', 'spin-only');
}, 3000);
}, 0);
}
function hide_spinner() {
add_class_by_query('.verifyspin', 'hidden');
}
async function submit_image(qrcode, angle, image_data_url) {
busy = true;
var begin = Date.now();
show_spinner();
debug_log(`submit: qrcode: ${qrcode} angle: ${angle}`);
try {
// TODO: pass these parameters from query string
var emblem_id = get_query("emblem_id");
var nick_name = get_query("nick_name");
var realip = get_query("realip");
var phonemodel = get_query("phonemodel");
var data = {
emblem_id,
nick_name,
realip,
qrcode,
angle,
phonemodel,
image_data_url,
log: debug_logs.join("\n"),
};
var r = await fetch("https://themblem.com/api/v1/qr-verify/", {
method: "POST",
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
},
});
var d = await r.json();
debug_log(JSON.stringify(d));
if (d.serial_code) {
if (wx) {
var delay = 3000 - (Date.now() - begin);
setTimeout(() => {
if (get_query("ai_chat_mode")) {
wx.miniProgram.redirectTo({
url: '/pages/chat/chat?serial_code=' + d.serial_code,
});
} else {
wx.miniProgram.redirectTo({
url: '/pages/productinfo/productinfo?serial_code=' + d.serial_code,
});
}
}, delay > 0 ? delay : 0);
}
} else {
this.show_modal('verifyfailed');
}
} catch (e) {
debug_log(`submission error: ${e}`);
this.show_modal('verifyfailed');
}
}
var pending_hint = null;
function update_hint() {
var now = Date.now();
if (pending_hint) {
const hint_dev = document.getElementById("hint");
hint_dev.innerHTML = pending_hint;
pending_hint = null;
}
}
function start() {
console.log("start");
setTimeout(handle_frame, 100);
hide_loading();
if (get_query("debug")) {
show_debug();
}
setInterval(update_hint, 1000);
setTimeout(() => {
show_tooltip();
}, 15000);
}
function show_tooltip() {
remove_class_by_query(".tooltip", "hidden");
add_class_by_query(".bottomfixed .action", "highlight");
}
function hide_tooltip() {
add_class_by_query(".tooltip", "hidden");
remove_class_by_query(".bottomfixed .action", "highlight");
}
async function init_scanguide() {
var r = await fetch('https://emblem-resources.oss-cn-guangzhou.aliyuncs.com/scan-guide-1080x1920-3.json');
var d = await r.json();
console.log("start scanguide", d);
const elem = document.getElementById("scanguide");
scanguide_anime = bodymovin.loadAnimation({
container: elem,
animationData: d,
// path: 'data.json',
renderer: 'svg',
loop: true,
autoplay: true,
name: "Scan guide",
})
}
function add_style_by_query(query, property, style) {
var list = document.querySelectorAll(query);
for (var i = 0; i < list.length; ++i) {
list[i].style[property] = style;
}
}
function add_class_by_query(query, to_add) {
var list = document.querySelectorAll(query);
for (var i = 0; i < list.length; ++i) {
list[i].classList.add(to_add);
}
}
function remove_class_by_query(query, to_remove) {
var list = document.querySelectorAll(query);
for (var i = 0; i < list.length; ++i) {
list[i].classList.remove(to_remove);
}
}
var modals = ['serviceqr', 'scanguide', 'verifyfailed', 'verifyspin'];
function hide_modal() {
busy = false;
scanguide_anime.stop();
add_class_by_query(".modal", "hidden");
hide_tooltip();
}
function show_modal(which) {
busy = true;
hide_tooltip();
hide_spinner();
add_class_by_query(".verifyspin", "hidden");
remove_class_by_query(".modal", "hidden");
remove_class_by_query('.actions', 'hidden');
for (var m of modals) {
add_class_by_query('.' + m, 'hidden');
}
if (which == 'scanguide') {
scanguide_anime.goToAndPlay(0);
remove_class_by_query('.scanguide', 'hidden');
}
if (which == 'serviceqr') {
remove_class_by_query('.serviceqr', 'hidden');
add_class_by_query('.actions', 'hidden');
}
if (which == 'verifyfailed') {
remove_class_by_query('.verifyfailed', 'hidden');
}
}
function set_service_qr_img() {
var tid = get_query('tenant');
var url = '/api/v1/service-qr/?tenant=' + tid;
const elem = document.getElementById("service_img");
elem.src = url;
}
(function() {
start_camera();
init_scanguide();
set_service_qr_img();
})();

File diff suppressed because it is too large Load Diff