Compare commits
10 Commits
779a37ac2d
...
d1b269570b
Author | SHA1 | Date | |
---|---|---|---|
d1b269570b | |||
225dc12f77 | |||
de18827af6 | |||
e8da4a76a8 | |||
3c80f4a2f7 | |||
f43f1d57ed | |||
b752d013bb | |||
a96bd4e88d | |||
0b4a8265c2 | |||
35f325a468 |
82
package-lock.json
generated
82
package-lock.json
generated
@ -11,6 +11,11 @@
|
||||
"@capacitor/android": "^7.0.1",
|
||||
"@capacitor/cli": "^7.0.1",
|
||||
"@capacitor/core": "^7.0.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.8",
|
||||
"@vant/touch-emulator": "^1.4.0",
|
||||
"amfe-flexible": "^2.2.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
@ -18,6 +23,7 @@
|
||||
"core-js": "^3.8.3",
|
||||
"element-plus": "^2.9.4",
|
||||
"express": "^4.21.2",
|
||||
"font-awesome": "^4.7.0",
|
||||
"lamejs": "^1.2.1",
|
||||
"mqtt": "^2.18.8",
|
||||
"nipplejs": "^0.10.2",
|
||||
@ -1988,6 +1994,73 @@
|
||||
"resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.8.tgz",
|
||||
"integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig=="
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
|
||||
"integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
|
||||
"integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.7.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-brands-svg-icons": {
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz",
|
||||
"integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==",
|
||||
"license": "(CC-BY-4.0 AND MIT)",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.7.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.7.2.tgz",
|
||||
"integrity": "sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g==",
|
||||
"license": "(CC-BY-4.0 AND MIT)",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.7.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz",
|
||||
"integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==",
|
||||
"license": "(CC-BY-4.0 AND MIT)",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.7.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/vue-fontawesome": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.8.tgz",
|
||||
"integrity": "sha512-yyHHAj4G8pQIDfaIsMvQpwKMboIZtcHTUvPqXjOHyldh1O1vZfH4W03VDPv5RvI9P6DLTzJQlmVgj9wCf7c2Fw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
|
||||
"vue": ">= 3.0.0 < 4"
|
||||
}
|
||||
},
|
||||
"node_modules/@hapi/hoek": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz",
|
||||
@ -7420,6 +7493,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/font-awesome": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmmirror.com/font-awesome/-/font-awesome-4.7.0.tgz",
|
||||
"integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==",
|
||||
"license": "(OFL-1.1 AND MIT)",
|
||||
"engines": {
|
||||
"node": ">=0.10.3"
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.0.tgz",
|
||||
|
@ -11,6 +11,11 @@
|
||||
"@capacitor/android": "^7.0.1",
|
||||
"@capacitor/cli": "^7.0.1",
|
||||
"@capacitor/core": "^7.0.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.8",
|
||||
"@vant/touch-emulator": "^1.4.0",
|
||||
"amfe-flexible": "^2.2.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
@ -18,6 +23,7 @@
|
||||
"core-js": "^3.8.3",
|
||||
"element-plus": "^2.9.4",
|
||||
"express": "^4.21.2",
|
||||
"font-awesome": "^4.7.0",
|
||||
"lamejs": "^1.2.1",
|
||||
"mqtt": "^2.18.8",
|
||||
"nipplejs": "^0.10.2",
|
||||
|
@ -1500,13 +1500,14 @@
|
||||
screen_start = new Object()
|
||||
screen_start.get_screen = 1;
|
||||
var str = JSON.stringify(screen_start);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -1527,13 +1528,14 @@
|
||||
screen_start = new Object()
|
||||
screen_start.get_sensor = 1;
|
||||
var str = JSON.stringify(screen_start);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -1554,13 +1556,14 @@
|
||||
screen_start = new Object()
|
||||
screen_start.get_program = parseInt(pro_num);
|
||||
var str = JSON.stringify(screen_start);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -1589,11 +1592,12 @@
|
||||
manage.pro_manage.type = type;
|
||||
manage.pro_manage.data = data;
|
||||
let string = JSON.stringify(manage);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
if (MQTT_MODE == 0) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('post', baseHost + '/communication', true);
|
||||
xhr.setRequestHeader('content-type', 'application/json');
|
||||
xhr.send(string);
|
||||
xhr.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -1705,13 +1709,14 @@
|
||||
}
|
||||
}
|
||||
let string = JSON.stringify(json_cfg);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
|
||||
console.log(string);
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
* @LastEditors: Andy
|
||||
* @LastEditTime: 2024-03-11 11:07:00
|
||||
*/
|
||||
var MQTT_MODE = 1;
|
||||
var MQTT_MODE = 0;
|
||||
|
||||
function pageName() {
|
||||
var a = location.href;
|
||||
|
@ -212,6 +212,8 @@
|
||||
screen_start.get_cmd = new Object()
|
||||
screen_start.get_cmd.type = _type
|
||||
var str = JSON.stringify(screen_start);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
|
||||
// 设置超时逻辑
|
||||
var timeoutId = setTimeout(function () {
|
||||
result_prompt_display(2, "数据获取失败");
|
||||
@ -222,7 +224,7 @@
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', baseHost + '/communication', true);
|
||||
xhr.setRequestHeader('content-type', 'application/json');
|
||||
xhr.send(str);
|
||||
xhr.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -292,13 +294,14 @@
|
||||
screen_start.cmd.data2 = parseInt($('#power_on2').find('option:selected').val());
|
||||
screen_start.cmd.data3 = 0;
|
||||
var str = JSON.stringify(screen_start);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -332,13 +335,14 @@
|
||||
screen_start.cmd.data2 = 0;
|
||||
screen_start.cmd.data3 = 0;
|
||||
var str = JSON.stringify(screen_start);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -395,13 +399,14 @@
|
||||
screen_start.cmd.data2 = 0;
|
||||
screen_start.cmd.data3 = 0;
|
||||
var str = JSON.stringify(screen_start);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -429,13 +434,14 @@
|
||||
screen_close.cmd.data2 = 0;
|
||||
screen_close.cmd.data3 = 0;
|
||||
var str = JSON.stringify(screen_close);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -467,13 +473,14 @@
|
||||
screen_clear.cmd.data2 = 0;
|
||||
screen_clear.cmd.data3 = 0;
|
||||
var str = JSON.stringify(screen_clear);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
|
@ -150,13 +150,14 @@
|
||||
screen_start = new Object()
|
||||
screen_start.get_screen = 1;
|
||||
var str = JSON.stringify(screen_start);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -224,11 +225,12 @@
|
||||
manage.pro_manage.type = 2;
|
||||
manage.pro_manage.data = -1;
|
||||
var str = JSON.stringify(manage);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
if (MQTT_MODE == 0) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('post', baseHost + '/communication', true);
|
||||
xhr.setRequestHeader('content-type', 'application/json');
|
||||
xhr.send(str);
|
||||
xhr.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@ -271,13 +273,14 @@
|
||||
screen.screen_p.data = parseInt($('#data_polarity').val())
|
||||
screen.screen_p.screen_angle = screen_angle;
|
||||
let str = JSON.stringify(screen);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
|
||||
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.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
|
@ -257,11 +257,12 @@
|
||||
manage.pro_manage.remarks = new Array();
|
||||
manage.pro_manage.remarks[0] = cont;
|
||||
let string = JSON.stringify(manage);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
|
||||
if (MQTT_MODE == 0) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('post', baseHost + '/communication', true);
|
||||
xhr.setRequestHeader('content-type', 'application/json');
|
||||
xhr.send(string);
|
||||
xhr.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4 || xhr.status == 200) {
|
||||
program_list_reply_parse(xhr.responseText);
|
||||
@ -295,11 +296,12 @@
|
||||
manage = new Object();
|
||||
manage.get_pro_manage = 1;
|
||||
let string = JSON.stringify(manage);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
|
||||
if (MQTT_MODE == 0) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('post', baseHost + '/communication', true);
|
||||
xhr.setRequestHeader('content-type', 'application/json');
|
||||
xhr.send(string);
|
||||
xhr.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4 && xhr.status == 200) {
|
||||
program_list_reply_parse(xhr.responseText);
|
||||
@ -329,11 +331,12 @@
|
||||
manage.pro_manage.data = data;
|
||||
result_prompt_display(1, "删除中...");
|
||||
let string = JSON.stringify(manage);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
|
||||
if (MQTT_MODE == 0) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open('post', baseHost + '/communication', true)
|
||||
xhr.setRequestHeader('content-type', 'application/json')
|
||||
xhr.send(string);
|
||||
xhr.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if ((xhr.readyState == 4) && (xhr.status == 200)) {
|
||||
program_list_reply_parse(xhr.responseText);
|
||||
@ -375,12 +378,13 @@
|
||||
manage.pro_manage.type = type;
|
||||
manage.pro_manage.data = data;
|
||||
let string = JSON.stringify(manage);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
|
||||
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.send(send_string)
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
|
@ -96,11 +96,12 @@
|
||||
manage = new Object();
|
||||
manage.get_pro_manage = 1;
|
||||
let string = JSON.stringify(manage);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
|
||||
if (MQTT_MODE == 0) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('post', baseHost + '/communication', true);
|
||||
xhr.setRequestHeader('content-type', 'application/json');
|
||||
xhr.send(string);
|
||||
xhr.send(send_string);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4 && xhr.status == 200) {
|
||||
screen_virtual_reply_parse(xhr.responseText);
|
||||
@ -126,12 +127,13 @@
|
||||
manage.pro_manage.type = 6;
|
||||
manage.pro_manage.data = parseInt(data);
|
||||
let string = JSON.stringify(manage);
|
||||
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
|
||||
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.send(send_string)
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
|
212
src/api/ledScreen.js
Normal file
212
src/api/ledScreen.js
Normal file
@ -0,0 +1,212 @@
|
||||
import axios from 'axios';
|
||||
|
||||
// 基础配置
|
||||
const baseURL = '/api'; // 根据实际情况配置API基础路径
|
||||
const boardId = 1; // 默认设备ID
|
||||
|
||||
// 创建axios实例
|
||||
const api = axios.create({
|
||||
baseURL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
// 响应拦截器处理响应
|
||||
api.interceptors.response.use(
|
||||
response => {
|
||||
// 检查错误码
|
||||
if (response.data && response.data.error_code !== undefined) {
|
||||
if (response.data.error_code !== 0) {
|
||||
console.error('API错误:', response.data.error_code);
|
||||
return Promise.reject(response.data);
|
||||
}
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
error => {
|
||||
console.error('网络错误:', error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* LED双色屏控制API
|
||||
*/
|
||||
export const ledScreenApi = {
|
||||
/**
|
||||
* 平台上升控制
|
||||
* @returns {Promise}
|
||||
*/
|
||||
platformUp() {
|
||||
return api.post('/device/control', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
platform: {
|
||||
action: "up"
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 平台下降控制
|
||||
* @returns {Promise}
|
||||
*/
|
||||
platformDown() {
|
||||
return api.post('/device/control', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
platform: {
|
||||
action: "down"
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 屏幕开关控制
|
||||
* @param {Boolean} status - true为开,false为关
|
||||
* @returns {Promise}
|
||||
*/
|
||||
screenToggle(status) {
|
||||
return api.post('/device/control', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
screen: {
|
||||
power: status ? "on" : "off"
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 灯光模式切换
|
||||
* @param {Number} mode - 灯光模式编号
|
||||
* @returns {Promise}
|
||||
*/
|
||||
lightMode(mode) {
|
||||
return api.post('/device/control', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
light: {
|
||||
mode: mode
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 单个灯控制
|
||||
* @param {Number} lightId - 灯ID (1-6)
|
||||
* @param {Boolean} status - true为开,false为关
|
||||
* @returns {Promise}
|
||||
*/
|
||||
controlSingleLight(lightId, status) {
|
||||
return api.post('/device/control', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
light: {
|
||||
id: lightId,
|
||||
status: status ? "on" : "off"
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 调节亮度
|
||||
* @param {Number} brightness - 亮度值(0-100)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setBrightness(brightness) {
|
||||
return api.post('/device/control', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
screen: {
|
||||
brightness: brightness
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 切换节目
|
||||
* @param {Number} programId - 节目ID
|
||||
* @returns {Promise}
|
||||
*/
|
||||
switchProgram(programId) {
|
||||
return api.post('/device/control', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
program: {
|
||||
id: programId
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 设备登录验证
|
||||
* @param {String} password - 登录密码
|
||||
* @returns {Promise}
|
||||
*/
|
||||
login(password) {
|
||||
return api.post('/device/auth', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
log_in: {
|
||||
type: 2,
|
||||
pass: password
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改设备密码
|
||||
* @param {String} oldPassword - 旧密码
|
||||
* @param {String} newPassword - 新密码
|
||||
* @returns {Promise}
|
||||
*/
|
||||
changePassword(oldPassword, newPassword) {
|
||||
return api.post('/device/auth', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
log_in: {
|
||||
type: 2,
|
||||
pass: oldPassword,
|
||||
new_pass: newPassword
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取设备状态
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getDeviceStatus() {
|
||||
return api.post('/device/status', {
|
||||
board_id: boardId,
|
||||
JSON_id: Date.now(),
|
||||
gateway: {
|
||||
status: {
|
||||
query: "all"
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default ledScreenApi;
|
281
src/api/ledScreenJsonFormat.js
Normal file
281
src/api/ledScreenJsonFormat.js
Normal file
@ -0,0 +1,281 @@
|
||||
/**
|
||||
* LED双色屏JSON通信格式定义
|
||||
* WEB/串口 => 设备,为请求格式
|
||||
* 设备 => WEB/串口,为响应格式
|
||||
*/
|
||||
|
||||
// ======================== 平台上升 ========================
|
||||
const platformUpRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"platform": {
|
||||
"action": "up"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const platformUpResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"platform": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 平台下降 ========================
|
||||
const platformDownRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"platform": {
|
||||
"action": "down"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const platformDownResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"platform": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 屏幕开关 ========================
|
||||
const screenOnRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"screen": {
|
||||
"power": "on"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const screenOnResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"screen": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
const screenOffRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"screen": {
|
||||
"power": "off"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const screenOffResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"screen": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 灯光模式 ========================
|
||||
const lightModeRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"light": {
|
||||
"mode": 1 // 模式编号,1-n
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const lightModeResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"light": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 单个灯控制 ========================
|
||||
// 这里以灯1开启为例,其他灯位可以修改id值(1-6)
|
||||
const light1OnRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"light": {
|
||||
"id": 1,
|
||||
"status": "on"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const light1OnResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"light": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
const light1OffRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"light": {
|
||||
"id": 1,
|
||||
"status": "off"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const light1OffResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"light": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 亮度调节 ========================
|
||||
const setBrightnessRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"screen": {
|
||||
"brightness": 80 // 亮度值,0-100
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const setBrightnessResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"screen": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 节目切换 ========================
|
||||
const switchProgramRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"program": {
|
||||
"id": 2 // 节目编号
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const switchProgramResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"program": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 设备登录 ========================
|
||||
const loginRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"log_in": {
|
||||
"type": 2,
|
||||
"pass": "#输入密码#"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const loginResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"log_in": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 修改设备密码 ========================
|
||||
const changePasswordRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"log_in": {
|
||||
"type": 2,
|
||||
"pass": "#输入密码#",
|
||||
"new_pass": "#新密码#"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const changePasswordResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"log_in": {
|
||||
"return": 0
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
||||
// ======================== 获取设备状态 ========================
|
||||
const getStatusRequest = {
|
||||
"board_id": 1,
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"status": {
|
||||
"query": "all"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusResponse = {
|
||||
"JSON_id": 1,
|
||||
"gateway": {
|
||||
"status": {
|
||||
"platform": "up", // up/down
|
||||
"screen": {
|
||||
"power": "on", // on/off
|
||||
"brightness": 80
|
||||
},
|
||||
"light": {
|
||||
"mode": 1,
|
||||
"lights": [
|
||||
{"id": 1, "status": "on"},
|
||||
{"id": 2, "status": "off"},
|
||||
{"id": 3, "status": "on"},
|
||||
{"id": 4, "status": "off"},
|
||||
{"id": 5, "status": "on"},
|
||||
{"id": 6, "status": "off"}
|
||||
]
|
||||
},
|
||||
"program": {
|
||||
"current": 2,
|
||||
"total": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
};
|
||||
|
@ -4,12 +4,7 @@ class GamepadController {
|
||||
...{
|
||||
debug: false,
|
||||
deadZone: 0.1,
|
||||
updateInterval: 50,
|
||||
buttonsConfig: [
|
||||
{ name: "Left2", index: 6 },
|
||||
{ name: "Back", index: 8 },
|
||||
{ name: "Right Joystick Press", index: 11 }
|
||||
]
|
||||
updateInterval: 50
|
||||
},
|
||||
...options
|
||||
};
|
||||
@ -17,135 +12,140 @@ class GamepadController {
|
||||
this.gamepadIndex = null;
|
||||
this.gamepad = null;
|
||||
this.interval = null;
|
||||
this.buttons = [];
|
||||
this.directionAxis0_1 = "";
|
||||
this.directionAxis9 = "";
|
||||
this.angle = 0;
|
||||
this.speed = 0;
|
||||
this.directionAxis9 = 0;
|
||||
this.rightJoystickPressed = false;
|
||||
this.speed = 0; // 添加速度属性
|
||||
// 初始化按钮状态
|
||||
this.buttons = this.options.buttonsConfig.map(button => ({
|
||||
...button,
|
||||
pressed: false
|
||||
}));
|
||||
this.isActive = false;
|
||||
|
||||
// 注册事件监听器
|
||||
window.addEventListener("gamepadconnected", this.onGamepadConnected.bind(this));
|
||||
window.addEventListener("gamepaddisconnected", this.onGamepadDisconnected.bind(this));
|
||||
|
||||
if (this.options.debug) {
|
||||
console.log("GamepadController initialized with options:", this.options);
|
||||
}
|
||||
// 立即开始更新循环,不等待连接事件
|
||||
this.startUpdateLoop();
|
||||
}
|
||||
|
||||
onGamepadConnected(e) {
|
||||
console.log("Gamepad connected:", e.gamepad);
|
||||
this.gamepadIndex = e.gamepad.index;
|
||||
this.gamepad = navigator.getGamepads()[this.gamepadIndex];
|
||||
this.startGamepad();
|
||||
}
|
||||
|
||||
onGamepadDisconnected() {
|
||||
clearInterval(this.interval);
|
||||
this.gamepad = null;
|
||||
if (this.options.debug) {
|
||||
console.log("Gamepad disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
startGamepad() {
|
||||
this.interval = setInterval(() => {
|
||||
update() {
|
||||
// 获取所有手柄
|
||||
const gamepads = navigator.getGamepads();
|
||||
const gamepad = gamepads[this.gamepadIndex];
|
||||
|
||||
if (gamepad) {
|
||||
// 注释掉调试打印
|
||||
// if (this.options.debug) {
|
||||
// console.log('Axes data:', {
|
||||
// axis0: gamepad.axes[0],
|
||||
// axis1: gamepad.axes[1],
|
||||
// gamepadIndex: this.gamepadIndex
|
||||
// });
|
||||
// }
|
||||
|
||||
this.updateDirection(gamepad.axes);
|
||||
this.updateDirectionAxis9(gamepad.axes);
|
||||
this.pressKey(gamepad.buttons);
|
||||
}
|
||||
}, this.options.updateInterval);
|
||||
}
|
||||
|
||||
updateDirection(axes) {
|
||||
const axis0 = axes[0];
|
||||
const axis1 = axes[1];
|
||||
|
||||
// 检查是否在死区
|
||||
if (Math.abs(axis0) < this.options.deadZone && Math.abs(axis1) < this.options.deadZone) {
|
||||
this.directionAxis0_1 = "未定义";
|
||||
this.angle = 0;
|
||||
this.speed = 0; // 在死区时速度为0
|
||||
if (!gamepads) {
|
||||
this.isActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算速度(到原点的距离)
|
||||
// 使用勾股定理计算距离,并将结果限制在0-100之间
|
||||
const distance = Math.sqrt(axis0 * axis0 + axis1 * axis1);
|
||||
this.speed = Math.round(Math.min(distance * 100, 100));
|
||||
|
||||
// 计算方向角度(0-360度)
|
||||
let angle = Math.atan2(axis1, axis0) * (180 / Math.PI);
|
||||
angle = (angle + 360) % 360;
|
||||
angle = Math.round(angle);
|
||||
this.angle = angle;
|
||||
|
||||
// 更新方向数据
|
||||
if (Math.abs(axis0) > this.options.deadZone || Math.abs(axis1) > this.options.deadZone) {
|
||||
this.directionAxis0_1 = `${angle}°`;
|
||||
// 注释掉调试打印
|
||||
// if (this.options.debug) {
|
||||
// console.log(` 摇杆方向: ${angle}°, X轴: ${axis0.toFixed(2)}, Y轴: ${axis1.toFixed(2)}`);
|
||||
// }
|
||||
// 找到第一个连接的手柄
|
||||
const gamepad = Array.from(gamepads).find(pad => pad && pad.connected);
|
||||
if (!gamepad) {
|
||||
this.isActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.isActive = true;
|
||||
|
||||
// 获取左摇杆的值
|
||||
const x = gamepad.axes[0];
|
||||
const y = gamepad.axes[1];
|
||||
|
||||
// 应用死区
|
||||
const absX = Math.abs(x);
|
||||
const absY = Math.abs(y);
|
||||
|
||||
if (absX < this.options.deadZone && absY < this.options.deadZone) {
|
||||
this.angle = 0;
|
||||
this.speed = 0;
|
||||
} else {
|
||||
this.updateDirection(gamepad.axes);
|
||||
}
|
||||
|
||||
// 更新 platform 值
|
||||
this.updateDirectionAxis9(gamepad.axes);
|
||||
|
||||
// 更新右摇杆按钮状态 - 尝试多个可能的按钮索引
|
||||
this.rightJoystickPressed =
|
||||
(gamepad.buttons[10] && gamepad.buttons[10].pressed) ||
|
||||
(gamepad.buttons[9] && gamepad.buttons[9].pressed) ||
|
||||
(gamepad.buttons[11] && gamepad.buttons[11].pressed);
|
||||
|
||||
if (this.options.debug) {
|
||||
console.log('GamepadController 状态:', {
|
||||
id: gamepad.id,
|
||||
index: gamepad.index,
|
||||
x: x.toFixed(2),
|
||||
y: y.toFixed(2),
|
||||
angle: this.angle,
|
||||
speed: this.speed.toFixed(2),
|
||||
directionAxis9: this.directionAxis9,
|
||||
rightJoystickPressed: this.rightJoystickPressed,
|
||||
buttons: Array.from(gamepad.buttons).map((btn, idx) => btn.pressed ? idx : null).filter(idx => idx !== null)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateDirection(axes) {
|
||||
const axis0 = axes[0]; // X轴
|
||||
const axis1 = axes[1]; // Y轴
|
||||
|
||||
// 检查是否在死区
|
||||
if (Math.abs(axis0) < this.options.deadZone && Math.abs(axis1) < this.options.deadZone) {
|
||||
this.angle = 0;
|
||||
this.speed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算角度(0-360度),从x轴正半轴开始顺时针旋转
|
||||
let angle = Math.atan2(axis1, axis0) * (180 / Math.PI);
|
||||
// 将角度转换到 0-360 范围
|
||||
if (angle < 0) {
|
||||
angle += 360;
|
||||
}
|
||||
this.angle = Math.round(angle);
|
||||
|
||||
// 计算速度(0-100)
|
||||
const distance = Math.sqrt(axis0 * axis0 + axis1 * axis1);
|
||||
this.speed = Math.min(Math.round(distance * 100), 100);
|
||||
}
|
||||
|
||||
updateDirectionAxis9(axes) {
|
||||
// 添加调试输出,查看所有轴的值
|
||||
if (this.options.debug) {
|
||||
// console.log('所有轴的值:', axes.map((value, index) => `轴${index}: ${value}`));
|
||||
}
|
||||
|
||||
// 检查第9轴是否存在
|
||||
if (axes[9] === undefined) {
|
||||
// 可能是第3轴或第4轴
|
||||
const axis3 = axes[3];
|
||||
const axis4 = axes[4];
|
||||
|
||||
if (axis3 !== undefined && Math.abs(axis3) > this.options.deadZone) {
|
||||
this.directionAxis9 = axis3 > 0 ? 2 : 1;
|
||||
} else if (axis4 !== undefined && Math.abs(axis4) > this.options.deadZone) {
|
||||
this.directionAxis9 = axis4 > 0 ? 2 : 1;
|
||||
} else {
|
||||
this.directionAxis9 = 0;
|
||||
}
|
||||
} else {
|
||||
const axis9 = axes[9];
|
||||
const roundedAxis9 = Math.round(axis9 * 100) / 100;
|
||||
if (roundedAxis9 <= -0.9) {
|
||||
this.directionAxis9 = 0;
|
||||
this.directionAxis9 = 1; // 向上
|
||||
} else if (roundedAxis9 >= 0.0 && roundedAxis9 <= 0.2) {
|
||||
this.directionAxis9 = 1;
|
||||
// } else if (roundedAxis9 >= 0.6 && roundedAxis9 <= 0.8) {
|
||||
// this.directionAxis9 = "左";
|
||||
// } else if (roundedAxis9 >= -0.5 && roundedAxis9 <= -0.4) {
|
||||
// this.directionAxis9 = "右";
|
||||
}
|
||||
else {
|
||||
this.directionAxis9 = 0;
|
||||
this.directionAxis9 = 2; // 向下
|
||||
} else {
|
||||
this.directionAxis9 = 0; // 中间位置
|
||||
}
|
||||
}
|
||||
|
||||
pressKey(buttons) {
|
||||
this.buttons.forEach(button => {
|
||||
const buttonData = buttons[button.index];
|
||||
button.pressed = buttonData ? buttonData.value === 1 : false;
|
||||
|
||||
// 特别检查 Right Joystick Press 按钮
|
||||
if (button.name === "Right Joystick Press") {
|
||||
this.rightJoystickPressed = button.pressed;
|
||||
if (this.options.debug) {
|
||||
// console.log('当前 directionAxis9 值:', this.directionAxis9);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
startUpdateLoop() {
|
||||
this.updateLoop = setInterval(() => this.update(), this.options.updateInterval);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
clearInterval(this.interval);
|
||||
window.removeEventListener("gamepadconnected", this.onGamepadConnected);
|
||||
window.removeEventListener("gamepaddisconnected", this.onGamepadDisconnected);
|
||||
if (this.options.debug) {
|
||||
console.log("GamepadController destroyed");
|
||||
if (this.updateLoop) {
|
||||
clearInterval(this.updateLoop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}export default GamepadController;
|
||||
|
||||
// 导出类以便外部使用
|
||||
export default GamepadController;
|
@ -21,19 +21,16 @@ export default {
|
||||
audioWs: null, // 音频 WebSocket 连接
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 初始化 WebSocket 连接
|
||||
this.ws = new WebSocket('ws://192.168.4.103/ws'); // 替换为 ESP32 IP 地址
|
||||
beforeDestroy() {
|
||||
// 组件销毁前清理资源
|
||||
this.cleanup();
|
||||
|
||||
this.ws.onopen = () => {
|
||||
console.log('WebSocket 连接已打开');
|
||||
};
|
||||
this.ws.onmessage = (event) => {
|
||||
console.log(' 接收到来自 ESP32 的消息:', event.data);
|
||||
};
|
||||
this.ws.onclose = () => {
|
||||
console.log('WebSocket 连接已关闭');
|
||||
};
|
||||
// 关闭主 WebSocket 连接
|
||||
if (this.ws) {
|
||||
console.log('关闭主 WebSocket 连接');
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleRecording() {
|
||||
@ -45,6 +42,8 @@ export default {
|
||||
},
|
||||
|
||||
async startRecording() {
|
||||
if (this.isRecording) return;
|
||||
|
||||
console.log('音频传输器: 开始录音');
|
||||
this.status = '开始录音并传输音频...';
|
||||
this.isRecording = true;
|
||||
@ -60,37 +59,19 @@ export default {
|
||||
console.log('使用的音频配置:', constraints);
|
||||
|
||||
try {
|
||||
// 初始化音频 WebSocket 连接
|
||||
this.audioWs = new WebSocket('ws://192.168.1.60:81');
|
||||
|
||||
// 等待 WebSocket 连接成功
|
||||
await new Promise((resolve, reject) => {
|
||||
this.audioWs.onopen = () => {
|
||||
console.log('音频 WebSocket 已连接');
|
||||
resolve();
|
||||
};
|
||||
this.audioWs.onerror = (error) => {
|
||||
console.error('音频 WebSocket 错误:', error);
|
||||
reject(error);
|
||||
};
|
||||
});
|
||||
|
||||
// WebSocket 连接成功后,开始获取麦克风权限
|
||||
// 直接获取麦克风权限,不再重新建立 WebSocket 连接
|
||||
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
console.log('成功获取麦克风权限');
|
||||
|
||||
// 创建 AudioContext
|
||||
const audioContext = new AudioContext({
|
||||
sampleRate: this.audioConfig.sampleRate
|
||||
});
|
||||
|
||||
// 加载 AudioWorklet
|
||||
await audioContext.audioWorklet.addModule('audio-processor.js');
|
||||
|
||||
const source = audioContext.createMediaStreamSource(stream);
|
||||
const worklet = new AudioWorkletNode(audioContext, 'audio-processor');
|
||||
|
||||
// 监听来自 worklet 的消息
|
||||
worklet.port.onmessage = (event) => {
|
||||
if (this.audioWs && this.audioWs.readyState === WebSocket.OPEN) {
|
||||
const currentTime = Date.now();
|
||||
@ -106,58 +87,118 @@ export default {
|
||||
source.connect(worklet);
|
||||
worklet.connect(audioContext.destination);
|
||||
|
||||
// 保存引用以便后续停止
|
||||
this.stream = stream;
|
||||
this.audioContext = audioContext;
|
||||
this.worklet = worklet;
|
||||
} catch (error) {
|
||||
console.error('音频初始化失败:', error);
|
||||
// 清理音频相关资源
|
||||
if (this.stream) {
|
||||
this.stream.getTracks().forEach(track => track.stop());
|
||||
}
|
||||
if (this.worklet) {
|
||||
this.worklet.disconnect();
|
||||
}
|
||||
if (this.audioContext) {
|
||||
this.audioContext.close();
|
||||
}
|
||||
if (this.audioWs) {
|
||||
this.audioWs.close();
|
||||
this.audioWs = null;
|
||||
}
|
||||
this.isRecording = false;
|
||||
|
||||
// 不抛出错误,让程序继续执行
|
||||
this.cleanup();
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
// stopRecording() {
|
||||
// console.log('音频传输器: 停止录音');
|
||||
// this.status = '停止录音';
|
||||
// this.isRecording = false;
|
||||
|
||||
// // 关闭音频资源
|
||||
// if (this.stream) {
|
||||
// console.log('关闭音频流');
|
||||
// this.stream.getTracks().forEach(track => track.stop());
|
||||
// }
|
||||
// if (this.worklet) {
|
||||
// console.log('断开 AudioWorklet');
|
||||
// this.worklet.disconnect();
|
||||
// }
|
||||
// if (this.audioContext) {
|
||||
// console.log('关闭音频上下文');
|
||||
// this.audioContext.close();
|
||||
// }
|
||||
|
||||
// // 关闭音频 WebSocket 连接
|
||||
// if (this.audioWs) {
|
||||
// console.log('关闭音频 WebSocket 连接');
|
||||
// this.audioWs.close();
|
||||
// this.audioWs = null;
|
||||
// }
|
||||
// }
|
||||
// 修改停止录音方法
|
||||
stopRecording() {
|
||||
console.log('音频传输器: 停止录音');
|
||||
this.status = '停止录音';
|
||||
this.isRecording = false;
|
||||
|
||||
// 关闭音频资源
|
||||
// 异步关闭防止状态冲突
|
||||
const cleanup = async () => {
|
||||
// 优先关闭音频流
|
||||
if (this.stream) {
|
||||
console.log('关闭音频流');
|
||||
this.stream.getTracks().forEach(track => track.stop());
|
||||
this.stream = null;
|
||||
}
|
||||
|
||||
// 断开音频处理节点
|
||||
if (this.worklet) {
|
||||
console.log('断开 AudioWorklet');
|
||||
this.worklet.disconnect();
|
||||
this.worklet = null;
|
||||
}
|
||||
if (this.audioContext) {
|
||||
|
||||
// 安全关闭音频上下文
|
||||
if (this.audioContext && this.audioContext.state !== 'closed') {
|
||||
console.log('关闭音频上下文');
|
||||
this.audioContext.close();
|
||||
await this.audioContext.close();
|
||||
this.audioContext = null;
|
||||
}
|
||||
|
||||
// 移除关闭 WebSocket 的代码
|
||||
// if (this.audioWs) {
|
||||
// console.log('关闭音频 WebSocket 连接');
|
||||
// this.audioWs.close();
|
||||
// this.audioWs = null;
|
||||
// }
|
||||
};
|
||||
|
||||
cleanup().catch(error => {
|
||||
console.error('清理过程中发生错误:', error);
|
||||
});
|
||||
},
|
||||
async cleanup() {
|
||||
console.log('开始清理音频资源...');
|
||||
|
||||
// 停止录音
|
||||
if (this.isRecording) {
|
||||
this.isRecording = false;
|
||||
}
|
||||
|
||||
// 优先关闭音频流
|
||||
if (this.stream) {
|
||||
console.log('关闭音频流');
|
||||
this.stream.getTracks().forEach(track => track.stop());
|
||||
this.stream = null;
|
||||
}
|
||||
|
||||
// 断开音频处理节点
|
||||
if (this.worklet) {
|
||||
console.log('断开 AudioWorklet');
|
||||
this.worklet.disconnect();
|
||||
this.worklet = null;
|
||||
}
|
||||
|
||||
// 安全关闭音频上下文
|
||||
if (this.audioContext && this.audioContext.state !== 'closed') {
|
||||
console.log('关闭音频上下文');
|
||||
await this.audioContext.close();
|
||||
this.audioContext = null;
|
||||
}
|
||||
|
||||
// 关闭音频 WebSocket 连接
|
||||
if (this.audioWs) {
|
||||
console.log('关闭音频 WebSocket 连接');
|
||||
this.audioWs.close();
|
||||
this.audioWs = null;
|
||||
// if (this.audioWs) {
|
||||
// console.log('关闭音频 WebSocket 连接');
|
||||
// this.audioWs.close();
|
||||
// this.audioWs = null;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
1
src/assets/js/iconfont.js
Normal file
1
src/assets/js/iconfont.js
Normal file
File diff suppressed because one or more lines are too long
@ -18,7 +18,7 @@
|
||||
|
||||
<style scoped>
|
||||
.custom-nav-bar {
|
||||
height: 90px; /* 你可以根据需要调整高度 */
|
||||
height: 60px; /* 减小高度从90px到60px */
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -26,16 +26,16 @@
|
||||
z-index: 999; /* 使 Header 在最上层 */
|
||||
}
|
||||
|
||||
/deep/ .van-nav-bar {
|
||||
:deep(.van-nav-bar) {
|
||||
height: 100%; /* 确保van-nav-bar占满父元素的高度 */
|
||||
background-color: #0668fc; /* 示例背景色,可以根据需要调整 */
|
||||
}
|
||||
/deep/ .van-nav-bar__title {
|
||||
font-size: 22px; /* 设置标题字体大小 */
|
||||
:deep(.van-nav-bar__title) {
|
||||
font-size: 20px; /* 减小标题字体大小 */
|
||||
font-weight: bold; /* 设置标题字体加粗 */
|
||||
color: #fff; /* 设置标题字体颜色 */
|
||||
line-height: 100%;
|
||||
margin-top: 40px;
|
||||
margin-top: 20px; /* 减小上边距从40px到20px */
|
||||
}
|
||||
</style>
|
||||
|
@ -62,6 +62,21 @@ const routes = [
|
||||
name: 'TEST',
|
||||
component: () => import('../views/TEST.vue'),
|
||||
},
|
||||
{
|
||||
path: '/gateway-setting',
|
||||
name: 'GatewaySetting',
|
||||
component: () => import('../views/gateway/GatewaySetting.vue')
|
||||
},
|
||||
{
|
||||
path: '/cone-control',
|
||||
name: 'ConeControl',
|
||||
component: () => import('../views/ConeControl.vue')
|
||||
},
|
||||
{
|
||||
path: '/flipScreen',
|
||||
name: 'flipScreen',
|
||||
component: () => import('../views/flipScreen/flipScreen.vue')
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
|
@ -2,17 +2,23 @@
|
||||
<div class="control-panel">
|
||||
<!-- 顶部状态栏 -->
|
||||
<div class="status-bar">
|
||||
<div class="back-button" @click="handleBack">
|
||||
←
|
||||
</div>
|
||||
<div class="placeholder-div"></div>
|
||||
<div class="title-container">
|
||||
<div class="title-box">
|
||||
遥控车当前状态
|
||||
<!-- 根据方向状态显示不同文本 -->
|
||||
{{ getDirectionText }}
|
||||
<img src="../assets/img/shout.png" alt="voice" class="voice-icon-img"
|
||||
:class="{ 'show-voice': isControlPressed }" style="width: 20px; height: 20px; margin-left: 20px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-right-icons">
|
||||
<img :src="connectionImage" alt="link" class="top-icon">
|
||||
<img :src="batteryImage" alt="battery" class="top-icon">
|
||||
<img src="../assets/img/bat_full.png" class="top-icon" alt="">
|
||||
<!-- 注释掉电池图标 -->
|
||||
<!-- <img :src="batteryImage" alt="battery" class="top-icon"> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -22,25 +28,25 @@
|
||||
<div class="left-controls">
|
||||
<div class="switch-item">
|
||||
<span>屏幕</span>
|
||||
<el-switch v-model="screenStatus" />
|
||||
<el-switch v-model="screenStatus" @change="handleScreenChange" />
|
||||
</div>
|
||||
<div class="switch-item">
|
||||
<span>警灯</span>
|
||||
<el-switch v-model="warningLightStatus" />
|
||||
<el-switch v-model="warningLightStatus" @change="handleWarningLightChange" />
|
||||
</div>
|
||||
<div class="switch-item">
|
||||
<span>跟随</span>
|
||||
<el-switch v-model="followStatus" />
|
||||
<el-switch v-model="followStatus" @change="handleFollowChange" />
|
||||
</div>
|
||||
<div class="switch-item">
|
||||
<span>避障</span>
|
||||
<el-switch v-model="obstacleAvoidEnabled" />
|
||||
<el-switch v-model="obstacleAvoidEnabled" @change="handleObstacleAvoidChange" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间车辆状态显示区域 -->
|
||||
<div class="center-display">
|
||||
<div class="status-text">云台状态</div>
|
||||
<div class="status-text">{{ getptz }}</div>
|
||||
<div class="car-display">
|
||||
<div class="boom-container">
|
||||
<img src="../assets/img/boom.png" alt="boom" class="boom-image top-boom" v-show="obstacleStatus.top">
|
||||
@ -66,10 +72,11 @@
|
||||
</div>
|
||||
<div class="control-button">
|
||||
<div class="circle-border" :class="{ 'pressed': isControlPressed }" @mousedown="handleControlPress"
|
||||
@mouseup="handleControlRelease" @mouseleave="handleControlRelease" @touchstart="handleControlPress"
|
||||
@touchend="handleControlRelease" @touchcancel="handleControlRelease">
|
||||
@mouseup="handleControlRelease" @mouseleave="handleControlRelease" @touchstart.prevent="handleControlPress"
|
||||
@touchend.prevent="handleControlRelease" @touchcancel.prevent="handleControlRelease" @contextmenu.prevent
|
||||
@copy.prevent @selectstart.prevent style="user-select: none;">
|
||||
<img src="../assets/img/stop.png" alt="control" class="control-button-img"
|
||||
style="width: 80px; height: 80px;">
|
||||
style="width: 80px; height: 80px; pointer-events: none;" draggable="false">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -101,7 +108,7 @@ export default {
|
||||
isControlPressed: false,
|
||||
ws: null,
|
||||
wsConnected: false,
|
||||
batteryLevel: 0,
|
||||
// batteryLevel: 0, // 注释掉电池电量
|
||||
lastResponseTime: 0,
|
||||
connectionCheckInterval: null,
|
||||
sendInterval: null,
|
||||
@ -111,13 +118,19 @@ export default {
|
||||
button: "",
|
||||
audioConfig: audioTransmitter.data(),
|
||||
isRecording: false,
|
||||
audioHandler: null
|
||||
audioHandler: null,
|
||||
reconnectTimer: null, // 添加重连定时器引用
|
||||
isComponentUnmounted: false, // 添加组件卸载标志
|
||||
isInitialized: false, // 添加初始化标志
|
||||
contenttext: "",
|
||||
_mousePressed: false, // 添加鼠标/触摸按下标志
|
||||
contentptz: "",
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 初始化 GamepadController,启用调试模式
|
||||
this.gamepadController = new GamepadController({
|
||||
debug: true,
|
||||
debug: false, // 启用调试
|
||||
deadZone: 0.1,
|
||||
updateInterval: 50
|
||||
});
|
||||
@ -126,41 +139,50 @@ export default {
|
||||
window.addEventListener("gamepadconnected", this.handleGamepadConnected);
|
||||
window.addEventListener("gamepaddisconnected", this.handleGamepadDisconnected);
|
||||
|
||||
this.isComponentUnmounted = false;
|
||||
this.initWebSocket();
|
||||
// 进入页面时发送数据
|
||||
this.$nextTick(() => {
|
||||
this.sendCarInfo();
|
||||
});
|
||||
|
||||
// 启动连接状态检查
|
||||
this.connectionCheckInterval = setInterval(() => {
|
||||
this.checkConnectionStatus();
|
||||
}, 3000); // 每3秒检查一次
|
||||
}, 3000);
|
||||
|
||||
// 启动定时发送数据
|
||||
this.sendInterval = setInterval(() => {
|
||||
this.sendControlData();
|
||||
}, 1000); // 每100ms发送一次
|
||||
}, 400);
|
||||
|
||||
// 初始化音频处理器
|
||||
this.audioHandler = {
|
||||
...audioTransmitter.data(),
|
||||
...audioTransmitter.methods
|
||||
};
|
||||
|
||||
// 初始化音频 WebSocket 连接
|
||||
this.audioHandler.audioWs = new WebSocket('ws://192.168.4.103/ws');
|
||||
|
||||
this.audioHandler.audioWs.onopen = () => {
|
||||
console.log('音频 WebSocket 已连接');
|
||||
};
|
||||
|
||||
this.audioHandler.audioWs.onerror = (error) => {
|
||||
console.error('音频 WebSocket 错误:', error);
|
||||
};
|
||||
|
||||
this.audioHandler.audioWs.onclose = () => {
|
||||
console.log('音频 WebSocket 已关闭');
|
||||
};
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 组件销毁前清理资源
|
||||
if (this.gamepadController) {
|
||||
this.gamepadController.destroy();
|
||||
}
|
||||
// 移除全局事件监听
|
||||
window.removeEventListener("gamepadconnected", this.handleGamepadConnected);
|
||||
window.removeEventListener("gamepaddisconnected", this.handleGamepadDisconnected);
|
||||
this.isComponentUnmounted = true; // 标记组件已卸载
|
||||
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
// 清除重连定时器
|
||||
if (this.reconnectTimer) {
|
||||
clearTimeout(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
|
||||
// 清除定时器
|
||||
if (this.connectionCheckInterval) {
|
||||
clearInterval(this.connectionCheckInterval);
|
||||
}
|
||||
@ -169,10 +191,34 @@ export default {
|
||||
clearInterval(this.sendInterval);
|
||||
}
|
||||
|
||||
// 移除全局事件监听
|
||||
window.removeEventListener("gamepadconnected", this.handleGamepadConnected);
|
||||
window.removeEventListener("gamepaddisconnected", this.handleGamepadDisconnected);
|
||||
|
||||
// 销毁手柄控制器
|
||||
if (this.gamepadController) {
|
||||
this.gamepadController.destroy();
|
||||
}
|
||||
|
||||
// 确保停止音频传输
|
||||
if (this.audioHandler && this.audioHandler.isRecording) {
|
||||
this.audioHandler.stopRecording();
|
||||
}
|
||||
|
||||
// 关闭音频 WebSocket 连接
|
||||
if (this.audioHandler && this.audioHandler.audioWs) {
|
||||
console.log('关闭音频 WebSocket 连接');
|
||||
this.audioHandler.audioWs.close();
|
||||
this.audioHandler.audioWs = null;
|
||||
}
|
||||
|
||||
// 关闭控制 WebSocket 连接
|
||||
if (this.ws) {
|
||||
console.log('关闭控制 WebSocket 连接');
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
this.wsConnected = false;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goto(path) {
|
||||
@ -196,17 +242,19 @@ export default {
|
||||
}
|
||||
},
|
||||
handleControlPress() {
|
||||
console.log('按钮被按下,设置 isControlPressed = true');
|
||||
this._mousePressed = true;
|
||||
this.isControlPressed = true;
|
||||
// 开始音频传输
|
||||
console.log('开始音频传输...');
|
||||
if (this.audioHandler) {
|
||||
this.audioHandler.startRecording();
|
||||
}
|
||||
},
|
||||
handleControlRelease() {
|
||||
console.log('按钮被释放,设置 isControlPressed = false');
|
||||
this._mousePressed = false;
|
||||
this.isControlPressed = false;
|
||||
// 停止音频传输
|
||||
console.log('停止音频传输...');
|
||||
if (this.audioHandler) {
|
||||
this.audioHandler.stopRecording();
|
||||
}
|
||||
@ -215,6 +263,7 @@ export default {
|
||||
try {
|
||||
console.log('正在连接 WebSocket...');
|
||||
this.ws = new WebSocket('ws://192.168.4.120/ws');
|
||||
// this.ws = new WebSocket('ws://192.168.1.120/ws');
|
||||
// this.ws = new WebSocket('ws://192.168.1.60:81');
|
||||
|
||||
|
||||
@ -238,14 +287,14 @@ export default {
|
||||
}
|
||||
};
|
||||
|
||||
this.ws.onclose = (event) => {
|
||||
console.log('WebSocket 已断开, code:', event.code, 'reason:', event.reason);
|
||||
this.wsConnected = false;
|
||||
// 尝试重新连接
|
||||
setTimeout(() => {
|
||||
console.log('尝试重新连接...');
|
||||
this.ws.onclose = () => {
|
||||
console.log('WebSocket连接关闭');
|
||||
// 只有在组件没有被卸载的情况下才重连
|
||||
if (!this.isComponentUnmounted) {
|
||||
this.reconnectTimer = setTimeout(() => {
|
||||
this.initWebSocket();
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
|
||||
this.ws.onerror = (error) => {
|
||||
@ -267,37 +316,53 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 更新手柄数据
|
||||
// 修改 updateGamepadData 方法
|
||||
updateGamepadData() {
|
||||
if (this.gamepadController) {
|
||||
// 获取手柄数据
|
||||
const angle = this.gamepadController.angle;
|
||||
const directionAxis9 = this.gamepadController.directionAxis9;
|
||||
const speed = this.gamepadController.speed; // 获取速度值
|
||||
const speed = this.gamepadController.speed;
|
||||
|
||||
// 更新控制按钮状态
|
||||
const wasPressed = this.isControlPressed;
|
||||
this.isControlPressed = this.gamepadController.rightJoystickPressed;
|
||||
// 根据角度计算方向值(0-4)
|
||||
let direction = 0; // 默认停止
|
||||
if (speed > 10) {
|
||||
if (angle >= 315 || angle < 45) {
|
||||
direction = 4; // 右转
|
||||
} else if (angle >= 45 && angle < 135) {
|
||||
direction = 2; // 后退
|
||||
} else if (angle >= 135 && angle < 225) {
|
||||
direction = 3; // 左转
|
||||
} else if (angle >= 225 && angle < 315) {
|
||||
direction = 1; // 前进
|
||||
}
|
||||
}
|
||||
|
||||
// 检测按钮状态变化并处理音频传输
|
||||
if (!wasPressed && this.isControlPressed) {
|
||||
// 按钮刚被按下
|
||||
console.log('手柄按钮按下,开始音频传输...');
|
||||
// 检测手柄右摇杆按钮状态,但不覆盖鼠标/触摸按下的状态
|
||||
const gamepadButtonPressed = this.gamepadController.rightJoystickPressed;
|
||||
|
||||
// 如果手柄按钮被按下且当前状态为未按下,则开始录音
|
||||
if (gamepadButtonPressed && !this.isControlPressed) {
|
||||
console.log('手柄按钮被按下,开始录音');
|
||||
this.isControlPressed = true;
|
||||
if (this.audioHandler) {
|
||||
this.audioHandler.startRecording();
|
||||
}
|
||||
} else if (wasPressed && !this.isControlPressed) {
|
||||
// 按钮刚被释放
|
||||
console.log('手柄按钮释放,停止音频传输...');
|
||||
}
|
||||
// 如果手柄按钮被释放且当前状态为按下,则停止录音
|
||||
else if (!gamepadButtonPressed && this.isControlPressed && !this._mousePressed) {
|
||||
console.log('手柄按钮被释放,停止录音');
|
||||
this.isControlPressed = false;
|
||||
if (this.audioHandler) {
|
||||
this.audioHandler.stopRecording();
|
||||
}
|
||||
}
|
||||
|
||||
// 更新其他数据
|
||||
// 更新状态
|
||||
this.contenttext = direction;
|
||||
this.lastDirection = angle;
|
||||
this.platform_fun = directionAxis9;
|
||||
this.lastSpeed = speed; // 更新速度值
|
||||
if (directionAxis9 !== undefined) this.platform_fun = directionAxis9;
|
||||
if (speed !== undefined) this.lastSpeed = speed;
|
||||
}
|
||||
},
|
||||
sendCarInfo() {
|
||||
@ -323,27 +388,29 @@ export default {
|
||||
this.sendCarInfo();
|
||||
},
|
||||
|
||||
// 修改状态更新函数
|
||||
updateCarStatus(data) {
|
||||
if (data.attribute) {
|
||||
// 更新电池状态
|
||||
this.batteryLevel = data.attribute.bat_quantity;
|
||||
|
||||
// 更新障碍物显示状态
|
||||
this.obstacleStatus = {
|
||||
top: data.attribute.obstacle_sta === 0,
|
||||
bottom: data.attribute.obstacle_sta === 1
|
||||
top: data.attribute.obstacle_sta === 1,
|
||||
bottom: data.attribute.obstacle_sta === 2
|
||||
};
|
||||
|
||||
// 更新开关状态
|
||||
this.platform_fun = data.attribute.platform;
|
||||
// 只在初始化时更新开关状态
|
||||
// if (!this.isInitialized) {
|
||||
this.screenStatus = data.attribute.screen_en === 1;
|
||||
this.warningLightStatus = data.attribute.warn_light_en === 1;
|
||||
this.followStatus = data.attribute.follow_en === 1;
|
||||
this.obstacleAvoidEnabled = data.attribute.obstacle_avoid_en === 1;
|
||||
this.contentptz = data.attribute.platform;
|
||||
// this.isInitialized = true;
|
||||
// }
|
||||
}
|
||||
|
||||
// 更新车辆状态
|
||||
this.lastSpeed = data.attribute.car_speed;
|
||||
this.lastDirection = data.attribute.car_direction;
|
||||
// 更新方向状态
|
||||
if (data.driver && typeof data.driver.direction !== 'undefined') {
|
||||
this.lastDirection = data.driver.direction; // 使用返回的方向值
|
||||
}
|
||||
},
|
||||
|
||||
@ -355,9 +422,33 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 修改开关状态处理函数
|
||||
handleScreenChange(value) {
|
||||
this.screenStatus = value;
|
||||
this.sendControlData();
|
||||
},
|
||||
|
||||
handleWarningLightChange(value) {
|
||||
this.warningLightStatus = value;
|
||||
this.sendControlData();
|
||||
},
|
||||
|
||||
handleFollowChange(value) {
|
||||
this.followStatus = value;
|
||||
this.sendControlData();
|
||||
},
|
||||
|
||||
handleObstacleAvoidChange(value) {
|
||||
this.obstacleAvoidEnabled = value;
|
||||
this.sendControlData();
|
||||
},
|
||||
|
||||
// 修改 sendControlData 方法
|
||||
sendControlData() {
|
||||
// 先更新手柄数据
|
||||
// 只在有手柄数据时更新手柄相关状态
|
||||
if (this.gamepadController && this.gamepadController.isActive) {
|
||||
this.updateGamepadData();
|
||||
}
|
||||
|
||||
const controlData = {
|
||||
"JSON_id": 1,
|
||||
@ -380,21 +471,122 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
handleBack() {
|
||||
// 先标记组件已卸载,防止重连
|
||||
this.isComponentUnmounted = true;
|
||||
|
||||
// 立即清除所有定时器
|
||||
if (this.connectionCheckInterval) {
|
||||
clearInterval(this.connectionCheckInterval);
|
||||
this.connectionCheckInterval = null;
|
||||
}
|
||||
if (this.sendInterval) {
|
||||
clearInterval(this.sendInterval);
|
||||
this.sendInterval = null;
|
||||
}
|
||||
if (this.reconnectTimer) {
|
||||
clearTimeout(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
|
||||
// 停止音频传输
|
||||
if (this.audioHandler && this.audioHandler.isRecording) {
|
||||
this.audioHandler.stopRecording();
|
||||
}
|
||||
|
||||
// 移除全局事件监听
|
||||
window.removeEventListener("gamepadconnected", this.handleGamepadConnected);
|
||||
window.removeEventListener("gamepaddisconnected", this.handleGamepadDisconnected);
|
||||
|
||||
// 销毁手柄控制器
|
||||
if (this.gamepadController) {
|
||||
this.gamepadController.destroy();
|
||||
this.gamepadController = null;
|
||||
}
|
||||
|
||||
// 断开所有 WebSocket 连接
|
||||
const closePromises = [];
|
||||
|
||||
if (this.ws) {
|
||||
console.log('断开控制 WebSocket 连接');
|
||||
this.ws.onclose = null; // 移除重连监听
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
this.wsConnected = false;
|
||||
}
|
||||
|
||||
if (this.audioHandler && this.audioHandler.audioWs) {
|
||||
console.log('断开音频 WebSocket 连接');
|
||||
this.audioHandler.audioWs.onclose = null; // 移除重连监听
|
||||
this.audioHandler.audioWs.close();
|
||||
this.audioHandler.audioWs = null;
|
||||
}
|
||||
|
||||
// 确保所有清理工作完成后再跳转
|
||||
setTimeout(() => {
|
||||
// 返回主页
|
||||
this.$router.push('/');
|
||||
}, 100);
|
||||
},
|
||||
|
||||
},
|
||||
computed: {
|
||||
// 注释掉电池图片计算属性
|
||||
/*
|
||||
batteryImage() {
|
||||
// 使用 require 来正确引用图片
|
||||
if (this.batteryLevel >= 80) return require('../assets/img/bat_full.png');
|
||||
if (this.batteryLevel >= 60) return require('../assets/img/bat_high.png');
|
||||
if (this.batteryLevel >= 40) return require('../assets/img/bat_medium.png');
|
||||
if (this.batteryLevel >= 20) return require('../assets/img/bat_low.png');
|
||||
return require('../assets/img/bat_empty.png');
|
||||
},
|
||||
*/
|
||||
connectionImage() {
|
||||
return this.wsConnected ?
|
||||
require('../assets/img/connect.png') :
|
||||
require('../assets/img/no_connect.png');
|
||||
},
|
||||
getDirectionText() {
|
||||
// 根据 direction 值显示对应状态
|
||||
switch (this.contenttext) {
|
||||
case 0:
|
||||
return '遥控车已停止';
|
||||
case 1:
|
||||
return '遥控车正在前进';
|
||||
case 2:
|
||||
return '遥控车正在后退';
|
||||
case 3:
|
||||
return '遥控车正在左转';
|
||||
case 4:
|
||||
return '遥控车正在右转';
|
||||
default:
|
||||
return '遥控车当前状态';
|
||||
}
|
||||
},
|
||||
getptz() {
|
||||
switch (this.contentptz) {
|
||||
case 0:
|
||||
return '云台静止';
|
||||
case 1:
|
||||
return '云台上升';
|
||||
case 2:
|
||||
return '云台下降';
|
||||
default:
|
||||
return '云台静止';
|
||||
}
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
|
||||
// 添加返回按钮处理函数
|
||||
const onClickLeft = () => {
|
||||
router.back();
|
||||
};
|
||||
|
||||
return {
|
||||
onClickLeft,
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -441,6 +633,11 @@ export default {
|
||||
border: 2px solid #00ffff;
|
||||
padding: 2px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 180px;
|
||||
/* 确保文本变化时盒子大小稳定 */
|
||||
}
|
||||
|
||||
.main-content {
|
||||
@ -589,6 +786,12 @@ export default {
|
||||
align-items: center;
|
||||
transition: border-color 0.3s ease;
|
||||
cursor: pointer;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.circle-border.pressed {
|
||||
@ -610,4 +813,28 @@ export default {
|
||||
.voice-icon-img.show-voice {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 确保标题栏在最上层 */
|
||||
:deep(.van-nav-bar) {
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
cursor: pointer;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.3s;
|
||||
font-size: 24px;
|
||||
/* 调整箭头大小 */
|
||||
color: #00ffff;
|
||||
/* 使用青色,与其他元素保持一致 */
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
</style>
|
||||
|
736
src/views/ConeControl.vue
Normal file
736
src/views/ConeControl.vue
Normal file
@ -0,0 +1,736 @@
|
||||
<template>
|
||||
<div class="cone-control">
|
||||
<van-nav-bar title="路锥控制" left-arrow @click-left="onClickLeft" fixed />
|
||||
|
||||
<!-- 添加下拉刷新组件 -->
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<!-- 为模组概况添加边框 -->
|
||||
<div class="module-container">
|
||||
<div class="module-header">
|
||||
<van-icon name="setting-o" size="18" />
|
||||
<span>模组概况</span>
|
||||
</div>
|
||||
<van-cell-group inset>
|
||||
<van-cell title="模组概况">
|
||||
<template #label>
|
||||
<div class="module-info">
|
||||
<div class="info-row">
|
||||
<span class="info-label">固件版本</span>
|
||||
<span class="info-value" ref="firmwareVersionEl">{{ firmwareVersion }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">MAC地址</span>
|
||||
<span class="info-value" ref="macAddressEl">{{ macAddress }}</span>
|
||||
</div>
|
||||
<div class="info-title">网络参数</div>
|
||||
|
||||
<div class="info-row">
|
||||
<span class="info-label">网络ID</span>
|
||||
<van-field v-model="networkId" readonly input-align="right" />
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">无线频段</span>
|
||||
<van-field v-model="freqBand" readonly input-align="right" />
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">信道</span>
|
||||
<van-field v-model="channel" readonly input-align="right" />
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">速率(SF)</span>
|
||||
<van-field v-model="speedRate" readonly input-align="right" />
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">功率</span>
|
||||
<van-field v-model="power" readonly input-align="right" />
|
||||
</div>
|
||||
<div class="mode-container">
|
||||
<div class="info-row mode-row">
|
||||
<span class="info-label">网络通道</span>
|
||||
<van-field v-model="currentMode" is-link readonly input-align="right" placeholder="请选择网络通道"
|
||||
@click="showModePopup" class="mode-field" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="upload-button-container">
|
||||
<van-button type="primary" size="small" block @click="uploadLoRaConfig">上传配置</van-button>
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
|
||||
<!-- 状态和控制面板 -->
|
||||
<div class="status-container">
|
||||
<div class="module-header">
|
||||
<van-icon name="info-o" size="18" />
|
||||
<span>状态与控制</span>
|
||||
</div>
|
||||
<van-cell-group inset>
|
||||
|
||||
<!-- 报警状态(只读) -->
|
||||
<van-cell title="报警状态">
|
||||
<template #value>
|
||||
<span :style="{ color: alarmStatus === '正常' ? '#07c160' : '#ee0a24' }">{{ alarmStatus }}</span>
|
||||
</template>
|
||||
<template #right-icon>
|
||||
<van-button v-if="alarmStatus !== '正常'" size="small" type="danger"
|
||||
@click="sendCommand('clearAlarm')">清除报警</van-button>
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
<!-- 灯光状态选择 -->
|
||||
<van-cell title="灯光状态" :value="lightStatus" is-link @click="showLightStatusPicker" />
|
||||
|
||||
<!-- 布防开关 -->
|
||||
<van-cell center title="布防开关">
|
||||
<template #right-icon>
|
||||
<van-switch v-model="defenseEnabled" size="24" @change="onDefenseChange" />
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
|
||||
<!-- 灯光状态选择器 -->
|
||||
<van-popup v-model:show="lightStatusPickerVisible" position="bottom">
|
||||
<van-picker :columns="lightStatusOptions" @confirm="onLightStatusConfirm"
|
||||
@cancel="lightStatusPickerVisible = false" show-toolbar />
|
||||
</van-popup>
|
||||
|
||||
<!-- 添加模式选择器 -->
|
||||
<van-popup v-model:show="modePickerVisible" position="bottom">
|
||||
<van-picker :columns="modeOptions" @confirm="onModeConfirm" @cancel="modePickerVisible = false" show-toolbar />
|
||||
</van-popup>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, onMounted, onBeforeUnmount, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
// import { showToast } from 'vant';
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
name: 'ConeControl',
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const networkId = ref('');
|
||||
const freqBand = ref('');
|
||||
const channel = ref('');
|
||||
const speedRate = ref('');
|
||||
const power = ref('');
|
||||
const firmwareVersionEl = ref(null);
|
||||
const macAddressEl = ref(null);
|
||||
const jsonId = ref(1);
|
||||
const isLocal = ref(true);
|
||||
const freqBandPickerVisible = ref(false);
|
||||
const channelPickerVisible = ref(false);
|
||||
const speedRatePickerVisible = ref(false);
|
||||
const powerPickerVisible = ref(false);
|
||||
const alarmStatus = ref('报警');
|
||||
const lightStatus = ref('白灯亮');
|
||||
const defenseEnabled = ref(false);
|
||||
const lightStatusPickerVisible = ref(false);
|
||||
const refreshing = ref(false);
|
||||
const firmwareVersion = ref('');
|
||||
const macAddress = ref('');
|
||||
const modePickerVisible = ref(false);
|
||||
const currentMode = ref('');
|
||||
|
||||
// 选项数据
|
||||
const freqBandOptions = [
|
||||
{ text: '433MHz(430MHz-446MHz)', value: 0 },
|
||||
{ text: '470MHz(454MHz-469MHz)', value: 1 },
|
||||
{ text: '480MHz(470MHz-486MHz)', value: 2 },
|
||||
{ text: '500MHz(494MHz-509MHz)', value: 3 }
|
||||
];
|
||||
|
||||
const channelOptions = Array.from({ length: 32 }, (_, i) => ({
|
||||
text: `信道${i + 1}`,
|
||||
value: i
|
||||
}));
|
||||
|
||||
const speedRateOptions = [
|
||||
{ text: '62.5kbps', value: 0 },
|
||||
{ text: '37.5kbps', value: 1 },
|
||||
{ text: '21.8kbps', value: 2 },
|
||||
{ text: '12.5kbps', value: 3 },
|
||||
{ text: '7.0kbps', value: 4 },
|
||||
{ text: '3.9kbps', value: 5 },
|
||||
{ text: '2.1kbps', value: 6 }
|
||||
];
|
||||
|
||||
const powerOptions = [
|
||||
{ text: '22dbm', value: 0 },
|
||||
{ text: '20dbm', value: 1 },
|
||||
{ text: '17dbm', value: 2 },
|
||||
{ text: '14dbm', value: 3 },
|
||||
{ text: '11dbm', value: 4 },
|
||||
{ text: '8dbm', value: 5 },
|
||||
{ text: '5dbm', value: 6 },
|
||||
{ text: '2dbm', value: 7 }
|
||||
];
|
||||
|
||||
// 灯光状态选项
|
||||
const lightStatusOptions = [
|
||||
{ text: '白光亮(高)', value: 0 },
|
||||
{ text: '白光亮(中)', value: 1 },
|
||||
{ text: '白光亮(低)', value: 2 },
|
||||
{ text: '红蓝快闪', value: 3 },
|
||||
{ text: '红蓝慢闪', value: 4 },
|
||||
{ text: '投射灯亮', value: 5 },
|
||||
{ text: '关闭', value: 6 }
|
||||
];
|
||||
|
||||
const modeOptions = [
|
||||
{ text: '通道一', value: 0, networkId: '6A6A00' },
|
||||
{ text: '通道二', value: 1, networkId: '6A6A01' },
|
||||
{ text: '通道三', value: 2, networkId: '6A6A02' },
|
||||
{ text: '通道四', value: 3, networkId: '6A6A03' }
|
||||
];
|
||||
|
||||
const onClickLeft = () => {
|
||||
router.back();
|
||||
};
|
||||
|
||||
const showFreqBandPopup = () => {
|
||||
freqBandPickerVisible.value = true;
|
||||
};
|
||||
|
||||
const showChannelPopup = () => {
|
||||
channelPickerVisible.value = true;
|
||||
};
|
||||
|
||||
const showSpeedRatePopup = () => {
|
||||
speedRatePickerVisible.value = true;
|
||||
};
|
||||
|
||||
const showPowerPopup = () => {
|
||||
powerPickerVisible.value = true;
|
||||
};
|
||||
|
||||
const showLightStatusPicker = () => {
|
||||
lightStatusPickerVisible.value = true;
|
||||
};
|
||||
|
||||
const showModePopup = () => {
|
||||
modePickerVisible.value = true;
|
||||
};
|
||||
|
||||
const onFreqBandConfirm = (value) => {
|
||||
freqBand.value = value.selectedOptions[0].text;
|
||||
freqBandPickerVisible.value = false;
|
||||
};
|
||||
|
||||
const onChannelConfirm = (value) => {
|
||||
channel.value = value.selectedOptions[0].text;
|
||||
channelPickerVisible.value = false;
|
||||
};
|
||||
|
||||
const onSpeedRateConfirm = (value) => {
|
||||
speedRate.value = value.selectedOptions[0].text;
|
||||
speedRatePickerVisible.value = false;
|
||||
};
|
||||
|
||||
const onPowerConfirm = (value) => {
|
||||
power.value = value.selectedOptions[0].text;
|
||||
powerPickerVisible.value = false;
|
||||
};
|
||||
|
||||
const onLightStatusConfirm = (value) => {
|
||||
lightStatus.value = value.selectedOptions[0].text;
|
||||
lightStatusPickerVisible.value = false;
|
||||
sendLightStatusCommand(value.selectedOptions[0].value);
|
||||
};
|
||||
|
||||
const sendLightStatusCommand = (value) => {
|
||||
const lightStatusCommand = {
|
||||
board_id: 50,
|
||||
JSON_id: 1,
|
||||
cones: {
|
||||
traffic_cone: {
|
||||
lamplight: value
|
||||
}
|
||||
},
|
||||
error_code: 0
|
||||
};
|
||||
if (isLocal.value) {
|
||||
axios.post('/communication', lightStatusCommand, {
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Light status response:', response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Light status error:', error);
|
||||
});
|
||||
} else {
|
||||
MQTT_send(lightStatusCommand);
|
||||
}
|
||||
};
|
||||
|
||||
const onDefenseChange = (value) => {
|
||||
const defenseCommand = {
|
||||
board_id: 50,
|
||||
JSON_id: 1,
|
||||
cones: {
|
||||
traffic_cone: {
|
||||
mode: value ? 1 : 0
|
||||
}
|
||||
},
|
||||
error_code: 0
|
||||
};
|
||||
if (isLocal.value) {
|
||||
axios.post('/communication', defenseCommand, {
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Defense mode response:', response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Defense mode error:', error);
|
||||
});
|
||||
} else {
|
||||
MQTT_send(defenseCommand);
|
||||
}
|
||||
};
|
||||
|
||||
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 MQTT_send = (send_string) => {
|
||||
showToast('设置成功');
|
||||
jsonId.value++;
|
||||
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 uploadLoRaConfig = () => {
|
||||
// 检查必填字段是否为空
|
||||
if (!networkId.value || !freqBand.value || !channel.value || !speedRate.value || !power.value) {
|
||||
showToast('请填写所有必填字段');
|
||||
return;
|
||||
}
|
||||
|
||||
// 将十进制字符串转换为十六进制数组
|
||||
const meshId = networkId.value.match(/.{2}/g)?.map(hex => parseInt(hex, 10)) || [0, 0, 0];
|
||||
|
||||
// 获取各个选项的值
|
||||
const freqBandValue = freqBandOptions.find(option => option.text === freqBand.value)?.value || 0;
|
||||
const channelValue = parseInt(channel.value.replace('信道', '')) - 1;
|
||||
const speedRateValue = speedRateOptions.find(option => option.text === speedRate.value)?.value || 0;
|
||||
const powerValue = powerOptions.find(option => option.text === power.value)?.value || 0;
|
||||
|
||||
const configData = {
|
||||
"board_id": 50,
|
||||
"JSON_id": jsonId.value,
|
||||
"gateway": {
|
||||
"LoRa_cfg": {
|
||||
"mesh_id": meshId,
|
||||
"fre_band": freqBandValue,
|
||||
"channel": channelValue,
|
||||
"SF": speedRateValue,
|
||||
"power": powerValue,
|
||||
"mode": 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
console.log('Uploading config:', configData);
|
||||
|
||||
if (isLocal.value) {
|
||||
axios.post('/communication', configData, {
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Upload response:', response.data);
|
||||
showToast('上传成功');
|
||||
jsonId.value++;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Upload error:', error);
|
||||
showToast('上传失败');
|
||||
jsonId.value++;
|
||||
});
|
||||
} else {
|
||||
MQTT_send(configData);
|
||||
}
|
||||
};
|
||||
|
||||
const sendCommand = (command) => {
|
||||
if (command === 'clearAlarm') {
|
||||
const clearAlarmCommand = {
|
||||
board_id: 50,
|
||||
JSON_id: 1,
|
||||
cones: {
|
||||
traffic_cone: {
|
||||
alarm: 0
|
||||
}
|
||||
},
|
||||
error_code: 0
|
||||
};
|
||||
if (isLocal.value) {
|
||||
axios.post('/communication', clearAlarmCommand, {
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Clear alarm response:', response.data);
|
||||
alarmStatus.value = '正常';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Clear alarm error:', error);
|
||||
});
|
||||
} else {
|
||||
MQTT_send(clearAlarmCommand);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onModeConfirm = (value) => {
|
||||
currentMode.value = value.selectedOptions[0].text;
|
||||
networkId.value = value.selectedOptions[0].networkId;
|
||||
modePickerVisible.value = false;
|
||||
|
||||
// 发送配置更新命令
|
||||
const configData = {
|
||||
board_id: 50,
|
||||
JSON_id: 1,
|
||||
cones: {
|
||||
LoRa_cfg: {
|
||||
mesh_id: [
|
||||
parseInt(networkId.value.slice(0, 2), 16),
|
||||
parseInt(networkId.value.slice(2, 4), 16),
|
||||
parseInt(networkId.value.slice(4, 6), 16)
|
||||
],
|
||||
fre_band: freqBandOptions.find(option => option.text === freqBand.value)?.value || 0,
|
||||
channel: channel.value ? (parseInt(channel.value.match(/\d+/)?.[0] || '1') - 1) : 0,
|
||||
SF: speedRateOptions.find(option => option.text === speedRate.value)?.value || 0,
|
||||
power: powerOptions.find(option => option.text === power.value)?.value || 0,
|
||||
mode: value.selectedOptions[0].value
|
||||
}
|
||||
},
|
||||
error_code: 0
|
||||
};
|
||||
|
||||
if (isLocal.value) {
|
||||
axios.post('/communication', configData, {
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Mode update response:', response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Mode update error:', error);
|
||||
});
|
||||
} else {
|
||||
MQTT_send(configData);
|
||||
}
|
||||
};
|
||||
|
||||
const updateStateFromResponse = (data) => {
|
||||
// 检查数据结构
|
||||
if (!data || !data.cones) {
|
||||
console.error('Invalid response data structure');
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新 LoRa 配置相关状态
|
||||
if (data.cones.LoRa_cfg) {
|
||||
const loraConfig = data.cones.LoRa_cfg;
|
||||
firmwareVersion.value = loraConfig.versions;
|
||||
macAddress.value = loraConfig.mac_addr.join(':');
|
||||
networkId.value = loraConfig.mesh_id.map(num => num.toString(16).padStart(2, '0').toUpperCase()).join('');
|
||||
freqBand.value = freqBandOptions.find(option => option.value === loraConfig.fre_band)?.text || '';
|
||||
channel.value = `信道${loraConfig.channel + 1}`;
|
||||
speedRate.value = speedRateOptions.find(option => option.value === loraConfig.SF)?.text || '';
|
||||
power.value = powerOptions.find(option => option.value === loraConfig.power)?.text || '';
|
||||
|
||||
// 更新当前模式
|
||||
const mode = modeOptions.find(option => option.networkId === networkId.value);
|
||||
if (mode) {
|
||||
currentMode.value = mode.text;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新路锥状态
|
||||
if (data.cones.traffic_cone) {
|
||||
const trafficCone = data.cones.traffic_cone;
|
||||
// 更新报警状态
|
||||
alarmStatus.value = trafficCone.alarm === 1 ? '报警' : '正常';
|
||||
|
||||
// 更新灯光状态
|
||||
const lightOption = lightStatusOptions.find(option => option.value === trafficCone.lamplight);
|
||||
if (lightOption) {
|
||||
lightStatus.value = lightOption.text;
|
||||
}
|
||||
|
||||
// 更新布防状态
|
||||
defenseEnabled.value = trafficCone.mode === 1;
|
||||
}
|
||||
};
|
||||
|
||||
const onRefresh = () => {
|
||||
const refreshCommand = {
|
||||
board_id: 50,
|
||||
JSON_id: 1,
|
||||
cones: {
|
||||
get_traffic_cone: 1,
|
||||
get_LoRa_cfg: 1
|
||||
},
|
||||
error_code: 0
|
||||
};
|
||||
if (isLocal.value) {
|
||||
axios.post('/communication', refreshCommand, {
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Refresh response:', response.data);
|
||||
// 直接传递整个响应数据
|
||||
updateStateFromResponse(response.data);
|
||||
refreshing.value = false;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Refresh error:', error);
|
||||
refreshing.value = false;
|
||||
});
|
||||
} else {
|
||||
MQTT_send(refreshCommand);
|
||||
refreshing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
checkEnvironment();
|
||||
onRefresh();
|
||||
});
|
||||
|
||||
return {
|
||||
networkId,
|
||||
freqBand,
|
||||
channel,
|
||||
speedRate,
|
||||
power,
|
||||
firmwareVersionEl,
|
||||
macAddressEl,
|
||||
onClickLeft,
|
||||
showFreqBandPopup,
|
||||
showChannelPopup,
|
||||
showSpeedRatePopup,
|
||||
showPowerPopup,
|
||||
uploadLoRaConfig,
|
||||
sendCommand,
|
||||
freqBandPickerVisible,
|
||||
channelPickerVisible,
|
||||
speedRatePickerVisible,
|
||||
powerPickerVisible,
|
||||
onFreqBandConfirm,
|
||||
onChannelConfirm,
|
||||
onSpeedRateConfirm,
|
||||
onPowerConfirm,
|
||||
freqBandOptions,
|
||||
channelOptions,
|
||||
speedRateOptions,
|
||||
powerOptions,
|
||||
alarmStatus,
|
||||
lightStatus,
|
||||
defenseEnabled,
|
||||
lightStatusPickerVisible,
|
||||
lightStatusOptions,
|
||||
showLightStatusPicker,
|
||||
onLightStatusConfirm,
|
||||
onDefenseChange,
|
||||
refreshing,
|
||||
onRefresh,
|
||||
firmwareVersion,
|
||||
macAddress,
|
||||
modePickerVisible,
|
||||
currentMode,
|
||||
modeOptions,
|
||||
showModePopup,
|
||||
onModeConfirm,
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cone-control {
|
||||
padding-top: 46px;
|
||||
/* 为固定的导航栏留出空间 */
|
||||
background-color: #f7f8fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.module-container {
|
||||
margin: 16px;
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(100, 101, 102, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.module-header {
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #323233;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.status-container {
|
||||
margin: 16px;
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(100, 101, 102, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
min-width: 80px;
|
||||
color: #646566;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-row :deep(.van-field) {
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.upload-button-container {
|
||||
margin-top: 16px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
/* 添加过渡动画 */
|
||||
.command-item {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.command-item::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(25, 137, 250, 0.1);
|
||||
border-radius: 8px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.command-item:active::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 为清除报警按钮添加样式 */
|
||||
:deep(.van-button--danger) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.mode-container {
|
||||
margin: 12px -16px;
|
||||
padding: 12px 16px;
|
||||
background-color: #f2f7ff;
|
||||
/* 浅蓝色背景 */
|
||||
border-left: 4px solid #1989fa;
|
||||
/* 左边添加蓝色边框 */
|
||||
}
|
||||
|
||||
.mode-row {
|
||||
margin-bottom: 0;
|
||||
/* 覆盖原来的 margin */
|
||||
}
|
||||
|
||||
.mode-field {
|
||||
font-weight: 500;
|
||||
/* 字体加粗 */
|
||||
color: #1989fa;
|
||||
/* 使用主题蓝色 */
|
||||
}
|
||||
|
||||
.mode-field :deep(.van-field__value) {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.mode-field :deep(.van-field__placeholder) {
|
||||
color: #1989fa;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 让其他网络参数稍微淡一点 */
|
||||
.info-row:not(.mode-row) {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.car-status {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-0 {
|
||||
color: #909399;
|
||||
/* 灰色 - 停止 */
|
||||
}
|
||||
|
||||
.status-1 {
|
||||
color: #67C23A;
|
||||
/* 绿色 - 前进 */
|
||||
}
|
||||
|
||||
.status-2 {
|
||||
color: #E6A23C;
|
||||
/* 橙色 - 后退 */
|
||||
}
|
||||
|
||||
.status-3 {
|
||||
color: #409EFF;
|
||||
/* 蓝色 - 左转 */
|
||||
}
|
||||
|
||||
.status-4 {
|
||||
color: #409EFF;
|
||||
/* 蓝色 - 右转 */
|
||||
}
|
||||
</style>
|
716
src/views/flipScreen/flipScreen.vue
Normal file
716
src/views/flipScreen/flipScreen.vue
Normal file
@ -0,0 +1,716 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<Header :title="currentTitle"></Header>
|
||||
<div class="content">
|
||||
<!-- Top Section - 4 buttons in 2 rows -->
|
||||
<div class="control-section">
|
||||
<div class="button-grid top-grid">
|
||||
<div class="control-btn" @click="handlePlatformControl('up')">
|
||||
<div class="btn-icon">
|
||||
<van-icon name="arrow-up" />
|
||||
</div>
|
||||
<div class="btn-label">平台上升</div>
|
||||
</div>
|
||||
<div class="control-btn" @click="handlePlatformControl('down')">
|
||||
<div class="btn-icon">
|
||||
<van-icon name="arrow-down" />
|
||||
</div>
|
||||
<div class="btn-label">平台下降</div>
|
||||
</div>
|
||||
<div class="control-btn" @click="handleScreenControl">
|
||||
<div class="btn-icon">
|
||||
<van-icon name="tv-o" />
|
||||
</div>
|
||||
<div class="btn-label">屏幕开关</div>
|
||||
</div>
|
||||
<div class="control-btn" @click="showLaserModeDialog">
|
||||
<div class="btn-icon">
|
||||
<van-icon name="bulb-o" />
|
||||
</div>
|
||||
<div class="btn-label">激光模式</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Middle Section - 6 buttons in 2 rows -->
|
||||
<div class="control-section">
|
||||
<div class="button-grid middle-grid">
|
||||
<div class="control-btn"
|
||||
@click="handleLightControl(1)"
|
||||
:class="{ 'active-light': lightStates[0] }">
|
||||
<div class="btn-icon">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-deng"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn-label">灯1</div>
|
||||
</div>
|
||||
<div class="control-btn"
|
||||
@click="handleLightControl(2)"
|
||||
:class="{ 'active-light': lightStates[1] }">
|
||||
<div class="btn-icon">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-deng"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn-label">灯2</div>
|
||||
</div>
|
||||
<div class="control-btn"
|
||||
@click="handleLightControl(3)"
|
||||
:class="{ 'active-light': lightStates[2] }">
|
||||
<div class="btn-icon">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-deng"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn-label">灯3</div>
|
||||
</div>
|
||||
<div class="control-btn"
|
||||
@click="handleLightControl(4)"
|
||||
:class="{ 'active-light': lightStates[3] }">
|
||||
<div class="btn-icon">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-deng"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn-label">灯4</div>
|
||||
</div>
|
||||
<div class="control-btn"
|
||||
@click="handleLightControl(5)"
|
||||
:class="{ 'active-light': lightStates[4] }">
|
||||
<div class="btn-icon">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-deng"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn-label">灯5</div>
|
||||
</div>
|
||||
<div class="control-btn"
|
||||
@click="handleLightControl(6)"
|
||||
:class="{ 'active-light': lightStates[5] }">
|
||||
<div class="btn-icon">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-deng"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn-label">灯6</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Section - 2 buttons in 1 row -->
|
||||
<div class="control-section">
|
||||
<div class="button-row bottom-row">
|
||||
<div class="action-btn reset-btn" @click="showBrightnessDialog">
|
||||
<div class="btn-icon">
|
||||
<van-icon name="setting-o" />
|
||||
</div>
|
||||
<div class="btn-label">亮度</div>
|
||||
</div>
|
||||
<div class="action-btn stop-btn" @click="showProgramDialog">
|
||||
<div class="btn-icon">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-jiemu"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="btn-label">节目</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer></Footer>
|
||||
|
||||
<!-- 激光模式选择弹窗 -->
|
||||
<van-popup v-model:show="showLaserMode" position="center" round>
|
||||
<div class="popup-content">
|
||||
<div class="popup-title">选择激光模式</div>
|
||||
<div class="mode-options">
|
||||
<div class="mode-option"
|
||||
v-for="mode in laserModes"
|
||||
:key="mode.value"
|
||||
:class="{ 'selected': lightMode === mode.value }"
|
||||
@click="selectLaserMode(mode.value)">
|
||||
{{ mode.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<!-- 亮度调节弹窗 -->
|
||||
<van-popup v-model:show="showBrightness" position="center" round class="brightness-popup">
|
||||
<div class="popup-content">
|
||||
<div class="popup-title">调节亮度</div>
|
||||
<div class="brightness-slider">
|
||||
<van-slider v-model="brightness" :min="0" :max="100" @change="handleBrightnessChange" />
|
||||
<div class="brightness-value">{{ brightness }}%</div>
|
||||
</div>
|
||||
<!-- <div class="popup-buttons">
|
||||
<van-button type="primary" block @click="showBrightness = false">确定</van-button>
|
||||
</div> -->
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<!-- 节目选择弹窗 -->
|
||||
<van-popup v-model:show="showProgram" position="center" round>
|
||||
<div class="popup-content">
|
||||
<div class="popup-title">选择节目</div>
|
||||
<div class="program-options">
|
||||
<div class="program-option"
|
||||
v-for="id in availablePrograms"
|
||||
:key="id"
|
||||
:class="{ 'selected': currentProgram === id }"
|
||||
@click="selectProgram(id)">
|
||||
节目 {{ id }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
import Header from "../../components/Header.vue";
|
||||
import Footer from "../../components/Footer.vue";
|
||||
import { iconfont } from '../../assets/js/iconfont.js';
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Header,
|
||||
Footer
|
||||
},
|
||||
setup() {
|
||||
|
||||
const currentTitle = ref('翻转屏遥控');
|
||||
const isLocal = ref(false);
|
||||
const jsonId = ref(1);
|
||||
const loading = ref(false);
|
||||
const screenPower = ref('off');
|
||||
const lightMode = ref('auto');
|
||||
const lightStates = ref([true, false, false, false, false, false]);
|
||||
const brightness = ref(70);
|
||||
const currentProgram = ref(1);
|
||||
const availablePrograms = ref([1, 2, 3, 4, 5]);
|
||||
|
||||
// 弹窗控制
|
||||
const showLaserMode = ref(false);
|
||||
const showBrightness = ref(false);
|
||||
const showProgram = ref(false);
|
||||
|
||||
// 激光模式选项
|
||||
const laserModes = [
|
||||
{ label: '自动模式', value: 'auto' },
|
||||
{ label: '手动模式', value: 'manual' },
|
||||
{ label: '关闭模式', value: 'off' }
|
||||
];
|
||||
|
||||
//环境监测部分
|
||||
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 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) }, "*");
|
||||
}
|
||||
showToast('发送成功');
|
||||
};
|
||||
|
||||
const MQTT_recv = (string) => {
|
||||
loading.value = false;
|
||||
console.log("MQTT 接收的json:" + string);
|
||||
const data = JSON.parse(string);
|
||||
parseAndFillData(data);
|
||||
|
||||
// 检查错误码
|
||||
if (data.error_code === 0) {
|
||||
showToast('操作成功');
|
||||
} else {
|
||||
showToast('操作失败: ' + (data.error_msg || '未知错误'));
|
||||
}
|
||||
|
||||
console.log('Received message:', string);
|
||||
};
|
||||
|
||||
// 解析接收到的数据并更新状态
|
||||
const parseAndFillData = (data) => {
|
||||
if (data.Flip_screen && data.Flip_screen.status) {
|
||||
const status = data.Flip_screen.status;
|
||||
|
||||
// 更新平台状态
|
||||
if (status.platform) {
|
||||
// 可以添加平台状态更新逻辑
|
||||
}
|
||||
|
||||
// 更新屏幕状态
|
||||
if (status.screen) {
|
||||
screenPower.value = status.screen.power;
|
||||
brightness.value = status.screen.brightness;
|
||||
}
|
||||
|
||||
// 更新灯光状态
|
||||
if (status.lights) {
|
||||
lightStates.value = status.lights.map(light => light.state === 'on');
|
||||
}
|
||||
|
||||
// 更新节目状态
|
||||
if (status.program) {
|
||||
currentProgram.value = status.program.current_id;
|
||||
if (status.program.available) {
|
||||
availablePrograms.value = status.program.available;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新灯光模式
|
||||
if (status.light_mode) {
|
||||
lightMode.value = status.light_mode;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 发送消息的统一方法
|
||||
const sendMessage = async (message) => {
|
||||
loading.value = true;
|
||||
|
||||
if (isLocal.value) {
|
||||
// 本地环境使用 axios
|
||||
try {
|
||||
const response = await axios.post('/api/flip-screen', message);
|
||||
console.log('本地通信响应:', response.data);
|
||||
parseAndFillData(response.data);
|
||||
|
||||
// 检查错误码
|
||||
if (response.data.error_code === 0) {
|
||||
showToast('操作成功');
|
||||
} else {
|
||||
showToast('操作失败: ' + (response.data.error_msg || '未知错误'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('本地通信错误:', error);
|
||||
showToast('通信错误: ' + error.message);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
} else {
|
||||
// 生产环境使用 MQTT
|
||||
MQTT_send(message);
|
||||
// MQTT 模式下,错误处理在 MQTT_recv 中进行
|
||||
}
|
||||
};
|
||||
|
||||
// 平台控制
|
||||
const handlePlatformControl = (direction) => {
|
||||
const message = {
|
||||
board_id: 121,
|
||||
JSON_id: jsonId.value,
|
||||
Flip_screen: {
|
||||
platform_control: {
|
||||
direction: direction
|
||||
}
|
||||
}
|
||||
};
|
||||
sendMessage(message);
|
||||
};
|
||||
|
||||
// 屏幕控制
|
||||
const handleScreenControl = () => {
|
||||
const newPower = screenPower.value === 'on' ? 'off' : 'on';
|
||||
const message = {
|
||||
board_id: 121,
|
||||
JSON_id: jsonId.value,
|
||||
Flip_screen: {
|
||||
screen_control: {
|
||||
power: newPower
|
||||
}
|
||||
}
|
||||
};
|
||||
sendMessage(message);
|
||||
};
|
||||
|
||||
// 显示激光模式选择弹窗
|
||||
const showLaserModeDialog = () => {
|
||||
showLaserMode.value = true;
|
||||
};
|
||||
|
||||
// 选择激光模式
|
||||
const selectLaserMode = (mode) => {
|
||||
lightMode.value = mode;
|
||||
showLaserMode.value = false;
|
||||
|
||||
const message = {
|
||||
board_id: 121,
|
||||
JSON_id: jsonId.value,
|
||||
Flip_screen: {
|
||||
light_mode: {
|
||||
mode: mode
|
||||
}
|
||||
}
|
||||
};
|
||||
sendMessage(message);
|
||||
};
|
||||
|
||||
// 单个灯控制
|
||||
const handleLightControl = (lightId) => {
|
||||
const currentState = lightStates.value[lightId - 1];
|
||||
const newState = currentState ? 'off' : 'on';
|
||||
|
||||
const message = {
|
||||
board_id: 121,
|
||||
JSON_id: jsonId.value,
|
||||
Flip_screen: {
|
||||
light_control: {
|
||||
light_id: lightId,
|
||||
state: newState
|
||||
}
|
||||
}
|
||||
};
|
||||
sendMessage(message);
|
||||
};
|
||||
|
||||
// 显示亮度调节弹窗
|
||||
const showBrightnessDialog = () => {
|
||||
showBrightness.value = true;
|
||||
};
|
||||
|
||||
// 亮度变化处理
|
||||
const handleBrightnessChange = (value) => {
|
||||
brightness.value = value;
|
||||
|
||||
const message = {
|
||||
board_id: 121,
|
||||
JSON_id: jsonId.value,
|
||||
Flip_screen: {
|
||||
brightness_control: {
|
||||
value: value
|
||||
}
|
||||
}
|
||||
};
|
||||
sendMessage(message);
|
||||
};
|
||||
|
||||
// 显示节目选择弹窗
|
||||
const showProgramDialog = () => {
|
||||
showProgram.value = true;
|
||||
};
|
||||
|
||||
// 选择节目
|
||||
const selectProgram = (programId) => {
|
||||
currentProgram.value = programId;
|
||||
showProgram.value = false;
|
||||
|
||||
const message = {
|
||||
board_id: 121,
|
||||
JSON_id: jsonId.value,
|
||||
Flip_screen: {
|
||||
program_control: {
|
||||
program_id: programId
|
||||
}
|
||||
}
|
||||
};
|
||||
sendMessage(message);
|
||||
};
|
||||
|
||||
// 查询设备状态
|
||||
const onRefresh = () => {
|
||||
const message = {
|
||||
board_id: 121,
|
||||
JSON_id: jsonId.value,
|
||||
Flip_screen: {
|
||||
status_query: {
|
||||
type: "all"
|
||||
}
|
||||
}
|
||||
};
|
||||
sendMessage(message);
|
||||
};
|
||||
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
await checkEnvironment();
|
||||
console.log(isLocal.value);
|
||||
window.MQTT_recv = MQTT_recv;
|
||||
onRefresh();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// 清理工作
|
||||
});
|
||||
|
||||
return {
|
||||
currentTitle,
|
||||
isLocal,
|
||||
checkEnvironment,
|
||||
MQTT_send,
|
||||
MQTT_recv,
|
||||
handlePlatformControl,
|
||||
handleScreenControl,
|
||||
showLaserModeDialog,
|
||||
selectLaserMode,
|
||||
handleLightControl,
|
||||
showBrightnessDialog,
|
||||
handleBrightnessChange,
|
||||
showProgramDialog,
|
||||
selectProgram,
|
||||
onRefresh,
|
||||
screenPower,
|
||||
lightMode,
|
||||
lightStates,
|
||||
brightness,
|
||||
currentProgram,
|
||||
availablePrograms,
|
||||
loading,
|
||||
showToast,
|
||||
showLaserMode,
|
||||
showBrightness,
|
||||
showProgram,
|
||||
laserModes
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f6fa;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
margin-top: 60px;
|
||||
margin-bottom: 60px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.control-section {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.button-grid {
|
||||
display: grid;
|
||||
gap: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.top-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.middle-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.button-row {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
position: relative;
|
||||
background-color: white;
|
||||
border-radius: 16px;
|
||||
height: 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.control-btn:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.control-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.active-light {
|
||||
background-color: #e6f7ff;
|
||||
border: 2px solid #1890ff;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
border-radius: 16px;
|
||||
height: 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background: linear-gradient(135deg, #3498db, #2980b9);
|
||||
}
|
||||
|
||||
.stop-btn {
|
||||
background: linear-gradient(135deg, #e74c3c, #c0392b);
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.action-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-size: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 12px;
|
||||
color: #3498db;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.control-btn:hover .btn-icon {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.action-btn .btn-icon {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-label {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-top: 4px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.action-btn .btn-label {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 弹窗样式 */
|
||||
.popup-content {
|
||||
padding: 20px;
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.mode-options, .program-options {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.mode-option, .program-option {
|
||||
padding: 12px 20px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.mode-option:hover, .program-option:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.mode-option.selected, .program-option.selected {
|
||||
background-color: #1890ff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.brightness-slider {
|
||||
padding: 0 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.brightness-value {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.popup-buttons {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.brightness-popup {
|
||||
width: 90%;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
@media (max-width: 380px) {
|
||||
.content {
|
||||
padding: 15px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.control-btn,
|
||||
.action-btn {
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-size: 24px;
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.btn-label {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
278
src/views/flipScreen/翻转屏协议.md
Normal file
278
src/views/flipScreen/翻转屏协议.md
Normal file
@ -0,0 +1,278 @@
|
||||
# 翻转屏通信协议文档
|
||||
|
||||
本文档描述了翻转屏设备的通信协议格式。所有通信采用JSON格式,包括从控制端到设备的请求和从设备到控制端的响应。
|
||||
|
||||
## 通信基本结构
|
||||
|
||||
### 请求格式(控制端 → 设备)
|
||||
```json
|
||||
{
|
||||
"board_id": 121, // 设备ID
|
||||
"JSON_id": 1, // 消息唯一标识
|
||||
"Flip-screen": { // 翻转屏指令
|
||||
"command_type": { // 具体命令类型
|
||||
// 命令参数
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应格式(设备 → 控制端)
|
||||
```json
|
||||
{
|
||||
"JSON_id": 1, // 与请求消息相同的标识
|
||||
"Flip-screen": { // 翻转屏响应
|
||||
"command_type": { // 与请求相同的命令类型
|
||||
"status": "success" // 操作状态: "success" 或 "failed"
|
||||
}
|
||||
},
|
||||
"error_code": 0 // 错误码,0表示成功
|
||||
}
|
||||
```
|
||||
|
||||
## 功能指令详解
|
||||
|
||||
### 1. 平台控制(上升/下降)
|
||||
|
||||
#### 请求:
|
||||
```json
|
||||
{
|
||||
"board_id": 121,
|
||||
"JSON_id": 2,
|
||||
"Flip-screen": {
|
||||
"platform_control": {
|
||||
"direction": "up" // 可选值: "up" 或 "down"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应:
|
||||
```json
|
||||
{
|
||||
"JSON_id": 2,
|
||||
"Flip-screen": {
|
||||
"platform_control": {
|
||||
"status": "success"
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 屏幕开关控制
|
||||
|
||||
#### 请求:
|
||||
```json
|
||||
{
|
||||
"board_id": 121,
|
||||
"JSON_id": 3,
|
||||
"Flip-screen": {
|
||||
"screen_control": {
|
||||
"power": "on" // 可选值: "on" 或 "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应:
|
||||
```json
|
||||
{
|
||||
"JSON_id": 3,
|
||||
"Flip-screen": {
|
||||
"screen_control": {
|
||||
"status": "success"
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 灯模式控制
|
||||
|
||||
#### 请求:
|
||||
```json
|
||||
{
|
||||
"board_id": 121,
|
||||
"JSON_id": 4,
|
||||
"Flip-screen": {
|
||||
"light_mode": {
|
||||
"mode": "auto" // 灯光模式: "auto", "manual", 等
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应:
|
||||
```json
|
||||
{
|
||||
"JSON_id": 4,
|
||||
"Flip-screen": {
|
||||
"light_mode": {
|
||||
"status": "success"
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 单个灯控制
|
||||
|
||||
#### 请求:
|
||||
```json
|
||||
{
|
||||
"board_id": 121,
|
||||
"JSON_id": 5,
|
||||
"Flip-screen": {
|
||||
"light_control": {
|
||||
"light_id": 1, // 灯ID编号: 1-6
|
||||
"state": "on" // 可选值: "on" 或 "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应:
|
||||
```json
|
||||
{
|
||||
"JSON_id": 5,
|
||||
"Flip-screen": {
|
||||
"light_control": {
|
||||
"status": "success"
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 亮度调节
|
||||
|
||||
#### 请求:
|
||||
```json
|
||||
{
|
||||
"board_id": 121,
|
||||
"JSON_id": 6,
|
||||
"Flip-screen": {
|
||||
"brightness_control": {
|
||||
"value": 70 // 亮度值: 0-100
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应:
|
||||
```json
|
||||
{
|
||||
"JSON_id": 6,
|
||||
"Flip-screen": {
|
||||
"brightness_control": {
|
||||
"status": "success"
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 节目控制
|
||||
|
||||
#### 请求:
|
||||
```json
|
||||
{
|
||||
"board_id": 121,
|
||||
"JSON_id": 7,
|
||||
"Flip-screen": {
|
||||
"program_control": {
|
||||
"program_id": 1 // 节目ID
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应:
|
||||
```json
|
||||
{
|
||||
"JSON_id": 7,
|
||||
"Flip-screen": {
|
||||
"program_control": {
|
||||
"status": "success"
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
当指令执行失败时,设备会返回非零的错误码和错误信息:
|
||||
|
||||
```json
|
||||
{
|
||||
"JSON_id": 3,
|
||||
"Flip-screen": {
|
||||
"screen_control": {
|
||||
"status": "failed"
|
||||
}
|
||||
},
|
||||
"error_code": 1001,
|
||||
"error_msg": "Device not responding"
|
||||
}
|
||||
```
|
||||
|
||||
## 错误码说明
|
||||
|
||||
| 错误码 | 描述 |
|
||||
|--------|------|
|
||||
| 0 | 成功 |
|
||||
| 1001 | 设备无响应 |
|
||||
| 1002 | 参数错误 |
|
||||
| 1003 | 设备忙 |
|
||||
| 1004 | 操作超时 |
|
||||
| 1005 | 设备未就绪 |
|
||||
|
||||
|
||||
## 设备状态查询
|
||||
|
||||
### 请求:
|
||||
```json
|
||||
{
|
||||
"board_id": 121,
|
||||
"JSON_id": 8,
|
||||
"Flip-screen": {
|
||||
"status_query": {
|
||||
"type": "all" // 查询类型: "all", "platform", "screen", "lights", "program"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应:
|
||||
```json
|
||||
{
|
||||
"JSON_id": 8,
|
||||
"Flip-screen": {
|
||||
"status": {
|
||||
"platform": {
|
||||
"position": "up" // "up" 或 "down"
|
||||
},
|
||||
"screen": {
|
||||
"power": "on", // "on" 或 "off"
|
||||
"brightness": 70 // 0-100
|
||||
},
|
||||
"lights": [
|
||||
{"id": 1, "state": "on", },
|
||||
{"id": 2, "state": "off",},
|
||||
{"id": 3, "state": "on", },
|
||||
{"id": 4, "state": "on", },
|
||||
{"id": 5, "state": "off",},
|
||||
{"id": 6, "state": "on", }
|
||||
],
|
||||
"program": {
|
||||
"current_id": 1,
|
||||
"available": [1, 2, 3, 4, 5]
|
||||
},
|
||||
"light_mode": "auto"
|
||||
}
|
||||
},
|
||||
"error_code": 0
|
||||
}
|
||||
```
|
1308
src/views/gateway/GatewaySetting.vue
Normal file
1308
src/views/gateway/GatewaySetting.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -16,9 +16,12 @@
|
||||
<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 size="large" class="custom-cell" title="小车控制" icon="car" is-link value="控制" @click="goto('CarControl')" />
|
||||
<van-cell size="large" class="custom-cell" title="小车控制" icon="car" is-link value="控制" @click="goto('TEST')" />
|
||||
<van-cell size="large" class="custom-cell" title="小车控制" icon="car" is-link value="控制" @click="goto('AudioPlay')" />
|
||||
<van-cell size="large" class="custom-cell" title="小车控制" icon="logistics" is-link value="控制" @click="goto('CarControl')" />
|
||||
<!-- <van-cell size="large" class="custom-cell" title="小车控制" icon="car" is-link value="控制" @click="goto('TEST')" /> -->
|
||||
<!-- <van-cell size="large" class="custom-cell" title="小车控制" icon="car" is-link value="控制" @click="goto('AudioPlay')" /> -->
|
||||
<van-cell size="large" class="custom-cell" title="网关设置" icon="desktop-o" is-link value="控制" @click="goto('GatewaySetting')" />
|
||||
<van-cell size="large" class="custom-cell" title="路锥控制" icon="warning-o" is-link value="控制" @click="goto('ConeControl')" />
|
||||
<van-cell size="large" class="custom-cell" title="翻转屏遥控" icon="warning-o" is-link value="控制" @click="goto('flipScreen')" />
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,6 +4,7 @@ const AutoImport = require('unplugin-auto-import/webpack');
|
||||
const Components = require('unplugin-vue-components/webpack');
|
||||
const { codeInspectorPlugin } = require('code-inspector-plugin');
|
||||
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
|
||||
const CompressionWebpackPlugin = require('compression-webpack-plugin');
|
||||
|
||||
module.exports = defineConfig({
|
||||
lintOnSave: false,
|
||||
@ -25,6 +26,7 @@ module.exports = defineConfig({
|
||||
devServer: {
|
||||
open: true,
|
||||
hot: true,//自动保存
|
||||
port:80
|
||||
},
|
||||
chainWebpack: (config) => {
|
||||
config.plugin('code-inspector-plugin').use(
|
||||
@ -44,7 +46,7 @@ module.exports = defineConfig({
|
||||
|
||||
}),
|
||||
Components.default({ resolvers: [VantResolver(),ElementPlusResolver()] }),
|
||||
// new CompressionPlugin({
|
||||
// new CompressionWebpackPlugin({
|
||||
// algorithm: 'gzip', // 使用gzip压缩
|
||||
// test: /\.js$|\.html$|\.css$/, // 匹配文件名
|
||||
// filename: '[path][base].gz[query]', // 压缩后的文件名(保持原文件名,后缀加.gz)
|
||||
|
Loading…
x
Reference in New Issue
Block a user