diff --git a/assets/js/credits.js b/assets/js/credits.js
index 493b91b4..970bf324 100644
--- a/assets/js/credits.js
+++ b/assets/js/credits.js
@@ -2,7 +2,7 @@
* AKSRT Credits Frontend
*
* 功能:
- * - 签到 panel:拉取 /signin/today,按钮触发 POST /signin
+ * - 签到 panel:跳转至全局签到按钮
* - revenue panel:拉取 /revenue/me,复制推广链接
*
* 仅在 page-profile 页面 + 启用积分时加载。
@@ -15,7 +15,6 @@
return;
}
var activePoll = null;
- var signinBusy = false;
function api(path, options) {
return window.AksrtRequest.request(path, options || {}).then(function (response) {
@@ -35,168 +34,6 @@
});
}
- // ===== 签到 =====
- function initSignin() {
- var buttons = Array.prototype.slice.call(document.querySelectorAll('[data-signin-btn]'));
- var freshButtons = buttons.filter(function (button) {
- return button.dataset.aksrtSigninInitialized !== '1';
- });
- if (!freshButtons.length) return;
- freshButtons.forEach(function (button) {
- button.dataset.aksrtSigninInitialized = '1';
- });
-
- function statuses() {
- return document.querySelectorAll('[data-signin-status]');
- }
-
- function currentButtons() {
- return document.querySelectorAll('[data-signin-btn]');
- }
-
- function setStatus(text) {
- statuses().forEach(function (status) { status.textContent = text; });
- }
-
- function setStatusHtml(html) {
- statuses().forEach(function (status) { status.innerHTML = html; });
- }
-
- function setButtonState(state) {
- currentButtons().forEach(function (button) {
- var label = button.querySelector('[data-signin-label]');
- var text = state === 'done'
- ? button.getAttribute('data-signin-done-label') || '已签到'
- : (state === 'busy' ? '…' : button.getAttribute('data-signin-idle-label') || '签到');
- if (label) label.textContent = text;
- button.disabled = state !== 'idle';
- button.classList.toggle('is-done', state === 'done');
- });
- }
-
- function refresh() {
- api('/signin/today').then(function (r) {
- if (!r.ok) {
- var message = (r.json && r.json.message) || '签到状态加载失败 (HTTP ' + r.status + ')';
- setStatus(message);
- notyf(message, 'danger');
- return;
- }
- var j = r.json;
- if (!j.enabled) {
- setStatus('签到功能未启用');
- setButtonState('done');
- return;
- }
- if (j.signed) {
- setStatusHtml('已签到 ' + j.streak + ' 天 +' + j.reward_today);
- setButtonState('done');
- } else {
- setStatusHtml('连续 ' + j.streak + ' 天,+' + j.reward_if_signin);
- setButtonState('idle');
- }
- }).catch(function (err) {
- if (window.console) console.error('[AKSRT Credits] /signin/today 请求失败:', err);
- setStatus('加载失败,请刷新重试');
- notyf('签到状态加载失败,请刷新重试', 'danger');
- });
- }
-
- function collectCaptcha() {
- var el = document.querySelector('[data-signin-captcha]');
- if (!el) return {};
- var out = {};
- var keys = [
- 'captcha_verified', 'cf_turnstile_response',
- 'tencent_ticket', 'tencent_randstr', 'tencent_sid',
- 'geetest_lot_number', 'geetest_captcha_output', 'geetest_pass_token', 'geetest_gen_time',
- 'aliyun_captcha_verify_param',
- ];
- keys.forEach(function (k) {
- var inp = el.querySelector('input[name="' + k + '"]');
- if (inp && inp.value !== '') out[k] = inp.value;
- });
- return out;
- }
-
- function resetCaptcha() {
- try {
- var state = window.AKSRTCaptchaState;
- var scene = state && state.scenes && state.scenes.signin;
- if (scene && typeof scene.reset === 'function') scene.reset();
- } catch (_) {}
- }
-
- function triggerCaptcha(onSuccess, onFail) {
- var mount = document.querySelector('[data-signin-captcha]');
- var state = window.AKSRTCaptchaState;
- var scene = state && state.scenes && state.scenes.signin;
-
- if (scene && typeof scene.verify === 'function') {
- scene.verify(function (ok) {
- if (ok === false) {
- if (typeof onFail === 'function') onFail('已取消验证');
- return;
- }
- onSuccess();
- });
- return;
- }
-
- if (mount) {
- if (typeof onFail === 'function') onFail('人机验证加载中,请稍候再试');
- return;
- }
-
- onSuccess();
- }
-
- freshButtons.forEach(function (button) {
- button.addEventListener('click', function () {
- if (signinBusy) return;
- signinBusy = true;
- setButtonState('busy');
-
- triggerCaptcha(function () {
- doSignin();
- }, function (msg) {
- signinBusy = false;
- resetCaptcha();
- if (msg) notyf(msg, 'danger');
- setButtonState('idle');
- });
- });
- });
-
- function doSignin() {
- notyf('正在签到…', 'load', '', 'aksrt-balance-signin-toast');
- api('/signin', {
- method: 'POST',
- body: JSON.stringify({ captcha: collectCaptcha() })
- }).then(function (r) {
- signinBusy = false;
- if (!r.ok) {
- resetCaptcha();
- notyf((r.json && r.json.message) || '签到失败', 'danger', 5, 'aksrt-balance-signin-toast');
- setButtonState('idle');
- return;
- }
- notyf(r.json.message || '签到成功', 'success', 5, 'aksrt-balance-signin-toast');
- var balanceEls = document.querySelectorAll('[data-credits-value]');
- balanceEls.forEach(function (el) { el.textContent = r.json.balance.toLocaleString(); });
- setButtonState('done');
- refresh();
- }).catch(function () {
- signinBusy = false;
- resetCaptcha();
- notyf('网络错误,请重试', 'danger', 5, 'aksrt-balance-signin-toast');
- setButtonState('idle');
- });
- }
-
- refresh();
- }
-
// Task-list "去签到" → scroll + click the real asset-card sign-in button.
function initSigninGoto() {
document.querySelectorAll('[data-aksrt-signin-goto]').forEach(function (el) {
@@ -857,7 +694,6 @@
window.AKSRTWithdrawInit = initWithdraw;
function bootAssets() {
- initSignin();
initSigninGoto();
initAffiliateRevenue();
initVipShop();
@@ -879,7 +715,6 @@
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('credits', function () {
- initSignin();
initSigninGoto();
initBalanceCharge();
initTransfer();
diff --git a/assets/js/signin.js b/assets/js/signin.js
new file mode 100644
index 00000000..adba6991
--- /dev/null
+++ b/assets/js/signin.js
@@ -0,0 +1,200 @@
+/**
+ * AKSRT global sign-in controller.
+ *
+ * All sign-in buttons share one REST request, captcha and toast flow.
+ */
+(function () {
+ 'use strict';
+
+ if (!window.aksrtData || !window.AksrtRequest) {
+ return;
+ }
+
+ var signinBusy = false;
+
+ function api(path, options) {
+ return window.AksrtRequest.request(path, options || {}).then(function (response) {
+ return {
+ ok: response.ok,
+ status: response.status,
+ json: response.json || {}
+ };
+ }).catch(function (error) {
+ var response = error && error.response ? error.response : {};
+ return {
+ ok: false,
+ status: error && error.status ? error.status : (response.status || 0),
+ json: error && error.json ? error.json : (response.json || { message: error && error.message })
+ };
+ });
+ }
+
+ function initSignin() {
+ var buttons = Array.prototype.slice.call(document.querySelectorAll('[data-signin-btn]'));
+ var freshButtons = buttons.filter(function (button) {
+ return button.dataset.aksrtSigninInitialized !== '1';
+ });
+ if (!freshButtons.length) return;
+
+ freshButtons.forEach(function (button) {
+ button.dataset.aksrtSigninInitialized = '1';
+ });
+
+ function statuses() {
+ return document.querySelectorAll('[data-signin-status]');
+ }
+
+ function currentButtons() {
+ return document.querySelectorAll('[data-signin-btn]');
+ }
+
+ function setStatus(text) {
+ statuses().forEach(function (status) {
+ status.textContent = text;
+ });
+ }
+
+ function setStatusHtml(html) {
+ statuses().forEach(function (status) {
+ status.innerHTML = html;
+ });
+ }
+
+ function setButtonState(state) {
+ currentButtons().forEach(function (button) {
+ var label = button.querySelector('[data-signin-label]');
+ var text = state === 'done'
+ ? button.getAttribute('data-signin-done-label') || '已签到'
+ : (state === 'busy' ? '…' : button.getAttribute('data-signin-idle-label') || '签到');
+ if (label) label.textContent = text;
+ button.disabled = state !== 'idle';
+ button.classList.toggle('is-done', state === 'done');
+ });
+ }
+
+ function refresh() {
+ api('/signin/today').then(function (result) {
+ if (!result.ok) {
+ var message = (result.json && result.json.message) || '签到状态加载失败 (HTTP ' + result.status + ')';
+ setStatus(message);
+ notyf(message, 'danger');
+ return;
+ }
+
+ var data = result.json;
+ if (!data.enabled) {
+ setStatus('签到功能未启用');
+ setButtonState('done');
+ return;
+ }
+ if (data.signed) {
+ setStatusHtml('已签到 ' + data.streak + ' 天 +' + data.reward_today);
+ setButtonState('done');
+ return;
+ }
+ setStatusHtml('连续 ' + data.streak + ' 天,+' + data.reward_if_signin);
+ setButtonState('idle');
+ });
+ }
+
+ function captchaMount() {
+ return document.querySelector('[data-signin-captcha]');
+ }
+
+ function collectCaptcha() {
+ var mount = captchaMount();
+ if (!mount) return {};
+ var payload = {};
+ var keys = [
+ 'captcha_verified', 'cf_turnstile_response',
+ 'tencent_ticket', 'tencent_randstr', 'tencent_sid',
+ 'geetest_lot_number', 'geetest_captcha_output', 'geetest_pass_token', 'geetest_gen_time',
+ 'aliyun_captcha_verify_param'
+ ];
+ keys.forEach(function (key) {
+ var input = mount.querySelector('input[name="' + key + '"]');
+ if (input && input.value !== '') payload[key] = input.value;
+ });
+ return payload;
+ }
+
+ function resetCaptcha() {
+ var state = window.AKSRTCaptchaState;
+ var scene = state && state.scenes && state.scenes.signin;
+ if (scene && typeof scene.reset === 'function') scene.reset();
+ }
+
+ function triggerCaptcha(onSuccess, onFail) {
+ var mount = captchaMount();
+ var state = window.AKSRTCaptchaState;
+ var scene = state && state.scenes && state.scenes.signin;
+
+ if (scene && typeof scene.verify === 'function') {
+ scene.verify(function (ok) {
+ if (ok === false) {
+ onFail('已取消验证');
+ return;
+ }
+ onSuccess();
+ });
+ return;
+ }
+ if (mount) {
+ onFail('人机验证加载中,请稍候再试');
+ return;
+ }
+ onSuccess();
+ }
+
+ function doSignin() {
+ notyf('正在签到…', 'load', '', 'aksrt-balance-signin-toast');
+ api('/signin', {
+ method: 'POST',
+ body: JSON.stringify({ captcha: collectCaptcha() })
+ }).then(function (result) {
+ signinBusy = false;
+ if (!result.ok) {
+ resetCaptcha();
+ notyf((result.json && result.json.message) || '签到失败', 'danger', 5, 'aksrt-balance-signin-toast');
+ setButtonState('idle');
+ return;
+ }
+
+ notyf(result.json.message || '签到成功', 'success', 5, 'aksrt-balance-signin-toast');
+ document.querySelectorAll('[data-credits-value]').forEach(function (element) {
+ element.textContent = Number(result.json.balance || 0).toLocaleString();
+ });
+ setButtonState('done');
+ refresh();
+ });
+ }
+
+ freshButtons.forEach(function (button) {
+ button.addEventListener('click', function (event) {
+ event.preventDefault();
+ if (signinBusy || button.disabled) return;
+
+ signinBusy = true;
+ setButtonState('busy');
+ triggerCaptcha(doSignin, function (message) {
+ signinBusy = false;
+ resetCaptcha();
+ if (message) notyf(message, 'danger');
+ setButtonState('idle');
+ });
+ });
+ });
+
+ refresh();
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', initSignin);
+ } else {
+ initSignin();
+ }
+
+ if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
+ window.AksrtFrontend.register('signin', initSignin);
+ }
+})();
diff --git a/inc/helpers/aksrt-header-userbox.php b/inc/helpers/aksrt-header-userbox.php
index b9ce29e3..d0651ca0 100644
--- a/inc/helpers/aksrt-header-userbox.php
+++ b/inc/helpers/aksrt-header-userbox.php
@@ -9,7 +9,7 @@ defined('ABSPATH') || exit;
if (!function_exists('aksrt_header_user_checkin_btn')) :
/**
- * Check-in CTA for header dropdown and compact card placements (uses REST /aksrt/v1/signin).
+ * Check-in CTA for header dropdown and compact card placements.
*
* @param int $user_id Current user ID.
* @param bool $compact Render a short card-friendly label.
@@ -26,37 +26,48 @@ if (!function_exists('aksrt_header_user_checkin_btn')) :
return '';
}
- // Lightweight today status via private API if available.
- $signed = false;
- try {
- $signin = \AKSRT\Credits\Signin::get_instance();
- // Prefer public method if present.
- if (method_exists($signin, 'is_signed_today')) {
- $signed = (bool) $signin->is_signed_today($user_id);
- } else {
- // Fallback: direct meta/table probe via rest_today logic is heavy; use option day key.
- $day = wp_date('Y-m-d');
- $signed = (bool) get_user_meta($user_id, 'aksrt_signin_' . $day, true);
- }
- } catch (\Throwable $e) {
- $signed = false;
- }
+ $signed = \AKSRT\Credits\Signin::get_instance()->is_signed_today($user_id);
$compact_class = $compact ? ' aksrt-header-checkin--compact' : '';
if ($signed) {
- return '