Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ const logout = () => {
})
.then(async () => {
await logOutApi();
sessionStorage.removeItem('dashboardCache');
localStorage.removeItem('dashboardCache');
sessionStorage.removeItem('upgradeChecked');
localStorage.removeItem('upgradeChecked');
router.push({ name: 'entrance', params: { code: globalStore.entrance } });
globalStore.setLogStatus(false);
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
Expand Down
61 changes: 61 additions & 0 deletions frontend/src/utils/dashboardCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const DASHBOARD_CACHE_KEY = 'dashboardCache';

type CacheEntry = {
value: any;
expireAt: number;
};

const readCache = (): Record<string, CacheEntry> | null => {
try {
const cacheRaw = localStorage.getItem(DASHBOARD_CACHE_KEY);
return cacheRaw ? JSON.parse(cacheRaw) : {};
} catch {
return null;
}
};

export const getDashboardCache = (key: string) => {
const cache = readCache();
if (!cache) return null;
const entry = cache[key];
if (entry && entry.expireAt > Date.now()) {
return entry.value;
}
return null;
};

export const setDashboardCache = (key: string, value: any, ttl: number) => {
try {
const cacheRaw = localStorage.getItem(DASHBOARD_CACHE_KEY);
const cache = cacheRaw ? JSON.parse(cacheRaw) : {};
cache[key] = {
value,
expireAt: Date.now() + ttl,
};
localStorage.setItem(DASHBOARD_CACHE_KEY, JSON.stringify(cache));
} catch {
localStorage.removeItem(DASHBOARD_CACHE_KEY);
}
};

export const clearDashboardCache = () => {
localStorage.removeItem(DASHBOARD_CACHE_KEY);
};

export const clearDashboardCacheByPrefix = (prefixes: string[]) => {
try {
const cacheRaw = localStorage.getItem(DASHBOARD_CACHE_KEY);
if (!cacheRaw) return;
const cache = JSON.parse(cacheRaw);
Object.keys(cache).forEach((key: string) => {
if (prefixes.some((prefix) => key.startsWith(prefix))) {
delete cache[key];
}
});
localStorage.setItem(DASHBOARD_CACHE_KEY, JSON.stringify(cache));
} catch {
clearDashboardCache();
}
};

export { DASHBOARD_CACHE_KEY };
84 changes: 76 additions & 8 deletions frontend/src/views/home/app/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<template>
<div>
<CardWithHeader :header="$t('app.app')" class="card-interval" v-loading="loading">
<CardWithHeader
:header="$t('app.app')"
class="card-interval"
v-loading="loading"
@mouseenter="refreshLauncherOnHover"
>
<template #header-r>
<el-button class="h-button-setting" link icon="Refresh" @click="refreshLauncher" />
<el-popover placement="left" :width="226" trigger="click">
<el-input size="small" v-model="filter" clearable @input="loadOption()" />
<el-table :show-header="false" :data="options" max-height="150px">
Expand Down Expand Up @@ -185,25 +191,41 @@ import { changeLauncherStatus, loadAppLauncher, loadAppLauncherOption } from '@/
import i18n from '@/lang';
import { GlobalStore } from '@/store';
import { MsgSuccess } from '@/utils/message';
import { ref } from 'vue';
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';
import { jumpToPath } from '@/utils/util';
import { jumpToInstall } from '@/utils/app';
import { routerToFileWithPath, routerToNameWithQuery } from '@/utils/router';
import { clearDashboardCacheByPrefix, getDashboardCache, setDashboardCache } from '@/utils/dashboardCache';

const router = useRouter();
const globalStore = GlobalStore();

const DASHBOARD_CACHE_TTL = {
launcherOption: 5 * 60 * 1000,
launcher: 10 * 60 * 1000,
systemIP: 10 * 60 * 1000,
};

const clearLauncherCache = () => {
clearDashboardCacheByPrefix(['appLauncherOption-', 'appLauncher', 'systemIP']);
};

let loading = ref(false);
let apps = ref([]);
const options = ref([]);
const filter = ref();
const launcherFromCache = ref(false);
const launcherOptionFromCache = ref(false);
const systemIPFromCache = ref(false);
const hasRefreshedLauncherOnHover = ref(false);
const mobile = computed(() => {
return globalStore.isMobile();
});
const defaultLink = ref('');

const acceptParams = (): void => {
hasRefreshedLauncherOnHover.value = false;
search();
loadOption();
getConfig();
Expand All @@ -215,17 +237,31 @@ const goInstall = (key: string, type: string) => {
}
};

const search = async () => {
const search = async (force?: boolean) => {
loading.value = true;
const cache = force ? null : getDashboardCache('appLauncher');
if (cache !== null) {
apps.value = cache;
launcherFromCache.value = true;
for (const item of apps.value) {
if (item.detail && item.detail.length !== 0) {
item.currentRow = item.detail[0];
}
}
loading.value = false;
return;
}
await loadAppLauncher()
.then((res) => {
loading.value = false;
apps.value = res.data;
launcherFromCache.value = false;
for (const item of apps.value) {
if (item.detail && item.detail.length !== 0) {
item.currentRow = item.detail[0];
}
}
setDashboardCache('appLauncher', apps.value, DASHBOARD_CACHE_TTL.launcher);
})
.finally(() => {
loading.value = false;
Expand All @@ -238,7 +274,9 @@ const onChangeStatus = async (row: any) => {
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
clearLauncherCache();
search();
loadOption();
})
.catch(() => {
loading.value = false;
Expand All @@ -249,12 +287,18 @@ const toLink = (link: string) => {
window.open(link, '_blank');
};

const getConfig = async () => {
const getConfig = async (force?: boolean) => {
try {
const res = await getAgentSettingByKey('SystemIP');
if (res.data != '') {
defaultLink.value = res.data;
const cache = force ? null : getDashboardCache('systemIP');
if (cache !== null) {
defaultLink.value = cache;
systemIPFromCache.value = true;
return;
}
const res = await getAgentSettingByKey('SystemIP');
defaultLink.value = res.data || '';
systemIPFromCache.value = false;
setDashboardCache('systemIP', defaultLink.value, DASHBOARD_CACHE_TTL.systemIP);
} catch (error) {}
};

Expand Down Expand Up @@ -286,9 +330,33 @@ const onOperate = async (operation: string, row: any) => {
});
};

const loadOption = async () => {
const loadOption = async (force?: boolean) => {
const cacheKey = `appLauncherOption-${filter.value || ''}`;
const cache = force ? null : getDashboardCache(cacheKey);
if (cache !== null) {
options.value = cache;
launcherOptionFromCache.value = true;
return;
}
const res = await loadAppLauncherOption(filter.value || '');
options.value = res.data || [];
launcherOptionFromCache.value = false;
setDashboardCache(cacheKey, options.value, DASHBOARD_CACHE_TTL.launcherOption);
};

const refreshLauncher = async () => {
clearLauncherCache();
hasRefreshedLauncherOnHover.value = false;
await Promise.allSettled([loadOption(true), search(true), getConfig(true)]);
};

const refreshLauncherOnHover = async () => {
if (hasRefreshedLauncherOnHover.value) return;
if (!launcherFromCache.value && !launcherOptionFromCache.value && !systemIPFromCache.value) return;
hasRefreshedLauncherOnHover.value = true;
await loadOption(true);
await search(true);
await getConfig(true);
};

defineExpose({
Expand Down
Loading
Loading