feat: add function of saving personal setting to local; :star:
新增:增加保存个人主题配置到本地的功能;
| | |
| | | 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 |
| | |
| | | }, |
| | | '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: { |
| | |
| | | <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]})" |
| | |
| | | </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> |
| | | |
| | |
| | | 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: { |
| | |
| | | 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']) |
| | |
| | | <template> |
| | | <div class="setting-item"> |
| | | <h3 class="title">{{title}}</h3> |
| | | <h3 v-if="title" class="title">{{title}}</h3> |
| | | <slot></slot> |
| | | </div> |
| | | </template> |
| | |
| | | direction: '动画方向' |
| | | }, |
| | | alert: '拷贝配置后,直接覆盖文件 src/config/config.js 中的全部内容,然后重启即可。(注意:仅会拷贝与默认配置不同的项)', |
| | | copy: '拷贝配置' |
| | | copy: '拷贝配置', |
| | | save: '保存配置', |
| | | reset: '重置配置', |
| | | }, |
| | | HK: { |
| | | theme: { |
| | |
| | | direction: '動畫方向' |
| | | }, |
| | | alert: '拷貝配置后,直接覆蓋文件 src/config/config.js 中的全部內容,然後重啟即可。(注意:僅會拷貝與默認配置不同的項)', |
| | | copy: '拷貝配置' |
| | | copy: '拷貝配置', |
| | | save: '保存配置', |
| | | reset: '重置配置', |
| | | }, |
| | | US: { |
| | | theme: { |
| | |
| | | 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', |
| | | } |
| | | } |
| | | } |
| | |
| | | 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, |
| | |
| | | menuData: [], |
| | | activatedFirst: undefined, |
| | | ...config, |
| | | ...localSetting |
| | | }, |
| | | getters: { |
| | | menuData(state, getters, rootState) { |
| | |
| | | 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 |
| | | } |