Vben 3 роки тому
батько
коміт
5b8eb4a49a
100 змінених файлів з 720 додано та 803 видалено
  1. 1 0
      CHANGELOG.zh_CN.md
  2. 6 44
      build/config/themeConfig.ts
  3. 35 0
      build/generate/generateModifyVars.ts
  4. 1 1
      build/vite/plugin/index.ts
  5. 38 6
      build/vite/plugin/theme.ts
  6. 17 1
      index.html
  7. 3 4
      package.json
  8. 16 0
      src/assets/icons/moon.svg
  9. 42 0
      src/assets/icons/sun.svg
  10. 19 0
      src/assets/svg/login-bg-dark.svg
  11. 2 2
      src/assets/svg/login-bg.svg
  12. 2 1
      src/components/Application/index.ts
  13. 111 0
      src/components/Application/src/AppDarkModeToggle.vue
  14. 2 2
      src/components/Application/src/search/AppSearchFooter.vue
  15. 2 5
      src/components/Application/src/search/AppSearchModal.vue
  16. 1 1
      src/components/Container/src/collapse/CollapseContainer.vue
  17. 2 2
      src/components/ContextMenu/src/index.less
  18. 1 1
      src/components/Drawer/src/BasicDrawer.vue
  19. 1 1
      src/components/Drawer/src/components/DrawerFooter.vue
  20. 1 1
      src/components/Form/src/components/FormItem.vue
  21. 9 22
      src/components/Loading/src/index.vue
  22. 20 2
      src/components/Markdown/src/index.vue
  23. 2 2
      src/components/Page/src/PageFooter.vue
  24. 19 9
      src/components/Page/src/PageWrapper.vue
  25. 2 2
      src/components/SimpleMenu/src/index.less
  26. 22 9
      src/components/Table/src/BasicTable.vue
  27. 3 1
      src/components/Tree/src/index.vue
  28. 2 3
      src/components/Upload/src/FileList.less
  29. 14 4
      src/design/ant/btn.less
  30. 30 0
      src/design/ant/pagination.less
  31. 4 27
      src/design/color.less
  32. 1 0
      src/design/index.less
  33. 31 0
      src/design/theme.less
  34. 0 2
      src/directives/loading.ts
  35. 0 8
      src/enums/appEnum.ts
  36. 2 0
      src/enums/cacheEnum.ts
  37. 12 0
      src/hooks/setting/useRootSetting.ts
  38. 0 57
      src/hooks/web/useApexCharts.ts
  39. 33 6
      src/hooks/web/useECharts.ts
  40. 0 1
      src/layouts/default/header/MultipleHeader.vue
  41. 0 1
      src/layouts/default/header/components/lock/LockModal.vue
  42. 0 4
      src/layouts/default/header/components/user-dropdown/index.vue
  43. 4 3
      src/layouts/default/header/index.less
  44. 9 4
      src/layouts/default/setting/SettingDrawer.tsx
  45. 1 1
      src/layouts/default/setting/components/ThemeColorPicker.vue
  46. 6 12
      src/layouts/default/setting/components/TypePicker.vue
  47. 1 1
      src/layouts/default/setting/components/index.ts
  48. 1 0
      src/layouts/default/setting/enum.ts
  49. 15 1
      src/layouts/default/setting/handler.ts
  50. 1 1
      src/layouts/default/sider/MixSider.vue
  51. 23 41
      src/layouts/default/tabs/index.less
  52. 3 0
      src/locales/lang/en/common.ts
  53. 1 0
      src/locales/lang/en/layout/setting.ts
  54. 0 1
      src/locales/lang/en/routes/demo/charts.ts
  55. 3 0
      src/locales/lang/zh_CN/common.ts
  56. 1 0
      src/locales/lang/zh_CN/layout/setting.ts
  57. 0 1
      src/locales/lang/zh_CN/routes/demo/charts.ts
  58. 23 9
      src/logics/initAppConfig.ts
  59. 13 0
      src/logics/theme/dark.ts
  60. 3 3
      src/logics/theme/index.ts
  61. 28 16
      src/logics/theme/updateBackground.ts
  62. 0 5
      src/router/menus/modules/demo/charts.ts
  63. 0 8
      src/router/routes/modules/demo/charts.ts
  64. 5 0
      src/settings/designSetting.ts
  65. 4 4
      src/settings/projectSetting.ts
  66. 16 1
      src/store/modules/app.ts
  67. 0 1
      src/views/dashboard/analysis/components/VisitRadar.vue
  68. 0 1
      src/views/dashboard/workbench/components/SaleRadar.vue
  69. 0 1
      src/views/demo/charts/SaleRadar.vue
  70. 0 58
      src/views/demo/charts/apex/Area.vue
  71. 0 52
      src/views/demo/charts/apex/Bar.vue
  72. 0 53
      src/views/demo/charts/apex/Line.vue
  73. 0 138
      src/views/demo/charts/apex/Mixed.vue
  74. 0 61
      src/views/demo/charts/apex/SaleRadar.vue
  75. 0 46
      src/views/demo/charts/apex/index.vue
  76. 1 1
      src/views/demo/comp/lazy/Transition.vue
  77. 1 1
      src/views/demo/comp/lazy/index.vue
  78. 1 1
      src/views/demo/comp/scroll/Action.vue
  79. 2 2
      src/views/demo/comp/scroll/VirtualScroll.vue
  80. 1 1
      src/views/demo/comp/scroll/index.vue
  81. 1 1
      src/views/demo/comp/strength-meter/index.vue
  82. 3 2
      src/views/demo/feat/tab-params/index.vue
  83. 3 2
      src/views/demo/level/Menu111.vue
  84. 3 2
      src/views/demo/level/Menu12.vue
  85. 3 1
      src/views/demo/level/Menu2.vue
  86. 2 4
      src/views/demo/page/account/center/Application.vue
  87. 2 2
      src/views/demo/page/account/center/index.vue
  88. 2 2
      src/views/demo/page/account/setting/index.vue
  89. 1 1
      src/views/demo/page/desc/basic/index.vue
  90. 1 1
      src/views/demo/page/form/basic/index.vue
  91. 3 3
      src/views/demo/page/form/step/Step1.vue
  92. 1 1
      src/views/demo/page/form/step/Step3.vue
  93. 1 1
      src/views/demo/page/form/step/index.vue
  94. 6 6
      src/views/demo/page/list/basic/index.vue
  95. 2 2
      src/views/demo/page/list/card/index.vue
  96. 4 4
      src/views/demo/page/list/search/index.vue
  97. 2 3
      src/views/demo/page/result/fail/index.vue
  98. 2 2
      src/views/demo/page/result/success/index.vue
  99. 1 1
      src/views/demo/permission/back/Btn.vue
  100. 1 1
      src/views/demo/permission/back/index.vue

+ 1 - 0
CHANGELOG.zh_CN.md

@@ -11,6 +11,7 @@
 - 移除 useFullScreen 函数
 - tinymce 由 Cdn 改为 npm(打包体积偏大)
 - Dashboard 重构
+- 移除 ApexCharts 及示例
 
 ### 🐛 Bug Fixes
 

+ 6 - 44
build/config/themeConfig.ts

@@ -2,11 +2,7 @@ import { generate } from '@ant-design/colors';
 
 export const primaryColor = '#0960bd';
 
-export const borderColorBase = '#d9d9d9';
-
-export const themeMode = 'light';
-
-export type ThemeMode = 'dark' | 'light';
+export const darkMode = 'light';
 
 type Fn = (...arg: any) => any;
 
@@ -17,18 +13,17 @@ export interface GenerateColorsParams {
   color?: string;
 }
 
