Jelajahi Sumber

feat: 暗黑模式,多语言修改

ljc 3 bulan lalu
induk
melakukan
5c66663f7c

+ 0 - 38
public/index.html

@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge">
-  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-  <link href="/css/preloading.css" rel="stylesheet" type="text/css">
-  <title>CWG-管理系统</title>
-
-</head>
-<body>
-<noscript>
-  <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
-    Please enable it to continue.</strong>
-</noscript>
-
-<div id="app">
-  <!-- preloadidng -->
-  <div id="pre" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 100000; ">
-    <div style="background-color: rgba(0, 0, 0, .8); width: 100%; height: 100%;">
-      <div style="position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);">
-        <div class="line-scale">
-          <div></div>
-          <div></div>
-          <div></div>
-          <div></div>
-          <div></div>
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-
-<!-- built files will be auto injected -->
-
-
-</body>
-</html>

+ 1 - 5
src/main.ts

@@ -12,9 +12,7 @@ import '@/styles/element/index.scss'
 import ElementPlus from 'element-plus'
 import ElementPlus from 'element-plus'
 // import 'element-plus/dist/index.css'
 // import 'element-plus/dist/index.css'
 // 引入暗黑模式 element-plus 2.2 内置暗黑模式
 // 引入暗黑模式 element-plus 2.2 内置暗黑模式
-// import 'element-plus/theme-chalk/dark/css-vars.css'
-// 自定义暗黑模式
-// import '@/styles/cwg_common.scss'
+import 'element-plus/theme-chalk/dark/css-vars.css'
 // bootstrap icon
 // bootstrap icon
 import "bootstrap-icons/font/bootstrap-icons.css";
 import "bootstrap-icons/font/bootstrap-icons.css";
 // 引入阿里图标库
 // 引入阿里图标库
@@ -30,8 +28,6 @@ import i18n from './i18n'
 const app = createApp(App)
 const app = createApp(App)
 registerElIcons(app)
 registerElIcons(app)
 
 
-// app.mixin(mixins)
-// app.component('SvgIcon', SvgIcon)
 app.use(vuex)
 app.use(vuex)
 app.use(pinia)
 app.use(pinia)
 app.use(router)
 app.use(router)

+ 2 - 2
src/routers/index.ts

