/* OSS中转直链 oss_browser_link 前端逻辑(双模式弹窗 / 交互详情 / 协议拉起) */ ;(function () { 'use strict' var CFG = { ui_mode: 'debug', public_url: '', launch_protocol: 'ossbrowser' } function $ (id) { return document.getElementById(id) } function bjNow () { try { return new Date().toLocaleString('sv-SE', { timeZone: 'Asia/Shanghai' }) } catch (e) { return new Date().toLocaleString() } } /* ---------- Toast ---------- */ var toastTimer = null function showToast (msg, kind) { var el = $('obl-toast') el.textContent = msg el.className = kind || '' clearTimeout(toastTimer) toastTimer = setTimeout(function () { el.className = 'obl-hidden' }, 2000) } /* ---------- 交互详情弹窗(双模式) ---------- */ var dialogTimer = null function showDialog (title, text, opts) { opts = opts || {} $('obl-dialog-title').textContent = title $('obl-dialog-body').textContent = text $('obl-dialog').classList.remove('obl-hidden') clearTimeout(dialogTimer) if (opts.error) return // 异常:停留窗口,不自动关闭 var delay = CFG.ui_mode === 'debug' ? 3000 : 2000 dialogTimer = setTimeout(closeDialog, delay) } function closeDialog () { clearTimeout(dialogTimer) $('obl-dialog').classList.add('obl-hidden') } function buildLog (rec) { return [ '触发动作: ' + rec.action, '时间: ' + rec.time, '接口: ' + rec.method + ' ' + rec.url, '请求参数: ' + JSON.stringify(rec.params || {}), '状态: ' + rec.status, '返回结果: ' + rec.result, rec.error ? '错误信息: ' + rec.error : '', '耗时: ' + rec.cost + 'ms' ].filter(Boolean).join('\n') } /* 包装一次与后台/系统交互的操作,按 ui_mode 分支提示 */ function runTracked (action, url, method, params, fn, opts) { opts = opts || {} var t0 = Date.now() var rec = { action: action, time: bjNow(), url: url, method: method, params: params, status: '进行中', result: '', error: '', cost: 0 } return Promise.resolve() .then(fn) .then(function (result) { rec.cost = Date.now() - t0 rec.status = '成功' rec.result = typeof result === 'string' ? result : JSON.stringify(result) if (CFG.ui_mode === 'debug') showDialog('交互详情 · ' + action, buildLog(rec)) else if (!opts.silent) showToast(action + ' 成功', 'success') return result }) .catch(function (err) { rec.cost = Date.now() - t0 rec.status = '失败' rec.error = String((err && err.message) || err) showDialog('交互详情 · ' + action, buildLog(rec), { error: true }) // 异常双模式均强提示 throw err }) } /* ---------- 初始化:拉配置 + 文件状态 ---------- */ function init () { fetch('/api/oss_browser_link/config').then(function (r) { return r.json() }).then(function (j) { if (j && j.ok && j.data) { CFG.ui_mode = j.data.ui_mode || 'debug' CFG.public_url = j.data.public_url || '' CFG.launch_protocol = j.data.launch_protocol || 'ossbrowser' } }).catch(function () {}) $('obl-link-input').value = CFG.public_url || location.origin + '/download_files/oss-browser-win32-x64.zip' refreshFileInfo() bindEvents() } function fmtSize (n) { if (!Number.isFinite(n)) return '' if (n >= 1024 * 1024) return (n / 1024 / 1024).toFixed(2) + ' MB' if (n >= 1024) return (n / 1024).toFixed(1) + ' KB' return n + ' B' } function refreshFileInfo () { var t0 = Date.now() fetch('/api/oss_browser_link/info').then(function (r) { return r.json() }).then(function (j) { var meta = $('obl-file-meta') var st = $('obl-file-status') var cost = Date.now() - t0 if (j && j.ok && j.data && j.data.available) { meta.textContent = '大小 ' + fmtSize(j.data.size) + ' · 已中转至本站 · 鉴权保护' st.textContent = '可下载' st.className = 'obl-status ok' $('obl-download-btn').disabled = false } else { meta.textContent = '尚未检测到中转文件 · 请等待管理员中转后刷新' st.textContent = '未就绪' st.className = 'obl-status miss' $('obl-download-btn').disabled = true } if (CFG.ui_mode === 'debug') { meta.textContent += ' · 检测耗时 ' + cost + 'ms' } }).catch(function () { $('obl-file-meta').textContent = '文件状态检测失败' $('obl-file-status').textContent = '异常' $('obl-file-status').className = 'obl-status miss' }) } /* ---------- 按钮事件 ---------- */ function bindEvents () { $('obl-copy-btn').addEventListener('click', function () { var url = $('obl-link-input').value var btn = this btn.disabled = true; btn.textContent = '复制中…' runTracked('复制直链', location.href, 'CLIPBOARD', { url: url }, function () { if (navigator.clipboard && navigator.clipboard.writeText) return navigator.clipboard.writeText(url) $('obl-link-input').select() document.execCommand('copy') return 'fallback copy ok' }).then(function () { showToast('直链已复制(对方需鉴权才能下载)', 'success') }).catch(function () {}) btn.disabled = false; btn.textContent = '复制直链' }) $('obl-download-btn').addEventListener('click', function () { var btn = this btn.disabled = true; btn.textContent = '准备下载…' runTracked('下载安装包', '/download_files/oss-browser-win32-x64.zip', 'GET', {}, function () { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest() xhr.open('GET', '/download_files/oss-browser-win32-x64.zip') xhr.responseType = 'blob' xhr.onload = function () { if (xhr.status !== 200) return reject(new Error('HTTP ' + xhr.status)) var a = document.createElement('a') a.href = URL.createObjectURL(xhr.response) a.download = 'oss-browser-win32-x64.zip' document.body.appendChild(a) a.click() setTimeout(function () { URL.revokeObjectURL(a.href); a.remove() }, 4000) resolve('下载已触发,大小 ' + (xhr.response ? xhr.response.size : 0) + ' 字节') } xhr.onerror = function () { reject(new Error('网络错误')) } xhr.send() }) }).catch(function () {}) btn.disabled = false; btn.textContent = '⬇ 下载 oss-browser 安装包' }) $('obl-launch-btn').addEventListener('click', function () { launchOssBrowser() }) $('obl-reg-btn').addEventListener('click', function () { var btn = this btn.disabled = true; btn.textContent = '下载中…' runTracked('下载注册脚本', '/tools/oss_browser_link/assets/register_ossbrowser_launch.bat', 'GET', {}, function () { var a = document.createElement('a') a.href = '/tools/oss_browser_link/assets/register_ossbrowser_launch.bat' a.download = 'register_ossbrowser_launch.bat' document.body.appendChild(a) a.click() setTimeout(function () { a.remove() }, 2000) return '脚本下载已触发(放入解压目录后双击运行)' }).catch(function () {}) btn.disabled = false; btn.textContent = '📄 下载一键注册脚本(首次)' }) $('obl-dialog-close').addEventListener('click', closeDialog) $('obl-dialog-copy').addEventListener('click', function () { var text = $('obl-dialog-body').textContent if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(text) showToast('交互日志已复制', 'success') }) } /* ---------- 协议拉起:未装则回退下载 ---------- */ function launchOssBrowser () { var proto = CFG.launch_protocol || 'ossbrowser' var url = proto + '://launch?t=' + Date.now() var btn = $('obl-launch-btn') btn.disabled = true; btn.textContent = '正在打开…' runTracked('打开 oss-browser', url, 'PROTOCOL', { protocol: proto }, function () { return new Promise(function (resolve, reject) { var done = false var started = false /* 拉起成功时浏览器通常会模糊/隐藏页面 */ window.addEventListener('blur', onBlur) document.addEventListener('visibilitychange', onVis) function onBlur () { started = true } function onVis () { if (document.hidden) started = true } try { var f = document.createElement('iframe') f.style.display = 'none' f.src = url document.body.appendChild(f) setTimeout(function () { try { f.remove() } catch (e) {} }, 3000) } catch (e) { location.href = url } setTimeout(function () { window.removeEventListener('blur', onBlur) document.removeEventListener('visibilitychange', onVis) if (done) return done = true if (started) resolve('已触发协议拉起') else reject(new Error('未检测到已安装的 oss-browser(协议未注册)')) }, 2500) }) }).then(function () { showToast('已尝试打开 oss-browser;若浏览器弹出确认框请勾选"始终允许"', 'success') }).catch(function () { /* 未安装:自动回退下载安装包 */ showToast('未检测到 oss-browser,已自动开始下载安装包', 'error') setTimeout(function () { $('obl-download-btn').click() }, 600) }) setTimeout(function () { btn.disabled = false; btn.textContent = '🚀 打开 oss-browser' }, 3200) } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init) else init() })()