This commit is contained in:
JayJiaJun 2024-11-13 11:26:59 +08:00
commit 25dc9971c7
130 changed files with 46165 additions and 0 deletions

4
.browserslistrc Normal file
View File

@ -0,0 +1,4 @@
> 1%
last 2 versions
not dead
not ie 11

17
.eslintrc.js Normal file
View File

@ -0,0 +1,17 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended'
],
parserOptions: {
parser: '@babel/eslint-parser'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
}

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

28
README.md Normal file
View File

@ -0,0 +1,28 @@
# set-vue
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
我a
See [Configuration Reference](https://cli.vuejs.org/config/).

5
babel.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

19
jsconfig.json Normal file
View File

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

13538
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

44
package.json Normal file
View File

@ -0,0 +1,44 @@
{
"name": "set-vue",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@vant/touch-emulator": "^1.4.0",
"amfe-flexible": "^2.2.1",
"autoprefixer": "^10.4.19",
"axios": "^1.7.2",
"core-js": "^3.8.3",
"mqtt": "^2.18.8",
"vant": "^4.9.5",
"vconsole": "^3.15.1",
"vue": "^3.2.13",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@locator/runtime": "^0.4.4",
"@vant/auto-import-resolver": "^1.2.1",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"code-inspector-plugin": "^0.17.3",
"compression-webpack-plugin": "^11.1.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"file-loader": "^6.2.0",
"less": "^4.2.0",
"less-loader": "^12.2.0",
"postcss-pxtorem": "^5.1.1",
"unplugin-auto-import": "^0.17.8",
"unplugin-vue-components": "^0.27.4"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

18
public/index.html Normal file
View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<script src="./web/js/webView.js"></script>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

13
public/web/cache.manifest Normal file
View File

@ -0,0 +1,13 @@
CACHE MANIFEST
#v0.01 //离线缓存文件的版本信息
CACHE: //需要进行离线缓存的资源
./css/common.css
./css/content.css
./css/style.css
NETWORK://表示只有在在线状态下才能访问的资源,即不需要缓存的资源
*
FALLBACK://资源加载失败的时候跳转的页面

File diff suppressed because it is too large Load Diff

52
public/web/css/common.css Normal file
View File

@ -0,0 +1,52 @@
/*底部导航*/
footer ul {
background-color: #333;
position: fixed;
display: block;
bottom: 0;
width: 100%;
height: 35px;
line-height: 35px;
font-family: "microsoft yahei";
font-size: 1.125rem;
border-radius: 6px;
}
footer li {
width: 25%;
float: left;
text-align: center;
}
/*导航选项链接*/
footer li a {
padding: 12px 5px;
color: white;
}
footer li a.active {
background-color: rgb(235, 84, 14);
}
footer li a:active,
footer li a:link,
footer li a:visited {
color: white;
}
footer {
width: 100%;
display: block;
}
footer img {
width: 145px;
left: 32%;
position: relative;
box-sizing: border-box;
}
footer p {
text-align: center;
}

517
public/web/css/content.css Normal file
View File

@ -0,0 +1,517 @@
*{
margin: 0 ;
padding: 0;
}
/* body{
background: #E5EDE2;
/* background:#eee;
}
/**/
/* .show{
position: relative;
margin-left: 50%;
margin-right: 50%;
transform:translate(-50%,50%);
color: #5555;
cursor: pointer;
} */
/* 屏幕展示区域样式 */
/* .e-screen {
width: 380px;
height: 135px;
background-color: black;
margin-bottom: 30px;
margin: 0 auto;
} */
textarea {
max-width: 335px;
min-width: 335px;
max-height: 58px;
min-height: 58px;
margin-top: 10px;
outline: none;
margin: 8px 8px;
font-size: 24px;
}
.bd textarea:focus {
box-shadow: 0 0 0 .075rem #fff, 0 0 0 .2rem #0074d9;
}
.bd textarea:active {
color: #fff;
background-color: #84c6ff;
}
.font {
width: 70px;
/* margin: 2px 10px; */
margin: 0;
padding: 8px;
}
.fontsize {
width: 50px;
margin: 0;
padding: 8px;
}
.tx,
.speed,
.stay,
.h-align,
.v-align {
left: 10px;
position: relative;
width: 70%;
margin: 0;
padding: 8px;
}
.my_fieldset {
margin: 0 auto;
width: 95%;
border: solid 2px #84c6ff;
}
.my_fieldset legend {
color: #84c6ff;
}
.my_fieldset label {
position: relative;
left: 5%;
margin-right: 70px;
font-size: 13px;
}
.select .img_type_css {
position: relative;
width: 200px;
font-size: 13px;
}
.my_fieldset_div {
margin: 0 auto;
width: 95%;
border: solid 2px #84c6ff;
}
.my_fieldset_div2{
position: relative;
width: 80%;
margin-left: 10%;
}
.my_fieldset_div legend {
color: #84c6ff;
}
.my_fieldset_div2 label {
font-size: 16px;
}
.my_fieldset_div2 input {
/* position: relative; */
border: solid 2px #d4d4d4;
border-radius: 6px;
width: 40%;
margin-bottom: 10px;
line-height: 24px;
font-size: 16px;
}
.my_fieldset_div2 div {
width: 50%;
float: left;
}
.select {
margin: 0 auto;
margin-left: 10px;
margin-bottom: 6px;
position: relative;
padding: 0;
box-shadow: 0 0 10px #d4d4d4;
border-radius: 8px;
}
.select input{
width: 148px;
border-radius: 6px;
color: #555;
background-color: #eee;
font-size: 14px;
padding: .5rem 2.25rem .5rem 1rem;
/* justify-content: space-around;
line-height: 1;
border: 0;
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: none;
*/
}
.select,
.animation_style {
position: relative;
display: inline-flex;
/* background-color: #ededed; */
color: #555;
font-size: 15px;
}
.select select {
width: 105px;
justify-content: space-around;
padding: .5rem 2.25rem .5rem 1rem;
line-height: 1;
color: #555;
background-color: #eee;
border: 0;
border-radius: 6px;
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: none;
font-size: 14px;
}
.select select:focus:-moz-focusring {
color: transparent;
text-shadow: 1.2 -1.2 1.8 #000;
}
/* Dropdown arrow */
.select:after {
position: absolute;
top: 50%;
right: 0.25rem;
content: "";
width: 0;
height: 0;
margin-top: -.15rem;
pointer-events: none;
border-top: .35rem solid;
border-right: .35rem solid transparent;
border-bottom: .35rem solid transparent;
border-left: .35rem solid transparent;
}
/* Focus */
.select select:focus,
.animation_style select:focus {
box-shadow: 0 0 0 .075rem #fff, 0 0 0 .2rem #0074d9;
}
/* Active/open */
.select select:active,
.animation_style select:active {
color: #fff;
background-color: #84c6ff;
}
.select select::-ms-expand,
.animation_style select::-ms-expand {
display: none;
}
/* Media query to target Firefox only */
/* IE9 hack to hide the arrow
@media screen and (min-width:0\0) {
.select select {
z-index: 1;
padding: .5rem 1.5rem .5rem 2rem;
}
.select:after {
z-index: 5;
}
.select:before {
position: absolute;
top: 0;
right: 1rem;
bottom: 0;
z-index: 2;
content: "";
display: block;
width: 1.5rem;
background-color: #eee;
}
.select select:hover,
.select select:focus,
.select select:active {
color: #555;
background-color: #eee;
}
} */
/* Hide the arrow in IE10 and up */
.animation_style select {
display: inline-block;
width: 140px;
margin-right: 10px;
padding: .5rem 2.25rem .5rem 1rem;
line-height: 1;
color: #555;
background-color: #eee;
border: 0;
border-radius: 6px;
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: none;
font-size: 14px;
}
.animation_style select:active {
color: #fff;
background-color: #84c6ff;
outline: none;
}
.animation_style table {
width: 340px;
left: 9px;
position: relative;
border: solid 1px #d4d4d4;
border-radius: 5px;
box-shadow: 0 1px 10px #e8e8e8;
font-size: 14px;
}
td {
width: 160px;
/* background-color: #eee; */
/* background: #fff; */
}
/* td:nth-child(2) {
width: 100px;
font-size: 15px;
/* color: #eee; */
/* background: #eee url(../img/coin.png) 15px 2px no-repeat; */
/* } */
.content_btn {
width: 375px;
display: flex;
margin: 0 auto;
}
.content_btn button {
width: 80px;
height: 35px;
line-height: 35px;
border-radius: 8px;
border: none;
color: #fff;
background-color: #67a9eb;
margin: 35px 55px 55px;
justify-content: space-around;
cursor: pointer;
box-shadow: 0 0 10px #e8e8e8;
}
.txt_bold {
width: 60px;
height: 30px;
/* float: left; */
/* background: url(../img/coin2.png) 10px -20px no-repeat; */
}
#txt_canvas {
background: rgba(0, 0, 0, 0);
}
/************************************************节目管理弹出css****************************************************/
.my_contain {
display: none;
background-color: #FFFFFF;
z-index: 11;
width: 80%;
height: 45%;
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
margin: auto;
}
.my_contain2 {
height: 57%;
}
.ground {
top: -20%;
display: none;
background-color: #B3B3B3;
position: absolute;
width: 100%;
height: 190%;
z-index: 10;
-moz-opacity: 0.8;
opacity: .80;
filter: alpha(opacity=80);
/* 只支持IE6、7、8、9 */
}
/*************************************************节目模式修改弹窗css************************************************/
.pro_mode_shade {
top: 0%;
display: none;
background-color: #B3B3B3;
position: fixed;
width: 100%;
height: 100%;
z-index: 10;
-moz-opacity: 0.8;
opacity: .80;
filter: alpha(opacity=80);
/* 只支持IE6、7、8、9 */
}
.pro_mode_window {
display: none;
background-color: #FFFFFF;
z-index: 11;
width: 80%;
height: 700px;
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
margin: auto;
}
.pro_mode_window h2 {
margin-top: 15px;
text-align: center;
/* 位置居中 */
}
.pro_mode_btn {
float: left;
margin-top: 15px;
margin-bottom: 15px;
margin-right: 5%;
margin-left: 5%;
border: none;
outline: none;
width: 40%;
height: 130px;
border-radius: 18px;
color: #2b2828;
font-size: 24px;
background-color: #67a9eb;
cursor: pointer;
}
.pro_mode_btn p {
font-size: 18px;
position: relative;
bottom: -10px;
text-align: center;
width: 100%;
}
.pro_mode1_area {
width: 90%;
height: 90%;
margin-top: 6.5px;
margin-left: 5%;
border-radius: 10px;
background-color: #B3B3B3;
text-align: center;
font-size: 20px;
}
.pro_mode2_area {
width: 90%;
height: 42.5%;
margin-top: 6.5px;
margin-left: 5%;
border-radius: 10px;
background-color: #B3B3B3;
text-align: center;
font-size: 20px;
}
.pro_mode3_area {
float: right;
width: 42.5%;
height: 90%;
margin-top: 6.5px;
margin-right: 5%;
border-radius: 10px;
background-color: #B3B3B3;
text-align: center;
font-size: 20px;
}
.pro_mode4_area {
width: 90%;
height: 26.66%;
margin-top: 6.5px;
margin-left: 5%;
border-radius: 10px;
background-color: #B3B3B3;
text-align: center;
font-size: 20px;
}
.pro_mode5_area {
width: 90%;
height: 18.75%;
margin-top: 6.5px;
margin-left: 5%;
border-radius: 10px;
background-color: #B3B3B3;
text-align: center;
font-size: 20px;
}
.pro_mode6_area {
float: right;
width: 42.5%;
height: 42.5%;
margin-top: 6.5px;
margin-right: 5%;
border-radius: 10px;
background-color: #B3B3B3;
text-align: center;
font-size: 20px;
}
/*************************************************屏幕亮度弹窗css************************************************/
.scroll {
margin: 100px;
width: 5px;
height: 320px;
background: #ccc;
position: relative;
}
.bar {
width: 15px;
height: 5px;
background: #369;
position: absolute;
top: 0px;
left: -5;
cursor: pointer;
}

1011
public/web/css/style.css Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,180 @@
html,
body {
height: 100%;
margin: 0;
}
*{
user-select: none;
}
.record-container {
/* 容器样式 */
text-align: center;
padding-top: 50px;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.voice-btn-wrap {
width: 100%;
/* position: fixed; */
/* bottom: 25px; */
left: 0;
display: flex;
justify-content: center;
}
.break_btn {
position: fixed;
right: calc(50% - 120px);
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
width: 100px;
height: 60px;
}
#record-btn {
/* 按钮样式 */
width: 200px;
height: 200px;
position: fixed;
top: 400px;
background-color: #4CAF50; /* 淡蓝色背景 */
color: black; /* 文字颜色 */
border: none;
border-radius: 50%; /* 圆形按钮 */
cursor: pointer;
left: calc(50% - 100px); /* 水平居中按钮 */
display: flex;
align-items: center;
justify-content: center;
font-size: 32px; /* 调整字体大小 */
text-align: center;
}
#record-btn:active {
/* 按钮按下时的样式 */
background-color: #45a049;
width: 200px;
height: 200px;
left: calc(50% - 100px);
border-radius: 60%; /* 圆形按钮 */
}
.record-popup {
/* 弹出窗样式 */
margin-top: 120px;
}
/* 其他样式调整 */
.voice-line-wrap {
display: flex;
justify-content: center;
align-items: center;
height: 50px;
/* 可调整高度 */
}
.voice-line {
width: 5px;
height: 20px;
/* 初始高度 */
margin: 0 2px;
background-color: #4CAF50;
animation: wave 1s infinite ease-in-out alternate;
}
#audio-playback{
position: fixed;
top: 250px;
left: calc(50% - 150px);
}
/* 不同的.voice-line将有不同的动画延迟来创建波动效果 */
.voice-line:nth-child(1) {
animation-delay: 0s;
}
.voice-line:nth-child(2) {
animation-delay: 0.1s;
}
.voice-line:nth-child(3) {
animation-delay: 0.2s;
}
.voice-line:nth-child(4) {
animation-delay: 0.3s;
}
.voice-line:nth-child(5) {
animation-delay: 0.4s;
}
.voice-line:nth-child(6) {
animation-delay: 0.5s;
}
.voice-line:nth-child(7) {
animation-delay: 0.6s;
}
@keyframes wave {
0% {
height: 20px;
}
100% {
height: 40px;
}
/* 动画结束时的高度 */
}
/* .record-popup {
position: absolute;
bottom: var(--popup-bottom);
left: calc(50vw - calc(var(--popup-width) / 2));
z-index: 1;
width: var(--popup-width);
height: var(--popup-height);
display: flex;
align-items: center;
justify-content: center;
border-radius: 10rpx;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
background: var(--popup-bg-color);
color: #000;
transition: 0.2s height;
} */
.record-popup .inner-content {
height: var(--popup-height);
font-size: 24rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.title {
font-weight: bold;
padding: 20rpx 0;
}
.tips {
color: #999;
padding: 20rpx 0;
}

121
public/web/edit_pwd.html Normal file
View File

@ -0,0 +1,121 @@
<!--
* @Descripttion:
* @version:
* @Author: Baron
* @Date: 2022-05-23 09:31:25
* @LastEditors: Andy
* @LastEditTime: 2024-06-25 11:15:19
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="max-age" content="31536000">
<meta http-equiv="Pragma" content="public">
<meta http-equiv="Cache-control" content="public">
<meta http-equiv="Cache" content="public">
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=0.01, maximum-scale=1, user-scalable=yes" />
<title>修改密码</title>
<link rel="stylesheet" href="css/style.css">
<script src="js/jquery-3.4.1.min.js"></script>
<script> src = "js/jsonid.js"</script>
</head>
<body>
<div class="contain">
<header>
<!-- <div><a href="screen_main.html">&lt;返回</a></div> -->
</header>
<div class="box" id="box">
<h2>修改密码</h2>
<!-- <form action="login.html" method="post"> -->
<ul>
<li>
<label><span>*</span>原始密码:</label>
<input type="password" name="pwd" maxlength="10" placeholder="请输入原始密码" id="raw_pass">
</li>
<li>
<label><span>*</span>新密码:</label>
<input type="password" name="pwd" maxlength="10" placeholder="请输入新密码" id="new_pwd">
</li>
<li>
<label><span>*</span>确认新密码:</label>
<input type="password" name="pwdOk" maxlength="10" placeholder="确认密码必须与密码一致" id="pwdOK">
</li>
</ul>
<button name="submit" id="submit">提交</button><br>
<input type="reset" id="reset" value="取消"></button>
<!-- </form> -->
<div class="toast">
<span>密码不能为空</span>
</div>
</div>
</div>
<script>
$(function () {
var baseHost = document.location.origin
$('#submit').on('click', function () {
var rawPwd = $('#raw_pass').val()
var newPwd = $('#new_pwd').val()
var rePwd = $('#pwdOK').val()
var submit = {}
// submit.jsonid = json_id;
submit = new Object()
submit.log_in = new Object()
submit.log_in.type = 2
submit.log_in.pass = rawPwd
submit.log_in.new_pass = newPwd
console.log(JSON.stringify(submit))
if (!newPwd.trim().length || !rePwd.trim().length) {
$('.toast').css('display', 'flex')
setTimeout(function () {
$('.toast').css('display', 'none')
}, 2000)
return false
} else if (newPwd != rePwd) {
alert('新密码与确认密码不一致')
return false
}
//1.创建ajax对象
var xhr = new XMLHttpRequest()
xhr.open('post', baseHost + '/communication', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(JSON.stringify(submit))
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
//1.服务器返回的json格式数据
var json = xhr.responseText
console.log(json)
/*2.
*通过eval方法将上面的数据转换成json格式
*上面数据的所有双引号全部转换成单引号
*/
var result = eval("(" + json.replace(/"/g, "'") + ")")
/* 3.转换成json格式后可以通过对象的方式进行访问既通过“.”的方式
* 判断从服务器返回值中return是否等于0
* 0密码正确 1密码错误
*/
if (result.led_protocol.log_in.return == 0) {
alert("修改密码成功!")
window.location.href = "/login.html"
return
} else {
alert("修改密码失败!")
return false
}
}
}
})
//单击取消按钮,跳转至登录页面
$("#reset").on('click', function () {
window.location.href = '/login.html'
})
})
</script>
</body>
</html>

BIN
public/web/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/web/img/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
public/web/img/coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/web/img/compicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
public/web/img/content.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
public/web/img/del.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
public/web/img/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
public/web/img/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/web/img/insert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/web/img/ld.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
public/web/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/web/img/refresh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
public/web/img/remove.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/web/img/setting.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,112 @@
/*
* @Descripttion:
* @version:
* @Author: Eugene
* @Date: 2023-10-12 09:55:52
* @LastEditors: Andy
* @LastEditTime: 2024-03-11 11:03:24
*/
var MQTT_MODE = 1;
function pageName() {
var a = location.href;
var b = a.split("/");
var c = b.slice(b.length - 1, b.length).toString(String).split(".");
return c[0];
}
var json_id = 0;
//在发送数据后调用这个函数
function MQTT_send(string) {
json_id = localStorage.getItem("json_id");
json_id++;
if(json_id>255)
{
json_id = 0;
}
localStorage.setItem("json_id", json_id);
let send_string = "{\"JSON_id\":" + json_id + ",\"led_protocol\":" + string + "}"
console.log("MQTT 发送:" + send_string);
if (/xazn/.test(navigator.userAgent)||/uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: send_string
}
});
} else {
//这里需要将string发送出去
window.parent.postMessage({
str: send_string
}, "*"); // 替换为Vue应用的URL
}
}
//在发送数据后调用这个函数(带协议发送)
function MQTT_json_send(string,protocol) {
json_id = localStorage.getItem("json_id");
json_id++;
if(json_id>255)
{
json_id = 0;
}
localStorage.setItem("json_id", json_id);
let send_string = "{\"JSON_id\":" + json_id + ",\"" + protocol + "\":" + string + "}";
console.log("MQTT 发送:" + send_string);
if (/xazn/.test(navigator.userAgent)||/uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: send_string
}
});
} else {
//这里需要将string发送出去
window.parent.postMessage({
str: send_string
}, "*"); // 替换为Vue应用的URL
}
}
//在收到数据后需要调用这个函数
function MQTT_recv(string) {
console.log("MQTT 接收:" + string);
let json = jQuery.parseJSON(string);
let href = pageName();
if ("error_code" in json) {
console.log("MQTT接收到回复码" + json.error_code);
}
if(json.led_protocol)
{
var str = JSON.stringify(json.led_protocol);
string = str;
}
console.log("MQTT 处理后:" + string);
if (href == "screen_main") {
console.log("now -> screen_main");
cmd_reply_parse_fun(string);
}
else if (href == "screen_par") {
console.log("now -> screen_par");
screen_par_reply_parse_fun(string);
}
else if (href == "screen_program") {
console.log("now -> screen_program");
program_list_reply_parse_fun(string);
}
else if (href == "screen_virtual") {
console.log("now -> screen_virtual");
screen_virtual_reply_parse_fun(string);
}
else if (href == "content_pattern1") {
console.log("now -> content_pattern1");
content_pattern_reply_parse_fun(string);
}
else if (href == "voice_set") {
console.log("now -> voice_set");
device_list_update(string);
}
else if (href == "voice") {
console.log("now -> voice");
voice_reply_parse_fun(string);
}
}

111
public/web/js/MQTT_port.js Normal file
View File

@ -0,0 +1,111 @@
/*
* @Descripttion:
* @version:
* @Author: Eugene
* @Date: 2023-10-12 09:55:52
* @LastEditors: Andy
* @LastEditTime: 2024-03-11 11:07:00
*/
var MQTT_MODE = 1;
function pageName() {
var a = location.href;
var b = a.split("/");
var c = b.slice(b.length - 1, b.length).toString(String).split(".");
return c[0];
}
var json_id = 0;
//在发送数据后调用这个函数
function MQTT_send(string) {
json_id = localStorage.getItem("json_id");
json_id++;
if (json_id > 255) {
json_id = 0;
}
localStorage.setItem("json_id", json_id);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
console.log("MQTT 发送:" + send_string);
if (/xazn/.test(navigator.userAgent)||/uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: send_string
}
});
} else {
//这里需要将string发送出去
window.parent.postMessage({
str: send_string
}, "*"); // 替换为Vue应用的URL
}
}
//在发送数据后调用这个函数(带协议发送)
function MQTT_json_send(string, protocol) {
json_id = localStorage.getItem("json_id");
json_id++;
if (json_id > 255) {
json_id = 0;
}
let send_string;
localStorage.setItem("json_id", json_id);
if(protocol=="sound_card"){
send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":103"+ ",\"" + protocol + "\":" + string + "}";
}else{
send_string = "{\"JSON_id\":" + json_id + ",\"" + protocol + "\":" + string + "}";
}
console.log("MQTT 发送:" + send_string);
if (/xazn/.test(navigator.userAgent)||/uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: send_string
}
});
} else {
//这里需要将string发送出去
window.parent.postMessage({
str: send_string
}, "*"); // 替换为Vue应用的URL
}
}
//在收到数据后需要调用这个函数
function MQTT_recv(string) {
console.log("MQTT 接收:" + string);
let json = jQuery.parseJSON(string);
let href = pageName();
if ("error_code" in json) {
console.log("MQTT接收到回复码" + json.error_code);
}
var str = JSON.stringify(json);
string = str;
console.log("MQTT 处理后:" + string);
if (href == "screen_main") {
console.log("now -> screen_main");
cmd_reply_parse_fun(string);
}
else if (href == "screen_par") {
console.log("now -> screen_par");
screen_par_reply_parse_fun(string);
}
else if (href == "screen_program") {
console.log("now -> screen_program");
program_list_reply_parse_fun(string);
}
else if (href == "screen_virtual") {
console.log("now -> screen_virtual");
screen_virtual_reply_parse_fun(string);
}
else if (href == "content_pattern1") {
console.log("now -> content_pattern1");
content_pattern_reply_parse_fun(string);
}
else if (href == "voice") {
console.log("now -> voice");
voice_reply_parse_fun(string);
}
}

930
public/web/js/content.js Normal file
View File

