|
@@ -38,10 +38,70 @@ const fetchAgreement = async (id) => {
|
|
|
agreementData.value = res
|
|
agreementData.value = res
|
|
|
// 解码 Base64 内容 (Admin端采用 btoa(unescape(encodeURIComponent(content))) 编码)
|
|
// 解码 Base64 内容 (Admin端采用 btoa(unescape(encodeURIComponent(content))) 编码)
|
|
|
if (res.content) {
|
|
if (res.content) {
|
|
|
- try {
|
|
|
|
|
- contentHtml.value = decodeURIComponent(escape(atob(res.content)))
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- // 如果解码失败,回显原始内容
|
|
|
|
|
|
|
+ const cleanStr = String(res.content).trim().replace(/\s+/g, '')
|
|
|
|
|
+ // 检查是否是 base64 格式(仅包含 A-Z, a-z, 0-9, +, /, =)
|
|
|
|
|
+ const isBase64 = /^[A-Za-z0-9+/=]+$/.test(cleanStr)
|
|
|
|
|
+
|
|
|
|
|
+ if (isBase64) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 1. Base64 解码为二进制字符串
|
|
|
|
|
+ const atobPolyfill = (str) => {
|
|
|
|
|
+ if (typeof atob === 'function') return atob(str)
|
|
|
|
|
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
|
|
|
|
|
+ let output = ''
|
|
|
|
|
+ const clean = str.replace(/=+$/, '')
|
|
|
|
|
+ for (let bc = 0, bs, buffer, idx = 0; idx < clean.length; ) {
|
|
|
|
|
+ const char = clean.charAt(idx++)
|
|
|
|
|
+ const buffer = chars.indexOf(char)
|
|
|
|
|
+ if (buffer === -1) throw new Error('Invalid base64 character')
|
|
|
|
|
+ bs = bc % 4 ? bs * 64 + buffer : buffer
|
|
|
|
|
+ if (bc++ % 4) {
|
|
|
|
|
+ output += String.fromCharCode(255 & bs >> (-2 * bc & 6))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return output
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const decodedBinary = atobPolyfill(cleanStr)
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 将二进制字符串解码为 UTF-8 字符串
|
|
|
|
|
+ const decodeUtf8 = (str) => {
|
|
|
|
|
+ let result = ''
|
|
|
|
|
+ let i = 0
|
|
|
|
|
+ while (i < str.length) {
|
|
|
|
|
+ const c1 = str.charCodeAt(i++)
|
|
|
|
|
+ if (c1 < 128) {
|
|
|
|
|
+ result += String.fromCharCode(c1)
|
|
|
|
|
+ } else if (c1 > 191 && c1 < 224) {
|
|
|
|
|
+ const c2 = str.charCodeAt(i++)
|
|
|
|
|
+ result += String.fromCharCode(((c1 & 31) << 6) | (c2 & 63))
|
|
|
|
|
+ } else if (c1 > 223 && c1 < 240) {
|
|
|
|
|
+ const c2 = str.charCodeAt(i++)
|
|
|
|
|
+ const c3 = str.charCodeAt(i++)
|
|
|
|
|
+ result += String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const c2 = str.charCodeAt(i++)
|
|
|
|
|
+ const c3 = str.charCodeAt(i++)
|
|
|
|
|
+ const c4 = str.charCodeAt(i++)
|
|
|
|
|
+ const codepoint = ((c1 & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63)
|
|
|
|
|
+ if (codepoint > 0xffff) {
|
|
|
|
|
+ const offset = codepoint - 0x10000
|
|
|
|
|
+ result += String.fromCharCode((offset >> 10) + 0xd800, (offset & 0x3ff) + 0xdc00)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ result += String.fromCharCode(codepoint)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return result
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ contentHtml.value = decodeUtf8(decodedBinary)
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // 解码失败,回显原始内容
|
|
|
|
|
+ contentHtml.value = res.content
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 非 base64 格式,直接回显原始 HTML 页面
|
|
|
contentHtml.value = res.content
|
|
contentHtml.value = res.content
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|