diff --git a/index.html b/index.html index f3b7c30d..e7d2e694 100644 --- a/index.html +++ b/index.html @@ -317,4 +317,4 @@ - + \ No newline at end of file diff --git a/public/loader.css b/public/loader.css index 553eabc7..48603cab 100644 --- a/public/loader.css +++ b/public/loader.css @@ -1,6 +1,6 @@ #loading-bg { position: fixed; - z-index: 9999; + z-index: 99999; display: block; background: var(--initial-loader-bg, #fff); block-size: 100vh; @@ -94,4 +94,4 @@ opacity: 1; transform: rotate(1turn); } -} +} \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 549fd251..4ff8097f 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,7 +3,7 @@ import { useTheme } from 'vuetify' import { checkPrefersColorSchemeIsDark } from '@/@core/utils' import { ensureRenderComplete, removeEl } from './@core/utils/dom' import api from '@/api' -import { useAuthStore } from '@/stores/auth' +import { useAuthStore, useGlobalSettingsStore } from '@/stores' import { getBrowserLocale, setI18nLanguage } from './plugins/i18n' import { SupportedLocale } from '@/types/i18n' import { checkAndEmitUnreadMessages } from '@/utils/badge' @@ -19,13 +19,13 @@ globalTheme.name.value = themeValue === 'auto' ? autoTheme : themeValue const localeValue = getBrowserLocale() setI18nLanguage(localeValue as SupportedLocale) -// 显示状态 -const show = ref(false) - // 检查是否登录 const authStore = useAuthStore() const isLogin = computed(() => authStore.token) +// 全局设置store +const globalSettingsStore = useGlobalSettingsStore() + // 生成背景图片key const loginStateKey = computed(() => (isLogin.value ? 'logged-in' : 'logged-out')) @@ -130,9 +130,7 @@ function animateAndRemoveLoader() { removeEl('#loading-bg') // 将background属性从html的style中移除 document.documentElement.style.removeProperty('background') - // 显示页面 - show.value = true - }, 500) // 与CSS动画持续时间匹配 + }, 500) } } @@ -155,6 +153,9 @@ async function loadBackgroundImages(retryCount = 0) { } onMounted(async () => { + // 初始化全局设置 + await globalSettingsStore.initialize() + // 配置 ApexCharts configureApexCharts() @@ -172,11 +173,8 @@ onMounted(async () => { }, ) - // 默认隐藏页面 - show.value = false - // 加载背景图片 - loadBackgroundImages() + await loadBackgroundImages() // 移除加载动画 ensureRenderComplete(() => { @@ -213,7 +211,7 @@ onUnmounted(() => {
- + diff --git a/src/components/FileBrowser.vue b/src/components/FileBrowser.vue index 272ec4e4..62d67cdd 100644 --- a/src/components/FileBrowser.vue +++ b/src/components/FileBrowser.vue @@ -5,6 +5,7 @@ import FileNavigator from './filebrowser/FileNavigator.vue' import type { EndPoints, FileItem, StorageConf } from '@/api/types' import { useDisplay } from 'vuetify' import { storageIconDict } from '@/api/constants' +import { usePWA } from '@/composables/usePWA' // 输入参数 const props = defineProps({ @@ -33,7 +34,8 @@ const emit = defineEmits(['pathchanged']) const display = useDisplay() // APP -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() const fileIcons = { // 压缩包 diff --git a/src/components/cards/MediaCard.vue b/src/components/cards/MediaCard.vue index 65a0c130..1dfa72cb 100644 --- a/src/components/cards/MediaCard.vue +++ b/src/components/cards/MediaCard.vue @@ -9,7 +9,7 @@ import { formatSeason, formatRating } from '@/@core/utils/formatters' import { doneNProgress, startNProgress } from '@/api/nprogress' import type { MediaInfo, Subscribe, MediaSeason, Site } from '@/api/types' import router from '@/router' -import { useUserStore } from '@/stores' +import { useUserStore, useGlobalSettingsStore } from '@/stores' import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue' import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue' import SubscribeSeasonDialog from '../dialog/SubscribeSeasonDialog.vue' @@ -28,7 +28,9 @@ const props = defineProps({ }) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 用户 Store const userStore = useUserStore() diff --git a/src/components/cards/PersonCard.vue b/src/components/cards/PersonCard.vue index 8c51ab72..1e1bb607 100644 --- a/src/components/cards/PersonCard.vue +++ b/src/components/cards/PersonCard.vue @@ -2,6 +2,7 @@ import personIcon from '@images/misc/person-icon.png' import type { Person } from '@/api/types' import router from '@/router' +import { useGlobalSettingsStore } from '@/stores' const personProps = defineProps({ person: Object as PropType, @@ -10,7 +11,9 @@ const personProps = defineProps({ }) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 当前人物 const personInfo = ref(personProps.person) diff --git a/src/components/cards/SubscribeCard.vue b/src/components/cards/SubscribeCard.vue index 11741ada..21789563 100644 --- a/src/components/cards/SubscribeCard.vue +++ b/src/components/cards/SubscribeCard.vue @@ -10,6 +10,7 @@ import type { Subscribe } from '@/api/types' import router from '@/router' import { useI18n } from 'vue-i18n' import { useDisplay } from 'vuetify' +import { useGlobalSettingsStore } from '@/stores' // 显示器宽度 const display = useDisplay() @@ -23,7 +24,9 @@ const props = defineProps({ }) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 定义触发的自定义事件 const emit = defineEmits(['remove', 'save']) diff --git a/src/components/cards/SubscribeShareCard.vue b/src/components/cards/SubscribeShareCard.vue index c3d6538a..023b5dbd 100644 --- a/src/components/cards/SubscribeShareCard.vue +++ b/src/components/cards/SubscribeShareCard.vue @@ -4,6 +4,7 @@ import type { SubscribeShare } from '@/api/types' import router from '@/router' import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue' import ForkSubscribeDialog from '../dialog/ForkSubscribeDialog.vue' +import { useGlobalSettingsStore } from '@/stores' // 输入参数 const props = defineProps({ @@ -14,7 +15,9 @@ const props = defineProps({ const emit = defineEmits(['delete']) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 图片是否加载完成 const imageLoaded = ref(false) diff --git a/src/components/dialog/ForkSubscribeDialog.vue b/src/components/dialog/ForkSubscribeDialog.vue index 35cd0c60..23045580 100644 --- a/src/components/dialog/ForkSubscribeDialog.vue +++ b/src/components/dialog/ForkSubscribeDialog.vue @@ -6,6 +6,7 @@ import router from '@/router' import { useToast } from 'vue-toastification' import { VBtn } from 'vuetify/lib/components/index.mjs' import { useI18n } from 'vue-i18n' +import { useGlobalSettingsStore } from '@/stores' // 国际化 const { t } = useI18n() @@ -19,7 +20,9 @@ const props = defineProps({ const emit = defineEmits(['fork', 'delete', 'close']) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 提示框 const $toast = useToast() diff --git a/src/components/dialog/PluginDataDialog.vue b/src/components/dialog/PluginDataDialog.vue index 19b5dea7..5e19a61a 100644 --- a/src/components/dialog/PluginDataDialog.vue +++ b/src/components/dialog/PluginDataDialog.vue @@ -4,6 +4,7 @@ import type { Plugin } from '@/api/types' import PageRender from '@/components/render/PageRender.vue' import api from '@/api' import { loadRemoteComponent } from '@/utils/federationLoader' +import { usePWA } from '@/composables/usePWA' // 输入参数 const props = defineProps({ @@ -22,7 +23,8 @@ const emit = defineEmits(['close', 'save', 'switch']) // 显示器宽度 const display = useDisplay() // APP -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() // 是否刷新 const isRefreshed = ref(false) diff --git a/src/components/dialog/ReorganizeDialog.vue b/src/components/dialog/ReorganizeDialog.vue index 2da58d44..71754b5d 100644 --- a/src/components/dialog/ReorganizeDialog.vue +++ b/src/components/dialog/ReorganizeDialog.vue @@ -8,6 +8,7 @@ import { useDisplay } from 'vuetify' import ProgressDialog from './ProgressDialog.vue' import { FileItem, StorageConf, TransferDirectoryConf, TransferForm } from '@/api/types' import { useI18n } from 'vue-i18n' +import { useGlobalSettingsStore } from '@/stores' // 国际化 const { t } = useI18n() @@ -24,10 +25,12 @@ const props = defineProps({ }) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 当前识别类型 -const mediaSource = ref(globalSettings.data?.RECOGNIZE_SOURCE || 'themoviedb') +const mediaSource = ref(globalSettings.RECOGNIZE_SOURCE || 'themoviedb') // 定义事件 const emit = defineEmits(['done', 'close']) diff --git a/src/components/dialog/SubscribeSeasonDialog.vue b/src/components/dialog/SubscribeSeasonDialog.vue index 12b0df79..8f24d2e8 100644 --- a/src/components/dialog/SubscribeSeasonDialog.vue +++ b/src/components/dialog/SubscribeSeasonDialog.vue @@ -4,6 +4,7 @@ import { MediaInfo, MediaSeason, NotExistMediaInfo } from '@/api/types' import { PropType } from 'vue' import NoDataFound from '@/components/NoDataFound.vue' import { useI18n } from 'vue-i18n' +import { useGlobalSettingsStore } from '@/stores' // 国际化 const { t } = useI18n() @@ -17,7 +18,9 @@ const props = defineProps({ }) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 季详情 const seasonInfos = ref([]) diff --git a/src/composables/usePWA.ts b/src/composables/usePWA.ts new file mode 100644 index 00000000..690599e0 --- /dev/null +++ b/src/composables/usePWA.ts @@ -0,0 +1,57 @@ +import { ref, computed, onMounted } from 'vue' +import { useDisplay } from 'vuetify' +import { isPWA } from '@/@core/utils/navigator' + +// 全局PWA状态,确保只初始化一次 +const globalPwaMode = ref(null) +const globalLoading = ref(false) +let initPromise: Promise | null = null + +// 全局初始化函数 +async function initializePWAGlobally() { + if (initPromise) return initPromise + + if (globalPwaMode.value !== null || globalLoading.value) return Promise.resolve() + + initPromise = new Promise(async (resolve, reject) => { + globalLoading.value = true + try { + globalPwaMode.value = await isPWA() + resolve() + } catch (error) { + console.error('Failed to detect PWA mode', error) + globalPwaMode.value = false + reject(error) + } finally { + globalLoading.value = false + } + }) + + return initPromise +} + +export function usePWA() { + const display = useDisplay() + + const appMode = computed(() => { + return globalPwaMode.value && display.mdAndDown.value + }) + + // 自动初始化PWA检测 + onMounted(() => { + initializePWAGlobally().catch(console.error) + }) + + // 如果是在服务端或首次调用,立即开始初始化 + if (typeof window !== 'undefined' && globalPwaMode.value === null && !globalLoading.value) { + initializePWAGlobally().catch(console.error) + } + + return { + pwaMode: globalPwaMode, + appMode, + loading: globalLoading, + // 保留手动初始化方法以防需要 + initializePWA: initializePWAGlobally, + } +} diff --git a/src/composables/usePullDownGesture.ts b/src/composables/usePullDownGesture.ts index 7438536a..ecaf5c1f 100644 --- a/src/composables/usePullDownGesture.ts +++ b/src/composables/usePullDownGesture.ts @@ -1,6 +1,7 @@ -import { ref, computed, onMounted, onBeforeUnmount, inject, readonly } from 'vue' +import { ref, computed, onMounted, onBeforeUnmount, readonly, watch } from 'vue' import { useDisplay } from 'vuetify' import { useRoute } from 'vue-router' +import { usePWA } from './usePWA' // 下拉手势配置类型 export interface PullDownConfig { @@ -37,8 +38,7 @@ const DEFAULT_CONFIG: PullDownConfig = { export function usePullDownGesture(options: PullDownOptions = {}) { const display = useDisplay() - const route = useRoute() - const appMode = inject('pwaMode') + const { appMode } = usePWA() // 合并配置 const config = { ...DEFAULT_CONFIG, ...options.config } @@ -126,7 +126,7 @@ export function usePullDownGesture(options: PullDownOptions = {}) { // 事件处理函数 const handleTouchStart = (event: TouchEvent) => { - if (!appMode || !display.mdAndDown.value || !options.enabled) return + if (!appMode.value || !display.mdAndDown.value || !options.enabled) return // 检查是否可以使用下拉手势 if (options.canUsePullGesture && !options.canUsePullGesture()) return @@ -149,7 +149,7 @@ export function usePullDownGesture(options: PullDownOptions = {}) { } const handleTouchMove = (event: TouchEvent) => { - if (!appMode || !display.mdAndDown.value || !options.enabled) return + if (!appMode.value || !display.mdAndDown.value || !options.enabled) return // 检查是否可以使用下拉手势 if (options.canUsePullGesture && !options.canUsePullGesture()) return @@ -192,7 +192,7 @@ export function usePullDownGesture(options: PullDownOptions = {}) { } const handleTouchEnd = () => { - if (!appMode || !display.mdAndDown.value || !options.enabled) return + if (!appMode.value || !display.mdAndDown.value || !options.enabled) return // 检查是否可以使用下拉手势 if (options.canUsePullGesture && !options.canUsePullGesture()) return @@ -217,20 +217,49 @@ export function usePullDownGesture(options: PullDownOptions = {}) { } // 生命周期管理 - onMounted(() => { - if (appMode && display.mdAndDown.value) { + let eventsAdded = false + + const addEventListeners = () => { + if (!eventsAdded && appMode.value && display.mdAndDown.value) { document.addEventListener('touchstart', handleTouchStart, { passive: false }) document.addEventListener('touchmove', handleTouchMove, { passive: false }) document.addEventListener('touchend', handleTouchEnd, { passive: true }) + eventsAdded = true + } + } + + const removeEventListeners = () => { + if (eventsAdded) { + document.removeEventListener('touchstart', handleTouchStart) + document.removeEventListener('touchmove', handleTouchMove) + document.removeEventListener('touchend', handleTouchEnd) + eventsAdded = false + } + } + + // PWA状态确定后,一次性决定是否添加事件监听器 + onMounted(() => { + // 如果PWA已经检测完成,直接添加事件监听器 + if (appMode.value !== null) { + addEventListeners() + } else { + // 等待PWA检测完成(从null变为boolean) + const stopWatcher = watch( + appMode, + newValue => { + if (newValue !== null) { + addEventListeners() + // PWA状态确定后停止监听 + stopWatcher() + } + }, + { immediate: true }, + ) } }) onBeforeUnmount(() => { - if (appMode && display.mdAndDown.value) { - document.removeEventListener('touchstart', handleTouchStart) - document.removeEventListener('touchmove', handleTouchMove) - document.removeEventListener('touchend', handleTouchEnd) - } + removeEventListeners() }) return { diff --git a/src/layouts/components/DefaultLayout.vue b/src/layouts/components/DefaultLayout.vue index a3cb3df2..0dea46b5 100644 --- a/src/layouts/components/DefaultLayout.vue +++ b/src/layouts/components/DefaultLayout.vue @@ -18,9 +18,11 @@ import { filterMenusByPermission } from '@/utils/permission' import { onUnreadMessage } from '@/utils/badge' import { usePullDownGesture } from '@/composables/usePullDownGesture' import { useScrollLockWithWatch } from '@/composables/useScrollLock' +import { usePWA } from '@/composables/usePWA' const display = useDisplay() -const appMode = inject('pwaMode') +// PWA模式检测 +const { appMode } = usePWA() const { t } = useI18n() const route = useRoute() diff --git a/src/layouts/components/Footer.vue b/src/layouts/components/Footer.vue index 2f612a18..9836d1c1 100644 --- a/src/layouts/components/Footer.vue +++ b/src/layouts/components/Footer.vue @@ -5,9 +5,11 @@ import { NavMenu } from '@/@layouts/types' import { useI18n } from 'vue-i18n' import { useUserStore } from '@/stores' import { filterMenusByPermission } from '@/utils/permission' +import { usePWA } from '@/composables/usePWA' const display = useDisplay() -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() const { t, locale } = useI18n() // 判断当前是否为英文环境 diff --git a/src/layouts/components/WorkflowSidebar.vue b/src/layouts/components/WorkflowSidebar.vue index f8656eca..39b1538a 100644 --- a/src/layouts/components/WorkflowSidebar.vue +++ b/src/layouts/components/WorkflowSidebar.vue @@ -4,6 +4,7 @@ import useDragAndDrop from '@core/utils/workflow' import { useDisplay } from 'vuetify' import { useI18n } from 'vue-i18n' import { actionStepDict } from '@/api/constants' +import { usePWA } from '@/composables/usePWA' interface ActionItem { name: string @@ -13,7 +14,8 @@ interface ActionItem { const display = useDisplay() // APP -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() const { t } = useI18n() const { onDragStart } = useDragAndDrop() diff --git a/src/main.ts b/src/main.ts index 05018750..ee874039 100644 --- a/src/main.ts +++ b/src/main.ts @@ -18,9 +18,7 @@ import { PerfectScrollbarPlugin } from 'vue3-perfect-scrollbar' import { CronVuetify } from '@vue-js-cron/vuetify' // 4. 工具函数和其他辅助模块 -import { isPWA } from './@core/utils/navigator' import { loadRemoteComponents } from './utils/federationLoader' -import { fetchGlobalSettings } from './utils/globalSetting' // 5. 其他插件和功能模块 import Toast from 'vue-toastification' @@ -51,59 +49,43 @@ const app = createApp(App) // 注册pinia app.use(pinia) -// 初始化配置 -async function initializeApp() { - try { - // 是否为PWA - const pwaMode = await isPWA() - app.provide('pwaMode', pwaMode) - - // 全局设置 - const globalSettings = await fetchGlobalSettings() - app.provide('globalSettings', globalSettings) - - // 加载并注册远程联邦组件 - await loadRemoteComponents() - } catch (error) { - console.error('Failed to initialize app', error) - } -} - -// 注册全局组件 -initializeApp().then(() => { - // 1. 注册 UI 框架 - app.use(vuetify) - - // 2. 注册路由 - app.use(router) - - // 3. 注册全局组件 - app - .component('VAceEditor', VAceEditor) - .component('VApexChart', VueApexCharts) - .component('VCronVuetify', CronVuetify) - .component('VDialogCloseBtn', DialogCloseBtn) - .component('VScrollToTopBtn', ScrollToTopBtn) - .component('VMediaCard', MediaCard) - .component('VPosterCard', PosterCard) - .component('VBackdropCard', BackdropCard) - .component('VPersonCard', PersonCard) - .component('VMediaInfoCard', MediaInfoCard) - .component('VTorrentCard', TorrentCard) - .component('VMediaIdSelector', MediaIdSelector) - .component('VCronField', CronField) - .component('VPathField', PathField) - .component('VHeaderTab', HeaderTab) - .component('VPageContentTitle', PageContentTitle) - - // 5. 注册其他插件 - app - .use(PerfectScrollbarPlugin) - .use(Toast, { - position: 'bottom-right', - hideProgressBar: true, - }) - .use(ConfirmDialog) - .use(i18n) - .mount('#app') +// 异步加载远程组件(不阻塞启动) +loadRemoteComponents().catch(error => { + console.error('Failed to load remote components', error) }) + +// 1. 注册 UI 框架 +app.use(vuetify) + +// 2. 注册路由 +app.use(router) + +// 3. 注册全局组件 +app + .component('VAceEditor', VAceEditor) + .component('VApexChart', VueApexCharts) + .component('VCronVuetify', CronVuetify) + .component('VDialogCloseBtn', DialogCloseBtn) + .component('VScrollToTopBtn', ScrollToTopBtn) + .component('VMediaCard', MediaCard) + .component('VPosterCard', PosterCard) + .component('VBackdropCard', BackdropCard) + .component('VPersonCard', PersonCard) + .component('VMediaInfoCard', MediaInfoCard) + .component('VTorrentCard', TorrentCard) + .component('VMediaIdSelector', MediaIdSelector) + .component('VCronField', CronField) + .component('VPathField', PathField) + .component('VHeaderTab', HeaderTab) + .component('VPageContentTitle', PageContentTitle) + +// 4. 注册其他插件 +app + .use(PerfectScrollbarPlugin) + .use(Toast, { + position: 'bottom-right', + hideProgressBar: true, + }) + .use(ConfirmDialog) + .use(i18n) + .mount('#app') diff --git a/src/pages/dashboard.vue b/src/pages/dashboard.vue index 6da1d53d..2eb8bebd 100644 --- a/src/pages/dashboard.vue +++ b/src/pages/dashboard.vue @@ -9,13 +9,15 @@ import { useDisplay } from 'vuetify' import { useDynamicButton } from '@/composables/useDynamicButton' import { useI18n } from 'vue-i18n' import { VCardActions } from 'vuetify/components' +import { usePWA } from '@/composables/usePWA' // 国际化 const { t } = useI18n() // APP const display = useDisplay() -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() // 从用户 Store 中获取superuser信息 const superUser = useUserStore().superUser diff --git a/src/stores/globalSettings.ts b/src/stores/globalSettings.ts new file mode 100644 index 00000000..a1b2be17 --- /dev/null +++ b/src/stores/globalSettings.ts @@ -0,0 +1,51 @@ +import { defineStore } from 'pinia' +import type { globalSettingsState } from '@/stores/types' +import { fetchGlobalSettings } from '@/utils/globalSetting' + +export const useGlobalSettingsStore = defineStore('globalSettings', { + state: (): globalSettingsState => ({ + data: {}, + initialized: false, + loading: false, + }), + + actions: { + async initialize() { + if (this.initialized || this.loading) return + + this.loading = true + try { + const result = await fetchGlobalSettings() + this.data = result || {} + this.initialized = true + } catch (error) { + console.error('Failed to initialize global settings', error) + } finally { + this.loading = false + } + }, + + setData(data: { [key: string]: any }) { + this.data = data + this.initialized = true + }, + + get(key: string) { + return this.data[key] + }, + + reset() { + this.data = {} + this.initialized = false + this.loading = false + }, + }, + + getters: { + isInitialized: state => state.initialized, + isLoading: state => state.loading, + getData: state => state.data, + // 直接返回data对象,避免使用.value + globalSettings: state => state.data, + }, +}) diff --git a/src/stores/index.ts b/src/stores/index.ts index f904e77b..89aa7421 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -12,5 +12,6 @@ export default pinia // 所有的 store import { useAuthStore } from './auth' import { useUserStore } from './user' +import { useGlobalSettingsStore } from './globalSettings' -export { useAuthStore, useUserStore } +export { useAuthStore, useUserStore, useGlobalSettingsStore } diff --git a/src/stores/types.ts b/src/stores/types.ts index 502ef9b0..5cccbe34 100644 --- a/src/stores/types.ts +++ b/src/stores/types.ts @@ -21,3 +21,12 @@ export interface userState { // 权限 permissions: { [key: string]: any } } + +export interface globalSettingsState { + // 全局设置数据 + data: { [key: string]: any } + // 是否已初始化 + initialized: boolean + // 是否正在加载 + loading: boolean +} diff --git a/src/views/discover/MediaDetailView.vue b/src/views/discover/MediaDetailView.vue index 9dc89c6c..81aa2c31 100644 --- a/src/views/discover/MediaDetailView.vue +++ b/src/views/discover/MediaDetailView.vue @@ -15,6 +15,7 @@ import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue' import { useTheme } from 'vuetify' import { useI18n } from 'vue-i18n' import { hasPermission } from '@/utils/permission' +import { useGlobalSettingsStore } from '@/stores' // 国际化 const { t } = useI18n() @@ -28,7 +29,9 @@ const mediaProps = defineProps({ }) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 用户 Store const userStore = useUserStore() diff --git a/src/views/discover/PersonDetailView.vue b/src/views/discover/PersonDetailView.vue index 6ce50283..3f3c1096 100644 --- a/src/views/discover/PersonDetailView.vue +++ b/src/views/discover/PersonDetailView.vue @@ -5,6 +5,7 @@ import personIcon from '@images/misc/person.png' import type { Person } from '@/api/types' import NoDataFound from '@/components/NoDataFound.vue' import { useI18n } from 'vue-i18n' +import { useGlobalSettingsStore } from '@/stores' // 国际化 const { t } = useI18n() @@ -17,7 +18,9 @@ const personProps = defineProps({ }) // 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 媒体详情 const personDetail = ref({} as Person) diff --git a/src/views/plugin/PluginCardListView.vue b/src/views/plugin/PluginCardListView.vue index 7359fd3c..df312cac 100644 --- a/src/views/plugin/PluginCardListView.vue +++ b/src/views/plugin/PluginCardListView.vue @@ -13,6 +13,7 @@ import PluginMarketSettingDialog from '@/components/dialog/PluginMarketSettingDi import { useDynamicButton } from '@/composables/useDynamicButton' import { useI18n } from 'vue-i18n' import PluginMixedSortCard from '@/components/cards/PluginMixedSortCard.vue' +import { usePWA } from '@/composables/usePWA' // 国际化 const { t } = useI18n() @@ -23,7 +24,8 @@ const route = useRoute() const display = useDisplay() // APP -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() // 当前标签 const activeTab = ref('installed') diff --git a/src/views/reorganize/TransferHistoryView.vue b/src/views/reorganize/TransferHistoryView.vue index 5ef899d8..738f8c8d 100644 --- a/src/views/reorganize/TransferHistoryView.vue +++ b/src/views/reorganize/TransferHistoryView.vue @@ -11,13 +11,15 @@ import router from '@/router' import { useDisplay } from 'vuetify' import { formatFileSize } from '@/@core/utils/formatters' import { useI18n } from 'vue-i18n' +import { usePWA } from '@/composables/usePWA' // i18n const { t } = useI18n() // APP const display = useDisplay() -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() // 提示框 const $toast = useToast() diff --git a/src/views/setting/AccountSettingCache.vue b/src/views/setting/AccountSettingCache.vue index a5b3bb9c..9bcc2895 100644 --- a/src/views/setting/AccountSettingCache.vue +++ b/src/views/setting/AccountSettingCache.vue @@ -3,18 +3,21 @@ import { useToast } from 'vue-toastification' import api from '@/api' import type { TorrentCacheData, TorrentCacheItem } from '@/api/types' import { useI18n } from 'vue-i18n' -import { useDisplay } from 'vuetify' import { formatFileSize, formatDateDifference } from '@core/utils/formatters' import { useConfirm } from '@/composables/useConfirm' +import { useGlobalSettingsStore } from '@/stores' +import { usePWA } from '@/composables/usePWA' // 国际化 const { t } = useI18n() -const display = useDisplay() -const appMode = inject('pwaMode') && display.mdAndDown.value -// 从 provide 中获取全局设置 -const globalSettings: any = inject('globalSettings') +// PWA模式检测 +const { appMode } = usePWA() + +// 全局设置 +const globalSettingsStore = useGlobalSettingsStore() +const globalSettings = globalSettingsStore.globalSettings // 确认框 const createConfirm = useConfirm() diff --git a/src/views/site/SiteCardListView.vue b/src/views/site/SiteCardListView.vue index 842e279c..0a12aa8e 100644 --- a/src/views/site/SiteCardListView.vue +++ b/src/views/site/SiteCardListView.vue @@ -8,13 +8,15 @@ import SiteAddEditDialog from '@/components/dialog/SiteAddEditDialog.vue' import { useDisplay } from 'vuetify' import { useDynamicButton } from '@/composables/useDynamicButton' import { useI18n } from 'vue-i18n' +import { usePWA } from '@/composables/usePWA' // 国际化 const { t } = useI18n() // APP const display = useDisplay() -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() // 站点列表 const siteList = ref([]) diff --git a/src/views/subscribe/SubscribeListView.vue b/src/views/subscribe/SubscribeListView.vue index 63079392..ea369770 100644 --- a/src/views/subscribe/SubscribeListView.vue +++ b/src/views/subscribe/SubscribeListView.vue @@ -9,13 +9,15 @@ import { useUserStore } from '@/stores' import { useDisplay } from 'vuetify' import { useDynamicButton } from '@/composables/useDynamicButton' import { useI18n } from 'vue-i18n' +import { usePWA } from '@/composables/usePWA' // 国际化 const { t } = useI18n() // APP const display = useDisplay() -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() // 用户 Store const userStore = useUserStore() diff --git a/src/views/user/UserListView.vue b/src/views/user/UserListView.vue index b2bc9f1a..ea805d63 100644 --- a/src/views/user/UserListView.vue +++ b/src/views/user/UserListView.vue @@ -7,13 +7,15 @@ import UserAddEditDialog from '@/components/dialog/UserAddEditDialog.vue' import { useDisplay } from 'vuetify' import { useDynamicButton } from '@/composables/useDynamicButton' import { useI18n } from 'vue-i18n' +import { usePWA } from '@/composables/usePWA' // 国际化 const { t } = useI18n() // APP const display = useDisplay() -const appMode = inject('pwaMode') && display.mdAndDown.value +// PWA模式检测 +const { appMode } = usePWA() // 是否刷新过 const isRefreshed = ref(false) diff --git a/src/views/workflow/WorkflowListView.vue b/src/views/workflow/WorkflowListView.vue index 93a83768..b7a9e222 100644 --- a/src/views/workflow/WorkflowListView.vue +++ b/src/views/workflow/WorkflowListView.vue @@ -1,19 +1,19 @@