@ -0,0 +1,930 @@
const width_screen = 64;
const height_screen = 64;
const txt_preview = document.getElementById("preview_canvas");
const txt_draw = document.getElementById("txt_canvas");
const input_ctl=document.getElementById('screen_info');
const f_color = document.getElementById('fcolor0');
const f_style = document.getElementById('txt_style0');
const f_stretch=document.getElementById('stretch_act0')
const h_align_ctrl = document.getElementById("h-align0");
const v_align_ctrl = document.getElementById("v-align0");
const font_type_ctl = document.getElementById("font0");
const font_size_ctl = document.getElementById("fontsize0");
const animation_type_ctl = document.getElementById("tx0");
const p_pausetime = document.getElementById('stay0');
const button_ctl =document.getElementById('btn_set');
const g_zoom_preview = 5;
var g_text_resrtcut_arry;//重组后的字符数组(字符串数组)
var g_text_line_width;//每一行的宽度,(数组)
var g_text_page_line;//每一页的行数,数组元素的个数,代表了总共有多少页,数组g_text_page_line[x]代表该页有多少行
var back_ground_img;//预览文字背景
var preview_img_data;//预览文字图片
var img_rgb_data;
//对文字进行预处理,根据屏幕的宽度,将文字存放到二维数组,二维数组行数代表屏幕上有几行
function restruct_input_text()
{
var row_txt_array = input_ctl.value;
var font_size = parseInt(font_size_ctl.value);
var animation_type = parseInt(animation_type_ctl.value);
var line = 0;
var cur_index = 0;
g_text_resrtcut_arry = null;
g_text_line_width = null;
g_text_page_lines = null;
if(row_txt_array.length != 0)
{
g_text_resrtcut_arry = new Array();
g_text_line_width = new Array();
g_text_page_lines = new Array();
g_text_page_lines[0] = 0;
}
else
{
return;
}
var line_max_per_screen = parseInt(height_screen/font_size);
if(line_max_per_screen == 0)
{
line_max_per_screen = 1;
}
if(animation_type == 6)//连续左移单独处理,因为不需要分页
{
g_text_resrtcut_arry[0] = row_txt_array;
var x_width = 0;
for(var i=0; i<row_txt_array.length; i++)
{
if (row_txt_array.charCodeAt(i) > 255) //中文
{
x_width += font_size;
}
else
{
x_width += font_size/2;
}
}
g_text_line_width[0] = Math.ceil(x_width/8)*8;
g_text_page_lines[0] = 1;
}
else
{
var page = 0;
while(1)
{
var text_write_width = 0;
var row = 0;
while(1)
{
if(font_size > width_screen)//字体大于屏幕宽度
{
if(g_text_resrtcut_arry[line] == null)
{
g_text_resrtcut_arry[line] = row_txt_array.substring(cur_index, cur_index + 1);
g_text_line_width[line] = width_screen;
}
else
{
g_text_resrtcut_arry[line] += row_txt_array.substring(cur_index, cur_index + 1);
g_text_line_width[line] += width_screen;
}
cur_index++;
line++;
if(line >= (page+1)*line_max_per_screen)//换一页
{
g_text_page_lines[page] += 1;
page++;
g_text_page_lines[page] = 0;
}
else
{
g_text_page_lines[page] += 1;
}
if(cur_index < row_txt_array.length)//文字未取完
{
break;//写不下 换行
}
}
else{
if (row_txt_array.charCodeAt(cur_index) > 255) //中文
{
if((text_write_width + font_size) <= width_screen)
{
if(g_text_resrtcut_arry[line] == null)
{
g_text_resrtcut_arry[line] = row_txt_array.substring(cur_index, cur_index + 1);
g_text_line_width[line] = font_size;
}
else
{
g_text_resrtcut_arry[line] += row_txt_array.substring(cur_index, cur_index + 1);
g_text_line_width[line] += font_size;
}
text_write_width += font_size;
cur_index++;
}
else
{
line++;
if(line >= (page+1)*line_max_per_screen)//换一页
{
g_text_page_lines[page] += 1;
page++;
g_text_page_lines[page] = 0;
}
else
{
g_text_page_lines[page] += 1;
}
break;//写不下 换行
}
}
else
{
if((text_write_width + font_size/2) <= width_screen)
{
if(g_text_resrtcut_arry[line] == null)
{
g_text_resrtcut_arry[line] = row_txt_array.substring(cur_index, cur_index + 1);
g_text_line_width[line] = font_size/2;
}
else
{
g_text_resrtcut_arry[line] += row_txt_array.substring(cur_index, cur_index + 1);
g_text_line_width[line] += font_size/2;
}
text_write_width += font_size/2;
cur_index++;
}
else
{
line++;
if(line >= (page+1)*line_max_per_screen)//换一页
{
g_text_page_lines[page] += 1;
page++;
g_text_page_lines[page] = 0;
}
else
{
g_text_page_lines[page] += 1;
}
break;
}
}
}
if(cur_index >= row_txt_array.length)//文字取完
{
if(g_text_resrtcut_arry[line].length != 0)//如果最后一行不是空,但并没有完整的一行
{
g_text_page_lines[page] += 1;
}
return;//结束
}
}
}
}
}
function uint8arrayToBase64(u8Arr) {
let CHUNK_SIZE = 0x8000; //arbitrary number
let index = 0;
let length = u8Arr.length;
let result = '';
let slice;
while (index < length) {
slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length));
result += String.fromCharCode.apply(null, slice);
index += CHUNK_SIZE;
}
return btoa(result);
}
// //将图片二值化
function img_binarization(img_rgb_data)
{
var tmp = 0;
var j = 0,k = 0;
var bin_arry = new Uint8Array(img_rgb_data.data.length/32);
for(var i=0; i<img_rgb_data.data.length; i += 4)
{
tmp <<= 1;
if(img_rgb_data.data[i] == 255 && img_rgb_data.data[i+1] == 0 && img_rgb_data.data[i+2] == 0)//白色
{
tmp |= 1;
}
j++;
if(j == 8)
{
bin_arry[k] = tmp;
k++;
j=0;
}
}
var string = uint8arrayToBase64(bin_arry);
return string;
}
// //绘制垂直连续的文字画布,适用于立即显示、上移和下移
// //会改变全局txt_draw控件的值
function draw_vertical_continue_img(font_size,H_align,V_align,total_line_nums,total_pages,type,zoom)
{
txt_draw.setAttribute("width", width_screen*zoom);
txt_draw.setAttribute("height", total_pages*height_screen*zoom);
var cur_line = 0;
var x_offset = 0;
var y_offset = 0;
var yy_offset = 0;
var font_color = parseInt(f_color.value);
var font_type= font_type_ctl.value;
var font_style=parseInt(f_style.value);
var font_stretch=parseInt(f_stretch.value)
var font_stay = parseInt(p_pausetime.value)
var cxt = txt_draw.getContext("2d");
cxt.scale(zoom,zoom);
cxt.textBaseline = "middle"; //设置字体底线对齐绘制基线
cxt.font = "lighter " + font_size.toString() + "px "+font_parse;
var font_parse ='宋体'
if(font_type==1){
font_parse="宋体"
cxt.font = "lighter " + font_size.toString() + "px "+'宋体';
}else if(font_type==2){
font_parse="仿宋"
cxt.font = "lighter " + font_size.toString() + "px "+'仿宋';
}else if(font_type==3){
font_parse="黑体"
cxt.font = "lighter " + font_size.toString() + "px "+'黑体';
}else if(font_type==4){
font_parse="楷体"
cxt.font = "lighter " + font_size.toString() + "px "+'楷体';
}
// switch(font_type){
// case 1:font_parse="宋体"
// cxt.font = "lighter " + font_size.toString() + "px "+'宋体';break;
// case 2:font_parse="仿宋"
// cxt.font = "lighter " + font_size.toString() + "px "+'仿宋';break;
// case 3:font_parse="黑体"
// cxt.font = "lighter " + font_size.toString() + "px "+'黑体';break;
// default: font_parse="楷体"
// cxt.font = "lighter " + font_size.toString() + "px "+'楷体';
// }
// cxt.fillStyle = "rgba(255,0,0,1)";
//设置字体颜色
switch(font_color){
case 1: cxt.fillStyle="rgba(255,0,0,1)";break;
case 2: cxt.fillStyle="green";break;
case 3: cxt.fillStyle="yellow";break;
default:cxt.fillStyle="rgba(255,0,0,1)"
}
if(font_style==1){
cxt.font="bold "+ font_size.toString() + "px "+font_parse;
}else{
cxt.font="lighter"+ font_size.toString() + "px "+font_parse;
}
if(font_stretch==1){
var width= cxt.measureText(input_ctl.value).width/4
if(width <= 64){
cxt.scale(width,1.35,x_offset)
cxt.save()
}
}else if(font_stretch==2){
var width= cxt.measureText(input_ctl.value).width/80
cxt.scale(width,1.5,y_offset)
cxt.save()
}
if(font_stay===2){
clear_screen();
}else if(font_stay===4){
setTimeout(function(){
txt_draw.style='hidden="true"'
},3000);
}
function clear_screen(){
txt_draw.getContext("2d");
// // cxt.beginPath()
txt_draw.width=txt_draw.width;
}
if(type == 0)//上移
{
y_offset = font_size/2;
cxt.font="lighter"+ font_size.toString() + "px "+font_parse;
}
else//下移
{
y_offset = (total_pages-1)*height_screen+font_size/2;
cxt.font="lighter"+ font_size.toString() + "px "+font_parse;
}
for(var i=0; i<total_pages; i++)//总共有几个页面
{
yy_offset = height_screen-g_text_page_lines[i]*font_size;
yy_offset = (yy_offset < 0?0:yy_offset);
if(V_align == 1)//居上
{
yy_offset = 0;
}
else if(V_align == 2)//居中
{
yy_offset = yy_offset/2;
}
for(var j=0; j<g_text_page_lines[i]; j++)
{
if(g_text_resrtcut_arry[cur_line] == null)
{
break;
}
if(H_align == 1)//居左
{
x_offset = 0;
}
else if(H_align == 2)//居中
{
if(g_text_line_width[cur_line] < width_screen)
{
x_offset = (width_screen-g_text_line_width[cur_line])/2;
}
}
else//居右
{
if(g_text_line_width[cur_line] < width_screen)
{
x_offset = (width_screen-g_text_line_width[cur_line]);
}
}
cxt.fillText(g_text_resrtcut_arry[cur_line], x_offset, yy_offset+y_offset+j*font_size);
cur_line++;
}
if(type == 0)
{
y_offset += height_screen;
}
else
{
y_offset -= height_screen;
}
}
}
//绘制连续左移的文字画布,适用连续左移
//会改变全局txt_draw控件的值
function draw_scroll_img(font_size,zoom)
{
var x_width = g_text_line_width[0];
var x_offset = 0
var y_offset = 0;
txt_draw.setAttribute("width", x_width*zoom);
txt_draw.setAttribute("height", font_size*zoom);
var font_stretch=parseInt(f_stretch.value)
var cxt = txt_draw.getContext("2d");
cxt.scale(zoom,zoom);
var font_type = font_type_ctl.value;
var font_style = parseInt(f_style.value)
var font_color = parseInt(f_color.value)
cxt.font = "lighter " + font_size.toString() + "px "+font_charse;
cxt.textBaseline = "middle"; //设置字体底线对齐绘制基线
cxt.fillStyle="rgba(255,0,0,1)"
cxt.fillText(g_text_resrtcut_arry[0], 0,font_size/2);
var font_parse ='宋体'
if(font_type==1){
font_parse="宋体"
}else if(font_type==2){
font_parse="仿宋"
}else if(font_type==3){
font_parse="黑体"
}else if(font_type==4){
font_parse="楷体"
}
switch(font_color){
case 1: cxt.fillStyle="rgba(255,0,0,1)";break;
case 2: cxt.fillStyle="green";break;
case 3: cxt.fillStyle="yellow";break;
default:cxt.fillStyle="rgba(255,0,0,1)"
}
if(font_style==1){
cxt.font="bold"+ font_size.toString() + "px "+font_charse;
}else{
cxt.font="lighter"+ font_size.toString() + "px "+font_charse;
}
if(font_stretch==1){
var width= cxt.measureText(input_ctl.value).width/4
if(width <= 64){
cxt.scale(width,1.35,x_offset)
cxt.save()
}
}else if(font_stretch==2){
var width= cxt.measureText(input_ctl.value).width/80
if(width <= 64){
cxt.scale(width,1.5,y_offset)
cxt.save()
}
}
}
//绘制水平连续的文字画布,适用于左移和右移
function draw_horizontal_continue_img(font_size,H_align,V_align,total_line_nums,total_pages,type,zoom)
{
txt_draw.setAttribute("width", total_pages*width_screen*zoom);
txt_draw.setAttribute("height", height_screen*zoom);
var cur_line = 0;
var x_offset = 0;
var y_offset = 0;
var font_color = parseInt(f_color.value);
var font_type= font_type_ctl.value;
var font_style=parseInt(f_style.value);
var font_stretch=parseInt(f_stretch.value)
var cxt = txt_draw.getContext("2d");
cxt.scale(zoom,zoom);
cxt.font = "lighter" + font_size.toString() + "px "+font_charse;
cxt.textBaseline = "middle"; //设置字体底线对齐绘制基线
var font_parse ='宋体'
if(font_type==1){
font_parse="宋体"
}else if(font_type==2){
font_parse="仿宋"
}else if(font_type==3){
font_parse="黑体"
}else if(font_type==4){
font_parse="楷体"
}
// cxt.fillStyle = f_color.value;
//设置水平方向字体颜色
switch(font_color){
case 1: cxt.fillStyle="rgba(255,0,0,1)";break;
case 2: cxt.fillStyle="green";break;
case 3: cxt.fillStyle="yellow";break;
default:cxt.fillStyle="rgba(255,0,0,1)"
}
if(font_style==1){
cxt.font="bold"+ font_size.toString() + "px "+font_charse;
}else{
cxt.font="lighter"+ font_size.toString() + "px "+font_charse;
}
if(font_stretch==1){
var width= cxt.measureText(input_ctl.value).width
if(width <= 64){
cxt.scale(width,1.35,x_offset)
cxt.save()
}
}else if(font_stretch==2){
var width= cxt.measureText(input_ctl.value).width/80
if(width <= 64){
cxt.scale(width,1.5,y_offset)
cxt.save()
}
}
// //设置字体类型
// switch(font_type){
// case 1:
// cxt.font="宋体 24px"+"lighter";break;
// case 2:
// cxt.font="楷体 24px"+"lighter";break;
// case 3:
// cxt.font="黑体 24px"+"lighter";break;
// case 4:
// cxt.font="仿宋 24px"+"lighter";break;
// default:
// cxt.font="宋体 24px"+"lighter";
// }
if(type == 0)//上移
{
x_offset = 0;
cxt.font="lighter"+ font_size.toString() + "px "+font_charse;
}
else//下移
{
x_offset = (total_pages-1)*width_screen;
cxt.font="lighter"+ font_size.toString() + "px "+font_charse;
}
for(var i=0; i<total_pages; i++)
{
y_offset = height_screen-g_text_page_lines[i]*font_size;
y_offset = (y_offset < 0?0:y_offset);
if(V_align == 1)//居上
{
y_offset = 0;
}
else if(V_align == 2)//居中
{
y_offset = y_offset/2;
}
for(var j=0; j<g_text_page_lines[i]; j++)
{
if(g_text_resrtcut_arry[cur_line] == null)
{
break;
}
var xx_offset = 0;
if(H_align == 1)//居左
{
xx_offset = 0;
}
else if(H_align == 2)//居中
{
if(g_text_line_width[cur_line] < width_screen)
{
xx_offset = (width_screen-g_text_line_width[cur_line])/2;
}
}
else//居右
{
if(g_text_line_width[cur_line] < width_screen)
{
xx_offset = (width_screen-g_text_line_width[cur_line]);
}
}
cxt.fillText(g_text_resrtcut_arry[cur_line], x_offset+xx_offset, y_offset+j*font_size+font_size/2);
cur_line++;
}
if(type == 0)
{
x_offset += width_screen;
}
else
{
x_offset -= width_screen;
}
}
}
//动态创建画布,将预处理过的文字写入画布
function dynamic_draw_txt()
{
var font_int = parseInt(font_size_ctl.value);
var animation_int = parseInt(animation_type_ctl.value);
var H_align = parseInt(h_align_ctrl.value);
var V_align = parseInt(v_align_ctrl.value);
var total_line_nums = g_text_resrtcut_arry.length;
var total_pages = g_text_page_lines.length;
var font_type= font_type_ctl.value;
var font_size = parseInt(font_size_ctl.value);
// console.log(total_pages);
if(animation_int == 1 || animation_int==4 || animation_int == 5)//立即显示或者上移
{
//首先绘制放大倍数为1的图片用于底层显示然后再绘制预览使用的放大后的图片
var type = animation_int==5?1:0;
var cxt = txt_draw.getContext("2d");
draw_vertical_continue_img(font_int,H_align,V_align,total_line_nums,total_pages,type,1);
img_rgb_data = cxt.getImageData(0,0,txt_draw.width,txt_draw.height);
draw_vertical_continue_img(font_int,H_align,V_align,total_line_nums,total_pages,type,g_zoom_preview);
preview_img_data = new Image();
preview_img_data.src = txt_draw.toDataURL("../img/png");
var font_stretch=parseInt(f_stretch.value)
var y_offset = 0
var x_offset = 0
if(font_stretch==1){
var width= cxt.measureText(input_ctl.value).width
if(width <= 64){
cxt.scale(width,1.35,x_offset)
}
}else if(font_stretch==2){
var width= cxt.measureText(input_ctl.value).width/80
if(width <= 64){
cxt.scale(width,1.5,y_offset)
cxt.save()
}
}
// console.log("-------->rebuild preview img data");
}
else if(animation_int == 6)//连续左移
{
var cxt = txt_draw.getContext("2d");
draw_scroll_img(font_int,1);
img_rgb_data = cxt.getImageData(0,0,txt_draw.width,txt_draw.height);
draw_scroll_img(font_int,5);
preview_img_data = new Image();
preview_img_data.src = txt_draw.toDataURL("../img/png");
var font_style =parseInt(f_style.value)
var font_type = font_type_ctl.value
if(font_style==1){
cxt.font="bold "+ font_size.toString() + "px "+font_type;
}else{
cxt.font="lighter"+ font_size.toString() + "px "+font_type;
}
}
else if(animation_int == 2 || animation_int == 3)//左移或者右移
{
//TODO
var type = animation_int==2?0:1;
var cxt = txt_draw.getContext("2d");
draw_horizontal_continue_img(font_int,H_align,V_align,total_line_nums,total_pages,type,1);
img_rgb_data = cxt.getImageData(0,0,txt_draw.width,txt_draw.height);
draw_horizontal_continue_img(font_int,H_align,V_align,total_line_nums,total_pages,type,g_zoom_preview);
preview_img_data = new Image();
preview_img_data.src = txt_draw.toDataURL("../img/png");
if(font_style==1){
cxt.font="bold "+ font_size.toString() + "px "+font_type;
}else{
cxt.font="lighter"+ font_size.toString() + "px "+font_type;
}
}
if(font_stretch==1){
var width= cxt.measureText(input_ctl.value).width
if(width <= 64){
cxt.scale(width,1.35,x_offset)
}
}else if(font_stretch==2){
var width= cxt.measureText(input_ctl.value).width/80
if(width <= 64){
cxt.scale(width,1.5,y_offset)
cxt.save()
}
}
}
function draw_backgroud(width, height, scale) {
txt_preview.setAttribute("width", width*scale);
txt_preview.setAttribute("height", height*scale);
var cxt = txt_preview.getContext("2d");
cxt.fillStyle = "rgba(0,0,0,0.9)" //背景
cxt.fillRect(0, 0, width * scale, height * scale);
cxt.beginPath();
cxt.strokeStyle = 'rgba(255,255,255,0.3)'; //水平线条
for (var i = 0; i < height * scale; i += 1 * scale) {
cxt.moveTo(0, i);
cxt.lineTo(width * scale, i);
}
for (var i = 0; i < width * scale; i += 1 * scale) { //竖直线条
cxt.moveTo(i, 0);
cxt.lineTo(i, height * scale);
}
cxt.stroke();
var img = new Image();
img.src = txt_preview.toDataURL("../img/png");
return img;
}
var cur_page_pre = 0;
var page_init = 0;
var cur_y_offset = 0;
var cur_x_offset = 0;
var cur_line_pre = 0;
var max_offset = 0;
var timer = 0;
var font_size = parseInt(font_size_ctl.value);
var font_type=font_type_ctl.value;
var font_style=parseInt(f_style.value);
function drawFrame()
{
var animation = parseInt(animation_type_ctl.value);//动画方式
var cxt = txt_preview.getContext("2d");
if(animation == 1)//立即显示
{
// console.log("--->draw page,cur_page_pre=%d",cur_page_pre);
cxt.clearRect(0,0,width_screen*g_zoom_preview,height_screen*g_zoom_preview);
cxt.drawImage(back_ground_img,0,0);
cxt.drawImage(preview_img_data, 0,cur_page_pre*height_screen*g_zoom_preview, width_screen*g_zoom_preview, height_screen*g_zoom_preview, 0, 0, width_screen*g_zoom_preview, g_zoom_preview*height_screen);
}
else if(animation == 2)//左移
{
if(cur_x_offset < cur_page_pre*width_screen*g_zoom_preview)
{
cur_x_offset += 1*g_zoom_preview;
timer = setTimeout("drawFrame()",30);
}
cxt.clearRect(0,0,width_screen*g_zoom_preview,height_screen*g_zoom_preview);
cxt.drawImage(back_ground_img,0,0);
cxt.drawImage(preview_img_data, cur_x_offset, 0, width_screen*g_zoom_preview, height_screen*g_zoom_preview, 0, 0, width_screen*g_zoom_preview, g_zoom_preview*height_screen);
if(font_style==1){
cxt.font="bold "+ font_size.toString() + "px "+font_type;
}else{
cxt.font="lighter"+ font_size.toString() + "px "+font_type;
}
}
else if(animation == 3)//右移
{
if(cur_x_offset > cur_page_pre*width_screen*g_zoom_preview)
{
cur_x_offset -= 1*g_zoom_preview;
timer = setTimeout("drawFrame()",20);
}
cxt.clearRect(0,0,width_screen*g_zoom_preview,height_screen*g_zoom_preview);
cxt.drawImage(back_ground_img,0,0);
cxt.drawImage(preview_img_data, cur_x_offset, 0, width_screen*g_zoom_preview, height_screen*g_zoom_preview, 0, 0, width_screen*g_zoom_preview, g_zoom_preview*height_screen);
if(font_style==1){
cxt.font="bold "+ font_size.toString() + "px "+font_type;
}else if(font_style==0){
cxt.font="lighter"+ font_size.toString() + "px "+font_type;
}
}
else if(animation == 4)//上移
{
if(cur_y_offset < cur_page_pre*height_screen*g_zoom_preview)
{
cur_y_offset += 1*g_zoom_preview;
timer = setTimeout("drawFrame()",20);
}
cxt.clearRect(0,0,width_screen*g_zoom_preview,height_screen*g_zoom_preview);
cxt.drawImage(back_ground_img,0,0);
cxt.drawImage(preview_img_data, 0, cur_y_offset, width_screen*g_zoom_preview, height_screen*g_zoom_preview, 0, 0, width_screen*g_zoom_preview, g_zoom_preview*height_screen);
}
else if(animation == 5)//下移
{
if(cur_y_offset > cur_page_pre*height_screen*g_zoom_preview)
{
cur_y_offset -= 1*g_zoom_preview;
timer = setTimeout("drawFrame()",20);
}
cxt.clearRect(0,0,width_screen*g_zoom_preview,height_screen*g_zoom_preview);
cxt.drawImage(back_ground_img,0,0);
cxt.drawImage(preview_img_data, 0, cur_y_offset, width_screen*g_zoom_preview, height_screen*g_zoom_preview, 0, 0, width_screen*g_zoom_preview, g_zoom_preview*height_screen);
cxt.font="lighter"+ font_size.toString() + "px "+font_type;
}
else if(animation == 6)//连续左移
{
cxt.clearRect(0,0,width_screen*g_zoom_preview,height_screen*g_zoom_preview);
cxt.drawImage(back_ground_img,0,0);
cxt.drawImage(preview_img_data, cur_x_offset, 0, width_screen*g_zoom_preview, 32*g_zoom_preview, 0, 16*g_zoom_preview, width_screen*g_zoom_preview, 32*g_zoom_preview);
cur_x_offset += 2;
if(cur_x_offset > g_text_line_width[0]*g_zoom_preview)
{
cur_x_offset = 0;
}
timer = setTimeout("drawFrame()",30);
}
}
var scroll_run = 0;
var timer_task;
function animation_display()
{
var animation = parseInt(animation_type_ctl.value);//动画方式
if(typeof(g_text_page_lines) == undefined)
{
return;
}
var total_pages = g_text_page_lines.length;
if(animation == 1 || animation==4 || animation==5)//上下切换方式的
{
if(animation != 5)
{
cur_page_pre++;
if(cur_page_pre >= total_pages || page_init == 1)
{
cur_page_pre = 0;
cur_y_offset = 0;
}
}
else
{
cur_page_pre--;
if(cur_page_pre < 0 || page_init == 1)
{
cur_page_pre = total_pages-1;
cur_y_offset = (total_pages-1)*height_screen*g_zoom_preview;
}
}
clearTimeout(timer);
drawFrame();
}
else if(animation == 6)//连续左移
{
if(!scroll_run)
{
clearTimeout(timer);
drawFrame();
scroll_run = 1;
}
}
else if(animation == 2 || animation == 3)//左右切换方式的
{
if(animation == 2)
{
cur_page_pre++;
if(cur_page_pre >= total_pages || page_init == 1)
{
cur_page_pre = 0;
cur_x_offset = 0;
}
}
else
{
cur_page_pre--;
if(cur_page_pre < 0 || page_init == 1)
{
cur_page_pre = total_pages-1;
cur_x_offset = (total_pages-1)*height_screen*g_zoom_preview;
}
}
clearTimeout(timer);
drawFrame();
}
page_init = 0;
timer_task = setTimeout("animation_display()",3000);
}
function re_draw_screens()
{
restruct_input_text();
dynamic_draw_txt();
clearTimeout(timer_task);
page_init = 1;
timer_task = setTimeout("animation_display()",200);
}
window.onload = () => {
back_ground_img = draw_backgroud(width_screen, height_screen, 5);
re_draw_screens();
}
//将图片二值化
function img_binarization(img_rgb_data)
{
var tmp = 0;
var j = 0,k = 0;
var bin_arry = new Uint8Array(img_rgb_data.data.length/32);
for(var i=0; i<img_rgb_data.data.length; i += 4)
{
tmp <<= 1;
if(img_rgb_data.data[i] == 255 && img_rgb_data.data[i+1] == 0 && img_rgb_data.data[i+2] == 0)//白色
{
tmp |= 1;
}
j++;
if(j == 8)
{
bin_arry[k] = tmp;
k++;
j=0;
}
}
// console.log(bin_arry);
var string = uint8arrayToBase64(bin_arry);
console.log(string);
return string;
}
// input_ctl.onchange = () => {
// re_draw_screens();
// var img_string = img_binarization(img_rgb_data);
// // httpPost("img_data",img_string);
// }
input_ctl.onchange = () => {
re_draw_screens();
}
p_pausetime.onchange=()=>{
re_draw_screens();
}
f_color.onchange=()=>{
re_draw_screens();
}
font_size_ctl.onchange = () => {
re_draw_screens();
}
font_type_ctl.onchange = () => {
re_draw_screens();
}
f_style.onchange=()=>{
re_draw_screens();
}
f_stretch.onclick=()=>{
re_draw_screens();
}
h_align_ctrl.onchange = () => {
re_draw_screens();
}
v_align_ctrl.onchange = () => {
re_draw_screens();
}
animation_type_ctl.onchange = () => {
re_draw_screens();
}
// button_ctl.onclick= () => {
// var canvas_width = txt_draw.getAttribute("width")/g_zoom_preview;
// var canvas_height = txt_draw.getAttribute("height")/g_zoom_preview;
// var img_string = img_binarization(img_rgb_data);
// var post_string =
// `<data>${img_string}</data><animation>${animation_type_ctl.value}</animation><width>${canvas_width}</width><height>${canvas_height}<height>`;
// httpPost("data.json", post_string);
// console.log(post_string)
// return false
// }

282
public/web/js/data.js Normal file
View File

@ -0,0 +1,282 @@
$(function () {
var baseHost = document.location.origin
/*********************************************************登录页面数据提交**************************************************/
// $('#login').on('click', function () {
// var pwd = $('#pwd').val()
// var login = {}
// login.log_in = new Object()
// login.log_in.type = 1
// login.log_in.pass = pwd
// console.log(JSON.stringify(login))
// if (!pwd.trim().length) {
// $('.toast').css('display', 'flex')
// setTimeout(function () {
// $('.toast').css('display', 'none')
// }, 2000)
// return false
// }
// //1.创建ajax对象
// var xhr = new XMLHttpRequest()
// //2.连接服务器
// xhr.open('post', baseHost + '/log_in', true)
// //3.设置请求头信息
// xhr.setRequestHeader('content-type', 'application/json')
// //4.发送请求
// xhr.send(JSON.stringify(login));
// xhr.onreadystatechange = function () {
// if (xhr.readyState == 4 && xhr.status == 200) {
// //1.服务器返回的json格式数据
// var json = xhr.responseText
// console.log(JSON.stringify(json))
// //alert(xhr.responseText)
// /*2.
// *通过eval方法将上面的数据转换成json格式
// *上面数据的所有双引号全部转换成单引号
// */
// var result = eval("(" + json.replace(/"/g, "'") + ")")
// /* 3.转换成json格式后可以通过对象的方式进行访问既通过“.”的方式
// * 判断从服务器返回值中return是否等于0
// * 0密码正确 1密码错误
// */
// if (result.log_in.return == 0) {
// alert("登录成功!")
// window.location.href = "/screen_main.html"
// return
// }
// else {
// alert("登录失败!")
// return
// }
// }
// }
// })
/*********************************************************密码修改页面数据提交**************************************************/
// $('#submit').on('click', function () {
// var rawPwd = $('#raw_pass').val()
// var newPwd = $('#new_pwd').val()
// var rePwd = $('#pwdOK').val()
// var submit = {}
// submit.log_in = new Object()
// submit.log_in.type = 2
// submit.log_in.pass = rawPwd
// submit.log_in.new_pass = newPwd
// console.log(JSON.stringify(submit))
// if (!newPwd.trim().length || !rePwd.trim().length) {
// $('.toast').css('display', 'flex')
// setTimeout(function () {
// $('.toast').css('display', 'none')
// }, 2000)
// return false
// } else if (newPwd != rePwd) {
// alert('新密码与确认密码不一致')
// return false
// }
// //1.创建ajax对象
// var xhr = new XMLHttpRequest()
// xhr.open('post', baseHost + '/log_in', true)
// xhr.setRequestHeader('content-type', 'application/json')
// xhr.send(JSON.stringify(submit))
// xhr.onreadystatechange = function () {
// if (xhr.readyState == 4 && xhr.status == 200) {
// //1.服务器返回的json格式数据
// var json = xhr.responseText
// console.log(json)
// /*2.
// *通过eval方法将上面的数据转换成json格式
// *上面数据的所有双引号全部转换成单引号
// */
// var result = eval("(" + json.replace(/"/g, "'") + ")")
// /* 3.转换成json格式后可以通过对象的方式进行访问既通过“.”的方式
// * 判断从服务器返回值中return是否等于0
// * 0密码正确 1密码错误
// */
// if (result.log_in.return == 0) {
// alert("修改密码成功!")
// window.location.href = "/login.html"
// return
// }
// else {
// alert("修改密码失败!")
// return false
// }
// }
// }
// })
// //单击取消按钮,跳转至登录页面
// $("#reset").on('click', function () {
// window.location.href = '/login.html'
// })
/*********************************************************屏幕参数页面数据提交->读取数据**************************************************/
// function item_init(obj) {
// document.getElementById('sw').value = obj.screen_p.w
// document.getElementById('sh').value = obj.screen_p.h
// if (obj.screen_p.oe == 0 && obj.screen_p.data == 1) {
// document.getElementById('two-color').checked = "checked"
// } else {
// document.getElementById('mono').checked = "checked"
// }
// document.getElementById('srt').value = obj.screen_p.screen_angle
// }
// // read intial values
// fetch(`${baseHost}/p/get?`)
// //异步执行 避免数据没获取到等问题
// .then(function (response) {
// return response.json()
// })
// .then(function (state) {
// item_init(state)
// }).catch(function (arr) {
// console.log(arr)
// })
// $('#read').on('click', function () {
// fetch(`${baseHost}/p/get?`)
// //异步执行 避免数据没获取到等问题
// .then(function (response) {
// return response.json()
// })
// .then(function (state) {
// item_init(state)
// }).catch(function (arr) {
// console.log(arr)
// })
// })
/*********************************************************屏幕参数页面数据提交->设置数据**************************************************/
// $('#set').on('click', function () {
// var screen_width = parseInt($('#sw').val())
// var screen_height = parseInt($('#sh').val())
// var oecolor = $("input[type='radio']:checked").val()
// var screen_angle = parseInt($('#srt').val())
// var screen = {}
// screen.screen_p = new Object()
// //获取屏幕宽度、高度
// screen.screen_p.w = screen_width
// screen.screen_p.h = screen_height
// /*mono单色 two-color双色
// *如果oecolor==momo 输出oe极性为1 另一个值则为0
// */
// if (oecolor === "mono") {
// screen.screen_p.oe = 1
// screen.screen_p.data = 0
// } else {
// screen.screen_p.oe = 0
// screen.screen_p.data = 1
// }
// screen.screen_p.screen_angle = screen_angle
// console.log(JSON.stringify(screen))
// var xhr = new XMLHttpRequest()
// xhr.open('post', baseHost + '/p/set', true)
// xhr.setRequestHeader('content-type', 'application/json')
// xhr.send(JSON.stringify(screen))
// xhr.onreadystatechange = function () {
// if (xhr.readyState == 4 && xhr.status == 200) {
// var info = xhr.responseText
// if (info == "OK") {
// alert("屏幕参数设置成功!")
// }
// }
// }
// })
/*********************************************************屏幕操作指令**************************************************/
/*1.
*当type=1data1的值为1表示关闭屏幕值为2表示开启屏幕值为3时清除屏幕
*/
$('#start').on('click', function () {
var screen_start = {}
screen_start.cmd = new Object()
screen_start.cmd.type = 1
screen_start.cmd.data1 = 2
screen_start.cmd.data2 = 0
screen_start.cmd.data3 = 0
console.log(JSON.stringify(screen_start))
var xhr = new XMLHttpRequest()
xhr.open('POST', baseHost + '/cmd', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(JSON.stringify(screen_start))
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var info = xhr.responseText
if (info == "OK") {
alert("开启屏幕成功!")
}
}
}
// alert(JSON.stringify(screen_start))
})
//关闭屏幕
$('#close').on('click', function () {
var screen_close = {}
screen_close.cmd = new Object()
screen_close.cmd.type = 1
screen_close.cmd.data1 = 1
screen_close.cmd.data2 = 0
screen_close.cmd.data3 = 0
console.log(JSON.stringify(screen_close))
var xhr = new XMLHttpRequest()
xhr.open('POST', baseHost + '/cmd', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(JSON.stringify(screen_close))
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var info = xhr.responseText
if (info == "OK") {
alert("关闭屏幕成功!")
}
}
}
return false
})
//清除屏幕
$('#clear').on('click', function () {
var screen_clear = {}
screen_clear.cmd = new Object()
screen_clear.cmd.type = 1
screen_clear.cmd.data1 = 3
screen_clear.cmd.data2 = 0
screen_clear.cmd.data3 = 0
console.log(JSON.stringify(screen_clear))
var xhr = new XMLHttpRequest()
xhr.open('POST', baseHost + '/cmd', true)
xhr.send(JSON.stringify(screen_clear))
xhr.setRequestHeader('content-type', 'application/json')
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var info = xhr.responseText
if (info == "OK") {
alert("清除屏幕成功!")
}
}
}
return false
})
/*********************************************************模式选择 pattern**************************************************/
/*mode1:
mode2:双色屏幕 播放项为文字和图片
mode3:彩色屏幕
*
*/
$("#pattern1").on('click', function () {
var screen_pattern = {}
screen_pattern.cmd = new Object()
screen_pattern.cmd.mode = 1
var screen_start = {}
screen_start.cmd = new Object()
screen_start.cmd.type = 1
screen_start.cmd.data1 = 2
var xhr = new XMLHttpRequest()
xhr.open('POST', baseHost + '/cmd', true)
xhr.send(JSON.stringify(screen_pattern))
// xhr.setRequestHeader('content-type', 'application/json')
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var info = xhr.responseText
if (info == "OK") {
alert("接入屏幕成功!")
window.location.href = "/content.html"
return
}
}
}
})
})

