142 lines
4.5 KiB
TypeScript
142 lines
4.5 KiB
TypeScript
export const MP_WEBVIEW_PATH_PREFIX = '/m/'
|
||
export const MP_PLAN_LIST_PATH = '/m/pl/plan'
|
||
export const MINI_WORKBENCH_PATH = '/pages/workbench/workbench'
|
||
/** H5 iframe / uni 壳页约定:内嵌页请求返回工作台 */
|
||
export const MP_WEBVIEW_GO_WORKBENCH = 'MP_WEBVIEW_GO_WORKBENCH'
|
||
/** H5 iframe:内嵌页 Clipboard API 被拦截时,请壳页代为写入剪贴板 */
|
||
export const MP_WEBVIEW_COPY_TEXT = 'MP_WEBVIEW_COPY_TEXT'
|
||
const MP_RETURN_ORIGIN_KEY = 'mp_webview_return_origin'
|
||
|
||
/** MpWebviewShell 换票 / 就绪引导中:业务请求若 401 不得触发登出(与换票竞态) */
|
||
let mpWebviewAuthBootDepth = 0
|
||
|
||
export function beginMpWebviewAuthBoot(): void {
|
||
mpWebviewAuthBootDepth += 1
|
||
}
|
||
|
||
export function endMpWebviewAuthBoot(): void {
|
||
mpWebviewAuthBootDepth = Math.max(0, mpWebviewAuthBootDepth - 1)
|
||
}
|
||
|
||
export function isMpWebviewAuthBooting(): boolean {
|
||
return mpWebviewAuthBootDepth > 0
|
||
}
|
||
|
||
export function isMpWebviewPath(path: string): boolean {
|
||
return (path || '').startsWith(MP_WEBVIEW_PATH_PREFIX)
|
||
}
|
||
|
||
type WxMiniProgramApi = {
|
||
reLaunch?: (opt: { url: string; fail?: () => void }) => void
|
||
navigateBack?: (opt?: { delta?: number; fail?: () => void }) => void
|
||
getEnv?: (cb: (res: { miniprogram?: boolean }) => void) => void
|
||
}
|
||
|
||
export function getWxMiniProgram(): WxMiniProgramApi | null {
|
||
if (typeof window === 'undefined') return null
|
||
const wxObj = (window as unknown as { wx?: { miniProgram?: unknown } }).wx
|
||
const mini = wxObj?.miniProgram as WxMiniProgramApi | undefined
|
||
return mini || null
|
||
}
|
||
|
||
/** 真机 web-view 内才为 true;勿信任 jweixin 在普通浏览器里挂上的空壳 API */
|
||
export function isInMiniProgramWebView(): boolean {
|
||
if (typeof window === 'undefined') return false
|
||
const w = window as unknown as { __wxjs_environment?: string }
|
||
if (w.__wxjs_environment === 'miniprogram') return true
|
||
const ua = typeof navigator !== 'undefined' ? navigator.userAgent || '' : ''
|
||
return /miniProgram/i.test(ua) && /MicroMessenger/i.test(ua)
|
||
}
|
||
|
||
/** 记住小程序壳 origin,供 H5 iframe 顶栏返回工作台(跨域无法读 parent.location) */
|
||
export function rememberMpReturnOrigin(origin?: string): void {
|
||
if (typeof sessionStorage === 'undefined') return
|
||
const value = String(origin || '').trim().replace(/\/$/, '')
|
||
if (!value || !/^https?:\/\//i.test(value)) return
|
||
try {
|
||
sessionStorage.setItem(MP_RETURN_ORIGIN_KEY, value)
|
||
} catch {
|
||
/* ignore quota */
|
||
}
|
||
}
|
||
|
||
function readMpReturnOrigin(): string {
|
||
if (typeof sessionStorage === 'undefined') return ''
|
||
try {
|
||
return String(sessionStorage.getItem(MP_RETURN_ORIGIN_KEY) || '').trim()
|
||
} catch {
|
||
return ''
|
||
}
|
||
}
|
||
|
||
function postGoWorkbenchToHost(): boolean {
|
||
if (typeof window === 'undefined') return false
|
||
const payload = { type: MP_WEBVIEW_GO_WORKBENCH }
|
||
let posted = false
|
||
try {
|
||
if (window.parent && window.parent !== window) {
|
||
window.parent.postMessage(payload, '*')
|
||
posted = true
|
||
}
|
||
} catch {
|
||
/* ignore */
|
||
}
|
||
try {
|
||
if (window.top && window.top !== window && window.top !== window.parent) {
|
||
window.top.postMessage(payload, '*')
|
||
posted = true
|
||
}
|
||
} catch {
|
||
/* ignore */
|
||
}
|
||
return posted
|
||
}
|
||
|
||
function navigateTopToMiniWorkbench(): boolean {
|
||
const origin = readMpReturnOrigin()
|
||
if (!origin || typeof window === 'undefined') return false
|
||
try {
|
||
const target = `${origin}${MINI_WORKBENCH_PATH}`
|
||
if (window.top && window.top !== window) {
|
||
window.top.location.href = target
|
||
return true
|
||
}
|
||
window.location.href = target
|
||
return true
|
||
} catch {
|
||
return false
|
||
}
|
||
}
|
||
|
||
/** 列表顶栏「返回」:回到小程序工作台(web-view 多用 redirectTo 打开,须 reLaunch) */
|
||
export function goToMiniWorkbench(): void {
|
||
const mini = getWxMiniProgram()
|
||
if (isInMiniProgramWebView() && mini?.reLaunch) {
|
||
mini.reLaunch({ url: MINI_WORKBENCH_PATH })
|
||
return
|
||
}
|
||
// uni-app H5:web-view 多为 iframe,由壳页监听 postMessage;再兜底顶层跳转
|
||
postGoWorkbenchToHost()
|
||
navigateTopToMiniWorkbench()
|
||
}
|
||
|
||
export function redirectToMiniLogin(): void {
|
||
const mini = getWxMiniProgram()
|
||
if (isInMiniProgramWebView() && mini?.reLaunch) {
|
||
mini.reLaunch({ url: '/pages/login/login' })
|
||
return
|
||
}
|
||
postGoWorkbenchToHost()
|
||
// 非小程序:只展示空态,禁止跳管理端登录
|
||
}
|
||
|
||
export function stripMpTicketFromUrl(
|
||
_path: string,
|
||
query: Record<string, unknown>
|
||
): Record<string, unknown> {
|
||
const next = { ...query }
|
||
delete next.mpTicket
|
||
delete next.mpReturnOrigin
|
||
return next
|
||
}
|