add cache management page

This commit is contained in:
MaysWind
2026-02-27 00:50:52 +08:00
parent 40a366e68d
commit d95fcd8b00
31 changed files with 685 additions and 39 deletions
+2 -2
View File
@@ -15,7 +15,7 @@ import { getMapWebsite } from '@/lib/map/index.ts';
import { getContributors } from '@/lib/contributors.ts';
import { getLicense, getThirdPartyLicenses } from '@/lib/licenses.ts';
import { formatDisplayVersion, getClientDisplayVersion, getClientBuildTime } from '@/lib/version.ts';
import { clearBrowserCaches } from '@/lib/ui/common.ts';
import { clearAllBrowserCaches } from '@/lib/cache.ts';
export function useAboutPageBase() {
const { tt, formatDateTimeToLongDateTime } = useI18n();
@@ -61,7 +61,7 @@ export function useAboutPageBase() {
const thirdPartyLicenses = computed<LicenseInfo[]>(() => getThirdPartyLicenses());
function refreshBrowserCache(): void {
clearBrowserCaches().then(() => {
clearAllBrowserCaches().then(() => {
location.reload();
});
}
+13 -2
View File
@@ -17,6 +17,10 @@
<v-icon size="20" start :icon="mdiCloudOutline"/>
{{ tt('Settings Sync') }}
</v-tab>
<v-tab value="browserCacheSetting" @click="pushRouter('browserCacheSetting')">
<v-icon size="20" start :icon="mdiDatabaseClockOutline"/>
{{ tt('Browser Cache Management') }}
</v-tab>
</v-tabs>
<v-window class="mt-4 disable-tab-transition" v-model="activeTab">
@@ -35,6 +39,10 @@
<v-window-item value="cloudSyncSetting">
<app-cloud-sync-setting-tab/>
</v-window-item>
<v-window-item value="browserCacheSetting">
<app-browser-cache-setting-tab/>
</v-window-item>
</v-window>
</div>
</template>
@@ -44,6 +52,7 @@ import AppBasicSettingTab from './settings/tabs/AppBasicSettingTab.vue';
import AppLockSettingTab from './settings/tabs/AppLockSettingTab.vue';
import AppStatisticsSettingTab from './settings/tabs/AppStatisticsSettingTab.vue';
import AppCloudSyncSettingTab from './settings/tabs/AppCloudSyncSettingTab.vue';
import AppBrowserCacheSettingTab from './settings/tabs/AppBrowserCacheSettingTab.vue';
import { ref } from 'vue';
import { useRouter, onBeforeRouteUpdate } from 'vue-router';
@@ -54,7 +63,8 @@ import {
mdiCogOutline,
mdiLockOpenOutline,
mdiChartPieOutline,
mdiCloudOutline
mdiCloudOutline,
mdiDatabaseClockOutline
} from '@mdi/js';
const props = defineProps<{
@@ -69,7 +79,8 @@ const ALL_TABS: string[] = [
'basicSetting',
'applicationLockSetting',
'statisticsSetting',
'cloudSyncSetting'
'cloudSyncSetting',
'browserCacheSetting'
];
const activeTab = ref<string>((() => {
@@ -0,0 +1,161 @@
<template>
<v-row>
<v-col cols="12">
<v-card :class="{ 'disabled': loadingCacheStatistics }">
<template #title>
<div class="d-flex align-center">
<span>{{ tt('File Cache') }}</span>
<v-btn density="compact" color="default" variant="text" size="24"
class="ms-2" :icon="true" :loading="loadingCacheStatistics" @click="reloadCacheStatistics()">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
<v-icon :icon="mdiRefresh" size="24" />
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
</div>
</template>
<v-card-text class="mt-1" v-if="loadingCacheStatistics">
<span class="text-body-1">{{ tt('Used storage') }}</span>
<v-skeleton-loader class="d-inline-block skeleton-no-margin ml-1 pt-1 pb-1" type="text" style="width: 100px; height: 24px" :loading="true" v-if="loadingCacheStatistics"></v-skeleton-loader>
</v-card-text>
<v-card-text v-else-if="!loadingCacheStatistics">
<span class="text-body-1">{{ tt('Used storage') }}</span>
<span class="text-xl ml-1" v-if="!loadingCacheStatistics">{{ fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.totalCacheSize, 2) : '-' }}</span>
</v-card-text>
<v-card-text>
<v-row>
<v-col cols="6" sm="3" :key="idx" v-for="(item, idx) in [
{
title: 'Application Code',
count: fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.codeCacheSize, 2) : '-',
icon: mdiFileCodeOutline,
color: 'info-darken-1'
},
{
title: 'Resource Files',
count: fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.assetsCacheSize, 2) : '-',
icon: mdiFileImageOutline,
color: 'teal'
},
{
title: 'Map Data',
count: fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.mapCacheSize, 2) : '-',
icon: mdiFileImageMarkerOutline,
color: 'warning'
},
{
title: 'Others',
count: fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.othersCacheSize, 2) : '-',
icon: mdiFileOutline,
color: 'grey'
}
]">
<div class="d-flex align-center">
<div class="me-3">
<v-avatar rounded :color="item.color" size="42" class="elevation-1">
<v-icon size="24" :icon="item.icon"/>
</v-avatar>
</div>
<div class="d-flex flex-column">
<span class="text-caption">{{ tt(item.title) }}</span>
<v-skeleton-loader class="skeleton-no-margin pt-2 pb-2" type="text" style="width: 100px" :loading="true" v-if="loadingCacheStatistics"></v-skeleton-loader>
<span class="text-xl" v-if="!loadingCacheStatistics">{{ item.count }}</span>
</div>
</div>
</v-col>
</v-row>
</v-card-text>
<v-card-text class="mt-2">
<v-btn color="gray" variant="tonal"
:disabled="loadingCacheStatistics || !fileCacheStatistics" @click="clearFileCache()">
{{ tt('Clear File Cache') }}
</v-btn>
</v-card-text>
</v-card>
</v-col>
<v-col cols="12">
<v-card>
<template #title>
<div class="d-flex align-center">
<span>{{ tt('Exchange Rates Data') }}</span>
</div>
</template>
<v-card-text>
<span class="text-body-1">{{ tt('Used storage') }}</span>
<span class="text-xl ml-1">{{ formatVolumeToLocalizedNumerals(exchangeRatesCacheSize ?? 0, 2) }}</span>
</v-card-text>
</v-card>
</v-col>
</v-row>
<confirm-dialog ref="confirmDialog"/>
<snack-bar ref="snackbar" />
</template>
<script setup lang="ts">
import ConfirmDialog from '@/components/desktop/ConfirmDialog.vue';
import SnackBar from '@/components/desktop/SnackBar.vue';
import { ref, useTemplateRef } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
import { type BrowserCacheStatistics } from '@/core/cache.ts';
import { loadBrowserCacheStatistics, clearAllBrowserCaches } from '@/lib/cache.ts';
import {
mdiRefresh,
mdiFileCodeOutline,
mdiFileImageOutline,
mdiFileImageMarkerOutline,
mdiFileOutline
} from '@mdi/js';
type ConfirmDialogType = InstanceType<typeof ConfirmDialog>;
type SnackBarType = InstanceType<typeof SnackBar>;
const { tt, formatVolumeToLocalizedNumerals } = useI18n();
const exchangeRatesStore = useExchangeRatesStore();
const confirmDialog = useTemplateRef<ConfirmDialogType>('confirmDialog');
const snackbar = useTemplateRef<SnackBarType>('snackbar');
const loadingCacheStatistics = ref<boolean>(true);
const fileCacheStatistics = ref<BrowserCacheStatistics | undefined>(undefined);
const exchangeRatesCacheSize = ref<number | undefined>(undefined);
function reloadCacheStatistics(): void {
loadingCacheStatistics.value = true;
loadBrowserCacheStatistics().then(statistics => {
fileCacheStatistics.value = statistics;
exchangeRatesCacheSize.value = exchangeRatesStore.getExchangeRatesCacheSize();
loadingCacheStatistics.value = false;
}).catch(() => {
loadingCacheStatistics.value = false;
snackbar.value?.showError('Failed to load browser cache statistics');
});
}
function clearFileCache(): void {
confirmDialog.value?.open('Are you sure you want to clear file cache?').then(() => {
clearAllBrowserCaches().then(() => {
location.reload();
});
});
}
reloadCacheStatistics();
</script>
+1
View File
@@ -108,6 +108,7 @@
</template>
</f7-list-item>
<f7-list-item :title="tt('Browser Cache Management')" link="/settings/browser_caches"></f7-list-item>
<f7-list-item link="#" no-chevron :title="tt('Switch to Desktop Version')" @click="switchToDesktopVersion"></f7-list-item>
<f7-list-item :title="tt('About')" link="/about" :after="version"></f7-list-item>
@@ -0,0 +1,103 @@
<template>
<f7-page>
<f7-navbar>
<f7-nav-left :class="{ 'disabled': loading }" :back-link="tt('Back')"></f7-nav-left>
<f7-nav-title :title="tt('Browser Cache Management')"></f7-nav-title>
<f7-nav-right :class="{ 'disabled': loading }">
<f7-link icon-f7="ellipsis" :class="{ 'disabled': loading || !fileCacheStatistics }" @click="showMoreActionSheet = true"></f7-link>
</f7-nav-right>
</f7-navbar>
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
<f7-list-item group-title :sortable="false">
<small>{{ tt('File Cache') }}</small>
</f7-list-item>
<f7-list-item title="Used storage" after="Count"></f7-list-item>
<f7-list-item title="Application Code" after="Count"></f7-list-item>
<f7-list-item title="Resource Files" after="Count"></f7-list-item>
<f7-list-item title="Map Data" after="Count"></f7-list-item>
<f7-list-item title="Others" after="Count"></f7-list-item>
</f7-list>
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
<f7-list-item group-title :sortable="false">
<small>{{ tt('Exchange Rates Data') }}</small>
</f7-list-item>
<f7-list-item title="Used storage" after="Count"></f7-list-item>
</f7-list>
<f7-list strong inset dividers class="margin-vertical" v-if="!loading">
<f7-list-item group-title :sortable="false">
<small>{{ tt('File Cache') }}</small>
</f7-list-item>
<f7-list-item :title="tt('Used storage')" :after="fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.totalCacheSize, 2) : '-'"></f7-list-item>
<f7-list-item :title="tt('Application Code')" :after="fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.codeCacheSize, 2) : '-'"></f7-list-item>
<f7-list-item :title="tt('Resource Files')" :after="fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.assetsCacheSize, 2) : '-'"></f7-list-item>
<f7-list-item :title="tt('Map Data')" :after="fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.mapCacheSize, 2) : '-'"></f7-list-item>
<f7-list-item :title="tt('Others')" :after="fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.othersCacheSize, 2) : '-'"></f7-list-item>
</f7-list>
<f7-list strong inset dividers class="margin-vertical" v-if="!loading">
<f7-list-item group-title :sortable="false">
<small>{{ tt('Exchange Rates Data') }}</small>
</f7-list-item>
<f7-list-item :title="tt('Used storage')" :after="formatVolumeToLocalizedNumerals(exchangeRatesCacheSize ?? 0, 2)"></f7-list-item>
</f7-list>
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
<f7-actions-group>
<f7-actions-button :class="{ 'disabled': loading || !fileCacheStatistics }"
@click="clearFileCache">{{ tt('Clear File Cache') }}</f7-actions-button>
</f7-actions-group>
<f7-actions-group>
<f7-actions-button bold close>{{ tt('Cancel') }}</f7-actions-button>
</f7-actions-group>
</f7-actions>
</f7-page>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
import { type BrowserCacheStatistics } from '@/core/cache.ts';
import { loadBrowserCacheStatistics, clearAllBrowserCaches } from '@/lib/cache.ts';
const { tt, formatVolumeToLocalizedNumerals } = useI18n();
const { showConfirm, showToast } = useI18nUIComponents();
const exchangeRatesStore = useExchangeRatesStore();
const loading = ref<boolean>(true);
const showMoreActionSheet = ref<boolean>(false);
const fileCacheStatistics = ref<BrowserCacheStatistics | undefined>(undefined);
const exchangeRatesCacheSize = ref<number | undefined>(undefined);
function reloadCacheStatistics(): void {
loading.value = true;
loadBrowserCacheStatistics().then(statistics => {
fileCacheStatistics.value = statistics;
exchangeRatesCacheSize.value = exchangeRatesStore.getExchangeRatesCacheSize();
loading.value = false;
}).catch(() => {
loading.value = false;
showToast('Failed to load browser cache statistics');
});
}
function clearFileCache(): void {
showConfirm('Are you sure you want to clear file cache?', () => {
clearAllBrowserCaches().then(() => {
location.reload();
});
});
}
reloadCacheStatistics();
</script>