2
public/web/js/jquery-3.4.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

5
public/web/js/jsonid.js Normal file
View File

@ -0,0 +1,5 @@
var json_id = 0;
localStorage.setItem("json_id", json_id);
if (json_id > 255) {
json_id = 0;
}

11401
public/web/js/mp3-engine.js Normal file

File diff suppressed because it is too large Load Diff

528
public/web/js/mp3.js Normal file
View File

@ -0,0 +1,528 @@
/*
mp3编码器需带上src/engine/mp3-engine.js引擎使用
https://github.com/xiangyuecn/Recorder
当然最佳推荐使用mp3wav格式代码也是优先照顾这两种格式
浏览器支持情况
https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
*/
(function(factory){
var browser=typeof window=="object" && !!window.document;
var win=browser?window:Object; //非浏览器环境Recorder挂载在Object下面
var rec=win.Recorder,ni=rec.i18n;
factory(rec,ni,ni.$T,browser);
}(function(Recorder,i18n,$T,isBrowser){
"use strict";
var SampleS="48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000";
var BitS="8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320";
Recorder.prototype.enc_mp3={
stable:true,takeEC:"full"
,getTestMsg:function(){
return $T("Zm7L::采样率范围:{1};比特率范围:{2}不同比特率支持的采样率范围不同小于32kbps时采样率需小于32000",0,SampleS,BitS);
}
};
var NormalizeSet=function(set){
var bS=set.bitRate, sS=set.sampleRate,s=sS;
if((" "+BitS+",").indexOf(" "+bS+",")==-1){
Recorder.CLog($T("eGB9::{1}不在mp3支持的取值范围{2}",0,"bitRate="+bS,BitS),3);
}
if((" "+SampleS+",").indexOf(" "+sS+",")==-1){//engine SmpFrqIndex函数会检测
var arr=SampleS.split(", "),vs=[];
for(var i=0;i<arr.length;i++) vs.push({v:+arr[i],s:Math.abs(arr[i]-sS)});
vs.sort(function(a,b){return a.s-b.s}); s=vs[0].v;
set.sampleRate=s;
Recorder.CLog($T("zLTa::sampleRate已更新为{1},因为{2}不在mp3支持的取值范围{3}",0,s,sS,SampleS),3);
}
};
var ImportEngineErr=function(){
return $T.G("NeedImport-2",["mp3.js","src/engine/mp3-engine.js"]);
};
//是否支持web worker
var HasWebWorker=isBrowser && typeof Worker=="function";
//*******标准UI线程转码支持函数************
Recorder.prototype.mp3=function(res,True,False){
var This=this,set=This.set,size=res.length;
if(!Recorder.lamejs){
False(ImportEngineErr()); return;
};
//优先采用worker编码非worker时用老方法提供兼容
if(HasWebWorker){
var ctx=This.mp3_start(set);
if(ctx){
if(ctx.isW){
This.mp3_encode(ctx,res);
This.mp3_complete(ctx,True,False,1);
return;
}
This.mp3_stop(ctx);
};
};
NormalizeSet(set);
//https://github.com/wangpengfei15975/recorder.js
//https://github.com/zhuker/lamejs bug:采样率必须和源一致不然8k时没有声音有问题fixhttps://github.com/zhuker/lamejs/pull/11
var mp3=new Recorder.lamejs.Mp3Encoder(1,set.sampleRate,set.bitRate);
var blockSize=57600;
var memory=new Int8Array(500000), mOffset=0;
var idx=0;
var run=function(){
try{
if(idx<size){
var buf=mp3.encodeBuffer(res.subarray(idx,idx+blockSize));
}else{
var buf=mp3.flush();
};
}catch(e){ //精简代码调用了abort
console.error(e);
False("MP3 Encoder: "+e.message);
return;
};
var bufLen=buf.length;
if(bufLen>0){
if(mOffset+bufLen>memory.length){
var tmp=new Int8Array(memory.length+Math.max(500000,bufLen));
tmp.set(memory.subarray(0, mOffset));
memory=tmp;
}
memory.set(buf,mOffset);
mOffset+=bufLen;
};
if(idx<size){
idx+=blockSize;
setTimeout(run);//尽量避免卡ui
}else{
var data=[memory.buffer.slice(0,mOffset)];
//去掉开头的标记信息帧
var meta=mp3TrimFix.fn(data,mOffset,size,set.sampleRate);
mp3TrimFixSetMeta(meta,set);
True(data[0]||new ArrayBuffer(0),"audio/mp3");
};
};
run();
}
//********边录边转码(Worker)支持函数,如果提供就代表可能支持,否则只支持标准转码*********
//全局共享一个Worker后台串行执行。如果每次都开一个新的编码速度可能会慢很多可能是浏览器运行缓存的因素并且可能瞬间产生多个并行操作占用大量cpu
var mp3Worker;
Recorder.BindDestroy("mp3Worker",function(){
if(mp3Worker){
Recorder.CLog("mp3Worker Destroy");
mp3Worker.terminate();
mp3Worker=null;
};
});
Recorder.prototype.mp3_envCheck=function(envInfo,set){//检查环境下配置是否可用
var errMsg="";
//需要实时编码返回数据,此时需要检查是否可实时编码
if(set.takeoffEncodeChunk){
if(!newContext()){//浏览器不能创建实时编码环境
errMsg=$T("yhUs::当前浏览器版本太低,无法实时处理");
};
};
if(!errMsg && !Recorder.lamejs){
errMsg=ImportEngineErr();
};
return errMsg;
};
Recorder.prototype.mp3_start=function(set){//如果返回null代表不支持
return newContext(set);
};
var openList={id:0};
var newContext=function(setOrNull,_badW){
//独立运行的函数scope.wkScope worker.onmessage 字符串会被替换
var run=function(e){
var ed=e.data;
var wk_ctxs=scope.wkScope.wk_ctxs;
var wk_lame=scope.wkScope.wk_lame;
var wk_mp3TrimFix=scope.wkScope.wk_mp3TrimFix;
var cur=wk_ctxs[ed.id];
if(ed.action=="init"){
wk_ctxs[ed.id]={
sampleRate:ed.sampleRate
,bitRate:ed.bitRate
,takeoff:ed.takeoff
,pcmSize:0
,memory:new Int8Array(500000), mOffset:0
,encObj:new wk_lame.Mp3Encoder(1,ed.sampleRate,ed.bitRate)
};
}else if(!cur){
return;
};
var addBytes=function(buf){
var bufLen=buf.length;
if(cur.mOffset+bufLen>cur.memory.length){
var tmp=new Int8Array(cur.memory.length+Math.max(500000,bufLen));
tmp.set(cur.memory.subarray(0, cur.mOffset));
cur.memory=tmp;
}
cur.memory.set(buf,cur.mOffset);
cur.mOffset+=bufLen;
};
switch(ed.action){
case "stop":
cur.encObj=null;
delete wk_ctxs[ed.id];
break;
case "encode":
cur.pcmSize+=ed.pcm.length;
try{
var buf=cur.encObj.encodeBuffer(ed.pcm);
}catch(e){ //精简代码调用了abort
cur.err=e;
console.error(e);
};
if(buf && buf.length>0){
if(cur.takeoff){
worker.onmessage({action:"takeoff",id:ed.id,chunk:buf});
}else{
addBytes(buf);
};
};
break;
case "complete":
try{
var buf=cur.encObj.flush();
}catch(e){ //精简代码调用了abort
cur.err=e;
console.error(e);
};
if(buf && buf.length>0){
if(cur.takeoff){
worker.onmessage({action:"takeoff",id:ed.id,chunk:buf});
}else{
addBytes(buf);
};
};
if(cur.err){
worker.onmessage({action:ed.action,id:ed.id
,err:"MP3 Encoder: "+cur.err.message});
break;
};
var data=[cur.memory.buffer.slice(0,cur.mOffset)];
//去掉开头的标记信息帧
var meta=wk_mp3TrimFix.fn(data,cur.mOffset,cur.pcmSize,cur.sampleRate);
worker.onmessage({
action:ed.action
,id:ed.id
,blob:data[0]||new ArrayBuffer(0)
,meta:meta
});
break;
};
};
var initOnMsg=function(isW){
worker.onmessage=function(e){
var data=e; if(isW)data=e.data;
var ctx=openList[data.id];
if(ctx){
if(data.action=="takeoff"){
//取走实时生成的mp3数据
ctx.set.takeoffEncodeChunk(new Uint8Array(data.chunk.buffer));
}else{
//complete
ctx.call&&ctx.call(data);
ctx.call=null;
};
};
};
};
var initCtx=function(){
var ctx={worker:worker,set:setOrNull};
if(setOrNull){
ctx.id=++openList.id;
openList[ctx.id]=ctx;
NormalizeSet(setOrNull);
worker.postMessage({
action:"init"
,id:ctx.id
,sampleRate:setOrNull.sampleRate
,bitRate:setOrNull.bitRate
,takeoff:!!setOrNull.takeoffEncodeChunk
,x:new Int16Array(5)//低版本浏览器不支持序列化TypedArray
});
}else{
worker.postMessage({
x:new Int16Array(5)//低版本浏览器不支持序列化TypedArray
});
};
return ctx;
};
var scope,worker=mp3Worker;
//非浏览器不支持worker或者开启失败使用UI线程处理
if(_badW || !HasWebWorker){
Recorder.CLog($T("k9PT::当前环境不支持Web Workermp3实时编码器运行在主线程中"),3);
worker={ postMessage:function(ed){ run({data:ed}); } };
scope={wkScope:{
wk_ctxs:{}, wk_lame:Recorder.lamejs, wk_mp3TrimFix:mp3TrimFix
}};
initOnMsg();
return initCtx();
};
try{
if(!worker){
//创建一个新Worker
var onmsg=(run+"").replace(/[\w\$]+\.onmessage/g,"self.postMessage");
onmsg=onmsg.replace(/[\w\$]+\.wkScope/g,"wkScope");
var jsCode=");wk_lame();self.onmessage="+onmsg;
jsCode+=";var wkScope={ wk_ctxs:{},wk_lame:wk_lame";
jsCode+=",wk_mp3TrimFix:{rm:"+mp3TrimFix.rm+",fn:"+mp3TrimFix.fn+"} }";
var lamejsCode=Recorder.lamejs.toString();
var url=(window.URL||webkitURL).createObjectURL(new Blob(["var wk_lame=(",lamejsCode,jsCode], {type:"text/javascript"}));
worker=new Worker(url);
setTimeout(function(){
(window.URL||webkitURL).revokeObjectURL(url);//必须要释放,不然每次调用内存都明显泄露内存
},10000);//chrome 83 file协议下如果直接释放将会使WebWorker无法启动
initOnMsg(1);
};
var ctx=initCtx(); ctx.isW=1;
mp3Worker=worker;
return ctx;
}catch(e){//出错了就不要提供了
worker&&worker.terminate();
console.error(e);
return newContext(setOrNull, 1);//切换到UI线程处理
};
};
Recorder.prototype.mp3_stop=function(startCtx){
if(startCtx&&startCtx.worker){
startCtx.worker.postMessage({
action:"stop"
,id:startCtx.id
});
startCtx.worker=null;
delete openList[startCtx.id];
//疑似泄露检测 排除id
var opens=-1;
for(var k in openList){
opens++;
};
if(opens){
Recorder.CLog($T("fT6M::mp3 worker剩{1}个未stop",0,opens),3);
};
};
};
Recorder.prototype.mp3_encode=function(startCtx,pcm){
if(startCtx&&startCtx.worker){
startCtx.worker.postMessage({
action:"encode"
,id:startCtx.id
,pcm:pcm
});
};
};
Recorder.prototype.mp3_complete=function(startCtx,True,False,autoStop){
var This=this;
if(startCtx&&startCtx.worker){
startCtx.call=function(data){
if(autoStop){
This.mp3_stop(startCtx);
};
if(data.err){
False(data.err);
}else{
mp3TrimFixSetMeta(data.meta,startCtx.set);
True(data.blob,"audio/mp3");
};
};
startCtx.worker.postMessage({
action:"complete"
,id:startCtx.id
});
}else{
False($T("mPxH::mp3编码器未start"));
};
};
//*******辅助函数************
/*lamejsmp3null
mp3Buffers=[ArrayBuffer,...]
length=mp3Buffers的数据二进制总长度
*/
Recorder.mp3ReadMeta=function(mp3Buffers,length){
//kill babel-polyfill ES6 Number.parseInt 不然放到Worker里面找不到方法也不能用typeof(x)==object 会被替换成 _typeof
var parseInt_ES3=typeof(window)!="undefined"&&window.parseInt||typeof(self)!="undefined"&&self.parseInt||parseInt;
var u8arr0=new Uint8Array(mp3Buffers[0]||[]);
if(u8arr0.length<4){
return null;
};
var byteAt=function(idx,u8){
return ("0000000"+((u8||u8arr0)[idx]||0).toString(2)).substr(-8);
};
var b2=byteAt(0)+byteAt(1);
var b4=byteAt(2)+byteAt(3);
if(!/^1{11}/.test(b2)){//未发现帧同步
return null;
};
var version=({"00":2.5,"10":2,"11":1})[b2.substr(11,2)];
var layer=({"01":3})[b2.substr(13,2)];//仅支持Layer3
var sampleRate=({ //lamejs -> Tables.samplerate_table
"1":[44100, 48000, 32000]
,"2":[22050, 24000, 16000]
,"2.5":[11025, 12000, 8000]
})[version];
sampleRate&&(sampleRate=sampleRate[parseInt_ES3(b4.substr(4,2),2)]);
var bitRate=[ //lamejs -> Tables.bitrate_table
[0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160] //MPEG 2 2.5
,[0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320]//MPEG 1
][version==1?1:0][parseInt_ES3(b4.substr(0,4),2)];
if(!version || !layer || !bitRate || !sampleRate){
return null;
};
var duration=Math.round(length*8/bitRate);
var frame=layer==1?384:layer==2?1152:version==1?1152:576;
var frameDurationFloat=frame/sampleRate*1000;
var frameSize=Math.floor((frame*bitRate)/8/sampleRate*1000);
//检测是否存在Layer3帧填充1字节。这里只获取第二帧的填充信息首帧永远没有填充。其他帧可能隔一帧出现一个填充或者隔很多帧出现一个填充目测是取决于frameSize未舍入时的小数部分因为有些采样率的frameSize会出现小数11025、22050、44100 典型的除不尽),然后字节数无法表示这种小数,就通过一定步长来填充弥补小数部分丢失
var hasPadding=0,seek=0;
for(var i=0;i<mp3Buffers.length;i++){
//寻找第二帧
var buf=mp3Buffers[i];
seek+=buf.byteLength;
if(seek>=frameSize+3){
var buf8=new Uint8Array(buf);
var idx=buf.byteLength-(seek-(frameSize+3)+1);
var ib4=byteAt(idx,buf8);
hasPadding=ib4.charAt(6)=="1";
break;
};
};
if(hasPadding){
frameSize++;
};
return {
version:version //1 2 2.5 -> MPEG1 MPEG2 MPEG2.5
,layer:layer//3 -> Layer3
,sampleRate:sampleRate //采样率 hz
,bitRate:bitRate //比特率 kbps
,duration:duration //音频时长 ms
,size:length //总长度 byte
,hasPadding:hasPadding //是否存在1字节填充首帧永远没有这个值其实代表的第二帧是否有填充并不代表其他帧的
,frameSize:frameSize //每帧最大长度含可能存在的1字节padding byte
,frameDurationFloat:frameDurationFloat //每帧时长,含小数 ms
};
};
//去掉lamejs开头的标记信息帧免得mp3解码出来的时长比pcm的长太多
var mp3TrimFix={//minfiy keep name
rm:Recorder.mp3ReadMeta
,fn:function(mp3Buffers,length,pcmLength,pcmSampleRate){
var meta=this.rm(mp3Buffers,length);
if(!meta){
return {err:"mp3 unknown format"};
};
var pcmDuration=Math.round(pcmLength/pcmSampleRate*1000);
//开头多出这么多帧移除掉正常情况下最多为2帧
var num=Math.floor((meta.duration-pcmDuration)/meta.frameDurationFloat);
if(num>0){
var size=num*meta.frameSize-(meta.hasPadding?1:0);//首帧没有填充第二帧可能有填充这里假设最多为2帧测试并未出现3帧以上情况其他帧不管就算出现了并且导致了错误后面自动容错
length-=size;
var arr0=0,arrs=[];
for(var i=0;i<mp3Buffers.length;i++){
var arr=mp3Buffers[i];
if(size<=0){
break;
};
if(size>=arr.byteLength){
size-=arr.byteLength;
arrs.push(arr);
mp3Buffers.splice(i,1);
i--;
}else{
mp3Buffers[i]=arr.slice(size);
arr0=arr;
size=0;
};
};
var checkMeta=this.rm(mp3Buffers,length);
if(!checkMeta){
//还原变更,应该不太可能会出现
arr0&&(mp3Buffers[0]=arr0);
for(var i=0;i<arrs.length;i++){
mp3Buffers.splice(i,0,arrs[i]);
};
meta.err="mp3 fix error: 已还原,错误原因不明"; //worker里面没$T翻译
};
var fix=meta.trimFix={};
fix.remove=num;
fix.removeDuration=Math.round(num*meta.frameDurationFloat);
fix.duration=Math.round(length*8/meta.bitRate);
};
return meta;
}
};
var mp3TrimFixSetMeta=function(meta,set){
var tag="MP3 Info: ";
if(meta.sampleRate&&meta.sampleRate!=set.sampleRate || meta.bitRate&&meta.bitRate!=set.bitRate){
Recorder.CLog(tag+$T("uY9i::和设置的不匹配{1},已更新成{2}",0,"set:"+set.bitRate+"kbps "+set.sampleRate+"hz","set:"+meta.bitRate+"kbps "+meta.sampleRate+"hz"),3,set);
set.sampleRate=meta.sampleRate;
set.bitRate=meta.bitRate;
};
var trimFix=meta.trimFix;
if(trimFix){
tag+=$T("iMSm::Fix移除{1}帧",0,trimFix.remove)+" "+trimFix.removeDuration+"ms -> "+trimFix.duration+"ms";
if(trimFix.remove>2){
meta.err=(meta.err?meta.err+", ":"")+$T("b9zm::移除帧数过多");
};
}else{
tag+=(meta.duration||"-")+"ms";
};
if(meta.err){
Recorder.CLog(tag,1,meta.err,meta);
}else{
Recorder.CLog(tag,meta);
};
};
}));

File diff suppressed because it is too large Load Diff

402
public/web/js/voice.html Normal file
View File

