feat: 优化更新检查逻辑 + 修复按量余额显示(v0.6.5)
Release / Version consistency (push) Canceled after 0s
Release / Build (macos-latest) (push) Canceled after 0s
Release / Build (ubuntu-latest) (push) Canceled after 0s
Release / Build (windows-latest) (push) Canceled after 0s

This commit is contained in:
KimiSwitch Dev committed 2026-08-01 10:51:54 +08:00
1 parent f60305fbeb
commit 2464500ef5
12 files changed
+141 -70

No files matched your search

+73 -17
View File
@@ -110,6 +110,15 @@ export function SettingsModal({
invoke("open_installer", { path: downloadedPath }).catch(() => {});
};
// Open an external link in the system browser. Falls back to a new tab
// when the opener plugin call fails, so a broken click never stays silent.
const openExternal = (url: string) => {
openUrl(url).catch(() => {
const w = window.open(url, "_blank");
if (!w) console.error(`failed to open ${url}`);
});
};
if (!open) return null;
const themeOptions: { value: Theme; icon: ReactNode; label: string }[] = [
@@ -253,26 +262,66 @@ export function SettingsModal({
type="button"
onClick={onCheckUpdate}
disabled={checking}
className="px-3 py-1.5 text-sm rounded border border-border hover:bg-hover-2 disabled:opacity-50 transition-colors"
className="px-3 py-1.5 text-sm rounded border border-border hover:bg-hover-2 disabled:opacity-50 transition-colors flex items-center gap-1.5"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className={checking ? "animate-spin" : ""}
>
<path d="M21 12a9 9 0 1 1-2.64-6.36" />
<polyline points="21 3 21 9 15 9" />
</svg>
{checking ? t("checking") : t("checkUpdate")}
</button>
{updateInfo?.updateAvailable && downloadProgress === null && !downloadedPath && (
<button
type="button"
onClick={handleDownload}
className="px-3 py-1.5 text-sm rounded bg-green-600 text-white hover:bg-green-500 transition-colors"
className="px-3 py-1.5 text-sm rounded bg-green-600 text-white hover:bg-green-500 transition-colors flex items-center gap-1.5"
>
{t("downloadUpdate")} ↓
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="7 10 12 15 17 10" />
<line x1="12" y1="15" x2="12" y2="3" />
</svg>
{t("downloadUpdate")}
</button>
)}
{downloadedPath && (
<button
type="button"
onClick={handleInstall}
className="px-3 py-1.5 text-sm rounded bg-blue-600 text-white hover:bg-blue-500 transition-colors"
className="px-3 py-1.5 text-sm rounded bg-blue-600 text-white hover:bg-blue-500 transition-colors flex items-center gap-1.5"
>
{t("install")} ⏎
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<polygon points="6 3 20 12 6 21 6 3" />
</svg>
{t("install")}
</button>
)}
</div>
@@ -323,18 +372,25 @@ export function SettingsModal({
<div className="font-medium text-content-primary">Kimi Switch</div>
<div>{t("appDescription")}</div>
<div className="text-xs text-content-muted">v{appVersion} · MIT License</div>
<div className="pt-2">
<span className="text-content-muted">{t("referenceProject")}: </span>
<button
type="button"
onClick={() =>
openUrl("https://github.com/JochenYang/kimicode-dashboard")
}
className="text-blue-500 hover:text-blue-400 underline bg-transparent p-0 border-0 cursor-pointer"
>
kimicode-dashboard
</button>
<span className="text-content-muted"> (MIT, © JochenYang)</span>
<div className="pt-2 space-y-1">
<div>
{t("attributionPorted")}{" "}
<span className="font-medium text-content-primary">kimicode-dashboard</span>
<span className="text-content-muted"> {t("attributionSuffix")}</span>
</div>
<div className="pt-1">
<span className="text-content-muted">{t("referenceProject")}: </span>
<button
type="button"
onClick={() =>
openExternal("https://github.com/farion1231/cc-switch")
}
className="text-blue-500 hover:text-blue-400 underline bg-transparent p-0 border-0 cursor-pointer"
>
cc-switch
</button>
<span className="text-content-muted"> (MIT, © Jason Young)</span>
</div>
</div>
</div>
</section>
+13 -2
View File
@@ -245,7 +245,13 @@ export function UsageFooter({
const compactSummary = (): { icon: string; text: string; color: string } | null => {
const d = data[0];
if (!d) return null;
const isPlan = !!d.planName && d.planName !== "NewAPI";
// A "plan" is a quota tier (used/total, e.g. 5h / weekly limit). Balance
// entries carry only remaining + unit — their plan_name is a currency /
// brand label and must render as an amount, not a percentage.
const isPlan =
!!d.planName &&
d.planName !== "NewAPI" &&
(d.total != null || d.used != null);
if (d.isValid === false) {
return { icon: "⚡", text: t("usageInvalidKey"), color: "text-red-500 dark:text-red-400" };
}
@@ -360,7 +366,12 @@ export function UsageFooter({
}`}
>
{data.map((d, i) => {
const isPlan = !!d.planName;
// Same plan-vs-balance rule as compactSummary: balance rows have no
// quota fields (total/used), so they render as an amount.
const isPlan =
!!d.planName &&
d.planName !== "NewAPI" &&
(d.total != null || d.used != null);
const pct = isPlan ? percentOf(d) : null;
const color =
pct == null
+1 -13
View File
@@ -1,5 +1,4 @@
import { useState, type ReactNode } from "react";
import { openUrl } from "@tauri-apps/plugin-opener";
import { useDashboard, type DashboardRange } from "../../hooks/useDashboard";
import { useTranslation } from "../../i18n";
import { fmtInt, fmtPct, fmtTime, fmtTokens, fmtUsd } from "../../lib/dashboard-format";
@@ -420,23 +419,12 @@ export function DashboardPage() {
)}
</Card>
{/* Footer — meta + attribution at the end of the content flow */}
{/* Footer — meta at the end of the content flow */}
<div className="text-xs text-content-muted pb-2">
<div>
{t("footerScanned", { n: data.meta.filesScanned, m: fmtInt(data.meta.recordCount) })} ·{" "}
{data.meta.home}
</div>
<div className="mt-0.5">
{t("dashboardAttribution")}{" "}
<button
type="button"
onClick={() => openUrl("https://github.com/JochenYang/kimicode-dashboard")}
className="text-blue-500 hover:text-blue-400 underline bg-transparent p-0 border-0 cursor-pointer"
>
kimicode-dashboard
</button>{" "}
{t("attributionSuffix")}
</div>
</div>
</div>
);
-11
View File
@@ -1,5 +1,4 @@
import { useMemo, useState } from "react";
import { openUrl } from "@tauri-apps/plugin-opener";
import { useSessions } from "../../hooks/useSessions";
import { fmtInt, fmtTime } from "../../lib/dashboard-format";
import { useTranslation } from "../../i18n";
@@ -547,16 +546,6 @@ export function SessionsPage() {
{/* Attribution */}
<div className="text-xs text-content-muted pb-2">
{data?.home && <>{data.home}</>}
<br />
{t("sessionsAttribution")}{" "}
<button
type="button"
onClick={() => openUrl("https://github.com/JochenYang/kimicode-dashboard")}
className="text-blue-500 hover:text-blue-400 underline bg-transparent p-0 border-0 cursor-pointer"
>
kimicode-dashboard
</button>{" "}
{t("attributionSuffix")}
</div>
{/* Confirm dialog */}