liuq 2 месяцев назад
Родитель
Сommit
7485498ceb
6 измененных файлов с 415 добавлено и 16 удалено
  1. 231 1
      templates/base.html
  2. 12 1
      templates/ha/index.html
  3. 54 1
      templates/kodi/index.html
  4. 15 1
      templates/led/index.html
  5. 12 5
      templates/login.html
  6. 91 7
      templates/self_check.html

+ 231 - 1
templates/base.html

@@ -247,6 +247,11 @@
             from { transform: translateX(100%); opacity: 0; }
             to { transform: translateX(0); opacity: 1; }
         }
+
+        @keyframes slideInMobile {
+            from { transform: translateY(120%); opacity: 0; }
+            to { transform: translateY(0); opacity: 1; }
+        }
         .msg-success { background-color: #4caf50; }
         .msg-error { background-color: #f44336; }
         
@@ -263,14 +268,177 @@
             flex-direction: column;
         }
 
+        /* —— 移动端顶栏与抽屉导航(默认隐藏,见媒体查询)—— */
+        .mobile-topbar {
+            display: none;
+            align-items: center;
+            gap: 12px;
+            padding: 10px 14px;
+            padding-left: max(14px, env(safe-area-inset-left, 0px));
+            padding-right: max(14px, env(safe-area-inset-right, 0px));
+            padding-top: max(10px, env(safe-area-inset-top, 0px));
+            background: #2c3e50;
+            color: #fff;
+            position: fixed;
+            top: 0;
+            left: 0;
+            right: 0;
+            z-index: 998;
+            min-height: 48px;
+            box-shadow: 0 2px 8px rgba(0,0,0,0.15);
+        }
+
+        .mobile-menu-btn {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            width: 44px;
+            height: 44px;
+            margin: -6px 0 -6px -8px;
+            padding: 0;
+            border: none;
+            border-radius: 8px;
+            background: rgba(255,255,255,0.12);
+            color: #fff;
+            font-size: 1.35rem;
+            line-height: 1;
+            cursor: pointer;
+            -webkit-tap-highlight-color: transparent;
+        }
+
+        .mobile-menu-btn:active {
+            background: rgba(255,255,255,0.22);
+        }
+
+        .mobile-topbar-title {
+            font-weight: 600;
+            font-size: 1.05rem;
+            flex: 1;
+            min-width: 0;
+            white-space: nowrap;
+            overflow: hidden;
+            text-overflow: ellipsis;
+        }
+
+        .sidebar-backdrop {
+            display: none;
+            position: fixed;
+            inset: 0;
+            background: rgba(0,0,0,0.45);
+            z-index: 999;
+            -webkit-tap-highlight-color: transparent;
+        }
+
+        .sidebar-backdrop.is-visible {
+            display: block;
+        }
+
+        body.nav-open {
+            overflow: hidden;
+            touch-action: none;
+        }
+
+        @media (max-width: 768px) {
+            .mobile-topbar {
+                display: flex;
+            }
+
+            .sidebar {
+                transform: translateX(-100%);
+                transition: transform 0.25s ease;
+                box-shadow: none;
+            }
+
+            .sidebar.sidebar-open {
+                transform: translateX(0);
+                box-shadow: 4px 0 24px rgba(0,0,0,0.25);
+            }
+
+            .main-content {
+                margin-left: 0;
+                width: 100%;
+                padding: 16px;
+                padding-bottom: max(16px, env(safe-area-inset-bottom, 0px));
+                padding-top: calc(56px + env(safe-area-inset-top, 0px));
+            }
+
+            .module-header {
+                flex-wrap: wrap;
+                gap: 8px;
+            }
+
+            .module-header h2 {
+                font-size: 1.35rem;
+            }
+
+            .sub-section {
+                padding: 16px;
+            }
+
+            .control-row {
+                flex-direction: column;
+                align-items: stretch;
+            }
+
+            .control-group {
+                min-width: 100%;
+                flex: 1 1 auto !important;
+            }
+
+            input[type="text"],
+            input[type="number"],
+            input[type="email"],
+            input[type="password"],
+            select,
+            textarea {
+                font-size: 16px;
+            }
+
+            .btn {
+                min-height: 44px;
+                padding: 12px 20px;
+            }
+
+            .nav-item {
+                min-height: 48px;
+                padding: 14px 22px;
+            }
+
+            .logout-btn {
+                min-height: 44px;
+                padding: 12px;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+            }
+
+            .message-box {
+                left: 12px;
+                right: 12px;
+                top: auto;
+                bottom: max(16px, env(safe-area-inset-bottom, 0px));
+                max-width: none;
+                padding: 14px 18px;
+                text-align: center;
+                animation-name: slideInMobile;
+            }
+        }
+
         /* 模块特定样式 */
         {% block extra_styles %}{% endblock %}
     </style>
 </head>
 <body>
 
+    <header class="mobile-topbar" id="mobileTopbar" aria-hidden="false">
+        <button type="button" class="mobile-menu-btn" id="mobileMenuBtn" aria-label="打开导航菜单" aria-expanded="false">☰</button>
+        <span class="mobile-topbar-title">展厅控制</span>
+    </header>
+
+    <div class="sidebar-backdrop" id="sidebarBackdrop" aria-hidden="true"></div>
+
     <!-- 侧边栏 -->
-    <div class="sidebar">
+    <div class="sidebar" id="sidebar">
         <div class="sidebar-header">
             <h1>展厅控制</h1>
             <p>Admin Dashboard</p>
@@ -330,6 +498,68 @@
         function showLoading(show = true) {
             document.getElementById('loadingOverlay').style.display = show ? 'flex' : 'none';
         }
+
+        (function () {
+            const mq = window.matchMedia('(max-width: 768px)');
+            const sidebar = document.getElementById('sidebar');
+            const backdrop = document.getElementById('sidebarBackdrop');
+            const menuBtn = document.getElementById('mobileMenuBtn');
+
+            function closeMobileNav() {
+                sidebar.classList.remove('sidebar-open');
+                backdrop.classList.remove('is-visible');
+                document.body.classList.remove('nav-open');
+                backdrop.setAttribute('aria-hidden', 'true');
+                if (menuBtn) {
+                    menuBtn.setAttribute('aria-expanded', 'false');
+                }
+            }
+
+            function openMobileNav() {
+                sidebar.classList.add('sidebar-open');
+                backdrop.classList.add('is-visible');
+                document.body.classList.add('nav-open');
+                backdrop.setAttribute('aria-hidden', 'false');
+                if (menuBtn) {
+                    menuBtn.setAttribute('aria-expanded', 'true');
+                }
+            }
+
+            function toggleMobileNav() {
+                if (sidebar.classList.contains('sidebar-open')) {
+                    closeMobileNav();
+                } else {
+                    openMobileNav();
+                }
+            }
+
+            if (menuBtn) {
+                menuBtn.addEventListener('click', toggleMobileNav);
+            }
+            if (backdrop) {
+                backdrop.addEventListener('click', closeMobileNav);
+            }
+
+            document.querySelectorAll('#sidebar .nav-item, #sidebar .logout-btn').forEach(function (el) {
+                el.addEventListener('click', function () {
+                    if (mq.matches) {
+                        closeMobileNav();
+                    }
+                });
+            });
+
+            window.addEventListener('resize', function () {
+                if (!mq.matches) {
+                    closeMobileNav();
+                }
+            });
+
+            document.addEventListener('keydown', function (e) {
+                if (e.key === 'Escape' && mq.matches) {
+                    closeMobileNav();
+                }
+            });
+        })();
     </script>
 
     {% block scripts %}

+ 12 - 1
templates/ha/index.html

@@ -2,6 +2,17 @@
 
 {% block title %}展厅灯光控制{% endblock %}
 
+{% block extra_styles %}
+    @media (max-width: 768px) {
+        .ha-ceiling-labels {
+            flex-wrap: wrap;
+            justify-content: space-between;
+            row-gap: 6px;
+            font-size: 11px;
+        }
+    }
+{% endblock %}
+
 {% block content %}
     <div class="module-header">
         <h2>💡 展厅灯光控制 (HA)</h2>
@@ -42,7 +53,7 @@
                            onchange="controlHALightLevel(this.value)"
                            oninput="document.getElementById('ceilingLightLevelVal').textContent = this.value">
                 </div>
-                <div style="display: flex; justify-content: space-between; font-size: 12px; color: #666; margin-top: 5px; padding: 0 5px;">
+                <div class="ha-ceiling-labels" style="display: flex; justify-content: space-between; font-size: 12px; color: #666; margin-top: 5px; padding: 0 5px;">
                     <span>0 (全关)</span>
                     <span>1 (单灯)</span>
                     <span>2 (双灯)</span>

+ 54 - 1
templates/kodi/index.html

@@ -77,6 +77,59 @@
         margin-bottom: 15px;
         border: 1px solid #eee;
     }
