feat(qoder): 适配国际版每日签到 — UMID 设备风控身份 + 国际版活动 schema
核心发现(实测): - Qoder 国际版服务端只对带 Cosy-MachineToken/Code/Type 的请求下发签到活动, 否则 campaigns 返回空数组(国内版无此限制) - 国际版活动 actionType=VIEW_DETAILS(国内版 CLAIM_BENEFIT),claimStatus 一致 - 活动窗口 2026-09-01~10-31,每日 10:00 (UTC+8) 刷新,领取后 30 天有效 实现: - 新增 umid.py:从官方 npm 包 @qoder-ai/qodercli 下载并提取内嵌 UMID 二进制 (x86_64/arm64 ELF),试跑校验后缓存到 @appdata/AgentCheckin/umid/ - qoder.py:签到前自动确保风控身份,支持国际版/国内版双 schema 活动解析 - API:/api/umid/status、/api/umid/install、/api/accounts/refresh_risk - 前端:设置页风控身份面板(下载/状态)、账号列表「刷新风控」按钮 - 诊断:测连接返回 risk_identity / campaigns_debug(原始字段) 验证:NAS 实测 Qoder 国际版从「活动列表为空」变为「今日已领取(75 积分)」 测试:37 后端 + 25 E2E + 9 前端,全部通过
This commit is contained in:
@@ -209,7 +209,8 @@
|
||||
"<td>" + (a.enabled ? "启用" : "禁用") + "</td>" +
|
||||
'<td class="actions">' +
|
||||
'<button class="btn btn-sm" data-a2="run" data-id="' + esc(a.id) + '">签到</button>' +
|
||||
(a.platform === "qoder" ? '<button class="btn btn-sm" data-a2="fixdomain" data-id="' + esc(a.id) + '" title="自动探测 Token 所属站点并切换">修复站点</button>' : "") +
|
||||
(a.platform === "qoder" ? '<button class="btn btn-sm" data-a2="fixdomain" data-id="' + esc(a.id) + '" title="自动探测 Token 所属站点并切换">修复站点</button>' +
|
||||
'<button class="btn btn-sm" data-a2="risk" data-id="' + esc(a.id) + '" title="重新生成设备风控身份(活动列表为空时使用)">刷新风控</button>' : "") +
|
||||
'<button class="btn btn-sm" data-a2="toggle" data-id="' + esc(a.id) + '">' + (a.enabled ? "禁用" : "启用") + "</button>" +
|
||||
'<button class="btn btn-sm btn-danger" data-a2="del" data-id="' + esc(a.id) + '">删除</button>' +
|
||||
"</td></tr>";
|
||||
@@ -219,6 +220,16 @@
|
||||
btn.addEventListener("click", function () {
|
||||
var id = btn.dataset.id, act = btn.dataset.a2;
|
||||
if (act === "run") runCheckin(id, btn);
|
||||
else if (act === "risk") {
|
||||
btn.disabled = true; btn.textContent = "生成中…";
|
||||
api("POST", "/accounts/refresh_risk", { id: id })
|
||||
.then(function (d) {
|
||||
if (d.ok) { toast("风控身份已更新", "ok"); refreshState(); }
|
||||
else { toast(d.error || "生成失败", "err"); }
|
||||
})
|
||||
.catch(function (e) { toast(e.message, "err"); })
|
||||
.finally(function () { btn.disabled = false; btn.textContent = "刷新风控"; });
|
||||
}
|
||||
else if (act === "fixdomain") {
|
||||
btn.disabled = true; btn.textContent = "探测中…";
|
||||
api("POST", "/accounts/fix_domain", { id: id })
|
||||
@@ -398,12 +409,52 @@
|
||||
var settings = null;
|
||||
var settingsDirty = false;
|
||||
|
||||
function loadUmidStatus() {
|
||||
api("GET", "/umid/status").then(function (d) {
|
||||
var el = $("umid-status");
|
||||
if (!el) return;
|
||||
if (!d.supported) {
|
||||
el.textContent = "当前 CPU 架构 " + d.cpu_arch + " 暂不支持自动生成(需 x86_64 / arm64)";
|
||||
} else if (d.installed) {
|
||||
el.textContent = "✅ 已安装 v" + d.version + "(" + d.arch + ",安装于 " + (d.installedAt || "-") + ")";
|
||||
} else {
|
||||
el.textContent = "⚠️ 未安装 —— 点击下方按钮下载(约 30MB)";
|
||||
}
|
||||
}).catch(function () {});
|
||||
}
|
||||
|
||||
var umidBtn = $("btn-umid-install");
|
||||
if (umidBtn) {
|
||||
umidBtn.addEventListener("click", function () {
|
||||
umidBtn.disabled = true;
|
||||
umidBtn.textContent = "下载中(约 1-3 分钟)…";
|
||||
$("umid-msg").textContent = "";
|
||||
$("umid-msg").className = "msg";
|
||||
api("POST", "/umid/install", { force: true })
|
||||
.then(function (d) {
|
||||
$("umid-msg").textContent = d.message || (d.ok ? "已安装" : "失败");
|
||||
$("umid-msg").className = "msg " + (d.ok ? "ok" : "err");
|
||||
toast(d.ok ? "风控组件已就绪" : (d.message || "下载失败"), d.ok ? "ok" : "err");
|
||||
loadUmidStatus();
|
||||
})
|
||||
.catch(function (e) {
|
||||
$("umid-msg").textContent = e.message;
|
||||
$("umid-msg").className = "msg err";
|
||||
})
|
||||
.finally(function () {
|
||||
umidBtn.disabled = false;
|
||||
umidBtn.textContent = "下载 / 重新获取风控组件";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openSettingsTab() {
|
||||
if (!settingsDirty) {
|
||||
settings = JSON.parse(JSON.stringify(
|
||||
(state && state.settings) || { schedule_times: [], webhook_url: "", notify_on: [] }));
|
||||
}
|
||||
renderSettings();
|
||||
loadUmidStatus();
|
||||
}
|
||||
|
||||
function renderSettings() {
|
||||
|
||||
Reference in New Issue
Block a user