app.ts 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. import { defineStore } from 'pinia'
  2. import { store } from '../index'
  3. import { setCssVar, humpToUnderline } from '@/utils'
  4. import { ElMessage, ComponentSize } from 'element-plus'
  5. import { colorIsDark, hexToRGB, lighten, mix } from '@/utils/color'
  6. import { unref } from 'vue'
  7. import { useCssVar } from '@vueuse/core'
  8. import { useDark } from '@vueuse/core'
  9. interface AppState {
  10. breadcrumb: boolean
  11. breadcrumbIcon: boolean
  12. collapse: boolean
  13. uniqueOpened: boolean
  14. hamburger: boolean
  15. screenfull: boolean
  16. size: boolean
  17. locale: boolean
  18. tagsView: boolean
  19. tagsViewIcon: boolean
  20. logo: boolean
  21. fixedHeader: boolean
  22. greyMode: boolean
  23. dynamicRouter: boolean
  24. serverDynamicRouter: boolean
  25. pageLoading: boolean
  26. layout: LayoutType
  27. title: string
  28. isDark: boolean
  29. currentSize: ComponentSize
  30. sizeMap: ComponentSize[]
  31. mobile: boolean
  32. footer: boolean
  33. theme: ThemeTypes
  34. fixedMenu: boolean
  35. }
  36. export const useAppStore = defineStore('app', {
  37. state: (): AppState => {
  38. return {
  39. sizeMap: ['default', 'large', 'small'],
  40. mobile: false, // 是否是移动端
  41. title: import.meta.env.VITE_APP_TITLE, // 标题
  42. pageLoading: false, // 路由跳转loading
  43. breadcrumb: true, // 面包屑
  44. breadcrumbIcon: true, // 面包屑图标
  45. collapse: false, // 折叠菜单
  46. uniqueOpened: false, // 是否只保持一个子菜单的展开
  47. hamburger: true, // 折叠图标
  48. screenfull: true, // 全屏图标
  49. size: true, // 尺寸图标
  50. locale: true, // 多语言图标
  51. tagsView: true, // 标签页
  52. tagsViewIcon: true, // 是否显示标签图标
  53. logo: true, // logo
  54. fixedHeader: true, // 固定toolheader
  55. footer: true, // 显示页脚
  56. greyMode: false, // 是否开始灰色模式,用于特殊悼念日
  57. dynamicRouter: true, // 是否动态路由
  58. serverDynamicRouter: true, // 是否服务端渲染动态路由
  59. fixedMenu: false, // 是否固定菜单
  60. layout: 'classic', // layout布局
  61. isDark: false, // 是否是暗黑模式
  62. currentSize: 'default', // 组件尺寸
  63. theme: {
  64. // 主题色
  65. elColorPrimary: '#409eff',
  66. // 左侧菜单边框颜色
  67. leftMenuBorderColor: 'inherit',
  68. // 左侧菜单背景颜色
  69. leftMenuBgColor: '#001529',
  70. // 左侧菜单浅色背景颜色
  71. leftMenuBgLightColor: '#0f2438',
  72. // 左侧菜单选中背景颜色
  73. leftMenuBgActiveColor: 'var(--el-color-primary)',
  74. // 左侧菜单收起选中背景颜色
  75. leftMenuCollapseBgActiveColor: 'var(--el-color-primary)',
  76. // 左侧菜单字体颜色
  77. leftMenuTextColor: '#bfcbd9',
  78. // 左侧菜单选中字体颜色
  79. leftMenuTextActiveColor: '#fff',
  80. // logo字体颜色
  81. logoTitleTextColor: '#fff',
  82. // logo边框颜色
  83. logoBorderColor: 'inherit',
  84. // 头部背景颜色
  85. topHeaderBgColor: '#fff',
  86. // 头部字体颜色
  87. topHeaderTextColor: 'inherit',
  88. // 头部悬停颜色
  89. topHeaderHoverColor: '#f6f6f6',
  90. // 头部边框颜色
  91. topToolBorderColor: '#eee'
  92. }
  93. }
  94. },
  95. getters: {
  96. getBreadcrumb(): boolean {
  97. return this.breadcrumb
  98. },
  99. getBreadcrumbIcon(): boolean {
  100. return this.breadcrumbIcon
  101. },
  102. getCollapse(): boolean {
  103. return this.collapse
  104. },
  105. getUniqueOpened(): boolean {
  106. return this.uniqueOpened
  107. },
  108. getHamburger(): boolean {
  109. return this.hamburger
  110. },
  111. getScreenfull(): boolean {
  112. return this.screenfull
  113. },
  114. getSize(): boolean {
  115. return this.size
  116. },
  117. getLocale(): boolean {
  118. return this.locale
  119. },
  120. getTagsView(): boolean {
  121. return this.tagsView
  122. },
  123. getTagsViewIcon(): boolean {
  124. return this.tagsViewIcon
  125. },
  126. getLogo(): boolean {
  127. return this.logo
  128. },
  129. getFixedHeader(): boolean {
  130. return this.fixedHeader
  131. },
  132. getGreyMode(): boolean {
  133. return this.greyMode
  134. },
  135. getDynamicRouter(): boolean {
  136. return this.dynamicRouter
  137. },
  138. getServerDynamicRouter(): boolean {
  139. return this.serverDynamicRouter
  140. },
  141. getFixedMenu(): boolean {
  142. return this.fixedMenu
  143. },
  144. getPageLoading(): boolean {
  145. return this.pageLoading
  146. },
  147. getLayout(): LayoutType {
  148. return this.layout
  149. },
  150. getTitle(): string {
  151. return this.title
  152. },
  153. getIsDark(): boolean {
  154. return this.isDark
  155. },
  156. getCurrentSize(): ComponentSize {
  157. return this.currentSize
  158. },
  159. getSizeMap(): ComponentSize[] {
  160. return this.sizeMap
  161. },
  162. getMobile(): boolean {
  163. return this.mobile
  164. },
  165. getTheme(): ThemeTypes {
  166. return this.theme
  167. },
  168. getFooter(): boolean {
  169. return this.footer
  170. }
  171. },
  172. actions: {
  173. setBreadcrumb(breadcrumb: boolean) {
  174. this.breadcrumb = breadcrumb
  175. },
  176. setBreadcrumbIcon(breadcrumbIcon: boolean) {
  177. this.breadcrumbIcon = breadcrumbIcon
  178. },
  179. setCollapse(collapse: boolean) {
  180. this.collapse = collapse
  181. },
  182. setUniqueOpened(uniqueOpened: boolean) {
  183. this.uniqueOpened = uniqueOpened
  184. },
  185. setHamburger(hamburger: boolean) {
  186. this.hamburger = hamburger
  187. },
  188. setScreenfull(screenfull: boolean) {
  189. this.screenfull = screenfull
  190. },
  191. setSize(size: boolean) {
  192. this.size = size
  193. },
  194. setLocale(locale: boolean) {
  195. this.locale = locale
  196. },
  197. setTagsView(tagsView: boolean) {
  198. this.tagsView = tagsView
  199. },
  200. setTagsViewIcon(tagsViewIcon: boolean) {
  201. this.tagsViewIcon = tagsViewIcon
  202. },
  203. setLogo(logo: boolean) {
  204. this.logo = logo
  205. },
  206. setFixedHeader(fixedHeader: boolean) {
  207. this.fixedHeader = fixedHeader
  208. },
  209. setGreyMode(greyMode: boolean) {
  210. this.greyMode = greyMode
  211. },
  212. setDynamicRouter(dynamicRouter: boolean) {
  213. this.dynamicRouter = dynamicRouter
  214. },
  215. setServerDynamicRouter(serverDynamicRouter: boolean) {
  216. this.serverDynamicRouter = serverDynamicRouter
  217. },
  218. setFixedMenu(fixedMenu: boolean) {
  219. this.fixedMenu = fixedMenu
  220. },
  221. setPageLoading(pageLoading: boolean) {
  222. this.pageLoading = pageLoading
  223. },
  224. setLayout(layout: LayoutType) {
  225. if (this.mobile && layout !== 'classic') {
  226. ElMessage.warning('移动端模式下不支持切换其它布局')
  227. return
  228. }
  229. this.layout = layout
  230. },
  231. setTitle(title: string) {
  232. this.title = title
  233. },
  234. setIsDark(isDark: boolean) {
  235. this.isDark = isDark
  236. if (this.isDark) {
  237. document.documentElement.classList.add('dark')
  238. document.documentElement.classList.remove('light')
  239. } else {
  240. document.documentElement.classList.add('light')
  241. document.documentElement.classList.remove('dark')
  242. }
  243. this.setPrimaryLight()
  244. },
  245. setCurrentSize(currentSize: ComponentSize) {
  246. this.currentSize = currentSize
  247. },
  248. setMobile(mobile: boolean) {
  249. this.mobile = mobile
  250. },
  251. setTheme(theme: ThemeTypes) {
  252. this.theme = Object.assign(this.theme, theme)
  253. },
  254. setCssVarTheme() {
  255. for (const key in this.theme) {
  256. setCssVar(`--${humpToUnderline(key)}`, this.theme[key])
  257. }
  258. this.setPrimaryLight()
  259. },
  260. setFooter(footer: boolean) {
  261. this.footer = footer
  262. },
  263. setPrimaryLight() {
  264. if (this.theme.elColorPrimary) {
  265. const elColorPrimary = this.theme.elColorPrimary
  266. const color = this.isDark ? '#000000' : '#ffffff'
  267. const lightList = [3, 5, 7, 8, 9]
  268. lightList.forEach((v) => {
  269. setCssVar(`--el-color-primary-light-${v}`, mix(color, elColorPrimary, v / 10))
  270. })
  271. setCssVar(`--el-color-primary-dark-2`, mix(color, elColorPrimary, 0.2))
  272. }
  273. },
  274. setMenuTheme(color: string) {
  275. const primaryColor = useCssVar('--el-color-primary', document.documentElement)
  276. const isDarkColor = colorIsDark(color)
  277. const theme: Recordable = {
  278. // 左侧菜单边框颜色
  279. leftMenuBorderColor: isDarkColor ? 'inherit' : '#eee',
  280. // 左侧菜单背景颜色
  281. leftMenuBgColor: color,
  282. // 左侧菜单浅色背景颜色
  283. leftMenuBgLightColor: isDarkColor ? lighten(color!, 6) : color,
  284. // 左侧菜单选中背景颜色
  285. leftMenuBgActiveColor: isDarkColor
  286. ? 'var(--el-color-primary)'
  287. : hexToRGB(unref(primaryColor), 0.1),
  288. // 左侧菜单收起选中背景颜色
  289. leftMenuCollapseBgActiveColor: isDarkColor
  290. ? 'var(--el-color-primary)'
  291. : hexToRGB(unref(primaryColor), 0.1),
  292. // 左侧菜单字体颜色
  293. leftMenuTextColor: isDarkColor ? '#bfcbd9' : '#333',
  294. // 左侧菜单选中字体颜色
  295. leftMenuTextActiveColor: isDarkColor ? '#fff' : 'var(--el-color-primary)',
  296. // logo字体颜色
  297. logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
  298. // logo边框颜色
  299. logoBorderColor: isDarkColor ? color : '#eee'
  300. }
  301. this.setTheme(theme)
  302. this.setCssVarTheme()
  303. },
  304. setHeaderTheme(color: string) {
  305. const isDarkColor = colorIsDark(color)
  306. const textColor = isDarkColor ? '#fff' : 'inherit'
  307. const textHoverColor = isDarkColor ? lighten(color!, 6) : '#f6f6f6'
  308. const topToolBorderColor = isDarkColor ? color : '#eee'
  309. setCssVar('--top-header-bg-color', color)
  310. setCssVar('--top-header-text-color', textColor)
  311. setCssVar('--top-header-hover-color', textHoverColor)
  312. this.setTheme({
  313. topHeaderBgColor: color,
  314. topHeaderTextColor: textColor,
  315. topHeaderHoverColor: textHoverColor,
  316. topToolBorderColor
  317. })
  318. if (this.getLayout === 'top') {
  319. this.setMenuTheme(color)
  320. }
  321. },
  322. initTheme() {
  323. const isDark = useDark({
  324. valueDark: 'dark',
  325. valueLight: 'light'
  326. })
  327. isDark.value = this.getIsDark
  328. }
  329. },
  330. persist: true
  331. })
  332. export const useAppStoreWithOut = () => {
  333. return useAppStore(store)
  334. }