@@ -94,8 +94,8 @@ const router = createRouter({
 })
 })
 
 
 function loggedIn() {
 function loggedIn() {
-  // return true
-  return !!sessionStorage.getItem('user')
+  return true
+  // return !!sessionStorage.getItem('user')
 }
 }
 
 
 router.beforeEach((to, from, next) => {
 router.beforeEach((to, from, next) => {

+ 3 - 0
src/styles/element/elememt-dark.scss

@@ -0,0 +1,3 @@
+html.dark{
+
+}

+ 24 - 0
src/utils/const/langues.ts

@@ -0,0 +1,24 @@
+// 语言配置数据
+export const langList = {
+  en: { name: 'ENGLISH', flag: '/src/assets/images/lang_EN.jpg' },
+  cn: { name: '中文简体', flag: '/src/assets/images/lang_CN.jpg' },
+  zhHant: { name: '中文繁体', flag: '/src/assets/images/lang_CN.jpg' },
+  vn: { name: 'Tiếng Việt', flag: '/src/assets/images/lang_VN.jpg' },
+  de: { name: 'Deutsch', flag: '/src/assets/images/lang_DE.jpg' },
+  es: { name: 'Español', flag: '/src/assets/images/lang_ES.jpg' },
+  id: { name: 'Indonesian', flag: '/src/assets/images/lang_Indonesian.jpg' },
+  ms: { name: 'Melayu', flag: '/src/assets/images/lang_MS.jpg' },
+  th: { name: 'ภาษาไทย', flag: '/src/assets/images/lang_TH.jpg' },
+  ar: { name: 'العربية', flag: '/src/assets/images/lang_AR.jpg' },
+  ko: { name: '한국어', flag: '/src/assets/images/lang_ko.png' },
+  pt: { name: 'Português', flag: '/src/assets/images/lang_PT.png' },
+  fa: { name: 'زبان پارسی', flag: '/src/assets/images/lang_FA.png' },
+  tr: { name: 'Türkçe', flag: '/src/assets/images/lang_TR.png' },
+}
+
+// 语言选项数组(用于v-for)
+export const languageOptions = Object.entries(langList).map(([code, lang]) => ({
+  code,
+  name: lang.name,
+  flag: lang.flag,
+}))

+ 2 - 47
src/views/enter/dashboard/index.vue

@@ -1,50 +1,5 @@
 <template>
 <template>
-  <el-row class="profile">
-    <el-col :sm="4" :md="4" :lg="4" class="info-picture">
-      <img
-        class="profile-picture"
-        src="@/assets/image/dashboard-profile-default.png"
-        alt="profile picture"
-      />
-      <div v-if="role == 1" class="username">{{ user.name || '--' }}</div>
-    </el-col>
-    <el-col :sm="20" :md="20" :lg="20" class="information">
-      <div v-if="role != 1" class="username row">{{ user.name || '--' }}</div>
-      <el-row :gutter="10" class="row">
-        <el-col :sm="10" :md="10">
-          <span>{{ t('Dashboard.Profile.Role') }}</span>
-          <template v-for="(department, index) in departmentOptions" :key="index">
-            <span v-if="user.departmentId == department.value" class="label">
-              {{ t(department.label) }}
-            </span>
-          </template>
-          <span v-if="!user.departmentId" class="label">
-            {{ t('Dashboard.Role.item0') }}
-          </span>
-        </el-col>
-        <el-col :sm="8" :md="8">
-          <span>{{ t('Dashboard.Profile.User') }}</span>
-          <span class="label">{{ user.name || '--' }}</span>
-        </el-col>
-        <el-col v-if="role == 5" :sm="6" :md="6">
-          <span>{{ t('Dashboard.Profile.Location') }}</span>
-          <span class="label">
-            {{ isZhCn ? user.groupName || '--' : user.groupEnName || '--' }}
-          </span>
-        </el-col>
-      </el-row>
-      <el-row :gutter="10" class="row">
-        <el-col :sm="10" :md="10">
-          <span>{{ t('Dashboard.Profile.Email') }}</span>
-          <span class="label">{{ user.email || '--' }}</span>
-        </el-col>
-        <el-col :sm="14" :md="14">
-          <span>{{ t('Dashboard.Profile.LastIP') }}</span>
-          <span class="label">{{ user.lastIp || '--' }}</span>
-        </el-col>
-      </el-row>
-    </el-col>
-  </el-row>
+
 </template>
 </template>
 <script setup lang="ts">
 <script setup lang="ts">
   import { computed, inject, onMounted, ref } from 'vue'
   import { computed, inject, onMounted, ref } from 'vue'
@@ -68,7 +23,7 @@
   const isZhCn = computed(() => store.state.home.isZhCn)
   const isZhCn = computed(() => store.state.home.isZhCn)
   onMounted(async () => {
   onMounted(async () => {
     console.log(user.value)
     console.log(user.value)
-    role.value = user.value.departmentId
+    // role.value = user.value.departmentId
   })
   })
 </script>
 </script>
 
 

+ 141 - 169
src/views/home2/Home.vue

@@ -1,11 +1,11 @@
 <template>
 <template>
-  <el-container id="home" v-loading="loading">
+  <el-container class="home" v-loading="loading">
     <el-aside width="auto">
     <el-aside width="auto">
-      <nav-menu></nav-menu>
+      <!--      <nav-menu></nav-menu>-->
     </el-aside>
     </el-aside>
     <el-container>
     <el-container>
       <el-header>
       <el-header>
-        <el-row :gutter="10">
+        <el-row>
           <el-col :span="2">
           <el-col :span="2">
             <div class="btn-control" @click="ChangeCollapse">
             <div class="btn-control" @click="ChangeCollapse">
               <el-icon v-show="!isCollapse"><Fold /></el-icon>
               <el-icon v-show="!isCollapse"><Fold /></el-icon>
@@ -13,56 +13,43 @@
             </div>
             </div>
           </el-col>
           </el-col>
           <el-col :span="22" class="tool-box">
           <el-col :span="22" class="tool-box">
-            <!--            <el-button-->
-            <!--              v-if="isQAlist"-->
-            <!--              plain-->
-            <!--              round-->
-            <!--              size="small"-->
-            <!--              type="primary"-->
-            <!--              icon="el-icon-chat-line-round"-->
-            <!--              style="margin-right: 20px"-->
-            <!--              @click="openQA"-->
-            <!--            >-->
-            <!--              {{ 'Q&A' }}-->
-            <!--            </el-button>-->
-            <el-dropdown trigger="click" class="language">
-              <span class="el-dropdown-link">
-                <span>{{ langName }}</span
-                ><el-icon><ArrowDown /></el-icon>
-              </span>
-              <template #dropdown>
-                <el-dropdown-menu>
-                  <el-dropdown-item @click="SwitchLanguage('cn')">中文简体</el-dropdown-item>
-                  <el-dropdown-item @click="SwitchLanguage('en')">English</el-dropdown-item>
-                </el-dropdown-menu>
-              </template>
-            </el-dropdown>
-            <el-dropdown v-if="info.roteCode == 'ROLE_SALE'" trigger="click" class="role-switch">
-              <span class="el-dropdown-link">
-                <span>{{ currentRoleName }}</span>
-                <el-icon><ArrowDown /></el-icon>
-              </span>
+            <!--            多语言-->
+            <el-dropdown trigger="click" class="language" @command="chooseLang">
+              <div>
+                <img v-if="currentFlag" :src="currentFlag" alt="flag" class="flag-icon" />
+                <span class="el-dropdown-link">
+                  <span>{{ langList[langName]?.name || langName }}</span>
+                  <el-icon><ArrowDown /></el-icon>
+                </span>
+              </div>
+
               <template #dropdown>
               <template #dropdown>
-                <el-dropdown-menu>
+                <el-dropdown-menu class="language-dropdown">
                   <el-dropdown-item
                   <el-dropdown-item
-                    v-for="item in attachList"
-                    :key="item.id"
-                    :class="{ 'is-active': item.id === currentAttachId }"
-                    @click="switchRole(item)"
+                    v-for="lang in languageOptions"
+                    :key="lang.code"
+                    :command="lang.code"
+                    :class="{ 'is-active': lang.code === langName }"
                   >
                   >
-                    {{ item.name }}
-                    <i v-if="item.id === currentAttachId" class="el-icon-check"></i>
+                    <div class="language-option">
+                      <span>{{ lang.name }}</span>
+                    </div>
                   </el-dropdown-item>
                   </el-dropdown-item>
                 </el-dropdown-menu>
                 </el-dropdown-menu>
               </template>
               </template>
             </el-dropdown>
             </el-dropdown>
+            <!--            暗黑模式-->
+            <div class="opt-dark" @click="changeDark">
+              <i v-show="!themeConfig.isDark" class="bi bi-sun-fill sun-color"></i>
+              <i v-show="themeConfig.isDark" class="bi bi-moon-fill moon-color"></i>
+            </div>
             <el-icon class="crm-cursor" style="font-size: 20px; margin-left: 20px">
             <el-icon class="crm-cursor" style="font-size: 20px; margin-left: 20px">
               <Bell />
               <Bell />
             </el-icon>
             </el-icon>
             <i class="crm-cursor iconquanping iconfont icon" @click="fullScreen"></i>
             <i class="crm-cursor iconquanping iconfont icon" @click="fullScreen"></i>
             <el-dropdown trigger="click" class="username crm-cursor">
             <el-dropdown trigger="click" class="username crm-cursor">
               <span class="el-dropdown-link">
               <span class="el-dropdown-link">
-                <span>{{ user.name || 'UserName' }}</span
+                <span>{{ user?.name || 'UserName' }}</span
                 ><el-icon><ArrowDown /></el-icon>
                 ><el-icon><ArrowDown /></el-icon>
               </span>
               </span>
               <template #dropdown>
               <template #dropdown>
@@ -72,10 +59,6 @@
                       {{ $t('Label.UpdatePwd') }}
                       {{ $t('Label.UpdatePwd') }}
                     </span>
                     </span>
                   </el-dropdown-item>
                   </el-dropdown-item>
-                  <!--                  商户个人信息,商户管理员可以看到,可以修改-->
-                  <el-dropdown-item v-if="isShopManager" @click="goShopInfo">
-                    Info
-                  </el-dropdown-item>
                   <el-dropdown-item @click="beforeLogout"> Logout </el-dropdown-item>
                   <el-dropdown-item @click="beforeLogout"> Logout </el-dropdown-item>
                 </el-dropdown-menu>
                 </el-dropdown-menu>
               </template>
               </template>
@@ -84,21 +67,21 @@
         </el-row>
         </el-row>
       </el-header>
       </el-header>
       <el-main>
       <el-main>
-        <el-row class="tool">
-          <el-col :span="16">
-            <bread-crumb></bread-crumb>
-          </el-col>
-          <el-col :span="8">
-            <span>
-              {{ $t('Home1.Time') }}
-            </span>
-            <span class="crm-cursor" @click="toReload">{{ time }}</span>
-            <el-icon class="crm-cursor el-icon-refresh-right" @click="toReload">
-              <RefreshRight />
-            </el-icon>
-          </el-col>
-        </el-row>
-        <tab-menu></tab-menu>
+<!--        <el-row class="tool">-->
+<!--          <el-col :span="16">-->
+<!--            <bread-crumb></bread-crumb>-->
+<!--          </el-col>-->
+<!--          <el-col :span="8">-->
+<!--            <span>-->
+<!--              {{ $t('Home1.Time') }}-->
+<!--            </span>-->
+<!--            <span class="crm-cursor" @click="toReload">{{ time }}</span>-->
+<!--            <el-icon class="crm-cursor el-icon-refresh-right" @click="toReload">-->
+<!--              <RefreshRight />-->
+<!--            </el-icon>-->
+<!--          </el-col>-->
+<!--        </el-row>-->
+<!--        <tab-menu></tab-menu>-->
         <div class="container">
         <div class="container">
           <router-view />
           <router-view />
         </div>
         </div>
@@ -184,19 +167,25 @@
   import NavMenu from '@/components/NavMenu.vue'
   import NavMenu from '@/components/NavMenu.vue'
   import BreadCrumb from '@/components/BreadCrumb.vue'
   import BreadCrumb from '@/components/BreadCrumb.vue'
   import TabMenu from '@/components/TabMenu.vue'
   import TabMenu from '@/components/TabMenu.vue'
-  // import QaList from './global/QAList'
-  // import QaAdd from './global/QAAdd'
   import Service from '@/service/login'
   import Service from '@/service/login'
   import Config from '@/config/index'
   import Config from '@/config/index'
   import { safeGetUser, safeGetDisplay } from '@/utils/safeJson'
   import { safeGetUser, safeGetDisplay } from '@/utils/safeJson'
   import { filterByShowTrue } from '@/utils/utils'
   import { filterByShowTrue } from '@/utils/utils'
-  import pigeon from '@/lib/pigeon'
+  import { langList, languageOptions } from '@/utils/const/langues'
+  import { useSettingStore } from '@/store/modules/setting'
+
+  // 计算当前国旗图标
+  const currentFlag = computed(() => {
+    const lang = langList[langName.value]
+    return lang ? lang.flag : '/src/assets/images/lang_EN.jpg'
+  })
 
 
   const { Code } = Config
   const { Code } = Config
   const { t, locale } = useI18n()
   const { t, locale } = useI18n()
   // 引入注入的全局
   // 引入注入的全局
   const session = inject('session')
   const session = inject('session')
   const reload = inject('reload')
   const reload = inject('reload')
+  const pigeon = inject('pigeon')
 
 
   // Vue 相关
   // Vue 相关
   const router = useRouter()
   const router = useRouter()
@@ -207,6 +196,7 @@
   const info = ref({})
   const info = ref({})
   const loading = ref(false)
   const loading = ref(false)
   const dialogCheck = ref(false)
   const dialogCheck = ref(false)
+
   const dialogCheck_form = reactive({
   const dialogCheck_form = reactive({
     oldPassword: '',
     oldPassword: '',
     newPassword: '',
     newPassword: '',
@@ -218,22 +208,15 @@
     window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
     window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
   )
   )
 
 
-  const dialogCheckQA = ref(false)
-  const qaType = ref(1)
-  const myId = ref('')
   const type = ref('')
   const type = ref('')
   const isQAlist = ref(false)
   const isQAlist = ref(false)
   const attachList = ref([])
   const attachList = ref([])
   const currentAttachId = ref(null)
   const currentAttachId = ref(null)
 
 
   const dialogCheckFormRef = ref(null)
   const dialogCheckFormRef = ref(null)
-
-  // 语言映射
-  const langs = {
-    cn: '中文简体',
-    en: 'English',
-  }
-
+  const SettingStore = useSettingStore()
+  // 设置信息
+  const themeConfig = computed(() => SettingStore.themeConfig)
   // 计算属性
   // 计算属性
   const user = computed(() => safeGetUser(session))
   const user = computed(() => safeGetUser(session))
   const expire = computed(() => store.state.home.expire)
   const expire = computed(() => store.state.home.expire)
@@ -282,51 +265,23 @@
     session.Set('display', JSON.stringify(display), true)
     session.Set('display', JSON.stringify(display), true)
   }
   }
 
 
-  // QA相关方法
-  const openQA = () => {
-    dialogCheckQA.value = true
-    qaType.value = 1
-  }
-
-  const toNew = (val) => {
-    const link = window.location.href
-    if (link.indexOf('system/qa/add') > -1) {
-      router.push({ path: '/system/qa/list' }).catch((arr) => arr)
-    }
-    dialogCheckQA.value = true
-    myId.value = -1
-    type.value = 'add'
-    qaType.value = val
-  }
-
-  const cancelQa = () => {
-    qaType.value = 1
-  }
-
-  const toUpdate = (id) => {
-    const link = window.location.href
-    if (link.indexOf('system/qa/add') > -1) {
-      router.push({ path: '/system/qa/list' }).catch((arr) => arr)
-    }
-    dialogCheckQA.value = true
-    myId.value = id
-    type.value = 'update'
-    qaType.value = 2
-  }
-
-  const toCheck = (id) => {
-    dialogCheckQA.value = true
-    myId.value = id
-    type.value = 'check'
-    qaType.value = 2
-  }
-
-  const isQAlistGet = () => {
-    const display = safeGetDisplay(session)
-    if (display && display['R-System-QAList-Search'] && display['R-System-QAList-Search'].show) {
-      isQAlist.value = true
-    } else {
-      isQAlist.value = false
+  const chooseLang = async (key) => {
+    console.log(key, langName.value)
+    console.log(2)
+    if (key !== langName.value) {
+      locale.value = key
+      langName.value = key
+      session.Set('lang', key)
+      axios.defaults.headers.common['Language'] = sessionStorage.getItem('lang')
+      setTimeout(() => {
+        // 使用注入的reload方法或刷新页面
+        if (reload) {
+          reload()
+        } else {
+          // 如果没有注入reload方法,可以手动刷新或更新组件
+          window.location.reload()
+        }
+      })
     }
     }
   }
   }
 
 
@@ -429,26 +384,6 @@
     store.commit('SetCollapse', isCollapse.value)
     store.commit('SetCollapse', isCollapse.value)
   }
   }
 
 
-  // 语言切换
-  const SwitchLanguage = (lang) => {
-    if (lang !== session.Get('lang')) {
-      switchLang(lang)
-    }
-  }
-
-  const switchLang = async (lang) => {
-    // 这里需要根据实际情况处理i18n
-    locale.value = lang
-    // 如果是使用 vue-i18n@next,可能需要通过 useI18n() 来处理
-    langName.value = langs[lang]
-    session.Set('lang', lang)
-    store.commit('ChangeLanguage', lang)
-    axios.defaults.headers.common['Language'] = lang
-    setTimeout(() => {
-      // reload()
-    }, 800)
-  }
-
   // 修改密码
   // 修改密码
   const updatePwd = () => {
   const updatePwd = () => {
     console.log('updatePwd')
     console.log('updatePwd')
@@ -490,20 +425,20 @@
   // 角色相关
   // 角色相关
   const getAttachList = async () => {
   const getAttachList = async () => {
     try {
     try {
-      const res = await Service.getUserAttachs({})
-      if (res.code == Code.StatusOK) {
-        attachList.value = res.data || []
-        if (attachList.value.length > 0) {
-          const userData = user.value
-          if (userData && userData.id) {
-            currentAttachId.value = userData.id
-          } else if (!currentAttachId.value) {
-            currentAttachId.value = attachList.value[0].id
-          }
-        }
-      } else {
-        pigeon.MessageError(res.msg)
-      }
+      // const res = await Service.getUserAttachs({})
+      // if (res.code == Code.StatusOK) {
+      //   attachList.value = res.data || []
+      //   if (attachList.value.length > 0) {
+      //     const userData = user.value
+      //     if (userData && userData.id) {
+      //       currentAttachId.value = userData.id
+      //     } else if (!currentAttachId.value) {
+      //       currentAttachId.value = attachList.value[0].id
+      //     }
+      //   }
+      // } else {
+      //   pigeon.MessageError(res.msg)
+      // }
     } catch (error) {
     } catch (error) {
       console.error('获取角色列表失败:', error)
       console.error('获取角色列表失败:', error)
     }
     }
@@ -584,7 +519,7 @@
     const lang = session.Get('lang') || 'cn'
     const lang = session.Get('lang') || 'cn'
     // 这里需要根据实际情况处理i18n
     // 这里需要根据实际情况处理i18n
     locale.value = lang
     locale.value = lang
-    langName.value = langs[lang]
+    langName.value = lang
   }
   }
 
 
   // 响应式布局
   // 响应式布局
@@ -607,6 +542,17 @@
       screenWidth.value = width
       screenWidth.value = width
     }
     }
   }
   }
