import { OA_H5_ORIGIN } from './config.js' const MODULES = [ ['presign', '预签约订单'], ['protocol', '协议单'], ['payment-chase', '催缴信息'], ['payment', '缴费信息'], ['freight', '运费信息'] ] const ROLE_GROUPS = [ ['specialist', '专员'], ['manager', '经理'] ] const MARKET_CLOSE_ACTIONS = new Set(['market-close', 'market-done']) /** * 从绝对地址解析 origin(scheme + host[:port])。 * 微信小程序运行时没有可用的 URL 构造函数,不能用 new URL().origin。 */ export function resolveHttpOrigin(value) { const match = String(value || '') .trim() .match(/^(https?:\/\/[^/?#]+)/i) return match ? match[1] : '' } const MARKET_H5_ORIGIN = resolveHttpOrigin(OA_H5_ORIGIN) export const MARKET_ENTRIES = Object.freeze( Object.fromEntries( ROLE_GROUPS.flatMap(([role, roleLabel]) => MODULES.map(([module, title]) => [ role + '-' + module, Object.freeze({ path: '/market/' + role + '/' + module, title: title + '(' + roleLabel + ')', groupTitle: '市场部' }) ]) ) ) ) function trimTrailingSlash(value) { return String(value || '').replace(/\/$/, '') } function isSafeMiniProgramPath(value) { const raw = String(value || '').trim() if (!raw || raw.includes('\\') || raw.includes('#')) return false let decoded = raw try { decoded = decodeURIComponent(raw) } catch (_) { return false } const pathname = decoded.split('?')[0] if (!/^\/pages\/[A-Za-z0-9_./-]+$/.test(pathname)) return false return pathname.split('/').every((part) => part !== '.' && part !== '..') } export function resolveMarketEntry(entry) { const key = String(entry || '').trim() return Object.prototype.hasOwnProperty.call(MARKET_ENTRIES, key) ? MARKET_ENTRIES[key] : null } export function resolveMarketReturnPath(query) { const fromQuery = String((query && query.returnPath) || '').trim() if (isSafeMiniProgramPath(fromQuery)) return fromQuery try { const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [] if (pages && pages.length >= 2) { const previous = pages[pages.length - 2] const route = '/' + String((previous && previous.route) || '').replace(/^\//, '') if (isSafeMiniProgramPath(route)) return route } } catch (_) { /* ignore */ } return '/pages/index/index' } export function resolveMarketBackFallback(returnPath) { return isSafeMiniProgramPath(returnPath) ? String(returnPath).trim() : '/pages/index/index' } export function isMarketCloseAction(action) { const value = String(action || '').trim() return value !== '' && MARKET_CLOSE_ACTIONS.has(value) } export function isTrustedMarketCloseMessage(event, expectedWindow) { if (!event || event.origin !== MARKET_H5_ORIGIN) return false if (expectedWindow && event.source !== expectedWindow) return false const payload = event.data return ( !!payload && payload.source === 'zkxw-oa-h5' && isMarketCloseAction(payload.action) ) } export function canOpenMarketWebview(unloaded, token) { return !unloaded && String(token || '').trim() !== '' } export function buildMarketH5Url({ entry, token, returnPath } = {}) { const resolved = resolveMarketEntry(entry) if (!resolved) return '' const params = [] const authToken = String(token || '').trim() if (authToken) { params.push('token=' + encodeURIComponent(authToken)) } const safeReturnPath = resolveMarketBackFallback(returnPath) params.push('returnPath=' + encodeURIComponent(safeReturnPath)) return ( trimTrailingSlash(OA_H5_ORIGIN) + resolved.path + '?' + params.join('&') ) }