@ -0,0 +1,402 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="js/webView.js"></script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title reclang="XvFp">远程喊话</title>
<link rel="stylesheet" href="./css/voice_style.css">
<script>
var PageLM = "2023-12-08 20:41";
</script>
</head>
<body>
<script src="js/recorder.core.js"></script>
<script src="js/mp3.js"></script>
<script src="js/mp3-engine.js"></script>
<script src="js/MQTT_port.js"></script>
<!-- 【2】构建界面 Build the web interface -->
<div class="content">
<div class="record-container">
<button class="break_btn" onclick="return_function()">返回</button>
<div id="record-popup" class="record-popup" style="display: none;">
<!-- 录音动效和提示信息 -->
<div id="recording-animation" style="display: none;">录音中...</div>
<div id="cancel-tip" style="display: none;">松手发送</div>
</div>
<div id="voice-wave-animation" class="voice-line-wrap" style="display: none;">
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
</div>
<div class="voice-btn-wrap">
<button id="record-btn">喊话</button>
</div>
<audio id="audio-playback" controls style="display: none;"></audio>
</div>
</div>
<!-- 【3】实现录音逻辑 Implement recording logic -->
<script>
document.getElementById('record-btn').addEventListener('mousedown', recStart);
document.getElementById('record-btn').addEventListener('mouseup', recStop);
document.getElementById('record-btn').addEventListener("touchstart", recStart); // 移动端
document.getElementById('record-btn').addEventListener("touchend", recStop); // 移动端
//-----------------------------------------------------------------------//
var voice_reply_parse_fun;
function return_function() {
//location.href='screen_main.html';
window.history.go(-1);
}
function voice_reply_parse(json_str) {
let json = jQuery.parseJSON(json_str);
if ("sound_card" in json) {
switch (json.sound_card.state) {
case "succeed":
console.log("---succeed---");
break;
case "playing":
console.log("---playing---");
break;
case "downloadin":
console.log("---downloadin---");
break;
}
}
}
voice_reply_parse_fun = voice_reply_parse;
function send_voice_function(url, interrupt) {
var send_json = {};
send_json.online_play = new Object();
send_json.online_play.url = url;
if (interrupt) {
send_json.interrupt = interrupt;
}
var str = JSON.stringify(send_json);
console.log(str);
MQTT_json_send(str, "sound_card");
}
//-----------------------------------------------------------------------//
var rec, recBlob;
/**调用open打开录音请求好录音权限 Call open to open the recording and request the recording permission**/
function recOpen() {
//一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了
rec = null;
recBlob = null;
var newRec = Recorder({
type: "mp3",
sampleRate: 16000,
bitRate: 16, //mp3格式指定采样率hz、比特率kbps其他参数使用默认配置注意是数字的参数必须提供数字不要用字符串需要使用的type类型需提前把格式支持文件加载进来比如使用wav格式需要提前加载wav.js编码引擎
onProcess: function (
buffers,
powerLevel,
bufferDuration,
bufferSampleRate,
newBufferIdx,
asyncEnd
) {
//录音实时回调大约1秒调用12次本回调
// document.querySelector(".recpowerx").style.width=powerLevel+"%";
// document.querySelector(".recpowert").innerText=formatMs(bufferDuration,1)+" / "+powerLevel;
},
});
newRec.open(
function () {
//打开麦克风授权获得相关资源
rec = newRec;
},
function (msg, isUserNotAllow) {
//用户拒绝未授权或不支持
}
);
}
/**关闭录音,释放资源 Close recording, release resources**/
function recClose() {
if (rec) {
rec.close();
reclog(Html_$T("jqOs::已关闭"));
} else {
reclog(Html_$T("VOOw::未打开录音"), 1);
}
}
/**开始录音 Start recording**/
function recStart() {
// this.preventDefault();
//打开了录音后才能进行start、stop调用
if (rec && Recorder.IsOpen()) {
recBlob = null;
rec.start();
document.getElementById('voice-wave-animation').style.display = 'flex';
// 显示录音动效
document.getElementById('record-popup').style.display = 'block';
document.getElementById('recording-animation').style.display = 'block';
document.getElementById('cancel-tip').style.display = 'block';
} else {
}
}
/**结束录音,得到音频文件 Stop recording and get audio files**/
function recStop() {
if (!(rec && Recorder.IsOpen())) {
return;
}
rec.stop(
function (blob, duration) {
recBlob = blob;
let playAudio = document.getElementById("audio-playback");
// 将音频 URL 赋值给第二个 audio 元素
playAudio.src = (window.URL || webkitURL).createObjectURL(recBlob);
// send_voice_function(playAudio.src, 0);
// playAudio.play();
document.getElementById('voice-wave-animation').style.display = 'none';
document.getElementById('record-popup').style.display = 'none';
// 隐藏录音动效
document.getElementById('recording-animation').style.display = 'none';
document.getElementById('audio-playback').style.display = 'block';
recUpload();
},
function (msg) { }
);
}
/**播放 Play**/
function recPlay() {
if (!recBlob) {
reclog(Html_$T("tIke::请先录音,然后停止后再播放"), 1);
return;
}
let playAudio = document.getElementById("audioPlay");
// 将音频 URL 赋值给第二个 audio 元素
playAudio.src = (window.URL || webkitURL).createObjectURL(recBlob);
// send_voice_function(playAudio.src, 0);
playAudio.play();
setTimeout(function () {
(window.URL || webkitURL).revokeObjectURL(audio.src);
}, 5000);
}
function getQueryString(name) {
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
let r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(decodeURI(r[2]));
return null;
}
/**上传 Upload**/
function recUpload() {
var blob = recBlob;
if (!blob) {
reclog(Html_$T("DUTn::请先录音,然后停止后再上传"), 1);
return;
}
// 创建 FormData 对象
let formData = new FormData();
// 将 Blob 对象添加到 FormData 中,假设字段名为 'audioFile'
formData.append("file", blob, "recording.mp3");
// 发送 POST 请求到服务器
fetch("http://iot.pcpnb.cn/prod-api/iot/tool/upload", {
method: "POST",
headers: {
Authorization: getQueryString("token"),
},
body: formData,
})
.then((response) => {
console.log(response);
if (response.ok) {
return response.json(); // 或者 response.text() 如果服务器返回的是文本
}
throw new Error("Network response was not ok.");
})
.then((data) => {
console.log("Success:", data);
// 处理服务器返回的数据
send_voice_function("http://iot.pcpnb.cn/prod-api" + data.fileName, 99);
})
.catch((error) => {
console.error("Error:", error);
});
}
/**本地下载 Local download**/
function recLocalDown() {
if (!recBlob) {
reclog(Html_$T("M86h::请先录音,然后停止后再下载"), 1);
return;
}
var cls = ("a" + Math.random()).replace(".", "");
recdown64.lastCls = cls;
reclog(
Html_$T("vJPl::点击 ") +
'<span class="' +
cls +
'"></span>' +
Html_$T("Whtc:: 下载,或复制文本") +
"<button onclick=\"recdown64('" +
cls +
"')\">" +
Html_$T("XK4l::生成Base64文本") +
'</button><span class="' +
cls +
'_b64"></span>'
);
var fileName = "recorder-" + Date.now() + ".mp3";
var downA = document.createElement("A");
downA.innerHTML = Html_$T("g8Fy::下载 ") + fileName;
downA.href = (window.URL || webkitURL).createObjectURL(recBlob);
downA.download = fileName;
document.querySelector("." + cls).appendChild(downA);
if (/mobile/i.test(navigator.userAgent)) {
alert(
Html_xT(
Html_$T(
"DIEK::因移动端绝大部分国产浏览器未适配Blob Url的下载所以本demo代码在移动端未调用downA.click()。请尝试点击日志中显示的下载链接下载"
)
)
);
} else {
downA.click();
}
//不用了时需要revokeObjectURL否则霸占内存
//(window.URL||webkitURL).revokeObjectURL(downA.href);
}
function recdown64(cls) {
var el = document.querySelector("." + cls + "_b64");
if (recdown64.lastCls != cls) {
el.innerHTML =
'<span style="color:red">' +
Html_$T("eKKx::老的数据没有保存,只支持最新的一条") +
"</span>";
return;
}
var reader = new FileReader();
reader.onloadend = function () {
el.innerHTML = "<textarea></textarea>";
el.querySelector("textarea").value = reader.result;
};
reader.readAsDataURL(recBlob);
}
var formatMs = function (ms, all) {
var ss = ms % 1000;
ms = (ms - ss) / 1000;
var s = ms % 60;
ms = (ms - s) / 60;
var m = ms % 60;
ms = (ms - m) / 60;
var h = ms;
var t =
(h ? h + ":" : "") +
(all || h + m ? ("0" + m).substr(-2) + ":" : "") +
(all || h + m + s ? ("0" + s).substr(-2) + "″" : "") +
("00" + ss).substr(-3);
return t;
};
recOpen();
</script>
<!--以下这坨可以忽略 The following can be ignored-->
<script>
function reclog(s, color) { }
function Html_$T(s) {
return s;
}
</script>
<style>
body {
word-wrap: break-word;
background: #f5f5f5 center top no-repeat;
background-size: auto 680px;
}
pre {
white-space: pre-wrap;
}
a {
text-decoration: none;
color: #06c;
}
a:hover {
color: #f00;
}
.main {
max-width: 700px;
margin: 0 auto;
padding-bottom: 80px;
}
.mainBox {
margin-top: 12px;
padding: 12px;
border-radius: 6px;
background: #fff;
--border: 1px solid #f60;
box-shadow: 2px 2px 3px #aaa;
}
.btns button {
display: inline-block;
cursor: pointer;
border: none;
border-radius: 3px;
background: #f60;
color: #fff;
padding: 0 15px;
margin: 3px 20px 3px 0;
line-height: 36px;
height: 36px;
overflow: hidden;
vertical-align: middle;
}
.btns button:active {
background: #f00;
}
.pd {
padding: 0 0 6px 0;
}
.lb {
display: inline-block;
vertical-align: middle;
background: #00940e;
color: #fff;
font-size: 14px;
padding: 2px 8px;
border-radius: 99px;
}
.voice-btn-wrap button {
-ms-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
</style>
</body>
</html>

1
public/web/js/webView.js Normal file

File diff suppressed because one or more lines are too long

137
public/web/login.html Normal file
View File

@ -0,0 +1,137 @@
<!--
* @Descripttion:
* @version:
* @Author: Baron
* @Date: 2022-05-23 09:31:25
* @LastEditors: Andy
* @LastEditTime: 2022-10-13 14:16:35
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="max-age" content="31536000">
<meta http-equiv="Pragma" content="public">
<meta http-equiv="Cache-control" content="public">
<meta http-equiv="Cache" content="public">
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=0.01, maximum-scale=1, user-scalable=yes" />
<title>登录页面</title>
<link rel="stylesheet" href="css/style.css">
<!-- <link rel="stylesheet" href="css/common.css"> -->
<script src="js/jquery-3.4.1.min.js"></script>
<script> src = "js/jsonid.js"</script>
</head>
<body>
<!-- <div class="screen"> -->
<div class="login">
<ul class="login_ul">
<li class="active">登录 </li>
<li>
<input id="pwd" type="password" maxlength="10" placeholder="密码" /><br>
</li>
</ul>
<div class="login_checkbox">
<input type="checkbox" id="checkbox">
<label for="checkbox"></label>
<span for="checkbox">记住密码</span>
</div>
<a href="edit_pwd.html"><span class="login_span">修改密码</span></a>
<button class="login_btn" id="login">登录</button>
</div>
<div id="d" class="toast">
<span>密码不能为空</span>
</div>
<div id='a' class="toast">
<span>登录中....</span>
</div>
<div id="b" class="toast">
<span>登录失败</span>
</div>
<div id='c' class="toast">
<span>登录成功</span>
</div>
<!-- </div> -->
<script>
$(function () {
document.getElementById('pwd').value = localStorage.getItem('keyPass') || '';
if ((localStorage.getItem('keyPass') || '') !== '') {
document.getElementById('checkbox').setAttribute('checked', '');
}
//登录验证
var baseHost = document.location.origin
$('#login').on('click', function () {
var pwd = $('#pwd').val();
if (document.getElementById('checkbox').checked) {
localStorage.setItem('keyPass', pwd);
} else {
localStorage.setItem('keyPass', '');
}
var login = {}
// login.jsonid = json_id;
login = new Object()
login.log_in = new Object()
login.log_in.type = 1
login.log_in.pass = pwd
console.log(JSON.stringify(login))
if (!pwd.trim().length) {
$('#d').css('display', 'flex')
setTimeout(function () {
$('#d').css('display', 'none')
}, 2000)
return false
}
//1.创建ajax对象
var xhr = new XMLHttpRequest()
//2.连接服务器
xhr.open('post', baseHost + '/communication', true)
//3.设置请求头信息
xhr.setRequestHeader('content-type', 'application/json')
//4.发送请求
xhr.send(JSON.stringify(login));
$('#a').css('display', 'flex');
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
//1.服务器返回的json格式数据
var json = xhr.responseText
console.log(JSON.stringify(json))
//alert(xhr.responseText)
/*2.
*通过eval方法将上面的数据转换成json格式
*上面数据的所有双引号全部转换成单引号
*/
var result = eval("(" + json.replace(/"/g, "'") + ")")
/* 3.转换成json格式后可以通过对象的方式进行访问既通过“.”的方式
* 判断从服务器返回值中return是否等于0
* 0密码正确 1密码错误
*/
if (result.led_protocol.log_in.return == 0) {
$('#a').css('display', 'none');
$('#c').css('display', 'flex');
setTimeout(function () {
$('#c').css('display', 'none')
}, 500)
window.location.href = "/screen_main.html"
return
} else {
$('#a').css('display', 'none');
$('#b').css('display', 'flex');
setTimeout(function () {
$('#b').css('display', 'none')
}, 500)
return
}
}
}
})
})
</script>
</body>
</html>

502
public/web/screen_main.html Normal file
View File

@ -0,0 +1,502 @@
<!--
* @Descripttion:
* @version:
* @Author: Baron
* @Date: 2022-07-06 10:00:11
* @LastEditors: Andy
* @LastEditTime: 2024-06-25 11:46:20
-->
<!DOCTYPE html>
<html lang="en" manifest="demo.appcache">
<head>
<script type="text/javascript" src="js/webView.js"></script>
<meta charset="UTF-8">
<meta http-equiv="max-age" content="31536000">
<meta http-equiv="Pragma" content="public">
<meta http-equiv="Cache-control" content="public">
<meta http-equiv="Cache" content="public">
<title>我的LED屏</title>
<link rel="stylesheet" href="css/style.css">
<!-- <link rel="stylesheet" href="css/common.css"> -->
<link rel="stylesheet" href="css/content.css">
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=0.01, maximum-scale=1, user-scalable=yes" />
<link rel="prefetch" href="screen_program.html">
<link rel="prefetch" href="screen_par.html">
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/MQTT_port.js"></script>
<!-- <script src="js/utils.js"></script> -->
<script> src = "js/jsonid.js"</script>
<!-- <script src="https://cdn.bootcss.com/vConsole/3.3.4/vconsole.min.js"></script> -->
</head>
<body>
<div class="contain">
<!-- 屏幕参数设置头部 -->
<!-- <header>
<div class="screen">
<ul class="tag">
<li>
<a href="content.html"><img src="img/content.png"/><span>内容编辑</span></a>
</li>
<li>
<a href="screen_pro.html"><img src="img/setting.png" alt=""><span>功能设置</span></a>
</li>
</ul>
</div>
</header> -->
<!-- <hr/> -->
<!-- 屏幕中部区域 -->
<div class="keys_div">
<article class="midart">
<ul class="tag_control">
<li class="control_li" onclick="location.href='screen_par.html'">
<img src="img/compicon.png" /><span>屏参</span>
</li>
<li class="control_li" onclick="location.href='screen_program.html' ">
<img src="img/compicon.png" /><span>节目</span>
</li>
<li class="control_li" id="luminance">
<img src="img/ld.png" /><span>屏幕亮度</span>
</li>
<li class="control_li" onclick="location.href='screen_virtual.html' ">
<img src="img/compicon.png" /><span>虚拟遥控器</span>
</li>
<li class="control_li" id="start">
<img src="img/compicon.png" /><span>开启屏幕</span>
</li>
<li class="control_li" id="close">
<img src="img/compicon.png" /><span>关闭屏幕</span>
</li>
<li class="control_li" id="clear">
<img src="img/compicon.png" /><span>清除屏幕</span>
</li>
<li class="control_li" id="other">
<img src="img/compicon.png" /><span>开机参数</span>
</li>
<li class="control_li">
<a onclick="navigateToVueHome()">
<img src="img/compicon.png" /><span>返回主页</span>
</a>
</li>
</ul>
</article>
</div>
<div class="version">
<p id="version">版本号 V1.0.0</p>
</div>
<!-- 添加节目弹窗 开始 -->
<div class="ground" id="Ground"></div>
<div class="my_contain" id="popup">
<div class="screen_box">
<h1>亮度设置</h1>
<div id="my_luminance" class="my_luminance">
<select id="luminance_select">
<option value="1">1%</option>
<option value="3">3%</option>
<option value="5">5%</option>
<option value="10">10%</option>
<option value="15">15%</option>
<option value="20">20%</option>
<option value="30">30%</option>
<option value="40">40%</option>
<option value="50">50%</option>
<option value="60">60%</option>
<option value="70">70%</option>
<option value="80">80%</option>
<option value="90">90%</option>
<option selected value="100">100%</option>
</select>
</div>
<button name="submit" id="new_program">确定</button><br>
<button name="cancel" id="cancel">返回</button>
</div>
</div>
<div class="my_contain my_contain2" id="power_on">
<div class="screen_box">
<h1>开机参数</h1>
<div class="card_item">
<p>开机界面</p>
<div class="data_div">
<select id="power_on1">
<option selected value=1>开启</option>
<option value=0>关闭</option>
</select>
</div>
</div>
<div class="card_item">
<p>重置开关</p>
<div class="data_div">
<select id="power_on2">
<option selected value=1>开启</option>
<option value=0>关闭</option>
</select>
</div>
</div>
<button name="submit" id="confirm2">确定</button><br>
<button name="cancel" id="cancel2">返回</button>
</div>
</div>
<!-- 添加节目弹窗 end -->
<!-- <footer>
<div class="logo">
<img src="img/logo.png" alt="">
</div>
<p>&copy;copyright 2022</p>
</footer> -->
<div id="result_prompt_txt" class="toast">
<span>结果内容</span>
</div>
</div>
<script>
json_id = localStorage.getItem("json_id");
var cmd_reply_parse_fun;
$(function () {
var baseHost = document.location.origin
//mode 提示消息显示模式(0关闭 1显示 3显示特定时间) txt显示内容
function result_prompt_display(mode, txt) {
document.getElementById("result_prompt_txt").getElementsByTagName("span")[0].innerHTML = txt;
if (mode == 0) {
$("#result_prompt_txt").css("display", "none");
} else if (mode == 1) {
$("#result_prompt_txt").css("display", "flex");
} else {
$("#result_prompt_txt").css("display", "flex");
setTimeout(function () {
$("#result_prompt_txt").css("display", "none");
}, 500);
}
}
function cmd_reply_parse(json_str) {
result_prompt_display(0, "");
let json = jQuery.parseJSON(json_str);
if ("cmd_ok" in json.led_protocol) {
switch (json.led_protocol.cmd_ok.type) {
case 1:
result_prompt_display(2, "屏幕操作成功");
break;
case 2:
result_prompt_display(2, "亮度设置成功");
break;
case 3:
result_prompt_display(2, "开机参数设置成功");
break;
}
}
else if ("cmd" in json.led_protocol) {
switch (json.led_protocol.cmd.type) {
case 2:
luminance_init(json);
break;
case 3:
power_on_init(json);
break;
case 4:
version_init(json);
break;
}
}
}
cmd_reply_parse_fun = cmd_reply_parse;
function get_cmd_function(_type) {
var screen_start = {}
// screen_start.jsonid = json_id;
screen_start = new Object()
screen_start.get_cmd = new Object()
screen_start.get_cmd.type = _type
var str = JSON.stringify(screen_start);
// 设置超时逻辑
var timeoutId = setTimeout(function () {
result_prompt_display(2, "数据获取失败");
}, 10000); // 10秒超时
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
cmd_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "数据获取失败");
}
}
}
}
else {
MQTT_send(str);
}
json_id++;
localStorage.setItem("json_id", json_id);
}
/*********************************************************亮度滑动条**************************************************/
/*点击弹出按钮*/
function popBox() {
//stop();
document.getElementById("popup").style.display = "block";
document.getElementById("Ground").style.display = "block";
};
/*点击关闭弹窗*/
function closeBox() {
//move();
document.getElementById("popup").style.display = "none";
document.getElementById("Ground").style.display = "none";
}
/*点击弹出按钮*/
function power_on_popBox() {
//stop();
document.getElementById("power_on").style.display = "block";
document.getElementById("Ground").style.display = "block";
};
/*点击关闭弹窗*/
function power_on_closeBox() {
//move();
document.getElementById("power_on").style.display = "none";
document.getElementById("Ground").style.display = "none";
}
function luminance_init(obj) {
document.getElementById('luminance_select').value = obj.led_protocol.cmd.data1
}
function power_on_init(obj) {
document.getElementById('power_on1').value = obj.led_protocol.cmd.data1
document.getElementById('power_on2').value = obj.led_protocol.cmd.data2
}
$('#other').on('click', function () {
power_on_popBox();
get_cmd_function(3);
})
$('#cancel2').on('click', function () {
power_on_closeBox();
})
$('#confirm2').on('click', function () {
var screen_start = {}
// screen_start.jsonid = json_id;
screen_start = new Object()
screen_start.cmd = new Object()
screen_start.cmd.type = 3
screen_start.cmd.data1 = parseInt($('#power_on1').find('option:selected').val());
screen_start.cmd.data2 = parseInt($('#power_on2').find('option:selected').val());
screen_start.cmd.data3 = 0;
var str = JSON.stringify(screen_start);
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
cmd_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "开机参数设置失败");
}
}
}
}
else {
MQTT_send(str);
}
json_id++;
localStorage.setItem("json_id", json_id);
})
$('#luminance').on('click', function () {
popBox();
get_cmd_function(2);
})
$('#cancel').on('click', function () {
closeBox();
})
$('#new_program').on('click', function () {
var screen_start = {};
// screen_start.jsonid = json_id;
screen_start = new Object()
screen_start.cmd = new Object();
screen_start.cmd.type = 2;
screen_start.cmd.data1 = parseInt($('#luminance_select').find('option:selected').val());
screen_start.cmd.data2 = 0;
screen_start.cmd.data3 = 0;
var str = JSON.stringify(screen_start);
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
cmd_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "亮度设置失败");
}
}
}
}
else {
MQTT_send(str);
}
json_id++;
localStorage.setItem("json_id", json_id);
})
function luminance_refresh() {
var val = $('#luminance_select').find('option:selected').val();
$('.my_luminance').append("<style>.my_luminance::before{width: " + val + "%;}</style>");
}
window.setInterval(luminance_refresh, 100);
function version_init(obj) {
document.getElementById('version').innerHTML = "版本号 V" + obj.led_protocol.cmd.data1 + "." + obj.led_protocol.cmd.data2 +
"." + obj.led_protocol.cmd.data3
}
// $(function () {
// get_cmd_function(4);
// })
$(function () {
if (/xazn/.test(navigator.userAgent)||/uni-app/.test(navigator.userAgent)) {
// 在App中
document.addEventListener("UniAppJSBridgeReady", function () {
get_cmd_function(4);
});
} else {
get_cmd_function(4);
}
})
/*********************************************************屏幕操作指令**************************************************/
/*1.开启屏幕
*当type=1时data1的值为1表示关闭屏幕、值为2表示开启屏幕、值为3时清除屏幕
*/
$('#start').on('click', function () {
var screen_start = {};
// screen_start.jsonid = json_id;
screen_start = 102;
screen_start = new Object()
screen_start.cmd = new Object();
screen_start.cmd.type = 1;
screen_start.cmd.data1 = 2;
screen_start.cmd.data2 = 0;
screen_start.cmd.data3 = 0;
var str = JSON.stringify(screen_start);
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
cmd_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "开启屏幕失败");
}
}
}
}
else {
MQTT_send(str);
}
json_id++;
localStorage.setItem("json_id", json_id);
})
//关闭屏幕
$('#close').on('click', function () {
var screen_close = {};
// screen_close.jsonid = json_id;
screen_close = new Object()
screen_close.cmd = new Object();
screen_close.cmd.type = 1;
screen_close.cmd.data1 = 1;
screen_close.cmd.data2 = 0;
screen_close.cmd.data3 = 0;
var str = JSON.stringify(screen_close);
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
cmd_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "关闭屏幕失败");
}
}
}
}
else {
MQTT_send(str);
}
json_id++;
localStorage.setItem("json_id", json_id);
return false
})
//清除屏幕
$('#clear').on('click', function () {
var flag = confirm("更改屏参后会清空节目")
if (flag == 1) {
var screen_clear = {};
// screen_clear.jsonid = json_id;
screen_clear = new Object()
screen_clear.cmd = new Object();
screen_clear.cmd.type = 1;
screen_clear.cmd.data1 = 3;
screen_clear.cmd.data2 = 0;
screen_clear.cmd.data3 = 0;
var str = JSON.stringify(screen_clear);
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
cmd_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "清除屏幕失败");
}
}
}
}
else {
MQTT_send(str);
}
}
return false
})
})
function navigateToVueHome() {
window.location.href='../';
}
</script>
</body>
</html>

301
public/web/screen_par.html Normal file
View File

@ -0,0 +1,301 @@
<!--
* @Descripttion:
* @version:
* @Author: Eugene
* @Date: 2022-05-23 09:31:25
* @LastEditors: Andy
* @LastEditTime: 2024-03-23 18:41:30
-->
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="js/webView.js"></script>
<meta charset="UTF-8">
<meta http-equiv="max-age" content="31536000">
<meta http-equiv="Pragma" content="public">
<meta http-equiv="Cache-control" content="public">
<meta http-equiv="Cache" content="public">
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=0.01, maximum-scale=1, user-scalable=yes" />
<title>屏幕参数</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/common.css">
<link rel="prefetch" href="content_pattern1.html">
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/MQTT_port.js"></script>
<script src="js/jsonid.js"></script>
</head>
<body>
<div class="contain">
<header>
<span><a href="screen_main.html">&lt;返回</a></span>
</header>
<div class="box">
<!-- <form action="content.html" method="post"> -->
<ul>
<li>
<label>屏幕模板:</label>
<select id="template">
<option selected="selected" value="0">自定义</option>
<option value="1">伸缩屏</option>
<option value="2">大屏</option>
<option value="3">小屏</option>
</select>
</li>
<li>
<label>OE极性</label>
<select id="oe_polarity">
<option value="0">0</option>
<option selected="selected" value="1">1</option>
</select>
</li>
<li>
<label>DATA极性</label>
<select id="data_polarity">
<option value="0">0</option>
<option selected="selected" value="1">1</option>
</select>
</li>
<li>
<label>屏宽:</label>
<input type="number" name="screenwidth" placeholder="请输入数值" id="sw">
</li>
<li>
<label>屏高:</label>
<input type="number" name="screenheight" placeholder="请输入数值" id="sh">
</li>
<!-- <li>
<label>色彩:</label>
<input type="radio" name="screencolor" id="mono" checked="checked" value="mono"><label
for="mono">单色</label>
<input type="radio" name="screencolor" id="two-color" value="two-color"><label
for="two-color">双色</label>
</li> -->
<li>
<label>屏幕旋转:</label>
<select name="screenrotate" id="srt">
<option selected="selected" value="0">0度</option>
<option value="90">90度</option>
<option value="180">180度</option>
<option value="270">270度</option>
</select>
</li>
</ul>
<button name="submit" id="read">读取</button><br>
<input type="submit" id="set" value="设置"></button>
<!-- </form> -->
</div>
</div>
<footer>
<ul>
<li><a href="screen_main.html">首页</a></li>
<li><a class="active" href="screen_par.html">屏参</a></li>
<li><a href="screen_program.html">节目管理</a></li>
<li><a href="#">联系我们</a></li>
</ul>
<div style="height:80px" hidden="hidden"></div>
</footer>
</div>
<div id="result_prompt_txt" class="toast">
<span>结果内容</span>
</div>
<script>
json_id = localStorage.getItem("json_id");
var screen_par_reply_parse_fun;
/*********************************************************屏幕参数页面数据提交->读取数据**************************************************/
var baseHost = document.location.origin
//mode 提示消息显示模式(0关闭 1显示 3显示特定时间) txt显示内容
function result_prompt_display(mode, txt) {
document.getElementById("result_prompt_txt").getElementsByTagName("span")[0].innerHTML = txt;
if (mode == 0) {
$("#result_prompt_txt").css("display", "none");
} else if (mode == 1) {
$("#result_prompt_txt").css("display", "flex");
} else {
$("#result_prompt_txt").css("display", "flex");
setTimeout(function () {
$("#result_prompt_txt").css("display", "none");
}, 500);
}
}
function item_init(obj) {
document.getElementById('sw').value = obj.screen_p.w
document.getElementById('sh').value = obj.screen_p.h
document.getElementById('oe_polarity').value = obj.screen_p.oe
document.getElementById('data_polarity').value = obj.screen_p.data
// if (obj.screen_p.oe == 0 && obj.screen_p.data == 1) {
// document.getElementById('two-color').checked = "checked"
// } else {
// document.getElementById('mono').checked = "checked"
// }
document.getElementById('srt').value = obj.screen_p.screen_angle
}
function screen_par_reply_parse(json_str) {
let json = jQuery.parseJSON(json_str);
if ("screen_p" in json.led_protocol) {
item_init(json.led_protocol);
result_prompt_display(2, "获取屏幕参数成功");
}
else if ("screen_ok" in json.led_protocol) {
del_all_icon();
result_prompt_display(2, "设置屏幕参数成功");
}
}
screen_par_reply_parse_fun = screen_par_reply_parse;
function get_screen_parameter() {
var screen_start = {};
// screen_start.jsonid = json_id;
screen_start = new Object()
screen_start.get_screen = 1;
var str = JSON.stringify(screen_start);
console.log(str);
result_prompt_display(1, "获取中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
screen_par_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "获取屏幕参数失败");
}
}
}
}
else {
MQTT_send(str);
}
json_id++;
localStorage.setItem("json_id", json_id);
}
$(function () {
if (/xazn/.test(navigator.userAgent)||/uni-app/.test(navigator.userAgent)) {
// 在App中
document.addEventListener("UniAppJSBridgeReady", function () {
get_screen_parameter();
$('#read').on('click', function () {
get_screen_parameter();
})
});
} else {
get_screen_parameter();
$('#read').on('click', function () {
get_screen_parameter();
})
}
})
// $(function () {
// get_screen_parameter();
// $('#read').on('click', function () {
// get_screen_parameter();
// })
// })
$("#template").on("change", function () {
if (document.getElementById("template").value == "1") {
document.getElementById('sw').value = 64;
document.getElementById('sh').value = 32;
// document.getElementById('mono').checked = "checked";
document.getElementById('srt').value = 270;
}
else if (document.getElementById("template").value == "2") {
document.getElementById('sw').value = 64;
document.getElementById('sh').value = 32;
// document.getElementById('mono').checked = "checked";
document.getElementById('srt').value = 180;
}
else if (document.getElementById("template").value == "3") {
document.getElementById('sw').value = 64;
document.getElementById('sh').value = 16;
// document.getElementById('mono').checked = "checked";
document.getElementById('srt').value = 0;
}
})
/*********************************************************屏幕参数页面数据提交->设置数据**************************************************/
function del_all_icon() {
let manage = {};
// manage.jsonid = json_id;
manage = new Object()
manage.pro_manage = new Object();
manage.pro_manage.type = 2;
manage.pro_manage.data = -1;
var str = JSON.stringify(manage);
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log("删除全部节目");
}
}
}
}
else {
MQTT_send(str);
}
json_id++;
localStorage.setItem("json_id", json_id);
}
$('#set').on('click', function () {
// var flag = confirm("更改屏参后会清空节目");
if (1) {
var screen_width = parseInt($('#sw').val())
var screen_height = parseInt($('#sh').val())
var oecolor = $("input[type='radio']:checked").val()
var screen_angle = parseInt($('#srt').val())
var screen = {}
// screen.jsonid = json_id;
screen = new Object()
screen.screen_p = new Object()
//获取屏幕宽度、高度
screen.screen_p.w = screen_width
screen.screen_p.h = screen_height
/*mono单色 two-color双色
*如果oecolor==momo 输出oe极性为1 另一个值则为0
*/
// if (oecolor === "mono") {
// screen.screen_p.oe = 1
// screen.screen_p.data = 0
// } else {
// screen.screen_p.oe = 0
// screen.screen_p.data = 1
// }
screen.screen_p.oe = parseInt($('#oe_polarity').val())
screen.screen_p.data = parseInt($('#data_polarity').val())
screen.screen_p.screen_angle = screen_angle;
let str = JSON.stringify(screen);
console.log(str);
result_prompt_display(1, "设置中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
screen_par_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "设置失败");
}
}
}
}
else {
MQTT_send(str);
}
json_id++;
localStorage.setItem("json_id", json_id);
}
})
</script>
</body>
</html>

View File

@ -0,0 +1,460 @@
<!--
* @Descripttion:
* @version:
* @Author: Eugene
* @Date: 2022-07-18 15:56:54
* @LastEditors: Andy
* @LastEditTime: 2024-06-25 14:11:05
-->
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="js/webView.js"></script>
<meta charset="UTF-8">
<meta http-equiv="max-age" content="31536000">
<meta http-equiv="Pragma" content="public">
<meta http-equiv="Cache-control" content="public">
<meta http-equiv="Cache" content="public">
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=0.01, maximum-scale=1, user-scalable=yes" />
<title>我的节目页面</title>
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/content.css">
<link rel="stylesheet" href="css/style.css">
<link rel="prefetch" href="content_pattern1.html">
<link rel="prefetch" href="screen_main.html">
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/MQTT_port.js"></script>
<script> src = "js/jsonid.js"</script>
</head>
</head>
<body>
<div class="contain">
<div class="screen">
<div class="item_list">
<p>节目列表</p>
<div class="pro">
<p class="list">
</p>
</div>
<div class="pro_right">
<div class="pro_icon">
<span><img name="delete_n" id="delete1" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set1" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch1" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<!-- <div class="clear"></div> -->
<div class="pro_icon">
<span><img name="delete_n" id="delete2" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set2" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch2" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<!-- <div class="clear"></div> -->
<div class="pro_icon">
<span><img name="delete_n" id="delete3" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set3" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch3" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<div class="pro_icon">
<span><img name="delete_n" id="delete4" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set4" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch4" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<div class="pro_icon">
<span><img name="delete_n" id="delete5" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set5" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch5" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<div class="pro_icon">
<span><img name="delete_n" id="delete6" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set6" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch6" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<div class="pro_icon">
<span><img name="delete_n" id="delete7" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set7" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch7" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<div class="pro_icon">
<span><img name="delete_n" id="delete8" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set8" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch8" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<div class="pro_icon">
<span><img name="delete_n" id="delete9" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set9" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch9" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
<div class="pro_icon">
<span><img name="delete_n" id="delete10" src="img/delete.png" alt=""></span>
<span><img name="setting" id="set10" src="img/setting.png" alt=""></span>
<input name="switch_n" id="switch10" class="bs_switch" type="checkbox" data-on="ON"
data-off="OFF" checked="">
</div>
</div>
</div>
<div class="clear"></div>
<article class="pro_insert">
<ul class="pro_bottom">
<li class="pro_li">
<a href="screen_main.html"><img id="home" src="img/home.png" alt=""><span
id="home">返回</span></a>
</li>
<li class="pro_li">
<img id="insert" src="img/insert.png" alt=""><span id="insert">添加</span>
</li>
<li class="pro_li">
<img id="refresh" src="img/refresh.png" alt=""><span id="refresh">刷新</span>
</li>
</ul>
</article>
</div>
<!-- 添加节目弹窗 开始 -->
<div class="ground" id="Ground"></div>
<div class="my_contain" id="popup">
<div class="screen_box">
<ul>
<li>
<input type="text" id="content" maxlength="5" placeholder="请输入备注名字"><br>
</li>
</ul>
<button name="submit" id="new_program">新建</button><br>
<button name="cancel" id="cancel">取消</button>
</div>
<div class="toast">
<span>节目备注不能为空</span>
</div>
</div>
<!-- 添加节目弹窗 end -->
<footer>
<ul>
<li><a href="screen_main.html">首页</a></li>
<li><a href="screen_par.html">屏参</a></li>
<li><a class="active" href="screen_program.html">节目管理</a></li>
<li><a href="#">联系我们</a></li>
</ul>
<div style="height:80px" hidden="hidden"></div>
</footer>
<div id='a' class="toast">
<span>加载中....</span>
</div>
<div id="b" class="toast">
<span>加载失败</span>
</div>
<div id='c' class="toast">
<span>删除中....</span>
</div>
<div id="d" class="toast">
<span>删除失败</span>
</div>
<div id='e' class="toast">
<span>设置中....</span>
</div>
<div id="f" class="toast">
<span>设置失败</span>
</div>
<div id="result_prompt_txt" class="toast">
<span>结果内容</span>
</div>
</div>
<script>
var program_list_reply_parse_fun;
var g_quantity = 0;
var play_mode = 0;
const g_max = 10;
json_id = localStorage.getItem("json_id");
// $(function () {
var baseHost = document.location.origin
var count = 0;
//mode 提示消息显示模式(0关闭 1显示 3显示特定时间) txt显示内容
function result_prompt_display(mode, txt) {
document.getElementById("result_prompt_txt").getElementsByTagName("span")[0].innerHTML = txt;
if (mode == 0) {
$("#result_prompt_txt").css("display", "none");
} else if (mode == 1) {
$("#result_prompt_txt").css("display", "flex");
} else {
$("#result_prompt_txt").css("display", "flex");
setTimeout(function () {
$("#result_prompt_txt").css("display", "none");
}, 500);
}
}
/*********************************************************节目管理->添加节目**************************************************/
/***滑动限制***/
function stop() {
var mo = function (e) {
e.preventDefault();
};
document.body.style.overflow = 'hidden';
document.addEventListener("touchmove", mo, false); //禁止页面滑动
}
/***取消滑动限制***/
function move() {
var mo = function (e) {
e.preventDefault();
};
document.body.style.overflow = ''; //出现滚动条
document.removeEventListener("touchmove", mo, false);
}
/*点击弹出按钮*/
function popBox() {
stop();
document.getElementById("popup").style.display = "block";
document.getElementById("Ground").style.display = "block";
document.getElementById("content").value = "";
};
/*点击关闭弹窗*/
function closeBox() {
move();
document.getElementById("popup").style.display = "none";
document.getElementById("Ground").style.display = "none";
}
function program_list_reply_parse(json_str) {
if (json_str == "") {
return;
}
let json = jQuery.parseJSON(json_str);
if ("pro_manage" in json.led_protocol) {
if (json.led_protocol.pro_manage_ok == 1) {
closeBox();
display(json.led_protocol);
}
else if ((json.led_protocol.pro_manage_ok == 4) || (json.led_protocol.pro_manage_ok == 5)) {
switch_display(json.led_protocol);
}
else {
display(json.led_protocol);
}
result_prompt_display(2, "节目操作成功");
}
}
program_list_reply_parse_fun = program_list_reply_parse;
$('#new_program').on('click', function () {
var cont = $('#content').val()
if (cont.trim().length) {
var manage = {};
// manage.jsonid = json_id;
manage = new Object();
manage.pro_manage = new Object();
manage.pro_manage.type = 1;
manage.pro_manage.data = (parseInt(g_quantity));
manage.pro_manage.remarks = new Array();
manage.pro_manage.remarks[0] = cont;
let string = JSON.stringify(manage);
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 || xhr.status == 200) {
program_list_reply_parse(xhr.responseText);
}
}
}
else {
MQTT_send(string);
}
} else if (!cont.trim().length) {
result_prompt_display(2, "节目备注不能为空");
}
json_id++;
localStorage.setItem("json_id", json_id);
})
$('#cancel').on('click', function () {
closeBox();
})
$('#insert').on('click', function () {
//alert("请输入节目备注名称!")
if (g_quantity < 10) {
popBox(); //window.location.href = './new_program.html?' + "quantity=" + g_quantity
} else {
alert('节目已达上限!')
}
})
/*********************************************************节目管理->刷新节目**************************************************/
function get_pro_manage() {
var manage = {};
// manage.jsonid = json_id;
manage = new Object();
manage.get_pro_manage = 1;
let string = JSON.stringify(manage);
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
program_list_reply_parse(xhr.responseText);
}
else {
result_prompt_display(2, "加载失败");
}
}
}
else {
MQTT_send(string);
}
}
$('#refresh').on('click', function () {
result_prompt_display(1, "加载中...");
get_pro_manage();
})
/*********************************************************节目管理->删除节目**************************************************/
//删除栈中第一个节目起始索引为0
function del_icon(data) {
manage = {};
// manage.jsonid = json_id;
manage = new Object();
manage.pro_manage = new Object();
manage.pro_manage.type = 2;
manage.pro_manage.data = data;
result_prompt_display(1, "删除中...");
let string = JSON.stringify(manage);
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest()
xhr.open('post', baseHost + '/communication', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(string);
xhr.onreadystatechange = function () {
if ((xhr.readyState == 4) && (xhr.status == 200)) {
program_list_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "删除失败");
}
}
}
else {
MQTT_send(string);
}
json_id++;
localStorage.setItem("json_id", json_id);
}
$("[name = 'delete_n']").off("click");
$("[name = 'delete_n']").on("click", function () {
let num = $("[name='delete_n']").index(this);
del_icon(num)
});
/*********************************************************节目管理->开启或关闭节目**************************************************/
function switch_display(obj) {
console.log(JSON.stringify(obj))
for (i = 1; i <= g_max; i++) {
if (obj.pro_manage.play_flag[i - 1] == 0) {
var el = document.getElementById("switch" + i);
el.checked = false;
} else {
var el = document.getElementById("switch" + i);
el.checked = true;
}
}
}
function open_or_close_play(type, data) {
manage = {};
// manage.jsonid = json_id;
manage = new Object()
manage.pro_manage = new Object();
manage.pro_manage.type = type;
manage.pro_manage.data = data;
let string = JSON.stringify(manage);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest()
xhr.open('post', baseHost + '/communication', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(string)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
program_list_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "发送失败");
}
}
}
}
else {
MQTT_send(string);
}
json_id++;
localStorage.setItem("json_id", json_id);
}
$("[name = 'switch_n']").off("click");
$("[name = 'switch_n']").on("click", function () {
let num = $("[name='switch_n']").index(this);
if (this.checked == true) {
open_or_close_play(4, num)
} else {
open_or_close_play(5, num)
}
});
/*********************************************************节目管理->设置节目**************************************************/
var note;
$("[name = 'setting']").off("click");
$("[name = 'setting']").on("click", function () {
let num = $("[name='setting']").index(this);
window.location.href = "content_pattern1.html?" + "pro_num=" + num + "&note=" + note[num]
});
$('.list').on('click', 'p', function () {
$(this).toggleClass('bordercolor')
})
function display(obj) {
note = obj.pro_manage.remarks;
g_quantity = obj.pro_manage.quantity;
for (var i = 1; i <= g_max; i++) {
$("#delete" + i).hide()
}
for (var i = 1; i <= g_max; i++) {
$("#set" + i).hide()
}
for (var i = 1; i <= g_max; i++) {
$("#switch" + i).hide()
}
$('.list').empty()
for (i = 0; i < g_quantity; i++) {
var itemHTML = '<p>' + note[i] + '</p>'
$('.list').append(itemHTML).css('background', '#1c7fc3')
var num = i + 1
$("#delete" + num).show()
$("#set" + num).show()
$("#switch" + num).show()
}
switch_display(obj);
}
// get_pro_manage();
$(function () {
if (/xazn/.test(navigator.userAgent)) {
// 在App中
document.addEventListener("UniAppJSBridgeReady", function () {
get_pro_manage();
});
} else {
get_pro_manage();
}
})
</script>
</body>
</html>

