研发图纸文件管理系统-前端项目
feat: add function of saving personal setting to local; :star:
新增:增加保存个人主题配置到本地的功能;
7个文件已修改
238 ■■■■■ 已修改文件
.env 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/setting/Setting.vue 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/setting/SettingItem.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/setting/i18n.js 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/setting.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/themeUtil.js 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env
@@ -3,4 +3,5 @@
VUE_APP_PERMISSIONS_KEY=admin.permissions
VUE_APP_ROLES_KEY=admin.roles
VUE_APP_USER_KEY=admin.user
VUE_APP_SETTING_KEY=admin.setting
VUE_APP_API_BASE_URL=http://api.iczer.com
src/App.vue
@@ -37,15 +37,11 @@
    },
    'theme.mode': function(val) {
      let closeMessage = this.$message.loading(`您选择了主题模式 ${val}, 正在切换...`)
      themeUtil.changeThemeColor(this.theme.color, val).then(() => {
        setTimeout(closeMessage, 1000)
      })
      themeUtil.changeThemeColor(this.theme.color, val).then(closeMessage)
    },
    'theme.color': function(val) {
      let closeMessage = this.$message.loading(`您选择了主题色 ${val}, 正在切换...`)
      themeUtil.changeThemeColor(val, this.theme.mode).then(() => {
        setTimeout(closeMessage, 1000)
      })
      themeUtil.changeThemeColor(val, this.theme.mode).then(closeMessage)
    }
  },
  computed: {
src/components/setting/Setting.vue
@@ -1,5 +1,9 @@
<template>
  <div class="side-setting">
    <setting-item>
      <a-button @click="saveSetting" type="primary" icon="save">{{$t('save')}}</a-button>
      <a-button @click="resetSetting" type="dashed" icon="redo" style="float: right">{{$t('reset')}}</a-button>
    </setting-item>
    <setting-item :title="$t('theme.title')">
      <img-checkbox-group
        @change="values => setTheme({...theme, mode: values[0]})"
@@ -102,12 +106,13 @@
      </a-list>
    </setting-item>
    <a-alert
      v-if="isDev"
      style="max-width: 240px; margin: -16px 0 8px; word-break: break-all"
      type="warning"
      :message="$t('alert')"
    >
    </a-alert>
    <a-button id="copyBtn" :data-clipboard-text="copyConfig" @click="copyCode" style="width: 100%" icon="copy" >{{$t('copy')}}</a-button>
    <a-button v-if="isDev" id="copyBtn" :data-clipboard-text="copyConfig" @click="copyCode" style="width: 100%" icon="copy" >{{$t('copy')}}</a-button>
  </div>
</template>
@@ -128,7 +133,8 @@
  components: {ImgCheckboxGroup, ImgCheckbox, ColorCheckboxGroup, ColorCheckbox, SettingItem},
  data() {
    return {
      copyConfig: 'Sorry, you have copied nothing O(∩_∩)O~'
      copyConfig: 'Sorry, you have copied nothing O(∩_∩)O~',
      isDev: process.env.NODE_ENV === 'development'
    }
  },
  computed: {
@@ -147,26 +153,48 @@
      return this.$el.parentNode
    },
    copyCode () {
      let config = this.extractConfig()
      this.copyConfig = `// 自定义配置,参考 ./default/setting.config.js,需要自定义的属性在这里配置即可
      module.exports = ${formatConfig(config)}
      `
      let clipboard = new Clipboard('#copyBtn')
      clipboard.on('success', () => {
        this.$message.success(`复制成功,覆盖文件 src/config/config.js 然后重启项目即可生效`).then(() => {
          const localConfig = localStorage.getItem(process.env.VUE_APP_SETTING_KEY)
          if (localConfig) {
            console.warn('检测到本地有历史保存的主题配置,想要要拷贝的配置代码生效,您可能需要先重置配置')
            this.$message.warn('检测到本地有历史保存的主题配置,想要要拷贝的配置代码生效,您可能需要先重置配置', 5)
          }
        })
        clipboard.destroy()
      })
    },
    saveSetting() {
      const closeMessage = this.$message.loading('正在保存到本地,请稍后...', 0)
      const config = this.extractConfig()
      localStorage.setItem(process.env.VUE_APP_SETTING_KEY, JSON.stringify(config))
      setTimeout(closeMessage, 800)
    },
    resetSetting() {
      this.$confirm({
        title: '重置主题会刷新页面,当前页面内容不会保留,确认重置?',
        onOk() {
          localStorage.removeItem(process.env.VUE_APP_SETTING_KEY)
          window.location.reload()
        }
      })
    },
    //提取配置
    extractConfig() {
      let config = {}
      // 提取配置
      let mySetting = this.$store.state.setting
      Object.keys(mySetting).forEach(key => {
        const dftValue = setting[key], myValue = mySetting[key]
        // 只提取与默认配置不同的配置项
        if (dftValue != undefined && !fastEqual(dftValue, myValue)) {
          config[key] = myValue
        }
      })
      this.copyConfig = '// 自定义配置,参考 ./default/setting.config.js,需要自定义的属性在这里配置即可\n'
      this.copyConfig += 'module.exports = '
      this.copyConfig += formatConfig(config)
      let clipboard = new Clipboard('#copyBtn')
      const _this = this
      clipboard.on('success', function () {
        _this.$message.success(`复制成功,覆盖文件 src/config/config.js 然后重启项目即可生效`)
        clipboard.destroy()
      })
      return config
    },
    ...mapMutations('setting', ['setTheme', 'setLayout', 'setMultiPage', 'setWeekMode',
      'setFixedSideBar', 'setFixedHeader', 'setAnimate', 'setHideSetting', 'setPageWidth'])
src/components/setting/SettingItem.vue
@@ -1,6 +1,6 @@
<template>
  <div class="setting-item">
    <h3 class="title">{{title}}</h3>
    <h3 v-if="title" class="title">{{title}}</h3>
    <slot></slot>
  </div>
</template>
src/components/setting/i18n.js
@@ -34,7 +34,9 @@
        direction: '动画方向'
      },
      alert: '拷贝配置后,直接覆盖文件 src/config/config.js 中的全部内容,然后重启即可。(注意:仅会拷贝与默认配置不同的项)',
      copy: '拷贝配置'
      copy: '拷贝配置',
      save: '保存配置',
      reset: '重置配置',
    },
    HK: {
      theme: {
@@ -69,7 +71,9 @@
        direction: '動畫方向'
      },
      alert: '拷貝配置后,直接覆蓋文件 src/config/config.js 中的全部內容,然後重啟即可。(注意:僅會拷貝與默認配置不同的項)',
      copy: '拷貝配置'
      copy: '拷貝配置',
      save: '保存配置',
      reset: '重置配置',
    },
    US: {
      theme: {
@@ -105,7 +109,9 @@
        direction: 'Direction'
      },
      alert: 'After copying the configuration code, directly cover all contents in the file src/config/config.js, then restart the server. (Note: only items that are different from the default configuration will be copied)',
      copy: 'Copy Setting'
      copy: 'Copy Setting',
      save: 'Save',
      reset: 'Reset',
    }
  }
}
src/store/modules/setting.js
@@ -2,6 +2,9 @@
import {ADMIN} from '@/config/default'
import {formatFullPath} from '@/utils/i18n'
import {filterMenu} from '@/utils/authority-utils'
import {getLocalSetting} from '@/utils/themeUtil'
const localSetting = getLocalSetting(true)
export default {
  namespaced: true,
@@ -13,6 +16,7 @@
    menuData: [],
    activatedFirst: undefined,
    ...config,
    ...localSetting
  },
  getters: {
    menuData(state, getters, rootState) {
src/utils/themeUtil.js
@@ -3,64 +3,101 @@
const {getMenuColors, getAntdColors, getThemeToggleColors, getFunctionalColors} = require('../utils/colors')
const {ANTD} = require('../config/default')
module.exports = {
  getThemeColors(color, $theme) {
    const _color = color || theme.color
    const mode = $theme || theme.mode
    const replaceColors = getThemeToggleColors(_color, mode)
    const themeColors = [
      ...replaceColors.mainColors,
      ...replaceColors.subColors,
      ...replaceColors.menuColors,
      ...replaceColors.contentColors,
      ...replaceColors.rgbColors,
      ...replaceColors.functionalColors.success,
      ...replaceColors.functionalColors.warning,
      ...replaceColors.functionalColors.error,
    ]
    return themeColors
  },
  changeThemeColor (newColor, $theme) {
    let promise = client.changer.changeColor({newColors: this.getThemeColors(newColor, $theme)})
    return promise
  },
  modifyVars(color) {
    let _color = color || theme.color
    const palettes = getAntdColors(_color, theme.mode)
    const menuColors = getMenuColors(_color, theme.mode)
    const {success, warning, error} = getFunctionalColors(theme.mode)
    const primary = palettes[5]
    return {
      'primary-color': primary,
      'primary-1': palettes[0],
      'primary-2': palettes[1],
      'primary-3': palettes[2],
      'primary-4': palettes[3],
      'primary-5': palettes[4],
      'primary-6': palettes[5],
      'primary-7': palettes[6],
      'primary-8': palettes[7],
      'primary-9': palettes[8],
      'primary-10': palettes[9],
      'info-color': primary,
      'success-color': success[5],
      'warning-color': warning[5],
      'error-color': error[5],
      'alert-info-bg-color': palettes[0],
      'alert-info-border-color': palettes[2],
      'alert-success-bg-color': success[0],
      'alert-success-border-color': success[2],
      'alert-warning-bg-color': warning[0],
      'alert-warning-border-color': warning[2],
      'alert-error-bg-color': error[0],
      'alert-error-border-color': error[2],
      'processing-color': primary,
      'menu-dark-submenu-bg': menuColors[0],
      'layout-header-background': menuColors[1],
      'layout-trigger-background': menuColors[2],
      'btn-danger-bg': error[4],
      'btn-danger-border': error[4],
      ...ANTD.theme[theme.mode]
    }
function getThemeColors(color, $theme) {
  const _color = color || theme.color
  const mode = $theme || theme.mode
  const replaceColors = getThemeToggleColors(_color, mode)
  const themeColors = [
    ...replaceColors.mainColors,
    ...replaceColors.subColors,
    ...replaceColors.menuColors,
    ...replaceColors.contentColors,
    ...replaceColors.rgbColors,
    ...replaceColors.functionalColors.success,
    ...replaceColors.functionalColors.warning,
    ...replaceColors.functionalColors.error,
  ]
  return themeColors
}
function changeThemeColor(newColor, $theme) {
  let promise = client.changer.changeColor({newColors: getThemeColors(newColor, $theme)})
  return promise
}
function modifyVars(color) {
  let _color = color || theme.color
  const palettes = getAntdColors(_color, theme.mode)
  const menuColors = getMenuColors(_color, theme.mode)
  const {success, warning, error} = getFunctionalColors(theme.mode)
  const primary = palettes[5]
  return {
    'primary-color': primary,
    'primary-1': palettes[0],
    'primary-2': palettes[1],
    'primary-3': palettes[2],
    'primary-4': palettes[3],
    'primary-5': palettes[4],
    'primary-6': palettes[5],
    'primary-7': palettes[6],
    'primary-8': palettes[7],
    'primary-9': palettes[8],
    'primary-10': palettes[9],
    'info-color': primary,
    'success-color': success[5],
    'warning-color': warning[5],
    'error-color': error[5],
    'alert-info-bg-color': palettes[0],
    'alert-info-border-color': palettes[2],
    'alert-success-bg-color': success[0],
    'alert-success-border-color': success[2],
    'alert-warning-bg-color': warning[0],
    'alert-warning-border-color': warning[2],
    'alert-error-bg-color': error[0],
    'alert-error-border-color': error[2],
    'processing-color': primary,
    'menu-dark-submenu-bg': menuColors[0],
    'layout-header-background': menuColors[1],
    'layout-trigger-background': menuColors[2],
    'btn-danger-bg': error[4],
    'btn-danger-border': error[4],
    ...ANTD.theme[theme.mode]
  }
}
function loadLocalTheme(localSetting) {
  if (localSetting) {
    let {color, mode} = localSetting.theme
    color = color || theme.color
    mode = mode || theme.mode
    changeThemeColor(color, mode)
  }
}
/**
 * 获取本地保存的配置
 * @param load {boolean} 是否加载配置中的主题
 * @returns {Object}
 */
function getLocalSetting(loadTheme) {
  let localSetting = {}
  try {
    const localSettingStr = localStorage.getItem(process.env.VUE_APP_SETTING_KEY)
    localSetting = JSON.parse(localSettingStr)
  } catch (e) {
    console.error(e)
  }
  if (loadTheme) {
    console.log(localSetting)
    loadLocalTheme(localSetting)
  }
  return localSetting
}
module.exports = {
  getThemeColors,
  changeThemeColor,
  modifyVars,
  loadLocalTheme,
  getLocalSetting
}