/** * 判断当前路径是否对应指定的应用路由。 */ function matchesRoutePath(pathname: string, routePath: string) { const normalizedPathname = pathname.replace(/\/+$/, ''); const normalizedRoutePath = routePath.replace(/\/+$/, ''); return ( normalizedPathname === normalizedRoutePath || normalizedPathname.endsWith(normalizedRoutePath) ); } /** * 解析 Hash 模式下当前激活的应用路由。 */ function parseHashRoute(hash: string) { if (!hash.startsWith('#/')) { return null; } return new URL(hash.slice(1), 'http://easyflow.local'); } /** * 从指定应用路由读取查询参数。 * * Hash 路由存在时仅信任 Hash 内的激活路由,避免 pathname 上遗留的分享参数 * 污染后续页面。 */ export function readScopedRouteQueryParam( routePath: string, queryName: string, url?: string, ): null | string { const currentUrl = url || (typeof window === 'undefined' ? '' : window.location.href); if (!currentUrl) { return null; } try { const parsed = new URL( currentUrl, typeof window === 'undefined' ? 'http://localhost' : window.location.origin, ); const hashRoute = parseHashRoute(parsed.hash); if (hashRoute) { if (!matchesRoutePath(hashRoute.pathname, routePath)) { return null; } return hashRoute.searchParams.get(queryName)?.trim() || null; } if (!matchesRoutePath(parsed.pathname, routePath)) { return null; } return parsed.searchParams.get(queryName)?.trim() || null; } catch { return null; } } /** * 将 Router 解析出的应用地址转换为可复制的绝对地址。 * * Hash 路由下 Router 可能只返回 `#/path`,需显式补齐部署基路径。 */ export function buildAbsoluteAppRouteUrl(href: string, origin?: string) { const currentOrigin = origin || (typeof window === 'undefined' ? 'http://localhost' : window.location.origin); if (!href.startsWith('#/') && !href.startsWith('/#/')) { return new URL(href, currentOrigin).toString(); } const configuredBase = import.meta.env.BASE_URL || '/'; const runtimeBase = configuredBase === '/' && typeof window !== 'undefined' && window.location.pathname.endsWith('/') ? window.location.pathname : configuredBase; return new URL( `${runtimeBase.replace(/\/?$/, '/')}${href.slice(href.indexOf('#'))}`, currentOrigin, ).toString(); }