refactor(referral): drop admin referral-code ops page, self-serve codes
- 移除「用户 → 推广码运营」页面(trait、子菜单、admin SPA 跳转路由) - 移除管理端 REST:/revenue/codes 列表与 generate/disable/regenerate 变更接口, 清理 rest_codes/rest_mutate_code/can_manage_codes/list_codes 死代码 - 推广码改为注册即得:bind_registered_user 内生成唯一推广码,无需后台管理 - 推广配置统一收敛到「支付&付费 → 推广返佣」设置段(现状保留,无改动) - 契约测试固化:无管理路由/页面残留 + 注册即得码
This commit is contained in:
@@ -11,7 +11,6 @@ class UsersMenus {
|
||||
|
||||
use UsersMenusVerify;
|
||||
use UsersMenusVip;
|
||||
use UsersMenusReferral;
|
||||
use UsersMenusInviteCode;
|
||||
use UsersMenusTickets;
|
||||
|
||||
@@ -42,15 +41,6 @@ class UsersMenus {
|
||||
}
|
||||
|
||||
public function register_menus(): void {
|
||||
add_submenu_page(
|
||||
'users.php',
|
||||
__('推广码运营', 'aksrt'),
|
||||
__('推广码运营', 'aksrt'),
|
||||
'edit_users',
|
||||
'aksrt_referral_codes',
|
||||
[$this, 'render_referral_codes_page']
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'users.php',
|
||||
__('邀请码管理', 'aksrt'),
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Native user referral-code operations.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Admin\Native;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait UsersMenusReferral {
|
||||
|
||||
public function render_referral_codes_page(): void {
|
||||
if (!current_user_can('edit_users')) {
|
||||
wp_die(esc_html__('您没有权限访问此页面。', 'aksrt'));
|
||||
}
|
||||
$endpoint = rest_url('aksrt/v1/revenue/codes');
|
||||
$nonce = wp_create_nonce('wp_rest');
|
||||
?>
|
||||
<div class="wrap" id="aksrt-referral-ops">
|
||||
<h1><?php esc_html_e('推广码运营', 'aksrt'); ?></h1>
|
||||
<p><?php esc_html_e('推广码与用户一一绑定。禁用或重新生成只影响后续访问和注册,不改变已有推广关系。', 'aksrt'); ?></p>
|
||||
|
||||
<div class="tablenav top">
|
||||
<div class="alignleft actions">
|
||||
<label class="screen-reader-text" for="aksrt-ref-status"><?php esc_html_e('筛选状态', 'aksrt'); ?></label>
|
||||
<select id="aksrt-ref-status">
|
||||
<option value="all"><?php esc_html_e('全部状态', 'aksrt'); ?></option>
|
||||
<option value="active"><?php esc_html_e('已启用', 'aksrt'); ?></option>
|
||||
<option value="disabled"><?php esc_html_e('已禁用', 'aksrt'); ?></option>
|
||||
<option value="missing"><?php esc_html_e('未生成', 'aksrt'); ?></option>
|
||||
</select>
|
||||
<input type="search" id="aksrt-ref-search" placeholder="<?php esc_attr_e('搜索归属用户或推广码', 'aksrt'); ?>">
|
||||
<button type="button" class="button" id="aksrt-ref-filter"><?php esc_html_e('筛选', 'aksrt'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="aksrt-ref-notice" role="status" aria-live="polite"></div>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead><tr>
|
||||
<th><?php esc_html_e('归属用户', 'aksrt'); ?></th>
|
||||
<th><?php esc_html_e('推广码', 'aksrt'); ?></th>
|
||||
<th><?php esc_html_e('启用状态', 'aksrt'); ?></th>
|
||||
<th style="text-align:right;"><?php esc_html_e('推广用户数', 'aksrt'); ?></th>
|
||||
<th style="text-align:right;"><?php esc_html_e('有效付费用户数', 'aksrt'); ?></th>
|
||||
<th><?php esc_html_e('创建时间', 'aksrt'); ?></th>
|
||||
<th><?php esc_html_e('操作', 'aksrt'); ?></th>
|
||||
</tr></thead>
|
||||
<tbody id="aksrt-ref-rows"><tr><td colspan="7"><?php esc_html_e('正在加载…', 'aksrt'); ?></td></tr></tbody>
|
||||
</table>
|
||||
<div class="tablenav bottom"><div class="tablenav-pages" id="aksrt-ref-pages"></div></div>
|
||||
</div>
|
||||
<script>
|
||||
(() => {
|
||||
const init = () => {
|
||||
const root = document.getElementById('aksrt-referral-ops');
|
||||
if (!root || root.dataset.aksrtReferralReady === '1') return;
|
||||
|
||||
const endpoint = <?php echo wp_json_encode($endpoint); ?>;
|
||||
const nonce = <?php echo wp_json_encode($nonce); ?>;
|
||||
const rows = root.querySelector('#aksrt-ref-rows');
|
||||
const pages = root.querySelector('#aksrt-ref-pages');
|
||||
const notice = root.querySelector('#aksrt-ref-notice');
|
||||
const search = root.querySelector('#aksrt-ref-search');
|
||||
const status = root.querySelector('#aksrt-ref-status');
|
||||
const filter = root.querySelector('#aksrt-ref-filter');
|
||||
if (!rows || !pages || !notice || !search || !status || !filter) {
|
||||
console.error('[AKSRT] Referral operations could not initialize: required page elements are missing.');
|
||||
return;
|
||||
}
|
||||
root.dataset.aksrtReferralReady = '1';
|
||||
let currentPage = 1;
|
||||
|
||||
const escapeHtml = (value) => String(value ?? '').replace(/[&<>'"]/g, (char) => ({
|
||||
'&': '&', '<': '<', '>': '>', "'": ''', '"': '"'
|
||||
})[char]);
|
||||
const setNotice = (message, isError = false) => {
|
||||
notice.className = message ? `notice notice-${isError ? 'error' : 'success'} inline` : '';
|
||||
notice.innerHTML = message ? `<p>${escapeHtml(message)}</p>` : '';
|
||||
};
|
||||
const request = async (url, options = {}) => {
|
||||
const response = await fetch(url, {
|
||||
credentials: 'same-origin',
|
||||
...options,
|
||||
headers: { 'X-WP-Nonce': nonce, 'Content-Type': 'application/json', ...(options.headers || {}) },
|
||||
});
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
if (!response.ok) throw new Error(payload.message || '<?php echo esc_js(__('请求失败', 'aksrt')); ?>');
|
||||
return payload;
|
||||
};
|
||||
const actionButton = (item) => {
|
||||
const id = Number(item.user.id);
|
||||
if (item.status === 'missing') {
|
||||
return `<button class="button button-primary" data-ref-action="generate" data-user-id="${id}"><?php echo esc_js(__('生成', 'aksrt')); ?></button>`;
|
||||
}
|
||||
if (item.status === 'disabled') {
|
||||
return `<button class="button" data-ref-action="regenerate" data-user-id="${id}"><?php echo esc_js(__('重新生成', 'aksrt')); ?></button>`;
|
||||
}
|
||||
return `<button class="button" data-ref-action="disable" data-user-id="${id}"><?php echo esc_js(__('禁用', 'aksrt')); ?></button> `
|
||||
+ `<button class="button" data-ref-action="regenerate" data-user-id="${id}"><?php echo esc_js(__('重新生成', 'aksrt')); ?></button>`;
|
||||
};
|
||||
const load = async (page = 1) => {
|
||||
currentPage = page;
|
||||
setNotice('');
|
||||
rows.innerHTML = '<tr><td colspan="7"><?php echo esc_js(__('正在加载…', 'aksrt')); ?></td></tr>';
|
||||
const url = new URL(endpoint);
|
||||
url.searchParams.set('page', String(page));
|
||||
url.searchParams.set('per_page', '20');
|
||||
url.searchParams.set('status', status.value);
|
||||
if (search.value.trim()) url.searchParams.set('search', search.value.trim());
|
||||
try {
|
||||
const data = await request(url.toString());
|
||||
rows.innerHTML = data.items.length ? data.items.map((item) => `
|
||||
<tr>
|
||||
<td><strong>${escapeHtml(item.user.name)}</strong><br><small>${escapeHtml(item.user.login)} · #${Number(item.user.id)}</small></td>
|
||||
<td>${item.ref ? `<code>${escapeHtml(item.ref)}</code>` : '—'}</td>
|
||||
<td>${escapeHtml({active:'<?php echo esc_js(__('已启用', 'aksrt')); ?>',disabled:'<?php echo esc_js(__('已禁用', 'aksrt')); ?>',missing:'<?php echo esc_js(__('未生成', 'aksrt')); ?>'}[item.status] || item.status)}</td>
|
||||
<td style="text-align:right;">${Number(item.bound_count || 0)}</td>
|
||||
<td style="text-align:right;">${Number(item.effective_payers || 0)}</td>
|
||||
<td>${item.created_at ? escapeHtml(item.created_at) : '—'}</td>
|
||||
<td>${actionButton(item)}</td>
|
||||
</tr>`).join('') : '<tr><td colspan="7"><?php echo esc_js(__('没有符合条件的用户', 'aksrt')); ?></td></tr>';
|
||||
pages.innerHTML = Array.from({length: Number(data.max_pages || 1)}, (_, index) => {
|
||||
const number = index + 1;
|
||||
return `<button type="button" class="button ${number === Number(data.page) ? 'button-primary' : ''}" data-ref-page="${number}">${number}</button>`;
|
||||
}).join(' ');
|
||||
} catch (error) {
|
||||
rows.innerHTML = '<tr><td colspan="6"><?php echo esc_js(__('推广码数据加载失败', 'aksrt')); ?></td></tr>';
|
||||
setNotice(error.message, true);
|
||||
}
|
||||
};
|
||||
|
||||
filter.addEventListener('click', () => load(1));
|
||||
search.addEventListener('keydown', (event) => { if (event.key === 'Enter') load(1); });
|
||||
root.addEventListener('click', async (event) => {
|
||||
const pageButton = event.target.closest('[data-ref-page]');
|
||||
if (pageButton) return load(Number(pageButton.dataset.refPage));
|
||||
const button = event.target.closest('[data-ref-action]');
|
||||
if (!button) return;
|
||||
button.disabled = true;
|
||||
try {
|
||||
await request(`${endpoint}/${Number(button.dataset.userId)}/${button.dataset.refAction}`, { method: 'POST', body: '{}' });
|
||||
setNotice('<?php echo esc_js(__('推广码已更新', 'aksrt')); ?>');
|
||||
await load(currentPage);
|
||||
} catch (error) {
|
||||
setNotice(error.message, true);
|
||||
button.disabled = false;
|
||||
}
|
||||
});
|
||||
load();
|
||||
};
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init, { once: true });
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user