-export function generateAntColors(color: string, mode: ThemeMode) {
+export function generateAntColors(color: string) {
   return generate(color, {
-    theme: mode == 'dark' ? 'dark' : 'default',
+    theme: 'default',
   });
 }
 
-export function getThemeColors(color?: string, theme?: ThemeMode) {
+export function getThemeColors(color?: string) {
   const tc = color || primaryColor;
-  const tm = theme || themeMode;
-  const colors = generateAntColors(tc, tm);
+  const colors = generateAntColors(tc);
   const primary = colors[5];
-  const modeColors = generateAntColors(primary, tm === 'dark' ? 'light' : 'dark');
+  const modeColors = generateAntColors(primary);
 
   return [...colors, ...modeColors];
 }
@@ -71,36 +66,3 @@ export function generateColors({
     .filter((item) => item !== '#000000');
   return [...lightens, ...darkens, ...alphaColors, ...tinycolorDarkens, ...tinycolorLightens];
 }
-
-/**
- * less global variable
- */
-export function generateModifyVars() {
-  const palettes = generateAntColors(primaryColor, themeMode);
-  const primary = palettes[5];
-
-  const primaryColorObj: Record<string, string> = {};
-
-  for (let index = 0; index < 10; index++) {
-    primaryColorObj[`primary-${index + 1}`] = palettes[index];
-  }
-
-  return {
-    'primary-color': primary,
-    ...primaryColorObj,
-    'info-color': primary,
-    'processing-color': primary,
-    'success-color': '#55D187', //  Success color
-    'error-color': '#ED6F6F', //  False color
-    'warning-color': '#EFBD47', //   Warning color
-    'disabled-color': 'rgba(0, 0, 0, 0.25)', //  Failure color
-    'heading-color': 'rgba(0, 0, 0, 0.85)', //  Title color
-    'text-color': 'rgba(0, 0, 0, 0.85)', //  Main text color
-    'text-color-secondary': 'rgba(0, 0, 0, 0.45)', // Subtext color
-    'font-size-base': '14px', //  Main font size
-    'box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)', //  Floating shadow
-    'border-color-base': borderColorBase, //  Border color,
-    'border-radius-base': '2px', //  Component/float fillet
-    'link-color': primary, //   Link color
-  };
-}

+ 35 - 0
build/generate/generateModifyVars.ts

@@ -0,0 +1,35 @@
+import { generateAntColors, primaryColor } from '../config/themeConfig';
+import { getThemeVariables } from 'ant-design-vue/dist/theme';
+import { resolve } from 'path';
+
+/**
+ * less global variable
+ */
+export function generateModifyVars(dark = false) {
+  const palettes = generateAntColors(primaryColor);
+  const primary = palettes[5];
+
+  const primaryColorObj: Record<string, string> = {};
+
+  for (let index = 0; index < 10; index++) {
+    primaryColorObj[`primary-${index + 1}`] = palettes[index];
+  }
+
+  const modifyVars = getThemeVariables({ dark });
+  return {
+    ...modifyVars,
+    // Used for global import to avoid the need to import each style file separately
+    // reference:  Avoid repeated references
+    hack: `${modifyVars.hack} @import (reference) "${resolve('src/design/config.less')}";`,
+    'primary-color': primary,
+    ...primaryColorObj,
+    'info-color': primary,
+    'processing-color': primary,
+    'success-color': '#55D187', //  Success color
+    'error-color': '#ED6F6F', //  False color
+    'warning-color': '#EFBD47', //   Warning color
+    'font-size-base': '14px', //  Main font size
+    'border-radius-base': '2px', //  Component/float fillet
+    'link-color': primary, //   Link color
+  };
+}

+ 1 - 1
build/vite/plugin/index.ts

@@ -62,7 +62,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
   vitePlugins.push(configVisualizerConfig());
 
   //vite-plugin-theme
-  vitePlugins.push(configThemePlugin());
+  vitePlugins.push(configThemePlugin(isBuild));
 
   // The following plugins only work in the production environment
   if (isBuild) {

+ 38 - 6
build/vite/plugin/theme.ts

@@ -2,18 +2,50 @@
  * Vite plugin for website theme color switching
  * https://github.com/anncwb/vite-plugin-theme
  */
-import { viteThemePlugin, mixLighten, mixDarken, tinycolor } from 'vite-plugin-theme';
+import type { Plugin } from 'vite';
+import {
+  viteThemePlugin,
+  antdDarkThemePlugin,
+  mixLighten,
+  mixDarken,
+  tinycolor,
+} from 'vite-plugin-theme';
 import { getThemeColors, generateColors } from '../../config/themeConfig';
+import { generateModifyVars } from '../../generate/generateModifyVars';
 
-export function configThemePlugin() {
+export function configThemePlugin(isBuild: boolean): Plugin[] {
   const colors = generateColors({
     mixDarken,
     mixLighten,
     tinycolor,
   });
 
-  const plugin = viteThemePlugin({
-    colorVariables: [...getThemeColors(), ...colors],
-  });
-  return plugin;
+  const plugin = [
+    viteThemePlugin({
+      resolveSelector: (s) => `[data-theme] ${s}`,
+      colorVariables: [...getThemeColors(), ...colors],
+    }),
+    antdDarkThemePlugin({
+      filter: (id) => {
+        if (isBuild) {
+          return !id.endsWith('antd.less');
+        }
+        return true;
+      },
+      // extractCss: false,
+      darkModifyVars: {
+        ...generateModifyVars(true),
+        'text-color': '#c9d1d9',
+        'text-color-base': '#c9d1d9',
+        'component-background': '#151515',
+        // black: '#0e1117',
+        // #8b949e
+        'text-color-secondary': '#8b949e',
+        'border-color-base': '#30363d',
+        'item-active-bg': '#111b26',
+      },
+    }),
+  ];
+
+  return (plugin as unknown) as Plugin[];
 }

+ 17 - 1
index.html

@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html lang="en">
+<html lang="en" id="htmlRoot">
   <head>
     <meta charset="UTF-8" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
@@ -13,8 +13,24 @@
     <link rel="icon" href="/favicon.ico" />
   </head>
   <body>
+    <script>
+      (() => {
+        var htmlRoot = document.getElementById('htmlRoot');
+        const theme = window.localStorage.getItem('__APP__DARK__MODE__');
+        if (!htmlRoot || !theme) return;
+        htmlRoot.setAttribute('data-theme', theme);
+      })();
+    </script>
     <div id="app">
       <style>
+        html[data-theme='dark'] .app-loading {
+          background: #2c344a;
+        }
+
+        html[data-theme='dark'] .app-loading .app-loading-title {
+          color: rgba(255, 255, 255, 0.85);
+        }
+
         .app-loading {
           display: flex;
           width: 100%;

+ 3 - 4
package.json

@@ -35,7 +35,6 @@
     "@vueuse/core": "^4.7.0",
     "@zxcvbn-ts/core": "^0.3.0",
     "ant-design-vue": "^2.1.2",
-    "apexcharts": "^3.26.0",
     "axios": "^0.21.1",
     "cropperjs": "^1.5.11",
     "crypto-js": "^4.0.0",
@@ -51,7 +50,7 @@
     "vditor": "^3.8.4",
     "vue": "3.0.11",
     "vue-i18n": "^9.0.0",
-    "vue-router": "^4.0.5",
+    "vue-router": "^4.0.6",
     "vue-types": "^3.0.2",
     "vuex": "^4.0.0",
     "vuex-module-decorators": "^1.0.1",
@@ -110,12 +109,12 @@
     "vite-plugin-compression": "^0.2.4",
     "vite-plugin-html": "^2.0.6",
     "vite-plugin-imagemin": "^0.3.0",
-    "vite-plugin-mock": "^2.4.2",
+    "vite-plugin-mock": "^2.5.0",
     "vite-plugin-purge-icons": "^0.7.0",
     "vite-plugin-pwa": "^0.6.5",
     "vite-plugin-style-import": "^0.9.2",
     "vite-plugin-svg-icons": "^0.4.1",
-    "vite-plugin-theme": "^0.5.0",
+    "vite-plugin-theme": "^0.6.0",
     "vite-plugin-windicss": "0.12.5",
     "vue-eslint-parser": "^7.6.0"
   },

+ 16 - 0
src/assets/icons/moon.svg

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 499.712 499.712" style="enable-background: new 0 0 499.712 499.712;" xml:space="preserve">
+<path style="fill: #FFD93B;" d="M146.88,375.528c126.272,0,228.624-102.368,228.624-228.64c0-55.952-20.16-107.136-53.52-146.88
+	C425.056,33.096,499.696,129.64,499.696,243.704c0,141.392-114.608,256-256,256c-114.064,0-210.608-74.64-243.696-177.712
+	C39.744,355.368,90.944,375.528,146.88,375.528z"/>
+<path style="fill: #F4C534;" d="M401.92,42.776c34.24,43.504,54.816,98.272,54.816,157.952c0,141.392-114.608,256-256,256
+	c-59.68,0-114.448-20.576-157.952-54.816c46.848,59.472,119.344,97.792,200.928,97.792c141.392,0,256-114.608,256-256
+	C499.712,162.12,461.392,89.64,401.92,42.776z"/>
+<g>
+	<polygon style="fill: #FFD83B;" points="128.128,99.944 154.496,153.4 213.472,161.96 170.8,203.56 180.864,262.296
+		128.128,234.568 75.376,262.296 85.44,203.56 42.768,161.96 101.744,153.4"/>
+	<polygon style="fill: #FFD83B;" points="276.864,82.84 290.528,110.552 321.104,114.984 298.976,136.552 304.208,166.984
+		276.864,152.616 249.52,166.984 254.752,136.552 232.624,114.984 263.2,110.552"/>
+</g>
+</svg>

+ 42 - 0
src/assets/icons/sun.svg

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 60 60" style="enable-background: new 0 0 60 60;" xml:space="preserve">
+<g>
+	<path style="fill: #F0C419;" d="M30,0c-0.552,0-1,0.448-1,1v6c0,0.552,0.448,1,1,1s1-0.448,1-1V1C31,0.448,30.552,0,30,0z"/>
+	<path style="fill: #F0C419;" d="M30,52c-0.552,0-1,0.448-1,1v6c0,0.552,0.448,1,1,1s1-0.448,1-1v-6C31,52.448,30.552,52,30,52z"/>
+	<path style="fill: #F0C419;" d="M59,29h-6c-0.552,0-1,0.448-1,1s0.448,1,1,1h6c0.552,0,1-0.448,1-1S59.552,29,59,29z"/>
+	<path style="fill: #F0C419;" d="M8,30c0-0.552-0.448-1-1-1H1c-0.552,0-1,0.448-1,1s0.448,1,1,1h6C7.552,31,8,30.552,8,30z"/>
+	<path style="fill: #F0C419;" d="M46.264,14.736c0.256,0,0.512-0.098,0.707-0.293l5.736-5.736c0.391-0.391,0.391-1.023,0-1.414
+		s-1.023-0.391-1.414,0l-5.736,5.736c-0.391,0.391-0.391,1.023,0,1.414C45.752,14.639,46.008,14.736,46.264,14.736z"/>
+	<path style="fill: #F0C419;" d="M13.029,45.557l-5.736,5.736c-0.391,0.391-0.391,1.023,0,1.414C7.488,52.902,7.744,53,8,53
+		s0.512-0.098,0.707-0.293l5.736-5.736c0.391-0.391,0.391-1.023,0-1.414S13.42,45.166,13.029,45.557z"/>
+	<path style="fill: #F0C419;" d="M46.971,45.557c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414l5.736,5.736
+		C51.488,52.902,51.744,53,52,53s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414L46.971,45.557z"/>
+	<path style="fill: #F0C419;" d="M8.707,7.293c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414l5.736,5.736
+		c0.195,0.195,0.451,0.293,0.707,0.293s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414L8.707,7.293z"/>
+	<path style="fill: #F0C419;" d="M50.251,21.404c0.162,0.381,0.532,0.61,0.921,0.61c0.13,0,0.263-0.026,0.39-0.08l2.762-1.172
+		c0.508-0.216,0.746-0.803,0.53-1.311s-0.804-0.746-1.311-0.53l-2.762,1.172C50.272,20.309,50.035,20.896,50.251,21.404z"/>
+	<path style="fill: #F0C419;" d="M9.749,38.596c-0.216-0.508-0.803-0.746-1.311-0.53l-2.762,1.172
+		c-0.508,0.216-0.746,0.803-0.53,1.311c0.162,0.381,0.532,0.61,0.921,0.61c0.13,0,0.263-0.026,0.39-0.08l2.762-1.172
+		C9.728,39.691,9.965,39.104,9.749,38.596z"/>
+	<path style="fill: #F0C419;" d="M54.481,38.813L51.7,37.688c-0.511-0.207-1.095,0.041-1.302,0.553
+		c-0.207,0.512,0.041,1.095,0.553,1.302l2.782,1.124c0.123,0.049,0.25,0.073,0.374,0.073c0.396,0,0.771-0.236,0.928-0.626
+		C55.241,39.603,54.994,39.02,54.481,38.813z"/>
+	<path style="fill: #F0C419;" d="M5.519,21.188L8.3,22.312c0.123,0.049,0.25,0.073,0.374,0.073c0.396,0,0.771-0.236,0.928-0.626
+		c0.207-0.512-0.041-1.095-0.553-1.302l-2.782-1.124c-0.513-0.207-1.095,0.04-1.302,0.553C4.759,20.397,5.006,20.98,5.519,21.188z"
+		/>
+	<path style="fill: #F0C419;" d="M39.907,50.781c-0.216-0.508-0.803-0.745-1.311-0.53c-0.508,0.216-0.746,0.803-0.53,1.311
+		l1.172,2.762c0.162,0.381,0.532,0.61,0.921,0.61c0.13,0,0.263-0.026,0.39-0.08c0.508-0.216,0.746-0.803,0.53-1.311L39.907,50.781z"
+		/>
+	<path style="fill: #F0C419;" d="M21.014,9.829c0.13,0,0.263-0.026,0.39-0.08c0.508-0.216,0.746-0.803,0.53-1.311l-1.172-2.762
+		c-0.215-0.509-0.802-0.747-1.311-0.53c-0.508,0.216-0.746,0.803-0.53,1.311l1.172,2.762C20.254,9.6,20.625,9.829,21.014,9.829z"/>
+	<path style="fill: #F0C419;" d="M21.759,50.398c-0.511-0.205-1.095,0.04-1.302,0.553l-1.124,2.782
+		c-0.207,0.512,0.041,1.095,0.553,1.302c0.123,0.049,0.25,0.073,0.374,0.073c0.396,0,0.771-0.236,0.928-0.626l1.124-2.782
+		C22.519,51.188,22.271,50.605,21.759,50.398z"/>
+	<path style="fill: #F0C419;" d="M38.615,9.675c0.396,0,0.771-0.236,0.928-0.626l1.124-2.782c0.207-0.512-0.041-1.095-0.553-1.302
+		c-0.511-0.207-1.095,0.041-1.302,0.553L37.688,8.3c-0.207,0.512,0.041,1.095,0.553,1.302C38.364,9.651,38.491,9.675,38.615,9.675z"
+		/>
+</g>
+<circle style="fill: #F0C419;" cx="30" cy="30" r="20"/>
+<circle style="fill: #EDE21B;" cx="30" cy="30" r="15"/>
+</svg>

+ 19 - 0
src/assets/svg/login-bg-dark.svg

@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="6395" height="1080" viewBox="0 0 6395 1080">
+  <defs>
+    <clipPath id="clip-path">
+      <rect id="Rectangle_73" data-name="Rectangle 73" width="6395" height="1079" transform="translate(-5391)" fill="#fff"/>
+    </clipPath>
+    <linearGradient id="linear-gradient" x1="0.631" y1="0.5" x2="0.958" y2="0.488" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#2e364a"/>
+      <stop offset="1" stop-color="#2c344a"/>
+    </linearGradient>
+  </defs>
+  <g id="Web_1920_1" data-name="Web 1920 – 1" clip-path="url(#clip-Web_1920_1)">
+    <g id="Mask_Group_1" data-name="Mask Group 1" transform="translate(5391)" clip-path="url(#clip-path)">
+      <g id="Group_118" data-name="Group 118" transform="translate(-419.333 -1.126)">
+        <path id="Path_142" data-name="Path 142" d="M6271.734-6.176s-222.478,187.809-55.349,583.254c44.957,106.375,81.514,205.964,84.521,277,8.164,192.764-156.046,268.564-156.046,268.564l-653.53-26.8L5475.065-21.625Z" transform="translate(-4876.383)" fill="#2d3750"/>
+        <path id="Union_6" data-name="Union 6" d="M-2631.1,1081.8v-1.6H-8230.9V.022h5599.8V0h759.7s-187.845,197.448-91.626,488.844c49.167,148.9,96.309,256.289,104.683,362.118,7.979,100.852-57.98,201.711-168.644,254.286-65.858,31.29-144.552,42.382-223.028,42.383C-2441.2,1147.632-2631.1,1081.8-2631.1,1081.8Z" transform="translate(3259.524 0.803)" fill="url(#linear-gradient)"/>
+      </g>
+    </g>
+  </g>
+</svg>

+ 2 - 2
src/assets/svg/login-bg.svg

@@ -4,8 +4,8 @@
       <rect id="Rectangle_73" data-name="Rectangle 73" width="6395" height="1079" transform="translate(-5391)" fill="#fff"/>
     </clipPath>
     <linearGradient id="linear-gradient" x1="0.747" y1="0.222" x2="0.973" y2="0.807" gradientUnits="objectBoundingBox">
-      <stop offset="0" stop-color="#2b51b4"/>
-      <stop offset="1" stop-color="#1c3faa"/>
+      <stop offset="0" stop-color="#2c41b4"/>
+      <stop offset="1" stop-color="#1b4fab"/>
     </linearGradient>
   </defs>
   <g id="Mask_Group_1" data-name="Mask Group 1" transform="translate(5391)" clip-path="url(#clip-path)">

+ 2 - 1
src/components/Application/index.ts

@@ -2,6 +2,7 @@ import AppLogo from './src/AppLogo.vue';
 import AppProvider from './src/AppProvider.vue';
 import AppSearch from './src/search/AppSearch.vue';
 import AppLocalePicker from './src/AppLocalePicker.vue';
+import AppDarkModeToggle from './src/AppDarkModeToggle.vue';
 
 export { useAppProviderContext } from './src/useAppContext';
-export { AppLogo, AppProvider, AppSearch, AppLocalePicker };
+export { AppLogo, AppProvider, AppSearch, AppLocalePicker, AppDarkModeToggle };

+ 111 - 0
src/components/Application/src/AppDarkModeToggle.vue

@@ -0,0 +1,111 @@
+<template>
+  <div
+    v-if="getShowDarkModeToggle"
+    :class="[
+      prefixCls,
+      `${prefixCls}--${size}`,
+      {
+        [`${prefixCls}--dark`]: isDark,
+      },
+    ]"
+    @click="toggleDarkMode"
+  >
+    <div :class="`${prefixCls}-inner`"> </div>
+    <SvgIcon size="14" name="sun" />
+    <SvgIcon size="14" name="moon" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, computed } from 'vue';
+
+  import { useDesign } from '/@/hooks/web/useDesign';
+
+  import { SvgIcon } from '/@/components/Icon';
+  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
+  import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
+  import { updateDarkTheme } from '/@/logics/theme/dark';
+
+  import { ThemeEnum } from '/@/enums/appEnum';
+
+  export default defineComponent({
+    name: 'DarkModeToggle',
+    components: { SvgIcon },
+    props: {
+      size: {
+        type: String,
+        default: 'default',
+        validate: (val) => ['default', 'large'].includes(val),
+      },
+    },
+    setup() {
+      const { prefixCls } = useDesign('dark-mode-toggle');
+      const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
+      const isDark = computed(() => getDarkMode.value === ThemeEnum.DARK);
+      function toggleDarkMode() {
+        const darkMode = getDarkMode.value === ThemeEnum.DARK ? ThemeEnum.LIGHT : ThemeEnum.DARK;
+        setDarkMode(darkMode);
+        updateDarkTheme(darkMode);
+        updateHeaderBgColor();
+        updateSidebarBgColor();
+      }
+
+      return {
+        isDark,
+        prefixCls,
+        toggleDarkMode,
+        getShowDarkModeToggle,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  @prefix-cls: ~'@{namespace}-dark-mode-toggle';
+
+  html[data-theme='dark'] {
+    .@{prefix-cls} {
+      border: 1px solid rgb(196, 188, 188);
+    }
+  }
+
+  .@{prefix-cls} {
+    position: relative;
+    display: flex;
+    width: 50px;
+    height: 26px;
+    padding: 0 6px;
+    margin-left: auto;
+    cursor: pointer;
+    background-color: #151515;
+    border-radius: 30px;
+    justify-content: space-between;
+    align-items: center;
+
+    &-inner {
+      position: absolute;
+      z-index: 1;
+      width: 18px;
+      height: 18px;
+      background-color: #fff;
+      border-radius: 50%;
+      transition: transform 0.5s, background-color 0.5s;
+      will-change: transform;
+    }
+
+    &--dark {
+      .@{prefix-cls}-inner {
+        transform: translateX(calc(100% + 2px));
+      }
+    }
+
+    &--large {
+      width: 72px;
+      height: 34px;
+      padding: 0 10px;
+
+      .@{prefix-cls}-inner {
+        width: 26px;
+        height: 26px;
+      }
+    }
+  }
+</style>

+ 2 - 2
src/components/Application/src/search/AppSearchFooter.vue

@@ -42,9 +42,9 @@
     padding: 0 16px;
     font-size: 12px;
     color: #666;
-    background: rgb(255 255 255);
+    background: @component-background;
+    border-top: 1px solid @border-color-base;
     border-radius: 0 0 16px 16px;
-    box-shadow: 0 -1px 0 0 #e0e3e8, 0 -3px 6px 0 rgba(69, 98, 155, 0.12);
     align-items: center;
     flex-shrink: 0;
 

+ 2 - 5
src/components/Application/src/search/AppSearchModal.vue

@@ -190,12 +190,10 @@
     &-content {
       position: relative;
       width: 632px;
-      // padding: 14px;
       margin: 0 auto auto auto;
-      background: #f5f6f7;
+      background: @component-background;
       border-radius: 16px;
       box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
-      // box-shadow: inset 1px 1px 0 0 hsla(0, 0%, 100%, 0.5), 0 3px 8px 0 #555a64;
       flex-direction: column;
     }
 
@@ -253,8 +251,7 @@
         font-size: 14px;
         color: @text-color-base;
         cursor: pointer;
-        // background: @primary-color;
-        background: #fff;
+        background: @component-background;
         border-radius: 4px;
         box-shadow: 0 1px 3px 0 #d4d9e1;
         align-items: center;

+ 1 - 1
src/components/Container/src/collapse/CollapseContainer.vue

@@ -101,7 +101,7 @@
   @prefix-cls: ~'@{namespace}-collapse-container';
 
   .@{prefix-cls} {
-    background: #fff;
+    background: @component-background;
     border-radius: 2px;
     transition: all 0.3s ease-in-out;
 

+ 2 - 2
src/components/ContextMenu/src/index.less

@@ -22,7 +22,7 @@
 
     &:not(.ant-menu-item-disabled):hover {
       color: @text-color-base;
-      background: #eee;
+      background: @item-hover-bg;
     }
   }
 }
@@ -36,7 +36,7 @@
   width: 156px;
   margin: 0;
   list-style: none;
-  background-color: #fff;
+  background-color: @component-background;
   border: 1px solid rgba(0, 0, 0, 0.08);
   border-radius: 0.25rem;
   box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1),

+ 1 - 1
src/components/Drawer/src/BasicDrawer.vue

@@ -221,7 +221,7 @@
     .ant-drawer-body {
       height: calc(100% - @header-height);
       padding: 0;
-      background-color: #fff;
+      background-color: @component-background;
 
       .scrollbar__wrap {
         padding: 16px !important;

+ 1 - 1
src/components/Drawer/src/components/DrawerFooter.vue

@@ -74,7 +74,7 @@
     width: 100%;
     padding: 0 12px 0 20px;
     text-align: right;
-    background: #fff;
+    background: @component-background;
     border-top: 1px solid @border-color-base;
 
     > * {

+ 1 - 1
src/components/Form/src/components/FormItem.vue

@@ -258,7 +258,7 @@
         const { label, helpMessage, helpComponentProps, subLabel } = props.schema;
         const renderLabel = subLabel ? (
           <span>
-            {label} <span style="color:#00000073">{subLabel}</span>
+            {label} <span class="text-secondary">{subLabel}</span>
           </span>
         ) : (
           label

+ 9 - 22
src/components/Loading/src/index.vue

@@ -1,16 +1,15 @@
 <template>
-  <section class="full-loading" :class="{ absolute }" v-show="loading" :style="getStyle">
+  <section class="full-loading" :class="{ absolute }" v-show="loading">
     <Spin v-bind="$attrs" :tip="tip" :size="size" :spinning="loading" />
   </section>
 </template>
 <script lang="ts">
-  import { computed, CSSProperties, PropType } from 'vue';
+  import { PropType } from 'vue';
 
   import { defineComponent } from 'vue';
   import { Spin } from 'ant-design-vue';
 
   import { SizeEnum } from '/@/enums/sizeEnum';
-  import { ThemeEnum } from '/@/enums/appEnum';
 
   export default defineComponent({
     name: 'Loading',
@@ -38,25 +37,6 @@
       background: {
         type: String as PropType<string>,
       },
-      theme: {
-        type: String as PropType<'dark' | 'light'>,
-        default: 'light',
-      },
-    },
-    setup(props) {
-      const getStyle = computed(
-        (): CSSProperties => {
-          const { background, theme } = props;
-          const bgColor = background
-            ? background
-            : theme === ThemeEnum.DARK
-            ? 'rgba(0, 0, 0, 0.2)'
-            : 'rgba(240, 242, 245, 0.4)';
-          return { background: bgColor };
-        }
-      );
-
-      return { getStyle };
     },
   });
 </script>
@@ -71,6 +51,7 @@
     height: 100%;
     justify-content: center;
     align-items: center;
+    background: rgba(240, 242, 245, 0.4);
 
     &.absolute {
       position: absolute;
@@ -79,4 +60,10 @@
       z-index: 300;
     }
   }
+
+  html[data-theme='dark'] {
+    .full-loading {
+      background: @modal-mask-bg;
+    }
+  }
 </style>

+ 20 - 2
src/components/Markdown/src/index.vue

@@ -10,7 +10,7 @@
     onUnmounted,
     nextTick,
     computed,
-    watchEffect,
+    watch,
   } from 'vue';
   import Vditor from 'vditor';
   import 'vditor/dist/index.css';
@@ -18,6 +18,7 @@
   import { propTypes } from '/@/utils/propTypes';
   import { useLocale } from '/@/locales/useLocale';
   import { useModalContext } from '../../Modal';
+  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
 
   type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
   export default defineComponent({
@@ -35,8 +36,24 @@
       const modalFn = useModalContext();
 
       const { getLocale } = useLocale();
+      const { getDarkMode } = useRootSetting();
 
-      watchEffect(() => {});
+      watch(
+        [() => getDarkMode.value, () => initedRef.value],
+        ([val]) => {
+          const vditor = unref(vditorRef);
+
+          if (!vditor) {
+            return;
+          }
+          const theme = val === 'dark' ? 'dark' : undefined;
+          vditor.setTheme(theme as 'dark');
+        },
+        {
+          immediate: true,
+          flush: 'post',
+        }
+      );
 
       const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {
         let lang: Lang;
@@ -60,6 +77,7 @@
         if (!wrapEl) return;
         const bindValue = { ...attrs, ...props };
         vditorRef.value = new Vditor(wrapEl, {
+          theme: 'classic',
           lang: unref(getCurrentLang),
           mode: 'sv',
           preview: {

+ 2 - 2
src/components/Page/src/PageFooter.vue

@@ -38,8 +38,8 @@
     align-items: center;
     padding: 0 24px;
     line-height: 44px;
-    background: #fff;
-    border-top: 1px solid #f0f0f0;
+    background: @component-background;
+    border-top: 1px solid @border-color-base;
     box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05),
       0 -12px 48px 16px rgba(0, 0, 0, 0.03);
     transition: width 0.2s;

+ 19 - 9
src/components/Page/src/PageWrapper.vue

@@ -17,11 +17,7 @@
         <slot :name="item" v-bind="data"></slot>
       </template>
     </PageHeader>
-    <div
-      class="overflow-hidden"
-      :class="[`${prefixCls}-content`, contentClass]"
-      :style="getContentStyle"
-    >
+    <div class="overflow-hidden" :class="getContentClass" :style="getContentStyle">
       <slot></slot>
     </div>
     <PageFooter v-if="getShowFooter" ref="footerRef">
@@ -87,14 +83,12 @@
 
       const getContentStyle = computed(
         (): CSSProperties => {
-          const { contentBackground, contentFullHeight, contentStyle, fixedHeight } = props;
-          const bg = contentBackground ? { backgroundColor: '#fff' } : {};
+          const { contentFullHeight, contentStyle, fixedHeight } = props;
           if (!contentFullHeight) {
-            return { ...bg, ...contentStyle };
+            return { ...contentStyle };
           }
           const height = `${unref(pageHeight)}px`;
           return {
-            ...bg,
             ...contentStyle,
             minHeight: height,
             ...(fixedHeight ? { height } : {}),
@@ -103,6 +97,17 @@
         }
       );
 
+      const getContentClass = computed(() => {
+        const { contentBackground, contentClass } = props;
+        return [
+          `${prefixCls}-content`,
+          contentClass,
+          {
+            [`${prefixCls}-content-bg`]: contentBackground,
+          },
+        ];
+      });
+
       watch(
         () => [contentHeight?.value, getShowFooter.value],
         () => {
@@ -170,6 +175,7 @@
         getShowFooter,
         pageHeight,
         omit,
+        getContentClass,
       };
     },
   });
@@ -190,6 +196,10 @@
       }
     }
 
+    &-content-bg {
+      background: @component-background;
+    }
+
     &--dense {
       .@{prefix-cls}-content {
         margin: 0;

+ 2 - 2
src/components/SimpleMenu/src/index.less

@@ -11,9 +11,9 @@
 
   &-dark&-vertical .@{simple-prefix-cls}__children,
   &-dark&-popup .@{simple-prefix-cls}__children {
-    background-color: @sider-dark-lighten-1-bg-color;
+    background-color: @sider-dark-lighten-bg-color;
     > .@{prefix-cls}-submenu-title {
-      background-color: @sider-dark-lighten-1-bg-color;
+      background-color: @sider-dark-lighten-bg-color;
     }
   }
 

+ 22 - 9
src/components/Table/src/BasicTable.vue

@@ -298,6 +298,26 @@
 
   @prefix-cls: ~'@{namespace}-basic-table';
 
+  html[data-theme='light'] {
+    .@{prefix-cls} {
+      &-row__striped {
+        td {
+          background: #fafafa;
+        }
+      }
+    }
+  }
+
+  html[data-theme='dark'] {
+    .@{prefix-cls} {
+      &-row__striped {
+        td {
+          background: rgb(255 255 255 / 4%);
+        }
+      }
+    }
+  }
+
   .@{prefix-cls} {
     &-form-container {
       padding: 16px;
@@ -305,17 +325,11 @@
       .ant-form {
         padding: 12px 10px 6px 10px;
         margin-bottom: 16px;
-        background: #fff;
+        background: @component-background;
         border-radius: 4px;
       }
     }
 
-    &-row__striped {
-      td {
-        background: #fafafa;
-      }
-    }
-
     &--inset {
       .ant-table-wrapper {
         padding: 0;
@@ -328,7 +342,7 @@
 
     .ant-table-wrapper {
       padding: 6px;
-      background: #fff;
+      background: @component-background;
       border-radius: 2px;
 
       .ant-table-title {
@@ -340,7 +354,6 @@
       }
     }
 
-    //
     .ant-table {
       width: 100%;
       overflow-x: hidden;

+ 3 - 1
src/components/Tree/src/index.vue

@@ -324,7 +324,7 @@
         const showTitle = title || toolbar || search || slots.headerTitle;
         const scrollStyle: CSSProperties = { height: 'calc(100% - 38px)' };
         return (
-          <div class={[prefixCls, 'h-full bg-white', attrs.class]}>
+          <div class={[prefixCls, 'h-full', attrs.class]}>
             {showTitle && (
               <TreeHeader
                 checkable={checkable}
@@ -361,6 +361,8 @@
   @prefix-cls: ~'@{namespace}-basic-tree';
 
   .@{prefix-cls} {
+    background: @component-background;
+
     .ant-tree-node-content-wrapper {
       position: relative;
 

+ 2 - 3
src/components/Upload/src/FileList.less

@@ -1,7 +1,6 @@
 .file-table {
   width: 100%;
   border-collapse: collapse;
-  //   border: 1px solid @border-color-light;
 
   .center {
     text-align: center;
@@ -21,12 +20,12 @@
   }
 
   thead {
-    background-color: @background-color-dark;
+    background-color: @background-color-light;
   }
 
   table,
   td,
   th {
-    border: 1px solid @border-color-light;
+    border: 1px solid @border-color-base;
   }
 }

+ 14 - 4
src/design/ant/btn.less

@@ -61,9 +61,9 @@
   &.ant-btn-link.is-disabled {
     color: rgba(0, 0, 0, 0.25) !important;
     text-shadow: none;
-    cursor: not-allowed;
-    background-color: transparent;
-    border-color: transparent;
+    cursor: not-allowed !important;
+    background-color: transparent !important;
+    border-color: transparent !important;
     box-shadow: none;
   }
 
@@ -187,7 +187,7 @@
 
   &-ghost {
     color: @button-ghost-color;
-    background-color: @white;
+    background-color: transparent;
     border-color: @button-ghost-color;
     border-width: 1px;
 
@@ -205,4 +205,14 @@
       border-color: fade(@button-ghost-color, 40%);
     }
   }
+
+  &-ghost.ant-btn-link:not([disabled='disabled']) {
+    color: @button-ghost-color;
+
+    &:hover,
+    &:focus {
+      color: @button-ghost-hover-color;
+      border-color: transparent;
+    }
+  }
 }

+ 30 - 0
src/design/ant/pagination.less

@@ -1,3 +1,33 @@
+html[data-theme='dark'] {
+  .ant-pagination {
+    &.mini {
+      .ant-pagination-prev,
+      .ant-pagination-next,
+      .ant-pagination-item {
+        background: rgb(255 255 255 / 4%) !important;
+
+        a {
+          color: #8b949e !important;
+        }
+      }
+
+      .ant-select-arrow {
+        color: @text-color-secondary !important;
+      }
+
+      .ant-pagination-item-active {
+        background: @primary-color !important;
+        border: none;
+        border-radius: none !important;
+
+        a {
+          color: @white !important;
+        }
+      }
+    }
+  }
+}
+
 .ant-pagination {
   &.mini {
     .ant-pagination-prev,

+ 4 - 27
src/design/color.less

@@ -1,4 +1,4 @@
-:root {
+html {
   // header
   --header-bg-color: #394664;
   --header-bg-hover-color: #273352;
@@ -7,16 +7,13 @@
   // sider
   --sider-dark-bg-color: #273352;
   --sider-dark-darken-bg-color: #273352;
-  --sider-dark-lighten-1-bg-color: #273352;
-  --sider-dark-lighten-2-bg-color: #273352;
+  --sider-dark-lighten-bg-color: #273352;
 }
 
 @white: #fff;
 
 @content-bg: #f4f7f9;
-// @content-bg: #f0f2f5;
 
-@basic-mask-color: fade(@white, 30%);
 // :export {
 //   name: "less";
 //   mainColor: @mainColor;
@@ -35,10 +32,7 @@
 @border-color-shallow-dark: #cececd;
 
 // Light-dark
-@border-color-light: #ebeef5;
-
-// Light-light
-@border-color-shallow-light: #f2f6fc;
+@border-color-light: @border-color-base;
 
 // =================================
 // ==============message==============
@@ -54,17 +48,6 @@
 @danger-background-color: #fef0f0;
 
 // =================================
-// ==============bg color============
-// =================================
-
-// dark
-@background-color-dark: #f4f7f9;
-// light
-@background-color-light: #f5f7fa;
-// layout content background
-@layout-content-bg-color: #f1f1f6;
-
-// =================================
 // ==============Header=============
 // =================================
 
@@ -83,14 +66,11 @@
 // let -menu
 @sider-dark-bg-color: var(--sider-dark-bg-color);
 @sider-dark-darken-bg-color: var(--sider-dark-darken-bg-color);
-@sider-dark-lighten-1-bg-color: var(--sider-dark-lighten-1-bg-color);
-@sider-dark-lighten-2-bg-color: var(--sider-dark-lighten-2-bg-color);
+@sider-dark-lighten-bg-color: var(--sider-dark-lighten-bg-color);
 
 // trigger
 @trigger-dark-hover-bg-color: rgba(255, 255, 255, 0.2);
 @trigger-dark-bg-color: rgba(255, 255, 255, 0.1);
-@trigger-light-bg-color: @white;
-@trigger-light-hover-bg-color: rgba(255, 255, 255, 0.7);
 
 // =================================
 // ==============tree============
@@ -119,9 +99,6 @@
 // Auxiliary information color-dark
 @text-color-help-dark: #909399;
 
-// Auxiliary information color-light color
-@text-color-help-light: #c0c4cc;
-
 // =================================
 // ==============breadcrumb=========
 // =================================

+ 1 - 0
src/design/index.less

@@ -2,6 +2,7 @@
 @import 'var/index.less';
 @import 'public.less';
 @import 'ant/index.less';
+@import './theme.less';
 
 input:-webkit-autofill {
   -webkit-box-shadow: 0 0 0 1000px white inset !important;

+ 31 - 0
src/design/theme.less

@@ -0,0 +1,31 @@
+.bg-white {
+  background: @component-background !important;
+}
+
+html[data-theme='light'] {
+  .text-secondary {
+    color: rgba(0, 0, 0, 0.45);
+  }
+}
+
+html[data-theme='dark'] {
+  .text-secondary {
+    color: #8b949e;
+  }
+
+  .ant-card-grid-hoverable:hover {
+    box-shadow: 0 3px 6px -4px rgb(0 0 0 / 48%), 0 6px 16px 0 rgb(0 0 0 / 32%),
+      0 9px 28px 8px rgb(0 0 0 / 20%);
+  }
+
+  .ant-alert-message,
+  .ant-alert-with-description .ant-alert-message,
+  .ant-alert-description {
+    color: rgba(0, 0, 0, 0.85);
+  }
+
+  .ant-checkbox-checked .ant-checkbox-inner::after {
+    border-top: 0;
+    border-left: 0;
+  }
+}

+ 0 - 2
src/directives/loading.ts

@@ -5,14 +5,12 @@ const loadingDirective: Directive = {
   mounted(el, binding) {
     const tip = el.getAttribute('loading-tip');
     const background = el.getAttribute('loading-background');
-    const theme = el.getAttribute('loading-theme');
     const size = el.getAttribute('loading-size');
     const fullscreen = !!binding.modifiers.fullscreen;
     const instance = createLoading(
       {
         tip,
         background,
-        theme,
         size: size || 'large',
         loading: !!binding.value,
         absolute: !fullscreen,

+ 0 - 8
src/enums/appEnum.ts

@@ -8,17 +8,9 @@ export enum ContentEnum {
   FIXED = 'fixed',
 }
 
-// app current theme
-export enum ThemeModeEnum {
-  LIGHT = 'light-mode',
-  DARK = 'dark-mode',
-  SEMI_DARK = 'semi-dark-mode',
-}
-
 // menu theme enum
 export enum ThemeEnum {
   DARK = 'dark',
-
   LIGHT = 'light',
 }
 

+ 2 - 0
src/enums/cacheEnum.ts

@@ -15,6 +15,8 @@ export const PROJ_CFG_KEY = 'PROJ__CFG__KEY__';
 // lock info
 export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__';
 
+export const APP_DARK_MODE_KEY_ = '__APP__DARK__MODE__';
+
 // base global local key
 export const APP_LOCAL_CACHE_KEY = 'COMMON__LOCAL__KEY__';
 

+ 12 - 0
src/hooks/setting/useRootSetting.ts

@@ -4,6 +4,7 @@ import { computed, unref } from 'vue';
 
 import { appStore } from '/@/store/modules/app';
 import { ContentEnum } from '/@/enums/appEnum';
+import { ThemeEnum } from '../../enums/appEnum';
 
 type RootSetting = Omit<
   ProjectConfig,
@@ -48,6 +49,10 @@ const getGrayMode = computed(() => unref(getRootSetting).grayMode);
 
 const getLockTime = computed(() => unref(getRootSetting).lockTime);
 
+const getShowDarkModeToggle = computed(() => unref(getRootSetting).showDarkModeToggle);
+
+const getDarkMode = computed(() => appStore.getDarkMode);
+
 const getLayoutContentMode = computed(() =>
   unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
 );
@@ -56,6 +61,10 @@ function setRootSetting(setting: Partial<RootSetting>) {
   appStore.commitProjectConfigState(setting);
 }
 
+function setDarkMode(mode: ThemeEnum) {
+  appStore.commitDarkMode(mode);
+}
+
 export function useRootSetting() {
   return {
     setRootSetting,
@@ -80,5 +89,8 @@ export function useRootSetting() {
     getContentMode,
     getLockTime,
     getThemeColor,
+    getDarkMode,
+    setDarkMode,
+    getShowDarkModeToggle,
   };
 }

+ 0 - 57
src/hooks/web/useApexCharts.ts

@@ -1,57 +0,0 @@
-import { useTimeoutFn } from '/@/hooks/core/useTimeout';
-import { unref, Ref, nextTick } from 'vue';
-import { tryOnUnmounted } from '@vueuse/core';
-
-interface CallBackFn {
-  (instance: Nullable<ApexCharts>): void;
-}
-
-export function useApexCharts(elRef: Ref<HTMLDivElement>) {
-  let chartInstance: Nullable<ApexCharts> = null;
-
-  function setOptions(options: any, callback?: CallBackFn) {
-    nextTick(() => {
-      useTimeoutFn(async () => {
-        const el = unref(elRef);
-
-        if (!el || !unref(el)) return;
-        const ApexCharts = await (await import('apexcharts')).default;
-        chartInstance = new ApexCharts(el, options);
-
-        chartInstance && chartInstance.render();
-
-        // The callback method is added to setOptions to return the chartInstance to facilitate the re-operation of the chart, such as calling the updateOptions method to update the chart
-        callback && callback(chartInstance);
-      }, 30);
-    });
-  }
-
-  // Call the updateOptions method of ApexCharts to update the chart
-  function updateOptions(
-    chartInstance: Nullable<ApexCharts>,
-    options: any,
-    redraw = false,
-    animate = true,
-    updateSyncedCharts = true,
-    callback: CallBackFn
-  ) {
-    nextTick(() => {
-      useTimeoutFn(() => {
-        chartInstance && chartInstance.updateOptions(options, redraw, animate, updateSyncedCharts);
-
-        callback && callback(chartInstance);
-      }, 30);
-    });
-  }
-
-  tryOnUnmounted(() => {
-    if (!chartInstance) return;
-    chartInstance?.destroy?.();
-    chartInstance = null;
-  });
-
-  return {
-    setOptions,
-    updateOptions,
-  };
-}

+ 33 - 6
src/hooks/web/useECharts.ts

@@ -1,31 +1,46 @@
 import { useTimeoutFn } from '/@/hooks/core/useTimeout';
 import { tryOnUnmounted } from '@vueuse/core';
-import { unref, Ref, nextTick } from 'vue';
+import { unref, Ref, nextTick, watch, computed, ref } from 'vue';
 import type { EChartsOption } from 'echarts';
 import { useDebounce } from '/@/hooks/core/useDebounce';
 import { useEventListener } from '/@/hooks/event/useEventListener';
 import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
 
 import echarts from '/@/plugins/echarts';
+import { useRootSetting } from '../setting/useRootSetting';
 
 export function useECharts(
   elRef: Ref<HTMLDivElement>,
   theme: 'light' | 'dark' | 'default' = 'light'
 ) {
+  const { getDarkMode } = useRootSetting();
   let chartInstance: echarts.ECharts | null = null;
   let resizeFn: Fn = resize;
+  const cacheOptions = ref<EChartsOption>({});
   let removeResizeFn: Fn = () => {};
 
   const [debounceResize] = useDebounce(resize, 200);
   resizeFn = debounceResize;
 
-  function initCharts() {
+  const getOptions = computed(
+    (): EChartsOption => {
+      if (getDarkMode.value !== 'dark') {
+        return cacheOptions.value;
+      }
+      return {
+        backgroundColor: '#151515',
+        ...cacheOptions.value,
+      };
+    }
+  );
+
+  function initCharts(t = theme) {
     const el = unref(elRef);
     if (!el || !unref(el)) {
       return;
     }
 
-    chartInstance = echarts.init(el, theme);
+    chartInstance = echarts.init(el, t);
     const { removeEvent } = useEventListener({
       el: window,
       name: 'resize',
@@ -41,22 +56,23 @@ export function useECharts(
   }
 
   function setOptions(options: EChartsOption, clear = true) {
+    cacheOptions.value = options;
     if (unref(elRef)?.offsetHeight === 0) {
       useTimeoutFn(() => {
-        setOptions(options);
+        setOptions(unref(getOptions));
       }, 30);
       return;
     }
     nextTick(() => {
       useTimeoutFn(() => {
         if (!chartInstance) {
-          initCharts();
+          initCharts(getDarkMode.value);
 
           if (!chartInstance) return;
         }
         clear && chartInstance?.clear();
 
-        chartInstance?.setOption(options);
+        chartInstance?.setOption(unref(getOptions));
       }, 30);
     });
   }
@@ -65,6 +81,17 @@ export function useECharts(
     chartInstance?.resize();
   }
 
+  watch(
+    () => getDarkMode.value,
+    (theme) => {
+      if (chartInstance) {
+        chartInstance.dispose();
+        initCharts(theme);
+        setOptions(cacheOptions.value);
+      }
+    }
+  );
+
   tryOnUnmounted(() => {
     if (!chartInstance) return;
     removeResizeFn();

+ 0 - 1
src/layouts/default/header/MultipleHeader.vue

@@ -112,7 +112,6 @@
   @prefix-cls: ~'@{namespace}-layout-multiple-header';
 
   .@{prefix-cls} {
-    // margin-left: 1px;
     transition: width 0.2s;
     flex: 0 0 auto;
 

+ 0 - 1
src/layouts/default/header/components/lock/LockModal.vue

@@ -91,7 +91,6 @@
       position: relative;
       height: 240px;
       padding: 130px 30px 60px 30px;
-      background: #fff;
       border-radius: 10px;
     }
 

+ 0 - 4
src/layouts/default/header/components/user-dropdown/index.vue

@@ -131,10 +131,6 @@
     cursor: pointer;
     align-items: center;
 
-    &:hover {
-      background: @header-light-bg-hover-color;
-    }
-
     img {
       width: 24px;
       height: 24px;

+ 4 - 3
src/layouts/default/header/index.less

@@ -131,7 +131,7 @@
   }
 
   &--light {
-    background: @white;
+    background: @white !important;
     border-bottom: 1px solid @header-light-bottom-border-color;
     border-left: 1px solid @header-light-bottom-border-color;
 
@@ -165,8 +165,9 @@
   }
 
   &--dark {
-    background: @header-dark-bg-color;
-
+    background: @header-dark-bg-color !important;
+    border-bottom: 1px solid @border-color-base;
+    border-left: 1px solid @border-color-base;
     .@{header-prefix-cls}-logo {
       &:hover {
         background: @header-dark-bg-hover-color;

+ 9 - 4
src/layouts/default/setting/SettingDrawer.tsx

@@ -3,13 +3,15 @@ import { BasicDrawer } from '/@/components/Drawer/index';
 import { Divider } from 'ant-design-vue';
 import {
   TypePicker,
-  ThemePicker,
+  ThemeColorPicker,
   SettingFooter,
   SwitchItem,
   SelectItem,
   InputNumberItem,
 } from './components';
 
+import { AppDarkModeToggle } from '/@/components/Application';
+
 import { MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum';
 
 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
@@ -52,6 +54,7 @@ export default defineComponent({
       getColorWeak,
       getGrayMode,
       getLockTime,
+      getShowDarkModeToggle,
       getThemeColor,
     } = useRootSetting();
 
@@ -116,7 +119,7 @@ export default defineComponent({
 
     function renderHeaderTheme() {
       return (
-        <ThemePicker
+        <ThemeColorPicker
           colorList={HEADER_PRESET_BG_COLOR_LIST}
           def={unref(getHeaderBgColor)}
           event={HandlerEnum.HEADER_THEME}
@@ -126,7 +129,7 @@ export default defineComponent({
 
     function renderSiderTheme() {
       return (
-        <ThemePicker
+        <ThemeColorPicker
           colorList={SIDE_BAR_BG_COLOR_LIST}
           def={unref(getMenuBgColor)}
           event={HandlerEnum.MENU_THEME}
@@ -136,7 +139,7 @@ export default defineComponent({
 
     function renderMainTheme() {
       return (
-        <ThemePicker
+        <ThemeColorPicker
           colorList={APP_PRESET_COLOR_LIST}
           def={unref(getThemeColor)}
           event={HandlerEnum.CHANGE_THEME_COLOR}
@@ -404,6 +407,8 @@ export default defineComponent({
         width={330}
         wrapClassName="setting-drawer"
       >
+        {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
+        {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" size="large" />}
         <Divider>{() => t('layout.setting.navMode')}</Divider>
         {renderSidebar()}
         <Divider>{() => t('layout.setting.sysTheme')}</Divider>

+ 1 - 1
src/layouts/default/setting/components/ThemePicker.vue → src/layouts/default/setting/components/ThemeColorPicker.vue

@@ -26,7 +26,7 @@
   import { HandlerEnum } from '../enum';
 
   export default defineComponent({
-    name: 'ThemePicker',
+    name: 'ThemeColorPicker',
     components: { CheckOutlined },
     props: {
       colorList: {

+ 6 - 12
src/layouts/default/setting/components/TypePicker.vue

@@ -74,7 +74,8 @@
         content: '';
       }
 
-      &--sidebar {
+      &--sidebar,
+      &--light {
         &::before {
           top: 0;
           left: 0;
@@ -124,6 +125,10 @@
         }
       }
 
+      &--dark {
+        background-color: #273352;
+      }
+
       &--mix-sidebar {
         &::before {
           top: 0;
@@ -152,17 +157,6 @@
         }
       }
 
-      // &::after {
-      //   position: absolute;
-      //   top: 50%;
-      //   left: 50%;
-      //   width: 0;
-      //   height: 0;
-      //   content: '';
-      //   opacity: 0;
-      //   transition: all 0.3s;
-      // }
-
       &:hover,
       &--active {
         padding: 12px;

+ 1 - 1
src/layouts/default/setting/components/index.ts

@@ -1,7 +1,7 @@
 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
 
 export const TypePicker = createAsyncComponent(() => import('./TypePicker.vue'));
-export const ThemePicker = createAsyncComponent(() => import('./ThemePicker.vue'));
+export const ThemeColorPicker = createAsyncComponent(() => import('./ThemeColorPicker.vue'));
 export const SettingFooter = createAsyncComponent(() => import('./SettingFooter.vue'));
 export const SwitchItem = createAsyncComponent(() => import('./SwitchItem.vue'));
 export const SelectItem = createAsyncComponent(() => import('./SelectItem.vue'));

+ 1 - 0
src/layouts/default/setting/enum.ts

@@ -14,6 +14,7 @@ const { t } = useI18n();
 export enum HandlerEnum {
   CHANGE_LAYOUT,
   CHANGE_THEME_COLOR,
+  CHANGE_THEME,
   // menu
   MENU_HAS_DRAG,
   MENU_ACCORDION,

+ 15 - 1
src/layouts/default/setting/handler.ts

@@ -6,15 +6,20 @@ import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
 import { appStore } from '/@/store/modules/app';
 import { ProjectConfig } from '/#/config';
 import { changeTheme } from '/@/logics/theme';
+import { updateDarkTheme } from '/@/logics/theme/dark';
 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
 
 export function baseHandler(event: HandlerEnum, value: any) {
   const config = handler(event, value);
   appStore.commitProjectConfigState(config);
+  if (event === HandlerEnum.CHANGE_THEME) {
+    updateHeaderBgColor();
+    updateSidebarBgColor();
+  }
 }
 
 export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConfig> {
-  const { getThemeColor } = useRootSetting();
+  const { getThemeColor, getDarkMode } = useRootSetting();
   switch (event) {
     case HandlerEnum.CHANGE_LAYOUT:
       const { mode, type, split } = value;
@@ -36,8 +41,17 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
         return {};
       }
       changeTheme(value);
+
       return { themeColor: value };
 
+    case HandlerEnum.CHANGE_THEME:
+      if (getDarkMode.value === value) {
+        return {};
+      }
+      updateDarkTheme(value);
+
+      return { darkMode: value };
+
     case HandlerEnum.MENU_HAS_DRAG:
       return { menuSetting: { canDrag: value } };
 

+ 1 - 1
src/layouts/default/sider/MixSider.vue

@@ -403,7 +403,7 @@
         }
       }
     }
-    @border-color: @sider-dark-lighten-1-bg-color;
+    @border-color: @sider-dark-lighten-bg-color;
 
     &.dark {
       &.open {

+ 23 - 41
src/layouts/default/tabs/index.less

@@ -1,10 +1,19 @@
 @prefix-cls: ~'@{namespace}-multiple-tabs';
 
+html[data-theme='dark'] {
+  .@{prefix-cls} {
+    .ant-tabs-tab {
+      border-bottom: 1px solid @border-color-base;
+    }
+  }
+}
+
 .@{prefix-cls} {
   z-index: 10;
   height: @multiple-height + 2;
   line-height: @multiple-height + 2;
-  background: @white;
+  background: @component-background;
+  border-bottom: 1px solid @border-color-base;
   box-shadow: 0 1px 2px 0 rgba(29, 35, 41, 0.05);
 
   .ant-tabs-small {
@@ -15,7 +24,7 @@
     .ant-tabs-card-bar {
       height: @multiple-height;
       margin: 0;
-      background: @white;
+      background: @component-background;
       border: 0;
       box-shadow: none;
 
@@ -28,35 +37,14 @@
         height: calc(@multiple-height - 2px);
         padding-right: 12px;
         line-height: calc(@multiple-height - 2px);
-        color: @text-color-call-out;
-        background: @white;
-        border-bottom: 1px solid @header-light-bottom-border-color;
+        color: @text-color-base;
+        background: @component-background;
         transition: none;
 
-        // &:not(.ant-tabs-tab-active)::before {
-        //   position: absolute;
-        //   top: -1px;
-        //   left: 50%;
-        //   width: 100%;
-        //   height: 2px;
-        //   background-color: @primary-color;
-        //   content: '';
-        //   opacity: 0;
-        //   transform: translate(-50%, 0) scaleX(0);
-        //   transform-origin: center;
-        //   transition: none;
-        // }
-
         &:hover {
           .ant-tabs-close-x {
             opacity: 1;
           }
-
-          // &:not(.ant-tabs-tab-active)::before {
-          //   opacity: 1;
-          //   transform: translate(-50%, 0) scaleX(1);
-          //   transition: all 0.3s ease-in-out;
-          // }
         }
 
         .ant-tabs-close-x {
@@ -85,26 +73,20 @@
         }
       }
 
+      .ant-tabs-tab:not(.ant-tabs-tab-active) {
+        &:hover {
+          color: @primary-color;
+        }
+      }
+
       .ant-tabs-tab-active {
         position: relative;
-        padding-left: 26px;
+        padding-left: 18px;
         color: @white;
-        background: fade(@primary-color, 100%);
+        background: @primary-color;
         border: 0;
         transition: none;
 
-        &::before {
-          position: absolute;
-          top: calc(50% - 3px);
-          left: 8px;
-          width: 6px;
-          height: 6px;
-          background: #fff;
-          border-radius: 50%;
-          content: '';
-          transition: none;
-        }
-
         .ant-tabs-close-x {
           opacity: 1;
         }
@@ -158,10 +140,10 @@
       width: 36px;
       height: @multiple-height;
       line-height: @multiple-height;
-      color: #666;
+      color: @text-color-secondary;
       text-align: center;
       cursor: pointer;
-      border-left: 1px solid #eee;
+      border-left: 1px solid @border-color-base;
 
       &:hover {
         color: @text-color-base;

+ 3 - 0
src/locales/lang/en/common.ts

@@ -14,4 +14,7 @@ export default {
 
   redo: 'Refresh',
   back: 'Back',
+
+  light: 'Light',
+  dark: 'Dark',
 };

+ 1 - 0
src/locales/lang/en/layout/setting.ts

@@ -30,6 +30,7 @@ export default {
 
   drawerTitle: 'Configuration',
 
+  darkMode: 'Dark mode',
   navMode: 'Navigation mode',
   interfaceFunction: 'Interface function',
   interfaceDisplay: 'Interface display',

+ 0 - 1
src/locales/lang/en/routes/demo/charts.ts

@@ -6,5 +6,4 @@ export default {
   map: 'Map',
   line: 'Line',
   pie: 'Pie',
-  apexChart: 'ApexChart',
 };

+ 3 - 0
src/locales/lang/zh_CN/common.ts

@@ -14,4 +14,7 @@ export default {
 
   redo: '刷新',
   back: '返回',
+
+  light: '亮色主题',
+  dark: '黑暗主题',
 };

+ 1 - 0
src/locales/lang/zh_CN/layout/setting.ts

@@ -29,6 +29,7 @@ export default {
 
   drawerTitle: '项目配置',
 
+  darkMode: '主题',
   navMode: '导航栏模式',
   interfaceFunction: '界面功能',
   interfaceDisplay: '界面显示',

+ 0 - 1
src/locales/lang/zh_CN/routes/demo/charts.ts

@@ -6,5 +6,4 @@ export default {
   map: '地图',
   line: '折线图',
   pie: '饼图',
-  apexChart: 'ApexChart',
 };

+ 23 - 9
src/logics/initAppConfig.ts

@@ -9,6 +9,7 @@ import projectSetting from '/@/settings/projectSetting';
 import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
 import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
 import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
+import { updateDarkTheme } from '/@/logics/theme/dark';
 import { changeTheme } from '/@/logics/theme';
 
 import { appStore } from '/@/store/modules/app';
@@ -19,30 +20,43 @@ import { getCommonStoragePrefix, getStorageShortName } from '/@/utils/env';
 import { primaryColor } from '../../build/config/themeConfig';
 import { Persistent } from '/@/utils/cache/persistent';
 import { deepMerge } from '/@/utils';
+import { ThemeEnum } from '../enums/appEnum';
 
 // Initial project configuration
 export function initAppConfigStore() {
   let projCfg: ProjectConfig = Persistent.getLocal(PROJ_CFG_KEY) as ProjectConfig;
   projCfg = deepMerge(projectSetting, projCfg || {});
+  const darkMode = appStore.getDarkMode;
+  const {
+    colorWeak,
+    grayMode,
+    themeColor,
+
+    headerSetting: { bgColor: headerBgColor } = {},
+    menuSetting: { bgColor } = {},
+  } = projCfg;
   try {
-    const {
-      colorWeak,
-      grayMode,
-      themeColor,
-      headerSetting: { bgColor: headerBgColor } = {},
-      menuSetting: { bgColor } = {},
-    } = projCfg;
     if (themeColor && themeColor !== primaryColor) {
       changeTheme(themeColor);
     }
-    headerBgColor && updateHeaderBgColor(headerBgColor);
-    bgColor && updateSidebarBgColor(bgColor);
+
     grayMode && updateGrayMode(grayMode);
     colorWeak && updateColorWeak(colorWeak);
   } catch (error) {
     console.log(error);
   }
   appStore.commitProjectConfigState(projCfg);
+
+  // init dark mode
+  updateDarkTheme(darkMode);
+  if (darkMode === ThemeEnum.DARK) {
+    updateHeaderBgColor();
+    updateSidebarBgColor();
+  } else {
+    headerBgColor && updateHeaderBgColor(headerBgColor);
+    bgColor && updateSidebarBgColor(bgColor);
+  }
+  // init store
   localeStore.initLocale();
 
   setTimeout(() => {

+ 13 - 0
src/logics/theme/dark.ts

@@ -0,0 +1,13 @@
+import { darkCssIsReady, loadDarkThemeCss } from 'vite-plugin-theme/es/client';
+
+export async function updateDarkTheme(mode: string | null = 'light') {
+  const htmlRoot = document.getElementById('htmlRoot');
+  if (mode === 'dark') {
+    if (import.meta.env.PROD && !darkCssIsReady) {
+      await loadDarkThemeCss();
+    }
+    htmlRoot?.setAttribute('data-theme', 'dark');
+  } else {
+    htmlRoot?.setAttribute('data-theme', 'light');
+  }
+}

+ 3 - 3
src/logics/theme/index.ts

@@ -1,9 +1,9 @@
-import { getThemeColors, ThemeMode, generateColors } from '../../../build/config/themeConfig';
+import { getThemeColors, generateColors } from '../../../build/config/themeConfig';
 
 import { replaceStyleVariables } from 'vite-plugin-theme/es/client';
 import { mixLighten, mixDarken, tinycolor } from 'vite-plugin-theme/es/colorUtils';
 
-export async function changeTheme(color: string, theme?: ThemeMode) {
+export async function changeTheme(color: string) {
   const colors = generateColors({
     mixDarken,
     mixLighten,
@@ -12,6 +12,6 @@ export async function changeTheme(color: string, theme?: ThemeMode) {
   });
 
   return await replaceStyleVariables({
-    colorVariables: [...getThemeColors(color, theme), ...colors],
+    colorVariables: [...getThemeColors(color), ...colors],
   });
 }

+ 28 - 16
src/logics/theme/updateBackground.ts

@@ -1,4 +1,4 @@
-import { isHexColor, colorIsDark, lighten, darken } from '/@/utils/color';
+import { colorIsDark, lighten, darken } from '/@/utils/color';
 import { appStore } from '/@/store/modules/app';
 import { ThemeEnum } from '/@/enums/appEnum';
 import { setCssVar } from './util';
@@ -9,29 +9,35 @@ const HEADER_MENU_ACTIVE_BG_COLOR_VAR = '--header-active-menu-bg-color';
 
 const SIDER_DARK_BG_COLOR = '--sider-dark-bg-color';
 const SIDER_DARK_DARKEN_BG_COLOR = '--sider-dark-darken-bg-color';
-const SIDER_LIGHTEN_1_BG_COLOR = '--sider-dark-lighten-1-bg-color';
-const SIDER_LIGHTEN_2_BG_COLOR = '--sider-dark-lighten-2-bg-color';
+const SIDER_LIGHTEN_BG_COLOR = '--sider-dark-lighten-bg-color';
 
 /**
  * Change the background color of the top header
  * @param color
  */
-export function updateHeaderBgColor(color: string) {
-  if (!isHexColor(color)) return;
+export function updateHeaderBgColor(color?: string) {
+  const darkMode = appStore.getDarkMode === ThemeEnum.DARK;
+  if (!color) {
+    if (darkMode) {
+      color = '#151515';
+    } else {
+      color = appStore.getProjectConfig.headerSetting.bgColor;
+    }
+  }
   // bg color
   setCssVar(HEADER_BG_COLOR_VAR, color);
 
   // hover color
-  const hoverColor = lighten(color, 6);
+  const hoverColor = lighten(color!, 6);
   setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor);
   setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor);
 
   // Determine the depth of the color value and automatically switch the theme
-  const isDark = colorIsDark(color);
+  const isDark = colorIsDark(color!);
 
   appStore.commitProjectConfigState({
     headerSetting: {
-      theme: isDark ? ThemeEnum.DARK : ThemeEnum.LIGHT,
+      theme: isDark || darkMode ? ThemeEnum.DARK : ThemeEnum.LIGHT,
     },
   });
 }
@@ -40,21 +46,27 @@ export function updateHeaderBgColor(color: string) {
  * Change the background color of the left menu
  * @param color  bg color
  */
-export function updateSidebarBgColor(color: string) {
-  if (!isHexColor(color)) return;
-
+export function updateSidebarBgColor(color?: string) {
+  // if (!isHexColor(color)) return;
+  const darkMode = appStore.getDarkMode === ThemeEnum.DARK;
+  if (!color) {
+    if (darkMode) {
+      color = '#212121';
+    } else {
+      color = appStore.getProjectConfig.menuSetting.bgColor;
+    }
+  }
   setCssVar(SIDER_DARK_BG_COLOR, color);
-  setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color, 6));
-  setCssVar(SIDER_LIGHTEN_1_BG_COLOR, lighten(color, 5));
-  setCssVar(SIDER_LIGHTEN_2_BG_COLOR, lighten(color, 8));
+  setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color!, 6));
+  setCssVar(SIDER_LIGHTEN_BG_COLOR, lighten(color!, 5));
 
   // only #ffffff is light
   // Only when the background color is #fff, the theme of the menu will be changed to light
-  const isLight = ['#fff', '#ffffff'].includes(color.toLowerCase());
+  const isLight = ['#fff', '#ffffff'].includes(color!.toLowerCase());
 
   appStore.commitProjectConfigState({
     menuSetting: {
-      theme: isLight ? ThemeEnum.LIGHT : ThemeEnum.DARK,
+      theme: isLight && !darkMode ? ThemeEnum.LIGHT : ThemeEnum.DARK,
     },
   });
 }

+ 0 - 5
src/router/menus/modules/demo/charts.ts

@@ -22,11 +22,6 @@ const menu: MenuModule = {
         name: t('routes.demo.charts.googleMap'),
       },
       {
-        path: 'apexChart',
-        name: t('routes.demo.charts.apexChart'),
-      },
-
-      {
         path: 'echarts',
         name: 'Echarts',
         children: [

+ 0 - 8
src/router/routes/modules/demo/charts.ts

@@ -39,14 +39,6 @@ const charts: AppRouteModule = {
     },
 
     {
-      path: 'apexChart',
-      name: 'ApexChart',
-      meta: {
-        title: t('routes.demo.charts.apexChart'),
-      },
-      component: () => import('/@/views/demo/charts/apex/index.vue'),
-    },
-    {
       path: 'echarts',
       name: 'Echarts',
       component: getParentLayout('Echarts'),

+ 5 - 0
src/settings/designSetting.ts

@@ -1,7 +1,10 @@
+import { ThemeEnum } from '../enums/appEnum';
 export default {
   prefixCls: 'vben',
 };
 
+export const darkMode = ThemeEnum.LIGHT;
+
 // app theme preset color
 export const APP_PRESET_COLOR_LIST: string[] = [
   '#0960bd',
@@ -18,6 +21,7 @@ export const APP_PRESET_COLOR_LIST: string[] = [
 // header preset color
 export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
   '#ffffff',
+  '#151515',
   '#009688',
   '#5172DC',
   '#018ffb',
@@ -32,6 +36,7 @@ export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
 // sider preset color
 export const SIDE_BAR_BG_COLOR_LIST: string[] = [
   '#001529',
+  '#212121',
   '#273352',
   '#ffffff',
   '#191b24',

+ 4 - 4
src/settings/projectSetting.ts

@@ -9,13 +9,16 @@ import {
   SettingButtonPositionEnum,
 } from '/@/enums/appEnum';
 import { SIDE_BAR_BG_COLOR_LIST, HEADER_PRESET_BG_COLOR_LIST } from './designSetting';
-import { primaryColor, themeMode } from '../../build/config/themeConfig';
+import { primaryColor } from '../../build/config/themeConfig';
 
 // ! You need to clear the browser cache after the change
 const setting: ProjectConfig = {
   // Whether to show the configuration button
   showSettingButton: true,
 
+  // Whether to show the theme switch button
+  showDarkModeToggle: true,
+
   // `Settings` button position
   settingButtonPosition: SettingButtonPositionEnum.AUTO,
 
@@ -28,9 +31,6 @@ const setting: ProjectConfig = {
   // color
   themeColor: primaryColor,
 
-  // TODO dark theme
-  themeMode: themeMode,
-
   // Website gray mode, open for possible mourning dates
   grayMode: false,
 

+ 16 - 1
src/store/modules/app.ts

@@ -4,13 +4,16 @@ import type { BeforeMiniState } from '../types';
 import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
 import store from '/@/store';
 
-import { PROJ_CFG_KEY } from '/@/enums/cacheEnum';
+import { PROJ_CFG_KEY, APP_DARK_MODE_KEY_ } from '/@/enums/cacheEnum';
 
 import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
 import { Persistent } from '/@/utils/cache/persistent';
 import { deepMerge } from '/@/utils';
 
 import { resetRouter } from '/@/router';
+import { ThemeEnum } from '../../enums/appEnum';
+
+import { darkMode } from '/@/settings/designSetting';
 
 export interface LockInfo {
   pwd: string | undefined;
@@ -22,6 +25,8 @@ const NAME = 'app';
 hotModuleUnregisterModule(NAME);
 @Module({ dynamic: true, namespaced: true, store, name: NAME })
 export default class App extends VuexModule {
+  private darkMode;
+
   // Page loading status
   private pageLoadingState = false;
 
@@ -38,6 +43,10 @@ export default class App extends VuexModule {
     return this.pageLoadingState;
   }
 
+  get getDarkMode() {
+    return this.darkMode || localStorage.getItem(APP_DARK_MODE_KEY_) || darkMode;
+  }
+
   get getBeforeMiniState() {
     return this.beforeMiniState;
   }
@@ -56,6 +65,12 @@ export default class App extends VuexModule {
   }
 
   @Mutation
+  commitDarkMode(mode: ThemeEnum): void {
+    this.darkMode = mode;
+    localStorage.setItem(APP_DARK_MODE_KEY_, mode);
+  }
+
+  @Mutation
   commitBeforeMiniState(state: BeforeMiniState): void {
     this.beforeMiniState = state;
   }

+ 0 - 1
src/views/dashboard/analysis/components/VisitRadar.vue

@@ -32,7 +32,6 @@
             return;
           }
           setOptions({
-            backgroundColor: '#fff',
             legend: {
               bottom: 0,
               data: ['访问', '购买'],

+ 0 - 1
src/views/dashboard/workbench/components/SaleRadar.vue

@@ -32,7 +32,6 @@
             return;
           }
           setOptions({
-            backgroundColor: '#fff',
             legend: {
               bottom: 0,
               data: ['Visits', 'Sales'],

+ 0 - 1
src/views/demo/charts/SaleRadar.vue

@@ -32,7 +32,6 @@
             return;
           }
           setOptions({
-            backgroundColor: '#fff',
             legend: {
               bottom: 0,
               data: ['Visits', 'Sales'],

+ 0 - 58
src/views/demo/charts/apex/Area.vue

@@ -1,58 +0,0 @@
-<template>
-  <div ref="chartRef" :style="{ width: '100%' }"></div>
-</template>
-<script lang="ts">
-  import { defineComponent, ref, Ref, onMounted } from 'vue';
-
-  import { useApexCharts } from '/@/hooks/web/useApexCharts';
-
-  export default defineComponent({
-    setup() {
-      const chartRef = ref<HTMLDivElement | null>(null);
-      const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);
-
-      onMounted(() => {
-        setOptions({
-          series: [
-            {
-              name: 'series1',
-              data: [31, 40, 28, 51, 42, 109, 100],
-            },
-            {
-              name: 'series2',
-              data: [11, 32, 45, 32, 34, 52, 41],
-            },
-          ],
-          chart: {
-            height: 350,
-            type: 'area',
-          },
-          dataLabels: {
-            enabled: false,
-          },
-          stroke: {
-            curve: 'smooth',
-          },
-          xaxis: {
-            type: 'datetime',
-            categories: [
-              '2018-09-19T00:00:00.000Z',
-              '2018-09-19T01:30:00.000Z',
-              '2018-09-19T02:30:00.000Z',
-              '2018-09-19T03:30:00.000Z',
-              '2018-09-19T04:30:00.000Z',
-              '2018-09-19T05:30:00.000Z',
-              '2018-09-19T06:30:00.000Z',
-            ],
-          },
-          tooltip: {
-            x: {
-              format: 'dd/MM/yy HH:mm',
-            },
-          },
-        });
-      });
-      return { chartRef };
-    },
-  });
-</script>

+ 0 - 52
src/views/demo/charts/apex/Bar.vue

@@ -1,52 +0,0 @@
-<template>
-  <div ref="chartRef" :style="{ width: '100%' }"></div>
-</template>
-<script lang="ts">
-  import { defineComponent, ref, Ref, onMounted } from 'vue';
-
-  import { useApexCharts } from '/@/hooks/web/useApexCharts';
-
-  export default defineComponent({
-    setup() {
-      const chartRef = ref<HTMLDivElement | null>(null);
-      const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);
-
-      onMounted(() => {
-        setOptions({
-          series: [
-            {
-              data: [400, 430, 448, 470, 540, 580, 690, 1100, 1200, 1380],
-            },
-          ],
-          chart: {
-            type: 'bar',
-            height: 350,
-          },
-          plotOptions: {
-            bar: {
-              horizontal: true,
-            },
-          },
-          dataLabels: {
-            enabled: false,
-          },
-          xaxis: {
-            categories: [
-              'South Korea',
-              'Canada',
-              'United Kingdom',
-              'Netherlands',
-              'Italy',
-              'France',
-              'Japan',
-              'United States',
-              'China',
-              'Germany',
-            ],
-          },
-        });
-      });
-      return { chartRef };
-    },
-  });
-</script>

+ 0 - 53
src/views/demo/charts/apex/Line.vue

@@ -1,53 +0,0 @@
-<template>
-  <div ref="chartRef" :style="{ width: '100%' }"></div>
-</template>
-<script lang="ts">
-  import { defineComponent, ref, Ref, onMounted } from 'vue';
-
-  import { useApexCharts } from '/@/hooks/web/useApexCharts';
-
-  export default defineComponent({
-    setup() {
-      const chartRef = ref<HTMLDivElement | null>(null);
-      const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);
-
-      onMounted(() => {
-        setOptions({
-          series: [
-            {
-              name: 'Desktops',
-              data: [10, 41, 35, 51, 49, 62, 69, 91, 148],
-            },
-          ],
-          chart: {
-            height: 350,
-            type: 'line',
-            zoom: {
-              enabled: false,
-            },
-          },
-          dataLabels: {
-            enabled: false,
-          },
-          stroke: {
-            curve: 'straight',
-          },
-          title: {
-            text: 'Product Trends by Month',
-            align: 'left',
-          },
-          grid: {
-            row: {
-              colors: ['#f3f3f3', 'transparent'], // takes an array which will be repeated on columns
-              opacity: 0.5,
-            },
-          },
-          xaxis: {
-            categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'],
-          },
-        });
-      });
-      return { chartRef };
-    },
-  });
-</script>

+ 0 - 138
src/views/demo/charts/apex/Mixed.vue

@@ -1,138 +0,0 @@
-<template>
-  <div ref="chartRef" :style="{ width: '100%' }"></div>
-</template>
-<script lang="ts">
-  import { defineComponent, ref, Ref, onMounted } from 'vue';
-
-  import { useApexCharts } from '/@/hooks/web/useApexCharts';
-
-  export default defineComponent({
-    setup() {
-      const chartRef = ref<HTMLDivElement | null>(null);
-      const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);
-
-      onMounted(() => {
-        setOptions({
-          series: [
-            {
-              name: 'Income',
-              type: 'column',
-              data: [1.4, 2, 2.5, 1.5, 2.5, 2.8, 3.8, 4.6],
-            },
-            {
-              name: 'Cashflow',
-              type: 'column',
-              data: [1.1, 3, 3.1, 4, 4.1, 4.9, 6.5, 8.5],
-            },
-            {
-              name: 'Revenue',
-              type: 'line',
-              data: [20, 29, 37, 36, 44, 45, 50, 58],
-            },
-          ],
-          chart: {
-            height: 350,
-            type: 'line',
-            stacked: false,
-          },
-          dataLabels: {
-            enabled: false,
-          },
-          stroke: {
-            width: [1, 1, 4],
-          },
-          title: {
-            text: 'XYZ - Stock Analysis (2009 - 2016)',
-            align: 'left',
-            offsetX: 110,
-          },
-          xaxis: {
-            categories: [2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016],
-          },
-          yaxis: [
-            {
-              axisTicks: {
-                show: true,
-              },
-              axisBorder: {
-                show: true,
-                color: '#008FFB',
-              },
-              labels: {
-                style: {
-                  colors: '#008FFB',
-                },
-              },
-              title: {
-                text: 'Income (thousand crores)',
-                style: {
-                  color: '#008FFB',
-                },
-              },
-              tooltip: {
-                enabled: true,
-              },
-            },
-            {
-              seriesName: 'Income',
-              opposite: true,
-              axisTicks: {
-                show: true,
-              },
-              axisBorder: {
-                show: true,
-                color: '#00E396',
-              },
-              labels: {
-                style: {
-                  colors: '#00E396',
-                },
-              },
-              title: {
-                text: 'Operating Cashflow (thousand crores)',
-                style: {
-                  color: '#00E396',
-                },
-              },
-            },
-            {
-              seriesName: 'Revenue',
-              opposite: true,
-              axisTicks: {
-                show: true,
-              },
-              axisBorder: {
-                show: true,
-                color: '#FEB019',
-              },
-              labels: {
-                style: {
-                  colors: '#FEB019',
-                },
-              },
-              title: {
-                text: 'Revenue (thousand crores)',
-                style: {
-                  color: '#FEB019',
-                },
-              },
-            },
-          ],
-          tooltip: {
-            fixed: {
-              enabled: true,
-              position: 'topLeft', // topRight, topLeft, bottomRight, bottomLeft
-              offsetY: 30,
-              offsetX: 60,
-            },
-          },
-          legend: {
-            horizontalAlign: 'left',
-            offsetX: 40,
-          },
-        });
-      });
-      return { chartRef };
-    },
-  });
-</script>

+ 0 - 61
src/views/demo/charts/apex/SaleRadar.vue

@@ -1,61 +0,0 @@
-<template>
-  <div ref="chartRef" :style="{ width: '100%' }"></div>
-</template>
-<script lang="ts">
-  import { defineComponent, Ref, ref, onMounted } from 'vue';
-
-  import { useApexCharts } from '/@/hooks/web/useApexCharts';
-
-  export default defineComponent({
-    setup() {
-      const chartRef = ref<HTMLDivElement | null>(null);
-      const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);
-      onMounted(() => {
-        setOptions({
-          series: [
-            { name: 'Visits', data: [90, 50, 86, 40, 100, 20] },
-            { name: 'Sales', data: [70, 75, 70, 76, 20, 85] },
-          ],
-          chart: {
-            height: 350,
-            type: 'radar',
-            toolbar: {
-              show: false,
-            },
-          },
-          yaxis: {
-            show: false,
-          },
-
-          title: {
-            show: false,
-          },
-          markers: {
-            // size: 0,
-          },
-          xaxis: {
-            categories: ['2016', '2017', '2018', '2019', '2020', '2021'],
-          },
-          stroke: {
-            width: 0,
-          },
-          colors: ['#9f8ed7', '#1edec5'],
-
-          fill: {
-            type: 'gradient',
-            gradient: {
-              shade: 'dark',
-              gradientToColors: ['#8e9ad6', '#1fcadb'],
-              shadeIntensity: 1,
-              type: 'horizontal',
-              opacityFrom: 1,
-              opacityTo: 1,
-              stops: [0, 100, 100, 100],
-            },
-          },
-        });
-      });
-      return { chartRef };
-    },
-  });
-</script>

+ 0 - 46
src/views/demo/charts/apex/index.vue

@@ -1,46 +0,0 @@
-<template>
-  <div class="apex-demo p-4">
-    <div class="demo-box">
-      <Line />
-    </div>
-    <div class="demo-box">
-      <Bar />
-    </div>
-    <div class="demo-box">
-      <Area />
-    </div>
-    <div class="demo-box">
-      <Mixed />
-    </div>
-    <div class="demo-box">
-      <SaleRadar />
-    </div>
-  </div>
-</template>
-<script>
-  import { defineComponent } from 'vue';
-
-  import Line from './Line.vue';
-  import Bar from './Bar.vue';
-  import Area from './Area.vue';
-  import Mixed from './Mixed.vue';
-  import SaleRadar from './SaleRadar.vue';
-  export default defineComponent({
-    components: { Line, Bar, Area, Mixed, SaleRadar },
-    setup() {},
-  });
-</script>
-<style lang="less" scoped>
-  .apex-demo {
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: space-between;
-
-    .demo-box {
-      width: 49%;
-      margin-bottom: 20px;
-      background: #fff;
-      border-radius: 10px;
-    }
-  }
-</style>

+ 1 - 1
src/views/demo/comp/lazy/Transition.vue

@@ -29,7 +29,7 @@
       height: 2000px;
       margin: 20px auto;
       text-align: center;
-      background: #fff;
+      background: @component-background;
       justify-content: center;
       flex-direction: column;
       align-items: center;

+ 1 - 1
src/views/demo/comp/lazy/index.vue

@@ -33,7 +33,7 @@
       height: 2000px;
       margin: 20px auto;
       text-align: center;
-      background: #fff;
+      background: @component-background;
       justify-content: center;
       flex-direction: column;
       align-items: center;

+ 1 - 1
src/views/demo/comp/scroll/Action.vue

@@ -54,6 +54,6 @@
   .scroll-wrap {
     width: 50%;
     height: 300px;
-    background: #fff;
+    background: @component-background;
   }
 </style>

+ 2 - 2
src/views/demo/comp/scroll/VirtualScroll.vue

@@ -50,7 +50,7 @@
     &-wrap {
       display: flex;
       margin: 0 30%;
-      background: #fff;
+      background: @component-background;
       justify-content: center;
     }
 
@@ -58,7 +58,7 @@
       height: 40px;
       padding: 0 20px;
       line-height: 40px;
-      border-bottom: 1px solid #ddd;
+      border-bottom: 1px solid @border-color-base;
     }
   }
 </style>

+ 1 - 1
src/views/demo/comp/scroll/index.vue

@@ -26,6 +26,6 @@
   .scroll-wrap {
     width: 50%;
     height: 300px;
-    background: #fff;
+    background: @component-background;
   }
 </style>

+ 1 - 1
src/views/demo/comp/strength-meter/index.vue

@@ -26,7 +26,7 @@
 <style lang="less" scoped>
   .demo-wrap {
     width: 50%;
-    background: #fff;
+    background: @component-background;
     border-radius: 10px;
   }
 </style>

+ 3 - 2
src/views/demo/feat/tab-params/index.vue

@@ -3,17 +3,18 @@
     Current Param : {{ params }}
     <br />
     Keep Alive
-    <input />
+    <Input />
   </PageWrapper>
 </template>
 <script lang="ts">
   import { computed, defineComponent, unref } from 'vue';
   import { useRouter } from 'vue-router';
   import { PageWrapper } from '/@/components/Page';
+  import { Input } from 'ant-design-vue';
 
   export default defineComponent({
     name: 'TestTab',
-    components: { PageWrapper },
+    components: { PageWrapper, Input },
     setup() {
       const { currentRoute } = useRouter();
       return {

+ 3 - 2
src/views/demo/level/Menu111.vue

@@ -2,10 +2,11 @@
   <div class="p-5">
     多层级缓存-页面1-1-1
     <br />
-    <input />
+    <Input />
   </div>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  export default defineComponent({ name: 'Menu111Demo' });
+  import { Input } from 'ant-design-vue';
+  export default defineComponent({ name: 'Menu111Demo', components: { Input } });
 </script>

+ 3 - 2
src/views/demo/level/Menu12.vue

@@ -2,10 +2,11 @@
   <div class="p-5">
     多层级缓存-页面1-2
     <br />
-    <input />
+    <Input />
   </div>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  export default defineComponent({ name: 'Menu12Demo' });
+  import { Input } from 'ant-design-vue';
+  export default defineComponent({ name: 'Menu12Demo', components: { Input } });
 </script>

+ 3 - 1
src/views/demo/level/Menu2.vue

@@ -2,12 +2,14 @@
   <div class="p-5">
     多层级缓存-页面2
     <br />
-    <input />
+    <Input />
   </div>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
+  import { Input } from 'ant-design-vue';
   export default defineComponent({
     name: 'Menu2Demo',
+    components: { Input },
   });
 </script>

+ 2 - 4
src/views/demo/page/account/center/Application.vue

@@ -64,7 +64,6 @@
         margin-bottom: 5px;
         font-size: 16px;
         font-weight: 500;
-        color: rgba(0, 0, 0, 0.85);
 
         .icon {
           margin-top: -5px;
@@ -75,19 +74,18 @@
       &-num {
         margin-left: 24px;
         line-height: 36px;
-        color: #7d7a7a;
+        color: @text-color-secondary;
 
         span {
           margin-left: 5px;
           font-size: 18px;
-          color: #000;
         }
       }
 
       &-download {
         float: right;
         font-size: 20px !important;
-        color: #1890ff;
+        color: @primary-color;
       }
     }
   }

+ 2 - 2
src/views/demo/page/account/center/index.vue

@@ -102,7 +102,7 @@
     &-top {
       padding: 10px;
       margin: 16px 16px 12px 16px;
-      background: #fff;
+      background: @component-background;
       border-radius: 3px;
 
       &__avatar {
@@ -144,7 +144,7 @@
     &-bottom {
       padding: 10px;
       margin: 0 16px 16px 16px;
-      background: #fff;
+      background: @component-background;
       border-radius: 3px;
     }
   }

+ 2 - 2
src/views/demo/page/account/setting/index.vue

@@ -48,14 +48,14 @@
 <style lang="less">
   .account-setting {
     margin: 12px;
-    background: #fff;
+    background: @component-background;
 
     .base-title {
       padding-left: 0;
     }
 
     .ant-tabs-tab-active {
-      background-color: #e6f7ff;
+      background-color: @item-active-bg;
     }
   }
 </style>

+ 1 - 1
src/views/demo/page/desc/basic/index.vue

@@ -93,6 +93,6 @@
 <style lang="less" scoped>
   .desc-wrap {
     padding: 16px;
-    background: #fff;
+    background: @component-background;
   }
 </style>

+ 1 - 1
src/views/demo/page/form/basic/index.vue

@@ -62,6 +62,6 @@
 <style lang="less" scoped>
   .form-wrap {
     padding: 24px;
-    background: #fff;
+    background: @component-background;
   }
 </style>

+ 3 - 3
src/views/demo/page/form/step/Step1.vue

@@ -78,18 +78,18 @@
       margin: 0 0 12px;
       font-size: 16px;
       line-height: 32px;
-      color: rgba(0, 0, 0, 0.45);
+      color: @text-color;
     }
 
     h4 {
       margin: 0 0 4px;
       font-size: 14px;
       line-height: 22px;
-      color: rgba(0, 0, 0, 0.45);
+      color: @text-color;
     }
 
     p {
-      color: rgba(0, 0, 0, 0.45);
+      color: @text-color;
     }
   }
 

+ 1 - 1
src/views/demo/page/form/step/Step3.vue

@@ -44,6 +44,6 @@
   .desc-wrap {
     padding: 24px 40px;
     margin-top: 24px;
-    background: #fafafa;
+    background: @background-color-light;
   }
 </style>

+ 1 - 1
src/views/demo/page/form/step/index.vue

@@ -85,7 +85,7 @@
 <style lang="less" scoped>
   .step-form-content {
     padding: 24px;
-    background: #fff;
+    background: @component-background;
   }
 
   .step-form-form {

+ 6 - 6
src/views/demo/page/list/basic/index.vue

@@ -86,25 +86,25 @@
     &__top {
       padding: 24px;
       text-align: center;
-      background: #fff;
+      background: @component-background;
 
       &-col {
         &:not(:last-child) {
-          border-right: 1px dashed rgba(206, 206, 206, 0.4);
+          border-right: 1px dashed @border-color-base;
         }
 
         div {
           margin-bottom: 12px;
           font-size: 14px;
           line-height: 22px;
-          color: rgba(0, 0, 0, 0.45);
+          color: @text-color;
         }
 
         p {
           margin: 0;
           font-size: 24px;
           line-height: 32px;
-          color: rgba(0, 0, 0, 0.85);
+          color: @text-color;
         }
       }
     }
@@ -112,7 +112,7 @@
     &__content {
       padding: 24px;
       margin-top: 12px;
-      background: #fff;
+      background: @component-background;
 
       .list {
         position: relative;
@@ -127,7 +127,7 @@
         top: 20px;
         right: 15px;
         font-weight: normal;
-        color: #1890ff;
+        color: @primary-color;
         cursor: pointer;
       }
 

+ 2 - 2
src/views/demo/page/list/card/index.vue

@@ -84,7 +84,7 @@
         margin-bottom: 5px;
         font-size: 16px;
         font-weight: 500;
-        color: rgba(0, 0, 0, 0.85);
+        color: @text-color;
 
         .icon {
           margin-top: -5px;
@@ -97,7 +97,7 @@
         padding-top: 10px;
         padding-left: 30px;
         font-size: 14px;
-        color: rgba(0, 0, 0, 0.5);
+        color: @text-color-secondary;
       }
     }
   }

+ 4 - 4
src/views/demo/page/list/search/index.vue

@@ -91,7 +91,7 @@
 
     &__container {
       padding: 12px;
-      background: #fff;
+      background: @component-background;
     }
 
     &__title {
@@ -100,7 +100,7 @@
     }
 
     &__content {
-      color: rgba(0, 0, 0, 0.65);
+      color: @text-color-secondary;
     }
 
     &__action {
@@ -109,7 +109,7 @@
       &-item {
         display: inline-block;
         padding: 0 16px;
-        color: rgba(0, 0, 0, 0.45);
+        color: @text-color-secondary;
 
         &:nth-child(1) {
           padding-left: 0;
@@ -117,7 +117,7 @@
 
         &:nth-child(1),
         &:nth-child(2) {
-          border-right: 1px solid rgba(206, 206, 206, 0.4);
+          border-right: 1px solid @border-color-base;
         }
       }
 

+ 2 - 3
src/views/demo/page/result/fail/index.vue

@@ -34,17 +34,16 @@
 <style lang="less" scoped>
   .result-error {
     padding: 48px 32px;
-    background: #fff;
+    background: @component-background;
 
     &__content {
       padding: 24px 40px;
-      background: #fafafa;
+      background: @background-color-light;
 
       &-title {
         margin-bottom: 16px;
         font-size: 16px;
         font-weight: 500;
-        color: rgba(0, 0, 0, 0.85);
       }
 
       &-icon {

+ 2 - 2
src/views/demo/page/result/success/index.vue

@@ -48,11 +48,11 @@
 <style lang="less" scoped>
   .result-success {
     padding: 48px 32px;
-    background: #fff;
+    background: @component-background;
 
     &__content {
       padding: 24px 40px;
-      background: #fafafa;
+      background: @background-color-light;
     }
   }
 </style>

+ 1 - 1
src/views/demo/permission/back/Btn.vue

@@ -83,6 +83,6 @@
 </script>
 <style lang="less" scoped>
   .demo {
-    background: #fff;
+    background: @component-background;
   }
 </style>

+ 1 - 1
src/views/demo/permission/back/index.vue

@@ -38,6 +38,6 @@
 </script>
 <style lang="less" scoped>
   .demo {
-    background: #fff;
+    background: @component-background;
   }
 </style>

Деякі файли не було показано, через те що забагато файлів було змінено