View File

@ -0,0 +1,192 @@
<!--
* @Descripttion:
* @version:
* @Author: Baron
* @Date: 2022-07-06 10:00:11
* @LastEditors: Andy
* @LastEditTime: 2024-06-25 14:20:32
-->
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="js/webView.js"></script>
<meta charset="UTF-8">
<meta http-equiv="max-age" content="31536000">
<meta http-equiv="Pragma" content="public">
<meta http-equiv="Cache-control" content="public">
<meta http-equiv="Cache" content="public">
<title>虚拟遥控器</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/content.css">
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=0.01, maximum-scale=1, user-scalable=yes" />
<link rel="prefetch" href="screen_main.html">
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/MQTT_port.js"></script>
<script> src = "js/jsonid.js"</script>
</head>
</head>
<body>
<div class="contain">
<article class="midart">
<ul class="tag_control">
<li class="control_li" onclick="location.href='screen_main.html' ">
<img src="img/delete.png" /><span>返回首页</span>
</li>
<li name="pro_butt" value="0" class="control_li">
<img src="img/compicon.png" /><span name="pro_txt">加载中</span>
</li>
</ul>
</article>
</div>
<div id='a' class="toast">
<span>打开中...</span>
</div>
<div id='b' class="toast">
<span>打开节目成功</span>
</div>
<div id='c' class="toast">
<span>打开节目失败</span>
</div>
<div id="result_prompt_txt" class="toast">
<span>结果内容</span>
</div>
<script>
json_id = localStorage.getItem("json_id");
var screen_virtual_reply_parse_fun;
// $(function () {
var baseHost = document.location.origin;
var g_note = []; //备注
var g_quantity = 0; //节目数量
//mode 提示消息显示模式(0关闭 1显示 3显示特定时间) txt显示内容
function result_prompt_display(mode, txt) {
document.getElementById("result_prompt_txt").getElementsByTagName("span")[0].innerHTML = txt;
if (mode == 0) {
$("#result_prompt_txt").css("display", "none");
} else if (mode == 1) {
$("#result_prompt_txt").css("display", "flex");
} else {
$("#result_prompt_txt").css("display", "flex");
setTimeout(function () {
$("#result_prompt_txt").css("display", "none");
}, 500);
}
}
function screen_virtual_reply_parse(json_str) {
let json = jQuery.parseJSON(json_str);
if (("pro_manage_ok" in json.led_protocol) && (json.led_protocol.pro_manage_ok != 0)) {
result_prompt_display(2, "打开节目成功");
}
if (("pro_manage" in json.led_protocol) && (json.led_protocol.pro_manage_ok == 0)) {
g_note = json.led_protocol.pro_manage.remarks;
g_quantity = json.led_protocol.pro_manage.quantity;
pro_butt_init(g_quantity);
result_prompt_display(2, "加载成功");
}
}
screen_virtual_reply_parse_fun = screen_virtual_reply_parse;
function get_pro_manage() {
var manage = {};
// manage.jsonid = json_id;
manage = new Object();
manage.get_pro_manage = 1;
let string = JSON.stringify(manage);
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
screen_virtual_reply_parse(xhr.responseText);
}
else {
result_prompt_display(2, "加载失败");
}
}
}
else {
MQTT_send(string);
}
json_id++;
localStorage.setItem("json_id", json_id);
}
get_pro_manage();
//发送指令
function only_dis_single(data) {
manage = {};
// manage.jsonid = json_id;
manage = new Object();
manage.pro_manage = new Object();
manage.pro_manage.type = 6;
manage.pro_manage.data = parseInt(data);
let string = JSON.stringify(manage);
result_prompt_display(1, "打开中");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest()
xhr.open('post', baseHost + '/communication', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(string)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
screen_virtual_reply_parse(xhr.responseText);
} else {
result_prompt_display(2, "打开节目失败");
}
}
}
}
else {
MQTT_send(string);
}
json_id++;
localStorage.setItem("json_id", json_id);
}
function pro_butt_init(len) {
if (len == 0) {
//没有节目
document.getElementsByName("pro_butt")[0].style.display = "none";
alert("节目列表为空!")
} else {
//拷贝一份
var sourceNode = document.getElementsByName("pro_butt")[0];
document.getElementsByName("pro_txt")[0].innerHTML = g_note[0]
for (var i = 1; i < len; i++) {
//创建并克隆子节点
var cloneNode = sourceNode.cloneNode(true)
cloneNode.setAttribute("value", i)
sourceNode.parentNode.appendChild(cloneNode)
document.getElementsByName("pro_txt")[i].innerHTML = g_note[i]
}
//绑定单击事件
var butts = document.getElementsByName("pro_butt");
for (var x = 0; x < g_quantity; x++) {
butts[x].onmousedown = function () {
only_dis_single(this.getAttribute("value"));
}
}
}
}
// pro_butt_init(g_quantity)
$(function () {
if (/xazn/.test(navigator.userAgent)) {
// 在App中
document.addEventListener("UniAppJSBridgeReady", function () {
get_pro_manage();
});
} else {
get_pro_manage();
}
})
</script>
</body>
</html>

BIN
public/web/traffic_sign.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

404
public/web/voice_copy.html Normal file
View File

@ -0,0 +1,404 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="js/webView.js"></script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title reclang="XvFp">远程喊话</title>
<link rel="stylesheet" href="./css/voice_style.css">
<script>
var PageLM = "2023-12-08 20:41";
</script>
</head>
<body>
<script src="js/recorder.core.js"></script>
<script src="js/mp3.js"></script>
<script src="js/mp3-engine.js"></script>
<script src="js/MQTT_port.js"></script>
<script src="js/jquery-3.4.1.min.js"></script>
<!-- 【2】构建界面 Build the web interface -->
<div class="content">
<div class="record-container">
<button class="break_btn" onclick="return_function()">返回</button>
<div id="record-popup" class="record-popup" style="display: none;">
<!-- 录音动效和提示信息 -->
<div id="recording-animation" style="display: none;">录音中...</div>
<div id="cancel-tip" style="display: none;">松手发送</div>
</div>
<div id="voice-wave-animation" class="voice-line-wrap" style="display: none;">
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
<div class="voice-line"></div>
</div>
<div class="voice-btn-wrap">
<button id="record-btn">喊话</button>
</div>
<audio id="audio-playback" controls style="display: none;"></audio>
</div>
</div>
<!-- 【3】实现录音逻辑 Implement recording logic -->
<script>
document.getElementById('record-btn').addEventListener('mousedown', recStart);
document.getElementById('record-btn').addEventListener('mouseup', recStop);
document.getElementById('record-btn').addEventListener("touchstart", recStart); // 移动端
document.getElementById('record-btn').addEventListener("touchend", recStop); // 移动端
//-----------------------------------------------------------------------//
var voice_reply_parse_fun;
function return_function() {
//location.href='screen_main.html';
window.history.go(-1);
}
function voice_reply_parse(json_str) {
let json = jQuery.parseJSON(json_str);
if ("sound_card" in json) {
switch (json.sound_card.state || json.sound_card.on_state) {
case "succeed":
console.log("---succeed---");
break;
case "playing":
console.log("---playing---");
break;
case "downloadin":
console.log("---downloadin---");
break;
}
}
}
voice_reply_parse_fun = voice_reply_parse;
function send_voice_function(url, interrupt) {
var send_json = {};
send_json.board_id=103;
send_json.online_play = new Object();
send_json.online_play.url = url;
if (interrupt) {
send_json.interrupt = interrupt;
}
var str = JSON.stringify(send_json);
console.log(str);
MQTT_json_send(str, "sound_card");
}
//-----------------------------------------------------------------------//
var rec, recBlob;
/**调用open打开录音请求好录音权限 Call open to open the recording and request the recording permission**/
function recOpen() {
//一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了
rec = null;
recBlob = null;
var newRec = Recorder({
type: "mp3",
sampleRate: 16000,
bitRate: 16, //mp3格式指定采样率hz、比特率kbps其他参数使用默认配置注意是数字的参数必须提供数字不要用字符串需要使用的type类型需提前把格式支持文件加载进来比如使用wav格式需要提前加载wav.js编码引擎
onProcess: function (
buffers,
powerLevel,
bufferDuration,
bufferSampleRate,
newBufferIdx,
asyncEnd
) {
//录音实时回调大约1秒调用12次本回调
// document.querySelector(".recpowerx").style.width=powerLevel+"%";
// document.querySelector(".recpowert").innerText=formatMs(bufferDuration,1)+" / "+powerLevel;
},
});
newRec.open(
function () {
//打开麦克风授权获得相关资源
rec = newRec;
},
function (msg, isUserNotAllow) {
//用户拒绝未授权或不支持
}
);
}
/**关闭录音,释放资源 Close recording, release resources**/
function recClose() {
if (rec) {
rec.close();
reclog(Html_$T("jqOs::已关闭"));
} else {
reclog(Html_$T("VOOw::未打开录音"), 1);
}
}
/**开始录音 Start recording**/
function recStart() {
// this.preventDefault();
//打开了录音后才能进行start、stop调用
if (rec && Recorder.IsOpen()) {
recBlob = null;
rec.start();
document.getElementById('voice-wave-animation').style.display = 'flex';
// 显示录音动效
document.getElementById('record-popup').style.display = 'block';
document.getElementById('recording-animation').style.display = 'block';
document.getElementById('cancel-tip').style.display = 'block';
} else {
}
}
/**结束录音,得到音频文件 Stop recording and get audio files**/
function recStop() {
if (!(rec && Recorder.IsOpen())) {
return;
}
rec.stop(
function (blob, duration) {
recBlob = blob;
let playAudio = document.getElementById("audio-playback");
// 将音频 URL 赋值给第二个 audio 元素
playAudio.src = (window.URL || webkitURL).createObjectURL(recBlob);
// send_voice_function(playAudio.src, 0);
// playAudio.play();
document.getElementById('voice-wave-animation').style.display = 'none';
document.getElementById('record-popup').style.display = 'none';
// 隐藏录音动效
document.getElementById('recording-animation').style.display = 'none';
document.getElementById('audio-playback').style.display = 'block';
recUpload();
},
function (msg) { }
);
}
/**播放 Play**/
function recPlay() {
if (!recBlob) {
reclog(Html_$T("tIke::请先录音,然后停止后再播放"), 1);
return;
}
let playAudio = document.getElementById("audioPlay");
// 将音频 URL 赋值给第二个 audio 元素
playAudio.src = (window.URL || webkitURL).createObjectURL(recBlob);
// send_voice_function(playAudio.src, 0);
playAudio.play();
setTimeout(function () {
(window.URL || webkitURL).revokeObjectURL(audio.src);
}, 5000);
}
function getQueryString(name) {
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
let r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(decodeURI(r[2]));
return null;
}
/**上传 Upload**/
function recUpload() {
var blob = recBlob;
if (!blob) {
reclog(Html_$T("DUTn::请先录音,然后停止后再上传"), 1);
return;
}
// 创建 FormData 对象
let formData = new FormData();
// 将 Blob 对象添加到 FormData 中,假设字段名为 'audioFile'
formData.append("file", blob, "recording.mp3");
// 发送 POST 请求到服务器
fetch("http://iot.pcpnb.cn/prod-api/iot/tool/upload", {
method: "POST",
headers: {
Authorization: localStorage.getItem('token'),
},
body: formData,
})
.then((response) => {
console.log(response);
if (response.ok) {
return response.json(); // 或者 response.text() 如果服务器返回的是文本
}
throw new Error("Network response was not ok.");
})
.then((data) => {
console.log("Success:", data);
// 处理服务器返回的数据
send_voice_function("http://iot.pcpnb.cn/prod-api" + data.fileName, 99);
})
.catch((error) => {
console.error("Error:", error);
});
}
/**本地下载 Local download**/
function recLocalDown() {
if (!recBlob) {
reclog(Html_$T("M86h::请先录音,然后停止后再下载"), 1);
return;
}
var cls = ("a" + Math.random()).replace(".", "");
recdown64.lastCls = cls;
reclog(
Html_$T("vJPl::点击 ") +
'<span class="' +
cls +
'"></span>' +
Html_$T("Whtc:: 下载,或复制文本") +
"<button onclick=\"recdown64('" +
cls +
"')\">" +
Html_$T("XK4l::生成Base64文本") +
'</button><span class="' +
cls +
'_b64"></span>'
);
var fileName = "recorder-" + Date.now() + ".mp3";
var downA = document.createElement("A");
downA.innerHTML = Html_$T("g8Fy::下载 ") + fileName;
downA.href = (window.URL || webkitURL).createObjectURL(recBlob);
downA.download = fileName;
document.querySelector("." + cls).appendChild(downA);
if (/mobile/i.test(navigator.userAgent)) {
alert(
Html_xT(
Html_$T(
"DIEK::因移动端绝大部分国产浏览器未适配Blob Url的下载所以本demo代码在移动端未调用downA.click()。请尝试点击日志中显示的下载链接下载"
)
)
);
} else {
downA.click();
}
//不用了时需要revokeObjectURL否则霸占内存
//(window.URL||webkitURL).revokeObjectURL(downA.href);
}
function recdown64(cls) {
var el = document.querySelector("." + cls + "_b64");
if (recdown64.lastCls != cls) {
el.innerHTML =
'<span style="color:red">' +
Html_$T("eKKx::老的数据没有保存,只支持最新的一条") +
"</span>";
return;
}
var reader = new FileReader();
reader.onloadend = function () {
el.innerHTML = "<textarea></textarea>";
el.querySelector("textarea").value = reader.result;
};
reader.readAsDataURL(recBlob);
}
var formatMs = function (ms, all) {
var ss = ms % 1000;
ms = (ms - ss) / 1000;
var s = ms % 60;
ms = (ms - s) / 60;
var m = ms % 60;
ms = (ms - m) / 60;
var h = ms;
var t =
(h ? h + ":" : "") +
(all || h + m ? ("0" + m).substr(-2) + ":" : "") +
(all || h + m + s ? ("0" + s).substr(-2) + "″" : "") +
("00" + ss).substr(-3);
return t;
};
recOpen();
</script>
<!--以下这坨可以忽略 The following can be ignored-->
<script>
function reclog(s, color) { }
function Html_$T(s) {
return s;
}
</script>
<style>
body {
word-wrap: break-word;
background: #f5f5f5 center top no-repeat;
background-size: auto 680px;
}
pre {
white-space: pre-wrap;
}
a {
text-decoration: none;
color: #06c;
}
a:hover {
color: #f00;
}
.main {
max-width: 700px;
margin: 0 auto;
padding-bottom: 80px;
}
.mainBox {
margin-top: 12px;
padding: 12px;
border-radius: 6px;
background: #fff;
--border: 1px solid #f60;
box-shadow: 2px 2px 3px #aaa;
}
.btns button {
display: inline-block;
cursor: pointer;
border: none;
border-radius: 3px;
background: #f60;
color: #fff;
padding: 0 15px;
margin: 3px 20px 3px 0;
line-height: 36px;
height: 36px;
overflow: hidden;
vertical-align: middle;
}
.btns button:active {
background: #f00;
}
.pd {
padding: 0 0 6px 0;
}
.lb {
display: inline-block;
vertical-align: middle;
background: #00940e;
color: #fff;
font-size: 14px;
padding: 2px 8px;
border-radius: 99px;
}
.voice-btn-wrap button {
-ms-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
</style>
</body>
</html>

4
src/App.vue Normal file
View File

@ -0,0 +1,4 @@
<template>
<router-view/>
</template>

File diff suppressed because one or more lines are too long

BIN
src/assets/img/pictur.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

1
src/assets/js/webView.js Normal file

File diff suppressed because one or more lines are too long

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,7 @@
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}

View File

@ -0,0 +1,4 @@
body{
margin: 0;
padding: 0;
}

47
src/components/Footer.vue Normal file
View File

@ -0,0 +1,47 @@
<template>
<div class="footer">
<router-view></router-view>
<van-tabbar v-model="active" @change="onChange">
<van-tabbar-item icon="home-o" name="home">系统设置</van-tabbar-item>
<van-tabbar-item icon="setting-o" name="info">系统信息</van-tabbar-item>
</van-tabbar>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue';
import { useRouter, useRoute } from 'vue-router';
export default {
setup() {
const active = ref('home');
const router = useRouter();
const route = useRoute();
const onChange = (name) => {
router.push({ name });
};
watchEffect(() => {
active.value = route.name;
});
return {
active,
onChange,
};
},
};
</script>
<style lang="less">
.footer {
height: 50px;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
z-index: 999;
}
</style>

41
src/components/Header.vue Normal file
View File

@ -0,0 +1,41 @@
<template>
<div class="custom-nav-bar">
<van-nav-bar :title="title" />
</div>
</template>
<script>
export default {
name: 'Header',
props: {
title: {
type: String,
default: '标题',
},
},
};
</script>
<style scoped>
.custom-nav-bar {
height: 90px; /* 你可以根据需要调整高度 */
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 999; /* 使 Header 在最上层 */
}
/deep/ .van-nav-bar {
height: 100%; /* 确保van-nav-bar占满父元素的高度 */
background-color: #0668fc; /* 示例背景色,可以根据需要调整 */
}
/deep/ .van-nav-bar__title {
font-size: 22px; /* 设置标题字体大小 */
font-weight: bold; /* 设置标题字体加粗 */
color: #fff; /* 设置标题字体颜色 */
line-height: 100%;
margin-top: 40px;
}
</style>

View File

@ -0,0 +1,35 @@
// src/mqttClient.js
import mqtt from 'mqtt/dist/mqtt.min';
let client;
const connectMQTT = (brokerUrl = 'ws://broker.emqx.io:8083/mqtt', options = {}) => {
if (!client || client.disconnected) {
client = mqtt.connect(brokerUrl, options);
client.on('connect', () => {
console.log('Connected to MQTT broker');
client.subscribe('/mytest/abc', (err) => {
if (err) {
console.error('Failed to subscribe to topic:', err);
} else {
console.log('Subscribed to topic: /mytest/abc');
}
});
});
client.on('error', (err) => {
console.error('MQTT connection error:', err);
client.end();
});
client.on('close', () => {
console.log('MQTT connection closed');
});
} else {
console.log('MQTT client is already connected');
}
};
// 导出客户端和连接函数
export { client, connectMQTT };

View File

@ -0,0 +1,12 @@
const checkEnvironment = () => {
if (window.location.hostname === '192.168.4.1') {
console.log('in local');
// 本地开发环境,设置 isLocal 为 true
isLocal.value = true;
} else {
// 生产环境,设置 isLocal 为 false
isLocal.value = false;
console.log('in online');
}
};

75
src/main.js Normal file
View File

@ -0,0 +1,75 @@
import 'amfe-flexible';
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import '@vant/touch-emulator';
import '../../set-vue/src/assets/icon/iconfont';
// const VConsole = require('vconsole');
// new VConsole(); // 初始化vConsole
if (/xazn/.test(navigator.userAgent) || /uni-app/.test(navigator.userAgent)) {
// 在App中
console.log("UniAppJSBridgeReady 事件已触发");
document.addEventListener("UniAppJSBridgeReady", function () {
console.log("ok");
});
}
window.MQTT_recv = MQTT_recv;
//在收到数据后需要调用这个函数
function MQTT_recv(string) {
console.log("MQTT 接收:" + string);
}
function checkEnvironment() {
if (window.location.hostname === '192.168.4.1') {
console.log('in local');
// 本地开发环境,需要登录
requireLogin();
} else {
// 生产环境,不需要登录
bypassLogin();
}
}
function requireLogin() {
if (!store.state.isAuthenticated) {
router.push('/login');
}
}
// 获取 URL 中的 token 参数
function getQueryString(name) {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(name);
}
// 在页面加载时,获取 token 并存储到 localStorage
const token = getQueryString('token');
if (token) {
localStorage.setItem('token', token);
console.log('Token stored:', token);
} else {
console.log('No token found in URL');
}
function bypassLogin() {
// 假设在服务器环境中已经有登录信息,可以直接跳过登录逻辑
store.commit('setAuthenticated', true);
}
const app = createApp(App);
checkEnvironment(); // 检查环境并执行相应的逻辑
const isAuthenticated = JSON.parse(localStorage.getItem('isAuthenticated'));
if (isAuthenticated) {
store.commit('setAuthenticated', true);
}
app.use(store).use(router).mount('#app');
window.VueRouter = router; // 这里立即暴露 router
console.log("VueRouter 已暴露到全局");

63
src/router/index.js Normal file
View File

@ -0,0 +1,63 @@
import { createRouter, createWebHashHistory } from 'vue-router';
import { useStore } from 'vuex';
const routes = [
{
path: '/login',
name: 'login',
component: () => import('../views/loggin/loggin.vue')
},
{
path: '/reset',
name: 'reset',
component: () => import('../views/loggin/reset.vue'),
meta: { requiresAuth: false } // 不需要认证
},
{
path: '/',
name: 'home',
component: () => import('../views/home/home.vue')
},
{
path: '/recognition',
name: 'recognition',
component: () => import('../views/recognize/License-plate-recognition.vue')
},
{
path: '/info',
name: 'info',
component: () => import('../views/system-info/info.vue')
},
{
path: '/warning',
name: 'warning',
component: () => import('../views/forewarning/forewarning.vue')
},
{
path: '/Footer',
name: 'Footer',
component: () => import('../components/Footer.vue')
},
{
path: '/voiceset',
name: 'voiceset',
component: () => import('../views/voice/voiceset.vue')
},
];
const router = createRouter({
history: createWebHashHistory(), // 使用 hash 模式
routes
});
router.beforeEach((to, from, next) => {
const store = useStore(); // 获取 store 实例
if (to.meta.requiresAuth === false) {
next(); // 允许访问所有不需要认证的页面
} else if (to.path !== '/login' && !store.state.isAuthenticated) {
next('/login'); // 未认证,重定向到登录页面
} else {
next(); // 已认证,继续导航
}
});
export default router;

24
src/store/index.js Normal file
View File

@ -0,0 +1,24 @@
import { createStore } from 'vuex';
export default createStore({
state: {
isAuthenticated: JSON.parse(localStorage.getItem('isAuthenticated')) || false,
},
mutations: {
setAuthenticated(state, value) {
state.isAuthenticated = value;
localStorage.setItem('isAuthenticated', JSON.stringify(value));
},
},
actions: {
login({ commit }, credentials) {
// 在这里进行登录请求,并在成功后设置认证状态
// 例如,假设登录成功:
commit('setAuthenticated', true);
},
logout({ commit }) {
commit('setAuthenticated', false);
},
},
modules: {},
});

548
src/views/event/event.vue Normal file
View File

