Bläddra i källkod

实现可以根据系统中设置的主题而更改项目主题

zhouyuhao 11 månader sedan
förälder
incheckning
26c921c572

+ 3 - 21
src/components/ContainerStatus/src/ContainerStatus.vue

@@ -1,32 +1,14 @@
 <script setup lang="ts">
-import emptyImage from './image/no_data.png'
 import { formatTimezone } from '@/utils/tools'
 import { useThemeStore } from '@/stores/modules/theme'
 import lightPng from './image/no_data.png'
 import darkPng from './image/no_data_dark.png'
 
-const emptyImg = ref(lightPng)
-
 const themeStore = useThemeStore()
-// 判断当前系统主题模式
-onMounted(() => {
-  watch(
-    () => themeStore.theme,
-    (newVal) => {
-      console.log(newVal, 'value')
-      if (newVal === 'dark') {
-        emptyImg.value = darkPng
-      } else {
-        emptyImg.value = lightPng
-      }
-    },
-    {
-      immediate: true,
-      deep: true
-    }
-  )
-})
 
+const emptyImg = computed(() => {
+  return themeStore.theme === 'dark' ? darkPng : lightPng
+})
 const props = defineProps({
   data: Object
 })

+ 2 - 17
src/components/VEmpty/src/VEmpty.vue

@@ -3,25 +3,10 @@ import lightPng from './images/default_image.png'
 import darkPng from './images/default_dark_image.png'
 import { useThemeStore } from '@/stores/modules/theme'
 
-const emptyImg = ref(lightPng)
-
 const themeStore = useThemeStore()
 // 判断当前系统主题模式
-onMounted(() => {
-  watch(
-    () => themeStore.theme,
-    (newVal) => {
-      if (newVal === 'dark') {
-        emptyImg.value = darkPng
-      } else {
-        emptyImg.value = lightPng
-      }
-    },
-    {
-      immediate: true,
-      deep: true
-    }
-  )
+const emptyImg = computed(() => {
+  return themeStore.theme === 'dark' ? darkPng : lightPng
 })
 </script>
 

+ 39 - 27
src/main.ts

@@ -19,9 +19,31 @@ import { createPinia } from 'pinia'
 
 import App from './App.vue'
 import router from './router'
+import { useThemeStore } from '@/stores/modules/theme'
 
 const app = createApp(App)
 
+for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+  app.component(key, component)
+}
+// 让VxeTable支持导出Excel
+VXETable.use(VXETablePluginExportXLSX, {
+  ExcelJS
+})
+VXETable.setI18n('en-US', enUS)
+VXETable.setLanguage('en-US')
+
+app.use(createPinia())
+app.use(VXETable)
+app.use(VxeUI)
+app.use(router)
+app.use(Antd)
+
+// 注册全局指令
+app.directive('vloading', VLoading)
+
+const themeStore = useThemeStore()
+
 // 动态加载暗黑主题
 async function loadDarkTheme() {
   await import('element-plus/theme-chalk/dark/css-vars.css') // 动态导入暗黑主题
@@ -33,15 +55,24 @@ function unloadDarkTheme() {
     darkThemeStylesheet.remove()
   }
 }
-// 根据用户偏好或系统设置决定是否加载暗黑主题 (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) ||
-if (localStorage.getItem('theme') === 'dark') {
-  loadDarkTheme()
-  document.documentElement.classList.add('dark')
+// 用户没有手动切换主题时,根据系统设置自动切换
+if (!themeStore.isManualChange) {
+  // 根据用户偏好或系统设置决定是否添加暗黑模式类名
+  if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+    themeStore.toggleTheme('dark')
+    loadDarkTheme()
+  } else {
+    unloadDarkTheme()
+    themeStore.toggleTheme('light')
+  }
+} else {
+  // 用户手动切换主题时,根据用户设置切换
+  if (themeStore.theme === 'dark') {
+    loadDarkTheme()
+    themeStore.toggleTheme('dark')
+  }
 }
-// 根据用户偏好或系统设置决定是否添加暗黑模式类名
-// if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
-//   document.documentElement.classList.add('dark')
-// }
+
 // 提供一个全局方法来切换主题
 app.config.globalProperties.$toggleDarkMode = () => {
   const html = document.documentElement
@@ -56,23 +87,4 @@ app.config.globalProperties.$toggleDarkMode = () => {
   }
 }
 
-for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
-  app.component(key, component)
-}
-// 让VxeTable支持导出Excel
-VXETable.use(VXETablePluginExportXLSX, {
-  ExcelJS
-})
-VXETable.setI18n('en-US', enUS)
-VXETable.setLanguage('en-US')
-
-app.use(createPinia())
-app.use(VXETable)
-app.use(VxeUI)
-app.use(router)
-app.use(Antd)
-
-// 注册全局指令
-app.directive('vloading', VLoading)
-
 app.mount('#app')

