diff --git a/client/src/lib/luxsinApi.ts b/client/src/lib/luxsinApi.ts index 6bcb98b..c07089a 100644 --- a/client/src/lib/luxsinApi.ts +++ b/client/src/lib/luxsinApi.ts @@ -188,11 +188,28 @@ export class LuxsinAPI { this.baseUrl = `${protocol}://${host}`; } + private maybeRedirectForHttpsCert(error: unknown) { + // On HTTPS pages, first-time device access may fail before user trusts the cert. + if (typeof window === "undefined") return; + if (window.location.protocol !== "https:") return; + if (!(error instanceof Error)) return; + // fetch network failure is typically reported as TypeError/Failed to fetch. + const msg = (error.message || "").toLowerCase(); + if (error.name === "TypeError" || msg.includes("failed to fetch") || msg.includes("networkerror")) { + window.location.href = this.baseUrl; + } + } + async getDeviceState(): Promise { - const response = await fetch(`${this.baseUrl}/dev/info.cgi?action=syncData`); - const text = await response.text(); - const decoded = decodeCustomBase64(text.trim()); - return JSON.parse(decoded) as DeviceState; + try { + const response = await fetch(`${this.baseUrl}/dev/info.cgi?action=syncData`); + const text = await response.text(); + const decoded = decodeCustomBase64(text.trim()); + return JSON.parse(decoded) as DeviceState; + } catch (error) { + this.maybeRedirectForHttpsCert(error); + throw error; + } } async getMsgCount(): Promise { diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx index 9e303b2..97379f8 100644 --- a/client/src/pages/Home.tsx +++ b/client/src/pages/Home.tsx @@ -395,14 +395,16 @@ export default function Home() { onClick={() => updateSetting({ bt_next: 0 })} className="w-10 h-10 rounded-full flex items-center justify-center transition-all active:scale-95" style={{ background: "rgba(0,255,246,0.15)", border: "1px solid rgba(0,255,246,0.3)" }}> - 上一首 + 上一首