@ -0,0 +1,548 @@
<template>
<div class="home">
<p class="title" style="pointer-events: none;">事件设置</p>
<div class="slider-container">
<p class="set-title">触发阈值</p>
<van-slider v-model="value" range @change="onChange" :min="0" :max="160" />
</div>
<div class="input-container">
<van-field v-model="value[0]" type="number" label="最小值" placeholder="最小值" />
<van-field v-model="value[1]" type="number" label="最大值" placeholder="最大值" />
</div>
<div class="slider-container">
<p class="set-title">超速阈值</p>
<van-slider v-model="overSpeedValue" range @change="onOverSpeedChange" :min="0" :max="160" />
</div>
<div class="input-container">
<van-field v-model="overSpeedValue[0]" type="number" label="最小值" placeholder="最小值" />
<van-field v-model="overSpeedValue[1]" type="number" label="最大值" placeholder="最大值" />
</div>
<div class="control">
<p class="title-control">双色屏控制</p>
<van-switch v-model="screencontrol" class="switch-control" />
</div>
<div class="control">
<p class="title-control">设备地址</p>
<van-field v-model="addr" placeholder="请输入设备地址" />
</div>
<div v-if="!screencontrol">
<van-button round type="success" size="large" @click="uploadthreshold">设置</van-button>
</div>
<div v-if="screencontrol" class="control">
<p class="title-control">事件列表</p>
<van-icon name="plus" @click="addEvent" />
</div>
<div v-if="screencontrol">
<div v-for="(event, index) in events" :key="index" :ref="'event' + index" class="event-item">
<van-swipe-cell :right-width="65" @close="onClose">
<template v-slot:right>
<van-button square type="danger" @click="removeEvent(index)"
class="delete-button">删除</van-button>
</template>
<van-cell is-link title="事件类型" @click="event.showTypePicker = true">
{{ event.type }}
</van-cell>
<van-field v-if="event.type === '其他'" v-model="event.code" label="事件编码" placeholder="请输入事件编码" />
<van-cell is-link title="事件来源" @click="event.showsourcePicker = true">
{{ event.sourcename }}
</van-cell>
<van-field v-if="event.sourcename === '其他'" v-model="event.source" label="来源编码"
placeholder="请输入事件来源" />
<van-field v-model="event.priority" label="优先级" placeholder="请输入优先级" />
<van-field v-model="event.showItem" is-link readonly label="显示节目" placeholder="选择显示节目"
@click="showItemPicker = index" />
<van-field v-model="event.showDuration" label="显示时长" placeholder="请输入显示时长" />
<van-field v-model="event.outputPin" is-link readonly label="输出引脚" placeholder="请输入输出引脚"
@click="showpinpicker = index" />
<van-cell v-if="event.outputPin !== '-1'" is-link title="输出电平" @click="event.showoutlevel = true">
{{ event.outlevel }}
</van-cell>
</van-swipe-cell>
<van-action-sheet v-model:show="event.showoutlevel" :actions="levelactions"
@select="onSelectlevel(event, $event)" />
<van-action-sheet v-model:show="event.showTypePicker" :actions="typeaction"
@select="onSelecttype(event, $event)" />
<van-action-sheet v-model:show="event.showsourcePicker" :actions="sourceaction"
@select="onSelectsource(event, $event)" />
<van-popup v-model="showItemPicker" :show="showItemPicker === index" round position="bottom">
<van-picker :columns="progremcolums" @cancel="() => showItemPicker = -1"
@confirm="value => onConfirmShowItem(index, value)" />
</van-popup>
<van-popup v-model="showpinpicker" :show="showpinpicker === index" round position="bottom">
<van-picker :columns="outpincolumns" @cancel="() => showpinpicker = -1"
@confirm="value => onConfirmoutpin(index, value)" />
</van-popup>
</div>
</div>
<div v-if="screencontrol && events.length > 0" class="button-container">
<van-button round type="success" size="large" @click="uploadEventSettings">设置</van-button>
</div>
</div>
</template>
<script>
import { onMounted, ref } from 'vue';
import { showToast } from 'vant';
import axios from 'axios';
import { connectMQTT, client } from "../../components/MQTT/mqttclient";
export default {
name: 'EventSettings',
methods: {
eventfilldata(data) {
//
console.log('Data received in EventSettings:', data);
},
},
components: {
connectMQTT,
client,
},
setup() {
const value = ref([10, 50]);
const overSpeedValue = ref([60, 160]);
const screencontrol = ref(false);
const addr = ref('');
const events = ref([]);
const showItemPicker = ref(-1);
const showpinpicker = ref(-1);
const isLocal = ref(true);
const jsonId = ref(1); // JSON ID
const addEvent = () => {
events.value.push({
type: '',
code: '',
source: '',
priority: '',
showItem: '',
showDuration: '',
outputPin: '',
outlevel: '',
sourcename: '',
showTypePicker: false,
showoutlevel: false,
showsourcePicker: false,
});
showToast('添加成功');
};
const checkEnvironment = () => {
if (window.location.hostname === '192.168.4.1') {
console.log('in local');
// isLocal true
isLocal.value = true;
} else {
// isLocal false
isLocal.value = false;
}
};
const removeEvent = (index) => {
events.value.splice(index, 1);
uploadEventSettings();
};
const onSelectlevel = (event, selectedItem) => {
event.outlevel = selectedItem.value.toString();
event.showoutlevel = false;
showToast(selectedItem.name);
};
const onSelecttype = (event, selectedItem) => {
event.type = selectedItem.name;
event.code = selectedItem.code.toString();
event.showTypePicker = false;
showToast(selectedItem.name);
};
const onOverSpeedChange = (value) => showToast('当前超速值:' + value);
const onSelectsource = (event, selectedItem) => {
event.sourcename = selectedItem.name;
event.source = selectedItem.code.toString();
event.showsourcePicker = false;
showToast(selectedItem.name);
};
const onClose = (position, instance) => {
if (position === 'right') {
instance.close();
}
};
const onConfirmShowItem = (index, value) => {
events.value[index].showItem = value.selectedOptions[0].value;
showItemPicker.value = -1;
};
const onConfirmoutpin = (index, value) => {
events.value[index].outputPin = value.selectedOptions[0].value;
showpinpicker.value = -1;
};
const onChange = (value) => {
showToast('当前值:' + value);
};
const uploadthreshold = () => {
if (!addr.value) {
showToast('请填写设备地址');
return;
}
const threshold = {
JSON_id: jsonId.value,
board_id: 105,
LoRa_card: {
trig_cfg: {
trig_spd_L: parseInt(value.value[0]),
trig_spd_H: parseInt(value.value[1]),
lmt_spd_L: parseInt(overSpeedValue.value[0]),
lmt_spd_H: parseInt(overSpeedValue.value[1]),
screen_ctrl_en: screencontrol.value ? 1 : 0,
addr: parseInt(addr.value),
},
},
};
console.log(JSON.stringify(threshold)); // JSON
if (isLocal.value) {
axios.post(`/communication`, threshold, {
headers: {
"content-type": "application/json"
}
})
.then(response => {
console.log('Response data:', response.data);
showToast('设置成功');
jsonId.value++;
})
.catch(error => {
//
console.error('Upload error:', error);
showToast('设置失败');
jsonId.value++;
});
}
else {
MQTT_send(threshold);
}
};
const uploadEventSettings = () => {
for (const event of events.value) {
if (!event.type || !event.code || !event.source || !event.priority || !event.showItem || !event.showDuration || !event.outputPin || !addr.value) {
showToast('请填写完整事件信息');
return;
}
}
const eventPayload = {
"JSON_id": jsonId.value,
board_id: 105,
LoRa_card: {
trig_cfg: {
trig_spd_L: parseInt(value.value[0]),
trig_spd_H: parseInt(value.value[1]),
lmt_spd_L: parseInt(overSpeedValue.value[0]),
lmt_spd_H: parseInt(overSpeedValue.value[1]),
screen_ctrl_en: screencontrol.value ? 1 : 0,
addr: parseInt(addr.value),
event: events.value.map(event => ({
code: parseInt(event.code),
source: parseInt(event.source),
priority: parseInt(event.priority),
prg_num: parseInt(event.showItem),
prg_time: parseInt(event.showDuration),
output: parseInt(event.outputPin),
level: parseInt(event.outlevel)
}))
},
},
};
console.log(JSON.stringify(eventPayload)); // JSON
if (isLocal.value) {
axios.post(`/communication`, eventPayload, {
headers: {
"content-type": "application/json"
}
})
.then(response => {
console.log('Response data:', response.data);
showToast('设置成功');
jsonId.value++;
})
.catch(error => {
//
console.error('Upload error:', error);
showToast('设置失败');
jsonId.value++;
});
}
else {
MQTT_send(eventPayload);
}
};
const eventfilldata = (msg) => {
if (msg.LoRa_card) {
const trigCfg = msg.LoRa_card.trig_cfg;
//
addr.value = trigCfg.addr;
value.value = [trigCfg.trig_spd_L, trigCfg.trig_spd_H];
overSpeedValue.value = [trigCfg.lmt_spd_L, trigCfg.lmt_spd_H]; 4
screencontrol.value = !!trigCfg.screen_ctrl_en;
//
events.value = trigCfg.event.map(event => {
let eventType;
let eventsource;
switch (event.source) {
case 0:
eventsource = '本台设备';
break;
case 254:
eventsource = '除本身外任意设备';
break;
case 255:
eventsource = '任意设备';
break;
default:
eventsource = '其他';
}
switch (event.code) {
case 0:
eventType = '默认显示';
break;
case 1:
eventType = '雷达触发(RS485 雷达)';
break;
case 2:
eventType = '雷达超速(RS485 雷达)';
break;
case 3:
eventType = '车牌触发(摄像头)';
break;
case 4:
eventType = '车牌超速(摄像头)';
break;
case 5:
eventType = '行人检测(相机)';
break;
case 0x51:
eventType = 'IN1下降沿';
break;
case 0x52:
eventType = 'IN2上升沿';
break;
case 0x53:
eventType = 'IN3下降沿';
break;
case 0x54:
eventType = 'IN4上升沿';
break;
case 0x55:
eventType = 'IN1低电平';
break;
case 0x56:
eventType = 'IN2高电平';
break;
case 0x57:
eventType = 'IN3低电平';
break;
case 0x58:
eventType = 'IN4高电平';
break;
default:
eventType = '其他';
}
return {
type: eventType,
code: event.code.toString(),
source: event.source.toString(),
sourcename: eventsource,
priority: event.priority.toString(),
showItem: event.prg_num.toString(),
// showItem: programnum,
showDuration: event.prg_time.toString(),
outputPin: event.output.toString(),
outlevel: event.level.toString(),
};
});
}
};
const typeaction = [
{ name: '默认显示', code: 0 },
{ name: '雷达触发(RS485 雷达)', code: 1 },
{ name: '雷达超速(RS485 雷达)', code: 2 },
{ name: '车牌触发(摄像头)', code: 3 },
{ name: '车牌超速(摄像头)', code: 4 },
{ name: '行人检测(相机)', code: 5 },
{ name: 'IN1下降沿', code: 0x51 },
{ name: 'IN2上升沿', code: 0x52 },
{ name: 'IN3下降沿', code: 0x53 },
{ name: 'IN4上升沿', code: 0x54 },
{ name: 'IN1低电平', code: 0x55 },
{ name: 'IN2高电平', code: 0x56 },
{ name: 'IN3低电平', code: 0x57 },
{ name: 'IN4高电平', code: 0x58 },
{ name: '其他', code: -1 },
];
const levelactions = [
{ name: '高(0)', value: 0 },
{ name: '低(1)', value: 1 },
];
const sourceaction = [
{ name: '本台设备', code: 0 },
{ name: '任意设备(不包含本设备)', code: 254 },
{ name: '任意设备', code: 255 },
{ name: '其他', code: 1 },
];
const progremcolums = [
{ text: '节目0(0)', value: '0' },
{ text: '节目1(1)', value: '1' },
{ text: '节目2(2)', value: '2' },
{ text: '节目3(3)', value: '3' },
{ text: '节目4(4)', value: '4' },
{ text: '节目5(5)', value: '5' },
{ text: '节目6(6)', value: '6' },
{ text: '节目7(7)', value: '7' },
{ text: '节目8(8)', value: '8' },
{ text: '节目9(9)', value: '9' },
];
const outpincolumns = [
{ text: '关闭(-1)', value: '-1' },
{ text: '引脚1(0)', value: '0' },
{ text: '引脚2(1)', value: '1' },
];
const MQTT_send = (send_string) => {
showToast('设置成功');
console.log("MQTT 发送:" + JSON.stringify(send_string));
if (/xazn/.test(navigator.userAgent) || /uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: JSON.stringify(send_string)
}
});
} else {
window.parent.postMessage({ str: JSON.stringify(send_string) }, "*");
}
};
onMounted(async () => {
await checkEnvironment();
console.log(isLocal.value);
}); return {
value,
overSpeedValue,
screencontrol,
addr,
events,
showItemPicker,
showpinpicker,
addEvent,
removeEvent,
onSelectlevel,
onSelecttype,
onSelectsource,
onConfirmShowItem,
onConfirmoutpin,
onChange,
uploadEventSettings,
typeaction,
levelactions,
sourceaction,
progremcolums,
outpincolumns,
checkEnvironment,
onOverSpeedChange,
onClose,
eventfilldata,
uploadthreshold,
MQTT_send
};
},
};
</script>
<style scoped>
.home {
padding: 20px;
border-radius: 10px;
border: 2px solid #0668fc;
margin: 100px 10px 20px;
flex: 1;
}
.title {
text-align: center;
font-size: 30px;
}
.slider-container {
display: flex;
align-items: center;
}
.title-control {
text-align: left;
font-size: 15px;
margin: 0;
white-space: nowrap;
}
.set-title {
font-size: 15px;
margin-right: 10px;
white-space: nowrap;
}
.input-container {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.button-container {
display: flex;
justify-content: center;
margin-top: 20px;
}
.switch-control {
margin-left: auto;
}
.control {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
.event-item {
margin-top: 20px;
padding: 10px;
border: 1px solid #e0e0e0;
border-radius: 10px;
}
.delete-button {
position: absolute;
top: 50%;
border-radius: 10px;
}
</style>

View File

@ -0,0 +1,451 @@
<template>
<div class="page-container">
<Header :title="currentTitle"></Header>
<van-pull-refresh v-model="loading" success-text="刷新成功" @refresh="onRefresh" class="fresh">
<div class="home">
<van-cell-group inset>
<p class="title">LoRa模组信息</p>
<van-divider :style="{ color: 'black' }" />
<van-field label="固件版本:" v-model="versions" readonly />
<van-field label="MAC地址:" v-model="mac_addr" readonly />
<van-field label="无线频率:" v-model="radio_band" readonly />
<van-field label="设备功率:" v-model="selectedpower" readonly />
<van-field label="模式:" v-model="mode" readonly />
</van-cell-group>
</div>
<div class="home">
<van-cell-group inset>
<p class="title">LoRa网络参数</p>
<!-- 网络id -->
<van-field v-model="value" label="网络ID" placeholder="请输入网络ID" @input="validateValue" />
<!-- 选择信道 -->
<van-field v-model="channelValue" is-link readonly label="信道" placeholder="选择信道"
@click="showchannelPicker = true" />
<van-popup v-model:show="showchannelPicker" round position="bottom">
<van-picker :columns="channelcolumns" @cancel="showchannelPicker = false" @confirm="onConfirmchannel" />
</van-popup>
<!-- 速率 -->
<van-cell is-link title="速率" @click="showspeed = true">
{{ selectedspeed }}
</van-cell>
<van-action-sheet v-model:show="showspeed" :actions="speedactions" @select="onSelectspeed" />
<van-button round type="success" size="large" @click="uploadEventSettings">设置</van-button>
</van-cell-group>
</div>
<EventSettings ref="eventSettingsRef">
</EventSettings>
</van-pull-refresh>
<Footer></Footer>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { useRouter } from 'vue-router';
import Header from "../../components/Header.vue";
import Footer from "../../components/Footer.vue";
import EventSettings from "../event/event.vue"
import '@vant/touch-emulator';
import axios from 'axios';
// import { showToast } from 'vant';
export default {
methods: {
eventfilldata(data) {
//
}
},
components: {
Header,
Footer,
EventSettings
},
setup() {
const jsonId = ref(1); // JSON ID
const currentTitle = ref('预警设置');
const loading = ref(false);
const show = ref(false);
const selectedspeed = ref('');
const selectedpower = ref('');
const channelValue = ref('');
const mode = ref('');
const showchannelPicker = ref(false);
const showspeed = ref(false);
const versions = ref('');
const mac_addr = ref('');
const radio_band = ref('');
const value = ref('');
const eventSettingsRef = ref(null); //
const maxRetries = 3;
let errorCount = 0;
// let client;
const isLocal = ref(true); // isLocal false
//
const checkEnvironment = () => {
if (window.location.hostname === '192.168.4.1') {
console.log('in local');
// isLocal true
isLocal.value = true;
} else {
// isLocal false
isLocal.value = false;
}
};
const validateValue = (event) => {
let inputValue = event.target.value;
if (inputValue > 255) {
value.value = '255';
} else {
value.value = inputValue;
}
};
const channelcolumns = [
{ text: '0 ', value: '0 ' },
{ text: '1 ', value: '1 ' },
{ text: '2 ', value: '2 ' },
{ text: '3 ', value: '3 ' },
{ text: '4 ', value: '4 ' },
{ text: '5 ', value: '5 ' },
{ text: '6 ', value: '6 ' },
{ text: '7 ', value: '7 ' },
{ text: '8 ', value: '8 ' },
{ text: '9 ', value: '9 ' },
{ text: '10', value: '10' },
{ text: '11', value: '11' },
{ text: '12', value: '12' },
{ text: '13', value: '13' },
{ text: '14', value: '14' },
{ text: '15', value: '15' },
{ text: '16', value: '16' },
{ text: '17', value: '17' },
{ text: '18', value: '18' },
{ text: '19', value: '19' },
{ text: '20', value: '20' },
{ text: '21', value: '21' },
{ text: '22', value: '22' },
{ text: '23', value: '23' },
{ text: '24', value: '24' },
{ text: '25', value: '25' },
{ text: '26', value: '26' },
{ text: '27', value: '27' },
{ text: '28', value: '28' },
{ text: '29', value: '29' },
{ text: '30', value: '30' },
{ text: '31', value: '31' },
];
const speedactions = [
{ name: '62.5kbps', value: '0' },
{ name: '37.5kbps', value: '1' },
{ name: '21.8kbps', value: '2' },
{ name: '12.5kbps', value: '3' },
{ name: '7.0kbps', value: '4' },
{ name: '3.9kbps', value: '5' },
{ name: '2.1kbps', value: '6' },
];
const onSelectspeed = (item) => {
selectedspeed.value = item.name;
showspeed.value = false;
showToast(item.name);
};
const onConfirmchannel = ({ selectedOptions }) => {
showchannelPicker.value = false;
channelValue.value = selectedOptions[0].text;
};
const onRefresh = () => {
loading.value = true;
const requestData = {
board_id: 105,
JSON_id: jsonId.value,
LoRa_card: {
get_LoRa_cfg: 1,
get_cfg: 1,
}
};
let timeoutHandler;
const timeoutDuration = 5000; // 5
if (isLocal.value) {
console.log('axios发送');
console.log('Send Data:', requestData);
axios.post(`/communication`, requestData, {
headers: {
"content-type": "application/json"
},
timeout: timeoutDuration // axios
})
.then(response => {
clearTimeout(timeoutHandler); //
parseAndFillData(response.data);
eventSettingsRef.value.eventfilldata(response.data);
console.log('Received message:', JSON.stringify(response.data));
jsonId.value++;
loading.value = false;
})
.catch(error => {
clearTimeout(timeoutHandler); //
if (error.code === 'ECONNABORTED') {
console.error('Request timeout:', error);
showToast('刷新超时');
} else {
console.error('Upload error:', error);
showToast('刷新失败');
}
jsonId.value++;
loading.value = false;
});
// axios
timeoutHandler = setTimeout(() => {
loading.value = false;
showToast('请求超时');
}, timeoutDuration);
} else {
//
const sendMQTTWithTimeout = new Promise((resolve, reject) => {
MQTT_send(requestData); //
resolve('MQTT消息已发送');
});
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('MQTT发送超时')), timeoutDuration)
);
Promise.race([sendMQTTWithTimeout, timeout])
.then(result => {
console.log(result); // MQTT
showToast('刷新请求已发送');
})
.catch(error => {
console.error(error.message); //
showToast('MQTT发送超时');
})
.finally(() => {
loading.value = false; // loading
});
}
};
const powerMap = {
0: '22dbm',
1: '20dbm',
2: '17dbm',
3: '14dbm',
4: '11dbm',
5: '8dbm',
6: '5dbm',
7: '2dbm'
};
const modeMap = {
1: '主机',
0: '从机',
}
const radio_bandMap = {
0: '62.5kbps',
1: '37.5kbps',
2: '21.8kbps',
3: '12.5kbps',
4: '7.0kbps',
5: '3.9kbps',
6: '2.1kbps',
};
const parseAndFillData = (msg) => {
// const LoRa_cfg = msg?.LoRa_card?.LoRa_cfg || {}; // LoRa_cfg使
// versions.value = LoRa_cfg.versions || ''; //
// mac_addr.value = Array.isArray(LoRa_cfg.mac_addr) ? LoRa_cfg.mac_addr.join(':') : ''; // mac_addr
// value.value = LoRa_cfg.mesh_id ? LoRa_cfg.mesh_id.slice(-1)[0].toString() : ''; // mesh_id
// radio_band.value = radio_bandMap[LoRa_cfg.fre_band] || ''; //
// // channelValue.value = channelcolumns.find(channel => channel.value === LoRa_cfg.channel.toString())?.text;
// channelValue.value = LoRa_cfg.channel ? LoRa_cfg.channel.toString() : ''; // channel
// selectedspeed.value = LoRa_cfg.SF ? speedactions.find(action => action.value === LoRa_cfg.SF.toString())?.name : ''; // SF
// selectedpower.value = powerMap[LoRa_cfg.power] || ''; // power
// mode.value = modeMap[LoRa_cfg.mode] || ''; // mode
const LoRa_cfg = msg.LoRa_card.LoRa_cfg;
versions.value = LoRa_cfg.versions;
mac_addr.value = LoRa_cfg.mac_addr.join(':');
value.value = LoRa_cfg.mesh_id ? LoRa_cfg.mesh_id.slice(-1)[0].toString() : '';
radio_band.value = radio_bandMap[LoRa_cfg.fre_band] || '';
// channelValue.value = channelcolumns.find(channel => channel.value === LoRa_cfg.channel.toString())?.text;
channelValue.value = LoRa_cfg.channel.toString();
selectedspeed.value = speedactions.find(action => action.value === LoRa_cfg.SF.toString())?.name;
selectedpower.value = powerMap[LoRa_cfg.power] || '';
mode.value = modeMap[LoRa_cfg.mode] || '';
loading.value = false;
showToast('配置已更新');
};
const uploadEventSettings = () => {
if (!value.value || !channelValue.value || !selectedspeed.value) {
showToast('请重新输入所有必填项');
return;
}
const data = {
JSON_id: jsonId.value,
board_id: 105,
LoRa_card: {
LoRa_cfg: {
mesh_id: [0, 0].concat(value.value.split(',').map(Number)),
channel: Number(channelValue.value),
SF: Number(speedactions.find(action => action.name === selectedspeed.value)?.value),
}
}
};
if (isLocal.value) {
console.log('axios发送');
// 使 Axios
console.log('Send Data:', data);
axios.post(`/communication`, data, {
headers: {
"content-type": "application/json"
},
})
.then(response => {
console.log('Received message:', response.data);
showToast('上传成功');
jsonId.value++;
})
.catch(error => {
//
console.error('Upload error:', error);
showToast('上传失败');
jsonId.value++;
});
} else {
MQTT_send(data);
showToast('设置已上传');
jsonId.value++;
}
}
const MQTT_send = (send_string) => {
console.log("MQTT 发送:" + JSON.stringify(send_string));
jsonId.value++;
if (/xazn/.test(navigator.userAgent) || /uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: JSON.stringify(send_string)
}
});
} else {
window.parent.postMessage({ str: JSON.stringify(send_string) }, "*");
}
};
const MQTT_recv = (string) => {
console.log("MQTT 接收的json:" + JSON.stringify(string));
loading.value = false;
const msg = JSON.parse(string);
console.log('Received message:', msg);
try {
parseAndFillData(msg);
eventSettingsRef.value.eventfilldata(msg);
} catch (error) {
console.error('Error in parseAndFillData:', error);
console.error('Error in eventfilldata:', error);
errorCount++;
if (errorCount >= maxRetries) {
showToast("设备异常,请检查系统");
return;
}
}
errorCount = 0; // Reset error count if successful
showToast("刷新成功");
};
onMounted(async () => {
await checkEnvironment();
console.log(isLocal.value);
window.MQTT_recv = MQTT_recv;
onRefresh();
});
onBeforeUnmount(() => {
});
return {
currentTitle,
jsonId,
loading,
onRefresh,
show,
onConfirmchannel,
channelValue,
channelcolumns,
showchannelPicker,
speedactions,
onSelectspeed,
showspeed,
selectedspeed,
selectedpower,
versions,
mac_addr,
radio_band,
value,
uploadEventSettings,
parseAndFillData,
checkEnvironment,
mode,
validateValue,
modeMap,
radio_bandMap,
eventSettingsRef,
MQTT_send,
MQTT_recv
};
}
};
</script>
<style scoped>
.page-container {
display: flex;
flex-direction: column;
min-height: 100vh;
position: relative;
margin-bottom: 100px;
}
.title {
text-align: center;
font-size: 30px;
}
.home {
padding: 20px;
border-radius: 10px;
border: 2px solid #0668fc;
margin: 50px 10px 10px;
flex: 1;
}
.page-container {
margin-top: 50px;
}
.fresh {
margin-top: 20px;
}
::v-deep .van-field__control {
text-align: right !important;
}
</style>

137
src/views/home/home.vue Normal file
View File

@ -0,0 +1,137 @@
<template>
<div class="page-container">
<Header :title="currentTitle"></Header>
<van-pull-refresh v-model="loading" @refresh="onRefresh" success-text="刷新成功">
<div class="content">
<van-notice-bar class="notice" scrollable text="下滑刷新页面" color="black" />
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
<van-swipe-item>信安智能</van-swipe-item>
<!-- <van-swipe-item>2</van-swipe-item> -->
<!-- <van-swipe-item>3</van-swipe-item> -->
</van-swipe>
<div class="item-content">
<van-cell-group inset>
<van-cell size="large" class="custom-cell" title="显示设置" icon="photo-o" is-link value="显示" @click="navigateTo('web/screen_main.html')" />
<van-cell size="large" class="custom-cell" title="声卡设置" icon="volume-o" is-link value="语音" @click="goto('voiceset')" />
<van-cell size="large" class="custom-cell" title="车牌识别" icon="search" is-link value="识别" @click="goto('recognition')" />
<van-cell size="large" class="custom-cell" title="预警设置" icon="warning-o" is-link value="预警" @click="goto('warning')" />
<van-cell size="large" class="custom-cell" title="远程喊话" icon="bullhorn-o" is-link value="喊话" @click="navigateTo('web/voice_copy.html')" />
</van-cell-group>
</div>
</div>
</van-pull-refresh>
<Footer></Footer>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import axios from 'axios';
import Header from "../../components/Header.vue";
import Footer from "../../components/Footer.vue";
export default {
components: {
Header,
Footer
},
setup() {
const currentTitle = ref('系统设置');
const loading = ref(false);
const router = useRouter();
//
const onRefresh = () => {
setTimeout(() => {
loading.value = false;
}, 1000);
};
//
const navigateTo = (path) => {
window.location.href = path;
};
// 使 router
const goto = (name) => {
router.push({ name });
};
onMounted(() => {
});
return {
currentTitle,
loading,
onRefresh,
navigateTo,
goto,
};
}
};
</script>
<style scoped>
.page-container {
display: flex;
flex-direction: column;
min-height: 100vh;
position: relative;
}
.content {
flex: 1;
overflow-y: auto;
padding: 20px;
border-radius: 20px !important;
margin-top: 80px;
margin-bottom: 40px;
min-height: 100vh;
}
.item-content {
margin-top: 20px;
}
van-pull-refresh {
flex: 1;
display: flex;
flex-direction: column;
}
.my-swipe .van-swipe-item {
color: #fff;
font-size: 20px;
line-height: 150px;
text-align: center;
background-color: #39a9ed;
border-radius: 10px;
margin-bottom: 10px;
}
.notice {
margin-bottom: 10px;
background-color: #fff;
}
/* Custom styles for van-cell */
.custom-cell .van-cell__title,
.custom-cell .van-cell__label,
.custom-cell .van-cell__value,
.custom-cell .van-icon {
font-size: 20px; /* Adjust the font size as needed */
}
.custom-cell .van-cell__title {
font-weight: bold;
}
.custom-cell .van-cell__value {
color: #666; /* Customize the value text color if needed */
}
</style>

184
src/views/loggin/loggin.vue Normal file
View File

