diff --git a/assets/css/routes/user-center/settings.css b/assets/css/routes/user-center/settings.css
index ecf1c4d4..f5fc18d2 100644
--- a/assets/css/routes/user-center/settings.css
+++ b/assets/css/routes/user-center/settings.css
@@ -519,20 +519,171 @@
margin: 20px 0 0;
}
-.uc-auth-modal__dialog { width: min(620px, calc(100vw - 28px)); max-width: 620px; max-height: min(760px, calc(100vh - 40px)); overflow: auto; background: var(--surface-1, #fff); }
-.aksrt-identity-modal-shell .aksrt-modal-runtime__dialog { width: min(620px, calc(100vw - 28px)); max-width: 620px; }
-.aksrt-identity-modal-shell .uc-auth-modal__dialog { width: auto; max-width: none; max-height: none; overflow: visible; background: transparent; }
-.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-field { 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; }
+.aksrt-identity-modal-shell .aksrt-modal-runtime__dialog {
+ width: min(600px, calc(100vw - 20px));
+ max-width: 600px;
+ max-height: calc(100vh - 20px);
+ max-height: calc(100dvh - 20px);
+ overflow: auto;
+ border-radius: var(--main-radius, 8px);
+ background: var(--main-bg-color, var(--surface-1, #fff));
+}
+.aksrt-identity-modal-shell .aksrt-modal-runtime__content { padding: 0; }
+.uc-auth-modal {
+ position: relative;
+ overflow: hidden;
+ padding: 1px;
+ border-radius: var(--main-radius, 8px);
+ background: var(--main-bg-color, var(--surface-1, #fff));
+}
+.uc-auth-modal__header,
+.uc-auth-modal__header.colorful-bg {
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ left: 1px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 120px;
+ overflow: hidden;
+ border-radius: var(--main-radius, 8px) var(--main-radius, 8px) 0 0;
+ background: var(--this-bg);
+ background-size: 120%;
+ color: var(--this-color);
+}
+.uc-auth-modal__header > .close {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ z-index: 9;
+ width: 30px;
+ height: 30px;
+ padding: 0;
+ border: 0;
+ background: transparent;
+ color: var(--this-color);
+ font-size: 18px;
+ line-height: 1;
+ opacity: .6;
+ cursor: pointer;
+}
+.uc-auth-modal__header > .close:hover { opacity: 1; }
+.uc-auth-modal__header .colorful-make,
+.uc-auth-modal__header .colorful-make::before,
+.uc-auth-modal__header .colorful-make::after {
+ position: absolute;
+ border-radius: 100%;
+ background: var(--this-bg);
+ color: var(--this-color);
+ content: '';
+}
+.uc-auth-modal__header .colorful-make {
+ top: 60%;
+ bottom: 0;
+ width: 323px;
+ height: 290px;
+ animation: uc-auth-colorful 120s linear infinite;
+}
+.uc-auth-modal__header .colorful-make::before {
+ top: -325px;
+ right: -558px;
+ bottom: 0;
+ width: 677px;
+ height: 300px;
+ transform: rotate(341deg);
+ opacity: .6;
+}
+.uc-auth-modal__header .colorful-make::after {
+ top: -170px;
+ bottom: 0;
+ left: -262px;
+ width: 402px;
+ height: 214px;
+ transform: rotate(326deg);
+ opacity: .4;
+}
+.uc-auth-modal__header .colorful-make + * { position: relative; }
+.uc-auth-modal__body {
+ position: relative;
+ margin-top: 120px;
+ padding: 15px;
+ background: var(--main-bg-color, var(--surface-1, #fff));
+}
+.uc-auth-form { margin: 0; }
+.uc-auth-form__scroll { max-height: 50vh; max-height: 50dvh; }
+.uc-auth-field { display: block; color: var(--muted-2-color); font-size: .9em; font-weight: 400; }
+.uc-auth-field__label { display: block; margin-bottom: 6px; }
+.uc-auth-form .form-control { width: 100%; box-sizing: border-box; }
.uc-auth-form textarea.form-control { resize: vertical; }
-.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 .preview .add {
+ appearance: none;
+ padding: 0;
+ border: 0;
+ cursor: pointer;
+}
+.uc-auth-upload .preview-item { overflow: hidden; }
+.uc-auth-upload .preview-item img { object-fit: contain; }
+.uc-auth-preview-remove {
+ position: absolute;
+ top: 5px;
+ right: 5px;
+ display: grid;
+ place-items: center;
+ width: 24px;
+ height: 24px;
+ padding: 0;
+ border: 0;
+ border-radius: 50%;
+ background: #fd2c53;
+ color: #fff;
+ font-size: 20px;
+ line-height: 1;
+ cursor: pointer;
+}
+.aksrt-identity-modal-shell .uc-auth-modal .uc-auth-modal__body .uc-auth-modal__footer {
+ display: flex;
+ grid-template-columns: none;
+ gap: 0;
+ margin: 0 -15px -15px;
+ overflow: hidden;
+ border-top: 1px solid var(--main-border-color, var(--color-line, rgba(50, 50, 50, .12)));
+ border-radius: 0 0 var(--main-radius, 8px) var(--main-radius, 8px);
+}
+.aksrt-identity-modal-shell .uc-auth-modal .uc-auth-modal__body .uc-auth-modal__footer > .but {
+ display: flex;
+ flex: 1 1 50%;
+ align-items: center;
+ justify-content: center;
+ min-height: 48px;
+ margin: 0 !important;
+ padding: .8em;
+ border: 0;
+ border-radius: 0;
+ background: transparent;
+ color: var(--muted-color, #888);
+ font: inherit;
+ font-weight: 400;
+ cursor: pointer;
+}
+.aksrt-identity-modal-shell .uc-auth-modal .uc-auth-modal__body .uc-auth-modal__footer > .but + .but {
+ border-left: 1px solid var(--main-border-color, var(--color-line, rgba(50, 50, 50, .12)));
+}
+.aksrt-identity-modal-shell .uc-auth-modal .uc-auth-modal__body .uc-auth-modal__footer > .but.c-blue {
+ background: transparent;
+ color: var(--this-color, #2997f7);
+}
+.aksrt-identity-modal-shell .uc-auth-modal .uc-auth-modal__body .uc-auth-modal__footer > .but:hover {
+ background: var(--this-bg, rgba(136, 136, 136, .1));
+}
+.aksrt-identity-modal-shell .uc-auth-modal .uc-auth-modal__body .uc-auth-modal__footer > .but:disabled { opacity: .5; cursor: wait; }
+@keyframes uc-auth-colorful { to { transform: rotate(360deg); } }
-@media (max-width: 640px) {
- .uc-auth-modal__dialog { position: fixed; inset: auto 0 0; width: 100%; max-width: none; max-height: 88vh; margin: 0; border-radius: 18px 18px 0 0; }
+@media (max-width: 768px) {
+ .aksrt-identity-modal-shell.aksrt-modal-runtime--bottom .aksrt-modal-runtime__dialog {
+ width: calc(100% - 20px);
+ max-width: none;
+ max-height: calc(100dvh - 30px - env(safe-area-inset-bottom));
+ margin: 0 10px calc(10px + env(safe-area-inset-bottom));
+ }
}
diff --git a/assets/js/routes/user-center-auth.js b/assets/js/routes/user-center-auth.js
index 50084a7c..b5d2c475 100644
--- a/assets/js/routes/user-center-auth.js
+++ b/assets/js/routes/user-center-auth.js
@@ -15,6 +15,10 @@
return error && error.message ? error.message : fallback;
}
+ function toast(message, type, time, id) {
+ if (message && typeof window.notyf === 'function') window.notyf(message, type || 'success', time, id);
+ }
+
function init(root) {
if (!root || root.dataset.identityBound === '1') return;
root.dataset.identityBound = '1';
@@ -27,39 +31,154 @@
function open() {
runtime.open({
html: template.innerHTML,
+ height: 320,
kind: 'identity',
className: 'aksrt-identity-modal-shell',
mobileBottom: true,
onContent: function (_, session) {
var shell = session && session.shell;
var form = shell && shell.querySelector('[data-auth-create]');
- if (!form) return;
- form.addEventListener('submit', function (event) {
- event.preventDefault();
- var input = form.querySelector('[name="evidence[]"]');
- var message = form.querySelector('[data-auth-message]');
- var button = form.querySelector('[type="submit"]');
- var files = input ? Array.prototype.slice.call(input.files || []) : [];
- if (files.length > 3) {
- if (message) message.textContent = '证明材料最多上传 3 张';
+ var input = form && form.querySelector('[data-auth-evidence]');
+ var preview = form && form.querySelector('[data-auth-preview]');
+ if (!form || !input || !preview) return;
+ shell.setAttribute('aria-labelledby', 'uc-auth-modal-title');
+
+ var selectedFiles = [];
+ function renderPreview() {
+ preview.replaceChildren();
+ selectedFiles.forEach(function (entry, index) {
+ var item = document.createElement('div');
+ item.className = 'preview-item';
+ var image = document.createElement('img');
+ image.className = 'fit-cover';
+ image.src = entry.url;
+ image.alt = entry.file.name;
+ var remove = document.createElement('button');
+ remove.type = 'button';
+ remove.className = 'uc-auth-preview-remove';
+ remove.dataset.authRemove = String(index);
+ remove.setAttribute('aria-label', '移除 ' + entry.file.name);
+ remove.textContent = '×';
+ item.appendChild(image);
+ item.appendChild(remove);
+ preview.appendChild(item);
+ });
+
+ if (selectedFiles.length < 3) {
+ var add = document.createElement('button');
+ add.type = 'button';
+ add.className = 'add';
+ add.dataset.authFilePicker = '';
+ add.setAttribute('aria-label', '选择证明材料图片');
+ preview.appendChild(add);
+ }
+ }
+
+ function releasePreviewUrls() {
+ selectedFiles.forEach(function (entry) { window.URL.revokeObjectURL(entry.url); });
+ selectedFiles = [];
+ }
+
+ function onModalClose(event) {
+ if (!event.detail || event.detail.shell !== shell) return;
+ document.removeEventListener('aksrt:modal:close', onModalClose);
+ releasePreviewUrls();
+ }
+
+ document.addEventListener('aksrt:modal:close', onModalClose);
+ preview.addEventListener('click', function (event) {
+ var remove = event.target.closest('[data-auth-remove]');
+ if (remove) {
+ var index = Number(remove.dataset.authRemove);
+ var entry = selectedFiles[index];
+ if (entry) window.URL.revokeObjectURL(entry.url);
+ selectedFiles.splice(index, 1);
+ renderPreview();
+ return;
+ }
+ if (event.target.closest('[data-auth-file-picker]')) input.click();
+ });
+ input.addEventListener('change', function () {
+ var files = Array.prototype.slice.call(input.files || []);
+ input.value = '';
+ if (!files.length) return;
+
+ var unsupported = files.some(function (file) { return !/^image\/(gif|jpe?g|png)$/i.test(file.type); });
+ if (unsupported) {
+ toast('证明材料仅支持 GIF、JPG、PNG 图片', 'danger');
return;
}
if (files.some(function (file) { return file.size > 2 * 1024 * 1024; })) {
- if (message) message.textContent = '单张证明材料不能超过 2MB';
+ toast('单张证明材料不能超过 2MB', 'danger');
return;
}
- if (button) button.disabled = true;
- if (message) message.textContent = '';
+ var uniqueFiles = files.filter(function (file, index) {
+ var key = [file.name, file.size, file.lastModified].join(':');
+ return !selectedFiles.some(function (entry) { return entry.key === key; }) &&
+ files.findIndex(function (candidate) {
+ return [candidate.name, candidate.size, candidate.lastModified].join(':') === key;
+ }) === index;
+ });
+ if (selectedFiles.length + uniqueFiles.length > 3) {
+ toast('证明材料最多上传 3 张', 'danger');
+ return;
+ }
+
+ uniqueFiles.forEach(function (file) {
+ selectedFiles.push({
+ file: file,
+ key: [file.name, file.size, file.lastModified].join(':'),
+ url: window.URL.createObjectURL(file),
+ });
+ });
+ renderPreview();
+ });
+
+ var header = shell.querySelector('.uc-auth-modal__header');
+ if (header) {
+ var touchStartY = null;
+ header.addEventListener('touchstart', function (event) {
+ touchStartY = event.touches.length ? event.touches[0].clientY : null;
+ }, { passive: true });
+ header.addEventListener('touchend', function (event) {
+ var touchEndY = event.changedTouches.length ? event.changedTouches[0].clientY : null;
+ if (touchStartY !== null && touchEndY !== null && touchEndY - touchStartY > 60 &&
+ runtime.getActive && runtime.getActive() === shell) {
+ runtime.close('swipe');
+ }
+ touchStartY = null;
+ }, { passive: true });
+ }
+
+ form.addEventListener('submit', function (event) {
+ event.preventDefault();
+ var invalidField = form.querySelector(':invalid');
+ if (!form.checkValidity()) {
+ toast((invalidField && invalidField.validationMessage) || '请检查申请信息是否填写完整', 'danger');
+ if (invalidField && typeof invalidField.focus === 'function') invalidField.focus();
+ return;
+ }
+ var button = form.querySelector('[type="submit"]');
+ var formData = new FormData(form);
+ selectedFiles.forEach(function (entry) {
+ formData.append('evidence[]', entry.file, entry.file.name);
+ });
+ var submitLabel = button ? button.innerHTML : '';
+ if (button) {
+ button.disabled = true;
+ button.innerHTML = '正在提交…';
+ }
+ toast('正在提交申请…', 'load', '', 'aksrt_identity_submit');
window.AksrtRequest.request(config.restBase, {
method: 'POST',
credentials: 'same-origin',
headers: { 'X-WP-Nonce': config.nonce || '' },
- body: new FormData(form),
+ body: formData,
}).then(function (response) {
var result = parseResponse(response);
if (!result || result.success === false) throw new Error((result && result.message) || '申请提交失败,请稍后重试');
- if (message) message.textContent = '申请已提交,请耐心等待管理员审核。';
+ toast('申请已提交,请耐心等待管理员审核。', 'success', '', 'aksrt_identity_submit');
var summary = root.querySelector('[data-auth-summary]');
if (summary) {
summary.replaceChildren();
@@ -101,9 +220,12 @@
}
if (runtime.getActive && runtime.getActive() === shell) runtime.close('submit');
}).catch(function (error) {
- if (message) message.textContent = errorMessage(error, '申请提交失败,请稍后重试');
+ toast(errorMessage(error, '申请提交失败,请稍后重试'), 'danger', '', 'aksrt_identity_submit');
}).finally(function () {
- if (button) button.disabled = false;
+ if (button) {
+ button.disabled = false;
+ button.innerHTML = submitLabel;
+ }
});
});
},
diff --git a/inc/helpers/user-center-renderers/profile-auth.php b/inc/helpers/user-center-renderers/profile-auth.php
index 3620ebd5..02bf6c15 100644
--- a/inc/helpers/user-center-renderers/profile-auth.php
+++ b/inc/helpers/user-center-renderers/profile-auth.php
@@ -14,7 +14,8 @@ $info = is_array($snapshot['info'] ?? null) ? $snapshot['info'] : [];
$application = is_array($snapshot['application'] ?? null) ? $snapshot['application'] : [];
$status = (string) ($snapshot['status'] ?? '');
$can_apply = !empty($snapshot['can_apply']);
-$auth_icon = '';
+$auth_icon = function_exists('aksrt_icon_markup') ? aksrt_icon_markup('zibsvg-user-auth') : '';
+$close_icon = function_exists('aksrt_icon_markup') ? aksrt_icon_markup('zibsvg-close', 'ic-close') : '';
$config = [
'restBase' => untrailingslashit(rest_url('aksrt/v1/identity/applications')),
'nonce' => wp_create_nonce('wp_rest'),
@@ -53,20 +54,35 @@ $config = [
-
-