131 lines
3.6 KiB
JavaScript
131 lines
3.6 KiB
JavaScript
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('&')
|
||
)
|
||
}
|