77 lines
2.4 KiB
JavaScript
77 lines
2.4 KiB
JavaScript
"use strict";
|
||
/* ================= 网络层:服务端 API 客户端 ================= */
|
||
const NET = {
|
||
user: null, // {username,email}
|
||
stats: null, // {bossKills,endlessHigh,runs}
|
||
codexTotal: 62,
|
||
online: false,
|
||
|
||
async api(path, method, body) {
|
||
let res;
|
||
try {
|
||
res = await fetch(path, {
|
||
method: method || "GET",
|
||
credentials: "same-origin",
|
||
headers: body ? { "Content-Type": "application/json" } : undefined,
|
||
body: body ? JSON.stringify(body) : undefined,
|
||
});
|
||
} catch (e) {
|
||
return { ok: false, status: 0, data: { error: "无法连接服务器" } };
|
||
}
|
||
let data = {};
|
||
try { data = await res.json(); } catch (e) { /* 空响应 */ }
|
||
return { ok: res.ok, status: res.status, data };
|
||
},
|
||
|
||
/* 启动:尝试恢复会话。true=已登录(未登录时服务端返回 200 {user:null}) */
|
||
async boot() {
|
||
const r = await this.api("/api/me", "GET");
|
||
if (r.ok && r.data.user) { this._apply(r.data); return true; }
|
||
return false;
|
||
},
|
||
|
||
async login(id, password) {
|
||
const r = await this.api("/api/login", "POST", { id, password });
|
||
if (r.ok) { this._apply(r.data); return null; }
|
||
return r.data.error || "登陆失败";
|
||
},
|
||
|
||
async register(username, email, password) {
|
||
const r = await this.api("/api/register", "POST", { username, email, password });
|
||
if (r.ok) { this._apply(r.data); return null; }
|
||
return r.data.error || "注册失败";
|
||
},
|
||
|
||
async logout() {
|
||
await this.api("/api/logout", "POST");
|
||
this.user = null; this.stats = null; this.online = false;
|
||
},
|
||
|
||
/* 应用服务端返回的用户数据:同步图鉴解锁到本地存档(并集) */
|
||
_apply(d) {
|
||
this.user = d.user;
|
||
this.stats = d.stats;
|
||
this.codexTotal = d.codexTotal || 62;
|
||
this.online = true;
|
||
if (Array.isArray(d.codex)) {
|
||
SAVE.codex = SAVE.codex || {};
|
||
for (const k of d.codex) SAVE.codex[k] = true;
|
||
persist();
|
||
}
|
||
},
|
||
|
||
/* 结算上报(fire-and-forget):成功后回写最新统计 */
|
||
submitRun(payload) {
|
||
if (!this.user) return;
|
||
this.api("/api/run", "POST", payload).then((r) => {
|
||
if (r.ok) {
|
||
this.stats = r.data.stats;
|
||
if (Array.isArray(r.data.codex)) {
|
||
for (const k of r.data.codex) SAVE.codex[k] = true;
|
||
persist();
|
||
}
|
||
}
|
||
}).catch(() => { /* 网络失败静默:本地存档仍在 */ });
|
||
},
|
||
};
|