(function (window, document) { 'use strict'; function parseConfig(root) { try { return JSON.parse(root.getAttribute('data-identity-config') || '{}'); } catch (_) { return {}; } } function uuid() { if (window.crypto && crypto.randomUUID) return crypto.randomUUID(); return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0; return (c === 'x' ? r : (r & 3 | 8)).toString(16); }); } function request(path, config, options) { options = Object.assign({}, options || {}); options.credentials = 'same-origin'; options.headers = Object.assign({ 'X-WP-Nonce': config.nonce || '' }, options.headers || {}); return window.AksrtRequest.request(path, options).then(function (response) { return response.data !== undefined ? response.data : response.json; }); } function errorMessage(error, fallback) { if (error && error.json) { return error.json.message || (error.json.data && error.json.data.message) || fallback; } return error && error.message ? error.message : fallback; } function loadScript(src) { return new Promise(function (resolve, reject) { var existing = document.querySelector('script[src="' + src + '"]'); if (existing) { if (existing.dataset.loaded === '1') return resolve(); existing.addEventListener('load', resolve, { once: true }); existing.addEventListener('error', reject, { once: true }); return; } var script = document.createElement('script'); script.src = src; script.async = true; script.onload = function () { script.dataset.loaded = '1'; resolve(); }; script.onerror = reject; document.head.appendChild(script); }); } function aliyunMetaInfo(config) { if (config.provider !== 'aliyun') return Promise.resolve(''); return loadScript('https://o.alicdn.com/yd-cloudauth/cloudauth-cdn/jsvm_all.js').then(function () { if (typeof window.getMetaInfo !== 'function') throw new Error('阿里云 MetaInfo 组件未加载成功'); var meta = window.getMetaInfo(); return typeof meta === 'string' ? meta : JSON.stringify(meta || {}); }); } function init(root) { if (!root || root.dataset.identityBound === '1') return; root.dataset.identityBound = '1'; var config = parseConfig(root); var template = root.querySelector('[data-auth-modal-template]'); var runtime = window.AksrtModalRuntime; if (!template) return; var activeShell = null; var currentUuid = config.currentUuid || ''; var currentStage = config.currentStage || ''; var pollTimer = null; var pollBackoff = 0; var currentController = null; var refreshController = null; var refreshTimeout = null; var refreshInFlight = false; var openSequence = 0; function isOpen(shell) { return !!shell && shell.classList.contains('is-open') && document.contains(shell); } function stopPolling() { if (pollTimer) window.clearTimeout(pollTimer); pollTimer = null; } function abortCurrent() { if (currentController) { try { currentController.abort(); } catch (_) {} } currentController = null; } function abortRefresh() { if (refreshTimeout) window.clearTimeout(refreshTimeout); refreshTimeout = null; if (refreshController) { try { refreshController.abort(); } catch (_) {} } refreshController = null; refreshInFlight = false; } function setMessage(shell, message) { var node = shell && shell.querySelector('[data-auth-status-message]'); if (node) node.textContent = message || ''; } function updateSummary(data) { if (!data || data.status !== 'verified') return; var trigger = root.querySelector('[data-auth-modal-open]'); if (trigger) { trigger.disabled = true; trigger.textContent = '已认证'; } runtime.invalidate(['identity']); document.dispatchEvent(new CustomEvent('aksrt:identity:changed', { detail: { status: data.status } })); } function schedulePoll(delay) { stopPolling(); if (!currentUuid || !isOpen(activeShell) || document.visibilityState !== 'visible') return; var base = Math.max(5, Number(delay || config.pollInterval || 5)); var seconds = Math.min(60, base * Math.pow(2, Math.min(4, pollBackoff))); pollTimer = window.setTimeout(function () { pollTimer = null; refresh(false); }, seconds * 1000); } function render(data, shell) { if (!shell || shell !== activeShell || !isOpen(shell)) return; data = data || {}; var previousStage = currentStage; currentUuid = data.uuid || currentUuid; currentStage = data.stage || currentStage; if (data.stage && data.stage !== previousStage) runtime.invalidate(['identity']); var lock = ['created', 'provider_pending', 'provider_processing', 'manual_pending'].indexOf(currentStage) !== -1; var retryable = data.next_action === 'manual_or_retry'; var statusBox = shell.querySelector('[data-auth-status]'); var createForm = shell.querySelector('[data-auth-create]'); var stageNode = shell.querySelector('[data-auth-stage]'); var messageNode = shell.querySelector('[data-auth-status-message]'); var continueLink = shell.querySelector('[data-auth-continue]'); var manualButton = shell.querySelector('[data-auth-manual-open]'); if (statusBox) statusBox.hidden = !data.uuid && !retryable; if (createForm) createForm.hidden = lock || data.status === 'verified'; if (stageNode) stageNode.textContent = data.stage || data.status || '准备认证'; if (messageNode) messageNode.textContent = data.message || '认证结果以站点服务端主动查询为准。'; if (continueLink) { var canContinue = data.next_action === 'poll' && data.redirect_url; continueLink.hidden = !canContinue; if (canContinue) continueLink.href = data.redirect_url; } if (manualButton) manualButton.hidden = !retryable; if (data.status === 'verified' || data.next_action !== 'poll') { pollBackoff = 0; stopPolling(); } else if (isOpen(shell) && document.visibilityState === 'visible') { schedulePoll(data.poll_interval || config.pollInterval); } updateSummary(data); } function refresh(explicit) { if (!currentUuid || !isOpen(activeShell) || document.visibilityState !== 'visible' || refreshInFlight) { return Promise.resolve(null); } stopPolling(); abortRefresh(); refreshInFlight = true; refreshController = window.AbortController ? new window.AbortController() : null; var timedOut = false; var shell = activeShell; var timeoutMs = Math.max(5000, Number(config.refreshTimeout || 15000)); refreshTimeout = window.setTimeout(function () { timedOut = true; if (refreshController) { try { refreshController.abort(); } catch (_) {} } }, timeoutMs); return request(config.restBase + '/' + encodeURIComponent(currentUuid) + '/refresh', config, { method: 'POST', signal: refreshController ? refreshController.signal : undefined, }).then(function (data) { if (shell !== activeShell || !isOpen(shell)) return data; pollBackoff = explicit ? 0 : Math.min(4, pollBackoff + 1); render(data, shell); return data; }).catch(function (error) { var aborted = error && (error.name === 'AbortError' || error.code === 'ABORT_ERR'); if (shell !== activeShell || !isOpen(shell) || (aborted && !timedOut)) return null; setMessage(shell, timedOut ? '云端刷新超时,请稍后重试。' : errorMessage(error, '刷新失败,请稍后重试。')); pollBackoff = Math.min(4, pollBackoff + 1); schedulePoll(config.pollInterval || 5); return null; }).finally(function () { if (refreshTimeout) window.clearTimeout(refreshTimeout); refreshTimeout = null; refreshController = null; refreshInFlight = false; }); } function loadCurrent(shell, sequence) { abortCurrent(); currentController = window.AbortController ? new window.AbortController() : null; var controller = currentController; return request(config.restBase + '/current', config, { method: 'GET', signal: controller ? controller.signal : undefined, }).then(function (snapshot) { if (sequence !== openSequence || shell !== activeShell || !isOpen(shell)) return; var data = snapshot && (snapshot.current || snapshot.active || snapshot.latest); if (!data) { currentUuid = ''; currentStage = ''; var statusBox = shell.querySelector('[data-auth-status]'); var createForm = shell.querySelector('[data-auth-create]'); if (statusBox) statusBox.hidden = true; if (createForm) createForm.hidden = false; stopPolling(); return; } render(data, shell); }).catch(function (error) { var aborted = error && (error.name === 'AbortError' || error.code === 'ABORT_ERR'); if (aborted || sequence !== openSequence || shell !== activeShell || !isOpen(shell)) return; setMessage(shell, errorMessage(error, '状态加载失败,请稍后重试。')); }).finally(function () { if (currentController === controller) currentController = null; }); } function bindForm(shell) { var createForm = shell.querySelector('[data-auth-create]'); var manualForm = shell.querySelector('[data-auth-manual]'); var statusBox = shell.querySelector('[data-auth-status]'); var refreshButton = shell.querySelector('[data-auth-refresh]'); var manualButton = shell.querySelector('[data-auth-manual-open]'); var typeSelect = createForm && createForm.querySelector('[name="type"]'); var enterprise = createForm && createForm.querySelector('[data-enterprise-fields]'); var personLabel = createForm && createForm.querySelector('[data-auth-person-label]'); var idLabel = createForm && createForm.querySelector('[data-auth-id-label]'); function syncEnterprise() { var enabled = typeSelect && typeSelect.value === 'enterprise'; if (enterprise) enterprise.hidden = !enabled; if (enterprise) enterprise.querySelectorAll('input').forEach(function (input) { input.required = enabled; }); if (personLabel) personLabel.textContent = enabled ? '法定代表人姓名' : '真实姓名'; if (idLabel) idLabel.textContent = enabled ? '法定代表人身份证号' : '身份证号码'; } if (typeSelect) { typeSelect.addEventListener('change', syncEnterprise); syncEnterprise(); } if (refreshButton) refreshButton.addEventListener('click', function () { refresh(true); }); if (manualButton) manualButton.addEventListener('click', function () { if (manualForm) manualForm.hidden = false; }); if (createForm) createForm.addEventListener('submit', function (event) { event.preventDefault(); var button = createForm.querySelector('[type="submit"]'); var message = createForm.querySelector('[data-auth-message]'); var form = new FormData(createForm); var payload = {}; form.forEach(function (value, key) { payload[key] = value; }); payload.consent = payload.consent === '1'; payload.client_request_id = uuid(); if (button) button.disabled = true; if (message) message.textContent = ''; aliyunMetaInfo(config).then(function (metaInfo) { if (metaInfo) payload.meta_info = metaInfo; return request(config.restBase, config, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); }).then(function (data) { render(data, shell); }).catch(function (error) { if (message) message.textContent = errorMessage(error, '创建认证会话失败,请重试。'); }).finally(function () { if (button) button.disabled = false; }); }); if (manualForm) manualForm.addEventListener('submit', function (event) { event.preventDefault(); if (!currentUuid) return; var files = manualForm.querySelector('[name="evidence[]"]'); if (files && files.files.length > 3) { setMessage(shell, '证明材料最多上传 3 张'); return; } var button = manualForm.querySelector('[type="submit"]'); var body = new FormData(); Array.prototype.forEach.call((files && files.files) || [], function (file) { body.append('evidence[]', file); }); if (button) button.disabled = true; request(config.restBase + '/' + encodeURIComponent(currentUuid) + '/manual', config, { method: 'POST', body: body, }).then(function (data) { manualForm.hidden = true; render(data, shell); }).catch(function (error) { setMessage(shell, errorMessage(error, '人工审核提交失败,请重试。')); }).finally(function () { if (button) button.disabled = false; }); }); if (statusBox && statusBox.hidden && createForm) createForm.hidden = false; } function open() { stopPolling(); abortCurrent(); abortRefresh(); openSequence += 1; var sequence = openSequence; var shell = runtime.open({ html: template.innerHTML, kind: 'identity', className: 'aksrt-identity-modal-shell', mobileBottom: true, onContent: function (_, session) { activeShell = session.shell; bindForm(session.shell); }, }); activeShell = shell; loadCurrent(shell, sequence); } root.querySelectorAll('[data-auth-modal-open]').forEach(function (button) { button.addEventListener('click', function (event) { event.preventDefault(); open(); }); }); document.addEventListener('visibilitychange', function () { if (!isOpen(activeShell)) return; if (document.visibilityState !== 'visible') { stopPolling(); abortCurrent(); abortRefresh(); return; } if (currentUuid && ['provider_pending', 'provider_processing'].indexOf(currentStage) !== -1) { schedulePoll(config.pollInterval || 5); } }); document.addEventListener('aksrt:modal:close', function (event) { if (!activeShell || !event.detail || event.detail.shell !== activeShell) return; stopPolling(); abortCurrent(); abortRefresh(); activeShell = null; }); } window.AKSRTUserCenterAuth = { init: init }; })(window, document);