+
+    @media (max-width: 768px) {
+        .tv-grid {
+            justify-content: center;
+            gap: 12px;
+        }
+
+        .tv-card {
+            width: min(100%, 160px);
+        }
+
+        .modal {
+            align-items: flex-end;
+            padding: 0;
+        }
+
+        .modal-content {
+            width: 100%;
+            max-width: none;
+            border-radius: 16px 16px 0 0;
+            max-height: 90vh;
+            padding: 20px 18px 24px;
+            padding-bottom: max(24px, env(safe-area-inset-bottom, 0px));
+        }
+
+        .close-btn {
+            min-width: 44px;
+            min-height: 44px;
+            display: inline-flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 1.75rem;
+        }
+
+        .modal-title {
+            font-size: 1.15rem;
+        }
+
+        .status-display .btn {
+            min-height: 44px;
+            padding: 0 16px !important;
+            font-size: 14px !important;
+        }
+
+        .free-time-actions {
+            width: 100%;
+        }
+
+        .free-time-actions .btn {
+            flex: 1 1 auto;
+            min-width: min(100%, 140px);
+        }
+    }
 {% endblock %}
 
 {% block content %}
@@ -147,7 +200,7 @@
                     <strong>当前状态:</strong>
                     <span id="freeTimeStatusText" style="font-weight: bold; color: #666;">加载中...</span>
                 </div>