@ -0,0 +1,184 @@
<template>
<div class="container">
<div class="welcome-wrapper">
<p>欢迎 :)</p>
</div>
<div class="login-wrapper">
<h4>登录</h4>
<div class="login-checkbox">
<van-cell-group class="custom-cell-group" inset id="password-input">
<van-field class="custom-field" v-model="password" type="password" label="密码" />
</van-cell-group>
<div class="options-row">
<van-checkbox v-model="checked">记住密码</van-checkbox>
<span class="forgot-password" @click="goto('reset')">修改密码</span>
</div>
</div>
<van-button class="login-button" type="primary" size="large" @click="login">登录</van-button>
</div>
<van-toast /> <!-- 这是挂载点 -->
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import axios from 'axios'; // axios
import '@vant/touch-emulator';
import { useStore } from 'vuex'; // useStore
export default {
setup() {
const checked = ref(true);
const password = ref('');
const router = useRouter();
const jsonId = ref(1); // JSON ID
const store = useStore(); // 使 useStore store
const goto = (name) => {
router.push({ name });
};
const login = () => {
const loginData = {
"board_id": 1,
"JSON_id": jsonId.value,
"gateway": {
"log_in": {
"type": 1,
"pass": password.value
}
}
};
console.log(JSON.stringify(loginData)); // loginData
axios.post(`/communication`, loginData, {
headers: {
"content-type": "application/json"
}
})
.then(response => {
//
const responseData = response.data;
if (responseData.gateway && responseData.gateway.log_in && responseData.gateway.log_in.return === 0) {
//
console.log(JSON.stringify(responseData)); // loginData
showSuccessToast('登录成功');
jsonId.value++;
store.commit('setAuthenticated', true); // mutation
router.push('/');
if (checked.value) {
localStorage.setItem('password', password.value);
} else {
localStorage.removeItem('password');
}
} else {
//
showFailToast('密码错误');
console.error('Login failed:', responseData);
}
})
.catch(error => {
//
showFailToast('登录失败,请重试');
console.error('Login error:', error);
});
};
onMounted(() => {
const savedPassword = localStorage.getItem('password');
if (savedPassword) {
password.value = savedPassword;
checked.value = true;
}
store.commit('setAuthenticated', false);
localStorage.removeItem('isAuthenticated');
});
return { checked, password, goto, login };
},
};
</script>
<style lang="less" scoped>
.container {
height: 100vh;
background-image: linear-gradient(0deg, #78e6f5 0%, #0668fc 100%);
}
.welcome-wrapper {
position: absolute;
left: 20px;
top: 10px;
color: #fff;
}
.custom-cell-group {
width: 100%;
display: flex;
justify-content: center;
}
.custom-field {
width: 100%;
max-width: 300px;
border: 2px solid #146bec;
border-radius: 10px;
box-sizing: border-box;
padding: 10px;
}
::v-deep .custom-field .van-field__control {
text-align: center;
}
.login-checkbox {
font-size: 14px;
display: flex;
flex-direction: column;
align-items: center;
}
.options-row {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
max-width: 300px;
margin-top: 30px;
}
.forgot-password {
color: #146bec;
cursor: pointer;
bottom: 0px;
}
.container .login-wrapper {
background-color: #fff;
width: 60%;
height: 400px;
padding: 0 10%;
position: fixed;
left: 50%;
border-radius: 15px;
top: 50%;
transform: translate(-50%, -50%);
animation-name: fadeIn;
margin-bottom: 20px;
}
h4 {
font-size: 40px;
color: #146bec;
}
.login-button {
margin-top: 40px;
}
.remember {
margin-top: 20px;
}
</style>

163
src/views/loggin/reset.vue Normal file
View File

@ -0,0 +1,163 @@
<template>
<div class="container">
<div class="welcome-wrapper">
<p class="title">欢迎使用 :)</p>
</div>
<div class="login-wrapper">
<p class="reset-title">修改密码</p>
<div class="change_pass">
<van-cell-group inset class="custom-cell-group">
<van-field v-model="password" class="custom-field" type="password" label="原始密码" />
<van-field v-model="password1" class="custom-field" type="password" label="新密码" />
<van-field v-model="password2" class="custom-field" type="password" label="确认新密码" />
</van-cell-group>
</div>
<div class="button-group">
<van-button type="primary" size="normal" class="flex-grow" @click="handleSubmit">确认</van-button>
<van-button type="primary" size="normal" class="flex-grow" @click="handleReset">取消</van-button>
</div>
</div>
</div>
</template>
<script>
import { useRouter } from 'vue-router';
import { ref } from 'vue';
import '@vant/touch-emulator';
import axios from 'axios'; // axios
export default {
setup() {
const router = useRouter();
const jsonId = ref(1); // JSON ID
const password = ref('');
const password1 = ref('');
const password2 = ref('');
const handleSubmit = () => {
const newPwd = password1.value.trim();
const rePwd = password2.value.trim();
if (!newPwd || !rePwd) {
showFailToast('密码不能为空');
return;
} else if (newPwd !== rePwd) {
showFailToast('密码不一致');
return;
}
const requestData = {
"JSON_id": jsonId.value,
"LPR_card": {
"gateway": {
"type": 2,
"pass": password.value,
"new_pass": password1.value
}
}
};
//
console.log(JSON.stringify(requestData)); // JSON
axios.post(`/communication`, requestData, {
headers: {
"content-type": "application/json"
}
})
.then(response => {
//
showSuccessToast('修改成功');
console.log(response.data);
// JSON ID
jsonId.value++;
router.push('/');
})
.catch(error => {
//
showFailToast('修改失败');
console.error(error);
});
};
const handleReset = () => {
//
router.push('/login');
};
return { password, password1, password2, handleSubmit, handleReset };
}
};
</script>
<style scoped>
.container {
height: 100vh;
background-image: linear-gradient(0deg, #78e6f5 0%, #0668fc 100%);
}
.flex-grow {
flex-grow: 1;
margin-right: 10px;
margin-left: 10px;
}
.welcome-wrapper {
position: absolute;
left: 20px;
top: 10px;
color: #fff;
}
.change_pass {
font-size: 14px;
display: flex;
flex-direction: column;
align-items: center;
}
.custom-cell-group {
width: 100%;
}
.container .login-wrapper {
background-color: #fff;
width: 60%;
height: 400px;
padding: 0 10%;
position: fixed;
left: 50%;
border-radius: 15px;
top: 50%;
transform: translate(-50%, -50%);
animation-name: fadeIn;
margin-bottom: 10px;
}
.reset-title {
font-size: 40px;
color: #146bec;
}
.button-group {
display: flex;
justify-content: space-between;
}
.custom-field {
width: 100%;
max-width: none;
border: 2px solid #146bec;
border-radius: 10px;
box-sizing: border-box;
padding: 10px;
margin-bottom: 10px;
}
.title {
color: #fff;
}
</style>

View File

@ -0,0 +1,879 @@
<template>
<Header :title="currentTitle"></Header>
<van-pull-refresh v-model="loading" success-text="刷新成功" @refresh="onRefresh">
<div class="content">
<div class="home">
<p class="title">数显设置</p>
<van-cell-group inset>
<van-field v-model.number="brightness" type="number" label="亮度" placeholder="请输入0-100" Max="100" />
<van-slider v-model.number="brightness" type="number" :step="1" :max="100" :min="0"
@change="onBrightnessChange" class="slider" />
</van-cell-group>
<van-cell is-link title="正常颜色" @click="showNormalColor = true">
{{ selectedNormalColor }}
</van-cell>
<van-action-sheet v-model:show="showNormalColor" :actions="actions" @select="onSelectNormalColor" />
<van-cell is-link title="超速颜色" @click="showOverSpeedColor = true">
{{ selectedOverSpeedColor }}
</van-cell>
<van-action-sheet v-model:show="showOverSpeedColor" :actions="actions"
@select="onSelectOverSpeedColor" />
<van-cell title="正常闪烁">
<van-switch v-model="checked" />
</van-cell>
<van-cell title="超速闪烁">
<van-switch v-model="showOverSpeedBlink" />
</van-cell>
<van-field v-model="fieldValue" is-link readonly label="闪烁速度" placeholder="请输入"
@click="showPicker = true" />
<van-popup v-model:show="showPicker" round position="bottom">
<van-picker :columns="columns" @cancel="showPicker = false" @confirm="onConfirm" />
</van-popup>
<div class="button-container">
<van-button type="primary" size="large" @click="uploadSettings">上传</van-button>
</div>
</div>
<div class="home">
<p class="title" style="pointer-events: none;">事件设置</p>
<div class="slider-container">
<p class="set-title">触发阈值</p>
<van-slider v-model="value" range @change="onChange" :min="0" :max="160" />
</div>
<div class="input-container">
<van-field v-model="value[0]" type="number" label="最小值" placeholder="最小值" />
<van-field v-model="value[1]" type="number" label="最大值" placeholder="最大值" />
</div>
<div class="slider-container">
<p class="set-title">超速阈值</p>
<van-slider v-model="overSpeedValue" range @change="onOverSpeedChange" :min="0" :max="160" />
</div>
<div class="input-container">
<van-field v-model="overSpeedValue[0]" type="number" label="最小值" placeholder="最小值" />
<van-field v-model="overSpeedValue[1]" type="number" label="最大值" placeholder="最大值" />
</div>
<div class="control">
<p class="title-control">双色屏控制</p>
<van-switch v-model="screencontrol" class="switch-control" />
</div>
<div class="control">
<p class="title-control">设备地址</p>
<van-field v-model="addr" placeholder="请输入设备地址" />
</div>
<div v-if="!screencontrol">
<van-button round type="success" size="large" @click="uploadthreshold">设置</van-button>
</div>
<div v-if="screencontrol" class="control">
<p class="title-control">事件列表</p>
<van-icon name="plus" @click="addEvent" />
</div>
<div v-if="screencontrol">
<div v-for="(event, index) in events" :key="index" :ref="'event' + index" class="event-item">
<van-swipe-cell :right-width="65" @close="onClose">
<template v-slot:right>
<van-button square type="danger" @click="removeEvent(index)"
class="delete-button">删除</van-button>
</template>
<van-cell is-link title="事件类型" v-model="event.type" @click="event.showTypePicker = true">
{{ event.type }}
</van-cell>
<van-field v-if="event.type === '其他'" v-model="event.code" label="事件编码"
placeholder="请输入事件编码" />
<!-- 改写 -->
<van-cell is-link title="事件来源" v-model="event.source"
@click="event.showsourcePicker = true">
{{ event.sourcename }}
</van-cell>
<van-field v-if="event.sourcename === '其他'" v-model="event.source" label="来源编码"
placeholder="请输入事件来源" />
<!-- 改写 -->
<van-field v-model="event.priority" label="优先级" placeholder="请输入优先级" />
<van-field v-model="event.showItem" is-link readonly label="显示节目" placeholder="选择显示节目"
@click="showItemPicker = index" />
<van-field v-model="event.showDuration" label="显示时长" placeholder="请输入显示时长" />
<van-field v-model="event.outputPin" is-link readonly label="输出引脚" placeholder="请输入输出引脚"
@click="showpinpicker = index" />
<van-cell v-if="event.outputPin !== '-1'" is-link title="输出电平" v-model="event.outlevel"
@click="event.showoutlevel = true">
{{ event.outlevel }}
</van-cell>
</van-swipe-cell>
<van-action-sheet v-model:show="event.showoutlevel" :actions="levelactions"
@select="onSelectlevel(event, $event)" />
<van-action-sheet v-model:show="event.showTypePicker" :actions="typeaction"
@select="onSelecttype(event, $event)" />
<!-- // -->
<van-action-sheet v-model:show="event.showsourcePicker" :actions="sourceaction"
@select="onSelectsource(event, $event)" />
<!-- // -->
<van-popup v-model="showItemPicker" :show="showItemPicker === index" round position="bottom">
<van-picker :columns="progremcolums" @cancel="() => showItemPicker = -1"
@confirm="value => onConfirmShowItem(index, value)" />
</van-popup>
<van-popup v-model="showpinpicker" :show="showpinpicker === index" round position="bottom">
<van-picker :columns="outpincolumns" @cancel="() => showpinpicker = -1"
@confirm="value => onConfirmoutpin(index, value)" />
</van-popup>
</div>
</div>
<div v-if="screencontrol && events.length > 0" class="button-container">
<van-button round type="success" size="large" @click="uploadEventSettings">设置</van-button>
</div>
</div>
</div>
</van-pull-refresh>
<Footer></Footer>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import Footer from "../../components/Footer.vue";
import Header from "../../components/Header.vue";
import '@vant/touch-emulator';
import * as mqtt from 'mqtt/dist/mqtt.min';
import axios from 'axios';
import { connectMQTT, client } from "../../components/MQTT/mqttclient";
// import { showToast } from 'vant';
export default {
components: {
Footer,
Header
},
data() {
return {
currentTitle: '车牌识别',
};
},
setup() {
const jsonId = ref(1); // JSON ID
const isLocal = ref(true); // isLocal false
const brightness = ref(0);
const fieldValue = ref('');
const loading = ref(false);
const selectedNormalColor = ref('');
const selectedOverSpeedColor = ref('');
const showNormalColor = ref(false);
const showOverSpeedColor = ref(false);
const checked = ref(false);
const showOverSpeedBlink = ref(false);
const screencontrol = ref(false);
const showPicker = ref(false);
const value = ref([10, 50]);
const overSpeedValue = ref([60, 160]);
const events = ref([]);
const showtype = ref(false);
const addr = ref('');
const showItemPicker = ref(-1);
const showpinpicker = ref(-1);
const outlevel = ref(false);
const typeaction = [
{ name: '默认显示', code: 0 },
{ name: '雷达触发(RS485 雷达)', code: 1 },
{ name: '雷达超速(RS485 雷达)', code: 2 },
{ name: '车牌触发(摄像头)', code: 3 },
{ name: '车牌超速(摄像头)', code: 4 },
{ name: '行人检测(相机)', code: 5 },
{ name: 'IN1下降沿', code: 0x51 },
{ name: 'IN2上升沿', code: 0x52 },
{ name: 'IN3下降沿', code: 0x53 },
{ name: 'IN4上升沿', code: 0x54 },
{ name: 'IN1低电平', code: 0x55 },
{ name: 'IN2高电平', code: 0x56 },
{ name: 'IN3低电平', code: 0x57 },
{ name: 'IN4高电平', code: 0x58 },
{ name: '其他', code: -1 },
];
const sourceaction = [
{ name: '本台设备', code: 0 },
{ name: '任意设备(不包含本设备)', code: 254 },
{ name: '任意设备', code: 255 },
{ name: '其他', code: 1 },
];
const levelactions = [
{ name: '高(0)', value: 0 },
{ name: '低(1)', value: 1 },
];
const onChange = (value) => showToast('当前值:' + value);
const onOverSpeedChange = (value) => showToast('当前超速值:' + value);
const actions = [
{ name: '红', value: 1 },
{ name: '绿', value: 2 },
{ name: '黄', value: 3 },
]
const columns = [
{ text: '1', value: '1' },
{ text: '2', value: '2' },
{ text: '3', value: '3' },
{ text: '4', value: '4' },
{ text: '5', value: '5' },
];
const progremcolums = [
{ text: '节目0', value: '0' },
{ text: '节目1', value: '1' },
{ text: '节目2', value: '2' },
{ text: '节目3', value: '3' },
{ text: '节目4', value: '4' },
{ text: '节目5', value: '5' },
{ text: '节目6', value: '6' },
{ text: '节目7', value: '7' },
{ text: '节目8', value: '8' },
{ text: '节目9', value: '9' },
];
const outpincolumns = [
{ text: '关闭(-1)', value: '-1' },
{ text: '引脚1(0)', value: '0' },
{ text: '引脚2(1)', value: '1' },
];
//
const checkEnvironment = () => {
if (window.location.hostname === '192.168.4.1') {
console.log('in local');
// isLocal true
isLocal.value = true;
} else {
// isLocal false
isLocal.value = false;
}
};
const onConfirmShowItem = (index, value) => {
// events.value[index].showItem = value.selectedOptions[0].text;
events.value[index].showItem = value.selectedOptions[0].value;
showItemPicker.value = -1;
};
const onConfirmoutpin = (index, value) => {
// events.value[index].outputPin = value.selectedOptions[0].text;
events.value[index].outputPin = value.selectedOptions[0].value;
showpinpicker.value = -1;
};
const onSelectNormalColor = (item) => {
showNormalColor.value = false;
selectedNormalColor.value = item.name;
showToast(item.name);
};
const onSelectOverSpeedColor = (item) => {
showOverSpeedColor.value = false;
selectedOverSpeedColor.value = item.name;
showToast(item.name);
};
const onConfirm = ({ selectedOptions }) => {
showPicker.value = false;
fieldValue.value = selectedOptions[0].text;
};
const onSelecttype = (event, selectedItem) => {
event.type = selectedItem.name; //
event.code = selectedItem.code.toString(); //
event.showTypePicker = false; //
showToast(event.type); //
};
//
const onSelectsource = (event, selectedItem) => {
event.sourcename = selectedItem.name; //
event.source = selectedItem.code.toString(); //
event.showsourcePicker = false; //
showToast(event.sourcename); //
};
const onSelectlevel = (event, selectedItem) => {
event.outlevelname = selectedItem.name; //
event.outlevel = selectedItem.value.toString(); //
event.showoutlevel = false; //
showToast(event.outlevelname);
};
//
const onRefresh = () => {
loading.value = true; // loading true
sendRequest();
};
const sendRequest = () => {
const requestload = {
JSON_id: jsonId.value,
board_id: 104,
LPR_card: {
get_seg_cfg: 1,
get_cfg: 1,
}
};
console.log(requestload);
let timeoutHandler;
if (isLocal.value) {
axios.post(`/communication`, requestload, {
headers: {
"content-type": "application/json"
},
timeout: 10000 // Set timeout to 10 seconds for Axios
})
.then(response => {
clearTimeout(timeoutHandler); // Clear the timeout if the request succeeds
console.log('Response data:', response.data);
parseAndFillData(response.data);
showToast('刷新成功');
jsonId.value++;
loading.value = false; // End loading
})
.catch(error => {
clearTimeout(timeoutHandler); // Clear the timeout on error
if (error.code === 'ECONNABORTED') {
console.error('Request timeout:', error);
showToast('刷新超时');
} else {
console.error('Upload error:', error);
showToast('刷新失败');
}
jsonId.value++;
loading.value = false; // End loading
});
// Set manual timeout to handle cases where no response is received
timeoutHandler = setTimeout(() => {
loading.value = false;
showToast('请求超时');
}, 10000); // 10 seconds timeout
} else {
// Sending via MQTT
MQTT_send(requestload);
// Set a manual timeout for MQTT
timeoutHandler = setTimeout(() => {
loading.value = false; // End loading if no response
showToast('请求超时'); // Display timeout message
}, 10000); // 10 seconds timeout for MQTT
}
};
const uploadSettings = () => {
if (!brightness.value || !selectedNormalColor.value || !selectedOverSpeedColor.value || !fieldValue.value) {
showToast('请填写完整数显信息');
return;
}
const payload = {
"JSON_id": jsonId.value,
board_id: 104,
LPR_card: {
seg_cfg: {
bright: parseInt(brightness.value),
trig_c: actions.findIndex(action => action.name === selectedNormalColor.value) + 1,
over_spd_c: actions.findIndex(action => action.name === selectedOverSpeedColor.value) + 1,
bk_trig_en: checked.value ? 1 : 0,
bk_over_spd_en: showOverSpeedBlink.value ? 1 : 0,
bk_spd: parseInt(fieldValue.value)
}
}
};
console.log(JSON.stringify(payload)); // JSON
if (isLocal.value) {
// 使 Axios
console.log('axios发送');
axios.post(`/communication`, payload, {
headers: {
"content-type": "application/json"
}
})
.then(response => {
if (response.data.LPR_card.seg_cfg_ok === 1) {
showToast('事件设置已上传');
}
console.log(response.data);
jsonId.value++;
})
.catch(error => {
//
// console.log(response.data);
console.error('Upload error:', error);
showToast('事件设置上传失败');
jsonId.value++;
});
} else {
jsonId.value++;
// 使 MQTT
console.log('mqtt发送');
MQTT_send(payload);
showToast("数显设置已上传")
}
};
//
const uploadthreshold = () => {
if (!addr.value) {
showToast('请填写设备地址');
return;
}
const threshold = {
JSON_id: jsonId.value,
board_id: 104,
LPR_card: {
trig_cfg: {
trig_spd_L: parseInt(value.value[0]),
trig_spd_H: parseInt(value.value[1]),
lmt_spd_L: parseInt(overSpeedValue.value[0]),
lmt_spd_H: parseInt(overSpeedValue.value[1]),
screen_ctrl_en: screencontrol.value ? 1 : 0,
addr: parseInt(addr.value),
},
},
};
console.log(JSON.stringify(threshold)); // JSON
if (isLocal.value) {
axios.post(`/communication`, threshold, {
headers: {
"content-type": "application/json"
}
})
.then(response => {
console.log('Response data:', response.data);
showToast('设置成功');
jsonId.value++;
})
.catch(error => {
//
console.error('Upload error:', error);
showToast('设置失败');
jsonId.value++;
});
}
else {
MQTT_send(threshold);
showToast("已发送设置")
}
};
const uploadEventSettings = () => {
for (const event of events.value) {
if (!event.type || !event.code || !event.source || !event.priority || !event.showItem || !event.showDuration || !event.outputPin || !addr.value) {
showToast('请填写完整事件信息');
return;
}
}
const eventPayload = {
"JSON_id": jsonId.value,
board_id: 104,
LPR_card: {
trig_cfg: {
trig_spd_L: parseInt(value.value[0]),
trig_spd_H: parseInt(value.value[1]),
lmt_spd_L: parseInt(overSpeedValue.value[0]),
lmt_spd_H: parseInt(overSpeedValue.value[1]),
screen_ctrl_en: screencontrol.value ? 1 : 0,
addr: parseInt(addr.value),
event: events.value.map(event => ({
code: parseInt(event.code),
source: parseInt(event.source),
priority: parseInt(event.priority),
prg_num: parseInt(event.showItem),
prg_time: parseInt(event.showDuration),
output: parseInt(event.outputPin),
level: parseInt(event.outlevel)
// level: event.outlevel.value
}))
},
},
};
console.log(JSON.stringify(eventPayload)); // JSON
if (isLocal.value) {
console.log('axios发送');
// 使 Axios
axios.post(`/communication`, eventPayload, {
headers: {
"content-type": "application/json"
},
})
.then(response => {
if (response.data.LPR_card.trig_cfg_ok === 1) {
showToast('事件设置已上传');
}
// showToast('');
console.log(response.data);
jsonId.value++;
})
.catch(error => {
//
console.error('Upload error:', error);
showToast('事件设置上传失败');
jsonId.value++;
});
} else {
console.log('mqtt发送');
jsonId.value++;
MQTT_send(eventPayload);
showToast("已发送请求");
}
};
//axios
const parseAndFillData = (msg) => {
if (msg.LPR_card) {
const config = msg.LPR_card.seg_cfg;
const trigCfg = msg.LPR_card.trig_cfg;
//
brightness.value = Number(msg.LPR_card.seg_cfg.bright);
selectedNormalColor.value = actions.find(action => action.value === config.trig_c).name;
selectedOverSpeedColor.value = actions.find(action => action.value === config.over_spd_c).name;
checked.value = !!config.bk_trig_en;
showOverSpeedBlink.value = !!config.bk_over_spd_en;
fieldValue.value = config.bk_spd.toString();
addr.value = trigCfg.addr;
//
value.value = [trigCfg.trig_spd_L, trigCfg.trig_spd_H];
overSpeedValue.value = [trigCfg.lmt_spd_L, trigCfg.lmt_spd_H]; 4
screencontrol.value = !!trigCfg.screen_ctrl_en;
//
events.value = trigCfg.event.map(event => {
let eventType;
let eventsource;
switch (event.source) {
case 0:
eventsource = '本台设备';
break;
case 254:
eventsource = '除本身外任意设备';
break;
case 255:
eventsource = '任意设备';
break;
default:
eventsource = '其他';
}
switch (event.code) {
case 0:
eventType = '默认显示';
break;
case 1:
eventType = '雷达触发(RS485 雷达)';
break;
case 2:
eventType = '雷达超速(RS485 雷达)';
break;
case 3:
eventType = '车牌触发(摄像头)';
break;
case 4:
eventType = '车牌超速(摄像头)';
break;
case 5:
eventType = '行人检测(相机)';
break;
case 0x51:
eventType = 'IN1下降沿';
break;
case 0x52:
eventType = 'IN2上升沿';
break;
case 0x53:
eventType = 'IN3下降沿';
break;
case 0x54:
eventType = 'IN4上升沿';
break;
case 0x55:
eventType = 'IN1低电平';
break;
case 0x56:
eventType = 'IN2高电平';
break;
case 0x57:
eventType = 'IN3低电平';
break;
case 0x58:
eventType = 'IN4高电平';
break;
default:
eventType = '其他';
}
return {
type: eventType,
code: event.code.toString(),
source: event.source.toString(),
sourcename: eventsource,
priority: event.priority.toString(),
showItem: event.prg_num.toString(),
// showItem: programnum,
showDuration: event.prg_time.toString(),
outputPin: event.output.toString(),
outlevel: event.level.toString(),
};
});
}
};
const MQTT_send = (send_string) => {
console.log("MQTT 发送:" + JSON.stringify(send_string));
jsonId.value++;
if (/xazn/.test(navigator.userAgent) || /uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: JSON.stringify(send_string)
}
});
} else {
window.parent.postMessage({ str: JSON.stringify(send_string) }, "*");
}
};
const MQTT_recv = (string) => {
loading.value = false;
console.log("MQTT 接收的json:" + string);
parseAndFillData(JSON.parse(string));
// showToast('');
console.log('Received message:', string);
};
// MQTT
onMounted(async () => {
await checkEnvironment();
console.log(isLocal.value);
window.MQTT_recv = MQTT_recv;
onRefresh();
});
onBeforeUnmount(() => {
});
const addEvent = () => {
events.value.push({
// pinname:'',
// name:'',
type: '',
code: '',
source: '',
priority: '',
showitem1: '',
showItem: '',
showDuration: '',
outputPin: '',
outputPin1: '',
outlevel: '',
outlevelname: '',
sourcename: '',
showTypePicker: false,
showoutlevel: false,
});
showToast('添加成功');
};
const removeEvent = (index) => {
events.value.splice(index, 1);
uploadEventSettings();
};
const onClose = (position, instance) => {
if (position === 'right') {
instance.close();
}
};
const onBrightnessChange = (value) => {
brightness.value = Number(value);
showToast('亮度值:' + value);
};
return {
brightness,
fieldValue,
loading,
showNormalColor,
showOverSpeedColor,
checked,
showOverSpeedBlink,
showPicker,
actions,
columns,
onSelectNormalColor,
onSelectOverSpeedColor,
onConfirm,
onRefresh,
selectedNormalColor,
selectedOverSpeedColor,
value,
onChange,
overSpeedValue,
onOverSpeedChange,
screencontrol,
events,
addEvent,
removeEvent,
uploadSettings,
showtype,
onSelecttype,
typeaction,
onClose,
onBrightnessChange,
uploadEventSettings,
parseAndFillData,
checkEnvironment,
isLocal,
jsonId,
addr,
onConfirmShowItem,
showItemPicker,
progremcolums,
onSelectlevel,
levelactions,
outlevel,
showpinpicker,
outpincolumns,
onConfirmoutpin,
sourceaction,
onSelectsource,
uploadthreshold,
MQTT_send,
MQTT_send
};
},
};
</script>
<style lang="less" scoped>
.home {
padding: 20px;
border-radius: 10px;
border: 2px solid #0668fc;
margin: 100px 10px 20px;
flex: 1;
}
.title {
text-align: center;
font-size: 30px;
}
.title-control {
text-align: left;
font-size: 15px;
margin: 0;
white-space: nowrap;
}
.content {
min-height: 100vh;
margin-bottom: 70px;
}
.button-container {
display: flex;
justify-content: center;
margin-top: 20px;
}
.set-title {
font-size: 15px;
margin-right: 10px;
white-space: nowrap;
}
.slider {
margin-top: 20px;
margin-bottom: 15px;
}
.slider-container {
display: flex;
align-items: center;
}
.control {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
.delete-button {
align-items: right;
}
.input-container {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.footer-container {
position: fixed;
bottom: 0;
width: 100%;
background-color: #fff;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.brightness {
padding-left: 0px !important;
}
::v-deep .van-field__label,
::v-deep .van-cell__title {
text-align: left !important;
margin-left: 0 !important;
padding-left: 10px !important;
}
::v-deep .van-field__control {
text-align: right !important;
}
.event-item {
margin-top: 20px;
padding: 10px;
border: 1px solid #e0e0e0;
border-radius: 10px;
}
.delete-button {
position: absolute;
top: 50%;
border-radius: 10px;
// transform: translateY(-50%);
}
.control .van-field__label {
white-space: nowrap;
}
</style>

View File

@ -0,0 +1,366 @@
<template>
<div class="page-container">
<Header :title="currentTitle"></Header>
<van-pull-refresh v-model="loading" success-text="刷新成功" @refresh="onRefresh">
<div class="content">
<!-- gateway -->
<div class="item">
<van-cell-group inset>
<div class="header">
<p class="title">网关卡</p>
<p :class="getStatusClass(gatewaystatus)" class="state">{{ gatewaystatus }}</p>
</div>
<van-divider :style="{ color: 'black' }" />
<van-field label="版本号:" :model-value="gatwayVision" readonly />
<van-field label="编译时间:" :model-value="gatewayTime" readonly />
</van-cell-group>
</div>
<!-- LED Screen -->
<div class="item">
<van-cell-group inset>
<div class="header">
<p class="title">双色LED屏驱动板</p>
<p :class="getStatusClass(ledStatus)" class="state">{{ ledStatus }}</p>
</div>
<van-divider :style="{ color: 'black' }" />
<van-field label="版本号:" :model-value="ledVision" readonly />
<van-field label="编译时间:" :model-value="ledTime" readonly />
</van-cell-group>
</div>
<!-- Car Recognition -->
<div class="item">
<van-cell-group inset>
<div class="header">
<p class="title">摄像头控制卡</p>
<p :class="getStatusClass(carStatus)" class="state">{{ carStatus }}</p>
</div>
<van-divider :style="{ color: 'black' }" />
<van-field label="版本号:" :model-value="carVision" readonly />
<van-field label="编译时间:" :model-value="carTime" readonly />
</van-cell-group>
</div>
<!-- 4G Sound Card -->
<div class="item">
<van-cell-group inset>
<div class="header">
<p class="title">音频控制卡</p>
<p :class="getStatusClass(g4Status)" class="state">{{ g4Status }}</p>
</div>
<van-divider :style="{ color: 'black' }" />
<van-field label="版本号:" :model-value="g4Vision" readonly />
<van-field label="编译时间:" :model-value="g4Time" readonly />
</van-cell-group>
</div>
<!-- LoRa -->
<div class="item">
<van-cell-group inset>
<div class="header">
<p class="title">LoRa预警板</p>
<p :class="getStatusClass(loraStatus)" class="state">{{ loraStatus }}</p>
</div>
<van-divider :style="{ color: 'black' }" />
<van-field label="版本号:" :model-value="loraVision" readonly />
<van-field label="编译时间:" :model-value="loraTime" readonly />
</van-cell-group>
</div>
</div>
</van-pull-refresh>
<Footer></Footer>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import Header from "../../components/Header.vue";
import Footer from "../../components/Footer.vue";
import axios from 'axios';
// import * as mqtt from 'mqtt/dist/mqtt.min';
import '@vant/touch-emulator';
export default {
components: {
Header,
Footer
},
setup() {
const currentTitle = ref('系统信息');
const loading = ref(false);
//
const gatwayVision = ref('');
const gatewayTime = ref('');
const gatewaystatus = ref('离线');
const ledVision = ref('');
const ledTime = ref('');
const ledStatus = ref('离线');
const carVision = ref('');
const carTime = ref('');
const carStatus = ref('离线');
const g4Vision = ref('');
const g4Time = ref('');
const g4Status = ref('离线');
const loraTime = ref('');
const loraVision = ref('');
const loraStatus = ref('离线');
let jsonId = ref(1);
let data; // data 使访
//
const isLocal = window.location.hostname === '192.168.4.1';
const MQTT_send = (send_string) => {
console.log("MQTT 发送:" + JSON.stringify(send_string));
if (/xazn/.test(navigator.userAgent) || /uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: JSON.stringify(send_string)
}
});
} else {
window.parent.postMessage({ str: JSON.stringify(send_string) }, "*");
}
};
const handleMQTTMessage = (string) => {
console.log("MQTT 接收:" + string);
const data = JSON.parse(string);
// console.log("MQTT :", JSON.stringify(data, null, 2)); // JSON
return new Promise((resolve, reject) => {
try {
if (data.led_protocol && data.led_protocol.info) {
const info = data.led_protocol.info;
ledVision.value = info.versions;
ledTime.value = info.compile_time;
ledStatus.value = '在线';
resolve(data);
} else if (data.LPR_card && data.LPR_card.info) {
const info = data.LPR_card.info;
carVision.value = info.versions;
carTime.value = info.compile_time;
carStatus.value = '在线';
resolve(data);
} else if (data.sound_card && data.sound_card.info) {
const info = data.sound_card.info;
g4Vision.value = info.versions;
g4Time.value = info.compile_time;
g4Status.value = '在线';
resolve(data);
} else if (data.LoRa_card && data.LoRa_card.info) {
const info = data.LoRa_card.info;
loraVision.value = info.versions;
loraTime.value = info.compile_time;
loraStatus.value = '在线';
resolve(data);
} else if (data.gateway && data.gateway.info) {
const info = data.gateway.info;
gatwayVision.value = info.versions;
gatewayTime.value = info.compile_time;
gatewaystatus.value = '在线';
resolve(data);
} else {
resolve(data);
}
} catch (error) {
reject(error);
}
});
};
//
const sendRequest = async (requestData, requestType) => {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
console.warn('请求超时,跳过该请求');
resolve({ skipped: true });
}, 5000); // 5
if (requestType === 'mqtt') {
MQTT_send(requestData);
// 使 handleMessage
} else if (requestType === 'axios') {
axios.post('/communication', requestData, {
headers: {
"content-type": "application/json"
},
})
.then(response => {
clearTimeout(timeout); //
const data = response.data;
console.log('收到 Axios 响应:', data);
if (data.led_protocol && data.led_protocol.info) {
const info = data.led_protocol.info;
ledVision.value = info.versions;
ledTime.value = info.compile_time;
ledStatus.value = '在线';
resolve(data);
} else if (data.LPR_card && data.LPR_card.info) {
const info = data.LPR_card.info;
carVision.value = info.versions;
carTime.value = info.compile_time;
carStatus.value = '在线';
resolve(data);
} else if (data.sound_card && data.sound_card.info) {
const info = data.sound_card.info;
g4Vision.value = info.versions;
g4Time.value = info.compile_time;
g4Status.value = '在线';
resolve(data);
} else if (data.LoRa_card && data.LoRa_card.info) {
const info = data.LoRa_card.info;
loraVision.value = info.versions;
loraTime.value = info.compile_time;
loraStatus.value = '在线';
resolve(data);
} else if (data.gateway && data.gateway.info) {
const info = data.gateway.info;
gatwayVision.value = info.versions;
gatewayTime.value = info.compile_time;
gatewaystatus.value = '在线';
resolve(data);
} else {
resolve(data);
}
})
.catch(error => {
clearTimeout(timeout); //
if (error.response && error.response.status === 500) {
console.error('收到 500 错误码,跳过该请求');
resolve({ skipped: true });
} else {
console.error('Axios 请求错误:', error);
reject(error);
}
});
}
});
};
// MQTT
const MQTT_recv = (string) => {
console.log("MQTT 接收的json:" + string);
handleMQTTMessage(string);
};
//
const onRefresh = async () => {
loading.value = true; // loading true
const requests = [
{ type: isLocal ? 'axios' : 'mqtt', data: { "JSON_id": jsonId.value++, "board_id": 1, "gateway": { "get_info": 1 } } },
{ type: isLocal ? 'axios' : 'mqtt', data: { "JSON_id": jsonId.value++, "board_id": 102, "led_protocol": { "get_info": 1 } } },
{ type: isLocal ? 'axios' : 'mqtt', data: { "JSON_id": jsonId.value++, "board_id": 104, "LPR_card": { "get_info": 1 } } },
{ type: isLocal ? 'axios' : 'mqtt', data: { "JSON_id": jsonId.value++, "board_id": 103, "sound_card": { "get_info": 1 } } },
{ type: isLocal ? 'axios' : 'mqtt', data: { "JSON_id": jsonId.value++, "board_id": 105, "LoRa_card": { "get_info": 1 } } },
];
for (const request of requests) {
await sendRequest(request.data, request.type);
}
loading.value = false; // loading
// 线
if (!ledVision.value) ledStatus.value = '离线';
if (!carVision.value) carStatus.value = '离线';
if (!g4Vision.value) g4Status.value = '离线';
if (!loraVision.value) loraStatus.value = '离线';
if (!gatwayVision.value) gatewaystatus.value = '离线';
};
// MQTT
onMounted(() => {
console.log(isLocal);
onRefresh();
window.MQTT_recv = MQTT_recv;
});
onBeforeUnmount(() => {
});
//
const getStatusClass = (status) => {
return status === '在线' ? 'state online' : 'state offline';
};
return {
currentTitle,
loading,
onRefresh,
ledVision,
ledTime,
carVision,
carTime,
g4Vision,
g4Time,
loraTime,
loraVision,
ledStatus,
g4Status,
carStatus,
loraStatus,
getStatusClass,
gatwayVision,
gatewayTime,
gatewaystatus,
MQTT_send,
MQTT_recv,
handleMQTTMessage,
};
}
};
</script>
<style scoped>
.page-container {
display: flex;
flex-direction: column;
min-height: 100vh;
position: relative;
}
.state {
text-align: right;
font-size: 20px;
}
.online {
color: green;
}
.offline {
color: gray;
}
.content {
flex: 1;
overflow-y: auto;
padding: 20px;
border-radius: 20px !important;
margin-top: 80px;
margin-bottom: 100px;
min-height: 100vh;
}
.item {
border: 2px solid #0668fc;
border-radius: 10px;
margin-top: 20px;
display: flex;
}
.title {
text-align: center;
font-size: 30px;
}
</style>

