This commit is contained in:
JayJiaJun 2025-03-13 09:58:38 +08:00
parent b752d013bb
commit f43f1d57ed
5 changed files with 250 additions and 84 deletions

View File

@ -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;

View File

@ -112,9 +112,9 @@ class GamepadController {
const axis9 = axes[9];
const roundedAxis9 = Math.round(axis9 * 100) / 100;
if (roundedAxis9 <= -0.9) {
this.directionAxis9 = 0;
} else if (roundedAxis9 >= 0.0 && roundedAxis9 <= 0.2) {
this.directionAxis9 = 1;
} else if (roundedAxis9 >= 0.0 && roundedAxis9 <= 0.2) {
this.directionAxis9 = 2;
// } else if (roundedAxis9 >= 0.6 && roundedAxis9 <= 0.8) {
// this.directionAxis9 = "左";
// } else if (roundedAxis9 >= -0.5 && roundedAxis9 <= -0.4) {

View File

@ -223,7 +223,8 @@ export default {
initWebSocket() {
try {
console.log('正在连接 WebSocket...');
this.ws = new WebSocket('ws://192.168.4.120/ws');
// 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');

View File

@ -1,13 +1,7 @@
<template>
<div class="gateway-setting">
<!-- 固定标题栏 -->
<van-nav-bar
title="事件列表"
left-arrow
@click-left="onClickLeft"
fixed
placeholder
/>
<van-nav-bar title="事件列表" left-arrow @click-left="onClickLeft" fixed placeholder />
<!-- 添加下拉刷新组件 -->
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
@ -33,14 +27,8 @@
<div class="info-title">网络参数</div>
<div class="info-row">
<span class="info-label">网络ID</span>
<van-field
v-model="networkId"
type="text"
input-align="right"
placeholder="请输入网络ID"
maxlength="6"
:formatter="value => value.replace(/[^0-9]/g, '')"
/>
<van-field v-model="networkId" type="text" input-align="right" placeholder="请输入网络ID" maxlength="6"
:formatter="value => value.replace(/[^0-9]/g, '')" />
</div>
<div class="info-row">
<span class="info-label">无线频段</span>
@ -72,7 +60,12 @@
<!-- 设备地址输入 -->
<van-cell-group inset>
<van-field v-model="deviceAddress" label="设备地址" placeholder="请输入设备地址" input-align="right" />
<van-field
v-model="deviceAddress"
label="设备地址"
placeholder="请输入设备地址"
input-align="right"
/>
<van-cell center title="事件开关">
<template #right-icon>
<van-switch v-model="eventEnabled" size="24" />
@ -109,8 +102,28 @@
<van-cell-group inset title="基础设置">
<van-field v-model="currentEvent.type" is-link readonly label="事件类型" placeholder="请选择事件类型"
input-align="right" @click="showTypePopup" />
<!-- 当选择"其他"时显示的输入框 -->
<van-field
v-if="currentEvent.type === '其他'"
v-model="customEventType"
label="自定义类型"
placeholder="请输入自定义事件类型"
input-align="right"
type="number"
/>
<van-field v-model="currentEvent.source" is-link readonly label="事件来源" placeholder="请选择事件来源"
input-align="right" @click="showSourcePopup" />
<!-- 当选择"其他"时显示的输入框 -->
<van-field
v-if="currentEvent.source === '其他'"
v-model="customEventSource"
label="自定义来源"
placeholder="请输入自定义事件来源"
input-align="right"
type="number"
/>
<van-field v-model="currentEvent.priority" is-link readonly label="优先级" placeholder="请选择优先级"
input-align="right" @click="showPriorityPopup" />
</van-cell-group>
@ -160,6 +173,42 @@
</template>
</van-cell>
</div>
<!-- 在输出设置部分添加自定义输入框 -->
<template v-if="output.type === '其他'">
<div class="output-settings">
<van-field
v-model="output.customTarget"
label="目标板卡号"
type="number"
input-align="right"
placeholder="请输入目标板卡号"
/>
<div class="custom-data-inputs">
<van-field
v-model="output.customData1"
label="数据1"
type="number"
input-align="right"
placeholder="请输入数据1"
/>
<van-field
v-model="output.customData2"
label="数据2"
type="number"
input-align="right"
placeholder="请输入数据2"
/>
<van-field
v-model="output.customData3"
label="数据3"
type="number"
input-align="right"
placeholder="请输入数据3"
/>
</div>
</div>
</template>
</template>
<template #right-icon>
<van-button size="small" type="danger" @click="removeOutput(index)">删除</van-button>
@ -223,7 +272,7 @@
</template>
<script>
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
import { ref, reactive, onMounted, onBeforeUnmount, watch } from 'vue';
// import { showConfirmDialog, showToast } from 'vant';
import { useRouter } from 'vue-router';
import axios from 'axios';
@ -313,20 +362,30 @@ export default {
const timeSourceTypes = [
{ text: '本台设备', value: 0x00 },
{ text: '任意设备(除本身外任意设备)', value: 0xfe },
{ text: '任意设备', value: 0xff }
{ text: '任意设备', value: 0xff },
{ text: '其他', value: 'other' }
];
const priorityLevels = [
{ text: '0', value: 0 },
{ text: '1', value: 1 },
{ text: '2', value: 2 }
{ text: '2', value: 2 },
{ text: '3', value: 3 },
{ text: '4', value: 4 },
{ text: '5', value: 5 },
{ text: '6', value: 6 },
{ text: '7', value: 7 },
{ text: '8', value: 8 },
{ text: '9', value: 9 },
{ text: '10', value: 10 },
];
const outputTypes = [
{ text: '显卡输出', value: 'display' },
{ text: '声卡输出', value: 'audio' },
{ text: '路锥输出', value: 'serial' },
{ text: '引脚模式', value: 'io' }
{ text: '引脚模式', value: 'io' },
{ text: '其他', value: 'other' }
];
const currentEvent = reactive({
@ -352,6 +411,10 @@ export default {
// WebSocket
const ws = ref(null);
// setup
const customEventType = ref('');
const customEventSource = ref('');
const onClickLeft = () => {
router.back();
};
@ -389,23 +452,29 @@ export default {
const onOutputConfirm = (value) => {
const outputType = value.selectedOptions[0].text;
const newOutput = {
const output = {
type: outputType,
...(outputType === '显卡输出' ? {
programNumber: '1',
duration: '60'
duration: '10'
} : {}),
...(outputType === '声卡输出' ? {
audioNumber: '1'
} : {}),
...(outputType === '路锥输出' ? {
lightMode: ''
lightMode: '常亮'
} : {}),
...(outputType === '引脚模式' ? {
pins: []
} : {}),
...(outputType === '其他' ? {
customTarget: '',
customData1: '0',
customData2: '0',
customData3: '0'
} : {})
};
currentEvent.outputs.push(newOutput);
currentEvent.outputs.push(output);
outputPickerVisible.value = false;
};
@ -425,29 +494,37 @@ export default {
};
const saveEvent = () => {
//
//
if (!currentEvent.type || !currentEvent.source || !currentEvent.priority || currentEvent.outputs.length === 0) {
showToast('请填写所有必填字段并至少添加一个输出');
return;
}
//
//
if (currentEvent.type === '其他' && !customEventType.value) {
showToast('请填写自定义事件类型');
return;
}
if (currentEvent.source === '其他' && !customEventSource.value) {
showToast('请填写自定义事件来源');
return;
}
const outputs = currentEvent.outputs.map(output => {
let target;
let target = 0;
let data = [0, 0, 0];
//
switch (output.type) {
case '显卡输出':
target = 101;
target = 102;
data = [
parseInt(output.programNumber) || 0,
parseInt(output.duration) || 0,
parseInt(output.duration) || 10,
0
];
break;
case '声卡输出':
target = 102;
target = 103;
data = [
parseInt(output.audioNumber) || 0,
0,
@ -455,7 +532,7 @@ export default {
];
break;
case '路锥输出':
target = 103;
target = 106;
data = [
lightModes.find(mode => mode.text === output.lightMode)?.value || 0,
0,
@ -463,48 +540,40 @@ export default {
];
break;
case '引脚模式':
target = 104;
target = 1;
const pinValue = output.pins.reduce((acc, pin) => acc | (1 << parseInt(pin)), 0);
data = [pinValue, 0, 0];
break;
case '其他':
target = parseInt(output.customTarget) || 0;
data = [
parseInt(output.customData1) || 0,
parseInt(output.customData2) || 0,
parseInt(output.customData3) || 0
];
break;
}
return {
target,
data
};
return { target, data };
});
// 使 index
const getNextAvailableIndex = () => {
const usedIndices = events.value.map(e => e.index).sort((a, b) => a - b);
let index = 0;
while (usedIndices.includes(index)) {
index++;
}
return index;
};
//
const eventConfig = {
"JSON_id": jsonId.value,
"board_id": 1,
"gateway": {
"trig_cfg": {
"event_en": eventEnabled.value ? 1 : 0,
"addr": parseInt(deviceAddress.value) || 0,
"operate": isEdit.value ? 2 : 1,
"event_group": [
{
"index": isEdit.value
? currentEvent.index
: getNextAvailableIndex(),
"event_id": parseInt(eventTypes.find(type => type.text === currentEvent.type)?.value) || 0,
"source": timeSourceTypes.find(source => source.text === currentEvent.source)?.value || 0,
"priority": parseInt(currentEvent.priority) || 0,
"output": outputs
}
]
board_id: 1,
JSON_id: jsonId.value,
gateway: {
trig_cfg: {
event_group: [{
index: events.value.length,
// ""使
event_id: currentEvent.type === '其他'
? parseInt(customEventType.value)
: parseInt(eventTypes.find(type => type.text === currentEvent.type)?.value || '0'),
source: currentEvent.source === '其他'
? parseInt(customEventSource.value)
: timeSourceTypes.find(source => source.text === currentEvent.source)?.value || 0,
priority: parseInt(currentEvent.priority),
output: outputs
}]
}
}
};
@ -804,26 +873,26 @@ export default {
//
switch (output.target) {
case 101: //
case 102: //
type = '显卡输出';
config = {
programNumber: output.data[0].toString(),
duration: output.data[1].toString()
};
break;
case 102: //
case 103: //
type = '声卡输出';
config = {
audioNumber: output.data[0].toString()
};
break;
case 103: //
case 106: //
type = '路锥输出';
config = {
lightMode: lightModes.find(mode => mode.value === output.data[0].toString())?.text || '常亮'
};
break;
case 104: //
case 1: //
type = '引脚模式';
const pinValue = output.data[0];
config = {
@ -877,11 +946,94 @@ export default {
}, 1000);
};
// setup
const sendDeviceAddressConfig = () => {
const configData = {
"board_id": 1,
"JSON_id": jsonId.value,
"gateway": {
"device_addr": deviceAddress.value
}
};
console.log('Sending device address config:', configData);
if (isLocal.value) {
axios.post('/communication', configData, {
headers: {
"content-type": "application/json"
}
})
.then(response => {
console.log('Device address config response:', response.data);
showToast('设备设置成功');
jsonId.value++;
})
.catch(error => {
console.error('Device address config error:', error);
showToast('设备设置失败');
jsonId.value++;
});
} else {
MQTT_send(configData);
}
};
const sendEventSwitchConfig = () => {
const configData = {
"board_id": 1,
"JSON_id": jsonId.value,
"gateway": {
"event_enable": eventEnabled.value ? 1 : 0
}
};
console.log('Sending event switch config:', configData);
if (isLocal.value) {
axios.post('/communication', configData, {
headers: {
"content-type": "application/json"
}
})
.then(response => {
console.log('Event switch config response:', response.data);
showToast('事件开关打开成功');
jsonId.value++;
})
.catch(error => {
console.error('Event switch config error:', error);
showToast('事件开关打开失败');
jsonId.value++;
});
} else {
MQTT_send(configData);
}
};
//
let deviceAddressTimeout;
watch(deviceAddress, (newValue, oldValue) => {
if (newValue && newValue !== oldValue) {
// 使 setTimeout
if (deviceAddressTimeout) {
clearTimeout(deviceAddressTimeout);
}
deviceAddressTimeout = setTimeout(() => {
sendDeviceAddressConfig();
}, 1000); // 1
}
});
//
watch(eventEnabled, () => {
sendEventSwitchConfig();
});
//
onMounted(() => {
checkEnvironment();
getLoRaConfig();
});
//
@ -1008,6 +1160,10 @@ export default {
firmwareVersionEl,
macAddressEl,
ws,
sendDeviceAddressConfig,
sendEventSwitchConfig,
customEventType,
customEventSource,
};
}
};
@ -1141,4 +1297,12 @@ export default {
min-height: 100vh;
background-color: #f7f8fa;
}
.custom-data-inputs {
margin-top: 8px;
}
.custom-data-inputs :deep(.van-field) {
margin-bottom: 8px;
}
</style>

View File

@ -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,
@ -44,7 +45,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)