// lib/webLink.ts:判断「给个链接能不能丢进右侧面板 iframe 打开」,以及生成标签标题。 // // 当前不区分站内站外:只要是 http(s) 地址就放行(后端返回的内网系统地址多为同域不同端口, // 按同源判定会被排除,先用「全放开」)—— 具体见需求:先不做限制,后续再收紧。 // 非 http(s) 协议(mailto/tel/javascript/data/blob)和页内锚点(#xxx)无法进 iframe,仍返回 null。 // // 注意:外链能否真的被嵌由对方站点决定(X-Frame-Options: DENY/SAMEORIGIN 或 CSP frame-ancestors 会被 // 浏览器直接拒绝,面板里只会一片空白,且跨域读不到内容、前端无法可靠识别),所以面板里始终保留 // 「新窗口打开」兜底。以后要收紧成白名单/同源,只改这里的判定即可。 /** 取出可放进面板的绝对地址;http(s) 以外的协议、页内锚点、空链接返回 null */ export const panelOpenableUrl = (href?: string | null): string | null => { const raw = (href || '').trim(); if (!raw || raw.startsWith('#')) return null; try { const url = new URL(raw, window.location.href); if (url.protocol !== 'http:' && url.protocol !== 'https:') return null; return url.href; } catch { // 非法 URL return null; } }; /** 面板标签标题:优先用链接文字,没有就用路径(去掉域名,整条 URL 会把标签栏挤爆) */ export const webTabTitle = (href: string, text?: string): string => { const label = (text || '').replace(/\s+/g, ' ').trim(); if (label) return label; try { const url = new URL(href, window.location.href); return url.pathname + url.search || url.host; } catch { return href; } };