Initial commit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
import API from "@/api";
|
||||
|
||||
function getUserInfoRaw() {
|
||||
return localStorage.getItem("userInfo");
|
||||
}
|
||||
|
||||
/** 用 token 识别会话,避免 refresh 改写 userInfo JSON 后误清线路缓存 */
|
||||
function getSessionKey(userInfoRaw) {
|
||||
if (!userInfoRaw) return "";
|
||||
try {
|
||||
const info = JSON.parse(userInfoRaw);
|
||||
return info && info.token ? String(info.token) : userInfoRaw;
|
||||
} catch (e) {
|
||||
return userInfoRaw;
|
||||
}
|
||||
}
|
||||
|
||||
export const LoginPlugin = {
|
||||
install(Vue, { router }) {
|
||||
console.log("Login plugin:::", Vue.prototype, router);
|
||||
|
||||
// 已请求失败(如 token 失效)后不再重复拉;重新登录后会重置
|
||||
let sourceInfoLoadFailed = false;
|
||||
// 并发去重:同一时刻只允许一次 getSourceList
|
||||
let sourceInfoPromise = null;
|
||||
// 递增以作废进行中的请求结果,避免登出后旧请求回写
|
||||
let loadSeq = 0;
|
||||
let lastSessionKey = "";
|
||||
|
||||
const showError = (error) => {
|
||||
console.error("update or sync source info error:::", error);
|
||||
Vue.prototype.$message.error("图片、视频资源将无法展示,推出重新登陆");
|
||||
};
|
||||
|
||||
const resetSourceInfoLoadState = () => {
|
||||
loadSeq += 1;
|
||||
sourceInfoLoadFailed = false;
|
||||
sourceInfoPromise = null;
|
||||
Vue.prototype.$sourceInfo = null;
|
||||
};
|
||||
|
||||
const updateSourceInfo = async () => {
|
||||
const userInfoRaw = getUserInfoRaw();
|
||||
if (!userInfoRaw) {
|
||||
lastSessionKey = "";
|
||||
resetSourceInfoLoadState();
|
||||
return;
|
||||
}
|
||||
|
||||
const sessionKey = getSessionKey(userInfoRaw);
|
||||
// 会话切换(重新登录 / 换账号)后允许再拉;同会话仅 token 刷新不清理已成功的线路
|
||||
if (lastSessionKey && lastSessionKey !== sessionKey) {
|
||||
resetSourceInfoLoadState();
|
||||
}
|
||||
lastSessionKey = sessionKey;
|
||||
|
||||
if (Vue.prototype.$sourceInfo || sourceInfoLoadFailed) return;
|
||||
if (sourceInfoPromise) return sourceInfoPromise;
|
||||
|
||||
const seq = ++loadSeq;
|
||||
sourceInfoPromise = (async () => {
|
||||
try {
|
||||
const r = await API.getSourceList();
|
||||
// 请求返回时会话已变(登出 / 重登),丢弃结果
|
||||
if (seq !== loadSeq || getSessionKey(getUserInfoRaw()) !== sessionKey) {
|
||||
return;
|
||||
}
|
||||
if (r.code !== 200) {
|
||||
sourceInfoLoadFailed = true;
|
||||
throw new Error(r.tip || r.msg || "getSourceList failed");
|
||||
}
|
||||
syncSourceInfo(r.data);
|
||||
} catch (error) {
|
||||
if (seq !== loadSeq || getSessionKey(getUserInfoRaw()) !== sessionKey) {
|
||||
return;
|
||||
}
|
||||
sourceInfoLoadFailed = true;
|
||||
showError(error);
|
||||
} finally {
|
||||
if (seq === loadSeq) {
|
||||
sourceInfoPromise = null;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
return sourceInfoPromise;
|
||||
};
|
||||
|
||||
const syncSourceInfo = (info) => {
|
||||
info = info || [];
|
||||
Vue.prototype.$sourceInfo = info;
|
||||
sourceInfoLoadFailed = false;
|
||||
try {
|
||||
let _index = localStorage.getItem("overallSituationLine") || 0;
|
||||
if (findUrls(info, "AdminImage")) {
|
||||
Vue.prototype.$imgUrls = [
|
||||
...findUrls(info, "IMAGE"),
|
||||
...findUrls(info, "AdminImage"),
|
||||
];
|
||||
} else {
|
||||
Vue.prototype.$imgUrls = [...findUrls(info, "IMAGE")];
|
||||
}
|
||||
Vue.prototype.$vidUrls = findUrls(info, "VID");
|
||||
Vue.prototype.$audUrls = findUrls(info, "AUDIO");
|
||||
Vue.prototype.$imgUrl =
|
||||
Vue.prototype.$imgUrls[_index].url || Vue.prototype.$imgUrls[0].url;
|
||||
Vue.prototype.$vidUrl = Vue.prototype.$vidUrls[0].url;
|
||||
Vue.prototype.$audUrl = Vue.prototype.$audUrls[0].url;
|
||||
} catch (error) {
|
||||
sourceInfoLoadFailed = true;
|
||||
showError(error);
|
||||
}
|
||||
};
|
||||
|
||||
const findUrls = (info, key) => {
|
||||
return (
|
||||
info.find((kv) => kv.type === key) &&
|
||||
info.find((kv) => kv.type === key).domain
|
||||
);
|
||||
};
|
||||
|
||||
Vue.prototype.$syncSourceInfo = syncSourceInfo;
|
||||
Vue.prototype.$setOverallSituationLine = (index) => {
|
||||
localStorage.setItem("overallSituationLine", index);
|
||||
Vue.prototype.$imgUrl =
|
||||
Vue.prototype.$imgUrls[index].url || Vue.prototype.$imgUrls[0].url;
|
||||
Vue.prototype.$vidUrl = Vue.prototype.$vidUrls[0].url;
|
||||
Vue.prototype.$audUrl = Vue.prototype.$audUrls[0].url;
|
||||
location.reload();
|
||||
};
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
if (to.path === "/" || to.path === "/login") {
|
||||
// 回到登录页且本地已无登录态时,清理失败标记,便于重新登录后拉取
|
||||
if (!getUserInfoRaw()) {
|
||||
lastSessionKey = "";
|
||||
resetSourceInfoLoadState();
|
||||
}
|
||||
return next();
|
||||
}
|
||||
await updateSourceInfo();
|
||||
return next();
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user