+  // 切换暗黑模式
+  const changeDark = () => {
+    const body = document.documentElement as HTMLElement
+    console.log(themeConfig.value.isDark)
+    themeConfig.value.isDark = !themeConfig.value.isDark
+    if (themeConfig.value.isDark) {
+      body.setAttribute('class', 'dark')
+    } else {
+      body.setAttribute('class', '')
+    }
+  }
 
 
   // 生命周期
   // 生命周期
   onBeforeMount(() => {
   onBeforeMount(() => {
@@ -629,7 +575,6 @@
     ListenResize()
     ListenResize()
     resize()
     resize()
     getDate()
     getDate()
-    isQAlistGet()
     getAttachList()
     getAttachList()
   })
   })
 
 
@@ -666,14 +611,14 @@
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">
-  #home {
+  .home {
     width: 100%;
     width: 100%;
     height: 100%;
     height: 100%;
 
 
     .el-header {
     .el-header {
       height: 60px;
       height: 60px;
-      background-color: #ffffff;
-      color: #333;
+      background-color: var(--bg-color);
+      color: var(--text-color);
       line-height: 60px;
       line-height: 60px;
 
 
       .btn-control {
       .btn-control {
@@ -700,22 +645,37 @@
           margin-left: 20px;
           margin-left: 20px;
         }
         }
         .language {
         .language {
-          .el-dropdown-link {
-            background-color: rgba(247, 247, 250, 1);
-            border: none;
-            border-radius: 30px;
-            padding: 6px 20px;
+          width: 120px;
+          height: 30px;
+          border-radius: 15px;
+          background-color: #e6ebf3;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          .language-selector {
+            display: flex;
+            align-items: center;
+            cursor: pointer;
+          }
+          .menu {
             cursor: pointer;
             cursor: pointer;
+            color: #fff;
+            display: flex;
+            align-items: center;
+
+            .el-icon {
+              margin-left: 4px;
+            }
           }
           }
         }
         }
-        .role-switch {
+        .opt-dark {
           margin-left: 20px;
           margin-left: 20px;
-          .el-dropdown-link {
-            background-color: rgba(247, 247, 250, 1);
-            border: none;
-            border-radius: 30px;
-            padding: 6px 20px;
-            cursor: pointer;
+          cursor: pointer;
+          .sun-color {
+            color: #feaf37;
+          }
+          .moon-color {
+            color: yellow;
           }
           }
         }
         }
       }
       }
