feat: redesign promotion earnings cards

This commit is contained in:
2026-08-16 20:15:56 +08:00
parent 6dbb556d60
commit 8799063c6c
7 changed files with 260 additions and 82 deletions
@@ -12,8 +12,6 @@ export const affiliateSchema = {
affiliate_allow_self_purchase: false,
affiliate_show_stats: true,
affiliate_promotion_text: '',
affiliate_earnings_text: '',
affiliate_withdrawal_agreement: '',
affiliate_payout_channels: ['alipay', 'wechat'],
affiliate_min_withdrawal: 50,
affiliate_withdrawal_fee: 5,
@@ -55,8 +53,6 @@ export const affiliateSchema = {
icon: 'fas fa-pen-fancy',
fields: [
{ key: 'affiliate_promotion_text', label: '推广说明', type: 'textarea', default: '', dependsOn: { key: 'affiliate_enabled', value: true } },
{ key: 'affiliate_earnings_text', label: '收益说明', type: 'textarea', default: '', dependsOn: { key: 'affiliate_enabled', value: true } },
{ key: 'affiliate_withdrawal_agreement', label: '提现协议', type: 'textarea', default: '', dependsOn: { key: 'affiliate_enabled', value: true } },
],
},
],
+235 -6
View File
@@ -87,9 +87,238 @@
.uc-content .uc-affiliate-stats article strong { color:var(--primary,#2563eb); font-size:24px; font-variant-numeric:tabular-nums; }
.uc-content .uc-affiliate-link-card [data-affiliate-feedback] { grid-column:1/-1; margin:0; min-height:18px; color:var(--success,#16a34a); font-size:12px; }
.uc-content .uc-affiliate-link-card [data-affiliate-feedback].is-error { color:var(--danger,#dc2626); }
.uc-content .uc-affiliate-accounts { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; padding-top:4px; }
.uc-content .uc-affiliate-accounts label { display:grid; gap:5px; color:var(--muted,#6b7280); font-size:12px; }
.uc-content .uc-affiliate-accounts input { height:38px; padding:0 10px; border:1px solid var(--border,#e5e7eb); border-radius:8px; background:var(--surface,#fff); color:var(--text,#111827); }
.uc-content .uc-affiliate-accounts button { justify-self:start; }
.uc-content .uc-affiliate-accounts p { grid-column:1/-1; margin:0; color:var(--success,#16a34a); font-size:12px; }
@media (max-width:640px) { .uc-content .aksrt-affiliate-panel { padding:16px; } .uc-content .uc-affiliate-link-card { align-items:stretch; flex-direction:column; } .uc-content .uc-affiliate-link-card button { width:100%; } .uc-content .uc-affiliate-stats,.uc-content .uc-affiliate-accounts { grid-template-columns:1fr; } }
@media (max-width:640px) { .uc-content .aksrt-affiliate-panel { padding:16px; } .uc-content .uc-affiliate-link-card { align-items:stretch; flex-direction:column; } .uc-content .uc-affiliate-link-card button { width:100%; } .uc-content .uc-affiliate-stats { grid-template-columns:1fr; } }
/* 推广收益新版布局:顶部概览卡 + 单一推荐奖励白卡。 */
.uc-content .uc-revenue-panel {
gap: 22px;
}
.uc-content .uc-commission-summary {
gap: 18px;
}
.uc-content .uc-commission-card {
min-height: 174px;
padding: 24px 26px;
border: 0;
border-radius: 18px;
box-shadow: 0 12px 28px rgba(15, 23, 42, .08);
}
.uc-content .uc-commission-card--ratio {
color: #fff;
background:
radial-gradient(circle at 86% 4%, rgba(255, 255, 255, .16) 0 22%, transparent 22.5%),
radial-gradient(circle at 32% 110%, rgba(213, 37, 43, .28) 0 42%, transparent 42.5%),
linear-gradient(135deg, #ff6d61 0%, #ff3e3e 100%);
}
.uc-content .uc-commission-card--balance {
color: #fff;
background:
radial-gradient(circle at 14% 96%, rgba(11, 103, 204, .2) 0 44%, transparent 44.5%),
radial-gradient(circle at 100% 100%, rgba(255, 255, 255, .12) 0 28%, transparent 28.5%),
linear-gradient(135deg, #48b7ee 0%, #2b8fe8 100%);
}
.uc-content .uc-commission-card__body {
display: grid;
align-content: space-between;
min-height: 126px;
}
.uc-content .uc-commission-card__body > span,
.uc-content .uc-commission-card__body > p,
.uc-content .uc-commission-card__body strong,
.uc-content .uc-commission-card__body strong small {
color: inherit;
}
.uc-content .uc-commission-card__body > span:first-child {
margin: 0;
font-size: 18px;
font-weight: 700;
}
.uc-content .uc-commission-card__body strong {
font-size: 42px;
line-height: 1;
}
.uc-content .uc-commission-card__body strong small {
margin-left: 4px;
font-size: 18px;
}
.uc-content .uc-commission-card__body > span:last-child,
.uc-content .uc-commission-card__body > p {
margin: 0;
font-size: 14px;
opacity: .92;
}
.uc-content .uc-commission-card--ratio .uc-commission-card__body strong {
color: inherit;
}
.uc-content .uc-commission-card__action {
align-self: center;
margin-left: auto;
padding: 10px 16px;
border: 0;
border-radius: 999px;
color: #fff;
background: rgba(255, 255, 255, .14);
font-size: 14px;
backdrop-filter: blur(4px);
}
.uc-content .uc-commission-card__action:hover {
background: rgba(255, 255, 255, .24);
}
.uc-content .aksrt-affiliate-panel {
gap: 24px;
padding: 34px 44px 38px;
border: 0;
border-radius: 18px;
background: var(--surface-1, #fff);
box-shadow: 0 8px 26px rgba(15, 23, 42, .06);
}
.uc-content .uc-panel-heading {
padding-bottom: 20px;
border-bottom: 1px solid var(--color-line-soft, rgba(15, 23, 42, .08));
}
.uc-content .uc-panel-heading h2 {
display: inline-block;
position: relative;
margin: 0 0 10px;
font-size: 20px;
}
.uc-content .uc-panel-heading h2::after {
position: absolute;
right: 0;
bottom: -11px;
left: 0;
height: 3px;
border-radius: 999px;
background: #f1498c;
content: "";
}
.uc-content .uc-panel-heading p {
font-size: 16px;
}
.uc-content .uc-affiliate-link-card {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 12px;
padding: 0;
background: transparent;
}
.uc-content .uc-affiliate-link-card > div {
display: contents;
}
.uc-content .uc-affiliate-link-card > div > span {
color: var(--color-ink-4);
font-size: 15px;
}
.uc-content .uc-affiliate-link-card input {
height: 42px;
border: 0;
border-radius: 7px;
color: #ef5370;
background: #fff0f2;
font-size: 15px;
}
.uc-content .uc-affiliate-link-card button {
min-height: 42px;
border-radius: 7px;
white-space: nowrap;
}
.uc-content .uc-affiliate-link-card [data-affiliate-feedback] {
grid-column: 2 / -1;
}
.uc-content .uc-affiliate-stats {
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
}
.uc-content .uc-affiliate-stats article {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 48px;
padding: 0 14px;
border: 0;
border-radius: 8px;
background: var(--surface-2, #f7f8fa);
}
.uc-content .uc-affiliate-stats article strong {
color: var(--color-primary);
font-size: 16px;
}
.uc-content .uc-affiliate-stats article:first-child strong {
color: #e94568;
}
.uc-content .uc-affiliate-note {
margin-top: -8px;
font-size: 13px;
}
@media (max-width: 720px) {
.uc-content .uc-commission-summary {
grid-template-columns: 1fr;
}
.uc-content .aksrt-affiliate-panel {
padding: 24px 20px 28px;
}
}
@media (max-width: 560px) {
.uc-content .uc-commission-card {
min-height: 150px;
padding: 20px;
}
.uc-content .uc-commission-card__body {
min-height: 108px;
}
.uc-content .uc-commission-card__body strong {
font-size: 36px;
}
.uc-content .uc-affiliate-link-card {
grid-template-columns: 1fr;
}
.uc-content .uc-affiliate-link-card > div {
display: grid;
gap: 6px;
}
.uc-content .uc-affiliate-link-card [data-affiliate-feedback] {
grid-column: 1;
}
.uc-content .uc-affiliate-stats {
grid-template-columns: 1fr;
}
}
-7
View File
@@ -407,13 +407,6 @@
if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(input.value).then(done).catch(function () { input.focus(); input.select(); setFeedback('复制失败,请手动复制。', true); });
else { input.focus(); input.select(); try { document.execCommand('copy'); done(); } catch (e) { setFeedback('复制失败,请手动复制。', true); } }
});
var accountForm = root.querySelector('[data-affiliate-accounts]');
if (accountForm) accountForm.addEventListener('submit', function (event) {
event.preventDefault();
var feedback = accountForm.querySelector('[data-affiliate-account-feedback]');
var accounts = {}; new FormData(accountForm).forEach(function (value, key) { if (String(value).trim()) accounts[key] = String(value).trim(); });
api('/promotion/payout-accounts', { method: 'PUT', body: JSON.stringify({ accounts: accounts }) }).then(function (r) { if (feedback) feedback.textContent = r.ok ? '收款方式已保存。' : ((r.json && r.json.message) || '保存失败。'); }).catch(function () { if (feedback) feedback.textContent = '网络错误,请稍后重试。'; });
});
}
window.AKSRTAffiliatePromotionInit = initAffiliatePromotion;
@@ -39,7 +39,7 @@ $available_commission = class_exists('\AKSRT\Credits\Balance')
: (float) ($commission_stats['settled'] ?? 0);
$vip_ratios = [];
$commission_ratio = (float) ($affiliate['ratio'] ?? 0);
$details_text = trim((string) ($affiliate['earnings_text'] ?? ''));
$details_text = trim((string) ($affiliate['promotion_text'] ?? ''));
if ($details_text === '') {
$details_text = __('好友通过推广链接完成符合条件的订单后,系统会按当前佣金比例记录返佣,结算后进入可提现余额。', 'aksrt');
}
@@ -85,9 +85,28 @@ $status_labels = [
];
?>
<div class="aksrt-revenue-page uc-revenue-panel" data-aksrt-revenue-page data-min-amount="<?php echo esc_attr((string) $withdraw_min); ?>">
<section class="uc-commission-summary" aria-label="<?php esc_attr_e('佣金概览', 'aksrt'); ?>">
<article class="uc-commission-card uc-commission-card--ratio">
<div class="uc-commission-card__body">
<span><?php esc_html_e('佣金比例', 'aksrt'); ?></span>
<strong><?php echo esc_html((string) $commission_ratio); ?><small>%</small></strong>
<p><?php echo $commission_ratio > 0 ? esc_html__('普通用户推广订单返佣比例', 'aksrt') : esc_html__('暂未参与', 'aksrt'); ?></p>
</div>
</article>
<article class="uc-commission-card uc-commission-card--balance">
<div class="uc-commission-card__body">
<span><?php esc_html_e('我的佣金', 'aksrt'); ?></span>
<strong><small>¥</small><?php echo esc_html($format_amount($available_commission)); ?></strong>
<span><?php printf(esc_html__('累计¥%s · 待结算¥%s', 'aksrt'), esc_html($format_amount($commission_stats['total'] ?? 0)), esc_html($format_amount($commission_stats['pending'] ?? 0))); ?></span>
</div>
<?php if ($withdraw_on) : ?>
<button type="button" class="uc-commission-card__action" data-aksrt-withdraw-open><?php esc_html_e('立即提现', 'aksrt'); ?><i class="fas fa-angle-right" aria-hidden="true"></i></button>
<?php endif; ?>
</article>
</section>
<section class="uc-affiliate-panel aksrt-affiliate-panel" data-aksrt-promotion-page aria-labelledby="uc-affiliate-title">
<header class="uc-panel-heading">
<h2 id="uc-affiliate-title"><?php esc_html_e('推广收益', 'aksrt'); ?></h2>
<h2 id="uc-affiliate-title"><?php esc_html_e('推荐奖励', 'aksrt'); ?></h2>
<p><?php echo esc_html($affiliate['promotion_text'] ?? __('分享推广链接,好友完成会员或付费内容订单后获得佣金。', 'aksrt')); ?></p>
</header>
<div class="uc-affiliate-link-card" data-affiliate-card>
@@ -105,42 +124,15 @@ $status_labels = [
<article><span><?php esc_html_e('推广人数', 'aksrt'); ?></span><strong data-affiliate-promoters>—</strong></article>
<article><span><?php esc_html_e('有效付费人数', 'aksrt'); ?></span><strong data-affiliate-payers>—</strong></article>
</div>
<form class="uc-affiliate-accounts" data-affiliate-accounts>
<label><?php esc_html_e('支付宝收款码/账户', 'aksrt'); ?><input type="text" name="alipay" autocomplete="off"></label>
<label><?php esc_html_e('微信收款码/账户', 'aksrt'); ?><input type="text" name="wechat" autocomplete="off"></label>
<button type="submit" class="btn-secondary btn-sm"><?php esc_html_e('保存收款方式', 'aksrt'); ?></button>
<p data-affiliate-account-feedback role="status" aria-live="polite"></p>
</form>
<p class="uc-affiliate-note"><?php esc_html_e('仅会员和付费内容订单参与返佣;首次触达后 30 天内绑定,禁止自邀和换绑。', 'aksrt'); ?></p>
</section>
<section class="uc-commission-summary" aria-label="<?php esc_attr_e('佣金概览', 'aksrt'); ?>">
<article class="uc-commission-card uc-commission-card--ratio">
<div class="uc-commission-card__icon"><i class="fas fa-percentage" aria-hidden="true"></i></div>
<div class="uc-commission-card__body">
<span><?php esc_html_e('佣金比例', 'aksrt'); ?></span>
<strong><?php echo esc_html((string) $commission_ratio); ?><small>%</small></strong>
<p><?php esc_html_e('普通用户推广订单返佣比例', 'aksrt'); ?></p>
</div>
</article>
<article class="uc-commission-card uc-commission-card--balance">
<div class="uc-commission-card__icon"><i class="fas fa-wallet" aria-hidden="true"></i></div>
<div class="uc-commission-card__body">
<span><?php esc_html_e('我的佣金', 'aksrt'); ?></span>
<strong><?php echo esc_html($format_amount($available_commission)); ?></strong>
<span><?php printf(esc_html__('累计佣金 %s,待结算 %s', 'aksrt'), esc_html($format_amount($commission_stats['total'] ?? 0)), esc_html($format_amount($commission_stats['pending'] ?? 0))); ?></span>
</div>
<?php if ($withdraw_on) : ?>
<button type="button" class="uc-commission-card__action" data-aksrt-withdraw-open><i class="fas fa-arrow-right" aria-hidden="true"></i><?php esc_html_e('立即提现', 'aksrt'); ?></button>
<?php endif; ?>
</article>
</section>
<section class="uc-reward-area" aria-labelledby="uc-reward-area-title">
<div class="uc-reward-area__heading">
<h3 id="uc-reward-area-title"><?php esc_html_e('收益明细', 'aksrt'); ?></h3>
<span><?php esc_html_e('佣金账本与提现状态', 'aksrt'); ?></span>
<h3 id="uc-reward-area-title"><?php esc_html_e('佣金详情', 'aksrt'); ?></h3>
<span><?php esc_html_e('推广订单与结算状态', 'aksrt'); ?></span>
</div>
<nav class="uc-reward-tabs" aria-label="<?php esc_attr_e('收益明细', 'aksrt'); ?>">
<a <?php echo $active_reward_tab === 'detail' ? 'aria-current="page"' : ''; ?> class="<?php echo $active_reward_tab === 'detail' ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('detail')); ?>"><?php esc_html_e('佣金详情', 'aksrt'); ?></a>
<a <?php echo $active_reward_tab === 'orders' ? 'aria-current="page"' : ''; ?> class="<?php echo $active_reward_tab === 'orders' ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('orders')); ?>"><?php esc_html_e('佣金明细', 'aksrt'); ?></a>
</nav>
@@ -171,6 +163,7 @@ $status_labels = [
<div class="uc-reward-pane"><p class="uc-reward-empty"><?php esc_html_e('暂无收益明细。', 'aksrt'); ?></p></div>
<?php endif; ?>
</section>
</section>
</div>
<?php if ($withdraw_on) {
require __DIR__ . '/withdraw-modal.php';
-2
View File
@@ -159,8 +159,6 @@ class SchemaPayment {
]],
['key' => 'text', 'title' => '文案设置', 'fields' => [
['key' => 'affiliate_promotion_text', 'label' => '推广说明', 'type' => 'textarea', 'default' => ''],
['key' => 'affiliate_earnings_text', 'label' => '收益说明', 'type' => 'textarea', 'default' => ''],
['key' => 'affiliate_withdrawal_agreement', 'label' => '提现协议', 'type' => 'textarea', 'default' => ''],
['key' => 'affiliate_payout_channels', 'label' => '可用收款渠道', 'type' => 'checkbox', 'options' => [['value' => 'alipay', 'label' => '支付宝收款码'], ['value' => 'wechat', 'label' => '微信收款码']], 'default' => ['alipay', 'wechat']],
]],
],
-29
View File
@@ -146,12 +146,6 @@ final class ReferralAttribution {
'callback' => [$this, 'rest_me'],
'permission_callback' => static fn() => is_user_logged_in(),
]);
register_rest_route('aksrt/v1', '/promotion/payout-accounts', [
'methods' => \WP_REST_Server::EDITABLE,
'callback' => [$this, 'rest_save_payout_accounts'],
'permission_callback' => static fn() => is_user_logged_in(),
'args' => ['accounts' => ['required' => true, 'type' => 'array']],
]);
}
public function rest_me(): \WP_REST_Response {
@@ -169,29 +163,6 @@ final class ReferralAttribution {
], 200);
}
public function rest_save_payout_accounts(\WP_REST_Request $request): \WP_REST_Response|\WP_Error {
$accounts = $request->get_param('accounts');
if (!is_array($accounts)) {
return new \WP_Error('aksrt_payout_accounts', __('收款账户格式无效。', 'aksrt'), ['status' => 400]);
}
global $wpdb;
$table = \AKSRT\Core\DBMigrator::table('payout_account');
if ($table === '') {
return new \WP_Error('aksrt_payout_unavailable', __('收款账户服务不可用。', 'aksrt'), ['status' => 500]);
}
$uid = get_current_user_id();
$now = current_time('mysql', true);
foreach (['alipay', 'wechat'] as $channel) {
$value = isset($accounts[$channel]) ? sanitize_text_field((string) $accounts[$channel]) : '';
if ($value === '') {
$wpdb->update($table, ['status' => 'inactive', 'updated_at' => $now], ['user_id' => $uid, 'channel' => $channel], ['%s', '%s'], ['%d', '%s']);
continue;
}
$wpdb->replace($table, ['user_id' => $uid, 'channel' => $channel, 'attachment_id' => 0, 'account_hash' => hash('sha256', $value), 'status' => 'active', 'created_at' => $now, 'updated_at' => $now], ['%d', '%s', '%d', '%s', '%s', '%s', '%s']);
}
return new \WP_REST_Response(['success' => true], 200);
}
private function resolve_promoter(string $code): int {
$code = sanitize_key($code);
if ($code === '') {
-2
View File
@@ -301,8 +301,6 @@ class PaymentRuntime {
'allow_self_purchase' => !empty($settings['affiliate_allow_self_purchase']),
'show_stats' => !isset($settings['affiliate_show_stats']) || !empty($settings['affiliate_show_stats']),
'promotion_text' => sanitize_textarea_field((string) ($settings['affiliate_promotion_text'] ?? '')),
'earnings_text' => sanitize_textarea_field((string) ($settings['affiliate_earnings_text'] ?? '')),
'withdrawal_agreement' => sanitize_textarea_field((string) ($settings['affiliate_withdrawal_agreement'] ?? '')),
];
}