diff --git a/backend/app/routers.py b/backend/app/routers.py index e839428..8f3ef8c 100644 --- a/backend/app/routers.py +++ b/backend/app/routers.py @@ -347,9 +347,21 @@ async def ai_asr(file: UploadFile = File(...), format: str = "m4a"): # ==================== 展示控制(管理端 → MQTT) ==================== - -_VALID_DISPLAY_ACTIONS = {"navigate", "navigate_rel", "play", "pause", "next", "prev", - "alert", "show_card", "set_mode", "minimize"} +# 全部 MQTT 前端控制命令白名单(与 docs/mqtt-commands.md 保持一致) +_VALID_DISPLAY_ACTIONS = { + # 页面 + "navigate", "navigate_rel", + # 全局视觉 + "vision_set", + # AI 助手页 + "ai_input", "ai_preset", "ai_company", "ai_zone", + # 语音对话页 + "voice_start", "voice_stop", "voice_refresh", + # 媒体 + "play", "pause", "next", "prev", "set_mode", "play_target", + # 全局 + "alert", "show_card", "minimize", "settings_changed", "playlist_changed", +} @router.post("/api/display/command") diff --git a/backend/static/admin.css b/backend/static/admin.css index 4d66bc0..6bd0cee 100644 --- a/backend/static/admin.css +++ b/backend/static/admin.css @@ -1241,3 +1241,20 @@ button { font-family: "Poppins", "PingFang SC", sans-serif; cursor: pointer; tra overflow: hidden; text-overflow: ellipsis; } + +/* ============ 大屏控制(MQTT 指令)面板 ============ */ +.mqtt-group { margin: 10px 0 4px; } +.mqtt-group-title { + font-size: 12px; font-weight: 600; color: #5a6b8c; + margin-bottom: 6px; letter-spacing: 0.04em; +} +.mqtt-row { + display: flex; flex-wrap: wrap; gap: 6px; align-items: center; + margin-bottom: 6px; +} +.mqtt-input { + flex: 1; min-width: 180px; + padding: 6px 10px; border: 1px solid #d7e1f0; border-radius: 8px; + font-size: 13px; color: #1d2c44; outline: none; +} +.mqtt-input:focus { border-color: #2f6bff; } diff --git a/backend/static/admin.js b/backend/static/admin.js index eba9d69..d6a4191 100644 --- a/backend/static/admin.js +++ b/backend/static/admin.js @@ -99,8 +99,15 @@ /* ========================================================= 事件委托:页面切换 / 播放控制 / 媒体操作 ========================================================= */ + // 输入框回车提交 + document.addEventListener('keydown', function (e) { + if (e.key !== 'Enter') return; + if (e.target && e.target.id === 'mqttAiInput') { document.getElementById('mqttAiSend').click(); } + else if (e.target && e.target.id === 'mqttAlertText') { document.getElementById('mqttAlertSend').click(); } + }); + document.addEventListener('click', function (e) { - var btn = e.target.closest ? e.target.closest('[data-nav], [data-control], [data-action], .copy-btn, [data-preview]') : null; + var btn = e.target.closest ? e.target.closest('[data-nav], [data-mqtt], [data-control], [data-action], .copy-btn, [data-preview], #mqttAiSend, #mqttAlertSend') : null; if (!btn) return; e.stopPropagation(); @@ -118,6 +125,37 @@ return; } + // 大屏 MQTT 指令(data-mqtt 携带完整 {action, params} JSON) + if (btn.hasAttribute('data-mqtt')) { + var cmd = null; + try { cmd = JSON.parse(btn.getAttribute('data-mqtt')); } catch (err) { toast('指令 JSON 错误', 'error'); return; } + post('/api/display/command', cmd, function (d) { + toast(d && d.ok !== false ? '指令已发送:' + (cmd.action || '') : '发送失败(MQTT 未连接?)', + d && d.ok !== false ? 'ok' : 'error'); + }); + return; + } + + // AI 提问输入框 + if (btn.id === 'mqttAiSend') { + var text = (document.getElementById('mqttAiInput').value || '').trim(); + if (!text) { toast('请输入问题', 'error'); return; } + post('/api/display/command', { action: 'ai_input', params: { text: text } }, function () { + toast('已发送问题到大屏 AI 页'); + }); + return; + } + + // 通知输入框 + if (btn.id === 'mqttAlertSend') { + var alertText = (document.getElementById('mqttAlertText').value || '').trim(); + if (!alertText) { toast('请输入通知内容', 'error'); return; } + post('/api/display/command', { action: 'alert', params: { text: alertText } }, function () { + toast('通知已广播'); + }); + return; + } + // 页面切换 if (btn.hasAttribute('data-nav')) { var page = btn.getAttribute('data-nav'); diff --git a/backend/templates/admin.html b/backend/templates/admin.html index 7da49ae..f92ddf3 100644 --- a/backend/templates/admin.html +++ b/backend/templates/admin.html @@ -118,6 +118,84 @@ + +