@@ -731,7 +691,7 @@
     .el-main {
     .el-main {
       padding: 15px;
       padding: 15px;
       overflow: hidden;
       overflow: hidden;
-      background-color: #f5f5f5;
+      background-color: var(--el-bg-color);
 
 
       .tool {
       .tool {
         margin-bottom: 15px;
         margin-bottom: 15px;
@@ -753,7 +713,19 @@
     body > .el-container {
     body > .el-container {
       margin-bottom: 40px;
       margin-bottom: 40px;
     }
     }
+    .flag-icon {
+      width: 15px;
+      height: 10px;
+      margin: 0 4px;
+      object-fit: cover;
+    }
   }
   }
+  .dark{
+    .home .el-header .tool-box .language{
+        background-color: #102047;
+      }
+    }
+
 </style>
 </style>
 <style lang="scss">
 <style lang="scss">
   .dialog_header_qa.dialog_header_w.el-dialog {
   .dialog_header_qa.dialog_header_w.el-dialog {

+ 316 - 344
src/views/userless/sigin/User.vue

@@ -64,17 +64,17 @@
           </div>
           </div>
           <div class="des">
           <div class="des">
             <span>
             <span>
-              {{ t('newSignin.item12') }}
-            </span><br />
+              {{ t('newSignin.item12') }} </span
+            ><br />
             <span>
             <span>
-              {{ t('newSignin.item12_1') }}
-            </span><br />
+              {{ t('newSignin.item12_1') }} </span
+            ><br />
             <span>
             <span>
-              {{ t('newSignin.item10') }}
-            </span><br />
+              {{ t('newSignin.item10') }} </span
+            ><br />
             <span>
             <span>
-              {{ t('newSignin.item11') }}
-            </span><br />
+              {{ t('newSignin.item11') }} </span
+            ><br />
             <span>{{ t('newSignin.item13') }}</span>
             <span>{{ t('newSignin.item13') }}</span>
             <a
             <a
               :href="`https://www.${ho}.com/doc/Risk-Disclosures-and-Acknowledgements-2020-08.pdf`"
               :href="`https://www.${ho}.com/doc/Risk-Disclosures-and-Acknowledgements-2020-08.pdf`"
@@ -97,417 +97,389 @@
 </template>
 </template>
 
 
 <script setup>
 <script setup>
-import { ref, computed, onMounted, inject } from 'vue'
-import { useRoute } from 'vue-router'
-import { useI18n } from 'vue-i18n'
-import { ArrowDown } from '@element-plus/icons-vue'
-import axios from 'axios'
-import Loop from './Loop.vue'
-import Service from '@/service/login'
-import Config from '@/config/index'
-import { useStore } from 'vuex'
-
-const { t, locale } = useI18n()
-const route = useRoute()
-const { Code } = Config
-const store = useStore()
-
-// 注入reload方法(如果有)
-const reload = inject('reload')
-const Session = inject('session')
-const pigeon = inject('pigeon')
-
-// 响应式数据
-const ho = ref('')
-const language = ref('')
-
-// 语言配置数据
-const langList = ref({
-  en: { name: 'ENGLISH', flag: '/src/assets/images/lang_EN.jpg' },
-  cn: { name: '中文简体', flag: '/src/assets/images/lang_CN.jpg' },
-  zhHant: { name: '中文繁体', flag: '/src/assets/images/lang_CN.jpg' },
-  vn: { name: 'Tiếng Việt', flag: '/src/assets/images/lang_VN.jpg' },
-  de: { name: 'Deutsch', flag: '/src/assets/images/lang_DE.jpg' },
-  es: { name: 'Español', flag: '/src/assets/images/lang_ES.jpg' },
-  id: { name: 'Indonesian', flag: '/src/assets/images/lang_Indonesian.jpg' },
-  ms: { name: 'Melayu', flag: '/src/assets/images/lang_MS.jpg' },
-  th: { name: 'ภาษาไทย', flag: '/src/assets/images/lang_TH.jpg' },
-  ar: { name: 'العربية', flag: '/src/assets/images/lang_AR.jpg' },
-  ko: { name: '한국어', flag: '/src/assets/images/lang_ko.png' },
-  pt: { name: 'Português', flag: '/src/assets/images/lang_PT.png' },
-  fa: { name: 'زبان پارسی', flag: '/src/assets/images/lang_FA.png' },
-  tr: { name: 'Türkçe', flag: '/src/assets/images/lang_TR.png' },
-})
-
-// 计算当前国旗图标
-const currentFlag = computed(() => {
-  const lang = langList.value[language.value]
-  return lang ? lang.flag : '/src/assets/images/lang_EN.jpg'
-})
-
-// 语言选项数组(用于v-for)
-const languageOptions = computed(() => {
-  return Object.entries(langList.value).map(([code, lang]) => ({
-    code,
-    name: lang.name,
-    flag: lang.flag,
-  }))
-})
-console.log(languageOptions.value)
-
-// 方法
-const chooseLang = async (key) => {
-  if (key !== language.value) {
-    // await switchLanguage(key)
-    locale.value = key
-    language.value = key
-    Session.Set('lang', key)
-    axios.defaults.headers.common['Language'] = sessionStorage.getItem(
-      'lang',
-    )
-    setTimeout(() => {
-      // 使用注入的reload方法或刷新页面
-      if (reload) {
-        reload()
-      } else {
-        // 如果没有注入reload方法,可以手动刷新或更新组件
-        window.location.reload()
-      }
-    })
+  import { ref, computed, onMounted, inject } from 'vue'
+  import { useRoute } from 'vue-router'
+  import { useI18n } from 'vue-i18n'
+  import { ArrowDown } from '@element-plus/icons-vue'
+  import axios from 'axios'
+  import Loop from './Loop.vue'
+  import Service from '@/service/login'
+  import Config from '@/config/index'
+  import { useStore } from 'vuex'
+  import { langList, languageOptions } from '@/utils/const/langues'
+
+  const { t, locale } = useI18n()
+  const route = useRoute()
+  const { Code } = Config
+  const store = useStore()
+
+  // 注入reload方法(如果有)
+  const reload = inject('reload')
+  const Session = inject('session')
+  const pigeon = inject('pigeon')
+
+  // 响应式数据
+  const ho = ref('')
+  const language = ref('')
+
+  // 计算当前国旗图标
+  const currentFlag = computed(() => {
+    const lang = langList[language.value]
+    return lang ? lang.flag : '/src/assets/images/lang_EN.jpg'
+  })
+  console.log(languageOptions)
+
+  // 方法
+  const chooseLang = async (key) => {
+    if (key !== language.value) {
+      // await switchLanguage(key)
+      locale.value = key
+      language.value = key
+      Session.Set('lang', key)
+      axios.defaults.headers.common['Language'] = sessionStorage.getItem('lang')
+      setTimeout(() => {
+        // 使用注入的reload方法或刷新页面
+        if (reload) {
+          reload()
+        } else {
+          // 如果没有注入reload方法,可以手动刷新或更新组件
+          window.location.reload()
+        }
+      })
+    }
   }
   }
-}
-
-const getCountryCode = async () => {
-  try {
-    const res = await Service.CodeById({})
-    if (res.code === Code.StatusOK) {
-      let lang = 'en'
-
-      switch (res.msg) {
-        case 'CN':
-          lang = 'cn'
-          break
-        case 'VN':
-          lang = 'vn'
-          break
-        default:
-          lang = 'en'
-      }
 
 
-      setLanguage(lang)
+  const getCountryCode = async () => {
+    try {
+      const res = await Service.CodeById({})
+      if (res.code === Code.StatusOK) {
+        let lang = 'en'
+
+        switch (res.msg) {
+          case 'CN':
+            lang = 'cn'
+            break
+          case 'VN':
+            lang = 'vn'
+            break
+          default:
+            lang = 'en'
+        }
+
+        setLanguage(lang)
+      }
+    } catch (error) {
+      console.error('获取国家编码失败:', error)
+      setLanguage('en')
     }
     }
-  } catch (error) {
-    console.error('获取国家编码失败:', error)
-    setLanguage('en')
   }
   }
-}
 
 
-const switchLanguage = async (lang) => {
-  try {
-    await Service.switchLanguage({ lang })
-  } catch (error) {
-    console.error('切换语言失败:', error)
+  const switchLanguage = async (lang) => {
+    try {
+      await Service.switchLanguage({ lang })
+    } catch (error) {
+      console.error('切换语言失败:', error)
+    }
   }
   }
-}
 
 
-const setLanguage = (lang) => {
-  locale.value = lang
-  language.value = lang
-  Session.Set('lang', lang)
-  axios.defaults.headers.common['Language'] = sessionStorage.getItem("lang")
+  const setLanguage = (lang) => {
+    locale.value = lang
+    language.value = lang
+    Session.Set('lang', lang)
+    axios.defaults.headers.common['Language'] = sessionStorage.getItem('lang')
 
 
-  if (reload) {
-    reload()
+    if (reload) {
+      reload()
+    }
   }
   }
-}
 
 
-const toHome = () => {
-  // 如果有store,可以这样使用
-  store.commit("isActiveTab", "0")
-}
+  const toHome = () => {
+    // 如果有store,可以这样使用
+    store.commit('isActiveTab', '0')
+  }
 
 
-// 初始化
-onMounted(() => {
-  ho.value = window.location.host.split('.')[1] || ''
+  // 初始化
+  onMounted(() => {
+    ho.value = window.location.host.split('.')[1] || ''
 
 
-  // 处理电子邮件广告参数
-  if (route.query.emailAdvertisement && !sessionStorage.getItem('lang')) {
-    setLanguage('cn')
-  }
+    // 处理电子邮件广告参数
+    if (route.query.emailAdvertisement && !sessionStorage.getItem('lang')) {
+      setLanguage('cn')
+    }
 
 
-  // 从存储中恢复语言设置
-  const savedLang = localStorage.getItem('lang')
-  if (savedLang) {
-    setLanguage(savedLang)
-  } else {
-    language.value = locale.value
-    Session.Set('lang', locale.value)
-    axios.defaults.headers.common['Language'] = sessionStorage.getItem("lang")
-    // getLanguage()
-  }
-})
+    // 从存储中恢复语言设置
+    const savedLang = localStorage.getItem('lang')
+    if (savedLang) {
+      setLanguage(savedLang)
+    } else {
+      language.value = locale.value
+      Session.Set('lang', locale.value)
+      axios.defaults.headers.common['Language'] = sessionStorage.getItem('lang')
+      // getLanguage()
+    }
+  })
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
-#user {
-  height: 100%;
-  @include font_gray_1();
-  background-image: url(../../../assets/images/login-bg.gif);
-  background-repeat: no-repeat;
-  background-size: cover;
-  background-position: center center;
-  display: flex;
-  justify-content: center;
-  flex-wrap: wrap;
-  overflow-y: scroll;
-
-  &:before {
-    content: '';
-    position: absolute;
-    left: 0;
-    top: 0;
-    width: 100%;
+  #user {
     height: 100%;
     height: 100%;
-    z-index: 0;
-    background-color: #000000;
-    opacity: 0.6;
-  }
+    @include font_gray_1();
+    background-image: url(../../../assets/images/login-bg.gif);
+    background-repeat: no-repeat;
+    background-size: cover;
+    background-position: center center;
+    display: flex;
+    justify-content: center;
+    flex-wrap: wrap;
+    overflow-y: scroll;
 
 
-  .section-common {
-    // height: 100%;
-  }
+    &:before {
+      content: '';
+      position: absolute;
+      left: 0;
+      top: 0;
+      width: 100%;
+      height: 100%;
+      z-index: 0;
+      background-color: #000000;
+      opacity: 0.6;
+    }
 
 
-  .section-top {
-    width: 100%;
-    position: relative;
-    z-index: 1;
+    .section-common {
+      // height: 100%;
+    }
 
 
-    .bar {
+    .section-top {
+      width: 100%;
       position: relative;
       position: relative;
       z-index: 1;
       z-index: 1;
-      padding: 20px 100px;
-      box-sizing: border-box;
 
 
-      .language {
-        display: flex;
-        justify-content: end;
-        align-items: center;
+      .bar {
+        position: relative;
+        z-index: 1;
+        padding: 20px 100px;
+        box-sizing: border-box;
 
 
-        .language-selector {
+        .language {
           display: flex;
           display: flex;
+          justify-content: end;
           align-items: center;
           align-items: center;
-          cursor: pointer;
-
-          .flag-icon {
-            width: 15px;
-            height: 10px;
-            margin: 0 4px;
-            object-fit: cover;
-          }
 
 
-          .menu {
-            cursor: pointer;
-            color: #fff;
+          .language-selector {
             display: flex;
             display: flex;
             align-items: center;
             align-items: center;
+            cursor: pointer;
 
 
-            .el-icon {
-              margin-left: 4px;
+            .flag-icon {
+              width: 15px;
+              height: 10px;
+              margin: 0 4px;
+              object-fit: cover;
             }
             }
-          }
-        }
-
-        .rbt-separator {
-          position: relative;
-          padding: 0 20px;
-
-          &::after {
-            position: absolute;
-            content: '';
-            height: 20px;
-            width: 1px;
-            background: #fff;
-            top: 50%;
-            transform: translateY(-50%);
-          }
-        }
 
 
-        .social-share-transparent {
-          display: flex;
-          flex-wrap: wrap;
-          justify-content: flex-end;
-          margin: -10px;
+            .menu {
+              cursor: pointer;
+              color: #fff;
+              display: flex;
+              align-items: center;
 
 
-          li {
-            margin: 0;
-            position: relative;
+              .el-icon {
+                margin-left: 4px;
+              }
+            }
           }
           }
 
 
-          a {
-            font-size: 14px;
-            color: #fff;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            width: 30px;
-            height: 30px;
-            border-radius: 100%;
+          .rbt-separator {
             position: relative;
             position: relative;
-            z-index: 1;
+            padding: 0 20px;
 
 
-            &:hover::before {
-              opacity: 1;
-              transform: scale(1);
-            }
-
-            &::before {
-              background: #f6f6f6;
+            &::after {
               position: absolute;
               position: absolute;
               content: '';
               content: '';
-              width: 100%;
-              height: 100%;
-              left: 0;
-              top: 0;
-              opacity: 0;
-              transform: scale(0.8);
-              border-radius: 100%;
-              z-index: -1;
-              transition: all 0.3s ease;
+              height: 20px;
+              width: 1px;
+              background: #fff;
+              top: 50%;
+              transform: translateY(-50%);
             }
             }
+          }
 
 
-            &:hover {
-              color: #e61f1e;
+          .social-share-transparent {
+            display: flex;
+            flex-wrap: wrap;
+            justify-content: flex-end;
+            margin: -10px;
+
+            li {
+              margin: 0;
+              position: relative;
             }
             }
 
 
-            .el-icon {
-              font-size: 16px;
+            a {
+              font-size: 14px;
+              color: #fff;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              width: 30px;
+              height: 30px;
+              border-radius: 100%;
+              position: relative;
+              z-index: 1;
+
+              &:hover::before {
+                opacity: 1;
+                transform: scale(1);
+              }
+
+              &::before {
+                background: #f6f6f6;
+                position: absolute;
+                content: '';
+                width: 100%;
+                height: 100%;
+                left: 0;
+                top: 0;
+                opacity: 0;
+                transform: scale(0.8);
+                border-radius: 100%;
+                z-index: -1;
+                transition: all 0.3s ease;
+              }
+
+              &:hover {
+                color: #e61f1e;
+              }
+
+              .el-icon {
+                font-size: 16px;
+              }
             }
             }
           }
           }
         }
         }
       }
       }
     }
     }
-  }
 
 
-  .section-bottom {
-    max-width: 1320px;
-    min-height: calc(100% - 54px);
-    position: relative;
-    z-index: 1;
-    flex: auto;
-    display: flex;
-    flex-wrap: wrap;
-  }
+    .section-bottom {
+      max-width: 1320px;
+      min-height: calc(100% - 54px);
+      position: relative;
+      z-index: 1;
+      flex: auto;
+      display: flex;
+      flex-wrap: wrap;
+    }
 
 
-  .section-left {
-    position: relative;
-    display: flex;
-    align-items: center;
+    .section-left {
+      position: relative;
+      display: flex;
+      align-items: center;
 
 
-    .des {
-      text-align: start;
-      line-height: 20px;
-      color: #fff;
-      font-size: 12px;
-      margin-top: 30px;
+      .des {
+        text-align: start;
+        line-height: 20px;
+        color: #fff;
+        font-size: 12px;
+        margin-top: 30px;
 
 
-      a {
-        color: #e61f1e;
+        a {
+          color: #e61f1e;
+        }
       }
       }
     }
     }
-  }
 
 
-  .section-right {
-    box-sizing: border-box;
-    overflow: auto;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-  }
+    .section-right {
+      box-sizing: border-box;
+      overflow: auto;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+    }
 
 
-  .language-dropdown {
-    position: sticky;
-    top: 50px;
-    max-height: calc(100vh - 80px);
-    overflow-y: auto;
-    scrollbar-width: none;
+    .language-dropdown {
+      position: sticky;
+      top: 50px;
+      max-height: calc(100vh - 80px);
+      overflow-y: auto;
+      scrollbar-width: none;
 
 
-    &::-webkit-scrollbar {
-      display: none;
-    }
+      &::-webkit-scrollbar {
+        display: none;
+      }
 
 
-    .language-option {
-      display: flex;
-      align-items: center;
-      gap: 8px;
+      .language-option {
+        display: flex;
+        align-items: center;
+        gap: 8px;
 
 
-      .flag-icon-small {
-        width: 20px !important;
-        height: 14px;
-        object-fit: cover;
-        border-radius: 2px;
+        .flag-icon-small {
+          width: 20px !important;
+          height: 14px;
+          object-fit: cover;
+          border-radius: 2px;
+        }
       }
       }
-    }
 
 
-    .el-dropdown-item.is-active {
-      background-color: #f5f7fa;
-      color: #409eff;
+      .el-dropdown-item.is-active {
+        background-color: #f5f7fa;
+        color: #409eff;
+      }
     }
     }
   }
   }
-}
 
 
-@media screen and (max-width: 768px) {
-  #user {
-    height: 100%;
-    overflow-y: auto;
+  @media screen and (max-width: 768px) {
+    #user {
+      height: 100%;
+      overflow-y: auto;
 
 
-    .section-top {
-      height: 54px;
+      .section-top {
+        height: 54px;
 
 
-      .bar {
-        padding: 20px;
+        .bar {
+          padding: 20px;
+        }
       }
       }
-    }
 
 
-    .section-bottom {
-      width: 100%;
-    }
+      .section-bottom {
+        width: 100%;
+      }
 
 
-    .section-left {
-      display: none;
-    }
+      .section-left {
+        display: none;
+      }
 
 
-    .section-right {
-      height: auto;
-      width: 100%;
-      padding-top: 48px;
-      overflow: hidden;
-      background-color: #fff;
+      .section-right {
+        height: auto;
+        width: 100%;
+        padding-top: 48px;
+        overflow: hidden;
+        background-color: #fff;
+      }
     }
     }
   }
   }
-}
 
 
-@media screen and (max-width: 768px) {
-  #user .el-carousel__indicators {
-    transform: initial;
-    left: 48px !important;
-    bottom: 48px;
-  }
+  @media screen and (max-width: 768px) {
+    #user .el-carousel__indicators {
+      transform: initial;
+      left: 48px !important;
+      bottom: 48px;
+    }
 
 
-  #user .el-carousel__button {
-    width: 8px;
-    height: 8px;
-    border-radius: 8px;
-    @include bg_gray_1();
-  }
+    #user .el-carousel__button {
+      width: 8px;
+      height: 8px;
+      border-radius: 8px;
+      @include bg_gray_1();
+    }
 
 
-  #user .is-active > .el-carousel__button {
-    width: 20px;
-    @include bg_main();
+    #user .is-active > .el-carousel__button {
+      width: 20px;
+      @include bg_main();
+    }
   }
   }
-}
 
 
-:deep(.el-dropdown-menu__item:not(.is-disabled):hover) {
-  background-color: #fdecee;
-  color: #ef6579
-}
+  :deep(.el-dropdown-menu__item:not(.is-disabled):hover) {
+    background-color: #fdecee;
+    color: #ef6579;
+  }
 </style>
 </style>

+ 6 - 0
src/vuexStore/modules/home.ts

@@ -7,6 +7,8 @@ export default {
     expire: false,
     expire: false,
     locale: 'cn',
     locale: 'cn',
     isZhCn: true,
     isZhCn: true,
+    // 暗黑模式
+    isDark: false,
   },
   },
   mutations: {
   mutations: {
     //个人信息/登录信息
     //个人信息/登录信息
@@ -40,5 +42,9 @@ export default {
       // 设置是否是中文
       // 设置是否是中文
       state.isZhCn = payload === 'cn'
       state.isZhCn = payload === 'cn'
     },
     },
+    // 切换暗黑模式
+    ChangeDark(state, payload) {
+      state.isDark = payload
+    },
   },
   },
 }
 }