Merge pull request 'fix(user-center): embed official certification panel' (#319) from worktree-user-center-sidebar-wallet-redesign into main
Reviewed-on: CYL/wordpress-theme-aksrt#319
This commit is contained in:
@@ -14,6 +14,21 @@
|
||||
<n-descriptions-item label="最近处理">{{ detail.request.reviewed_at || '-' }}</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
|
||||
<div class="aksrt-verify-drawer__section">
|
||||
<div class="aksrt-verify-drawer__title">申请资料</div>
|
||||
<n-descriptions bordered :column="1" size="small" label-placement="left">
|
||||
<n-descriptions-item label="认证类型">{{ detail.request.application?.type || '-' }}</n-descriptions-item>
|
||||
<n-descriptions-item label="认证身份">{{ detail.request.application?.name || '-' }}</n-descriptions-item>
|
||||
<n-descriptions-item label="身份简介">{{ detail.request.application?.desc || '-' }}</n-descriptions-item>
|
||||
<n-descriptions-item label="申请说明">{{ detail.request.application?.msg || '-' }}</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
<div v-if="detail.request.application?.img?.length" class="aksrt-verify-drawer__proofs">
|
||||
<a v-for="image in detail.request.application.img" :key="image" :href="image" target="_blank" rel="noopener noreferrer">
|
||||
<img :src="image" alt="认证证明材料" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="aksrt-verify-drawer__section">
|
||||
<div class="aksrt-verify-drawer__title">当前备注</div>
|
||||
<n-alert type="info" :show-icon="false">
|
||||
@@ -149,6 +164,21 @@ async function handleSubmit() {
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.aksrt-verify-drawer__proofs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.aksrt-verify-drawer__proofs img {
|
||||
display: block;
|
||||
width: 92px;
|
||||
height: 92px;
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.aksrt-verify-drawer__timeline {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
|
||||
@@ -4,7 +4,7 @@ export const featuresSchema = {
|
||||
icon: 'fas fa-user-cog',
|
||||
description: '配置用户中心和个人主页的功能模块。',
|
||||
defaults: {
|
||||
user_center_tabs: 'profile,posts,comments,favorites,vip,credits',
|
||||
user_center_tabs: 'profile,posts,comments,favorites,vip,credits,auth',
|
||||
user_avatar_upload: true,
|
||||
user_cover_upload: true,
|
||||
user_social_links: true,
|
||||
@@ -26,7 +26,7 @@ export const featuresSchema = {
|
||||
title: '用户中心',
|
||||
icon: 'fas fa-user-shield',
|
||||
fields: [
|
||||
{ key: 'user_center_tabs', label: '用户中心 Tab', type: 'input', default: 'profile,posts,comments,favorites,vip,credits', help: '逗号分隔。vip=我的会员(会员功能开启时也会自动注入)' },
|
||||
{ key: 'user_center_tabs', label: '用户中心 Tab', type: 'input', default: 'profile,posts,comments,favorites,vip,credits,auth', help: '逗号分隔。auth=官方认证;vip、订单和认证会按功能开关自动注入' },
|
||||
{ key: 'user_avatar_upload', label: '头像上传', type: 'switch', default: true },
|
||||
{ key: 'user_cover_upload', label: '封面上传', type: 'switch', default: true },
|
||||
{ key: 'user_social_links', label: '社交链接', type: 'switch', default: true },
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* User identity auth page styles (zibll user-auth).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
.aksrt-user-auth-panel {
|
||||
overflow: hidden;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel .colorful-bg.c-blue {
|
||||
background: linear-gradient(135deg, #4e9bff 0%, #2f6df6 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel .muted-2-color {
|
||||
color: var(--muted-2-color, #888);
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel .form-control {
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--main-border-color, #ddd);
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel .mb20 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel .mb6 {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel .but.c-blue,
|
||||
.aksrt-user-auth-panel button.but {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
background: var(--focus-color, #2f6df6);
|
||||
color: #fff;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
padding: 10px 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel .btn-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel__imgs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel__imgs .preview-item {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--main-border-color, #eee);
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel__imgs img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-user-auth-panel .c-red {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
/* Dual-column geometry owned by layout.css site-layout float rules (Zibll). */
|
||||
@@ -359,3 +359,79 @@
|
||||
margin-right: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
|
||||
/* ==================== 官方认证面板 ==================== */
|
||||
.uc-auth-panel { overflow: hidden; }
|
||||
|
||||
.uc-auth-card {
|
||||
display: grid;
|
||||
grid-template-columns: 128px minmax(0, 1fr);
|
||||
min-height: 210px;
|
||||
overflow: hidden;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(135deg, rgba(59, 130, 246, 0.13), rgba(124, 92, 220, 0.08));
|
||||
}
|
||||
|
||||
.uc-auth-card__art {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: linear-gradient(150deg, #3988f4, #7567de);
|
||||
color: #fff;
|
||||
font-size: 46px;
|
||||
}
|
||||
|
||||
.uc-auth-card__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding: 28px;
|
||||
}
|
||||
|
||||
.uc-auth-card__content small { color: var(--color-primary); font-weight: 700; }
|
||||
.uc-auth-card__content h2 { margin: 5px 0 9px; font-size: 24px; }
|
||||
.uc-auth-card__content p,
|
||||
.uc-auth-card__content time { margin: 0; color: var(--color-ink-4); font-size: 13px; line-height: 1.7; }
|
||||
.uc-auth-card__notice { margin-top: 14px; color: var(--color-error, #dc2626); font-size: 13px; }
|
||||
.uc-auth-apply-open { margin-top: 18px; min-width: 112px; }
|
||||
.uc-auth-card--verified { background: linear-gradient(135deg, rgba(16, 185, 129, 0.12), rgba(59, 130, 246, 0.08)); }
|
||||
.uc-auth-card--verified .uc-auth-card__art { background: linear-gradient(150deg, #20a77d, #3287df); }
|
||||
|
||||
.uc-auth-modal { z-index: 620; }
|
||||
.uc-auth-modal .aksrt-modal__dialog { width: min(620px, calc(100vw - 28px)); max-height: min(760px, calc(100vh - 40px)); overflow: auto; }
|
||||
.uc-auth-modal__header > div { display: flex; align-items: center; gap: 10px; }
|
||||
.uc-auth-modal__header > div > span { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 11px; background: var(--color-primary-soft); color: var(--color-primary); }
|
||||
.uc-auth-modal__body { padding: 22px; }
|
||||
|
||||
.uc-auth-form { display: grid; gap: 17px; }
|
||||
.uc-auth-form > label { display: grid; gap: 7px; color: var(--color-ink-2); font-size: 13px; font-weight: 600; }
|
||||
.uc-auth-form .form-control { width: 100%; min-height: 42px; padding: 9px 11px; border: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.1)); border-radius: 9px; background: var(--surface-1); color: var(--color-ink); font: inherit; font-weight: 400; box-sizing: border-box; }
|
||||
.uc-auth-form textarea.form-control { resize: vertical; }
|
||||
.uc-auth-upload small { color: var(--color-ink-4); font-weight: 400; }
|
||||
.uc-auth-submit { display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-height: 44px; }
|
||||
.uc-auth-form__message { min-height: 18px; color: var(--color-error, #dc2626); font-size: 12px; text-align: center; }
|
||||
|
||||
.uc-auth-upload__previews { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.uc-auth-upload__previews img,
|
||||
.uc-auth-proof-list .preview-item { width: 82px; height: 82px; border-radius: 8px; overflow: hidden; object-fit: cover; }
|
||||
.uc-auth-proof-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
|
||||
.uc-auth-proof-list img { width: 100%; height: 100%; object-fit: cover; }
|
||||
|
||||
.uc-auth-pending { text-align: center; padding: 4px 0 18px; }
|
||||
.uc-auth-pending > span { display: grid; place-items: center; width: 58px; height: 58px; margin: 0 auto 12px; border-radius: 18px; background: rgba(245, 158, 11, 0.14); color: #a66e0b; font-size: 24px; }
|
||||
.uc-auth-pending h3 { margin: 0 0 7px; }
|
||||
.uc-auth-pending p { margin: 0; color: var(--color-ink-4); font-size: 13px; }
|
||||
.uc-auth-apply-detail { display: grid; gap: 0; border-top: 1px solid var(--color-line-soft); }
|
||||
.uc-auth-apply-detail dl { display: grid; grid-template-columns: 90px minmax(0, 1fr); gap: 12px; margin: 0; padding: 12px 0; border-bottom: 1px solid var(--color-line-soft); font-size: 13px; }
|
||||
.uc-auth-apply-detail dt { color: var(--color-ink-4); }
|
||||
.uc-auth-apply-detail dd { margin: 0; color: var(--color-ink-2); }
|
||||
.uc-auth-modal__confirm { width: 100%; margin-top: 20px; }
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.uc-auth-card { grid-template-columns: 92px minmax(0, 1fr); min-height: 180px; }
|
||||
.uc-auth-card__art { font-size: 34px; }
|
||||
.uc-auth-card__content { padding: 20px 17px; }
|
||||
.uc-auth-card__content h2 { font-size: 20px; }
|
||||
.uc-auth-modal .aksrt-modal__dialog { position: fixed; inset: auto 0 0; width: 100%; max-height: 88vh; margin: 0; border-radius: 18px 18px 0 0; }
|
||||
}
|
||||
|
||||
@@ -631,10 +631,15 @@ body.aksrt-user-center .uc-content,
|
||||
.uc-service-grid__item--profile .uc-service-grid__icon { color: #6550c7; background: rgba(124, 92, 220, 0.12); }
|
||||
.uc-service-grid__item--security .uc-service-grid__icon { color: #16816c; background: rgba(16, 185, 129, 0.12); }
|
||||
|
||||
.uc-service-grid__item:hover {
|
||||
.uc-service-grid__item:hover,
|
||||
.uc-service-grid__item.is-active {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.uc-service-grid__item.is-active .uc-service-grid__icon {
|
||||
box-shadow: 0 0 0 2px var(--color-primary-soft), 0 5px 14px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.uc-order-grid__icon { transition: none; }
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
if (!tabContainer) return;
|
||||
|
||||
var tabs = tabContainer.querySelectorAll('[data-tab]');
|
||||
var sidebarBtns = document.querySelectorAll('.uc-sidebar__btn[data-tab]');
|
||||
var sidebarBtns = document.querySelectorAll('.uc-sidebar__btn[data-tab], .uc-service-grid__item[data-tab]');
|
||||
var panels = {};
|
||||
var defaultTab = cfg.defaultTab || 'profile';
|
||||
var drawerTrigger = document.getElementById('uc-drawer-trigger');
|
||||
@@ -193,6 +193,92 @@
|
||||
});
|
||||
}
|
||||
|
||||
function initAuthForm() {
|
||||
var modal = document.getElementById('uc-auth-modal');
|
||||
if (!modal || modal.dataset.authModalBound === '1') return;
|
||||
modal.dataset.authModalBound = '1';
|
||||
|
||||
function openModal() {
|
||||
modal.classList.add('is-open');
|
||||
modal.setAttribute('aria-hidden', 'false');
|
||||
document.body.style.overflow = 'hidden';
|
||||
var first = modal.querySelector('input:not([type="hidden"]), select, textarea, button');
|
||||
if (first) window.setTimeout(function() { first.focus(); }, 80);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
modal.classList.remove('is-open');
|
||||
modal.setAttribute('aria-hidden', 'true');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
document.querySelectorAll('[data-auth-modal-open]').forEach(function(button) {
|
||||
button.addEventListener('click', openModal);
|
||||
});
|
||||
modal.querySelectorAll('[data-auth-modal-close]').forEach(function(button) {
|
||||
button.addEventListener('click', closeModal);
|
||||
});
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape' && modal.classList.contains('is-open')) closeModal();
|
||||
});
|
||||
|
||||
var fileInput = modal.querySelector('[data-auth-files]');
|
||||
var previews = modal.querySelector('[data-auth-previews]');
|
||||
if (fileInput && previews) {
|
||||
fileInput.addEventListener('change', function() {
|
||||
previews.innerHTML = '';
|
||||
var files = Array.prototype.slice.call(fileInput.files || []);
|
||||
if (files.length > 3) {
|
||||
showToast('证明材料最多上传 3 张');
|
||||
fileInput.value = '';
|
||||
return;
|
||||
}
|
||||
for (var index = 0; index < files.length; index++) {
|
||||
if (files[index].size > 2 * 1024 * 1024) {
|
||||
showToast('单张图片不能超过 2MB');
|
||||
fileInput.value = '';
|
||||
previews.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
var image = document.createElement('img');
|
||||
image.src = URL.createObjectURL(files[index]);
|
||||
image.alt = '';
|
||||
image.onload = function() { URL.revokeObjectURL(this.src); };
|
||||
previews.appendChild(image);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var form = modal.querySelector('.aksrt-user-auth-form');
|
||||
if (!form) return;
|
||||
form.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
var button = form.querySelector('[type="submit"]');
|
||||
var message = form.querySelector('[data-auth-message]');
|
||||
var original = button ? button.textContent : '';
|
||||
if (button) {
|
||||
button.disabled = true;
|
||||
button.textContent = i18n.submitting || '提交中…';
|
||||
}
|
||||
if (message) message.textContent = '';
|
||||
fetch(ajaxUrl, { method: 'POST', body: new FormData(form), credentials: 'same-origin' })
|
||||
.then(function(response) { return response.json(); })
|
||||
.then(function(response) {
|
||||
if (!response || response.error) throw new Error((response && response.msg) || '提交失败');
|
||||
showToast(response.msg || '提交成功');
|
||||
window.setTimeout(function() { window.location.assign(tabUrls.auth || '?tab=auth'); }, 500);
|
||||
})
|
||||
.catch(function(error) {
|
||||
if (message) message.textContent = error.message || '提交失败';
|
||||
showToast(error.message || '提交失败');
|
||||
if (button) {
|
||||
button.disabled = false;
|
||||
button.textContent = original;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* ==================== 列表内取消收藏 ==================== */
|
||||
function initUnfavorite() {
|
||||
var list = document.querySelector('.profile-list[data-list="favorites"]');
|
||||
@@ -678,6 +764,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initDashboardNavigation();
|
||||
initProfileForm();
|
||||
initAuthForm();
|
||||
initUnfavorite();
|
||||
initNotifications();
|
||||
initSettings();
|
||||
@@ -685,6 +772,7 @@
|
||||
} else {
|
||||
initDashboardNavigation();
|
||||
initProfileForm();
|
||||
initAuthForm();
|
||||
initUnfavorite();
|
||||
initNotifications();
|
||||
initSettings();
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* User auth apply form AJAX.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function ajaxUrl() {
|
||||
if (window.aksrtData && window.aksrtData.ajaxUrl) return window.aksrtData.ajaxUrl;
|
||||
return '/wp-admin/admin-ajax.php';
|
||||
}
|
||||
|
||||
function toast(msg, type) {
|
||||
if (window.aksrt && typeof window.aksrt.toast === 'function') {
|
||||
window.aksrt.toast(msg, type || 'info');
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line no-alert
|
||||
window.alert(msg);
|
||||
}
|
||||
|
||||
function init() {
|
||||
var form = document.querySelector('.aksrt-user-auth-form');
|
||||
if (!form) return;
|
||||
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var btn = form.querySelector('button[type="submit"]');
|
||||
if (btn) btn.disabled = true;
|
||||
var fd = new FormData(form);
|
||||
if (!fd.get('action')) fd.set('action', 'aksrt_user_auth_apply');
|
||||
|
||||
fetch(ajaxUrl(), {
|
||||
method: 'POST',
|
||||
body: fd,
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (data) {
|
||||
if (!data || data.error) {
|
||||
toast((data && data.msg) || '提交失败', 'danger');
|
||||
return;
|
||||
}
|
||||
toast(data.msg || '提交成功', 'success');
|
||||
if (data.reload) {
|
||||
window.setTimeout(function () { window.location.reload(); }, 500);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
toast('网络错误', 'danger');
|
||||
})
|
||||
.finally(function () {
|
||||
if (btn) btn.disabled = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
@@ -148,6 +148,7 @@ if (!function_exists('aksrt_capture_user_center_view')) {
|
||||
'credits' => 'credits',
|
||||
'vip' => 'vip',
|
||||
'orders' => 'orders',
|
||||
'auth' => 'auth',
|
||||
'settings' => 'settings',
|
||||
'header' => 'header',
|
||||
'sidebar' => 'sidebar',
|
||||
@@ -172,7 +173,7 @@ if (!function_exists('aksrt_capture_user_center_panel')) {
|
||||
* Capture a built-in or registered user-center panel body.
|
||||
*/
|
||||
function aksrt_capture_user_center_panel(string $tab_key, array $tab, array $context): string {
|
||||
$built_in_tabs = ['profile', 'posts', 'comments', 'favorites', 'credits', 'vip', 'orders', 'settings'];
|
||||
$built_in_tabs = ['profile', 'posts', 'comments', 'favorites', 'credits', 'vip', 'orders', 'auth', 'settings'];
|
||||
if (in_array($tab_key, $built_in_tabs, true)) {
|
||||
return aksrt_capture_user_center_view($tab_key, $context);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/**
|
||||
* User center panel: official certification.
|
||||
*
|
||||
* Zibll parity: compact center card + in-place application modal.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
use AKSRT\User\AuthApply;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
$user_id = (int) ($context['user_id'] ?? get_current_user_id());
|
||||
$settings = class_exists(AuthApply::class) ? AuthApply::settings() : ['enabled' => false, 'allow_apply' => false];
|
||||
$status = $user_id > 0 && class_exists(AuthApply::class) ? AuthApply::get_status($user_id) : '';
|
||||
$info = $user_id > 0 && class_exists(AuthApply::class) ? AuthApply::get_auth_info($user_id) : [];
|
||||
$apply = $user_id > 0 && class_exists(AuthApply::class) ? AuthApply::get_apply_payload($user_id) : [];
|
||||
$type_labels = [];
|
||||
foreach ((array) ($settings['types'] ?? []) as $type) {
|
||||
$type_labels[(string) ($type['slug'] ?? '')] = (string) ($type['label'] ?? '');
|
||||
}
|
||||
$apply_type = sanitize_key((string) ($apply['type'] ?? ''));
|
||||
$limit = (int) ($settings['limit_level'] ?? 0);
|
||||
$current_level = class_exists('\AKSRT\User\Level') ? (int) \AKSRT\User\Level::get_level($user_id) : 0;
|
||||
$blocked_level = $limit > 0 && $current_level < $limit;
|
||||
$can_apply = !empty($settings['enabled']) && !empty($settings['allow_apply']) && !$blocked_level && $status !== 'verified';
|
||||
?>
|
||||
<div class="aksrt-user-auth-panel uc-auth-panel">
|
||||
<?php if ($status === 'verified') :
|
||||
$name = (string) ($info['name'] ?? $apply['name'] ?? __('官方认证', 'aksrt'));
|
||||
$desc = (string) ($info['desc'] ?? $apply['desc'] ?? '');
|
||||
$time = (string) ($info['time'] ?? get_user_meta($user_id, 'aksrt_user_verify_reviewed_at', true));
|
||||
?>
|
||||
<div class="uc-auth-card uc-auth-card--verified">
|
||||
<span class="uc-auth-card__art"><i class="fas fa-check-circle" aria-hidden="true"></i></span>
|
||||
<div class="uc-auth-card__content">
|
||||
<small><?php esc_html_e('已通过官方认证', 'aksrt'); ?></small>
|
||||
<h2><?php echo esc_html($name); ?></h2>
|
||||
<?php if ($desc !== '') : ?><p><?php echo esc_html($desc); ?></p><?php endif; ?>
|
||||
<?php if ($time !== '') : ?><time><?php printf(esc_html__('认证时间:%s', 'aksrt'), esc_html($time)); ?></time><?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="uc-auth-card">
|
||||
<span class="uc-auth-card__art"><i class="fas fa-id-badge" aria-hidden="true"></i></span>
|
||||
<div class="uc-auth-card__content">
|
||||
<small><?php esc_html_e('身份权益', 'aksrt'); ?></small>
|
||||
<h2><?php esc_html_e('官方认证', 'aksrt'); ?></h2>
|
||||
<p><?php echo esc_html((string) ($settings['desc'] ?? __('认证后将展示官方身份标识。', 'aksrt'))); ?></p>
|
||||
<?php if (empty($settings['allow_apply'])) : ?>
|
||||
<div class="uc-auth-card__notice"><?php echo wp_kses_post(nl2br(esc_html((string) ($settings['disable_desc'] ?? __('暂时不能申请身份认证', 'aksrt'))))); ?></div>
|
||||
<?php elseif ($blocked_level) : ?>
|
||||
<div class="uc-auth-card__notice"><?php printf(esc_html__('达到 LV.%d 后即可申请', 'aksrt'), $limit); ?></div>
|
||||
<?php elseif ($can_apply) : ?>
|
||||
<button type="button" class="btn-primary uc-auth-apply-open" data-auth-modal-open>
|
||||
<?php echo $status === 'pending' ? esc_html__('查看申请进度', 'aksrt') : esc_html__('申请认证', 'aksrt'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($can_apply) : ?>
|
||||
<div class="aksrt-modal uc-auth-modal" id="uc-auth-modal" aria-hidden="true">
|
||||
<div class="aksrt-modal__backdrop" data-auth-modal-close></div>
|
||||
<div class="aksrt-modal__dialog" role="dialog" aria-modal="true" aria-labelledby="uc-auth-modal-title">
|
||||
<div class="aksrt-modal__header uc-auth-modal__header">
|
||||
<div><span><i class="fas fa-id-badge" aria-hidden="true"></i></span><strong id="uc-auth-modal-title"><?php esc_html_e('申请身份认证', 'aksrt'); ?></strong></div>
|
||||
<button type="button" class="aksrt-modal__close" data-auth-modal-close aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>"><i class="fas fa-times" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
<div class="aksrt-modal__body uc-auth-modal__body">
|
||||
<?php if ($status === 'pending') : ?>
|
||||
<div class="uc-auth-pending">
|
||||
<span><i class="fas fa-hourglass-half" aria-hidden="true"></i></span>
|
||||
<h3><?php esc_html_e('您的申请正在审核中', 'aksrt'); ?></h3>
|
||||
<p><?php esc_html_e('请耐心等待,审核结果会通过消息中心通知。', 'aksrt'); ?></p>
|
||||
</div>
|
||||
<div class="uc-auth-apply-detail">
|
||||
<dl><dt><?php esc_html_e('认证身份', 'aksrt'); ?></dt><dd><?php echo esc_html((string) ($apply['name'] ?? '')); ?></dd></dl>
|
||||
<?php if ($apply_type !== '') : ?><dl><dt><?php esc_html_e('认证类型', 'aksrt'); ?></dt><dd><?php echo esc_html($type_labels[$apply_type] ?? $apply_type); ?></dd></dl><?php endif; ?>
|
||||
<?php if (!empty($apply['desc'])) : ?><dl><dt><?php esc_html_e('身份简介', 'aksrt'); ?></dt><dd><?php echo esc_html((string) $apply['desc']); ?></dd></dl><?php endif; ?>
|
||||
<?php if (!empty($apply['msg'])) : ?><dl><dt><?php esc_html_e('申请说明', 'aksrt'); ?></dt><dd><?php echo esc_html((string) $apply['msg']); ?></dd></dl><?php endif; ?>
|
||||
<?php if (!empty($apply['time'])) : ?><dl><dt><?php esc_html_e('申请时间', 'aksrt'); ?></dt><dd><?php echo esc_html((string) $apply['time']); ?></dd></dl><?php endif; ?>
|
||||
</div>
|
||||
<?php if (!empty($apply['img'])) : ?>
|
||||
<div class="aksrt-user-auth-panel__imgs uc-auth-proof-list"><?php foreach ((array) $apply['img'] as $img_url) : ?><div class="preview-item"><img src="<?php echo esc_attr(AuthApply::evidence_src((string) $img_url)); ?>" alt="" loading="lazy"></div><?php endforeach; ?></div>
|
||||
<?php endif; ?>
|
||||
<button type="button" class="btn-primary uc-auth-modal__confirm" data-auth-modal-close><?php esc_html_e('确定', 'aksrt'); ?></button>
|
||||
<?php else : ?>
|
||||
<form class="aksrt-user-auth-form uc-auth-form" enctype="multipart/form-data">
|
||||
<label><span><?php esc_html_e('认证类型', 'aksrt'); ?></span><select class="form-control" name="type" required><?php foreach ((array) ($settings['types'] ?? []) as $type) : ?><option value="<?php echo esc_attr((string) $type['slug']); ?>"><?php echo esc_html((string) $type['label']); ?></option><?php endforeach; ?></select></label>
|
||||
<label><span><?php esc_html_e('认证身份', 'aksrt'); ?></span><input type="text" class="form-control" name="name" required minlength="4" maxlength="16" placeholder="<?php esc_attr_e('请输入 4-16 个字符', 'aksrt'); ?>"></label>
|
||||
<label><span><?php esc_html_e('身份简介', 'aksrt'); ?></span><textarea class="form-control" name="desc" rows="3" maxlength="300" placeholder="<?php esc_attr_e('认证通过后公开展示的身份说明', 'aksrt'); ?>"></textarea></label>
|
||||
<label><span><?php esc_html_e('申请说明', 'aksrt'); ?></span><textarea class="form-control" name="msg" rows="3" maxlength="500" placeholder="<?php esc_attr_e('说明申请缘由,便于管理员审核', 'aksrt'); ?>"></textarea></label>
|
||||
<label class="uc-auth-upload"><span><?php esc_html_e('证明材料', 'aksrt'); ?></span><input type="file" name="image[]" accept="image/jpeg,image/png,image/gif,image/webp" multiple data-auth-files><small><?php esc_html_e('最多上传 3 张图片,单张不超过 2MB(可选)。', 'aksrt'); ?></small><div class="uc-auth-upload__previews" data-auth-previews></div></label>
|
||||
<?php wp_nonce_field('aksrt_user_auth_apply', '_wpnonce', false); ?>
|
||||
<input type="hidden" name="action" value="aksrt_user_auth_apply">
|
||||
<button type="submit" class="btn-primary uc-auth-submit"><i class="fas fa-check" aria-hidden="true"></i><?php esc_html_e('确认提交', 'aksrt'); ?></button>
|
||||
<div class="uc-auth-form__message" data-auth-message role="status"></div>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -11,10 +11,7 @@ $cart_url = function_exists('aksrt_get_cart_page_url') ? aksrt_get_cart_page_url
|
||||
$level_url = isset($dashboard_tabs['credits'])
|
||||
? add_query_arg('asset_tab', 'points', aksrt_get_user_center_tab_url('credits'))
|
||||
: '';
|
||||
$auth_settings = class_exists('\AKSRT\User\AuthApply') ? \AKSRT\User\AuthApply::settings() : [];
|
||||
$auth_url = !empty($auth_settings['enabled']) && function_exists('aksrt_get_user_auth_page_url')
|
||||
? aksrt_get_user_auth_page_url()
|
||||
: '';
|
||||
$auth_url = isset($dashboard_tabs['auth']) ? aksrt_get_user_center_tab_url('auth') : '';
|
||||
|
||||
$services = array_values(array_filter([
|
||||
[
|
||||
@@ -34,6 +31,7 @@ $services = array_values(array_filter([
|
||||
'icon' => 'id-badge',
|
||||
'tone' => 'auth',
|
||||
'url' => $auth_url,
|
||||
'tab' => 'auth',
|
||||
],
|
||||
], static fn(array $item): bool => (string) $item['url'] !== ''));
|
||||
|
||||
@@ -63,7 +61,7 @@ $render_grid = static function (array $items): void {
|
||||
?>
|
||||
<div class="uc-service-grid">
|
||||
<?php foreach ($items as $item) : ?>
|
||||
<a class="uc-service-grid__item uc-service-grid__item--<?php echo esc_attr((string) $item['tone']); ?>" href="<?php echo esc_url((string) $item['url']); ?>">
|
||||
<a class="uc-service-grid__item uc-service-grid__item--<?php echo esc_attr((string) $item['tone']); ?><?php echo !empty($item['tab']) && ($active_tab ?? '') === $item['tab'] ? ' is-active' : ''; ?>" href="<?php echo esc_url((string) $item['url']); ?>"<?php if (!empty($item['tab'])) : ?> data-tab="<?php echo esc_attr((string) $item['tab']); ?>"<?php endif; ?>>
|
||||
<span class="uc-service-grid__icon">
|
||||
<i class="fas fa-<?php echo esc_attr((string) $item['icon']); ?>" aria-hidden="true"></i>
|
||||
<?php if (!empty($item['count'])) : ?><small><?php echo esc_html((string) $item['count']); ?></small><?php endif; ?>
|
||||
|
||||
@@ -18,7 +18,6 @@ add_filter('query_vars', function ($vars) {
|
||||
$vars[] = 'aksrt_orders';
|
||||
$vars[] = 'aksrt_cart';
|
||||
$vars[] = 'aksrt_revenue';
|
||||
$vars[] = 'aksrt_user_auth';
|
||||
return $vars;
|
||||
});
|
||||
|
||||
@@ -43,14 +42,12 @@ add_action('init', function () {
|
||||
add_rewrite_tag('%aksrt_orders%', '([0-1])');
|
||||
add_rewrite_tag('%aksrt_cart%', '([0-1])');
|
||||
add_rewrite_tag('%aksrt_revenue%', '([0-1])');
|
||||
add_rewrite_tag('%aksrt_user_auth%', '([0-1])');
|
||||
add_rewrite_rule('^profile/?$', 'index.php?aksrt_user_center=1', 'top');
|
||||
add_rewrite_rule('^user/([^/]+)/?$', 'index.php?user_nicename=$matches[1]', 'top');
|
||||
// Commerce center aliases (work even before WP page is assigned).
|
||||
add_rewrite_rule('^orders/?$', 'index.php?aksrt_orders=1', 'top');
|
||||
add_rewrite_rule('^cart/?$', 'index.php?aksrt_cart=1', 'top');
|
||||
add_rewrite_rule('^revenue/?$', 'index.php?aksrt_revenue=1', 'top');
|
||||
add_rewrite_rule('^user-auth/?$', 'index.php?aksrt_user_auth=1', 'top');
|
||||
});
|
||||
|
||||
// --- 3b. 统一模板拦截器(核心)---
|
||||
@@ -169,7 +166,7 @@ add_action('init', function () {
|
||||
}
|
||||
|
||||
// 统一 flush 检查 — bump when user-home rewrite / author override changes
|
||||
$rewrite_version = AKSRT_VERSION . ':user-home-profile-routing-v4';
|
||||
$rewrite_version = AKSRT_VERSION . ':user-home-profile-routing-v5';
|
||||
$flushed = get_option('aksrt_user_rules_flushed');
|
||||
$rules = get_option('rewrite_rules');
|
||||
$need_flush = ($flushed !== $rewrite_version)
|
||||
@@ -218,9 +215,6 @@ add_filter('request', function ($query_vars) {
|
||||
if (empty($query_vars['aksrt_user_center']) && isset($_GET['aksrt_user_center'])) {
|
||||
$query_vars['aksrt_user_center'] = '1';
|
||||
}
|
||||
if (empty($query_vars['aksrt_user_auth']) && isset($_GET['aksrt_user_auth'])) {
|
||||
$query_vars['aksrt_user_auth'] = '1';
|
||||
}
|
||||
return $query_vars;
|
||||
});
|
||||
|
||||
|
||||
@@ -131,12 +131,6 @@ $_aksrt_special_templates = [
|
||||
'title' => '消息中心',
|
||||
'fallback' => '/messages/',
|
||||
],
|
||||
'user-auth' => [
|
||||
'file' => 'templates/pages/page-user-auth.php',
|
||||
'slug' => 'user-auth',
|
||||
'title' => '官方认证',
|
||||
'fallback' => '/user-auth/',
|
||||
],
|
||||
'submit' => [
|
||||
'file' => 'templates/pages/page-submit.php',
|
||||
'slug' => 'submit',
|
||||
@@ -282,7 +276,6 @@ function aksrt_resolve_page_template_file(string $template_file = '', string $po
|
||||
'categories' => 'templates/pages/page-categories.php',
|
||||
'friends' => 'templates/pages/page-friends.php',
|
||||
'profile' => 'templates/pages/page-profile.php',
|
||||
'user-auth' => 'templates/pages/page-user-auth.php',
|
||||
];
|
||||
|
||||
if (!empty($slug_map[$post_slug]) && aksrt_locate_template_file($slug_map[$post_slug])) {
|
||||
@@ -444,11 +437,6 @@ function aksrt_get_current_special_template_path(): string {
|
||||
return $revenue_template ?: '';
|
||||
}
|
||||
|
||||
if (get_query_var('aksrt_user_auth')) {
|
||||
$auth_template = aksrt_locate_template_file('templates/pages/page-user-auth.php');
|
||||
return $auth_template ?: '';
|
||||
}
|
||||
|
||||
if (get_query_var('aksrt_sign')) {
|
||||
$auth_template = aksrt_get_auth_template_file((string) get_query_var('aksrt_auth_tab'), true);
|
||||
$auth_template_path = aksrt_locate_template_file($auth_template);
|
||||
|
||||
@@ -106,21 +106,6 @@ function aksrt_get_revenue_page_url(): string {
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_get_user_auth_page_url')) :
|
||||
/**
|
||||
* 官方认证页面 URL。
|
||||
*/
|
||||
function aksrt_get_user_auth_page_url(): string {
|
||||
if (function_exists('aksrt_get_template_url')) {
|
||||
return aksrt_get_template_url('user-auth');
|
||||
}
|
||||
if (get_option('permalink_structure')) {
|
||||
return home_url('/user-auth/');
|
||||
}
|
||||
return add_query_arg('aksrt_user_auth', '1', home_url('/'));
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_get_messages_page_url')) :
|
||||
/**
|
||||
* 消息中心页面 URL(模板 templates/pages/page-messages.php)。
|
||||
|
||||
@@ -547,7 +547,8 @@ class UsersMenus {
|
||||
echo '<div class="description">' . esc_html((string) $apply['msg']) . '</div>';
|
||||
}
|
||||
foreach ((array) ($apply['img'] ?? []) as $image_url) {
|
||||
echo '<a href="' . esc_url((string) $image_url) . '" target="_blank" rel="noopener noreferrer"><img src="' . esc_url((string) $image_url) . '" alt="" style="width:56px;height:56px;object-fit:cover;margin:6px 6px 0 0;border-radius:4px;" /></a>';
|
||||
$evidence_src = class_exists('\AKSRT\User\AuthApply') ? \AKSRT\User\AuthApply::evidence_src((string) $image_url) : '';
|
||||
echo '<a href="' . esc_attr($evidence_src) . '" target="_blank" rel="noopener noreferrer"><img src="' . esc_attr($evidence_src) . '" alt="" style="width:56px;height:56px;object-fit:cover;margin:6px 6px 0 0;border-radius:4px;" /></a>';
|
||||
}
|
||||
}
|
||||
if (!empty($row['verify_reason'])) {
|
||||
@@ -588,7 +589,17 @@ class UsersMenus {
|
||||
check_admin_referer('aksrt_users_review_verify_' . $user_id);
|
||||
|
||||
$ok = false;
|
||||
if ($user_id > 0 && in_array($status, ['verified', 'rejected'], true) && get_userdata($user_id)) {
|
||||
$current_status = sanitize_key((string) get_user_meta($user_id, 'aksrt_user_verify_status', true));
|
||||
$application = get_user_meta($user_id, 'aksrt_user_verify_apply', true);
|
||||
if (
|
||||
$user_id > 0
|
||||
&& in_array($status, ['verified', 'rejected'], true)
|
||||
&& get_userdata($user_id)
|
||||
&& $current_status === 'pending'
|
||||
&& is_array($application)
|
||||
&& !empty($application['name'])
|
||||
&& !empty($application['type'])
|
||||
) {
|
||||
update_user_meta($user_id, 'aksrt_user_verify_status', $status);
|
||||
update_user_meta($user_id, 'aksrt_user_verify_reviewed_at', current_time('mysql'));
|
||||
update_user_meta($user_id, 'aksrt_user_verify_reviewer', get_current_user_id());
|
||||
@@ -619,6 +630,15 @@ class UsersMenus {
|
||||
'time' => current_time('mysql'),
|
||||
];
|
||||
update_option('aksrt_verify_review_log', array_slice($log, -500), false);
|
||||
if (class_exists('\AKSRT\Messages\Message')) {
|
||||
$message = $status === 'verified'
|
||||
? __('您的官方认证申请已通过审核', 'aksrt')
|
||||
: sprintf(__('您的官方认证申请未通过:%s', 'aksrt'), $note !== '' ? $note : __('请修改资料后重新申请', 'aksrt'));
|
||||
\AKSRT\Messages\Message::get_instance()->send($user_id, 'auth_apply_reply', $message, [
|
||||
'title' => __('官方认证审核结果', 'aksrt'),
|
||||
'target_url' => aksrt_get_user_center_tab_url('auth'),
|
||||
]);
|
||||
}
|
||||
$ok = true;
|
||||
}
|
||||
$this->redirect('aksrt_user_auth', $ok ? 'verify_updated' : 'verify_failed', ['status' => 'pending']);
|
||||
|
||||
@@ -515,7 +515,7 @@ class SchemaUsers {
|
||||
'option_key' => 'aksrt_settings',
|
||||
'groups' => [
|
||||
['key' => 'center', 'title' => '用户中心', 'fields' => [
|
||||
['key' => 'user_center_tabs', 'label' => '用户中心 Tab', 'type' => 'input', 'default' => 'profile,posts,comments,favorites,vip,credits', 'help' => '逗号分隔。vip=我的会员(会员功能开启时也会自动注入)'],
|
||||
['key' => 'user_center_tabs', 'label' => '用户中心 Tab', 'type' => 'input', 'default' => 'profile,posts,comments,favorites,vip,credits,auth', 'help' => '逗号分隔。auth=官方认证;vip、订单和认证会按功能开关自动注入'],
|
||||
['key' => 'user_avatar_upload', 'label' => '头像上传', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'user_cover_upload', 'label' => '封面上传', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'user_social_links', 'label' => '社交链接', 'type' => 'switch', 'default' => true],
|
||||
|
||||
@@ -179,6 +179,11 @@ trait UserControllerVerifyIntegrations {
|
||||
if (!$user) {
|
||||
return $this->error(__('用户不存在', 'aksrt'), 404);
|
||||
}
|
||||
$current_status = sanitize_key((string) get_user_meta($user_id, 'aksrt_user_verify_status', true));
|
||||
$application = get_user_meta($user_id, 'aksrt_user_verify_apply', true);
|
||||
if ($current_status !== 'pending' || !is_array($application) || empty($application['name']) || empty($application['type'])) {
|
||||
return $this->error(__('该用户没有可审核的认证申请', 'aksrt'), 409);
|
||||
}
|
||||
|
||||
update_user_meta($user_id, 'aksrt_user_verify_status', $status);
|
||||
update_user_meta($user_id, 'aksrt_user_verify_reviewed_at', current_time('mysql'));
|
||||
@@ -216,6 +221,15 @@ trait UserControllerVerifyIntegrations {
|
||||
$log = array_slice($log, -500);
|
||||
}
|
||||
update_option('aksrt_verify_review_log', $log, false);
|
||||
if (class_exists('\AKSRT\Messages\Message')) {
|
||||
$message = $status === 'verified'
|
||||
? __('您的官方认证申请已通过审核', 'aksrt')
|
||||
: sprintf(__('您的官方认证申请未通过:%s', 'aksrt'), $note !== '' ? $note : __('请修改资料后重新申请', 'aksrt'));
|
||||
\AKSRT\Messages\Message::get_instance()->send($user_id, 'auth_apply_reply', $message, [
|
||||
'title' => __('官方认证审核结果', 'aksrt'),
|
||||
'target_url' => aksrt_get_user_center_tab_url('auth'),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'message' => $status === 'verified'
|
||||
@@ -239,7 +253,7 @@ trait UserControllerVerifyIntegrations {
|
||||
'email' => (string) ($row['user_email'] ?? ''),
|
||||
'status' => $status,
|
||||
'reason' => (string) ($row['verify_reason'] ?? ''),
|
||||
'requested_at' => (string) ($row['user_registered'] ?? ''),
|
||||
'requested_at' => (string) ($application['time'] ?? $row['user_registered'] ?? ''),
|
||||
'reviewed_at' => (string) ($row['reviewed_at'] ?? ''),
|
||||
'email_verified' => $email_verified,
|
||||
'application' => $application,
|
||||
|
||||
@@ -448,7 +448,9 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
|
||||
'aksrt-route-user-center',
|
||||
$base_uri . '/assets/js/routes/user-center.js',
|
||||
['aksrt-script'],
|
||||
$version,
|
||||
file_exists(get_template_directory() . '/assets/js/routes/user-center.js')
|
||||
? (string) filemtime(get_template_directory() . '/assets/js/routes/user-center.js')
|
||||
: $version,
|
||||
true
|
||||
);
|
||||
// 绑定手机短信发送按钮依赖 sign-register 的 data-aksrt-sms-trigger 契约
|
||||
@@ -623,38 +625,6 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
|
||||
}
|
||||
}
|
||||
|
||||
// 用户身份认证页(zibll user-auth.php)
|
||||
$is_user_auth_page = (bool) get_query_var('aksrt_user_auth')
|
||||
|| is_page_template('templates/pages/page-user-auth.php')
|
||||
|| (
|
||||
is_page()
|
||||
&& (
|
||||
(string) get_post_field('post_name', get_queried_object_id()) === 'user-auth'
|
||||
|| (string) get_post_meta(get_queried_object_id(), '_wp_page_template', true) === 'templates/pages/page-user-auth.php'
|
||||
)
|
||||
);
|
||||
if ($is_user_auth_page) {
|
||||
$ua_css = get_template_directory() . '/assets/css/routes/user-auth.css';
|
||||
if (file_exists($ua_css)) {
|
||||
wp_enqueue_style(
|
||||
'aksrt-route-user-auth',
|
||||
$base_uri . '/assets/css/routes/user-auth.css',
|
||||
['aksrt-tokens'],
|
||||
(string) filemtime($ua_css)
|
||||
);
|
||||
}
|
||||
$ua_js = get_template_directory() . '/assets/js/user-auth-page.js';
|
||||
if (file_exists($ua_js)) {
|
||||
wp_enqueue_script(
|
||||
'aksrt-user-auth-page',
|
||||
$base_uri . '/assets/js/user-auth-page.js',
|
||||
[],
|
||||
(string) filemtime($ua_js),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 交易中心共享壳层(购物车 / 订单 / 收益)
|
||||
// Virtual rewrite routes (aksrt_orders / aksrt_cart / aksrt_revenue) also count.
|
||||
$is_commerce_center = is_page_template('templates/pages/page-orders.php')
|
||||
|
||||
@@ -48,7 +48,6 @@ class Templates {
|
||||
'templates/pages/page-posts-navs.php' => __('AKSRT - 文章导航', 'aksrt'),
|
||||
'templates/pages/page-friends.php' => __('AKSRT - 友情链接', 'aksrt'),
|
||||
'templates/pages/page-links.php' => __('AKSRT - 网址导航', 'aksrt'),
|
||||
'templates/pages/page-user-auth.php' => __('AKSRT - 用户身份认证', 'aksrt'),
|
||||
'templates/pages/page-ban-appeal.php' => __('AKSRT - 禁封申诉', 'aksrt'),
|
||||
'templates/pages/page-orders.php' => __('AKSRT - 订单中心', 'aksrt'),
|
||||
'templates/pages/page-revenue.php' => __('AKSRT - 收益中心', 'aksrt'),
|
||||
|
||||
@@ -83,14 +83,14 @@ class UserRuntime {
|
||||
*/
|
||||
public static function get_user_center_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$raw_tabs = $settings['user_center_tabs'] ?? 'profile,posts,comments,credits,favorites';
|
||||
$raw_tabs = $settings['user_center_tabs'] ?? 'profile,posts,comments,credits,favorites,auth';
|
||||
$tabs = is_array($raw_tabs)
|
||||
? $raw_tabs
|
||||
: preg_split('/[\s,]+/', (string) $raw_tabs, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
// Built-in switchable panels. VIP is always auto-injected when enabled
|
||||
// by AKSRT\User\Center — keep it allowed for explicit config too.
|
||||
$allowed_tabs = ['profile', 'posts', 'comments', 'favorites', 'credits', 'vip', 'settings'];
|
||||
$allowed_tabs = ['profile', 'posts', 'comments', 'favorites', 'credits', 'vip', 'orders', 'auth', 'settings'];
|
||||
$normalized_tabs = ['profile'];
|
||||
|
||||
foreach ((array) $tabs as $tab) {
|
||||
|
||||
@@ -56,6 +56,12 @@ class AuthApply {
|
||||
}
|
||||
$types[] = ['slug' => $slug, 'label' => (string) $label];
|
||||
}
|
||||
if ($types === []) {
|
||||
$types = [
|
||||
['slug' => 'real_name', 'label' => __('实名认证', 'aksrt')],
|
||||
['slug' => 'organization', 'label' => __('企业认证', 'aksrt')],
|
||||
];
|
||||
}
|
||||
return [
|
||||
'enabled' => $enabled,
|
||||
'allow_apply' => !isset($all['user_verify_allow_apply']) || !empty($all['user_verify_allow_apply']),
|
||||
@@ -95,6 +101,13 @@ class AuthApply {
|
||||
return is_array($apply) ? $apply : [];
|
||||
}
|
||||
|
||||
public static function evidence_src(string $value): string {
|
||||
if (preg_match('#^data:image/(?:jpeg|png|gif|webp);base64,[A-Za-z0-9+/=]+$#', $value)) {
|
||||
return $value;
|
||||
}
|
||||
return esc_url_raw($value);
|
||||
}
|
||||
|
||||
public function ajax_apply(): void {
|
||||
if (!is_user_logged_in()) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('请先登录', 'aksrt')]);
|
||||
@@ -133,8 +146,9 @@ class AuthApply {
|
||||
$msg = isset($_POST['msg']) ? sanitize_textarea_field(wp_unslash((string) $_POST['msg'])) : '';
|
||||
$type = isset($_POST['type']) ? sanitize_key((string) wp_unslash($_POST['type'])) : '';
|
||||
$allowed_types = array_column((array) $s['types'], 'slug');
|
||||
if ($name === '') {
|
||||
wp_send_json(['error' => 1, 'msg' => __('请填写认证身份名称', 'aksrt')]);
|
||||
$name_length = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
|
||||
if ($name_length < 4 || $name_length > 16) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('认证身份长度需在 4-16 个字符之间', 'aksrt')]);
|
||||
}
|
||||
if ($type === '' || !in_array($type, $allowed_types, true)) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('请选择有效的认证类型', 'aksrt')]);
|
||||
@@ -142,46 +156,43 @@ class AuthApply {
|
||||
|
||||
$images = [];
|
||||
if (!empty($_FILES['image']['name'])) {
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/media.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
|
||||
$files = $_FILES['image'];
|
||||
// Normalize multi-file upload.
|
||||
$names = $files['name'];
|
||||
if (!is_array($names)) {
|
||||
$names = [$names];
|
||||
$tmp = [
|
||||
$names = is_array($files['name']) ? $files['name'] : [$files['name']];
|
||||
if (!is_array($files['name'])) {
|
||||
$files = [
|
||||
'name' => $names,
|
||||
'type' => [$files['type']],
|
||||
'tmp_name' => [$files['tmp_name']],
|
||||
'error' => [$files['error']],
|
||||
'size' => [$files['size']],
|
||||
];
|
||||
$files = $tmp;
|
||||
}
|
||||
$count = min(3, count($files['name']));
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (empty($files['name'][$i]) || (int) $files['error'][$i] !== UPLOAD_ERR_OK) {
|
||||
if (count($files['name']) > 3) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('证明材料最多上传 3 张', 'aksrt')]);
|
||||
}
|
||||
foreach ($files['name'] as $index => $filename) {
|
||||
if ($filename === '') {
|
||||
continue;
|
||||
}
|
||||
$file = [
|
||||
'name' => $files['name'][$i],
|
||||
'type' => $files['type'][$i],
|
||||
'tmp_name' => $files['tmp_name'][$i],
|
||||
'error' => $files['error'][$i],
|
||||
'size' => $files['size'][$i],
|
||||
];
|
||||
$_FILES['aksrt_auth_img'] = $file;
|
||||
$aid = media_handle_upload('aksrt_auth_img', 0);
|
||||
if (!is_wp_error($aid)) {
|
||||
$url = wp_get_attachment_url((int) $aid);
|
||||
if ($url) {
|
||||
$images[] = $url;
|
||||
}
|
||||
if ((int) ($files['error'][$index] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('证明材料上传失败,请重新选择', 'aksrt')]);
|
||||
}
|
||||
$size = (int) ($files['size'][$index] ?? 0);
|
||||
$tmp_name = (string) ($files['tmp_name'][$index] ?? '');
|
||||
if ($size <= 0 || $size > 2 * MB_IN_BYTES || !is_uploaded_file($tmp_name)) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('单张证明图片不能超过 2MB', 'aksrt')]);
|
||||
}
|
||||
$file_check = wp_check_filetype_and_ext($tmp_name, (string) $filename);
|
||||
$mime = (string) ($file_check['type'] ?? '');
|
||||
if (!in_array($mime, ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], true)) {
|
||||
wp_send_json(['error' => 1, 'msg' => __('证明材料仅支持 JPG、PNG、GIF 或 WebP 图片', 'aksrt')]);
|
||||
}
|
||||
$bytes = file_get_contents($tmp_name);
|
||||
if (!is_string($bytes) || $bytes === '') {
|
||||
wp_send_json(['error' => 1, 'msg' => __('证明材料读取失败', 'aksrt')]);
|
||||
}
|
||||
$images[] = 'data:' . $mime . ';base64,' . base64_encode($bytes);
|
||||
}
|
||||
unset($_FILES['aksrt_auth_img']);
|
||||
}
|
||||
|
||||
$payload = [
|
||||
|
||||
@@ -91,6 +91,12 @@ class Center {
|
||||
'priority' => 60,
|
||||
'type' => 'link',
|
||||
],
|
||||
'auth' => [
|
||||
'label' => __('官方认证', 'aksrt'),
|
||||
'icon' => 'id-badge',
|
||||
'priority' => 65,
|
||||
'type' => 'panel',
|
||||
],
|
||||
'settings' => [
|
||||
'label' => __('账号设置', 'aksrt'),
|
||||
'icon' => 'cog',
|
||||
@@ -144,6 +150,11 @@ class Center {
|
||||
if (($credits_on || $balance_on) && !in_array('credits', $order, true)) {
|
||||
$order[] = 'credits';
|
||||
}
|
||||
$auth_on = class_exists('\AKSRT\User\AuthApply')
|
||||
&& !empty(\AKSRT\User\AuthApply::settings()['enabled']);
|
||||
if ($auth_on && !in_array('auth', $order, true)) {
|
||||
$order[] = 'auth';
|
||||
}
|
||||
if (!in_array('settings', $order, true)) {
|
||||
$order[] = 'settings';
|
||||
}
|
||||
@@ -161,6 +172,9 @@ class Center {
|
||||
if ($key === 'orders' && !$orders_on) {
|
||||
continue;
|
||||
}
|
||||
if ($key === 'auth' && !$auth_on) {
|
||||
continue;
|
||||
}
|
||||
$panel = $definitions[$key];
|
||||
if ($key === 'credits' && $balance_on) {
|
||||
$panel['label'] = __('我的资产', 'aksrt');
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Template Name: AKSRT - 用户身份认证
|
||||
* Template Post Type: page
|
||||
*
|
||||
* Zibll pages/user-auth.php 1:1 shell on aksrt_user_verify_* storage.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
use AKSRT\User\AuthApply;
|
||||
|
||||
$settings = class_exists(AuthApply::class) ? AuthApply::settings() : ['enabled' => true, 'allow_apply' => true];
|
||||
$user_id = get_current_user_id();
|
||||
$status = $user_id && class_exists(AuthApply::class) ? AuthApply::get_status($user_id) : '';
|
||||
$info = $user_id && class_exists(AuthApply::class) ? AuthApply::get_auth_info($user_id) : [];
|
||||
$apply = $user_id && class_exists(AuthApply::class) ? AuthApply::get_apply_payload($user_id) : [];
|
||||
$login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url(aksrt_get_user_auth_page_url()) : wp_login_url(aksrt_get_user_auth_page_url());
|
||||
|
||||
get_header();
|
||||
?>
|
||||
<main class="container page-template-user-auth">
|
||||
<div class="content-wrap">
|
||||
<div class="content-layout">
|
||||
<?php while (have_posts()) : the_post(); ?>
|
||||
<div class="nopw-sm box-body theme-box radius8 main-bg main-shadow">
|
||||
<article class="article wp-posts-content">
|
||||
<?php
|
||||
the_content();
|
||||
wp_link_pages([
|
||||
'before' => '<p class="text-center post-nav-links radius8 padding-6">',
|
||||
'after' => '</p>',
|
||||
]);
|
||||
?>
|
||||
</article>
|
||||
</div>
|
||||
<?php endwhile; ?>
|
||||
|
||||
<div class="theme-box radius8 main-bg main-shadow relative-h aksrt-user-auth-panel">
|
||||
<?php if (empty($settings['enabled'])) : ?>
|
||||
<div class="colorful-bg c-blue flex jc" style="min-height:120px;align-items:center;justify-content:center;">
|
||||
<div class="text-center">
|
||||
<div class="em2x"><i class="fa fa-id-badge" aria-hidden="true"></i></div>
|
||||
<div class="mt10 em12"><?php esc_html_e('身份认证功能未启用', 'aksrt'); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif ($status === 'verified') : ?>
|
||||
<?php
|
||||
$name = (string) ($info['name'] ?? ($apply['name'] ?? __('官方认证', 'aksrt')));
|
||||
$desc = (string) ($info['desc'] ?? ($apply['desc'] ?? ''));
|
||||
$time = (string) ($info['time'] ?? get_user_meta($user_id, 'aksrt_user_verify_reviewed_at', true));
|
||||
?>
|
||||
<div class="colorful-bg c-blue flex ac jse aksrt-user-auth-panel__verified" style="padding:30px 16px;gap:20px;flex-wrap:wrap;">
|
||||
<div class="text-center flex0">
|
||||
<div class="em3x"><i class="fa fa-id-badge" aria-hidden="true"></i></div>
|
||||
<div class="mt10 padding-w10"><?php esc_html_e('我的认证信息', 'aksrt'); ?></div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div><i class="fa fa-check-circle" aria-hidden="true"></i> <b class="ml3"><?php echo esc_html($name); ?></b></div>
|
||||
<?php if ($desc !== '') : ?>
|
||||
<div class="muted-2-color mt10"><?php echo esc_html($desc); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($time !== '') : ?>
|
||||
<div class="muted-2-color mt10"><?php echo esc_html(sprintf(__('认证时间:%s', 'aksrt'), $time)); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif (!$user_id) : ?>
|
||||
<div class="colorful-bg c-blue flex jc" style="min-height:120px;align-items:center;justify-content:center;padding:24px;">
|
||||
<div class="text-center">
|
||||
<div class="em2x"><i class="fa fa-id-badge" aria-hidden="true"></i></div>
|
||||
<div class="em12 padding-w10 mt10"><?php esc_html_e('申请身份认证', 'aksrt'); ?></div>
|
||||
<p class="mt20">
|
||||
<a class="but c-blue padding-lg signin-loader" href="<?php echo esc_url($login_url); ?>">
|
||||
<i class="fa fa-sign-in mr6" aria-hidden="true"></i><?php esc_html_e('登录后申请', 'aksrt'); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif ($status === 'pending') : ?>
|
||||
<div class="box-body" style="padding:24px;">
|
||||
<div class="c-red mb10"><?php esc_html_e('您的申请正在审核中,请耐心等待', 'aksrt'); ?></div>
|
||||
<div><i class="fa fa-id-badge" aria-hidden="true"></i> <b class="ml3"><?php echo esc_html((string) ($apply['name'] ?? '')); ?></b></div>
|
||||
<?php if (!empty($apply['desc'])) : ?>
|
||||
<div class="muted-2-color mt10"><?php echo esc_html((string) $apply['desc']); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($apply['msg'])) : ?>
|
||||
<div class="muted-2-color mt10"><?php echo esc_html(sprintf(__('申请说明:%s', 'aksrt'), (string) $apply['msg'])); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($apply['time'])) : ?>
|
||||
<div class="muted-2-color mt10"><?php echo esc_html(sprintf(__('申请时间:%s', 'aksrt'), (string) $apply['time'])); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($apply['img']) && is_array($apply['img'])) : ?>
|
||||
<div class="mt20 aksrt-user-auth-panel__imgs">
|
||||
<?php foreach ($apply['img'] as $img_url) : ?>
|
||||
<div class="preview-item"><img src="<?php echo esc_url((string) $img_url); ?>" alt=""></div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php elseif (empty($settings['allow_apply'])) : ?>
|
||||
<div class="box-body" style="padding:24px;">
|
||||
<div class="c-red"><i class="fa mr6 fa-info-circle" aria-hidden="true"></i><?php esc_html_e('抱歉!暂时不能申请身份认证', 'aksrt'); ?></div>
|
||||
<?php if (!empty($settings['disable_desc'])) : ?>
|
||||
<div class="muted-color mt20"><?php echo wp_kses_post(nl2br(esc_html((string) $settings['disable_desc']))); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
$blocked_level = false;
|
||||
$limit = (int) ($settings['limit_level'] ?? 0);
|
||||
if ($limit > 0 && class_exists('\AKSRT\User\Level')) {
|
||||
$lv = (int) \AKSRT\User\Level::get_level($user_id);
|
||||
if ($lv < $limit) {
|
||||
$blocked_level = true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php if ($blocked_level) : ?>
|
||||
<div class="box-body" style="padding:24px;">
|
||||
<div class="c-red"><i class="fa mr6 fa-info-circle" aria-hidden="true"></i><?php esc_html_e('抱歉!您暂时不能申请身份认证', 'aksrt'); ?></div>
|
||||
<div class="muted-color mt20">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %d level */
|
||||
esc_html__('由于您的等级过低,请升级到 LV.%d 后再来申请', 'aksrt'),
|
||||
$limit
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="colorful-bg c-blue flex ac" style="height:100px;justify-content:center;gap:10px;">
|
||||
<div class="em2x"><i class="fa fa-id-badge" aria-hidden="true"></i></div>
|
||||
<div class="em12 padding-w10"><?php esc_html_e('申请身份认证', 'aksrt'); ?></div>
|
||||
</div>
|
||||
<div class="box-body" style="padding:20px;">
|
||||
<?php if ($status === 'rejected') : ?>
|
||||
<div class="c-red mb15">
|
||||
<?php esc_html_e('上次申请未通过,可修改资料后重新提交。', 'aksrt'); ?>
|
||||
<?php
|
||||
$reason = (string) get_user_meta($user_id, AuthApply::REASON_META, true);
|
||||
if ($reason !== '') {
|
||||
echo '<div class="muted-2-color mt6">' . esc_html(sprintf(__('原因:%s', 'aksrt'), $reason)) . '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($settings['desc'])) : ?>
|
||||
<div class="muted-color mb20"><?php echo wp_kses_post(nl2br(esc_html((string) $settings['desc']))); ?></div>
|
||||
<?php endif; ?>
|
||||
<form class="aksrt-user-auth-form form-upload" enctype="multipart/form-data">
|
||||
<?php if (!empty($settings['types'])) : ?>
|
||||
<div class="mb20">
|
||||
<div class="em09 muted-2-color mb6"><?php esc_html_e('认证类型', 'aksrt'); ?></div>
|
||||
<select class="form-control" name="type">
|
||||
<?php foreach ($settings['types'] as $t) : ?>
|
||||
<option value="<?php echo esc_attr($t['slug']); ?>"><?php echo esc_html($t['label']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="mb20">
|
||||
<div class="em09 muted-2-color mb6"><?php esc_html_e('认证身份', 'aksrt'); ?></div>
|
||||
<input type="text" class="form-control" name="name" required placeholder="<?php esc_attr_e('请输入身份名称', 'aksrt'); ?>" value="<?php echo esc_attr((string) ($apply['name'] ?? '')); ?>">
|
||||
</div>
|
||||
<div class="mb20">
|
||||
<div class="em09 muted-2-color mb6"><?php esc_html_e('身份简介', 'aksrt'); ?></div>
|
||||
<textarea class="form-control" name="desc" rows="2" placeholder="<?php esc_attr_e('请输入申请的身份简介', 'aksrt'); ?>"><?php echo esc_textarea((string) ($apply['desc'] ?? '')); ?></textarea>
|
||||
</div>
|
||||
<div class="mb20">
|
||||
<div class="em09 muted-2-color mb6"><?php esc_html_e('申请说明', 'aksrt'); ?></div>
|
||||
<textarea class="form-control" name="msg" rows="2" placeholder="<?php esc_attr_e('请输入申请缘由及说明', 'aksrt'); ?>"><?php echo esc_textarea((string) ($apply['msg'] ?? '')); ?></textarea>
|
||||
</div>
|
||||
<div class="mb20">
|
||||
<div class="em09 muted-2-color mb6"><?php esc_html_e('证明材料', 'aksrt'); ?></div>
|
||||
<input type="file" name="image[]" accept="image/gif,image/jpeg,image/jpg,image/png" multiple>
|
||||
<div class="px12 muted-2-color mt6"><?php esc_html_e('最多 3 张图片', 'aksrt'); ?></div>
|
||||
</div>
|
||||
<?php wp_nonce_field('aksrt_user_auth_apply', '_wpnonce', false); ?>
|
||||
<input type="hidden" name="action" value="aksrt_user_auth_apply">
|
||||
<button type="submit" class="but c-blue padding-lg btn-block">
|
||||
<i class="fa fa-check" aria-hidden="true"></i> <?php esc_html_e('确认提交', 'aksrt'); ?>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if (comments_open() || get_comments_number()) {
|
||||
comments_template();
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php get_sidebar(); ?>
|
||||
</main>
|
||||
<?php
|
||||
get_footer();
|
||||
Reference in New Issue
Block a user