GateWay/src/views/ConeControl.vue
2025-03-06 15:10:00 +08:00

383 lines
10 KiB
Vue

<template>
<div class="cone-control">
<van-nav-bar title="路锥控制" left-arrow @click-left="onClickLeft" fixed placeholder />
<!-- 为模组概况添加边框 -->
<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"></span>
</div>
<div class="info-row">
<span class="info-label">MAC地址</span>
<span class="info-value" ref="macAddressEl"></span>
</div>
<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, '')" />
</div>
<div class="info-row">
<span class="info-label">无线频段</span>
<van-field v-model="freqBand" is-link readonly input-align="right" placeholder="请选择频段"
@click="showFreqBandPopup" />
</div>
<div class="info-row">
<span class="info-label">信道</span>
<van-field v-model="channel" is-link readonly input-align="right" placeholder="请选择信道"
@click="showChannelPopup" />
</div>
<div class="info-row">
<span class="info-label">速率(SF)</span>
<van-field v-model="speedRate" is-link readonly input-align="right" placeholder="请选择速率"
@click="showSpeedRatePopup" />
</div>
<div class="info-row">
<span class="info-label">功率</span>
<van-field v-model="power" is-link readonly input-align="right" placeholder="请选择功率"
@click="showPowerPopup" />
</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="command-container">
<div class="command-header">
<van-icon name="apps-o" size="18" />
<span>控制面板</span>
</div>
<div class="command-grid">
<div class="command-item" @click="sendCommand('command1')">
<div class="command-icon">
<van-icon name="play-circle-o" size="24" />
</div>
<div class="command-text">启动路锥</div>
</div>
<div class="command-item" @click="sendCommand('command2')">
<div class="command-icon">
<van-icon name="pause-circle-o" size="24" />
</div>
<div class="command-text">停止路锥</div>
</div>
<div class="command-item" @click="sendCommand('command3')">
<div class="command-icon">
<van-icon name="setting-o" size="24" />
</div>
<div class="command-text">设置模式</div>
</div>
<div class="command-item" @click="sendCommand('command4')">
<div class="command-icon">
<van-icon name="warning-o" size="24" />
</div>
<div class="command-text">紧急停止</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref, reactive, onMounted, onBeforeUnmount } 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 isLocal = ref(true); // 用于判断是否为本地模式
const onClickLeft = () => {
router.back();
};
const showFreqBandPopup = () => {
// 显示频段选择器
};
const showChannelPopup = () => {
// 显示信道选择器
};
const showSpeedRatePopup = () => {
// 显示速率选择器
};
const showPowerPopup = () => {
// 显示功率选择器
};
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 sendCommand = (command) => {
// 发送指令逻辑
showToast(`发送${command}`);
};
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": 1,
"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 MQTT_recv = (string) => {
loading.value = false;
console.log("MQTT 接收的json:" + string);
parseAndFillData(JSON.parse(string));
// showToast('刷新成功');
console.log('Received message:', string);
};
onMounted(() => {
checkEnvironment();
window.MQTT_recv = MQTT_recv;
});
// 组件卸载前断开连接
onBeforeUnmount(() => {
});
return {
networkId,
freqBand,
channel,
speedRate,
power,
firmwareVersionEl,
macAddressEl,
onClickLeft,
showFreqBandPopup,
showChannelPopup,
showSpeedRatePopup,
showPowerPopup,
uploadLoRaConfig,
sendCommand,
uploadLoRaConfig,
checkEnvironment
};
}
};
</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;
}
.command-container {
margin: 16px;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(100, 101, 102, 0.08);
overflow: hidden;
}
.command-header {
padding: 16px;
font-size: 16px;
font-weight: 500;
color: #323233;
border-bottom: 1px solid #f5f5f5;
display: flex;
align-items: center;
gap: 8px;
}
.command-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
padding: 16px;
}
.command-item {
background: #f7f8fa;
border-radius: 8px;
padding: 16px;
text-align: center;
transition: all 0.3s;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.command-item:active {
background: #e8e8e8;
transform: scale(0.98);
}
.command-icon {
color: #1989fa;
margin-bottom: 4px;
}
.command-text {
font-size: 14px;
color: #323233;
}
.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;
}
</style>