/** * Shared helpers for page configuration, login state, ads, links and safe HTML. * Depends on config.js, ApiClient.js, DateUtil.js and layui. */ const CommonUtil = { get $() { return layui.$; }, getAuthToken() { const raw = localStorage.getItem('token'); if (!raw) return null; try { return JSON.parse(raw); } catch (e) { return raw; } }, getToken() { return typeof ApiClient !== 'undefined' && ApiClient.getToken ? ApiClient.getToken() : this.getAuthToken(); }, escapeHtml(value) { return String(value === undefined || value === null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }, isLocalDevHost() { return /^(localhost|127\.0\.0\.1|0\.0\.0\.0)$/i.test(window.location.hostname); }, safeHref(url) { if (!url) return '#'; const value = String(url).trim(); const lowered = value.toLowerCase(); if (lowered.startsWith('javascript:') || lowered.startsWith('data:') || lowered.startsWith('vbscript:')) { return '#'; } return value; }, siteHref(url) { const value = this.safeHref(url); if (!value || value === '#') return value; if (/^(?:https?:)?\/\//i.test(value) || value.startsWith('javascript:')) return value; if (!value.startsWith('/')) return value; if (!this.isLocalHtmlPathMode()) return value; if (value.startsWith('/html/')) return value; const freeArticleMatch = value.match(/^\/mianfei\/([^/?#]+)\.html([?#].*)?$/i); if (freeArticleMatch) { return `/html/mianfei.html?id=${encodeURIComponent(decodeURIComponent(freeArticleMatch[1]))}${freeArticleMatch[2] || ''}`; } if (/^\/[^/?#]+\.html(?:[?#].*)?$/i.test(value)) return `/html${value}`; return value; }, isLocalHtmlPathMode() { const hostname = window.location && window.location.hostname; return hostname === 'localhost' || hostname === '127.0.0.1' || Boolean(window.location && window.location.port); }, rewritePageRootLinks() { const $ = this.$; $('a[href^="/"]').each((index, link) => { const $link = $(link); const href = $link.attr('href'); const nextHref = this.siteHref(href); if (href !== nextHref) $link.attr('href', nextHref); }); }, freeArticleHref(articleId) { const id = encodeURIComponent(articleId || ''); if (!id) return 'javascript:void(0)'; if (this.isLocalDevHost()) return `mianfei.html?id=${id}`; return `/mianfei/${id}.html`; }, authHeaders() { const token = typeof ApiClient !== 'undefined' && ApiClient.getToken ? ApiClient.getToken() : this.getAuthToken(); const tenantId = typeof ApiClient !== 'undefined' && ApiClient.tenantId ? ApiClient.tenantId : '936208'; const headers = { tenantId }; if (token) headers.Authorization = `Bearer ${token}`; return headers; }, requireAuth(callback) { if (this.getAuthToken()) { callback(); return; } layui.use('layer', function () { layui.layer.confirm( '请先登录', { btn: ['去登录', '取消'] }, function (index) { layui.layer.close(index); window.location.href = 'login.html'; } ); }); }, getUserLevelText(user = {}) { const truthy = (value) => value === true || value === 1 || value === '1' || String(value).toLowerCase() === 'true'; const expertStatus = String( user.expertStatus || user.expert_status || user.expertLevel || user.expert_level || '' ).toLowerCase(); const isRegularExpert = truthy(user.regularExpert) || truthy(user.isRegularExpert) || truthy(user.is_regular_expert) || truthy(user.formalExpert) || truthy(user.isFormalExpert) || /正式|regular|formal/.test(expertStatus); const isInternExpert = truthy(user.internExpert) || truthy(user.isInternExpert) || truthy(user.is_intern_expert) || truthy(user.trialExpert) || truthy(user.isTrialExpert) || truthy(user.is_expert) || truthy(user.isExpert) || truthy(user.expert) || /实习|intern|trial/.test(expertStatus); if (isRegularExpert) return '正式专家'; if (isInternExpert) return '实习专家'; return '会员'; }, getExpertState(user = {}) { const truthy = (value) => value === true || value === 1 || value === '1' || String(value).toLowerCase() === 'true'; const firstPresent = (...values) => { for (const value of values) { if (value !== undefined && value !== null && value !== '') return value; } return ''; }; const statusText = String( firstPresent( user.expertStatus, user.expert_status, user.expertApplyStatus, user.expert_apply_status, user.applyStatus, user.apply_status, user.auditStatus, user.audit_status, user.expertAuditStatus, user.expert_audit_status ) ).toLowerCase(); const isExpert = truthy(user.regularExpert) || truthy(user.isRegularExpert) || truthy(user.is_regular_expert) || truthy(user.formalExpert) || truthy(user.isFormalExpert) || truthy(user.internExpert) || truthy(user.isInternExpert) || truthy(user.is_intern_expert) || truthy(user.trialExpert) || truthy(user.isTrialExpert) || truthy(user.is_expert) || truthy(user.isExpert) || truthy(user.expert) || /实习|正式|intern|trial|regular|formal|expert/.test(statusText); const isApplying = !isExpert && ([ '0', 'pending', 'reviewing', 'review', 'audit', 'auditing', 'apply', 'applying', 'submitted', 'wait', 'waiting', ].includes(statusText) || /审核|待审|申请中|pending|review|audit|applying|waiting/.test(statusText)); return { isExpert, isApplying, status: statusText, }; }, getUserLevelTextLegacy(user = {}) { if (user.regularExpert || user.isExpert === '1' || user.expertStatus === 'regular') { return '正式专家'; } if (user.internExpert || user.isInternExpert || user.expertStatus === 'intern') { return '实习专家'; } return '会员'; }, applyTopbarUserLevel(user = {}) { const $ = this.$; const text = this.getUserLevelText(user); $('#userLevel, #headerUserLevel').text(text); $('.topbar__ubadge, .uc-role').text(text); }, installTopbarUserCenterEntry() { if (typeof document === 'undefined') return; const $ = this.$; $('#loggedInBox').each((index, box) => { const $box = $(box); const $logout = $box.find('.topbar__btn--logout').first(); let $actions = $box.find('.topbar__actions').first(); if (!$actions.length) { $actions = $('
', { id: 'copyright-info', class: 'site-footer__copyright', text: '© 2014-2026 神彩算 版权所有', })); } if ($desc.length) { $brand.append($desc.addClass('site-footer__desc')); } else { $brand.append($('
', { id: 'additional-info', class: 'site-footer__desc', text: '本站内容仅供数据分析参考,不构成任何投注建议', })); } $layout = $('