Files
zkxw/mobile-h5/utils/oa-pdf-preview-query.js
T
2026-08-13 16:50:36 +08:00

150 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* OA PDF 预览页 query 解析(短 fileUrl / 兼容旧 url)
* 微信 onLoad 可能已 decode 一次;须安全二次解码,并兼容大小写 key。
*/
const LOG_TAG = '[oa-pdf-preview]'
export function pdfPreviewLog(...args) {
try {
console.log(LOG_TAG, ...args)
} catch (_) {
/* ignore */
}
}
export function safeDecodeURIComponent(value) {
const raw = String(value == null ? '' : value).trim()
if (!raw) return ''
try {
return decodeURIComponent(raw)
} catch (_) {
return raw
}
}
/** 按候选 key 取值;忽略大小写;兼容微信偶发改写 */
export function pickQueryValue(query, keys) {
const q = query && typeof query === 'object' ? query : {}
const list = Array.isArray(keys) ? keys : [keys]
for (let i = 0; i < list.length; i++) {
const k = list[i]
if (k == null) continue
if (Object.prototype.hasOwnProperty.call(q, k) && q[k] != null) {
const v = String(q[k]).trim()
if (v) return v
}
}
const lowerMap = {}
Object.keys(q).forEach((k) => {
lowerMap[String(k).toLowerCase()] = q[k]
})
for (let i = 0; i < list.length; i++) {
const k = String(list[i] || '').toLowerCase()
if (!k) continue
if (lowerMap[k] != null) {
const v = String(lowerMap[k]).trim()
if (v) return v
}
}
return ''
}
/**
* @returns {{ fileUrl: string, legacyUrl: string, name: string, rawKeys: string[] }}
*/
export function parsePdfPreviewQuery(query) {
const rawKeys = Object.keys(query && typeof query === 'object' ? query : {})
const fileUrl = safeDecodeURIComponent(
pickQueryValue(query, ['fileUrl', 'fileurl', 'file_url', 'f'])
)
const legacyUrl = safeDecodeURIComponent(
pickQueryValue(query, ['url', 'downloadUrl', 'download_url'])
)
const name =
safeDecodeURIComponent(pickQueryValue(query, ['name', 'fileName', 'file_name', 'n'])) ||
'approval.pdf'
return { fileUrl, legacyUrl, name, rawKeys }
}
/**
* 后端 MINIO_BASE_URL 常配成同域相对路径(如 /minio/zkxw),预签名改写后也是
* `/minio/zkxw/...?X-Amz-...`。微信 downloadFile 必须绝对 http(s)。
*
* @param {string} url
* @param {{ apiBaseUrl?: string, minioBaseUrl?: string }} [bases]
*/
export function toAbsoluteDownloadUrl(url, bases = {}) {
const s = String(url || '').trim()
if (!s) return ''
if (/^https?:\/\//i.test(s)) return s
if (s.startsWith('//')) return 'https:' + s
const apiBase = String(bases.apiBaseUrl || '').trim()
const minioBase = String(bases.minioBaseUrl || '').trim()
const originFrom = (base) => {
const m = String(base || '').match(/^(https?:\/\/[^/]+)/i)
return m ? m[1] : ''
}
const origin = originFrom(apiBase) || originFrom(minioBase)
if (s.startsWith('/')) {
return origin ? origin + s : ''
}
// 相对 object key
const minio = minioBase.replace(/\/$/, '')
if (/^https?:\/\//i.test(minio)) {
return minio + '/' + s.replace(/^\//, '')
}
if (minio.startsWith('/') && origin) {
return origin + minio + '/' + s.replace(/^\//, '')
}
return ''
}
/**
* 拼 MinIO 公网直链(无预签名)。
* 预签名经相对路径改写后微信 downloadFile 常 403;公网直链对本环境可 200。
*/
export function buildDirectMinioUrl(fileUrl, bases = {}) {
const raw = String(fileUrl || '').trim()
if (!raw) return ''
const minioBase = String(bases.minioBaseUrl || '').replace(/\/$/, '')
const apiBase = String(bases.apiBaseUrl || '').trim()
const originMatch = (apiBase || minioBase).match(/^(https?:\/\/[^/]+)/i)
const origin = originMatch ? originMatch[1] : ''
// 已是绝对 http(s):去掉 query(签名)后若可识别为同域 MinIO 则规范化,否则原样去 query
if (/^https?:\/\//i.test(raw)) {
const noQuery = raw.split('?')[0]
try {
const u = new URL(noQuery)
const minioPath = minioBase.replace(/^https?:\/\/[^/]+/i, '') || ''
if (minioPath && u.pathname.indexOf(minioPath) === 0) {
return origin && minioPath.startsWith('/')
? origin + u.pathname
: noQuery
}
} catch (_) {
/* ignore */
}
return noQuery
}
// 根相对:/minio/zkxw/key.pdf?... → 拼 origin
if (raw.startsWith('/')) {
const pathOnly = raw.split('?')[0]
return origin ? origin + pathOnly : toAbsoluteDownloadUrl(pathOnly, bases)
}
// object key:去掉可能误带的 minio 路径前缀
let key = raw.replace(/^\//, '').split('?')[0]
const minioPath = minioBase.replace(/^https?:\/\/[^/]+/i, '').replace(/^\//, '')
if (minioPath && key.indexOf(minioPath + '/') === 0) {
key = key.slice(minioPath.length + 1)
}
return toAbsoluteDownloadUrl(key, bases)
}