const $ = (id) => document.getElementById(id); function setStatus(msg, danger = false) { const el = $("status"); if (!el) return; el.style.color = danger ? "#b42318" : "#0f5f3d"; el.textContent = msg; } function setLoading(button, loading, idleText, loadingText) { if (!button) return; button.disabled = loading; button.textContent = loading ? loadingText : idleText; } async function postJSON(url, body) { const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const data = await res.json(); if (!res.ok) throw new Error(data.detail || "请求失败"); return data; } async function authMe() { const res = await fetch("/api/auth/me"); const data = await res.json(); if (!data.logged_in) { window.location.href = "/auth?next=/settings"; return null; } return data; } function renderAccounts(me) { const sel = $("accountSelect"); if (!sel) return; const list = Array.isArray(me.wechat_accounts) ? me.wechat_accounts : []; const active = me.active_wechat_account && me.active_wechat_account.id ? Number(me.active_wechat_account.id) : 0; sel.innerHTML = ""; if (!list.length) { const opt = document.createElement("option"); opt.value = ""; opt.textContent = "未绑定公众号"; sel.appendChild(opt); return; } list.forEach((a) => { const opt = document.createElement("option"); opt.value = String(a.id); opt.textContent = `${a.account_name} (${a.appid})`; if ((active && a.id === active) || a.active) opt.selected = true; sel.appendChild(opt); }); } function renderModels(me) { const sel = $("modelSelect"); if (!sel) return; const list = Array.isArray(me.ai_models) ? me.ai_models : []; const active = me.active_ai_model && me.active_ai_model.id ? Number(me.active_ai_model.id) : 0; sel.innerHTML = ""; if (!list.length) { const opt = document.createElement("option"); opt.value = ""; opt.textContent = "暂无模型配置,请先新增"; sel.appendChild(opt); return; } list.forEach((m) => { const opt = document.createElement("option"); opt.value = String(m.id); opt.textContent = `${m.model_name} (${m.model})`; if ((active && m.id === active) || m.active) opt.selected = true; sel.appendChild(opt); }); } function renderVip(me) { const vip = me && me.vip ? me.vip : {}; const enabledSelect = $("vipEnabledSelect"); const tokenBalance = $("vipTokenBalance"); const totalConsumed = $("vipTotalConsumed"); if (enabledSelect) enabledSelect.value = vip.vip_enabled ? "1" : "0"; if (tokenBalance) tokenBalance.value = String(Number(vip.token_balance || 0)); if (totalConsumed) totalConsumed.value = String(Number(vip.total_consumed_tokens || 0)); } async function refresh() { const me = await authMe(); if (!me) return; renderAccounts(me); renderModels(me); renderVip(me); } const accountSelect = $("accountSelect"); const bindBtn = $("bindBtn"); const deleteWechatBtn = $("deleteWechatBtn"); const logoutBtn = $("logoutBtn"); const changePwdBtn = $("changePwdBtn"); const deleteAccountBtn = $("deleteAccountBtn"); const modelSelect = $("modelSelect"); const saveModelBtn = $("saveModelBtn"); const deleteModelBtn = $("deleteModelBtn"); const saveVipBtn = $("saveVipBtn"); const vipRechargeBtn = $("vipRechargeBtn"); if (accountSelect) { accountSelect.addEventListener("change", async () => { const id = Number(accountSelect.value || 0); if (!id) return; try { const out = await postJSON("/api/auth/wechat/switch", { account_id: id }); if (!out.ok) { setStatus(out.detail || "切换失败", true); return; } setStatus("已切换当前公众号。"); await refresh(); } catch (e) { setStatus(e.message || "切换失败", true); } }); } if (deleteWechatBtn) { deleteWechatBtn.addEventListener("click", async () => { const id = Number((accountSelect && accountSelect.value) || 0); if (!id) { setStatus("请先选择要删除的公众号", true); return; } const sure = await window.uiConfirm("确定删除当前公众号绑定吗?删除后不可恢复。", "删除公众号"); if (!sure) return; setLoading(deleteWechatBtn, true, "删除当前公众号", "删除中..."); try { const out = await postJSON("/api/auth/wechat/delete", { account_id: id }); if (!out.ok) { setStatus(out.detail || "删除失败", true); return; } setStatus("公众号账号已删除。"); await refresh(); } catch (e) { setStatus(e.message || "删除失败", true); } finally { setLoading(deleteWechatBtn, false, "删除当前公众号", "删除中..."); } }); } if (bindBtn) { bindBtn.addEventListener("click", async () => { setLoading(bindBtn, true, "绑定并设为当前账号", "绑定中..."); try { const out = await postJSON("/api/auth/wechat/bind", { account_name: ($("accountName") && $("accountName").value.trim()) || "", appid: ($("appid") && $("appid").value.trim()) || "", secret: ($("secret") && $("secret").value.trim()) || "", author: "", thumb_media_id: "", thumb_image_path: "", }); if (!out.ok) { setStatus(out.detail || "绑定失败", true); return; } setStatus("公众号绑定成功,已切换为当前账号。"); if ($("appid")) $("appid").value = ""; if ($("secret")) $("secret").value = ""; await refresh(); } catch (e) { setStatus(e.message || "绑定失败", true); } finally { setLoading(bindBtn, false, "绑定并设为当前账号", "绑定中..."); } }); } if (modelSelect) { modelSelect.addEventListener("change", async () => { const id = Number(modelSelect.value || 0); if (!id) return; try { const out = await postJSON("/api/auth/ai-models/switch", { model_id: id }); if (!out.ok) { setStatus(out.detail || "模型切换失败", true); return; } setStatus("已切换当前模型。"); await refresh(); } catch (e) { setStatus(e.message || "模型切换失败", true); } }); } if (saveModelBtn) { saveModelBtn.addEventListener("click", async () => { setLoading(saveModelBtn, true, "保存并设为当前模型", "保存中..."); try { const out = await postJSON("/api/auth/ai-models/add", { model_name: ($("modelName") && $("modelName").value.trim()) || "", api_key: ($("apiKey") && $("apiKey").value.trim()) || "", base_url: ($("baseUrl") && $("baseUrl").value.trim()) || "", model: ($("modelValue") && $("modelValue").value.trim()) || "", 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()), }); if (!out.ok) { setStatus(out.detail || "模型保存失败", true); return; } setStatus("模型配置已保存并设为当前。"); if ($("apiKey")) $("apiKey").value = ""; if ($("modelName")) $("modelName").value = ""; if ($("imageModelValue")) $("imageModelValue").value = ""; await refresh(); } catch (e) { setStatus(e.message || "模型保存失败", true); } finally { setLoading(saveModelBtn, false, "保存并设为当前模型", "保存中..."); } }); } if (deleteModelBtn) { deleteModelBtn.addEventListener("click", async () => { const id = Number((modelSelect && modelSelect.value) || 0); if (!id) { setStatus("请先选择要删除的模型", true); return; } const sure = await window.uiConfirm("确定删除当前模型配置吗?删除后不可恢复。", "删除模型"); if (!sure) return; setLoading(deleteModelBtn, true, "删除当前模型", "删除中..."); try { const out = await postJSON("/api/auth/ai-models/delete", { model_id: id }); if (!out.ok) { setStatus(out.detail || "模型删除失败", true); return; } setStatus("模型配置已删除。"); await refresh(); } catch (e) { setStatus(e.message || "模型删除失败", true); } finally { setLoading(deleteModelBtn, false, "删除当前模型", "删除中..."); } }); } if (saveVipBtn) { saveVipBtn.addEventListener("click", async () => { setLoading(saveVipBtn, true, "保存 VIP 设置", "保存中..."); try { const enabled = (($("vipEnabledSelect") && $("vipEnabledSelect").value) || "0") === "1"; const out = await postJSON("/api/auth/vip/toggle", { enabled }); if (!out.ok) { setStatus(out.detail || "VIP 设置保存失败", true); return; } setStatus("VIP 设置已更新。"); await refresh(); } catch (e) { setStatus(e.message || "VIP 设置保存失败", true); } finally { setLoading(saveVipBtn, false, "保存 VIP 设置", "保存中..."); } }); } if (vipRechargeBtn) { vipRechargeBtn.addEventListener("click", async () => { setLoading(vipRechargeBtn, true, "充值 Token", "创建订单中..."); try { const tokens = Number((($("vipRechargeTokens") && $("vipRechargeTokens").value) || "0").trim()); if (!Number.isFinite(tokens) || tokens <= 0) { setStatus("请输入正确的充值数量", true); return; } const out = await postJSON("/api/pay/wechat/", { tokens: Math.round(tokens), amount_cny: Number((((Number(tokens) / 10000) * 9.9) || 9.9).toFixed(2)), channel: "wechat", }); if (!out.ok) { setStatus(out.detail || "充值失败", true); return; } if (out.pay_url) { window.open(out.pay_url, "_blank", "noopener"); setStatus("订单已创建,请在新窗口完成支付。"); } else { setStatus("订单已创建,但未获取到支付链接,请联系管理员配置购物系统。", true); } window.setTimeout(() => { window.location.href = "/billing"; }, 400); } catch (e) { setStatus(e.message || "充值失败", true); } finally { setLoading(vipRechargeBtn, false, "充值 Token", "创建订单中..."); } }); } if (logoutBtn) { logoutBtn.addEventListener("click", async () => { setLoading(logoutBtn, true, "退出登录", "退出中..."); try { await postJSON("/api/auth/logout", {}); window.location.href = "/auth?next=/"; } catch (e) { setStatus(e.message || "退出失败", true); } finally { setLoading(logoutBtn, false, "退出登录", "退出中..."); } }); } if (changePwdBtn) { changePwdBtn.addEventListener("click", async () => { setLoading(changePwdBtn, true, "修改密码", "提交中..."); try { const out = await postJSON("/api/auth/password/change", { old_password: ($("oldPassword") && $("oldPassword").value) || "", new_password: ($("newPassword") && $("newPassword").value) || "", }); if (!out.ok) { setStatus(out.detail || "修改密码失败", true); return; } setStatus("密码修改成功。"); if ($("oldPassword")) $("oldPassword").value = ""; if ($("newPassword")) $("newPassword").value = ""; } catch (e) { setStatus(e.message || "修改密码失败", true); } finally { setLoading(changePwdBtn, false, "修改密码", "提交中..."); } }); } if (deleteAccountBtn) { deleteAccountBtn.addEventListener("click", async () => { const pwd = ($("deletePassword") && $("deletePassword").value) || ""; const rkey = ($("deleteResetKey") && $("deleteResetKey").value.trim()) || ""; if (!pwd) { setStatus("请输入注销校验密码", true); return; } if (!rkey) { setStatus("请输入注销校验重置码", true); return; } const sure = await window.uiConfirm("确定注销账户吗?将清空此账号所有业务数据,操作不可恢复。", "注销账户"); if (!sure) return; const confirmText = await window.uiPrompt( "为防止误删,请输入「注销账户」后确认:", "二次确认", "", "请输入:注销账户", ); if ((confirmText || "").trim() !== "注销账户") { setStatus("二次确认未通过,已取消注销。", true); return; } setLoading(deleteAccountBtn, true, "注销账户", "注销中..."); try { const out = await postJSON("/api/auth/account/delete", { password: pwd, reset_key: rkey, }); if (!out.ok) { setStatus(out.detail || "注销失败", true); return; } setStatus("账号已注销,正在返回登录页。"); window.setTimeout(() => { window.location.href = "/auth?next=/"; }, 900); } catch (e) { setStatus(e.message || "注销失败", true); } finally { setLoading(deleteAccountBtn, false, "注销账户", "注销中..."); } }); } refresh();