mirror of
https://github.com/hanxi/xiaomusic.git
synced 2026-05-20 11:15:46 +08:00
增加手动获取设备列表以及高级配置改为Tab结构 (#753)
* Update setting.css 高级设置改为tab结构,减少滚动 * Update setting.html 高级设置改为tab结构,减少滚动 * Update setting.js 高级设置改为tab结构,减少滚动; 扫码登录改为jQuery * 修改获取所有设备接口 * 增加手动获取设备 * 获取设备列表 * fix:缺少导入 * fix * 修改二维码图标 * 二维码登录tab兼容手机版页面 * fix:生成二维码在手机端溢出显示 * 增加返回二维码超时时间 * 页面增加二维码超时倒计时
This commit is contained in:
@@ -24,8 +24,7 @@ router = APIRouter(dependencies=[Depends(verification)])
|
|||||||
@router.get("/device_list")
|
@router.get("/device_list")
|
||||||
async def device_list():
|
async def device_list():
|
||||||
"""获取设备列表"""
|
"""获取设备列表"""
|
||||||
await xiaomusic.auth_manager.init_all_data()
|
devices = await xiaomusic.getalldevices()
|
||||||
devices = await xiaomusic.auth_manager.try_update_device_id()
|
|
||||||
return {"devices": devices}
|
return {"devices": devices}
|
||||||
|
|
||||||
@router.get("/getvolume")
|
@router.get("/getvolume")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""系统管理路由"""
|
"""系统管理路由"""
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
@@ -44,7 +44,7 @@ from xiaomusic.utils.system_utils import (
|
|||||||
restart_xiaomusic,
|
restart_xiaomusic,
|
||||||
update_version,
|
update_version,
|
||||||
)
|
)
|
||||||
|
from xiaomusic.qrcode_login import MiJiaAPI
|
||||||
router = APIRouter(dependencies=[Depends(verification)])
|
router = APIRouter(dependencies=[Depends(verification)])
|
||||||
auth_data_path = config.conf_path if config.conf_path else None
|
auth_data_path = config.conf_path if config.conf_path else None
|
||||||
mi_jia_api = MiJiaAPI(auth_data_path=auth_data_path)
|
mi_jia_api = MiJiaAPI(auth_data_path=auth_data_path)
|
||||||
@@ -92,6 +92,7 @@ async def get_qrcode():
|
|||||||
"success": True,
|
"success": True,
|
||||||
"qrcode_url": qrcode_url,
|
"qrcode_url": qrcode_url,
|
||||||
"status_url": qrcode_data.get("lp", ""),
|
"status_url": qrcode_data.get("lp", ""),
|
||||||
|
"expire_seconds": config.qrcode_timeout,
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception("get_qrcode failed: %s", e)
|
log.exception("get_qrcode failed: %s", e)
|
||||||
|
|||||||
188
xiaomusic/static/default/setting.css
vendored
188
xiaomusic/static/default/setting.css
vendored
@@ -21,6 +21,7 @@
|
|||||||
word-wrap: normal;
|
word-wrap: normal;
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
-webkit-font-feature-settings: 'liga';
|
-webkit-font-feature-settings: 'liga';
|
||||||
|
font-feature-settings: 'liga';
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
@@ -209,19 +210,19 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表单元素样式 */
|
/* 表单元素样式(.setting-panel 统一基础设置与高级 Tab 内表单样式) */
|
||||||
.setting-card label {
|
.setting-panel label {
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #555;
|
color: #555;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-card input[type="text"],
|
.setting-panel input[type="text"],
|
||||||
.setting-card input[type="password"],
|
.setting-panel input[type="password"],
|
||||||
.setting-card input[type="number"],
|
.setting-panel input[type="number"],
|
||||||
.setting-card select,
|
.setting-panel select,
|
||||||
.setting-card textarea {
|
.setting-panel textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
@@ -234,24 +235,24 @@ body {
|
|||||||
box-shadow 0.2s ease;
|
box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-card input[type="text"]:focus,
|
.setting-panel input[type="text"]:focus,
|
||||||
.setting-card input[type="password"]:focus,
|
.setting-panel input[type="password"]:focus,
|
||||||
.setting-card input[type="number"]:focus,
|
.setting-panel input[type="number"]:focus,
|
||||||
.setting-card select:focus,
|
.setting-panel select:focus,
|
||||||
.setting-card textarea:focus {
|
.setting-panel textarea:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #007bff;
|
border-color: #007bff;
|
||||||
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
|
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-card textarea {
|
.setting-panel textarea {
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 按钮样式 */
|
/* 按钮样式(面板内按钮与 header/footer 统一) */
|
||||||
.setting-card button,
|
.setting-panel button,
|
||||||
.header-buttons button,
|
.header-buttons button,
|
||||||
.setting-footer button {
|
.setting-footer button {
|
||||||
background-color: #007bff;
|
background-color: #007bff;
|
||||||
@@ -271,20 +272,20 @@ body {
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-card button:hover,
|
.setting-panel button:hover,
|
||||||
.header-buttons button:hover,
|
.header-buttons button:hover,
|
||||||
.setting-footer button:hover {
|
.setting-footer button:hover {
|
||||||
background-color: #0056b3;
|
background-color: #0056b3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-card button:active,
|
.setting-panel button:active,
|
||||||
.header-buttons button:active,
|
.header-buttons button:active,
|
||||||
.setting-footer button:active {
|
.setting-footer button:active {
|
||||||
transform: translateY(1px);
|
transform: translateY(1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 小按钮样式 */
|
/* 小按钮样式 */
|
||||||
.setting-card button.mini-button,
|
.setting-panel button.mini-button,
|
||||||
button.mini-button {
|
button.mini-button {
|
||||||
padding: 4px 10px !important;
|
padding: 4px 10px !important;
|
||||||
font-size: 12px !important;
|
font-size: 12px !important;
|
||||||
@@ -298,14 +299,14 @@ button.mini-button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.setting-card button,
|
.setting-panel button,
|
||||||
.header-buttons button,
|
.header-buttons button,
|
||||||
.setting-footer button {
|
.setting-footer button {
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
min-height: 44px;
|
min-height: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-card button.mini-button,
|
.setting-panel button.mini-button,
|
||||||
button.mini-button {
|
button.mini-button {
|
||||||
padding: 8px 12px !important;
|
padding: 8px 12px !important;
|
||||||
font-size: 13px !important;
|
font-size: 13px !important;
|
||||||
@@ -318,6 +319,11 @@ button.mini-button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 设备选择区域 */
|
/* 设备选择区域 */
|
||||||
|
#refresh-device-list {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.device-selection {
|
.device-selection {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -480,6 +486,11 @@ button.mini-button {
|
|||||||
/* 添加图标支持 */
|
/* 添加图标支持 */
|
||||||
.auth-tab-button .material-icons {
|
.auth-tab-button .material-icons {
|
||||||
font-size: 18px !important;
|
font-size: 18px !important;
|
||||||
|
width: 20px;
|
||||||
|
min-width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-tab-panels {
|
.auth-tab-panels {
|
||||||
@@ -495,6 +506,31 @@ button.mini-button {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 二维码登录:未点击获取前不显示图片 */
|
||||||
|
#qrcode-container .qrcode-image-hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode-image {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin: 8px 0 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode-status {
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@keyframes fadeInUp {
|
@keyframes fadeInUp {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -509,18 +545,110 @@ button.mini-button {
|
|||||||
/* 移动端适配 */
|
/* 移动端适配 */
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.auth-tabs {
|
.auth-tabs {
|
||||||
gap: 8px;
|
flex-direction: column;
|
||||||
padding: 4px;
|
gap: 6px;
|
||||||
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-tab-button {
|
.auth-tab-button {
|
||||||
padding: 12px 12px !important;
|
width: 100%;
|
||||||
|
display: grid !important;
|
||||||
|
grid-template-columns: 18px minmax(0, 1fr);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: initial;
|
||||||
|
padding: 12px 14px !important;
|
||||||
font-size: 13px !important;
|
font-size: 13px !important;
|
||||||
gap: 6px;
|
column-gap: 8px;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-tab-button .material-icons {
|
.auth-tab-button .material-icons {
|
||||||
font-size: 18px !important;
|
font-size: 17px !important;
|
||||||
|
width: 18px;
|
||||||
|
min-width: 18px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-tab-button > span:last-child {
|
||||||
|
min-width: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode-container {
|
||||||
|
max-width: 260px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 高级配置 Tab 切换 */
|
||||||
|
.config-tabs {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 4px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-tab-button {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 10px 14px !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
color: #6c757d !important;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
z-index: 1;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-tab-button:hover {
|
||||||
|
color: #495057 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-tab-button.active {
|
||||||
|
color: #007bff !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
background: #fff !important;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-tab-panels {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-tab-content {
|
||||||
|
display: none !important;
|
||||||
|
animation: fadeInUp 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-tab-content.active {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-tab-content .card-content {
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 0 20px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.config-tabs {
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-tab-button {
|
||||||
|
padding: 8px 10px !important;
|
||||||
|
font-size: 12px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -882,12 +1010,14 @@ footer a:hover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 链接样式 */
|
/* 链接样式(面板内与卡片内统一) */
|
||||||
|
.setting-panel a,
|
||||||
.setting-card a {
|
.setting-card a {
|
||||||
color: #007bff;
|
color: #007bff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.setting-panel a:hover,
|
||||||
.setting-card a:hover {
|
.setting-card a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
@@ -1077,6 +1207,7 @@ hr {
|
|||||||
word-wrap: normal;
|
word-wrap: normal;
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
-webkit-font-feature-settings: "liga";
|
-webkit-font-feature-settings: "liga";
|
||||||
|
font-feature-settings: "liga";
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1093,9 +1224,6 @@ hr {
|
|||||||
word-wrap: normal;
|
word-wrap: normal;
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
-webkit-font-feature-settings: "liga";
|
-webkit-font-feature-settings: "liga";
|
||||||
|
font-feature-settings: "liga";
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
/* 二维码登录:未点击获取前不显示图片 */
|
|
||||||
#qrcode-container .qrcode-image-hidden {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|||||||
1323
xiaomusic/static/default/setting.html
vendored
1323
xiaomusic/static/default/setting.html
vendored
File diff suppressed because it is too large
Load Diff
179
xiaomusic/static/default/setting.js
vendored
179
xiaomusic/static/default/setting.js
vendored
@@ -1,6 +1,75 @@
|
|||||||
|
// 获取二维码的函数(点击「获取二维码」后再请求并显示)
|
||||||
|
let qrcodeCountdownTimer = null;
|
||||||
|
const DEFAULT_QRCODE_EXPIRE_SECONDS = 120;
|
||||||
|
|
||||||
|
function stopQRCodeCountdown() {
|
||||||
|
if (qrcodeCountdownTimer) {
|
||||||
|
clearInterval(qrcodeCountdownTimer);
|
||||||
|
qrcodeCountdownTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startQRCodeCountdown($qrcodeStatus, $qrcodeImage, expireSeconds) {
|
||||||
|
stopQRCodeCountdown();
|
||||||
|
|
||||||
|
let remainSeconds = Number(expireSeconds);
|
||||||
|
if (!Number.isFinite(remainSeconds) || remainSeconds <= 0) {
|
||||||
|
remainSeconds = DEFAULT_QRCODE_EXPIRE_SECONDS;
|
||||||
|
}
|
||||||
|
remainSeconds = Math.floor(remainSeconds);
|
||||||
|
|
||||||
|
const updateCountdownText = function () {
|
||||||
|
if (remainSeconds <= 0) {
|
||||||
|
stopQRCodeCountdown();
|
||||||
|
$qrcodeImage.addClass("qrcode-image-hidden");
|
||||||
|
$qrcodeStatus.text("二维码已过期,请点击“刷新二维码”重新获取");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$qrcodeStatus.text(
|
||||||
|
"请使用米家App扫码登录,二维码将在 " + remainSeconds + " 秒后过期"
|
||||||
|
);
|
||||||
|
remainSeconds -= 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
updateCountdownText();
|
||||||
|
qrcodeCountdownTimer = setInterval(updateCountdownText, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchQRCode() {
|
||||||
|
var $qrcodeImage = $("#qrcode-image");
|
||||||
|
var $qrcodeStatus = $("#qrcode-status");
|
||||||
|
var $refreshBtn = $("#refresh-qrcode");
|
||||||
|
|
||||||
|
if (!$qrcodeImage.length || !$qrcodeStatus.length) return;
|
||||||
|
stopQRCodeCountdown();
|
||||||
|
|
||||||
|
$qrcodeImage.attr("src", "");
|
||||||
|
$qrcodeStatus.text("正在生成二维码...");
|
||||||
|
$refreshBtn.text("刷新二维码");
|
||||||
|
|
||||||
|
$.get("/api/get_qrcode")
|
||||||
|
.done(function (data) {
|
||||||
|
if (data.success) {
|
||||||
|
if (data.already_logged_in) {
|
||||||
|
$qrcodeStatus.text(data.message || "已登录,无需更新");
|
||||||
|
$qrcodeImage.addClass("qrcode-image-hidden");
|
||||||
|
} else {
|
||||||
|
$qrcodeImage.attr("src", data.qrcode_url || "").removeClass("qrcode-image-hidden");
|
||||||
|
startQRCodeCountdown($qrcodeStatus, $qrcodeImage, data.expire_seconds);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$qrcodeStatus.text(data.message || "二维码生成失败,请稍后重试");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(function (xhr) {
|
||||||
|
console.error("获取二维码失败:", xhr);
|
||||||
|
$qrcodeStatus.text("网络错误,请检查连接");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ============ 字体加载检测 ============
|
// ============ 字体加载检测 ============
|
||||||
// 检测字体加载完成,避免图标文字闪烁
|
// 检测字体加载完成,避免图标文字闪烁
|
||||||
(function() {
|
(function () {
|
||||||
// 使用 Promise.race 实现超时保护
|
// 使用 Promise.race 实现超时保护
|
||||||
const fontLoadTimeout = new Promise(resolve => {
|
const fontLoadTimeout = new Promise(resolve => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -24,6 +93,8 @@
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
|
$("#refresh-qrcode").on("click", fetchQRCode);
|
||||||
|
|
||||||
// 拉取版本
|
// 拉取版本
|
||||||
$.get("/getversion", function (data, status) {
|
$.get("/getversion", function (data, status) {
|
||||||
console.log(data, status, data["version"]);
|
console.log(data, status, data["version"]);
|
||||||
@@ -94,13 +165,28 @@ $(function () {
|
|||||||
return selectedDids.join(",");
|
return selectedDids.join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拉取现有配置
|
// 获取设备列表(供“获取设备列表”按钮和初始加载共用)
|
||||||
$.get("/getsetting?need_device_list=true", function (data, status) {
|
function fetchDeviceList(callback) {
|
||||||
console.log(data, status);
|
$.get("/getsetting?need_device_list=true", function (data, status) {
|
||||||
const accountPassValid = data.account && data.password;
|
if (typeof callback === "function") {
|
||||||
updateCheckbox("#mi_did", data.mi_did, data.device_list, accountPassValid);
|
callback(data, status);
|
||||||
|
}
|
||||||
|
}).fail(function (xhr) {
|
||||||
|
alert(
|
||||||
|
"获取设备列表失败: " +
|
||||||
|
(xhr.responseJSON && xhr.responseJSON.detail
|
||||||
|
? xhr.responseJSON.detail
|
||||||
|
: xhr.statusText)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始加载:拉取配置并填充表单与设备列表
|
||||||
|
fetchDeviceList(function (data, status) {
|
||||||
|
console.log(data, status);
|
||||||
|
var accountPassValid = data.account && data.password;
|
||||||
|
updateCheckbox("#mi_did", data.mi_did || "", data.device_list || [], accountPassValid);
|
||||||
|
|
||||||
// 初始化显示
|
|
||||||
for (const key in data) {
|
for (const key in data) {
|
||||||
const $element = $("#" + key);
|
const $element = $("#" + key);
|
||||||
if ($element.length) {
|
if ($element.length) {
|
||||||
@@ -117,6 +203,29 @@ $(function () {
|
|||||||
autoSelectOne();
|
autoSelectOne();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#update-devices").on("click", function () {
|
||||||
|
var $btn = $(this);
|
||||||
|
var oldText = $btn.text();
|
||||||
|
$btn.prop("disabled", true).text("更新中…");
|
||||||
|
$.get("/device_list")
|
||||||
|
.done(function (data) {
|
||||||
|
var currentMiDid = getSelectedDids("#mi_did");
|
||||||
|
var raw = data.devices || {};
|
||||||
|
var deviceList = Object.keys(raw).map(function (did) {
|
||||||
|
var d = raw[did];
|
||||||
|
return { miotDID: d.did || did, hardware: d.hardware || "", name: d.name || "" };
|
||||||
|
});
|
||||||
|
updateCheckbox("#mi_did", currentMiDid, deviceList);
|
||||||
|
})
|
||||||
|
.fail(function (xhr) {
|
||||||
|
alert("更新设备列表失败: " + (xhr.responseJSON && xhr.responseJSON.detail ? xhr.responseJSON.detail : xhr.statusText));
|
||||||
|
})
|
||||||
|
.always(function () {
|
||||||
|
$btn.prop("disabled", false).text(oldText);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
$(".save-button").on("click", () => {
|
$(".save-button").on("click", () => {
|
||||||
var setting = $("#setting");
|
var setting = $("#setting");
|
||||||
var inputs = setting.find("input, select, textarea");
|
var inputs = setting.find("input, select, textarea");
|
||||||
@@ -311,6 +420,25 @@ $(function () {
|
|||||||
$("#tab-" + tabName).addClass("active");
|
$("#tab-" + tabName).addClass("active");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 高级配置 Tab 切换:委托到高级配置容器,阻止冒泡并强制切换面板
|
||||||
|
$("#advancedConfigContent").on("click", ".config-tab-button", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
var $btn = $(this);
|
||||||
|
var panelId = $btn.attr("aria-controls") || ("tab-" + $btn.data("tab"));
|
||||||
|
if (!panelId) return;
|
||||||
|
|
||||||
|
$("#advancedConfigContent .config-tab-button").removeClass("active").attr("aria-selected", "false");
|
||||||
|
$btn.addClass("active").attr("aria-selected", "true");
|
||||||
|
|
||||||
|
$("#advancedConfigContent .config-tab-content").removeClass("active");
|
||||||
|
var $panel = $("#" + panelId);
|
||||||
|
if ($panel.length) {
|
||||||
|
$panel.addClass("active");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 功能操作区域折叠功能
|
// 功能操作区域折叠功能
|
||||||
const operationToggle = $("#operationToggle");
|
const operationToggle = $("#operationToggle");
|
||||||
const operationContent = $("#operationContent");
|
const operationContent = $("#operationContent");
|
||||||
@@ -514,40 +642,3 @@ $(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取二维码的函数(点击「获取二维码」后再请求并显示)
|
|
||||||
function fetchQRCode() {
|
|
||||||
const qrcodeImage = document.getElementById("qrcode-image");
|
|
||||||
const qrcodeStatus = document.getElementById("qrcode-status");
|
|
||||||
const refreshBtn = document.getElementById("refresh-qrcode");
|
|
||||||
|
|
||||||
if (!qrcodeImage || !qrcodeStatus) return;
|
|
||||||
|
|
||||||
qrcodeImage.src = "";
|
|
||||||
qrcodeStatus.textContent = "正在生成二维码...";
|
|
||||||
if (refreshBtn) refreshBtn.textContent = "刷新二维码";
|
|
||||||
|
|
||||||
fetch("/api/get_qrcode")
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((data) => {
|
|
||||||
if (data.success) {
|
|
||||||
if (data.already_logged_in) {
|
|
||||||
qrcodeStatus.textContent = data.message || "已登录,无需扫码";
|
|
||||||
qrcodeImage.classList.add("qrcode-image-hidden");
|
|
||||||
} else {
|
|
||||||
qrcodeImage.src = data.qrcode_url || "";
|
|
||||||
qrcodeImage.classList.remove("qrcode-image-hidden");
|
|
||||||
qrcodeStatus.textContent = "请使用米家App扫码登录,扫码成功后请刷新页面以获取设备列表";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qrcodeStatus.textContent = data.message || "二维码生成失败,请稍后重试";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("获取二维码失败:", error);
|
|
||||||
qrcodeStatus.textContent = "网络错误,请检查连接";
|
|
||||||
});
|
|
||||||
// 显示二维码区域并进入加载状态
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user