11.13
4
.browserslistrc
Normal file
@ -0,0 +1,4 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
not ie 11
|
17
.eslintrc.js
Normal 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
@ -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
@ -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
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
19
jsconfig.json
Normal 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
44
package.json
Normal 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
After Width: | Height: | Size: 4.2 KiB |
18
public/index.html
Normal 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
@ -0,0 +1,13 @@
|
||||
CACHE MANIFEST
|
||||
#v0.01 //离线缓存文件的版本信息
|
||||
|
||||
CACHE: //需要进行离线缓存的资源
|
||||
./css/common.css
|
||||
./css/content.css
|
||||
./css/style.css
|
||||
|
||||
NETWORK://表示只有在在线状态下才能访问的资源,即不需要缓存的资源
|
||||
*
|
||||
|
||||
FALLBACK://资源加载失败的时候跳转的页面
|
||||
|
1961
public/web/content_pattern1.html
Normal file
52
public/web/css/common.css
Normal 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
@ -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
180
public/web/css/voice_style.css
Normal 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
@ -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"><返回</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
After Width: | Height: | Size: 15 KiB |
BIN
public/web/img/bg.jpg
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
public/web/img/coin.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
public/web/img/compicon.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
public/web/img/content.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
public/web/img/del.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
public/web/img/delete.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
public/web/img/home.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
public/web/img/insert.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
public/web/img/ld.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
public/web/img/logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
public/web/img/refresh.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
public/web/img/remove.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
public/web/img/setting.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
public/web/img/traffic_sign.bmp
Normal file
After Width: | Height: | Size: 26 KiB |
112
public/web/js/MQTT_port copy.js
Normal 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
@ -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
@ -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
@ -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=1时,data1的值为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
5
public/web/js/jsonid.js
Normal 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
528
public/web/js/mp3.js
Normal file
@ -0,0 +1,528 @@
|
||||
/*
|
||||
mp3编码器,需带上src/engine/mp3-engine.js引擎使用
|
||||
https://github.com/xiangyuecn/Recorder
|
||||
|
||||
当然最佳推荐使用mp3、wav格式,代码也是优先照顾这两种格式
|
||||
浏览器支持情况
|
||||
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时没有声音,有问题fix:https://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 Worker,mp3实时编码器运行在主线程中"),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"));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//*******辅助函数************
|
||||
|
||||
/*读取lamejs编码出来的mp3信息,只能读特定格式,如果读取失败返回null
|
||||
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);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
}));
|
1783
public/web/js/recorder.core.js
Normal file
402
public/web/js/voice.html
Normal 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
137
public/web/login.html
Normal 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
@ -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>©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
@ -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"><返回</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>
|
460
public/web/screen_program.html
Normal 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 + "¬e=" + 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>
|
192
public/web/screen_virtual.html
Normal 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
After Width: | Height: | Size: 26 KiB |
404
public/web/voice_copy.html
Normal 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
@ -0,0 +1,4 @@
|
||||
<template>
|
||||
<router-view/>
|
||||
</template>
|
||||
|
1
src/assets/icon/iconfont.js
Normal file
BIN
src/assets/img/pictur.png
Normal file
After Width: | Height: | Size: 25 KiB |
1
src/assets/js/webView.js
Normal file
BIN
src/assets/logo.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
7
src/assets/style/iconfont.css
Normal file
@ -0,0 +1,7 @@
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
4
src/assets/style/reset.css
Normal file
@ -0,0 +1,4 @@
|
||||
body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
47
src/components/Footer.vue
Normal 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
@ -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>
|
||||
|
35
src/components/MQTT/mqttclient.js
Normal 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 };
|
12
src/components/environment/check.js
Normal 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
@ -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
@ -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
@ -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
@ -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>
|
451
src/views/forewarning/forewarning.vue
Normal 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
@ -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
@ -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
@ -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>
|
||||
|
879
src/views/recognize/License-plate-recognition.vue
Normal 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>
|
366
src/views/system-info/info.vue
Normal 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
48
vue.config.js
Normal 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
@ -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
@ -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
1
web/css/619.93201e95.css
Normal file
1
web/css/718.dc007c1e.css
Normal file
1
web/css/769.522c5d34.css
Normal 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
1
web/css/928.e3bab1c5.css
Normal file
1
web/css/960.56b57727.css
Normal file
BIN
web/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
1
web/js/149.2f4f7417.js
Normal file
1
web/js/193.256e1126.js
Normal file
1
web/js/233.a1cddea4.js
Normal file
1
web/js/239.1c6f4606.js
Normal 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
1
web/js/506.70402c53.js
Normal file
1
web/js/619.a1ca49f9.js
Normal file
1
web/js/718.62d77b72.js
Normal file
1
web/js/769.9bee6fb6.js
Normal 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
@ -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
@ -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
1
web/js/app.f4ff13fe.js
Normal file
31
web/js/chunk-vendors.5737b5d2.js
Normal file
1
web/login.html
Normal 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
@ -0,0 +1,13 @@
|
||||
CACHE MANIFEST
|
||||
#v0.01 //离线缓存文件的版本信息
|
||||
|
||||
CACHE: //需要进行离线缓存的资源
|
||||
./css/common.css
|
||||
./css/content.css
|
||||
./css/style.css
|
||||
|
||||
NETWORK://表示只有在在线状态下才能访问的资源,即不需要缓存的资源
|
||||
*
|
||||
|
||||
FALLBACK://资源加载失败的时候跳转的页面
|
||||
|