383 lines
10 KiB
Vue
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> |