<!DOCTYPE html>
|
<html lang="en">
|
<head>
|
<meta charset="utf-8">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
<title>峰峰矿区智慧停车</title>
|
|
<!--
|
样式文件:主源用国内阿里云 npmmirror(移动/联通/电信网络稳定可达),
|
加载失败自动切回 jsdelivr。CSS 失败不会导致白屏,仅样式异常。
|
-->
|
<link rel="stylesheet"
|
href="https://registry.npmmirror.com/element-ui/2.15.14/files/lib/theme-chalk/index.css"
|
onerror="this.onerror=null;this.href='https://cdn.jsdelivr.net/npm/element-ui@2.15.14/lib/theme-chalk/index.css'">
|
<link rel="stylesheet"
|
href="https://registry.npmmirror.com/view-design/4.7.0/files/dist/styles/iview.css"
|
onerror="this.onerror=null;this.href='https://cdn.jsdelivr.net/npm/view-design@4.7.0/dist/styles/iview.css'">
|
|
<style>
|
/* 首屏加载占位(Vue 挂载后会自动替换掉 #app 内的内容) */
|
#app-loading{position:fixed;top:0;left:0;right:0;bottom:0;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#f5f7fa;color:#606266;font-size:15px;z-index:9998}
|
#app-loading .spin{width:38px;height:38px;margin-bottom:14px;border:3px solid #dcdfe6;border-top-color:#409eff;border-radius:50%;animation:appspin .8s linear infinite}
|
@keyframes appspin{to{transform:rotate(360deg)}}
|
/* 资源全部加载失败时的提示层,替代“纯白屏” */
|
#fatal-mask{display:none;position:fixed;top:0;left:0;right:0;bottom:0;inset:0;z-index:9999;background:#fff;align-items:center;justify-content:center;padding:30px;box-sizing:border-box}
|
#fatal-mask .box{max-width:420px;text-align:center;color:#303133}
|
#fatal-mask .ico{font-size:44px;color:#f56c6c;margin-bottom:14px}
|
#fatal-mask .msg{font-size:15px;line-height:1.7;color:#606266;margin-bottom:20px;word-break:break-all}
|
#fatal-mask button{padding:10px 34px;font-size:15px;color:#fff;background:#409eff;border:none;border-radius:4px;outline:none}
|
#fatal-mask button:active{background:#3a8ee6}
|
</style>
|
|
<script>
|
/*
|
* 基础库(Vue / ElementUI / ViewUI / ECharts)多源容灾加载器
|
*
|
* 背景:这些库通过 webpack externals 外置,业务包执行强依赖对应的全局变量。
|
* 之前只引用 cdn.jsdelivr.net 一个源,该域名在国内手机蜂窝网络(4G/5G)下
|
* 经常被 DNS 污染 / 连接重置,脚本加载失败后 window.Vue 为 undefined,
|
* 业务包执行立即报错,#app 永远为空,表现为手机白屏。
|
*
|
* 策略:国内 npmmirror 为主源,jsdelivr、bootcdn 依次兜底;
|
* 用“外链脚本 + 紧随其后的内联检测脚本”成对输出,保证严格的加载顺序,
|
* 业务包(webpack 注入在 body 末尾)一定在所有基础库就绪后才执行。
|
*/
|
window.__cdnTry = function (globalName, urls, idx) {
|
if (window[globalName]) return true;
|
if (idx >= urls.length) {
|
(window.__CDN_FAILED__ = window.__CDN_FAILED__ || []).push(globalName);
|
return false;
|
}
|
document.write('<script src="' + urls[idx] + '"><\/script>');
|
document.write('<script>window.__cdnTry("' + globalName + '",' + JSON.stringify(urls) + ',' + (idx + 1) + ');<\/script>');
|
};
|
|
/* 白屏兜底:记录脚本错误,超时后若基础库仍未就绪则给出可见提示 */
|
window.__lastError__ = '';
|
window.addEventListener('error', function (e) {
|
if (e && e.message) {
|
window.__lastError__ = e.message + (e.filename ? ('(' + e.filename.split('/').pop() + ':' + e.lineno + ')') : '');
|
}
|
}, true);
|
window.addEventListener('unhandledrejection', function (e) {
|
var r = e && e.reason;
|
window.__lastError__ = 'Promise异常: ' + (r && r.message ? r.message : String(r));
|
});
|
window.__showFatal = function (msg) {
|
var mask = document.getElementById('fatal-mask');
|
var loading = document.getElementById('app-loading');
|
if (loading) loading.style.display = 'none';
|
if (mask) {
|
document.getElementById('fatal-msg').textContent = msg;
|
mask.style.display = 'flex';
|
}
|
};
|
setTimeout(function () {
|
/* 注意:view-design 的 UMD 包在浏览器下挂载的全局名是小写 iview,不是 ViewUI */
|
var required = ['Vue', 'ELEMENT', 'iview', 'echarts'];
|
var labels = { Vue: 'Vue', ELEMENT: 'ElementUI', iview: 'ViewUI', echarts: 'ECharts' };
|
var missing = required.filter(function (n) { return !window[n]; });
|
if (missing.length) {
|
window.__showFatal('静态资源加载失败,页面无法启动(缺少:' + missing.map(function (n) { return labels[n]; }).join('、') +
|
')。请切换 WiFi 或 4G/5G 网络后重试。' +
|
(window.__lastError__ ? ('\n' + window.__lastError__) : ''));
|
return;
|
}
|
/* 库齐全但 12 秒仍未挂载,通常是业务包/接口异常,也要让用户看到而不是白屏 */
|
setTimeout(function () {
|
var loading = document.getElementById('app-loading');
|
if (loading && loading.parentNode) {
|
window.__showFatal('页面加载超时,请点击重试。' +
|
(window.__lastError__ ? ('\n' + window.__lastError__) : ''));
|
}
|
}, 12000);
|
}, 8000);
|
</script>
|
</head>
|
<body>
|
<div id="app"><div id="app-loading"><div class="spin"></div><div>正在加载,请稍候…</div></div></div>
|
|
<div id="fatal-mask">
|
<div class="box">
|
<div class="ico">!</div>
|
<div class="msg" id="fatal-msg">静态资源加载失败,请重试。</div>
|
<button type="button" onclick="location.reload()">重新加载</button>
|
</div>
|
</div>
|
|
<script>
|
(function () {
|
/* 顺序不能变:Vue -> ElementUI -> ViewUI -> ECharts */
|
var LIBS = [
|
['Vue', [
|
'https://registry.npmmirror.com/vue/2.7.16/files/dist/vue.min.js',
|
'https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.min.js',
|
'https://cdn.bootcdn.net/ajax/libs/vue/2.7.16/vue.min.js'
|
]],
|
['ELEMENT', [
|
'https://registry.npmmirror.com/element-ui/2.15.14/files/lib/index.js',
|
'https://cdn.jsdelivr.net/npm/element-ui@2.15.14/lib/index.js',
|
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.14/index.js'
|
]],
|
['iview', [
|
'https://registry.npmmirror.com/view-design/4.7.0/files/dist/iview.min.js',
|
'https://cdn.jsdelivr.net/npm/view-design@4.7.0/dist/iview.min.js',
|
'https://cdn.bootcdn.net/ajax/libs/view-design/4.7.0/iview.min.js'
|
]],
|
['echarts', [
|
'https://registry.npmmirror.com/echarts/5.4.3/files/dist/echarts.min.js',
|
'https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js',
|
'https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js'
|
]]
|
];
|
LIBS.forEach(function (lib) {
|
var name = lib[0], urls = lib[1];
|
document.write('<script src="' + urls[0] + '"><\/script>');
|
document.write('<script>window.__cdnTry("' + name + '",' + JSON.stringify(urls) + ',1);<\/script>');
|
});
|
})();
|
</script>
|
</body>
|
</html>
|