1404
src/views/voice/voiceset.vue Normal file

File diff suppressed because it is too large Load Diff

48
vue.config.js Normal file
View File

@ -0,0 +1,48 @@
const { defineConfig } = require('@vue/cli-service');
const { VantResolver } = require('@vant/auto-import-resolver');
const AutoImport = require('unplugin-auto-import/webpack');
const Components = require('unplugin-vue-components/webpack');
module.exports = defineConfig({
lintOnSave: false,
productionSourceMap: false,
transpileDependencies: true,
publicPath: './',
css: {
loaderOptions: {
postcss: {
postcssOptions: {
plugins: [
require('autoprefixer'),
// 其他插件
]
}
}
}
},
devServer: {
open: true,
hot: true,//自动保存
},
configureWebpack: {
plugins: [
// 当 unplugin-vue-components 版本小于 0.26.0 时,使用以下写法
// AutoImport({ resolvers: [VantResolver()] }),
// Components({ resolvers: [VantResolver()] }),
//当大于等于 0.26.0 时,使用以下写法
AutoImport.default({
resolvers: [VantResolver()],
}),
Components.default({ resolvers: [VantResolver()] }),
// new CompressionPlugin({
// algorithm: 'gzip', // 使用gzip压缩
// test: /\.js$|\.html$|\.css$/, // 匹配文件名
// filename: '[path][base].gz[query]', // 压缩后的文件名(保持原文件名,后缀加.gz)
// minRatio: 1, // 压缩率小于1才会压缩
// threshold: 0, // 对超过10k的数据压缩
// deleteOriginalAssets: true, // 是否删除未压缩的源文件谨慎设置如果希望提供非gzip的资源可不设置或者设置为false比如删除打包后的gz后还可以加载到原始资源文件
// }),
],
},
});

1
web/css/193.0c29947b.css Normal file
View File

@ -0,0 +1 @@
.van-checkbox-group--horizontal{display:flex;flex-wrap:wrap}:host,:root{--van-checkbox-size:20px;--van-checkbox-border-color:var(--van-gray-5);--van-checkbox-duration:var(--van-duration-fast);--van-checkbox-label-margin:var(--van-padding-xs);--van-checkbox-label-color:var(--van-text-color);--van-checkbox-checked-icon-color:var(--van-primary-color);--van-checkbox-disabled-icon-color:var(--van-gray-5);--van-checkbox-disabled-label-color:var(--van-text-color-3);--van-checkbox-disabled-background:var(--van-border-color)}.van-checkbox{display:flex;align-items:center;overflow:hidden;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.van-checkbox--disabled{cursor:not-allowed}.van-checkbox--label-disabled{cursor:default}.van-checkbox--horizontal{margin-right:var(--van-padding-sm)}.van-checkbox__icon{flex:none;height:1em;font-size:var(--van-checkbox-size);line-height:1em;cursor:pointer}.van-checkbox__icon .van-icon{display:block;box-sizing:border-box;width:1.25em;height:1.25em;color:transparent;font-size:.8em;line-height:1.25;text-align:center;border:1px solid var(--van-checkbox-border-color);transition-duration:var(--van-checkbox-duration);transition-property:color,border-color,background-color}.van-checkbox__icon--round .van-icon{border-radius:100%}.van-checkbox__icon--indeterminate .van-icon{display:flex;align-items:center;justify-content:center}.van-checkbox__icon--checked .van-icon,.van-checkbox__icon--indeterminate .van-icon{color:var(--van-white);border-color:var(--van-checkbox-checked-icon-color);background-color:var(--van-checkbox-checked-icon-color)}.van-checkbox__icon--disabled{cursor:not-allowed}.van-checkbox__icon--disabled .van-icon{background-color:var(--van-checkbox-disabled-background);border-color:var(--van-checkbox-disabled-icon-color)}.van-checkbox__icon--disabled.van-checkbox__icon--checked .van-icon{color:var(--van-checkbox-disabled-icon-color)}.van-checkbox__label{margin-left:var(--van-checkbox-label-margin);color:var(--van-checkbox-label-color);line-height:var(--van-checkbox-size)}.van-checkbox__label--left{margin:0 var(--van-checkbox-label-margin) 0 0}.van-checkbox__label--disabled{color:var(--van-checkbox-disabled-label-color)}.container[data-v-cb07f33e]{height:100vh;background-image:linear-gradient(0deg,#78e6f5,#0668fc)}.welcome-wrapper[data-v-cb07f33e]{position:absolute;left:20px;top:10px;color:#fff}.custom-cell-group[data-v-cb07f33e]{width:100%;display:flex;justify-content:center}.custom-field[data-v-cb07f33e]{width:100%;max-width:300px;border:2px solid #146bec;border-radius:10px;box-sizing:border-box;padding:10px}[data-v-cb07f33e] .custom-field .van-field__control{text-align:center}.login-checkbox[data-v-cb07f33e]{font-size:14px;display:flex;flex-direction:column;align-items:center}.options-row[data-v-cb07f33e]{display:flex;justify-content:space-between;align-items:center;width:100%;max-width:300px;margin-top:30px}.forgot-password[data-v-cb07f33e]{color:#146bec;cursor:pointer;bottom:0}.container .login-wrapper[data-v-cb07f33e]{background-color:#fff;width:60%;height:400px;padding:0 10%;position:fixed;left:50%;border-radius:15px;top:50%;transform:translate(-50%,-50%);animation-name:fadeIn;margin-bottom:20px}h4[data-v-cb07f33e]{font-size:40px;color:#146bec}.login-button[data-v-cb07f33e]{margin-top:40px}.remember[data-v-cb07f33e]{margin-top:20px}

1
web/css/239.fd5d7b06.css Normal file
View File

@ -0,0 +1 @@
.container[data-v-4dd8be90]{height:100vh;background-image:linear-gradient(0deg,#78e6f5,#0668fc)}.flex-grow[data-v-4dd8be90]{flex-grow:1;margin-right:10px;margin-left:10px}.welcome-wrapper[data-v-4dd8be90]{position:absolute;left:20px;top:10px;color:#fff}.change_pass[data-v-4dd8be90]{font-size:14px;display:flex;flex-direction:column;align-items:center}.custom-cell-group[data-v-4dd8be90]{width:100%}.container .login-wrapper[data-v-4dd8be90]{background-color:#fff;width:60%;height:400px;padding:0 10%;position:fixed;left:50%;border-radius:15px;top:50%;transform:translate(-50%,-50%);animation-name:fadeIn;margin-bottom:10px}.reset-title[data-v-4dd8be90]{font-size:40px;color:#146bec}.button-group[data-v-4dd8be90]{display:flex;justify-content:space-between}.custom-field[data-v-4dd8be90]{width:100%;max-width:none;border:2px solid #146bec;border-radius:10px;box-sizing:border-box;padding:10px;margin-bottom:10px}.title[data-v-4dd8be90]{color:#fff}

1
web/css/419.832a40ea.css Normal file

File diff suppressed because one or more lines are too long

1
web/css/619.93201e95.css Normal file

File diff suppressed because one or more lines are too long

1
web/css/718.dc007c1e.css Normal file

File diff suppressed because one or more lines are too long

1
web/css/769.522c5d34.css Normal file
View File

@ -0,0 +1 @@
:host,:root{--van-tabbar-height:50px;--van-tabbar-z-index:1;--van-tabbar-background:var(--van-background-2)}.van-tabbar{z-index:var(--van-tabbar-z-index);display:flex;box-sizing:content-box;width:100%;height:var(--van-tabbar-height);background:var(--van-tabbar-background)}.van-tabbar--fixed{position:fixed;bottom:0;left:0}:host,:root{--van-tabbar-item-font-size:var(--van-font-size-sm);--van-tabbar-item-text-color:var(--van-text-color);--van-tabbar-item-active-color:var(--van-primary-color);--van-tabbar-item-active-background:var(--van-background-2);--van-tabbar-item-line-height:1;--van-tabbar-item-icon-size:22px;--van-tabbar-item-icon-margin-bottom:var(--van-padding-base)}.van-tabbar-item{display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;color:var(--van-tabbar-item-text-color);font-size:var(--van-tabbar-item-font-size);line-height:var(--van-tabbar-item-line-height);cursor:pointer}.van-tabbar-item__icon{margin-bottom:var(--van-tabbar-item-icon-margin-bottom);font-size:var(--van-tabbar-item-icon-size)}.van-tabbar-item__icon .van-icon{display:block}.van-tabbar-item__icon .van-badge{margin-top:var(--van-padding-base)}.van-tabbar-item__icon img{display:block;height:20px}.van-tabbar-item--active{color:var(--van-tabbar-item-active-color);background-color:var(--van-tabbar-item-active-background)}.footer{height:50px;position:fixed;bottom:0;left:0;width:100%;z-index:999}

1
web/css/772.fdf33262.css Normal file

File diff suppressed because one or more lines are too long

1
web/css/928.e3bab1c5.css Normal file

File diff suppressed because one or more lines are too long

1
web/css/960.56b57727.css Normal file

File diff suppressed because one or more lines are too long

BIN
web/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

1
web/js/149.2f4f7417.js Normal file

File diff suppressed because one or more lines are too long

1
web/js/193.256e1126.js Normal file

File diff suppressed because one or more lines are too long

1
web/js/233.a1cddea4.js Normal file

File diff suppressed because one or more lines are too long

1
web/js/239.1c6f4606.js Normal file
View File

@ -0,0 +1 @@
"use strict";(self["webpackChunkset_vue"]=self["webpackChunkset_vue"]||[]).push([[239],{5239:function(e,s,l){l.r(s),l.d(s,{default:function(){return y}});var a=l(122),o=(l(9998),l(3788)),t=(l(7540),l(5050)),n=(l(9766),l(6768));const d=e=>((0,n.Qi)("data-v-4dd8be90"),e=e(),(0,n.jt)(),e),r={class:"container"},u=d((()=>(0,n.Lk)("div",{class:"welcome-wrapper"},[(0,n.Lk)("p",{class:"title"},"欢迎使用 :)")],-1))),c={class:"login-wrapper"},p=d((()=>(0,n.Lk)("p",{class:"reset-title"},"修改密码",-1))),i={class:"change_pass"},m={class:"button-group"};function w(e,s,l,d,w,v){const f=t.D0,k=o.Qh,b=a.$n;return(0,n.uX)(),(0,n.CE)("div",r,[u,(0,n.Lk)("div",c,[p,(0,n.Lk)("div",i,[(0,n.bF)(k,{inset:"",class:"custom-cell-group"},{default:(0,n.k6)((()=>[(0,n.bF)(f,{modelValue:d.password,"onUpdate:modelValue":s[0]||(s[0]=e=>d.password=e),class:"custom-field",type:"password",label:"原始密码"},null,8,["modelValue"]),(0,n.bF)(f,{modelValue:d.password1,"onUpdate:modelValue":s[1]||(s[1]=e=>d.password1=e),class:"custom-field",type:"password",label:"新密码"},null,8,["modelValue"]),(0,n.bF)(f,{modelValue:d.password2,"onUpdate:modelValue":s[2]||(s[2]=e=>d.password2=e),class:"custom-field",type:"password",label:"确认新密码"},null,8,["modelValue"])])),_:1})]),(0,n.Lk)("div",m,[(0,n.bF)(b,{type:"primary",size:"normal",class:"flex-grow",onClick:d.handleSubmit},{default:(0,n.k6)((()=>[(0,n.eW)("确认")])),_:1},8,["onClick"]),(0,n.bF)(b,{type:"primary",size:"normal",class:"flex-grow",onClick:d.handleReset},{default:(0,n.k6)((()=>[(0,n.eW)("取消")])),_:1},8,["onClick"])])])])}l(4114);var v=l(1387),f=l(144),k=(l(8628),l(4373)),b=l(1508),h=(l(3081),{setup(){const e=(0,v.rd)(),s=(0,f.KR)(""),l=(0,f.KR)(""),a=(0,f.KR)(""),o=()=>{const o=l.value.trim(),t=a.value.trim();if(!o||!t)return void(0,b.xr)("密码不能为空");if(o!==t)return void(0,b.xr)("密码不一致");const n={JSON_id:1,LPR_card:{log_in:{type:2,pass:s.value,new_pass:l.value}}};console.log(JSON.stringify(n)),k.A.post("/communication",n,{headers:{"content-type":"application/json"}}).then((s=>{(0,b.GF)("修改成功"),console.log(s.data),jsonId.value++,e.push("/")})).catch((e=>{(0,b.xr)("修改失败"),console.error(e)}))},t=()=>{e.push("/login")};return{password:s,password1:l,password2:a,handleSubmit:o,handleReset:t}}}),_=l(1241);const g=(0,_.A)(h,[["render",w],["__scopeId","data-v-4dd8be90"]]);var y=g}}]);

1
web/js/419.a70e3c85.js Normal file

File diff suppressed because one or more lines are too long

1
web/js/506.70402c53.js Normal file

File diff suppressed because one or more lines are too long

1
web/js/619.a1ca49f9.js Normal file

File diff suppressed because one or more lines are too long

1
web/js/718.62d77b72.js Normal file

File diff suppressed because one or more lines are too long

1
web/js/769.9bee6fb6.js Normal file
View File

@ -0,0 +1 @@
"use strict";(self["webpackChunkset_vue"]=self["webpackChunkset_vue"]||[]).push([[769],{6769:function(e,t,n){n.r(t),n.d(t,{default:function(){return T}});var a=n(4726),o=n(6768),r=n(144),l=n(5828),i=n(6370),c=n(7905),u=n(4612),s=n(9725),d=n(6591),v=n(4397);const[f,p]=(0,l.YX)("tabbar"),m={route:Boolean,fixed:i.Rd,border:i.Rd,zIndex:i.VQ,placeholder:Boolean,activeColor:String,beforeChange:Function,inactiveColor:String,modelValue:(0,i.TU)(0),safeAreaInsetBottom:{type:Boolean,default:null}},b=Symbol(f);var h=(0,o.pM)({name:f,props:m,emits:["change","update:modelValue"],setup(e,{emit:t,slots:n}){const a=(0,r.KR)(),{linkChildren:l}=(0,d.Py)(b),i=(0,v.h)(a,p),f=()=>{var t;return null!=(t=e.safeAreaInsetBottom)?t:e.fixed},m=()=>{var t;const{fixed:r,zIndex:l,border:i}=e;return(0,o.bF)("div",{ref:a,role:"tablist",style:(0,c.AO)(l),class:[p({fixed:r}),{[u.pT]:i,"van-safe-area-bottom":f()}]},[null==(t=n.default)?void 0:t.call(n)])},h=(n,a)=>{(0,s.m)(e.beforeChange,{args:[n],done(){t("update:modelValue",n),t("change",n),a()}})};return l({props:e,setActive:h}),()=>e.fixed&&e.placeholder?i(m):m()}});const g=(0,a.G)(h);n(6647);var x=n(8442),C=n(4548),V=n(5632),k=n(3408);const[F,y]=(0,l.YX)("tabbar-item"),B=(0,x.X$)({},C.aI,{dot:Boolean,icon:String,name:i.VQ,badge:i.VQ,badgeProps:Object,iconPrefix:String});var I=(0,o.pM)({name:F,props:B,emits:["click"],setup(e,{emit:t,slots:n}){const a=(0,C.lq)(),r=(0,o.nI)().proxy,{parent:l,index:i}=(0,d.cJ)(b);if(!l)return void 0;const c=(0,o.EW)((()=>{var t;const{route:n,modelValue:a}=l.props;if(n&&"$route"in r){const{$route:t}=r,{to:n}=e,a=(0,x.Gv)(n)?n:{path:n};return!!t.matched.find((e=>{const t="path"in a&&a.path===e.path,n="name"in a&&a.name===e.name;return t||n}))}return(null!=(t=e.name)?t:i.value)===a})),u=n=>{var o;c.value||l.setActive(null!=(o=e.name)?o:i.value,a),t("click",n)},s=()=>n.icon?n.icon({active:c.value}):e.icon?(0,o.bF)(V.In,{name:e.icon,classPrefix:e.iconPrefix},null):void 0;return()=>{var t;const{dot:a,badge:r}=e,{activeColor:i,inactiveColor:d}=l.props,v=c.value?i:d;return(0,o.bF)("div",{role:"tab",class:y({active:c.value}),style:{color:v},tabindex:0,"aria-selected":c.value,onClick:u},[(0,o.bF)(k.Ex,(0,o.v6)({dot:a,class:y("icon"),content:r},e.badgeProps),{default:s}),(0,o.bF)("div",{class:y("text")},[null==(t=n.default)?void 0:t.call(n,{active:c.value})])])}}});const A=(0,a.G)(I);n(7708),n(7484);const P={class:"footer"};function w(e,t,n,a,r,l){const i=(0,o.g2)("router-view"),c=A,u=g;return(0,o.uX)(),(0,o.CE)("div",P,[(0,o.bF)(i),(0,o.bF)(u,{modelValue:a.active,"onUpdate:modelValue":t[0]||(t[0]=e=>a.active=e),onChange:a.onChange},{default:(0,o.k6)((()=>[(0,o.bF)(c,{icon:"home-o",name:"home"},{default:(0,o.k6)((()=>[(0,o.eW)("系统设置")])),_:1}),(0,o.bF)(c,{icon:"setting-o",name:"info"},{default:(0,o.k6)((()=>[(0,o.eW)("系统信息")])),_:1})])),_:1},8,["modelValue","onChange"])])}n(4114);var R=n(1387),S={setup(){const e=(0,r.KR)("home"),t=(0,R.rd)(),n=(0,R.lq)(),a=e=>{t.push({name:e})};return(0,o.nT)((()=>{e.value=n.name})),{active:e,onChange:a}}},X=n(1241);const _=(0,X.A)(S,[["render",w]]);var T=_},4397:function(e,t,n){n.d(t,{h:function(){return u}});var a=n(6768),o=n(6591),r=n(144),l=n(240),i=n(8957);const c=(e,t)=>{const n=(0,r.KR)(),c=()=>{n.value=(0,o.yD)(e).height};return(0,a.sV)((()=>{if((0,a.dY)(c),t)for(let e=1;e<=3;e++)setTimeout(c,100*e)})),(0,i.V)((()=>(0,a.dY)(c))),(0,a.wB)([l.Xw,l.C7],c),n};function u(e,t){const n=c(e,!0);return e=>(0,a.bF)("div",{class:t("placeholder"),style:{height:n.value?`${n.value}px`:void 0}},[e()])}}}]);

1
web/js/772.ea12d9e4.js Normal file
View File

@ -0,0 +1 @@
"use strict";(self["webpackChunkset_vue"]=self["webpackChunkset_vue"]||[]).push([[772],{7265:function(){},1351:function(e,t,l){l.r(t),l.d(t,{default:function(){return h}});var a=l(6769),n=l(6987),r=(l(6463),l(4758)),u=l(6768);const o=e=>((0,u.Qi)("data-v-14c7b2a1"),e=e(),(0,u.jt)(),e),s={class:"page-container"},c=o((()=>(0,u.Lk)("div",{class:"content"}," 预警设置 ",-1)));function i(e,t,l,o,i,v){const f=r.A,d=n.j5,p=a["default"];return(0,u.uX)(),(0,u.CE)("div",s,[(0,u.bF)(f,{title:o.currentTitle},null,8,["title"]),(0,u.bF)(d,{loading:o.loading,"onUpdate:loading":t[0]||(t[0]=e=>o.loading=e),"success-text":"刷新成功",onRefresh:o.onRefresh},{default:(0,u.k6)((()=>[c])),_:1},8,["loading","onRefresh"]),(0,u.bF)(p)])}l(4114);var v=l(144),f=l(1387),d=(l(8628),{components:{Header:r.A,Footer:a["default"]},setup(){const e=(0,v.KR)("预警设置"),t=(0,f.rd)(),l=(0,v.KR)(!1),a=()=>{setTimeout((()=>{l.value=!1}),1e3)},n=e=>{t.push({name:e})};return{currentTitle:e,loading:l,onRefresh:a,goto:n}}}),p=l(1241);const b=(0,p.A)(d,[["render",i],["__scopeId","data-v-14c7b2a1"]]);var h=b},4390:function(e,t,l){l.d(t,{P:function(){return u}});var a=l(144),n=l(4612);function r(e,t){return e>t?"horizontal":t>e?"vertical":""}function u(){const e=(0,a.KR)(0),t=(0,a.KR)(0),l=(0,a.KR)(0),u=(0,a.KR)(0),o=(0,a.KR)(0),s=(0,a.KR)(0),c=(0,a.KR)(""),i=(0,a.KR)(!0),v=()=>"vertical"===c.value,f=()=>"horizontal"===c.value,d=()=>{l.value=0,u.value=0,o.value=0,s.value=0,c.value="",i.value=!0},p=l=>{d(),e.value=l.touches[0].clientX,t.value=l.touches[0].clientY},b=a=>{const v=a.touches[0];l.value=(v.clientX<0?0:v.clientX)-e.value,u.value=v.clientY-t.value,o.value=Math.abs(l.value),s.value=Math.abs(u.value);const f=10;(!c.value||o.value<f&&s.value<f)&&(c.value=r(o.value,s.value)),i.value&&(o.value>n.Ez||s.value>n.Ez)&&(i.value=!1)};return{move:b,start:p,reset:d,startX:e,startY:t,deltaX:l,deltaY:u,offsetX:o,offsetY:s,direction:c,isVertical:v,isHorizontal:f,isTap:i}}},2094:function(e,t,l){l.d(t,{Rh:function(){return b}});var a=l(4726),n=l(6768),r=l(5828),u=l(6370),o=l(8442),s=l(7905);const[c,i]=(0,r.YX)("loading"),v=Array(12).fill(null).map(((e,t)=>(0,n.bF)("i",{class:i("line",String(t+1))},null))),f=(0,n.bF)("svg",{class:i("circular"),viewBox:"25 25 50 50"},[(0,n.bF)("circle",{cx:"50",cy:"50",r:"20",fill:"none"},null)]),d={size:u.VQ,type:(0,u.Ts)("circular"),color:String,vertical:Boolean,textSize:u.VQ,textColor:String};var p=(0,n.pM)({name:c,props:d,setup(e,{slots:t}){const l=(0,n.EW)((()=>(0,o.X$)({color:e.color},(0,s.vE)(e.size)))),a=()=>{const a="spinner"===e.type?v:f;return(0,n.bF)("span",{class:i("spinner",e.type),style:l.value},[t.icon?t.icon():a])},r=()=>{var l;if(t.default)return(0,n.bF)("span",{class:i("text"),style:{fontSize:(0,s._V)(e.textSize),color:null!=(l=e.textColor)?l:e.color}},[t.default()])};return()=>{const{type:t,vertical:l}=e;return(0,n.bF)("div",{class:i([t,{vertical:l}]),"aria-live":"polite","aria-busy":!0},[a(),r()])}}});const b=(0,a.G)(p)}}]);

1
web/js/928.aebea282.js Normal file
View File

@ -0,0 +1 @@
"use strict";(self["webpackChunkset_vue"]=self["webpackChunkset_vue"]||[]).push([[928],{3133:function(e,l,a){a.r(l),a.d(l,{default:function(){return x}});var o=a(6769),t=a(6987),n=(a(6463),a(3788)),s=(a(7540),a(5050)),i=(a(9766),a(4726)),r=a(6768),c=a(5828),d=a(6370);const[u,v]=(0,c.YX)("divider"),m={dashed:Boolean,hairline:d.Rd,vertical:Boolean,contentPosition:(0,d.Ts)("center")};var b=(0,r.pM)({name:u,props:m,setup(e,{slots:l}){return()=>{var a;return(0,r.bF)("div",{role:"separator",class:v({dashed:e.dashed,hairline:e.hairline,vertical:e.vertical,[`content-${e.contentPosition}`]:!!l.default&&!e.vertical})},[!e.vertical&&(null==(a=l.default)?void 0:a.call(l))])}}});const f=(0,i.G)(b);a(6647);var p=a(4758);const k=e=>((0,r.Qi)("data-v-96208070"),e=e(),(0,r.jt)(),e),R={class:"page-container"},F={class:"content"},_={class:"item"},g=k((()=>(0,r.Lk)("p",{class:"title"},"双色LED屏驱动板",-1))),h={class:"item"},L=k((()=>(0,r.Lk)("p",{class:"title"},"车辆识别",-1))),y={class:"item"},T=k((()=>(0,r.Lk)("p",{class:"title"},"4G声卡",-1)));function V(e,l,a,i,c,d){const u=p.A,v=f,m=s.D0,b=n.Qh,k=t.j5,V=o["default"];return(0,r.uX)(),(0,r.CE)("div",R,[(0,r.bF)(u,{title:i.currentTitle},null,8,["title"]),(0,r.bF)(k,{modelValue:i.loading,"onUpdate:modelValue":l[0]||(l[0]=e=>i.loading=e),"success-text":"刷新成功",onRefresh:i.onRefresh},{default:(0,r.k6)((()=>[(0,r.Lk)("div",F,[(0,r.Lk)("div",_,[(0,r.bF)(b,{inset:""},{default:(0,r.k6)((()=>[g,(0,r.bF)(v,{style:{color:"black"}}),(0,r.bF)(m,{label:"版本号:","model-value":i.ledVision,readonly:""},null,8,["model-value"]),(0,r.bF)(m,{label:"编译时间:","model-value":i.ledTime,readonly:""},null,8,["model-value"])])),_:1})]),(0,r.Lk)("div",h,[(0,r.bF)(b,{inset:""},{default:(0,r.k6)((()=>[L,(0,r.bF)(v,{style:{color:"black"}}),(0,r.bF)(m,{label:"版本号:","model-value":i.carVision,readonly:""},null,8,["model-value"]),(0,r.bF)(m,{label:"编译时间:","model-value":i.carTime,readonly:""},null,8,["model-value"])])),_:1})]),(0,r.Lk)("div",y,[(0,r.bF)(b,{inset:""},{default:(0,r.k6)((()=>[T,(0,r.bF)(v,{style:{color:"black"}}),(0,r.bF)(m,{label:"版本号:","model-value":i.g4Vision,readonly:""},null,8,["model-value"]),(0,r.bF)(m,{label:"编译时间:","model-value":i.g4Time,readonly:""},null,8,["model-value"])])),_:1})])])])),_:1},8,["modelValue","onRefresh"]),(0,r.bF)(V)])}var K=a(144),P=a(5149),w=(a(8628),{components:{Header:p.A,Footer:o["default"]},setup(){const e=(0,K.KR)("系统信息"),l=(0,K.KR)(!1),a=(0,K.KR)(""),o=(0,K.KR)(""),t=(0,K.KR)(""),n=(0,K.KR)(""),s=(0,K.KR)(""),i=(0,K.KR)("");let c,d=(0,K.KR)(1);c=P.connect("wss://broker.emqx.io:8084/mqtt");const u=()=>{l.value=!0,v()},v=()=>{c.publish("recewive/abc",JSON.stringify({JSON_id:d.value,LPR_card:{get_info:1}})),d.value+=1},m=()=>{c.on("connect",(()=>{console.log("Connected to MQTT broker"),c.subscribe("/mytest/abc")})),c.on("message",((e,r)=>{const c=JSON.parse(r.toString());if(console.log("Received message:",c),c.LPR_card&&c.LPR_card.info){const e=c.LPR_card.info;a.value=e.versions,o.value=e.compile_time,t.value=e.versions,n.value=e.compile_time,s.value=e.versions,i.value=e.compile_time,l.value=!1}}))};return(0,r.sV)((()=>{m()})),(0,r.xo)((()=>{c&&c.end()})),{currentTitle:e,loading:l,onRefresh:u,ledVision:a,ledTime:o,carVision:t,carTime:n,g4Vision:s,g4Time:i}}}),C=a(1241);const S=(0,C.A)(w,[["render",V],["__scopeId","data-v-96208070"]]);var x=S}}]);

1
web/js/960.29de40e4.js Normal file

File diff suppressed because one or more lines are too long

1
web/js/app.f4ff13fe.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
web/login.html Normal file
View File

@ -0,0 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>set-vue</title><script defer="defer" src="js/chunk-vendors.5737b5d2.js"></script><script defer="defer" src="js/app.f4ff13fe.js"></script></head><body><noscript><strong>We're sorry but set-vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

13
web/web/cache.manifest Normal file
View File

@ -0,0 +1,13 @@
CACHE MANIFEST
#v0.01 //离线缓存文件的版本信息
CACHE: //需要进行离线缓存的资源
./css/common.css
./css/content.css
./css/style.css
NETWORK://表示只有在在线状态下才能访问的资源,即不需要缓存的资源
*
FALLBACK://资源加载失败的时候跳转的页面

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More