index.html 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. {% extends "base.html" %}
  2. {% block title %}展品灯座控制{% endblock %}
  3. {% block extra_styles %}
  4. @media (max-width: 768px) {
  5. .led-effect-actions {
  6. flex-direction: column !important;
  7. align-items: stretch !important;
  8. width: 100%;
  9. }
  10. .led-effect-actions .btn {
  11. width: 100%;
  12. }
  13. }
  14. {% endblock %}
  15. {% block content %}
  16. <div class="module-header">
  17. <h2>💡 展品灯座控制</h2>
  18. </div>
  19. <div class="sub-section">
  20. <!-- HA 设备控制 -->
  21. <h3 style="margin-bottom: 20px; color: #2c3e50; border-bottom: 2px solid #eee; padding-bottom: 10px;">其他灯座控制</h3>
  22. <!-- 展厅桌面的灯座总开关 -->
  23. <div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border: 1px solid #eee; margin-bottom: 15px;">
  24. <h4 style="margin-bottom: 15px; color: #555;">展厅桌面的灯座总开关</h4>
  25. <div class="control-row">
  26. <div class="control-group" style="display: flex; gap: 15px;">
  27. <button class="btn btn-secondary" style="flex: 1;" onclick="controlHALight('exhibition_desktop_switch', 'turn_on')">打开</button>
  28. <button class="btn" style="flex: 1; background-color: #34495e; color: white;" onclick="controlHALight('exhibition_desktop_switch', 'turn_off')">关闭</button>
  29. </div>
  30. </div>
  31. </div>
  32. <!-- 展厅桌面3D风扇投影 -->
  33. <div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border: 1px solid #eee; margin-bottom: 15px;">
  34. <h4 style="margin-bottom: 15px; color: #555;">展厅桌面3D风扇投影</h4>
  35. <div class="control-row">
  36. <div class="control-group" style="display: flex; gap: 15px;">
  37. <button class="btn btn-secondary" style="flex: 1;" onclick="controlHALight('exhibition_3d_fan', 'turn_on')">打开</button>
  38. <button class="btn" style="flex: 1; background-color: #34495e; color: white;" onclick="controlHALight('exhibition_3d_fan', 'turn_off')">关闭</button>
  39. </div>
  40. </div>
  41. </div>
  42. <!-- 展台桌子灯带 -->
  43. <div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border: 1px solid #eee; margin-bottom: 15px;">
  44. <h4 style="margin-bottom: 15px; color: #555;">展台桌子灯带</h4>
  45. <div class="control-row">
  46. <div class="control-group" style="display: flex; gap: 15px;">
  47. <button class="btn btn-secondary" style="flex: 1;" onclick="controlHALight('exhibition_stand_light_strip', 'turn_on')">打开</button>
  48. <button class="btn" style="flex: 1; background-color: #34495e; color: white;" onclick="controlHALight('exhibition_stand_light_strip', 'turn_off')">关闭</button>
  49. </div>
  50. </div>
  51. </div>
  52. <h3 style="margin-top: 30px; margin-bottom: 20px; color: #2c3e50; border-bottom: 2px solid #eee; padding-bottom: 10px;">展品灯带特效控制</h3>
  53. <div class="control-row">
  54. <div class="control-group">
  55. <label for="exhibitId">选择展品</label>
  56. <select id="exhibitId">
  57. {% if led_segments %}
  58. {% for segment in led_segments %}
  59. <option value="{{ segment.id }}">{{ segment.name }} (ID: {{ segment.id }})</option>
  60. {% endfor %}
  61. {% else %}
  62. <option value="0">未找到配置 (默认ID: 0)</option>
  63. {% endif %}
  64. </select>
  65. </div>
  66. <div class="control-group led-effect-actions" style="flex: 2; display: flex; align-items: flex-end; gap: 10px;">
  67. <button class="btn btn-primary" onclick="startEffect()">启动灯效</button>
  68. <button class="btn btn-secondary" onclick="stopEffect()">停止灯效</button>
  69. <button class="btn btn-warning" onclick="getStatus()">刷新状态</button>
  70. </div>
  71. </div>
  72. <div class="status-display" id="ledStatusDisplay">
  73. <div id="statusContent">点击"刷新状态"查看当前LED状态</div>
  74. </div>
  75. <div style="margin-top: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3; color: #0d47a1;">
  76. <p><strong>📖 灯效说明:</strong> 指定展品将显示白色呼吸灯效,其他展品保持静止。10秒后,所有展品将随机播放波浪、闪烁或呼吸效果。</p>
  77. </div>
  78. </div>
  79. {% endblock %}
  80. {% block scripts %}
  81. <script>
  82. let currentStatus = null;
  83. document.addEventListener('DOMContentLoaded', function() {
  84. getStatus();
  85. });
  86. async function getStatus() {
  87. try {
  88. const response = await fetch('/api/led/status');
  89. const result = await response.json();
  90. if (result.success) {
  91. currentStatus = result.data;
  92. document.getElementById('statusContent').innerHTML = `
  93. <p><strong>运行状态:</strong> ${currentStatus.is_running ? '运行中' : '已停止'}</p>
  94. <p><strong>信息:</strong> ${currentStatus.message}</p>
  95. `;
  96. } else {
  97. document.getElementById('statusContent').innerHTML = `<span style="color:red">获取失败: ${result.message}</span>`;
  98. }
  99. } catch (error) {
  100. console.error(error);
  101. document.getElementById('statusContent').innerHTML = `<span style="color:red">网络错误</span>`;
  102. }
  103. }
  104. async function startEffect() {
  105. const exhibitId = parseInt(document.getElementById('exhibitId').value);
  106. if (isNaN(exhibitId) || exhibitId < 0) {
  107. showMessage('请输入有效的展品ID', 'error');
  108. return;
  109. }
  110. try {
  111. showLoading(true);
  112. const response = await fetch('/api/led/start', {
  113. method: 'POST',
  114. headers: { 'Content-Type': 'application/json' },
  115. body: JSON.stringify({ exhibit_id: exhibitId })
  116. });
  117. const result = await response.json();
  118. if (result.success) {
  119. showMessage(result.message);
  120. getStatus();
  121. } else {
  122. showMessage(result.message, 'error');
  123. }
  124. } catch (error) {
  125. showMessage('网络错误: ' + error.message, 'error');
  126. } finally {
  127. showLoading(false);
  128. }
  129. }
  130. async function stopEffect() {
  131. try {
  132. showLoading(true);
  133. const response = await fetch('/api/led/stop', { method: 'POST', headers: { 'Content-Type': 'application/json' } });
  134. const result = await response.json();
  135. if (result.success) {
  136. showMessage(result.message);
  137. getStatus();
  138. } else {
  139. showMessage(result.message, 'error');
  140. }
  141. } catch (error) {
  142. showMessage('网络错误: ' + error.message, 'error');
  143. } finally {
  144. showLoading(false);
  145. }
  146. }
  147. async function controlHALight(device, action) {
  148. let url = '';
  149. if (device === 'all') {
  150. url = `/api/ha/${action}_all`;
  151. } else {
  152. url = `/api/ha/${device}/${action}`;
  153. }
  154. try {
  155. showLoading(true);
  156. const response = await fetch(url, {
  157. method: 'POST',
  158. headers: { 'Content-Type': 'application/json' }
  159. });
  160. const result = await response.json();
  161. if (result.success) {
  162. showMessage(result.message);
  163. } else {
  164. showMessage(result.message, 'error');
  165. }
  166. } catch (error) {
  167. showMessage('网络错误: ' + error.message, 'error');
  168. } finally {
  169. showLoading(false);
  170. }
  171. }
  172. </script>
  173. {% endblock %}