优化体验,修复 bug

This commit is contained in:
eafonyang
2026-06-15 18:39:20 +08:00
parent b421fe1ca3
commit 7eb7647484
6 changed files with 89 additions and 35 deletions
+5 -3
View File
@@ -365,12 +365,15 @@
"shareCopied": "Code copied", "shareCopied": "Code copied",
"shareGenerating": "Generating…", "shareGenerating": "Generating…",
"shareCreateFail": "Failed to generate share code", "shareCreateFail": "Failed to generate share code",
"shareActiveExists": "You already have an active share code. Please try again later.",
"shareInvalidParams": "Invalid request. Please check and try again.",
"shareSystemError": "System error. Please try again later.",
"shareExpireAt": "Expires at", "shareExpireAt": "Expires at",
"importTab": "Import EQ", "importTab": "Import EQ",
"importCodeHint": "Enter or paste the 5-character share code", "importCodeHint": "Enter or paste the 5-character share code",
"importQuery": "Query", "importQuery": "Query",
"importQuerying": "Querying…", "importQuerying": "Querying…",
"importCodeNotFound": "Share code not found", "importCodeNotFound": "Share code not found or expired",
"importEqName": "EQ Name", "importEqName": "EQ Name",
"importButton": "Import", "importButton": "Import",
"importSaving": "Importing…", "importSaving": "Importing…",
@@ -381,8 +384,7 @@
"mySharesEmpty": "No shared EQ yet", "mySharesEmpty": "No shared EQ yet",
"mySharesCode": "Code", "mySharesCode": "Code",
"mySharesName": "EQ Name", "mySharesName": "EQ Name",
"mySharesLoadFail": "Failed to load share list", "mySharesLoadFail": "Failed to load share list"
"importCodeNotFound": "Share code not found or expired"
} }
}, },
"dac": { "dac": {
+3
View File
@@ -301,6 +301,9 @@
"shareCopied": "已複製分享碼", "shareCopied": "已複製分享碼",
"shareGenerating": "產生中…", "shareGenerating": "產生中…",
"shareCreateFail": "產生分享碼失敗", "shareCreateFail": "產生分享碼失敗",
"shareActiveExists": "已有未過期的分享碼,請稍後再試",
"shareInvalidParams": "請求參數無效,請檢查後重試",
"shareSystemError": "系統錯誤,請稍後重試",
"shareExpireAt": "有效期至", "shareExpireAt": "有效期至",
"importTab": "匯入 EQ", "importTab": "匯入 EQ",
"importCodeHint": "輸入或貼上 5 位分享碼", "importCodeHint": "輸入或貼上 5 位分享碼",
+3
View File
@@ -301,6 +301,9 @@
"shareCopied": "已复制分享码", "shareCopied": "已复制分享码",
"shareGenerating": "生成中…", "shareGenerating": "生成中…",
"shareCreateFail": "生成分享码失败", "shareCreateFail": "生成分享码失败",
"shareActiveExists": "已有未过期的分享码,请稍后再试",
"shareInvalidParams": "请求参数无效,请检查后重试",
"shareSystemError": "系统错误,请稍后重试",
"shareExpireAt": "有效期至", "shareExpireAt": "有效期至",
"importTab": "导入 EQ", "importTab": "导入 EQ",
"importCodeHint": "输入或粘贴 5 位分享码", "importCodeHint": "输入或粘贴 5 位分享码",
+1 -11
View File
@@ -25,7 +25,6 @@ import {
type PeqChangePayload, type PeqChangePayload,
type PeqState, type PeqState,
buildPeqPresetBody, buildPeqPresetBody,
acceptShareCode,
} from "@/lib/luxsinApi"; } from "@/lib/luxsinApi";
import { import {
getFilterType, getFilterType,
@@ -719,16 +718,6 @@ export default function EQPage() {
skipPeqAutoSyncRef.current = true; skipPeqAutoSyncRef.current = true;
try { try {
const mac = deviceState?.mac ?? "";
if (!isDemoMode && mac) {
const acceptRes = await acceptShareCode(mac, shareCode.trim());
if (acceptRes.code !== 200) {
toast.error(eqUi.importFail ?? eqUi.importCodeNotFound);
skipPeqAutoSyncRef.current = false;
return;
}
}
await upgradePeqChange(payload); await upgradePeqChange(payload);
if (api && !isDemoMode) { if (api && !isDemoMode) {
const latest = await fetchEqSyncPeq(api, "importSharedEq"); const latest = await fetchEqSyncPeq(api, "importSharedEq");
@@ -1850,6 +1839,7 @@ export default function EQPage() {
eqUi={eqUi} eqUi={eqUi}
peqCardLabels={peqCardLabels} peqCardLabels={peqCardLabels}
mac={deviceState?.mac ?? ""} mac={deviceState?.mac ?? ""}
isDemoMode={isDemoMode}
onImportEq={handleImportSharedEq} onImportEq={handleImportSharedEq}
/> />
+37 -21
View File
@@ -2,8 +2,9 @@ import { useState } from "react";
import { X, Copy, Loader2 } from "lucide-react"; import { X, Copy, Loader2 } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { toast } from "sonner"; import { toast } from "sonner";
import { createShareCode, listShareCodes, queryShareCode } from "@/lib/luxsinApi"; import { acceptShareCode, createShareCode, listShareCodes, queryShareCode } from "@/lib/luxsinApi";
import type { PeqEqUi } from "../constants"; import type { PeqEqUi } from "../constants";
import { resolveShareApiMessage } from "../shareMessages";
type PeqItem = { type PeqItem = {
name: string; name: string;
@@ -39,6 +40,7 @@ export function ShareDialog({
eqUi, eqUi,
peqCardLabels, peqCardLabels,
mac, mac,
isDemoMode,
onImportEq, onImportEq,
}: { }: {
open: boolean; open: boolean;
@@ -48,6 +50,7 @@ export function ShareDialog({
eqUi: PeqEqUi; eqUi: PeqEqUi;
peqCardLabels: PeqCardLabels; peqCardLabels: PeqCardLabels;
mac: string; mac: string;
isDemoMode: boolean;
onImportEq: (data: ImportedEqData, shareCode: string) => void | Promise<void>; onImportEq: (data: ImportedEqData, shareCode: string) => void | Promise<void>;
}) { }) {
const [shareDialogTab, setShareDialogTab] = useState<"share" | "import" | "myShares">("share"); const [shareDialogTab, setShareDialogTab] = useState<"share" | "import" | "myShares">("share");
@@ -64,6 +67,26 @@ export function ShareDialog({
const [mySharesList, setMySharesList] = useState<Array<{ share_code: string; expire_at: string; eq_data: Record<string, unknown> }>>([]); const [mySharesList, setMySharesList] = useState<Array<{ share_code: string; expire_at: string; eq_data: Record<string, unknown> }>>([]);
const [mySharesLoading, setMySharesLoading] = useState(false); const [mySharesLoading, setMySharesLoading] = useState(false);
const handleImportClick = async () => {
if (importSaving || !importedEqData || !queriedShareCode) return;
const nextName = importPresetName.trim();
if (!nextName) return;
setImportSaving(true);
try {
if (!isDemoMode && mac) {
const acceptRes = await acceptShareCode(mac, queriedShareCode);
if (acceptRes.code !== 200) {
toast.error(resolveShareApiMessage("accept", acceptRes, eqUi));
return;
}
}
await onImportEq({ ...importedEqData, name: nextName }, queriedShareCode);
} finally {
setImportSaving(false);
}
};
if (!open) return null; if (!open) return null;
/* ── clipboard helper ── */ /* ── clipboard helper ── */
@@ -87,7 +110,9 @@ export function ShareDialog({
return ( return (
<div <div
className="fixed inset-0 z-[120] flex items-center justify-center bg-black/65 px-4" className="fixed inset-0 z-[120] flex items-center justify-center bg-black/65 px-4"
onClick={onClose} onClick={() => {
if (!importSaving) onClose();
}}
> >
<div <div
className="w-full max-w-[420px] rounded-[14px] p-5" className="w-full max-w-[420px] rounded-[14px] p-5"
@@ -142,12 +167,12 @@ export function ShareDialog({
try { try {
const res = await listShareCodes(mac); const res = await listShareCodes(mac);
if (res.code !== 200) { if (res.code !== 200) {
toast.error(eqUi.mySharesLoadFail); toast.error(resolveShareApiMessage("list", res, eqUi));
return; return;
} }
setMySharesList(res.share_codes ?? []); setMySharesList(res.share_codes ?? []);
} catch { } catch {
toast.error(eqUi.mySharesLoadFail); toast.error(resolveShareApiMessage("list", { code: 500 }, eqUi));
} finally { } finally {
setMySharesLoading(false); setMySharesLoading(false);
} }
@@ -160,7 +185,8 @@ export function ShareDialog({
</div> </div>
<button <button
type="button" type="button"
className="rounded-full p-1.5 text-white/45 transition-colors hover:bg-white/10 hover:text-white/80" className="rounded-full p-1.5 text-white/45 transition-colors hover:bg-white/10 hover:text-white/80 disabled:opacity-40 disabled:pointer-events-none"
disabled={importSaving}
onClick={onClose} onClick={onClose}
> >
<X size={20} /> <X size={20} />
@@ -236,13 +262,13 @@ export function ShareDialog({
}; };
const res = await createShareCode(mac, eqData); const res = await createShareCode(mac, eqData);
if (res.code !== 200) { if (res.code !== 200) {
toast.error(res.msg || eqUi.shareCreateFail); toast.error(resolveShareApiMessage("create", res, eqUi));
return; return;
} }
setShareCode(res.share_code ?? ""); setShareCode(res.share_code ?? "");
setShareCodeExpireAt(res.expire_at ?? null); setShareCodeExpireAt(res.expire_at ?? null);
} catch { } catch {
toast.error(eqUi.shareCreateFail); toast.error(resolveShareApiMessage("create", { code: 500 }, eqUi));
} finally { } finally {
setShareGenerating(false); setShareGenerating(false);
} }
@@ -391,12 +417,12 @@ export function ShareDialog({
try { try {
const res = await queryShareCode(code); const res = await queryShareCode(code);
if (res.code !== 200) { if (res.code !== 200) {
toast.error(eqUi.importCodeNotFound); toast.error(resolveShareApiMessage("query", res, eqUi));
return; return;
} }
const eq = res.eq_data; const eq = res.eq_data;
if (!eq) { if (!eq) {
toast.error(eqUi.importCodeNotFound); toast.error(resolveShareApiMessage("query", { code: 0 }, eqUi));
return; return;
} }
const fetchedName = (eq.name as string) || ""; const fetchedName = (eq.name as string) || "";
@@ -413,7 +439,7 @@ export function ShareDialog({
setImportPresetName(fetchedName); setImportPresetName(fetchedName);
setQueriedShareCode(code); setQueriedShareCode(code);
} catch { } catch {
toast.error(eqUi.importCodeNotFound); toast.error(resolveShareApiMessage("query", { code: 500 }, eqUi));
} finally { } finally {
setImportQuerying(false); setImportQuerying(false);
} }
@@ -451,17 +477,7 @@ export function ShareDialog({
? "bg-[#00FFF6]/40 cursor-not-allowed" ? "bg-[#00FFF6]/40 cursor-not-allowed"
: "bg-[#00FFF6] hover:brightness-95", : "bg-[#00FFF6] hover:brightness-95",
)} )}
onClick={() => { onClick={() => void handleImportClick()}
if (importSaving || !importedEqData || !queriedShareCode) return;
const nextName = importPresetName.trim();
if (!nextName) return;
setImportSaving(true);
void Promise.resolve(
onImportEq({ ...importedEqData, name: nextName }, queriedShareCode),
).finally(() => {
setImportSaving(false);
});
}}
> >
{importSaving ? ( {importSaving ? (
<span className="flex items-center justify-center gap-1.5"> <span className="flex items-center justify-center gap-1.5">
+40
View File
@@ -0,0 +1,40 @@
import type { PeqEqUi } from "./constants";
export type ShareApiAction = "create" | "query" | "accept" | "list";
export function resolveShareApiMessage(
action: ShareApiAction,
res: { code: number; msg?: string },
eqUi: PeqEqUi,
): string {
if (res.code === 200) return "";
if (action === "list") {
return eqUi.mySharesLoadFail ?? "Failed to load share list";
}
if (res.code === 0) {
if (action === "create") {
return eqUi.shareActiveExists ?? eqUi.shareCreateFail ?? "Failed to generate share code";
}
return eqUi.importCodeNotFound ?? "Share code not found or expired";
}
if (res.code === 400) {
return eqUi.shareInvalidParams ?? eqUi.shareCreateFail ?? "Invalid request";
}
if (res.code === 500) {
return eqUi.shareSystemError ?? eqUi.shareCreateFail ?? "System error";
}
if (action === "create") {
return eqUi.shareCreateFail ?? "Failed to generate share code";
}
if (action === "accept") {
return eqUi.importFail ?? eqUi.importCodeNotFound ?? "Failed to import EQ";
}
return eqUi.importCodeNotFound ?? "Share code not found or expired";
}