diff --git a/assets/css/routes/user-center/shell.css b/assets/css/routes/user-center/shell.css index c17db312..aa45bd2c 100644 --- a/assets/css/routes/user-center/shell.css +++ b/assets/css/routes/user-center/shell.css @@ -124,16 +124,30 @@ body.aksrt-user-center .uc-content, .uc-header__actions { position: relative; + display: flex; + align-items: center; + gap: 6px; +} + +.uc-header__signin-btn.is-done { + color: var(--color-success, #10b981); +} + +.uc-header__message-btn { + position: relative; } .uc-header__action-badge { + position: absolute; + top: -5px; + right: -5px; display: inline-flex; align-items: center; justify-content: center; - min-width: 18px; - height: 18px; - margin-left: 6px; - padding: 0 5px; + min-width: 16px; + height: 16px; + margin: 0; + padding: 0 4px; border-radius: 999px; background: var(--color-error, #ef4444); color: #fff; diff --git a/assets/js/credits.js b/assets/js/credits.js index 223db5cf..493b91b4 100644 --- a/assets/js/credits.js +++ b/assets/js/credits.js @@ -15,6 +15,7 @@ return; } var activePoll = null; + var signinBusy = false; function api(path, options) { return window.AksrtRequest.request(path, options || {}).then(function (response) { @@ -36,15 +37,42 @@ // ===== 签到 ===== function initSignin() { - var root = document.querySelector('[data-aksrt-signin]'); - if (!root || root.dataset.aksrtSigninInitialized === '1') return; - root.dataset.aksrtSigninInitialized = '1'; - var status = root.querySelector('[data-signin-status]'); - var btn = root.querySelector('[data-signin-btn]'); - if (!btn) return; + 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 setStatus(text) { if (status) status.textContent = text; } - function setStatusHtml(html) { if (status) status.innerHTML = html; } + 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) { @@ -57,16 +85,15 @@ var j = r.json; if (!j.enabled) { setStatus('签到功能未启用'); - btn.disabled = true; + setButtonState('done'); return; } if (j.signed) { setStatusHtml('已签到 ' + j.streak + ' 天 +' + j.reward_today); - btn.disabled = true; - btn.innerHTML = '已签到'; + setButtonState('done'); } else { setStatusHtml('连续 ' + j.streak + ' 天,+' + j.reward_if_signin); - btn.disabled = false; + setButtonState('idle'); } }).catch(function (err) { if (window.console) console.error('[AKSRT Credits] /signin/today 请求失败:', err); @@ -124,45 +151,49 @@ onSuccess(); } - btn.addEventListener('click', function () { - btn.disabled = true; - btn.innerHTML = '…'; + freshButtons.forEach(function (button) { + button.addEventListener('click', function () { + if (signinBusy) return; + signinBusy = true; + setButtonState('busy'); - triggerCaptcha(function () { - doSignin(); - }, function (msg) { - resetCaptcha(); - if (msg) notyf(msg, 'danger'); - btn.disabled = false; - btn.innerHTML = '签到'; - }); - - function doSignin() { - notyf('正在签到…', 'load', '', 'aksrt-balance-signin-toast'); - api('/signin', { - method: 'POST', - body: JSON.stringify({ captcha: collectCaptcha() }) - }).then(function (r) { - if (!r.ok) { - resetCaptcha(); - notyf((r.json && r.json.message) || '签到失败', 'danger', 5, 'aksrt-balance-signin-toast'); - btn.disabled = false; - btn.innerHTML = '签到'; - return; - } - notyf('签到成功,获得 ' + r.json.reward + ' 积分(连续 ' + r.json.streak + ' 天)', 'success', 5, 'aksrt-balance-signin-toast'); - var balanceEls = document.querySelectorAll('[data-credits-value]'); - balanceEls.forEach(function (el) { el.textContent = r.json.balance.toLocaleString(); }); - refresh(); - }).catch(function () { + triggerCaptcha(function () { + doSignin(); + }, function (msg) { + signinBusy = false; resetCaptcha(); - notyf('网络错误,请重试', 'danger', 5, 'aksrt-balance-signin-toast'); - btn.disabled = false; - btn.innerHTML = '签到'; + 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(); } diff --git a/inc/helpers/aksrt-user-center.php b/inc/helpers/aksrt-user-center.php index 9f791ab2..9df9bac5 100644 --- a/inc/helpers/aksrt-user-center.php +++ b/inc/helpers/aksrt-user-center.php @@ -496,6 +496,13 @@ if (!function_exists('aksrt_get_user_center_render_context')) { $currency_name = (string) ($dashboard['currency_name'] ?? __('积分', 'aksrt')); $balance_enabled = (bool) ($dashboard['balance_enabled'] ?? false); $wallet_balance = (float) ($dashboard['wallet_balance'] ?? 0.0); + $signin_settings = class_exists('\AKSRT\Settings\Settings') + ? \AKSRT\Settings\Settings::get_signin_reward_settings() + : ['enabled' => false]; + $signin_enabled = !empty($signin_settings['enabled']) && class_exists('\AKSRT\Credits\Signin'); + $signin_signed_today = $signin_enabled + ? \AKSRT\Credits\Signin::get_instance()->is_signed_today($user_id) + : false; $runtime_config = aksrt_user_center_runtime_config($user_id, $tabs['default'], $active_tab, $tabs['urls']); $runtime_config['avatarUpload'] = aksrt_user_center_avatar_upload_config($allow_avatar_upload); @@ -539,6 +546,8 @@ if (!function_exists('aksrt_get_user_center_render_context')) { 'currency_name' => $currency_name, 'credit_balance' => (float) ($dashboard['credit_balance'] ?? 0.0), 'credits_enabled' => $show_credit_tabs, + 'signin_enabled' => $signin_enabled, + 'signin_signed_today' => $signin_signed_today, 'balance_enabled' => $balance_enabled, 'wallet_balance' => $wallet_balance, 'vip_settings' => $vip_settings, diff --git a/inc/helpers/user-center-renderers/credits-balance.php b/inc/helpers/user-center-renderers/credits-balance.php index 1b7e4b95..f38e3e28 100644 --- a/inc/helpers/user-center-renderers/credits-balance.php +++ b/inc/helpers/user-center-renderers/credits-balance.php @@ -34,12 +34,14 @@ $currency = (string) ($currency_name ?? __('积分', 'aksrt'));