diff --git a/src/App.vue b/src/App.vue index 014a6428..9758e4cb 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,7 +4,6 @@ import { NConfigProvider, darkTheme } from 'naive-ui'; import type { WatermarkProps } from 'naive-ui'; import { useAppStore } from './store/modules/app'; import { useThemeStore } from './store/modules/theme'; -import { useAuthStore } from './store/modules/auth'; import { naiveDateLocales, naiveLocales } from './locales/naive'; defineOptions({ @@ -13,7 +12,6 @@ defineOptions({ const appStore = useAppStore(); const themeStore = useThemeStore(); -const authStore = useAuthStore(); const naiveDarkTheme = computed(() => (themeStore.darkMode ? darkTheme : undefined)); @@ -26,13 +24,8 @@ const naiveDateLocale = computed(() => { }); const watermarkProps = computed(() => { - const content = - themeStore.watermark.enableUserName && authStore.userInfo.userName - ? authStore.userInfo.userName - : themeStore.watermark.text; - return { - content, + content: themeStore.watermarkContent, cross: true, fullscreen: true, fontSize: 16, diff --git a/src/constants/app.ts b/src/constants/app.ts index ed468c59..0c8ba5ac 100644 --- a/src/constants/app.ts +++ b/src/constants/app.ts @@ -63,3 +63,13 @@ export const resetCacheStrategyRecord: Record import GlobalSettings from './modules/global-settings.vue'; +import WatermarkSettings from './modules/watermark-settings.vue'; defineOptions({ name: 'GeneralSettings' @@ -9,6 +10,7 @@ defineOptions({ diff --git a/src/layouts/modules/theme-drawer/modules/general/modules/global-settings.vue b/src/layouts/modules/theme-drawer/modules/general/modules/global-settings.vue index b47eacf9..15ee3925 100644 --- a/src/layouts/modules/theme-drawer/modules/general/modules/global-settings.vue +++ b/src/layouts/modules/theme-drawer/modules/general/modules/global-settings.vue @@ -11,34 +11,14 @@ const themeStore = useThemeStore(); diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts index c6bd61e4..83b48833 100644 --- a/src/locales/langs/en-us.ts +++ b/src/locales/langs/en-us.ts @@ -158,10 +158,14 @@ const local: App.I18n.Schema = { } }, general: { + title: 'General Settings', watermark: { + title: 'Watermark Settings', visible: 'Watermark Full Screen Visible', - text: 'Watermark Text', - enableUserName: 'Enable User Name Watermark' + text: 'Custom Watermark Text', + enableUserName: 'Enable User Name Watermark', + enableTime: 'Show Current Time', + timeFormat: 'Time Format' }, multilingual: { title: 'Multilingual Settings', diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts index 0c8f451a..47c6e7c0 100644 --- a/src/locales/langs/zh-cn.ts +++ b/src/locales/langs/zh-cn.ts @@ -158,10 +158,14 @@ const local: App.I18n.Schema = { } }, general: { + title: '通用设置', watermark: { + title: '水印设置', visible: '显示全屏水印', - text: '水印文本', - enableUserName: '启用用户名水印' + text: '自定义水印文本', + enableUserName: '启用用户名水印', + enableTime: '显示当前时间', + timeFormat: '时间格式' }, multilingual: { title: '多语言设置', diff --git a/src/store/modules/theme/index.ts b/src/store/modules/theme/index.ts index 23947bb3..f5a7a51d 100644 --- a/src/store/modules/theme/index.ts +++ b/src/store/modules/theme/index.ts @@ -1,10 +1,11 @@ import { computed, effectScope, onScopeDispose, ref, toRefs, watch } from 'vue'; import type { Ref } from 'vue'; -import { useEventListener, usePreferredColorScheme } from '@vueuse/core'; +import { useDateFormat, useEventListener, useNow, usePreferredColorScheme } from '@vueuse/core'; import { defineStore } from 'pinia'; import { getPaletteColorByNumber } from '@sa/color'; import { localStg } from '@/utils/storage'; import { SetupStoreId } from '@/enum'; +import { useAuthStore } from '../auth'; import { addThemeVarsToGlobal, createThemeToken, @@ -18,10 +19,14 @@ import { export const useThemeStore = defineStore(SetupStoreId.Theme, () => { const scope = effectScope(); const osTheme = usePreferredColorScheme(); + const authStore = useAuthStore(); /** Theme settings */ const settings: Ref = ref(initThemeSettings()); + /** Watermark time instance with controls */ + const { now: watermarkTime, pause: pauseWatermarkTime, resume: resumeWatermarkTime } = useNow({ controls: true }); + /** Dark mode */ const darkMode = computed(() => { if (settings.value.themeScheme === 'auto') { @@ -57,6 +62,28 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { */ const settingsJson = computed(() => JSON.stringify(settings.value)); + /** Watermark time date formatter */ + const formattedWatermarkTime = computed(() => { + const { watermark } = settings.value; + const date = useDateFormat(watermarkTime, watermark.timeFormat); + return date.value; + }); + + /** Watermark content */ + const watermarkContent = computed(() => { + const { watermark } = settings.value; + + if (watermark.enableUserName && authStore.userInfo.userName) { + return authStore.userInfo.userName; + } + + if (watermark.enableTime) { + return formattedWatermarkTime.value; + } + + return watermark.text; + }); + /** Reset store */ function resetStore() { const themeStore = useThemeStore(); @@ -153,6 +180,44 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { settings.value.layout.reverseHorizontalMix = reverse; } + /** + * Set watermark enable user name + * + * @param enable Whether to enable user name watermark + */ + function setWatermarkEnableUserName(enable: boolean) { + settings.value.watermark.enableUserName = enable; + + if (enable) { + settings.value.watermark.enableTime = false; + } + } + + /** + * Set watermark enable time + * + * @param enable Whether to enable time watermark + */ + function setWatermarkEnableTime(enable: boolean) { + settings.value.watermark.enableTime = enable; + + if (enable) { + settings.value.watermark.enableUserName = false; + } + } + + /** Only run timer when watermark is visible and time display is enabled */ + function updateWatermarkTimer() { + const { watermark } = settings.value; + const shouldRunTimer = watermark.visible && watermark.enableTime; + + if (shouldRunTimer) { + resumeWatermarkTime(); + } else { + pauseWatermarkTime(); + } + } + /** Cache theme settings */ function cacheThemeSettings() { const isProd = import.meta.env.PROD; @@ -196,6 +261,15 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { }, { immediate: true } ); + + // watch watermark settings to control timer + watch( + () => [settings.value.watermark.visible, settings.value.watermark.enableTime], + () => { + updateWatermarkTimer(); + }, + { immediate: true } + ); }); /** On scope dispose */ @@ -209,6 +283,7 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { themeColors, naiveTheme, settingsJson, + watermarkContent, setGrayscale, setColourWeakness, resetStore, @@ -216,6 +291,8 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { toggleThemeScheme, updateThemeColors, setThemeLayout, - setLayoutReverseHorizontalMix + setLayoutReverseHorizontalMix, + setWatermarkEnableUserName, + setWatermarkEnableTime }; }); diff --git a/src/theme/settings.ts b/src/theme/settings.ts index 0083563f..1d83bd74 100644 --- a/src/theme/settings.ts +++ b/src/theme/settings.ts @@ -59,7 +59,9 @@ export const themeSettings: App.Theme.ThemeSetting = { watermark: { visible: false, text: 'SoybeanAdmin', - enableUserName: false + enableUserName: false, + enableTime: false, + timeFormat: 'YYYY-MM-DD HH:mm' }, tokens: { light: { diff --git a/src/typings/app.d.ts b/src/typings/app.d.ts index 3291a1bc..9c407c7a 100644 --- a/src/typings/app.d.ts +++ b/src/typings/app.d.ts @@ -114,6 +114,10 @@ declare namespace App { text: string; /** Whether to use user name as watermark text */ enableUserName: boolean; + /** Whether to use current time as watermark text */ + enableTime: boolean; + /** Time format for watermark text */ + timeFormat: string; }; /** define some theme settings tokens, will transform to css variables */ tokens: { @@ -420,10 +424,14 @@ declare namespace App { resetCacheStrategy: { title: string } & Record; }; general: { + title: string; watermark: { + title: string; visible: string; text: string; enableUserName: string; + enableTime: string; + timeFormat: string; }; multilingual: { title: string;