+ 12 - 6
src/stores/modules/theme.ts

@@ -2,24 +2,30 @@ import { defineStore } from 'pinia'
 
 interface ThemeState {
   theme: string
+  isManualChange: boolean
 }
 export const useThemeStore = defineStore('theme', {
   state: (): ThemeState => ({
-    theme: localStorage.getItem('theme') || 'light'
+    theme: localStorage.getItem('theme') || 'light',
+    isManualChange: JSON.parse(localStorage.getItem('isManualChange')) || false
   }),
   actions: {
-    toggleTheme(theme: string) {
+    toggleTheme(theme: string, isManualChange = false) {
+      localStorage.setItem('theme', theme)
+      this.theme = theme
+
       const html = document.documentElement
       if (html.classList.contains('dark') && theme === 'light') {
         unloadDarkTheme()
         html.classList.remove('dark')
-        localStorage.setItem('theme', 'light')
-        this.theme = 'light'
       } else if (!html.classList.contains('dark') && theme === 'dark') {
         loadDarkTheme()
         html.classList.add('dark')
-        localStorage.setItem('theme', 'dark')
-        this.theme = 'dark'
+      }
+      // 主动修改主题后,不再跟随系统设置
+      if (isManualChange) {
+        localStorage.setItem('isManualChange', JSON.stringify(isManualChange))
+        this.isManualChange = isManualChange
       }
     }
   }

+ 1 - 1
src/views/Dashboard/src/components/TopMap.vue

@@ -226,7 +226,7 @@ defineExpose({
 }
 /* 示例:将所有地图图片的颜色反转 */
 .dark-mode img:not(.leaflet-marker-icon) {
-  filter: invert(1) hue-rotate(170deg);
+  filter: invert(1) hue-rotate(230deg) saturate(60%) brightness(60%) opacity(80%);
 }
 // 防止暗黑模式下地图超出容器
 #map {

+ 1 - 1
src/views/Layout/src/components/Header/HeaderView.vue

@@ -18,7 +18,7 @@ const headerSearch = useHeaderSearch()
 const themePopoverRef = ref()
 // 切换系统主题颜色
 const toggleThemeMode = (theme: string) => {
-  themeStore.toggleTheme(theme)
+  themeStore.toggleTheme(theme, true)
 }
 
 const searchValue = ref('')

+ 1 - 19
src/views/Login/src/components/ChangePasswordCard.vue

@@ -7,24 +7,6 @@ const userStore = useUserStore()
 const router = useRouter()
 
 const themeStore = useThemeStore()
-const changePasswordRef = ref()
-// 判断当前系统主题模式
-onMounted(() => {
-  watch(
-    () => themeStore.theme,
-    (newVal) => {
-      if (newVal === 'dark') {
-        changePasswordRef.value.classList.add('dark-bg')
-      } else {
-        changePasswordRef.value.classList.remove('dark-bg')
-      }
-    },
-    {
-      immediate: true,
-      deep: true
-    }
-  )
-})
 
 const route = useRoute()
 
@@ -147,7 +129,7 @@ onUnmounted(() => {
 </script>
 
 <template>
-  <div class="login" ref="changePasswordRef">
+  <div class="login" :class="{ 'dark-bg': themeStore.theme === 'dark' }">
     <el-card class="login-card">
       <div class="title" :class="{ 'is-dark': themeStore.theme === 'dark' }">
         <span class="welcome">Change Password</span>

+ 1 - 20
src/views/Login/src/loginView.vue

@@ -12,25 +12,6 @@ const router = useRouter()
 const route = useRoute()
 const themeStore = useThemeStore()
 
-const loginRef = ref()
-// 判断当前系统主题模式
-onMounted(() => {
-  watch(
-    () => themeStore.theme,
-    (newVal) => {
-      if (newVal === 'dark') {
-        loginRef.value.classList.add('dark-bg')
-      } else {
-        loginRef.value.classList.remove('dark-bg')
-      }
-    },
-    {
-      immediate: true,
-      deep: true
-    }
-  )
-})
-
 // 手动获取url中的参数,直接获取route.query的参数时如果有+号会被转义成空格
 const getQueryParams = (url: string) => {
   const params = url.split('?')[1]
@@ -343,7 +324,7 @@ const firstLoginTipsRef = ref()
 </script>
 
 <template>
-  <div class="login" ref="loginRef">
+  <div class="login" :class="{ 'dark-bg': themeStore.theme === 'dark' }">
     <ScoringSystem class="scoring-system"></ScoringSystem>
     <el-card class="login-card" v-if="status === 'login'">
       <div class="card-title" :class="{ 'is-dark': themeStore.theme === 'dark' }">

+ 1 - 21
src/views/Tracking/src/components/PublicTracking/src/PublicTrackingSearch.vue

@@ -1,30 +1,11 @@
 <script setup lang="ts">
 import { useRouter } from 'vue-router'
 import { useHeaderSearch } from '@/stores/modules/headerSearch'
-import SlideVerify from './components/SlideVerify.vue'
 import CryptoJS from 'crypto-js'
 import dayjs from 'dayjs'
 import { useThemeStore } from '@/stores/modules/theme'
 
 const themeStore = useThemeStore()
-const publicTrackingRef = ref()
-// 判断当前系统主题模式
-onMounted(() => {
-  watch(
-    () => themeStore.theme,
-    (newVal) => {
-      if (newVal === 'dark') {
-        publicTrackingRef.value.classList.add('dark-bg')
-      } else {
-        publicTrackingRef.value.classList.remove('dark-bg')
-      }
-    },
-    {
-      immediate: true,
-      deep: true
-    }
-  )
-})
 
 const router = useRouter()
 
@@ -112,7 +93,7 @@ const encryptPassword = (password) => {
 </script>
 
 <template>
-  <div class="public-tracking-search" ref="publicTrackingRef" v-vloading="loading">
+  <div class="public-tracking-search" v-vloading="loading" :class="{ 'dark-bg': themeStore.theme }">
     <div class="search-info">
       <div class="title">Tracking</div>
       <el-input
@@ -151,7 +132,6 @@ const encryptPassword = (password) => {
         </VEmpty>
       </div>
     </div>
-    <!-- <SlideVerify ref="slideVerifyRef" @verify-success="confirmVerify"></SlideVerify> -->
     <VSliderVerification
       v-if="isShowSliderVerification"
       @close="confirmVerification"

+ 1 - 1
src/views/Tracking/src/components/TrackingDetail/src/components/MapView.vue

@@ -626,7 +626,7 @@ onUnmounted(() => {
 
 /* 示例:将所有地图图片的颜色反转 */
 .dark-mode img:not(.leaflet-marker-icon) {
-  filter: invert(1) hue-rotate(230deg) saturate(60%) brightness(40%) opacity(80%);
+  filter: invert(1) hue-rotate(230deg) saturate(60%) brightness(60%) opacity(80%);
 }
 // 防止暗黑模式下地图超出容器
 .tracking-map {