-                <div class="control-row" style="margin-bottom: 0; gap: 10px; flex: 0 0 auto;">
+                <div class="control-row free-time-actions" style="margin-bottom: 0; gap: 10px; flex: 0 0 auto;">
                     <button id="btnEnableFreeTime" class="btn btn-primary" onclick="controlFreeTimePlay('start')">开启功能</button>
                     <button id="btnDisableFreeTime" class="btn btn-secondary" style="background-color: #95a5a6; display: none;" onclick="controlFreeTimePlay('stop')">关闭功能</button>
                 </div>

+ 15 - 1
templates/led/index.html

@@ -2,6 +2,20 @@
 
 {% block title %}展品灯座控制{% endblock %}
 
+{% block extra_styles %}
+    @media (max-width: 768px) {
+        .led-effect-actions {
+            flex-direction: column !important;
+            align-items: stretch !important;
+            width: 100%;
+        }
+
+        .led-effect-actions .btn {
+            width: 100%;
+        }
+    }
+{% endblock %}
+
 {% block content %}
     <div class="module-header">
         <h2>💡 展品灯座控制</h2>
@@ -58,7 +72,7 @@
                     {% endif %}
                 </select>
             </div>
-            <div class="control-group" style="flex: 2; display: flex; align-items: flex-end; gap: 10px;">
+            <div class="control-group led-effect-actions" style="flex: 2; display: flex; align-items: flex-end; gap: 10px;">
                 <button class="btn btn-primary" onclick="startEffect()">启动灯效</button>
                 <button class="btn btn-secondary" onclick="stopEffect()">停止灯效</button>
                 <button class="btn btn-warning" onclick="getStatus()">刷新状态</button>

+ 12 - 5
templates/login.html

@@ -25,16 +25,18 @@
             font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
             background: var(--bg-gradient);
             min-height: 100vh;
+            min-height: 100dvh;
             display: flex;
             align-items: center;
             justify-content: center;
             color: var(--dark-text);
