|
|
@@ -59,6 +59,12 @@ const LIGHT_MODES = [
|
|
|
{key: 'off', label: 'Off'},
|
|
|
]
|
|
|
|
|
|
+const GPIO_OPTIONS = [
|
|
|
+ {value: 2, label: 'GPIO2'},
|
|
|
+ {value: 3, label: 'GPIO3'},
|
|
|
+ {value: 4, label: 'GPIO4'},
|
|
|
+]
|
|
|
+
|
|
|
const bleWifiForm = reactive({ssid: '', password: ''})
|
|
|
const bleMqttForm = reactive({
|
|
|
broker: '',
|
|
|
@@ -71,6 +77,7 @@ const bleMqttForm = reactive({
|
|
|
topicConfig: 'agent/status/config',
|
|
|
})
|
|
|
const blePinForm = reactive({red: 4, green: 3, yellow: 2})
|
|
|
+let blePendingAction: 'save' | 'restart' | null = null
|
|
|
|
|
|
const mqttWifiForm = reactive({ssid: '', password: ''})
|
|
|
const mqttMqttForm = reactive({
|
|
|
@@ -101,6 +108,17 @@ watch(bleConfig, (cfg) => {
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+watch(bleState, (state) => {
|
|
|
+ if (state === 'disconnected' && blePendingAction) {
|
|
|
+ if (blePendingAction === 'save') {
|
|
|
+ message.success('保存成功,请待设备启动成功后手动连接设备!')
|
|
|
+ } else if (blePendingAction === 'restart') {
|
|
|
+ message.success('重启成功,请待设备启动成功后手动连接设备!')
|
|
|
+ }
|
|
|
+ blePendingAction = null
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
watch(mqttConfig, (cfg) => {
|
|
|
if (cfg) {
|
|
|
mqttWifiForm.ssid = cfg.wifi_ssid || ''
|
|
|
@@ -134,18 +152,20 @@ async function handleBleSave() {
|
|
|
pin_yellow: blePinForm.yellow,
|
|
|
}
|
|
|
try {
|
|
|
+ blePendingAction = 'save'
|
|
|
await bleSaveConfig(cfg)
|
|
|
- message.success('配置已保存,设备将重启')
|
|
|
} catch {
|
|
|
+ blePendingAction = null
|
|
|
message.error('保存失败')
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async function handleBleRestart() {
|
|
|
try {
|
|
|
+ blePendingAction = 'restart'
|
|
|
await bleRestartDevice()
|
|
|
- message.success('重启指令已发送')
|
|
|
} catch {
|
|
|
+ blePendingAction = null
|
|
|
message.error('重启失败')
|
|
|
}
|
|
|
}
|
|
|
@@ -168,7 +188,7 @@ async function handleMqttSave() {
|
|
|
}
|
|
|
try {
|
|
|
await mqttSaveConfig(cfg)
|
|
|
- message.success('配置已保存并推送')
|
|
|
+ message.success('保存成功,请待设备启动成功后手动连接设备!')
|
|
|
} catch {
|
|
|
message.error('保存失败')
|
|
|
}
|
|
|
@@ -177,7 +197,7 @@ async function handleMqttSave() {
|
|
|
async function handleMqttRestart() {
|
|
|
try {
|
|
|
await mqttRestartDevice()
|
|
|
- message.success('重启指令已发送')
|
|
|
+ message.success('重启成功,请待设备启动成功后手动连接设备!')
|
|
|
} catch {
|
|
|
message.error('重启失败')
|
|
|
}
|
|
|
@@ -255,96 +275,114 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
<a-tag color="processing">{{ bleMode || '-' }}</a-tag>
|
|
|
</a-descriptions-item>
|
|
|
<a-descriptions-item label="通信">
|
|
|
- {{ bleConfig?.comm_mode === 1 ? 'MQTT' : 'BLE-only' }}
|
|
|
+ <a-tag v-if="bleConfig?.mqtt_broker" color="success">MQTT</a-tag>
|
|
|
+ <a-tag v-else color="warning">BLE-only</a-tag>
|
|
|
</a-descriptions-item>
|
|
|
</a-descriptions>
|
|
|
</a-card>
|
|
|
|
|
|
- <a-card class="section-card" size="small" title="灯效模式">
|
|
|
- <div :class="isMobile ? 'mode-grid-mobile' : 'mode-grid-desktop'">
|
|
|
- <a-button
|
|
|
- v-for="m in LIGHT_MODES"
|
|
|
- :key="m.key"
|
|
|
- :type="bleMode === m.key ? 'primary' : 'default'"
|
|
|
- class="mode-btn"
|
|
|
- @click="bleSetMode(m.key)"
|
|
|
- >
|
|
|
- {{ m.label }}
|
|
|
- </a-button>
|
|
|
- </div>
|
|
|
- </a-card>
|
|
|
-
|
|
|
- <a-card class="section-card" size="small" title="WiFi 配置">
|
|
|
- <a-form layout="vertical">
|
|
|
- <a-form-item label="SSID">
|
|
|
- <a-input v-model:value="bleWifiForm.ssid" placeholder="WiFi 名称"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="密码">
|
|
|
- <a-input-password v-model:value="bleWifiForm.password" placeholder="WiFi 密码"/>
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-card>
|
|
|
+ <a-row :gutter="8" class="equal-height-row">
|
|
|
+ <a-col :span="isMobile ? 24 : 14" class="equal-height-col">
|
|
|
+ <a-card class="section-card equal-height-card" size="small" title="灯效模式">
|
|
|
+ <div class="mode-grid">
|
|
|
+ <a-button
|
|
|
+ v-for="m in LIGHT_MODES"
|
|
|
+ :key="m.key"
|
|
|
+ :type="bleMode === m.key ? 'primary' : 'default'"
|
|
|
+ class="mode-btn"
|
|
|
+ @click="bleSetMode(m.key)"
|
|
|
+ >
|
|
|
+ {{ m.label }}
|
|
|
+ </a-button>
|
|
|
+ </div>
|
|
|
+ </a-card>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="isMobile ? 24 : 10" class="equal-height-col">
|
|
|
+ <a-card class="section-card equal-height-card" size="small" title="WiFi 配置">
|
|
|
+ <a-form layout="vertical">
|
|
|
+ <a-form-item label="SSID">
|
|
|
+ <a-input v-model:value="bleWifiForm.ssid" placeholder="WiFi 名称"/>
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="密码">
|
|
|
+ <a-input-password v-model:value="bleWifiForm.password" placeholder="WiFi 密码"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+ </a-card>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
|
|
|
<a-card class="section-card" size="small" title="MQTT 配置">
|
|
|
<a-form layout="vertical">
|
|
|
- <a-form-item label="Broker">
|
|
|
- <a-input v-model:value="bleMqttForm.broker" placeholder="192.168.1.100"/>
|
|
|
- </a-form-item>
|
|
|
<a-row :gutter="12">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="Broker">
|
|
|
+ <a-input v-model:value="bleMqttForm.broker" placeholder="192.168.1.100"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
<a-col :span="12">
|
|
|
<a-form-item label="端口">
|
|
|
<a-input-number v-model:value="bleMqttForm.port" :max="65535" :min="1" style="width: 100%"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
+ </a-row>
|
|
|
+ <a-row :gutter="12">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="订阅主题">
|
|
|
+ <a-input v-model:value="bleMqttForm.topic" placeholder="agent/status"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
<a-col :span="12">
|
|
|
<a-form-item label="Client ID">
|
|
|
<a-input v-model:value="bleMqttForm.client" placeholder="AI-Light"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
</a-row>
|
|
|
- <a-form-item label="用户名">
|
|
|
- <a-input v-model:value="bleMqttForm.username" placeholder="可选"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="密码">
|
|
|
- <a-input-password v-model:value="bleMqttForm.password" placeholder="可选"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="订阅主题">
|
|
|
- <a-input v-model:value="bleMqttForm.topic" placeholder="agent/status"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="状态发布主题">
|
|
|
- <a-input v-model:value="bleMqttForm.statusTopic" placeholder="openCodeLight/status"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="配置订阅主题">
|
|
|
- <a-input v-model:value="bleMqttForm.topicConfig" placeholder="agent/status/config"/>
|
|
|
- </a-form-item>
|
|
|
+ <a-row :gutter="12">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="用户名">
|
|
|
+ <a-input v-model:value="bleMqttForm.username" placeholder="可选"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="密码">
|
|
|
+ <a-input-password v-model:value="bleMqttForm.password" placeholder="可选"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ <a-row :gutter="12">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="状态发布主题">
|
|
|
+ <a-input v-model:value="bleMqttForm.statusTopic" placeholder="openCodeLight/status"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="配置订阅主题">
|
|
|
+ <a-input v-model:value="bleMqttForm.topicConfig" placeholder="agent/status/config"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
</a-form>
|
|
|
</a-card>
|
|
|
|
|
|
- <a-card class="section-card" size="small" title="引脚配置(灯序)">
|
|
|
+ <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-input-number v-model:value="blePinForm.red" :max="21" :min="0" style="width: 100%"/>
|
|
|
+ <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-input-number v-model:value="blePinForm.green" :max="21" :min="0" style="width: 100%"/>
|
|
|
+ <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-input-number v-model:value="blePinForm.yellow" :max="21" :min="0" style="width: 100%"/>
|
|
|
+ <a-select v-model:value="blePinForm.yellow" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
</a-row>
|
|
|
- <a-alert
|
|
|
- banner
|
|
|
- message="默认接线:红=IO4、绿=IO3、黄=IO2。修改引脚后需确认硬件接线对应。"
|
|
|
- show-icon
|
|
|
- type="info"
|
|
|
- />
|
|
|
</a-form>
|
|
|
</a-card>
|
|
|
|
|
|
@@ -383,7 +421,8 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
<a-tag color="processing">{{ bleMode || '-' }}</a-tag>
|
|
|
</a-descriptions-item>
|
|
|
<a-descriptions-item label="通信">
|
|
|
- {{ bleConfig?.comm_mode === 1 ? 'MQTT' : 'BLE-only' }}
|
|
|
+ <a-tag v-if="bleConfig?.mqtt_broker" color="success">MQTT</a-tag>
|
|
|
+ <a-tag v-else color="warning">BLE-only</a-tag>
|
|
|
</a-descriptions-item>
|
|
|
</a-descriptions>
|
|
|
</a-card>
|
|
|
@@ -462,95 +501,114 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
<a-descriptions-item label="模式">
|
|
|
<a-tag color="processing">{{ mqttMode || '-' }}</a-tag>
|
|
|
</a-descriptions-item>
|
|
|
- <a-descriptions-item label="通信">MQTT</a-descriptions-item>
|
|
|
+ <a-descriptions-item label="通信">
|
|
|
+ <a-tag color="success">MQTT</a-tag>
|
|
|
+ </a-descriptions-item>
|
|
|
</a-descriptions>
|
|
|
</a-card>
|
|
|
|
|
|
- <a-card class="section-card" size="small" title="灯效模式">
|
|
|
- <div :class="isMobile ? 'mode-grid-mobile' : 'mode-grid-desktop'">
|
|
|
- <a-button
|
|
|
- v-for="m in LIGHT_MODES"
|
|
|
- :key="m.key"
|
|
|
- :type="mqttMode === m.key ? 'primary' : 'default'"
|
|
|
- class="mode-btn"
|
|
|
- @click="mqttSetMode(m.key)"
|
|
|
- >
|
|
|
- {{ m.label }}
|
|
|
- </a-button>
|
|
|
- </div>
|
|
|
- </a-card>
|
|
|
-
|
|
|
- <a-card class="section-card" size="small" title="WiFi 配置">
|
|
|
- <a-form layout="vertical">
|
|
|
- <a-form-item label="SSID">
|
|
|
- <a-input v-model:value="mqttWifiForm.ssid" placeholder="WiFi 名称"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="密码">
|
|
|
- <a-input-password v-model:value="mqttWifiForm.password" placeholder="WiFi 密码"/>
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-card>
|
|
|
+ <a-row :gutter="8" class="equal-height-row">
|
|
|
+ <a-col :span="isMobile ? 24 : 14" class="equal-height-col">
|
|
|
+ <a-card class="section-card equal-height-card" size="small" title="灯效模式">
|
|
|
+ <div class="mode-grid">
|
|
|
+ <a-button
|
|
|
+ v-for="m in LIGHT_MODES"
|
|
|
+ :key="m.key"
|
|
|
+ :type="mqttMode === m.key ? 'primary' : 'default'"
|
|
|
+ class="mode-btn"
|
|
|
+ @click="mqttSetMode(m.key)"
|
|
|
+ >
|
|
|
+ {{ m.label }}
|
|
|
+ </a-button>
|
|
|
+ </div>
|
|
|
+ </a-card>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="isMobile ? 24 : 10" class="equal-height-col">
|
|
|
+ <a-card class="section-card equal-height-card" size="small" title="WiFi 配置">
|
|
|
+ <a-form layout="vertical">
|
|
|
+ <a-form-item label="SSID">
|
|
|
+ <a-input v-model:value="mqttWifiForm.ssid" placeholder="WiFi 名称"/>
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="密码">
|
|
|
+ <a-input-password v-model:value="mqttWifiForm.password" placeholder="WiFi 密码"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+ </a-card>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
|
|
|
<a-card class="section-card" size="small" title="MQTT 配置">
|
|
|
<a-form layout="vertical">
|
|
|
- <a-form-item label="Broker">
|
|
|
- <a-input v-model:value="mqttMqttForm.broker" placeholder="192.168.1.100"/>
|
|
|
- </a-form-item>
|
|
|
<a-row :gutter="12">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="Broker">
|
|
|
+ <a-input v-model:value="mqttMqttForm.broker" placeholder="192.168.1.100"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
<a-col :span="12">
|
|
|
<a-form-item label="端口">
|
|
|
<a-input-number v-model:value="mqttMqttForm.port" :max="65535" :min="1" style="width: 100%"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
+ </a-row>
|
|
|
+ <a-row :gutter="12">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="订阅主题">
|
|
|
+ <a-input v-model:value="mqttMqttForm.topic" placeholder="agent/status"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
<a-col :span="12">
|
|
|
<a-form-item label="Client ID">
|
|
|
<a-input v-model:value="mqttMqttForm.client" placeholder="AI-Light"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
</a-row>
|
|
|
- <a-form-item label="用户名">
|
|
|
- <a-input v-model:value="mqttMqttForm.username" placeholder="可选"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="密码">
|
|
|
- <a-input-password v-model:value="mqttMqttForm.password" placeholder="可选"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="订阅主题">
|
|
|
- <a-input v-model:value="mqttMqttForm.topic" placeholder="agent/status"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="状态发布主题">
|
|
|
- <a-input v-model:value="mqttMqttForm.statusTopic" placeholder="openCodeLight/status"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="配置订阅主题">
|
|
|
- <a-input v-model:value="mqttMqttForm.topicConfig" placeholder="agent/status/config"/>
|
|
|
- </a-form-item>
|
|
|
+ <a-row :gutter="12">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="用户名">
|
|
|
+ <a-input v-model:value="mqttMqttForm.username" placeholder="可选"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="密码">
|
|
|
+ <a-input-password v-model:value="mqttMqttForm.password" placeholder="可选"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ <a-row :gutter="12">
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="状态发布主题">
|
|
|
+ <a-input v-model:value="mqttMqttForm.statusTopic" placeholder="openCodeLight/status"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="12">
|
|
|
+ <a-form-item label="配置订阅主题">
|
|
|
+ <a-input v-model:value="mqttMqttForm.topicConfig" placeholder="agent/status/config"/>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
</a-form>
|
|
|
</a-card>
|
|
|
|
|
|
- <a-card class="section-card" size="small" title="引脚配置(灯序)">
|
|
|
+ <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-input-number v-model:value="mqttPinForm.red" :max="21" :min="0" style="width: 100%"/>
|
|
|
+ <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-input-number v-model:value="mqttPinForm.green" :max="21" :min="0" style="width: 100%"/>
|
|
|
+ <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-input-number v-model:value="mqttPinForm.yellow" :max="21" :min="0" style="width: 100%"/>
|
|
|
+ <a-select v-model:value="mqttPinForm.yellow" :options="GPIO_OPTIONS" style="width: 100%"/>
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
</a-row>
|
|
|
- <a-alert
|
|
|
- banner
|
|
|
- message="默认接线:红=IO4、绿=IO3、黄=IO2。修改引脚后需确认硬件接线对应。"
|
|
|
- show-icon
|
|
|
- type="info"
|
|
|
- />
|
|
|
</a-form>
|
|
|
</a-card>
|
|
|
|
|
|
@@ -591,7 +649,9 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
<a-descriptions-item label="模式">
|
|
|
<a-tag color="processing">{{ mqttMode || '-' }}</a-tag>
|
|
|
</a-descriptions-item>
|
|
|
- <a-descriptions-item label="通信">MQTT</a-descriptions-item>
|
|
|
+ <a-descriptions-item label="通信">
|
|
|
+ <a-tag color="success">MQTT</a-tag>
|
|
|
+ </a-descriptions-item>
|
|
|
</a-descriptions>
|
|
|
</a-card>
|
|
|
|
|
|
@@ -614,7 +674,7 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
-<style scoped>
|
|
|
+<style lang="scss" scoped>
|
|
|
.device-config-page {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
@@ -630,6 +690,19 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
|
+
|
|
|
+ :deep(.ant-card-head) {
|
|
|
+ min-height: 46px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.ant-card-body) {
|
|
|
+ height: calc(100% - 46px);
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.ant-form-item) {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.section-card {
|
|
|
@@ -637,13 +710,20 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
|
}
|
|
|
|
|
|
-.mode-grid-mobile {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(3, 1fr);
|
|
|
- gap: 8px;
|
|
|
+.equal-height-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: stretch;
|
|
|
+}
|
|
|
+
|
|
|
+.equal-height-col {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+
|
|
|
+.equal-height-card {
|
|
|
+ flex: 1;
|
|
|
}
|
|
|
|
|
|
-.mode-grid-desktop {
|
|
|
+.mode-grid {
|
|
|
display: grid;
|
|
|
grid-template-columns: repeat(3, 1fr);
|
|
|
gap: 8px;
|
|
|
@@ -660,9 +740,10 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
padding: 12px;
|
|
|
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
|
font-size: 11px;
|
|
|
+ line-height: 1.8;
|
|
|
flex: 1;
|
|
|
+ min-height: 0;
|
|
|
overflow-y: auto;
|
|
|
- line-height: 1.8;
|
|
|
}
|
|
|
|
|
|
.log-line {
|
|
|
@@ -680,11 +761,15 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
display: flex;
|
|
|
gap: 8px;
|
|
|
align-items: stretch;
|
|
|
+ height: calc(100% - 52px);
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.config-col {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
+ overflow-y: auto;
|
|
|
+ overflow-x: hidden;
|
|
|
}
|
|
|
|
|
|
.side-col {
|
|
|
@@ -692,28 +777,33 @@ onMounted(() => window.addEventListener('resize', onResize))
|
|
|
flex-shrink: 0;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
-}
|
|
|
-
|
|
|
-.log-card {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
-
|
|
|
-.log-card :deep(.ant-card-body) {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .log-card {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ margin-bottom: 0;
|
|
|
+ height: 0;
|
|
|
+
|
|
|
+ :deep(.ant-card-body) {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@media (max-width: 767px) {
|
|
|
- .mode-grid-mobile {
|
|
|
+ .mode-grid {
|
|
|
grid-template-columns: repeat(2, 1fr);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@media (min-width: 1200px) {
|
|
|
- .mode-grid-desktop {
|
|
|
+ .mode-grid {
|
|
|
grid-template-columns: repeat(3, 1fr);
|
|
|
}
|
|
|
}
|