This commit is contained in:
Daniel
2026-04-28 19:16:27 +08:00
parent 6de7e782fc
commit c234fe64d6
13 changed files with 229 additions and 31 deletions

36
app/static/guide.js Normal file
View File

@@ -0,0 +1,36 @@
const guideGetServerIpBtn = document.getElementById("getServerIpBtn");
async function showGuideAlert(message, title = "提示") {
if (typeof window.uiAlert === "function") {
await window.uiAlert(message, title);
return;
}
window.alert(message);
}
if (guideGetServerIpBtn) {
guideGetServerIpBtn.addEventListener("click", async () => {
const idleText = "获取服务器IP";
guideGetServerIpBtn.disabled = true;
guideGetServerIpBtn.textContent = "获取中...";
try {
const res = await fetch("/api/tools/server-ip");
const data = await res.json();
if (!res.ok || !data.ok) {
await showGuideAlert((data && data.detail) || "获取服务器IP失败请稍后重试", "获取失败");
return;
}
const ip = String(data.ip || "").trim();
if (!ip) {
await showGuideAlert("服务器IP为空请稍后重试", "获取失败");
return;
}
await showGuideAlert(`当前服务器IP${ip}`, "API IP白名单");
} catch {
await showGuideAlert("获取服务器IP失败请稍后重试", "获取失败");
} finally {
guideGetServerIpBtn.disabled = false;
guideGetServerIpBtn.textContent = idleText;
}
});
}

27
app/static/mode-hint.js Normal file
View File

@@ -0,0 +1,27 @@
(() => {
const badges = Array.from(document.querySelectorAll(".global-mode-hint"));
if (!badges.length) return;
function setText(text) {
badges.forEach((el) => {
el.textContent = text;
});
}
async function run() {
try {
const res = await fetch("/api/auth/me");
const data = await res.json();
if (!res.ok || !data || !data.logged_in) return;
const vip = data.vip || {};
const now = Math.floor(Date.now() / 1000);
const enabled = Boolean(vip.vip_enabled);
const hasActiveSubscription = Number(vip.cycle_started_at || 0) > 0 && Number(vip.cycle_expires_at || 0) > now;
setText(enabled && hasActiveSubscription ? "当前模型模式:平台模型" : "当前模型模式:自由模型");
} catch {
// ignore
}
}
run();
})();

View File

@@ -207,7 +207,7 @@ if (saveModelBtn) {
api_key: ($("apiKey") && $("apiKey").value.trim()) || "",
base_url: ($("baseUrl") && $("baseUrl").value.trim()) || "",
model: ($("modelValue") && $("modelValue").value.trim()) || "",
image_model: "",
image_model: ($("imageModelValue") && $("imageModelValue").value.trim()) || "",
timeout_sec: Number((($("timeoutSec") && $("timeoutSec").value) || "120").trim()),
max_output_tokens: Number((($("maxOutputTokens") && $("maxOutputTokens").value) || "8192").trim()),
max_retries: Number((($("maxRetries") && $("maxRetries").value) || "0").trim()),
@@ -219,6 +219,7 @@ if (saveModelBtn) {
setStatus("模型配置已保存并设为当前。");
if ($("apiKey")) $("apiKey").value = "";
if ($("modelName")) $("modelName").value = "";
if ($("imageModelValue")) $("imageModelValue").value = "";
await refresh();
} catch (e) {
setStatus(e.message || "模型保存失败", true);

View File

@@ -215,6 +215,41 @@ a {
flex-wrap: wrap;
}
.upgrade-topbar {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
}
.topbar-spacer {
min-height: 1px;
}
.topbar-center {
display: flex;
justify-content: center;
}
.upgrade-topbar .topbar-actions {
justify-self: end;
flex-wrap: nowrap;
}
.mode-badge {
display: inline-flex;
align-items: center;
min-height: var(--control-h);
padding: 0 12px;
border-radius: var(--radius);
border: 1px solid var(--accent);
background: linear-gradient(180deg, #ff922e, #ff6b16);
color: #fff;
font-size: 12px;
font-weight: 850;
white-space: nowrap;
box-shadow: 0 10px 20px rgba(255, 107, 22, 0.2);
}
.wechat-account-switch {
min-width: 250px;
display: grid;
@@ -333,12 +368,14 @@ a {
.panel-scroll {
min-height: 0;
overflow: auto;
overflow-y: auto;
overflow-x: hidden;
padding: 10px;
}
.input-panel .panel-scroll {
overflow: visible;
overflow-y: visible;
overflow-x: hidden;
padding: 8px;
}
@@ -783,27 +820,29 @@ button.secondary:hover,
}
.target-chars-quick {
display: flex;
align-items: center;
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
align-items: stretch;
gap: 6px;
width: 100%;
min-width: 0;
flex-wrap: wrap;
overflow: visible;
}
.target-char-chip,
button.target-char-chip {
width: auto;
min-width: 54px;
width: 100%;
min-width: 0;
min-height: 30px;
margin-top: 0;
padding: 5px 8px;
flex: 0 0 auto;
border-radius: 999px;
padding: 5px 6px;
border-radius: 8px;
border-color: var(--line-strong);
color: #344054;
background: #fff;
font-size: 12px;
line-height: 1.2;
line-height: 1.1;
text-align: center;
white-space: nowrap;
box-shadow: none;
}
@@ -1587,7 +1626,7 @@ button.target-char-chip {
.upgrade-grid {
margin-top: 10px;
display: grid;
grid-template-columns: minmax(0, 1.4fr) minmax(320px, 0.8fr);
grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
gap: 10px;
}
@@ -2009,6 +2048,12 @@ button.target-char-chip {
border-radius: 10px;
}
@media (max-width: 1100px) {
.upgrade-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 860px) {
.upgrade-hero {
align-items: flex-start;

View File

@@ -85,6 +85,8 @@ function renderVip(vip) {
const enabled = Boolean(vip.vip_enabled);
const cycleStart = Number(vip.cycle_started_at || 0);
const cycleEnd = Number(vip.cycle_expires_at || 0);
const now = Math.floor(Date.now() / 1000);
const hasActiveSubscription = cycleStart > 0 && cycleEnd > now;
if ($("upgradeTokenBalance")) $("upgradeTokenBalance").textContent = String(totalAvailable);
if ($("upgradeTokenBalanceHero")) $("upgradeTokenBalanceHero").textContent = String(totalAvailable);
if ($("vipTokenBalance")) $("vipTokenBalance").textContent = String(shared);
@@ -103,6 +105,15 @@ function renderVip(vip) {
$("vipCycleHint").textContent = "当前未开始月周期,首次支付成功后开始计时。";
}
}
if ($("vipModeHint")) {
if (enabled && hasActiveSubscription) {
$("vipModeHint").textContent = "当前模型模式:平台模型(订阅有效)";
} else if (enabled && !hasActiveSubscription) {
$("vipModeHint").textContent = "当前模型模式:自由模型(未开通订阅)";
} else {
$("vipModeHint").textContent = "当前模型模式:自由模型";
}
}
if (totalAvailable <= 0) {
setStatus("Credits 额度已用完,请充值共享加油包或等待下个计费周期。", true);
}