+            padding: max(16px, env(safe-area-inset-top, 0px)) max(16px, env(safe-area-inset-right, 0px)) max(16px, env(safe-area-inset-bottom, 0px)) max(16px, env(safe-area-inset-left, 0px));
         }
 
         .login-container {
             background: var(--card-bg);
             border-radius: 15px;
-            padding: 40px;
+            padding: clamp(20px, 5vw, 40px);
             width: 100%;
             max-width: 400px;
             box-shadow: 0 10px 25px rgba(0,0,0,0.1);
@@ -76,10 +78,11 @@
 
         input {
             width: 100%;
-            padding: 12px;
+            padding: 12px 14px;
             border: 1px solid #ddd;
             border-radius: 8px;
-            font-size: 15px;
+            font-size: 16px;
+            min-height: 44px;
             transition: border-color 0.3s;
         }
 
@@ -90,7 +93,8 @@
 
         .btn-submit {
             width: 100%;
-            padding: 12px;
+            padding: 14px;
+            min-height: 48px;
             background-color: var(--primary-color);
             color: white;
             border: none;
@@ -133,7 +137,9 @@
         .btn-sso {
             display: block;
             width: 100%;
-            padding: 12px;
+            padding: 14px;
+            min-height: 48px;
+            line-height: 1.2;
             margin-top: 10px;
             background-color: #3498db;
             color: white;
@@ -143,6 +149,7 @@
             font-size: 16px;
             font-weight: 600;
             transition: background-color 0.3s;
+            box-sizing: border-box;
         }
 
         .btn-sso:hover {

+ 91 - 7
templates/self_check.html

@@ -26,7 +26,7 @@
     </div>
 
     <div id="reportArea" style="display: none;">
-        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
+        <div class="report-header-row">
             <h3 style="color: #2c3e50; margin: 0;">📋 自检报告</h3>
             <span id="checkTime" style="color: #999; font-size: 0.9em;"></span>
         </div>
@@ -48,12 +48,12 @@
         </div>
 
         <!-- 邮件发送区域 -->
-        <div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border: 1px solid #eee; margin-bottom: 25px; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 15px;">
-            <div style="flex: 1; min-width: 250px;">
-                <label for="reportEmail" style="font-weight: bold; color: #555; margin-right: 10px;">📧 发送报告到邮箱:</label>
-                <input type="email" id="reportEmail" placeholder="留空则发送给默认接收者" style="padding: 8px; border: 1px solid #ddd; border-radius: 4px; width: 250px;">
+        <div class="report-email-row">
+            <div class="report-email-field">
+                <label for="reportEmail" class="report-email-label">📧 发送报告到邮箱:</label>
+                <input type="email" id="reportEmail" class="report-email-input" placeholder="留空则发送给默认接收者">
             </div>
-            <button class="btn btn-info" onclick="sendReport()">📤 发送报告</button>
+            <button type="button" class="btn btn-info report-email-send" onclick="sendReport()">📤 发送报告</button>
         </div>
 
         <!-- 详细结果 -->
@@ -111,6 +111,90 @@
     
     .status-online { color: #2ecc71; }
     .status-offline { color: #e74c3c; }
+
+    .report-header-row {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 20px;
+        flex-wrap: wrap;
+        gap: 10px;
+    }
+
+    .report-email-row {
+        background: #f8f9fa;
+        padding: 15px;
+        border-radius: 8px;
+        border: 1px solid #eee;
+        margin-bottom: 25px;
+        display: flex;
+        align-items: flex-end;
+        justify-content: space-between;
+        flex-wrap: wrap;
+        gap: 15px;
+    }
+
+    .report-email-field {
+        flex: 1;
+        min-width: min(100%, 220px);
+    }
+
+    .report-email-label {
+        display: block;
+        font-weight: bold;
+        color: #555;
+        margin-bottom: 8px;
+    }
+
+    .report-email-input {
+        width: 100%;
+        max-width: 400px;
+        padding: 10px 12px;
+        border: 1px solid #ddd;
+        border-radius: 8px;
+        box-sizing: border-box;
+    }
+
+    .report-email-send {
+        flex-shrink: 0;
+    }
+
+    @media (max-width: 768px) {
+        .report-header-row {
+            flex-direction: column;
+            align-items: flex-start;
+        }
+
+        .report-email-row {
+            flex-direction: column;
+            align-items: stretch;
+        }
+
+        .report-email-input {
+            max-width: none;
+        }
+
+        .report-email-send {
+            width: 100%;
+        }
+
+        .module-report-header {
+            flex-direction: column;
+            align-items: flex-start;
+            gap: 8px;
+        }
+
+        .device-item {
+            flex-direction: column;
+            align-items: flex-start;
+            gap: 10px;
+        }
+
+        .device-status {
+            align-self: stretch;
+            justify-content: flex-end;
+        }
+    }
 {% endblock %}
 
 {% block scripts %}
@@ -256,7 +340,7 @@
 
     async function sendReport() {
         const email = document.getElementById('reportEmail').value.trim();
-        const btn = document.querySelector('button[onclick="sendReport()"]');
+        const btn = document.querySelector('.report-email-send');
         
         try {
             btn.disabled = true;