'admin-22.05.22:修复标记为需要缓存的tab页后,再次从左侧菜单打开,还是显示被缓存的页面内容(#I4UY3G),感谢@axcc1234、特别感谢群友@华仔'

This commit is contained in:
lyt
2022-05-22 17:18:13 +08:00
parent 2c8dbace6c
commit 1cd056cb83
20 changed files with 681 additions and 639 deletions

View File

@ -1,9 +1,9 @@
<template>
<el-config-provider :size="getGlobalComponentSize" :locale="i18nLocale">
<router-view v-show="themeConfig.lockScreenTime !== 0" />
<router-view v-show="themeConfig.lockScreenTime > 1" />
<LockScreen v-if="themeConfig.isLockScreen" />
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime !== 0" />
<CloseFull />
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
<CloseFull v-if="!themeConfig.isLockScreen" />
</el-config-provider>
</template>

View File

@ -49,9 +49,9 @@
</div>
</div>
<div class="layout-lock-screen-login-icon">
<SvgIcon name="ele-Microphone" />
<SvgIcon name="ele-AlarmClock" />
<SvgIcon name="ele-SwitchButton" />
<SvgIcon name="ele-Microphone" :size="20" />
<SvgIcon name="ele-AlarmClock" :size="20" />
<SvgIcon name="ele-SwitchButton" :size="20" />
</div>
</div>
</transition>
@ -255,11 +255,11 @@ export default defineComponent({
bottom: 50px;
&-time {
font-size: 100px;
color: var(--color-whites);
color: var(--el-color-white);
}
&-info {
font-size: 40px;
color: var(--color-whites);
color: var(--el-color-white);
}
&-minutes {
font-size: 16px;
@ -272,7 +272,7 @@ export default defineComponent({
border-radius: 100%;
border: 1px solid var(--el-border-color-light, #ebeef5);
background: rgba(255, 255, 255, 0.1);
color: var(--color-whites);
color: var(--el-color-white);
opacity: 0.8;
position: absolute;
right: 30px;
@ -288,7 +288,7 @@ export default defineComponent({
position: absolute;
top: 150%;
font-size: 12px;
color: var(--color-whites);
color: var(--el-color-white);
left: 50%;
line-height: 1.2;
transform: translate(-50%, -50%);
@ -299,7 +299,7 @@ export default defineComponent({
border: 1px solid rgba(255, 255, 255, 0.5);
background: rgba(255, 255, 255, 0.2);
box-shadow: 0 0 12px 0 rgba(255, 255, 255, 0.5);
color: var(--color-whites);
color: var(--el-color-white);
opacity: 1;
transition: all 0.3s ease;
i {
@ -324,7 +324,7 @@ export default defineComponent({
display: flex;
flex-direction: column;
justify-content: center;
color: var(--color-whites);
color: var(--el-color-white);
&-box {
text-align: center;
margin: auto;

View File

@ -93,7 +93,6 @@ export default defineComponent({
};
// 当前路由字符串切割成数组,并删除第一项空内容
const initRouteSplit = (path: string) => {
state.breadcrumbList = [];
if (!themeConfig.value.isBreadcrumb) return false;
state.breadcrumbList = [routesList.value[0]];
state.routeSplit = path.split('/');
@ -129,12 +128,16 @@ export default defineComponent({
height: inherit;
display: flex;
align-items: center;
padding-left: 15px;
.layout-navbars-breadcrumb-icon {
cursor: pointer;
font-size: 18px;
margin-right: 15px;
color: var(--next-bg-topBarColor);
height: 100%;
width: 40px;
opacity: 0.8;
&:hover {
opacity: 1;
}
}
.layout-navbars-breadcrumb-span {
opacity: 0.7;

View File

@ -97,7 +97,7 @@ export default defineComponent({
});
// 页面卸载时
onUnmounted(() => {
proxy.mittBus.off('getBreadcrumbIndexSetFilterRoutes');
proxy.mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {});
});
return {
setIsShowLogo,

View File

@ -64,7 +64,9 @@ export default defineComponent({
state.isShowSearch = true;
initTageView();
nextTick(() => {
layoutMenuAutocompleteRef.value.focus();
setTimeout(() => {
layoutMenuAutocompleteRef.value.focus();
});
});
};
// 搜索弹窗关闭

View File

@ -643,7 +643,7 @@ export default defineComponent({
});
});
onUnmounted(() => {
proxy.mittBus.off('layoutMobileResize');
proxy.mittBus.off('layoutMobileResize', () => {});
});
return {
openDrawer,

View File

@ -33,7 +33,7 @@
<i class="icon-skin iconfont" :title="$t('message.user.title3')"></i>
</div>
<div class="layout-navbars-breadcrumb-user-icon">
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300">
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
<template #reference>
<el-badge :is-dot="true">
<el-icon :title="$t('message.user.title4')">

View File

@ -67,6 +67,7 @@ import { storeToRefs } from 'pinia';
import pinia from '/@/stores/index';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useThemeConfig } from '/@/stores/themeConfig';
import { useKeepALiveNames } from '/@/stores/keepAliveNames';
import { Session } from '/@/utils/storage';
import { isObjectValueEqual } from '/@/utils/arrayOperation';
import other from '/@/utils/other';
@ -115,6 +116,7 @@ export default defineComponent({
const storesTagsViewRoutes = useTagsViewRoutes();
const { themeConfig } = storeToRefs(storesThemeConfig);
const { tagsViewRoutes } = storeToRefs(storesTagsViewRoutes);
const storesKeepALiveNames = useKeepALiveNames();
const route = useRoute();
const router = useRouter();
const state = reactive<TagsViewState>({
@ -176,6 +178,7 @@ export default defineComponent({
if (v.meta.isAffix && !v.meta.isHide) {
v.url = setTagsViewHighlight(v);
state.tagsViewList.push({ ...v });
storesKeepALiveNames.addCachedView(v);
}
});
await addTagsView(route.path, route);
@ -202,6 +205,7 @@ export default defineComponent({
if (findItem.meta.isLink && !findItem.meta.isIframe) return false;
to.meta.isDynamic ? (findItem.params = to.params) : (findItem.query = to.query);
findItem.url = setTagsViewHighlight(findItem);
await storesKeepALiveNames.addCachedView(findItem);
state.tagsViewList.push({ ...findItem });
addBrowserSetSession(state.tagsViewList);
}
@ -247,19 +251,26 @@ export default defineComponent({
if (to && to.meta.isDynamic) item.params = to?.params ? to?.params : route.params;
else item.query = to?.query ? to?.query : route.query;
item.url = setTagsViewHighlight(item);
await storesKeepALiveNames.addCachedView(item);
await state.tagsViewList.push({ ...item });
await addBrowserSetSession(state.tagsViewList);
});
};
// 2、刷新当前 tagsView
const refreshCurrentTagsView = (fullPath: string) => {
proxy.mittBus.emit('onTagsViewRefreshRouterView', fullPath);
const refreshCurrentTagsView = async (fullPath: string) => {
const item = state.tagsViewList.find((v: any) => (getThemeConfig.value.isShareTagsView ? v.path === fullPath : v.url === fullPath));
if (item != null) {
await storesKeepALiveNames.delCachedView(item);
proxy.mittBus.emit('onTagsViewRefreshRouterView', fullPath);
if (item.meta.isKeepAlive) storesKeepALiveNames.addCachedView(item);
}
};
// 3、关闭当前 tagsView如果是设置了固定的isAffix不可以关闭
const closeCurrentTagsView = (path: string) => {
state.tagsViewList.map((v: any, k: number, arr: any) => {
if (!v.meta.isAffix) {
if (getThemeConfig.value.isShareTagsView ? v.path === path : v.url === path) {
storesKeepALiveNames.delCachedView(v);
state.tagsViewList.splice(k, 1);
setTimeout(() => {
if (state.tagsViewList.length === k && getThemeConfig.value.isShareTagsView ? state.routePath === path : state.routeActive === path) {
@ -298,6 +309,7 @@ export default defineComponent({
Session.get('tagsViewList').map((v: any) => {
if (v.meta.isAffix && !v.meta.isHide) {
v.url = setTagsViewHighlight(v);
storesKeepALiveNames.delOthersCachedViews(v);
state.tagsViewList.push({ ...v });
}
});
@ -308,6 +320,7 @@ export default defineComponent({
// 5、关闭全部 tagsView如果是设置了固定的isAffix不进行关闭
const closeAllTagsView = () => {
if (Session.get('tagsViewList')) {
storesKeepALiveNames.delAllCachedViews();
state.tagsViewList = [];
Session.get('tagsViewList').map((v: any) => {
if (v.meta.isAffix && !v.meta.isHide) {
@ -531,11 +544,11 @@ export default defineComponent({
// 页面卸载时
onUnmounted(() => {
// 取消非本页面调用监听
proxy.mittBus.off('onCurrentContextmenuClick');
proxy.mittBus.off('onCurrentContextmenuClick', () => {});
// 取消监听布局配置界面开启/关闭拖拽
proxy.mittBus.off('openOrCloseSortable');
proxy.mittBus.off('openOrCloseSortable', () => {});
// 取消监听布局配置开启 TagsView 共用
proxy.mittBus.off('openShareTagsView');
proxy.mittBus.off('openShareTagsView', () => {});
// 取消窗口 resize 监听
window.removeEventListener('resize', onSortableResize);
});

View File

@ -2,7 +2,7 @@
<div class="h100">
<router-view v-slot="{ Component }">
<transition :name="setTransitionName" mode="out-in">
<keep-alive :include="keepAliveNameList">
<keep-alive :include="getKeepAliveNames">
<component :is="Component" :key="refreshRouterViewKey" class="w100" />
</keep-alive>
</transition>
@ -28,9 +28,9 @@ export default defineComponent({
setup() {
const { proxy } = <any>getCurrentInstance();
const route = useRoute();
const stores = useKeepALiveNames();
const storesKeepAliveNames = useKeepALiveNames();
const storesThemeConfig = useThemeConfig();
const { keepAliveNames } = storeToRefs(stores);
const { keepAliveNames, cachedViews } = storeToRefs(storesKeepAliveNames);
const { themeConfig } = storeToRefs(storesThemeConfig);
const state = reactive<ParentViewState>({
refreshRouterViewKey: null,
@ -40,6 +40,10 @@ export default defineComponent({
const setTransitionName = computed(() => {
return themeConfig.value.animation;
});
// 获取组件缓存列表(name值)
const getKeepAliveNames = computed(() => {
return themeConfig.value.isTagsview ? cachedViews.value : state.keepAliveNameList;
});
// 页面加载前,处理缓存,页面刷新时路由缓存处理
onBeforeMount(() => {
state.keepAliveNameList = keepAliveNames.value;
@ -54,7 +58,7 @@ export default defineComponent({
});
// 页面卸载时
onUnmounted(() => {
proxy.mittBus.off('onTagsViewRefreshRouterView');
proxy.mittBus.off('onTagsViewRefreshRouterView', () => {});
});
// 监听路由变化,防止 tagsView 多标签时,切换动画消失
watch(
@ -65,6 +69,7 @@ export default defineComponent({
);
return {
setTransitionName,
getKeepAliveNames,
...toRefs(state),
};
},

View File

@ -18,6 +18,7 @@ export interface UserInfosStates {
// 路由缓存列表
export interface KeepAliveNamesState {
keepAliveNames: string[];
cachedViews: string[];
}
// 后端返回原始路由(未处理时)

View File

@ -3,15 +3,35 @@ import { KeepAliveNamesState } from './interface';
/**
* 路由缓存列表
* @methods setCacheKeepAlive 设置要缓存的路由 names
* @methods setCacheKeepAlive 设置要缓存的路由 names(开启 Tagsview
* @methods addCachedView 添加要缓存的路由 names关闭 Tagsview
* @methods delCachedView 删除要缓存的路由 names关闭 Tagsview
* @methods delOthersCachedViews 右键菜单`关闭其它`,删除要缓存的路由 names关闭 Tagsview
* @methods delAllCachedViews 右键菜单`全部关闭`,删除要缓存的路由 names关闭 Tagsview
*/
export const useKeepALiveNames = defineStore('keepALiveNames', {
state: (): KeepAliveNamesState => ({
keepAliveNames: [],
cachedViews: [],
}),
actions: {
async setCacheKeepAlive(data: Array<string>) {
this.keepAliveNames = data;
},
async addCachedView(view: any) {
if (this.cachedViews.includes(view.name)) return;
if (view.meta.isKeepAlive) this.cachedViews.push(view.name);
},
async delCachedView(view: any) {
const index = this.cachedViews.indexOf(view.name);
index > -1 && this.cachedViews.splice(index, 1);
},
async delOthersCachedViews(view: any) {
if (view.meta.isKeepAlive) this.cachedViews = [view.name];
else this.cachedViews = [];
},
async delAllCachedViews() {
this.cachedViews = [];
},
},
});

View File

@ -1,5 +1,6 @@
import { defineStore } from 'pinia';
import { UserInfosStates, UserInfosState } from './interface';
import Cookies from 'js-cookie';
import { UserInfosStates } from './interface';
import { Session } from '/@/utils/storage';
/**
@ -9,21 +10,54 @@ import { Session } from '/@/utils/storage';
export const useUserInfo = defineStore('userInfo', {
state: (): UserInfosStates => ({
userInfos: {
authBtnList: [],
photo: '',
roles: [],
time: 0,
userName: '',
photo: '',
time: 0,
roles: [],
authBtnList: [],
},
}),
actions: {
async setUserInfos(data?: UserInfosState) {
if (data) {
this.userInfos = <any>data;
async setUserInfos() {
// 模拟数据,请求接口时,记得删除多余代码及对应依赖的引入
const userName = Cookies.get('userName');
// 模拟数据
let defaultRoles: Array<string> = [];
let defaultAuthBtnList: Array<string> = [];
// admin 页面权限标识,对应路由 meta.roles用于控制路由的显示/隐藏
let adminRoles: Array<string> = ['admin'];
// admin 按钮权限标识
let adminAuthBtnList: Array<string> = ['btn.add', 'btn.del', 'btn.edit', 'btn.link'];
// test 页面权限标识,对应路由 meta.roles用于控制路由的显示/隐藏
let testRoles: Array<string> = ['common'];
// test 按钮权限标识
let testAuthBtnList: Array<string> = ['btn.add', 'btn.link'];
// 不同用户模拟不同的用户权限
if (userName === 'admin') {
defaultRoles = adminRoles;
defaultAuthBtnList = adminAuthBtnList;
} else {
if (Session.get('userInfo')) {
this.userInfos = Session.get('userInfo');
}
defaultRoles = testRoles;
defaultAuthBtnList = testAuthBtnList;
}
// 用户信息模拟数据
const userInfos = {
userName: userName,
photo:
userName === 'admin'
? 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg'
: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=317673774,2961727727&fm=26&gp=0.jpg',
time: new Date().getTime(),
roles: defaultRoles,
authBtnList: defaultAuthBtnList,
};
// 存储用户信息到浏览器缓存
Session.set('userInfo', userInfos);
if (Session.get('userInfo')) {
this.userInfos = Session.get('userInfo');
} else {
this.userInfos = userInfos;
}
},
},

View File

@ -1,3 +1,5 @@
import Cookies from 'js-cookie';
/**
* window.localStorage 浏览器永久缓存
* @method set 设置永久缓存
@ -35,19 +37,23 @@ export const Local = {
export const Session = {
// 设置临时缓存
set(key: string, val: any) {
if (key === 'token') return Cookies.set(key, val);
window.sessionStorage.setItem(key, JSON.stringify(val));
},
// 获取临时缓存
get(key: string) {
if (key === 'token') return Cookies.get(key);
let json: any = window.sessionStorage.getItem(key);
return JSON.parse(json);
},
// 移除临时缓存
remove(key: string) {
if (key === 'token') return Cookies.remove(key);
window.sessionStorage.removeItem(key);
},
// 移除全部临时缓存
clear() {
Cookies.remove('token');
window.sessionStorage.clear();
},
};

View File

@ -24,16 +24,16 @@
<script lang="ts">
import { toRefs, reactive, onMounted, defineComponent } from 'vue';
import Cookies from 'js-cookie';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
import { frontEndsResetRoute, setAddRoute, setFilterMenuAndCacheTagsViewRoutes } from '/@/router/frontEnd';
import { Session } from '/@/utils/storage';
export default defineComponent({
name: 'limitsFrontEndPage',
setup() {
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);
const storesUserInfo = useUserInfo();
const { userInfos } = storeToRefs(storesUserInfo);
const state = reactive({
val: '',
userAuth: '',
@ -46,36 +46,9 @@ export default defineComponent({
const onRadioChange = async () => {
// 模拟数据
frontEndsResetRoute();
let defaultRoles: string[] = [];
let defaultAuthBtnList: string[] = [];
// admin 页面权限标识,对应路由 meta.roles用于控制路由的显示/隐藏
let adminRoles: string[] = ['admin'];
// admin 按钮权限标识
let adminAuthBtnList: string[] = ['btn.add', 'btn.del', 'btn.edit', 'btn.link'];
// test 页面权限标识,对应路由 meta.roles用于控制路由的显示/隐藏
let testRoles: string[] = ['common'];
// test 按钮权限标识
let testAuthBtnList: string[] = ['btn.add', 'btn.link'];
// 不同用户模拟不同的用户权限
if (state.userAuth === 'admin') {
defaultRoles = adminRoles;
defaultAuthBtnList = adminAuthBtnList;
} else {
defaultRoles = testRoles;
defaultAuthBtnList = testAuthBtnList;
}
const userInfos = {
userName: state.userAuth,
photo:
state.userAuth === 'admin'
? 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg'
: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=317673774,2961727727&fm=26&gp=0.jpg',
time: new Date().getTime(),
roles: defaultRoles,
authBtnList: defaultAuthBtnList,
};
Session.set('userInfo', userInfos);
stores.setUserInfos({ ...userInfos }); // 请注意执行顺序(存储用户信息 pinia)
Cookies.set('userName', state.userAuth);
// 模拟切换不同权限用户
storesUserInfo.setUserInfos();
await setAddRoute();
setFilterMenuAndCacheTagsViewRoutes();
};

View File

@ -60,11 +60,11 @@ import { toRefs, reactive, defineComponent, computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import { useI18n } from 'vue-i18n';
import Cookies from 'js-cookie';
import { storeToRefs } from 'pinia';
import { useThemeConfig } from '/@/stores/themeConfig';
import { initFrontEndControlRoutes } from '/@/router/frontEnd';
import { initBackEndControlRoutes } from '/@/router/backEnd';
import { useUserInfo } from '/@/stores/userInfo';
import { Session } from '/@/utils/storage';
import { formatAxis } from '/@/utils/formatTime';
import { NextLoading } from '/@/utils/loading';
@ -73,7 +73,6 @@ export default defineComponent({
name: 'loginAccount',
setup() {
const { t } = useI18n();
const stores = useUserInfo();
const storesThemeConfig = useThemeConfig();
const { themeConfig } = storeToRefs(storesThemeConfig);
const route = useRoute();
@ -95,43 +94,11 @@ export default defineComponent({
});
// 登录
const onSignIn = async () => {
// 模拟数据
state.loading.signIn = true;
let defaultRoles: Array<string> = [];
let defaultAuthBtnList: Array<string> = [];
// admin 页面权限标识,对应路由 meta.roles用于控制路由的显示/隐藏
let adminRoles: Array<string> = ['admin'];
// admin 按钮权限标识
let adminAuthBtnList: Array<string> = ['btn.add', 'btn.del', 'btn.edit', 'btn.link'];
// test 页面权限标识,对应路由 meta.roles用于控制路由的显示/隐藏
let testRoles: Array<string> = ['common'];
// test 按钮权限标识
let testAuthBtnList: Array<string> = ['btn.add', 'btn.link'];
// 不同用户模拟不同的用户权限
if (state.ruleForm.userName === 'admin') {
defaultRoles = adminRoles;
defaultAuthBtnList = adminAuthBtnList;
} else {
defaultRoles = testRoles;
defaultAuthBtnList = testAuthBtnList;
}
// 用户信息模拟数据
const userInfos = {
userName: state.ruleForm.userName,
photo:
state.ruleForm.userName === 'admin'
? 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg'
: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=317673774,2961727727&fm=26&gp=0.jpg',
time: new Date().getTime(),
roles: defaultRoles,
authBtnList: defaultAuthBtnList,
};
// 存储 token 到浏览器缓存
Session.set('token', Math.random().toString(36).substr(0));
// 存储用户信息到浏览器缓存
Session.set('userInfo', userInfos);
// 1、请注意执行顺序(存储用户信息到vuex)
stores.setUserInfos({ ...userInfos });
// 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.ts` 中不同用户登录判断(模拟数据)
Cookies.set('userName', state.ruleForm.userName);
if (!themeConfig.value.isRequestRoutes) {
// 前端控制路由2、请注意执行顺序
await initFrontEndControlRoutes();