mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 22:57:15 +08:00 
			
		
		
		
	feat: 新增应用配置开关属性,迁移主题配置至 src/config/setting.ts,新增色弱模式与哀悼模式
				
					
				
			This commit is contained in:
		| @@ -13,3 +13,6 @@ VITE_BASE = '/' | ||||
|  | ||||
| # 是否开启开发者工具 | ||||
| VITE_OPEN_DEVTOOLS = false | ||||
|  | ||||
| # 应用配置面板 | ||||
| VITE_APP_SETTING = true | ||||
| @@ -9,3 +9,6 @@ VITE_API_WS_URL = 'wss://api.continew.top' | ||||
|  | ||||
| # 地址前缀 | ||||
| VITE_BASE = '/' | ||||
|  | ||||
| # 应用配置面板 | ||||
| VITE_APP_SETTING = false | ||||
| @@ -14,3 +14,6 @@ VITE_BASE = '/test' | ||||
|  | ||||
| # 是否开启开发者工具 | ||||
| VITE_OPEN_DEVTOOLS = true | ||||
|  | ||||
| # 应用配置面板 | ||||
| VITE_APP_SETTING = false | ||||
| @@ -1,13 +0,0 @@ | ||||
| { | ||||
|   "theme": "light", | ||||
|   "themeColor": "#165DFF", | ||||
|   "tab": true, | ||||
|   "tabMode": "card-gutter", | ||||
|   "animate": false, | ||||
|   "animateMode": "zoom-fade", | ||||
|   "menuCollapse": true, | ||||
|   "menuAccordion": true, | ||||
|   "menuDark": false, | ||||
|   "copyrightDisplay": true, | ||||
|   "layout": "left" | ||||
| } | ||||
							
								
								
									
										19
									
								
								src/config/setting.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/config/setting.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| export const defaultSettings: App.AppSettings = { | ||||
|   theme: 'light', | ||||
|   themeColor: '#165DFF', | ||||
|   tab: true, | ||||
|   tabMode: 'card-gutter', | ||||
|   animate: false, | ||||
|   animateMode: 'zoom-fade', | ||||
|   menuCollapse: true, | ||||
|   menuAccordion: true, | ||||
|   menuDark: false, | ||||
|   copyrightDisplay: true, | ||||
|   layout: 'left', | ||||
|   enableColorWeaknessMode: false, | ||||
|   enableMourningMode: false, | ||||
| } | ||||
| // 根据环境返回配置 | ||||
| export const getSettings = (): App.AppSettings => { | ||||
|   return defaultSettings | ||||
| } | ||||
| @@ -1,8 +1,11 @@ | ||||
| <template> | ||||
|   <a-drawer v-model:visible="visible" title="项目配置" width="300px" unmount-on-close :footer="false"> | ||||
|     <a-space :size="15" direction="vertical" fill> | ||||
|       <a-divider orientation="center">系统布局</a-divider> | ||||
|       <a-row justify="center"> | ||||
|       <a-alert v-if="settingOpen" :show-icon="false" type="info"> | ||||
|         「复制配置」按钮,并将配置粘贴到 src/config/settings.ts 文件中。 | ||||
|       </a-alert> | ||||
|       <a-divider v-if="settingOpen" orientation="center">系统布局</a-divider> | ||||
|       <a-row v-if="settingOpen" justify="center"> | ||||
|         <a-space> | ||||
|           <a-badge> | ||||
|             <template #content> | ||||
| @@ -35,9 +38,9 @@ | ||||
|         ></ColorPicker> | ||||
|       </a-row> | ||||
|  | ||||
|       <a-divider orientation="center">界面显示</a-divider> | ||||
|       <a-divider v-if="settingOpen" orientation="center">界面显示</a-divider> | ||||
|  | ||||
|       <a-descriptions :column="1" :align="{ value: 'right' }" :value-style="{ paddingRight: 0 }"> | ||||
|       <a-descriptions v-if="settingOpen" :column="1" :align="{ value: 'right' }" :value-style="{ paddingRight: 0 }"> | ||||
|         <a-descriptions-item label="页签显示"> | ||||
|           <a-switch v-model="appStore.tab" /> | ||||
|         </a-descriptions-item> | ||||
| @@ -70,10 +73,28 @@ | ||||
|         <a-descriptions-item label="水印"> | ||||
|           <a-switch v-model="appStore.isOpenWatermark" /> | ||||
|         </a-descriptions-item> | ||||
|         <a-descriptions-item v-if="appStore.isOpenWatermark" label="水印信息"> | ||||
|         <a-descriptions-item label="水印信息"> | ||||
|           <a-input v-model="appStore.watermark" placeholder="留空则显示用户名" /> | ||||
|         </a-descriptions-item> | ||||
|       </a-descriptions> | ||||
|  | ||||
|       <a-divider orientation="center">其它</a-divider> | ||||
|       <a-descriptions :column="1" :align="{ value: 'right' }" :value-style="{ paddingRight: 0 }"> | ||||
|         <a-descriptions-item label="色弱模式"> | ||||
|           <a-switch v-model="appStore.enableColorWeaknessMode" /> | ||||
|         </a-descriptions-item> | ||||
|         <a-descriptions-item v-if="settingOpen" label="哀悼模式"> | ||||
|           <a-switch v-model="appStore.enableMourningMode" /> | ||||
|         </a-descriptions-item> | ||||
|       </a-descriptions> | ||||
|       <a-space v-if="settingOpen" direction="vertical" fill> | ||||
|         <a-button type="primary" long @click="copySettings"> | ||||
|           <template #icon> | ||||
|             <icon-copy /> | ||||
|           </template> | ||||
|           复制配置 | ||||
|         </a-button> | ||||
|       </a-space> | ||||
|     </a-space> | ||||
|   </a-drawer> | ||||
| </template> | ||||
| @@ -81,13 +102,15 @@ | ||||
| <script setup lang="ts"> | ||||
| import { ColorPicker } from 'vue-color-kit' | ||||
| import 'vue-color-kit/dist/vue-color-kit.css' | ||||
| import { useClipboard } from '@vueuse/core' | ||||
| import { Message } from '@arco-design/web-vue' | ||||
| import LayoutItem from './components/LayoutItem.vue' | ||||
| import { useAppStore } from '@/stores' | ||||
|  | ||||
| defineOptions({ name: 'SettingDrawer' }) | ||||
| const appStore = useAppStore() | ||||
| const visible = ref(false) | ||||
|  | ||||
| const settingOpen = JSON.parse(import.meta.env.VITE_APP_SETTING) | ||||
| const tabModeList: App.TabItem[] = [ | ||||
|   { label: '卡片', value: 'card' }, | ||||
|   { label: '间隔卡片', value: 'card-gutter' }, | ||||
| @@ -138,6 +161,36 @@ const changeColor = (colorObj: ColorObj) => { | ||||
|   appStore.setThemeColor(colorObj.hex) | ||||
| } | ||||
|  | ||||
| // 复制配置 | ||||
| const copySettings = () => { | ||||
|   const settings: App.AppSettings = { | ||||
|     theme: 'light', | ||||
|     themeColor: appStore.themeColor, | ||||
|     tab: appStore.tab, | ||||
|     tabMode: appStore.tabMode, | ||||
|     animate: appStore.animate, | ||||
|     animateMode: appStore.animateMode, | ||||
|     menuCollapse: appStore.menuCollapse, | ||||
|     menuAccordion: appStore.menuAccordion, | ||||
|     menuDark: appStore.menuDark, | ||||
|     copyrightDisplay: appStore.copyrightDisplay, | ||||
|     layout: appStore.layout, | ||||
|     isOpenWatermark: appStore.isOpenWatermark, | ||||
|     watermark: appStore.watermark, | ||||
|     enableColorWeaknessMode: appStore.enableColorWeaknessMode, | ||||
|     enableMourningMode: appStore.enableMourningMode, | ||||
|   } | ||||
|  | ||||
|   const settingJson = JSON.stringify(settings, null, 2) | ||||
|   const { isSupported, copy } = useClipboard({ source: settingJson }) | ||||
|   if (isSupported) { | ||||
|     copy(settingJson) | ||||
|     Message.success({ content: '复制成功!' }) | ||||
|   } else { | ||||
|     Message.error({ content: '请检查浏览器权限是否开启' }) | ||||
|   } | ||||
| } | ||||
|  | ||||
| defineExpose({ open }) | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -80,7 +80,6 @@ import { isMobile } from '@/utils' | ||||
| import { getToken } from '@/utils/auth' | ||||
|  | ||||
| defineOptions({ name: 'HeaderRight' }) | ||||
|  | ||||
| let socket: WebSocket | ||||
| onBeforeUnmount(() => { | ||||
|   if (socket) { | ||||
|   | ||||
| @@ -2,11 +2,11 @@ import { defineStore } from 'pinia' | ||||
| import { computed, reactive, toRefs } from 'vue' | ||||
| import { generate, getRgbStr } from '@arco-design/color' | ||||
| import { type BasicConfig, listSiteOptionDict } from '@/apis' | ||||
| import defaultSettings from '@/config/setting.json' | ||||
| import { getSettings } from '@/config/setting' | ||||
|  | ||||
| const storeSetup = () => { | ||||
|   // App配置 | ||||
|   const settingConfig = reactive({ ...defaultSettings }) as App.SettingConfig | ||||
|   const settingConfig = reactive({ ...getSettings() }) as App.AppSettings | ||||
|   // 页面切换动画类名 | ||||
|   const transitionName = computed(() => (settingConfig.animate ? settingConfig.animateMode : '')) | ||||
|  | ||||
| @@ -81,6 +81,27 @@ const storeSetup = () => { | ||||
|     document.title = config.SITE_TITLE || '' | ||||
|     document.querySelector('link[rel="shortcut icon"]')?.setAttribute('href', config.SITE_FAVICON || '/favicon.ico') | ||||
|   } | ||||
|   // 监听 色弱模式 和 哀悼模式 | ||||
|   watch([ | ||||
|     () => settingConfig.enableMourningMode, | ||||
|     () => settingConfig.enableColorWeaknessMode, | ||||
|   ], ([mourningMode, colorWeaknessMode]) => { | ||||
|     const filters = [] as string[] | ||||
|     if (mourningMode) { | ||||
|       filters.push('grayscale(100%)') | ||||
|     } | ||||
|     if (colorWeaknessMode) { | ||||
|       filters.push('invert(80%)') | ||||
|     } | ||||
|     // 如果没有任何滤镜条件,移除 `filter` 样式 | ||||
|     if (filters.length === 0) { | ||||
|       document.documentElement.style.removeProperty('filter') | ||||
|     } else { | ||||
|       document.documentElement.style.setProperty('filter', filters.join(' ')) | ||||
|     } | ||||
|   }, { | ||||
|     immediate: true, | ||||
|   }) | ||||
|  | ||||
|   const getFavicon = () => { | ||||
|     return siteConfig.SITE_FAVICON | ||||
|   | ||||
							
								
								
									
										30
									
								
								src/types/app.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								src/types/app.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -1,20 +1,22 @@ | ||||
| declare namespace App { | ||||
|   /** 系统配置 */ | ||||
|   interface SettingConfig { | ||||
|     theme: 'light' | 'dark' // 主题 | ||||
|     themeColor: string // 主题色 | ||||
|     tab: boolean // 是否显示页签 | ||||
|     tabMode: TabType // 页签风格 | ||||
|     animate: boolean // 是否显示动画 | ||||
|     animateMode: AnimateType // 动画类名 | ||||
|     menuCollapse: boolean // 左侧菜单折叠状态 | ||||
|     menuAccordion: boolean // 左侧菜单手风琴效果 | ||||
|     copyrightDisplay: boolean // 是否显示底部版权信息 | ||||
|     menuDark: boolean // 菜单深色模式 | ||||
|   interface AppSettings { | ||||
|     theme: 'light' | 'dark' | ||||
|     themeColor: string | ||||
|     tab: boolean | ||||
|     tabMode: 'card' | 'card-gutter' | 'rounded' | ||||
|     animate: boolean | ||||
|     animateMode: 'zoom-fade' | 'slide-dynamic-origin' | 'fade-slide' | 'fade' | 'fade-bottom' | 'fade-scale' | ||||
|     menuCollapse: boolean | ||||
|     menuAccordion: boolean | ||||
|     menuDark: boolean | ||||
|     copyrightDisplay: boolean | ||||
|     layout: 'left' | 'mix' | ||||
|     isOpenWatermark: boolean // 是否开启水印 | ||||
|     watermark: string // 水印 | ||||
|     isOpenWatermark?: boolean | ||||
|     watermark?: string | ||||
|     enableColorWeaknessMode?: boolean | ||||
|     enableMourningMode?: boolean | ||||
|   } | ||||
|  | ||||
|   /** 导航页签的样式类型 */ | ||||
|   type TabType = 'card' | 'card-gutter' | 'rounded' | ||||
|   interface TabItem { | ||||
|   | ||||
							
								
								
									
										1
									
								
								src/types/env.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/types/env.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -5,6 +5,7 @@ interface ImportMetaEnv { | ||||
|   readonly VITE_API_PREFIX: string | ||||
|   readonly VITE_API_BASE_URL: string | ||||
|   readonly VITE_BASE: string | ||||
|   readonly VITE_APP_SETTING: string | ||||
| } | ||||
|  | ||||
| interface ImportMeta { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 KAI
					KAI