|
|
@@ -1,5 +1,5 @@
|
|
|
<script lang="ts" setup>
|
|
|
-import {onMounted, reactive, ref, watch} from 'vue'
|
|
|
+import {computed, onMounted, reactive, ref, watch} from 'vue'
|
|
|
import {message} from 'ant-design-vue'
|
|
|
import {ClearOutlined, LoadingOutlined, ReloadOutlined, SaveOutlined,} from '@ant-design/icons-vue'
|
|
|
import {useBleDevice} from '@/composables/useBleDevice'
|
|
|
@@ -47,17 +47,68 @@ function onTabChange(key: string) {
|
|
|
activeTab.value = key
|
|
|
}
|
|
|
|
|
|
-const LIGHT_MODES = [
|
|
|
- {key: 'traffic', label: 'Traffic'},
|
|
|
- {key: 'thinking', label: 'Thinking'},
|
|
|
- {key: 'ai', label: 'AI'},
|
|
|
- {key: 'busy', label: 'Busy'},
|
|
|
- {key: 'success', label: 'Success'},
|
|
|
- {key: 'error', label: 'Error'},
|
|
|
- {key: 'alarm', label: 'Alarm'},
|
|
|
- {key: 'init', label: 'Init'},
|
|
|
- {key: 'off', label: 'Off'},
|
|
|
-]
|
|
|
+const DEVICE_CONFIGS: Record<string, {
|
|
|
+ modes: { key: string; label: string }[];
|
|
|
+ pins: { key: string; label: string }[]
|
|
|
+}> = {
|
|
|
+ 'AI-Beacon-Light': {
|
|
|
+ modes: [
|
|
|
+ {key: 'red', label: 'Red'},
|
|
|
+ {key: 'green', label: 'Green'},
|
|
|
+ {key: 'blue', label: 'Blue'},
|
|
|
+ {key: 'thinking', label: 'Thinking'},
|
|
|
+ {key: 'ai', label: 'AI'},
|
|
|
+ {key: 'busy', label: 'Busy'},
|
|
|
+ {key: 'success', label: 'Success'},
|
|
|
+ {key: 'error', label: 'Error'},
|
|
|
+ {key: 'alarm', label: 'Alarm'},
|
|
|
+ {key: 'init', label: 'Init'},
|
|
|
+ {key: 'off', label: 'Off'},
|
|
|
+ ],
|
|
|
+ pins: [
|
|
|
+ {key: 'red', label: '红灯引脚'},
|
|
|
+ {key: 'green', label: '绿灯引脚'},
|
|
|
+ {key: 'blue', label: '蓝灯引脚'},
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ 'AI-Traffic-Light': {
|
|
|
+ modes: [
|
|
|
+ {key: 'traffic', label: 'Traffic'},
|
|
|
+ {key: 'red', label: 'Red'},
|
|
|
+ {key: 'yellow', label: 'Yellow'},
|
|
|
+ {key: 'green', label: 'Green'},
|
|
|
+ {key: 'thinking', label: 'Thinking'},
|
|
|
+ {key: 'ai', label: 'AI'},
|
|
|
+ {key: 'busy', label: 'Busy'},
|
|
|
+ {key: 'success', label: 'Success'},
|
|
|
+ {key: 'error', label: 'Error'},
|
|
|
+ {key: 'alarm', label: 'Alarm'},
|
|
|
+ {key: 'init', label: 'Init'},
|
|
|
+ {key: 'off', label: 'Off'},
|
|
|
+ ],
|
|
|
+ pins: [
|
|
|
+ {key: 'red', label: '红灯引脚'},
|
|
|
+ {key: 'green', label: '绿灯引脚'},
|
|
|
+ {key: 'yellow', label: '黄灯引脚'},
|
|
|
+ ],
|
|
|
+ },
|
|
|
+}
|
|
|
+
|
|
|
+const DEFAULT_DEVICE = 'AI-Beacon-Light'
|
|
|
+
|
|
|
+function getDeviceType(name: string): string {
|
|
|
+ if (name.includes('Traffic')) return 'AI-Traffic-Light'
|
|
|
+ return 'AI-Beacon-Light'
|
|
|
+}
|
|
|
+
|
|
|
+const bleDeviceType = computed(() => getDeviceType(bleName.value))
|
|
|
+const mqttDeviceType = computed(() => getDeviceType(mqttName.value))
|
|
|
+
|
|
|
+const bleLightModes = computed(() => DEVICE_CONFIGS[bleDeviceType.value]?.modes || DEVICE_CONFIGS[DEFAULT_DEVICE].modes)
|
|
|
+const mqttLightModes = computed(() => DEVICE_CONFIGS[mqttDeviceType.value]?.modes || DEVICE_CONFIGS[DEFAULT_DEVICE].modes)
|
|
|
+
|
|
|
+const blePinConfig = computed(() => DEVICE_CONFIGS[bleDeviceType.value]?.pins || DEVICE_CONFIGS[DEFAULT_DEVICE].pins)
|
|
|
+const mqttPinConfig = computed(() => DEVICE_CONFIGS[mqttDeviceType.value]?.pins || DEVICE_CONFIGS[DEFAULT_DEVICE].pins)
|
|
|
|
|
|
const GPIO_OPTIONS = [
|
|
|
{value: 2, label: 'GPIO2'},
|
|
|
@@ -69,41 +120,42 @@ const bleWifiForm = reactive({ssid: '', password: ''})
|
|
|
const bleMqttForm = reactive({
|
|
|
broker: '',
|
|
|
port: 1883,
|
|
|
- client: 'AI-Light',
|
|
|
+ client: 'AI-Beacon-Light',
|
|
|
username: '',
|
|
|
password: '',
|
|
|
topic: 'agent/status',
|
|
|
statusTopic: 'openCodeLight/status',
|
|
|
topicConfig: 'agent/status/config',
|
|
|
})
|
|
|
-const blePinForm = reactive({red: 4, green: 3, yellow: 2})
|
|
|
+const blePinForm = reactive<Record<string, number>>({red: 4, green: 3, blue: 2, yellow: 2})
|
|
|
let blePendingAction: 'save' | 'restart' | null = null
|
|
|
|
|
|
const mqttWifiForm = reactive({ssid: '', password: ''})
|
|
|
const mqttMqttForm = reactive({
|
|
|
broker: '',
|
|
|
port: 1883,
|
|
|
- client: 'AI-Light',
|
|
|
+ client: 'AI-Beacon-Light',
|
|
|
username: '',
|
|
|
password: '',
|
|
|
topic: 'agent/status',
|
|
|
statusTopic: 'openCodeLight/status',
|
|
|
topicConfig: 'agent/status/config',
|
|
|
})
|
|
|
-const mqttPinForm = reactive({red: 4, green: 3, yellow: 2})
|
|
|
+const mqttPinForm = reactive<Record<string, number>>({red: 4, green: 3, blue: 2, yellow: 2})
|
|
|
|
|
|
watch(bleConfig, (cfg) => {
|
|
|
if (cfg) {
|
|
|
bleWifiForm.ssid = cfg.wifi_ssid || ''
|
|
|
bleMqttForm.broker = cfg.mqtt_broker || ''
|
|
|
bleMqttForm.port = cfg.mqtt_port || 1883
|
|
|
- bleMqttForm.client = cfg.mqtt_client || 'AI-Light'
|
|
|
+ bleMqttForm.client = cfg.mqtt_client || 'AI-Beacon-Light'
|
|
|
bleMqttForm.username = cfg.mqtt_user || ''
|
|
|
bleMqttForm.topic = cfg.mqtt_topic || ''
|
|
|
bleMqttForm.statusTopic = cfg.mqtt_status || ''
|
|
|
bleMqttForm.topicConfig = cfg.mqtt_topic_config || 'agent/status/config'
|
|
|
blePinForm.red = cfg.pin_red ?? 4
|
|
|
blePinForm.green = cfg.pin_green ?? 3
|
|
|
+ blePinForm.blue = cfg.pin_blue ?? 2
|
|
|
blePinForm.yellow = cfg.pin_yellow ?? 2
|
|
|
}
|
|
|
})
|
|
|
@@ -124,19 +176,20 @@ watch(mqttConfig, (cfg) => {
|
|
|
mqttWifiForm.ssid = cfg.wifi_ssid || ''
|
|
|
mqttMqttForm.broker = cfg.mqtt_broker || ''
|
|
|
mqttMqttForm.port = cfg.mqtt_port || 1883
|
|
|
- mqttMqttForm.client = cfg.mqtt_client || 'AI-Light'
|
|
|
+ mqttMqttForm.client = cfg.mqtt_client || 'AI-Beacon-Light'
|
|
|
mqttMqttForm.username = cfg.mqtt_user || ''
|
|
|
mqttMqttForm.topic = cfg.mqtt_topic || ''
|
|
|
mqttMqttForm.statusTopic = cfg.mqtt_status || ''
|
|
|
mqttMqttForm.topicConfig = cfg.config_topic || 'agent/status/config'
|
|
|
mqttPinForm.red = cfg.pin_red ?? 4
|
|
|
mqttPinForm.green = cfg.pin_green ?? 3
|
|
|
+ mqttPinForm.blue = cfg.pin_blue ?? 2
|
|
|
mqttPinForm.yellow = cfg.pin_yellow ?? 2
|
|
|
}
|
|
|
})
|
|
|
|
|
|
async function handleBleSave() {
|
|
|
- const cfg = {
|
|
|
+ const cfg: Record<string, any> = {
|
|
|
wifi_ssid: bleWifiForm.ssid,
|
|
|
wifi_pass: bleWifiForm.password,
|
|
|
mqtt_broker: bleMqttForm.broker,
|
|
|
@@ -149,7 +202,11 @@ async function handleBleSave() {
|
|
|
mqtt_topic_config: bleMqttForm.topicConfig,
|
|
|
pin_red: blePinForm.red,
|
|
|
pin_green: blePinForm.green,
|
|
|
- pin_yellow: blePinForm.yellow,
|
|
|
+ }
|
|
|
+ if (bleDeviceType.value === 'AI-Beacon-Light') {
|
|
|
+ cfg.pin_blue = blePinForm.blue
|
|
|
+ } else {
|
|
|
+ cfg.pin_yellow = blePinForm.yellow
|
|
|
}
|
|
|
try {
|
|
|
blePendingAction = 'save'
|
|
|
@@ -171,7 +228,7 @@ async function handleBleRestart() {
|
|
|
}
|
|
|
|
|
|
async function handleMqttSave() {
|
|
|
- const cfg = {
|
|
|
+ const cfg: Record<string, any> = {
|
|
|
wifi_ssid: mqttWifiForm.ssid,
|
|
|
wifi_pass: mqttWifiForm.password,
|
|
|
mqtt_broker: mqttMqttForm.broker,
|
|
|
@@ -184,7 +241,11 @@ async function handleMqttSave() {
|
|
|
mqtt_topic_config: mqttMqttForm.topicConfig,
|
|
|
pin_red: mqttPinForm.red,
|
|
|
pin_green: mqttPinForm.green,
|
|
|
- pin_yellow: mqttPinForm.yellow,
|
|
|
+ }
|
|
|
+ if (mqttDeviceType.value === 'AI-Beacon-Light') {
|
|
|
+ cfg.pin_blue = mqttPinForm.blue
|
|
|
+ } else {
|
|
|
+ cfg.pin_yellow = mqttPinForm.yellow
|
|
|
}
|
|
|
try {
|
|
|
await mqttSaveConfig(cfg)
|
|
|
@@ -285,7 +346,7 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
<a-card class="section-card equal-height-card" size="small" title="灯效模式">
|
|
|
<div class="mode-grid">
|
|
|
<a-button
|
|
|
- v-for="m in LIGHT_MODES"
|
|
|
+ v-for="m in bleLightModes"
|
|
|
:key="m.key"
|
|
|
:type="bleMode === m.key ? 'primary' : 'default'"
|
|
|
class="mode-btn"
|
|
|
@@ -332,7 +393,7 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
</a-col>
|
|
|
<a-col :span="12">
|
|
|
<a-form-item label="客户端ID">
|
|
|
- <a-input v-model:value="bleMqttForm.client" placeholder="AI-Light"/>
|
|
|
+ <a-input v-model:value="bleMqttForm.client" placeholder="AI-Beacon-Light"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
</a-row>
|
|
|
@@ -366,19 +427,9 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
<a-card class="section-card" size="small" title="灯序配置">
|
|
|
<a-form layout="vertical">
|
|
|
<a-row :gutter="12">
|
|
|
- <a-col :span="8">
|
|
|
- <a-form-item label="红灯引脚">
|
|
|
- <a-select v-model:value="blePinForm.red" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="8">
|
|
|
- <a-form-item label="绿灯引脚">
|
|
|
- <a-select v-model:value="blePinForm.green" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="8">
|
|
|
- <a-form-item label="黄灯引脚">
|
|
|
- <a-select v-model:value="blePinForm.yellow" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
+ <a-col v-for="pin in blePinConfig" :key="pin.key" :span="8">
|
|
|
+ <a-form-item :label="pin.label">
|
|
|
+ <a-select v-model:value="blePinForm[pin.key]" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
</a-row>
|
|
|
@@ -511,7 +562,7 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
<a-card class="section-card equal-height-card" size="small" title="灯效模式">
|
|
|
<div class="mode-grid">
|
|
|
<a-button
|
|
|
- v-for="m in LIGHT_MODES"
|
|
|
+ v-for="m in mqttLightModes"
|
|
|
:key="m.key"
|
|
|
:type="mqttMode === m.key ? 'primary' : 'default'"
|
|
|
class="mode-btn"
|
|
|
@@ -558,7 +609,7 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
</a-col>
|
|
|
<a-col :span="12">
|
|
|
<a-form-item label="客户端ID">
|
|
|
- <a-input v-model:value="mqttMqttForm.client" placeholder="AI-Light"/>
|
|
|
+ <a-input v-model:value="mqttMqttForm.client" placeholder="AI-Beacon-Light"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
</a-row>
|
|
|
@@ -592,19 +643,9 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
<a-card class="section-card" size="small" title="灯序配置">
|
|
|
<a-form layout="vertical">
|
|
|
<a-row :gutter="12">
|
|
|
- <a-col :span="8">
|
|
|
- <a-form-item label="红灯引脚">
|
|
|
- <a-select v-model:value="mqttPinForm.red" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="8">
|
|
|
- <a-form-item label="绿灯引脚">
|
|
|
- <a-select v-model:value="mqttPinForm.green" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="8">
|
|
|
- <a-form-item label="黄灯引脚">
|
|
|
- <a-select v-model:value="mqttPinForm.yellow" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
+ <a-col v-for="pin in mqttPinConfig" :key="pin.key" :span="8">
|
|
|
+ <a-form-item :label="pin.label">
|
|
|
+ <a-select v-model:value="mqttPinForm[pin.key]" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
</a-row>
|