自动检测更新
continuous-integration/drone/push Build is passing Details

uat_us
DESKTOP-6C3NK6N\WXS 2024-08-13 13:55:02 +08:00
parent 8c8ffa5ea5
commit 58f8586232
2 changed files with 239 additions and 2 deletions

View File

@ -1,10 +1,9 @@
import Vue from 'vue'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import { createVersionPolling } from "@/utils/version-polling.esm.js";
import ElementUI, { MessageBox } from 'element-ui'
import { getBasicDataAllSelect, getFrontInternationalizationList, getCurrentPublishInfo } from '@/api/dictionary/dictionary'
import { sendMFAEmail } from "@/api/user.js";
import { resetReadingRestTime } from '@/api/trials/reading'
// import 'element-ui/lib/theme-chalk/index.css'
import './assets/css/theme-blue/index.css' // 浅绿色主题
@ -529,5 +528,21 @@ async function VueInit() {
} : () => { }, process.env.VUE_APP_LOCK_FOR_TIME)
}
VueInit()
createVersionPolling({
appETagKey: "__APP_ETAG__",
pollingInterval: 5 * 1000, // 单位为毫秒
silent: process.env.NODE_ENV === false, // 开发环境下不检测
onUpdate: (self) => {
// 当检测到有新版本时,执行的回调函数,可以在这里提示用户刷新页面
const result = confirm("页面有更新,点击确定刷新页面!");
if (result) {
self.onRefresh();
} else {
self.onCancel();
}
// 强制更新可以用alert
// alert('有新版本,请刷新页面');
},
});

View File

@ -0,0 +1,222 @@
/*!
* version-polling v1.2.6
* (c) 2023 JoeshuTT
* @license MIT
*/
function _defineProperty(obj, key, value) {
key = _toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _toPrimitive(input, hint) {
if (typeof input !== "object" || input === null) return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint || "default");
if (typeof res !== "object") return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return typeof key === "symbol" ? key : String(key);
}
/**
* 是否有值
* @param {*} val
*/
/**
* 创建一个 Web Work 实例
* @param func
*/
function createWorker(func) {
const blob = new Blob(["(" + func.toString() + ")()"]);
const url = window.URL.createObjectURL(blob);
const worker = new Worker(url);
window.URL.revokeObjectURL(url);
return worker;
}
function createWorkerFunc() {
let timerId = null;
let options;
self.onmessage = event => {
let code = event.data["code"];
options = Object.assign({}, options, event.data["data"]);
const {
htmlFileUrl,
lastEtag,
appETagKey,
pollingInterval,
silentPollingInterval
} = options;
const runReq = () => {
fetch(htmlFileUrl, {
method: "HEAD",
cache: "no-cache"
}).then(response => {
if (Number(response.status) !== 200) {
return;
}
const etag = response.headers.get("etag");
if (lastEtag !== etag) {
self.postMessage({
appETagKey,
lastEtag,
etag
});
}
});
};
const startPollingTask = () => {
timerId = setInterval(runReq, pollingInterval);
};
const pausePollingTask = () => {
if (timerId) {
clearInterval(timerId);
timerId = null;
}
};
if (code === "pause") {
pausePollingTask();
} else {
runReq(); // 立即执行一次
if (!silentPollingInterval) {
startPollingTask();
}
}
};
return self;
}
function closeWorker(worker) {
worker.terminate();
}
let APP_ETAG_KEY = "__APP_ETAG__";
let myWorker;
const defaultOptions = {
appETagKey: APP_ETAG_KEY,
pollingInterval: 5 * 60 * 1000,
htmlFileUrl: `${location.origin}${location.pathname}`,
silent: false,
silentPollingInterval: false,
silentPageVisibility: false,
forceUpdate: false
};
let attached = false;
/**
* 页面隐藏时停止轮询任务页面再度可见时在继续
*/
function handleVisibilityChange() {
if (document.visibilityState === "visible") {
myWorker.postMessage({
code: "resume"
});
} else {
myWorker.postMessage({
code: "pause"
});
}
}
class VersionPolling {
constructor(options) {
_defineProperty(this, "options", void 0);
_defineProperty(this, "appEtag", "");
this.options = Object.assign({}, defaultOptions, options);
this.init();
}
async init() {
const {
htmlFileUrl
} = this.options;
if (!htmlFileUrl) {
throw new Error("[version-polling]: htmlFileUrl is required");
}
const response = await fetch(htmlFileUrl, {
method: "HEAD",
cache: "no-cache"
});
if (Number(response.status) !== 200) {
throw new Error(`[version-polling]: status is ${response.status}`);
}
const etag = response.headers.get("etag");
// eslint-disable-next-line no-eq-null
if (etag == null) {
throw new Error(`[version-polling]: etag is null`);
}
this.appEtag = etag;
localStorage.setItem(`${this.options.appETagKey}`, etag);
this.start();
}
start() {
const {
appETagKey,
pollingInterval,
htmlFileUrl,
silent,
silentPollingInterval,
silentPageVisibility
} = this.options;
if (silent) {
return;
}
myWorker = createWorker(createWorkerFunc);
myWorker.postMessage({
code: "start",
data: {
appETagKey,
pollingInterval,
htmlFileUrl,
silentPollingInterval,
lastEtag: this.appEtag
}
});
myWorker.onmessage = event => {
const {
lastEtag,
etag
} = event.data;
if (lastEtag !== etag) {
this.stop();
this.options.onUpdate(this);
}
};
if (!silentPageVisibility) {
if (!attached) {
document.addEventListener("visibilitychange", handleVisibilityChange);
attached = true;
}
}
}
stop() {
if (myWorker) {
closeWorker(myWorker);
if (attached) {
document.removeEventListener("visibilitychange", handleVisibilityChange);
attached = false;
}
}
}
onRefresh() {
window.location.reload();
}
onCancel() {
this.options.forceUpdate && this.start();
}
}
function createVersionPolling(options) {
const versionPolling = new VersionPolling(options);
return versionPolling;
}
export { VersionPolling, createVersionPolling };