| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629 |
- /**
- * 主题状态管理
- */
- import {
- changeColor,
- screenWidth,
- screenHeight,
- contentWidth,
- contentHeight,
- WEAK_CLASS,
- BODY_LIMIT_CLASS,
- DISABLES_CLASS
- } from 'ele-admin';
- import {
- TAB_KEEP_ALIVE,
- KEEP_ALIVE_EXCLUDES,
- THEME_STORE_NAME
- } from '@/config/setting';
- /**
- * state 默认值
- */
- const DEFAULT_STATE = Object.freeze({
- // 页签数据
- tabs: [],
- // 是否折叠侧栏
- collapse: false,
- // 是否折叠一级侧栏
- sideNavCollapse: false,
- // 内容区域是否全屏
- bodyFullscreen: false,
- // 是否开启页签栏
- showTabs: true,
- // 是否开启页脚
- showFooter: true,
- // 顶栏风格: light(亮色), dark(暗色), primary(主色)
- headStyle: 'light',
- // 侧栏风格: light(亮色), dark(暗色)
- sideStyle: 'dark',
- // 布局风格: side(默认), top(顶栏导航), mix(混合导航)
- layoutStyle: 'side',
- // 侧栏菜单风格: default(默认), mix(双排侧栏)
- sideMenuStyle: 'default',
- // 页签风格: default(默认), dot(圆点), card(卡片)
- tabStyle: 'default',
- // 路由切换动画
- transitionName: 'slide-right',
- // 是否固定顶栏
- fixedHeader: false,
- // 是否固定侧栏
- fixedSidebar: true,
- // 是否固定主体
- fixedBody: true,
- // 内容区域宽度铺满
- bodyFull: true,
- // logo 是否自适应宽度
- logoAutoSize: false,
- // 侧栏是否彩色图标
- colorfulIcon: false,
- // 侧栏是否只保持一个子菜单展开
- sideUniqueOpen: true,
- // 是否是色弱模式
- weakMode: false,
- // 是否是暗黑模式
- darkMode: false,
- // 主题色
- color: null,
- // 主页的组件名称
- homeComponents: [],
- // 刷新路由时的参数
- routeReload: null,
- // 屏幕宽度
- screenWidth: screenWidth(),
- // 屏幕高度
- screenHeight: screenHeight(),
- // 内容区域宽度
- contentWidth: contentWidth(),
- // 内容区域高度
- contentHeight: contentHeight(),
- // 是否开启响应式
- styleResponsive: true
- });
- // 延时操作定时器
- let disableTransitionTimer, updateContentSizeTimer;
- /**
- * 读取缓存配置
- */
- function getCacheSetting () {
- try {
- const value = localStorage.getItem(THEME_STORE_NAME);
- if (value) {
- const cache = JSON.parse(value);
- if (typeof cache === 'object' && cache !== null) {
- return cache;
- }
- }
- } catch (e) {
- console.error(e);
- }
- return {};
- }
- /**
- * 缓存配置
- */
- function cacheSetting (key, value) {
- const cache = getCacheSetting();
- if (cache[key] !== value) {
- cache[key] = value;
- localStorage.setItem(THEME_STORE_NAME, JSON.stringify(cache));
- }
- }
- /**
- * 开关响应式布局
- */
- function changeStyleResponsive (styleResponsive) {
- if (styleResponsive) {
- document.body.classList.remove(BODY_LIMIT_CLASS);
- } else {
- document.body.classList.add(BODY_LIMIT_CLASS);
- }
- }
- /**
- * 切换色弱模式
- */
- function changeWeakMode (weakMode) {
- if (weakMode) {
- document.body.classList.add(WEAK_CLASS);
- } else {
- document.body.classList.remove(WEAK_CLASS);
- }
- }
- /**
- * 切换主题
- */
- function changeTheme (value, dark) {
- return new Promise((resolve, reject) => {
- try {
- changeColor(value, dark);
- resolve();
- } catch (e) {
- reject(e);
- }
- });
- }
- /**
- * 切换布局时禁用过渡动画
- */
- function disableTransition () {
- disableTransitionTimer && clearTimeout(disableTransitionTimer);
- document.body.classList.add(DISABLES_CLASS);
- disableTransitionTimer = setTimeout(() => {
- document.body.classList.remove(DISABLES_CLASS);
- }, 100);
- }
- export default {
- namespaced: true,
- state: (() => {
- const state = { ...DEFAULT_STATE };
- const cache = getCacheSetting();
- Object.keys(state).forEach((key) => {
- if (typeof cache[key] !== 'undefined') {
- state[key] = cache[key];
- }
- });
- return state;
- })(),
- getters: {
- // 需要 keep-alive 的组件
- keepAliveInclude (state) {
- if (!TAB_KEEP_ALIVE || !state.showTabs) {
- return [];
- }
- const components = new Set();
- const { reloadPath, reloadHome } = state.routeReload || {};
- state.tabs?.forEach((t) => {
- const isAlive = t.meta?.keepAlive !== false;
- const isExclude = KEEP_ALIVE_EXCLUDES.includes(t.path);
- const isReload = reloadPath && reloadPath === t.fullPath;
- if (isAlive && !isExclude && !isReload && t.components) {
- t.components.forEach((c) => {
- if (typeof c === 'string' && c) {
- components.add(c);
- }
- });
- }
- });
- if (!reloadHome) {
- state.homeComponents?.forEach((c) => {
- if (typeof c === 'string' && c) {
- components.add(c);
- }
- });
- }
- return Array.from(components);
- }
- },
- mutations: {
- SET (state, { key, value }) {
- state[key] = value;
- }
- },
- actions: {
- setTabs ({ commit }, value) {
- commit('SET', { key: 'tabs', value });
- //cacheSetting('tabs', value);
- },
- setCollapse ({ commit, dispatch }, value) {
- commit('SET', { key: 'collapse', value });
- dispatch('delayUpdateContentSize', 800);
- },
- setSideNavCollapse ({ commit, dispatch }, value) {
- commit('SET', { key: 'sideNavCollapse', value });
- dispatch('delayUpdateContentSize', 800);
- },
- setBodyFullscreen ({ commit, dispatch }, value) {
- disableTransition();
- commit('SET', { key: 'bodyFullscreen', value });
- dispatch('delayUpdateContentSize', 800);
- },
- setShowTabs ({ commit, dispatch }, value) {
- commit('SET', { key: 'showTabs', value });
- cacheSetting('showTabs', value);
- dispatch('delayUpdateContentSize');
- },
- setShowFooter ({ commit, dispatch }, value) {
- commit('SET', { key: 'showFooter', value });
- cacheSetting('showFooter', value);
- dispatch('delayUpdateContentSize');
- },
- setHeadStyle ({ commit }, value) {
- commit('SET', { key: 'headStyle', value });
- cacheSetting('headStyle', value);
- },
- setSideStyle ({ commit }, value) {
- commit('SET', { key: 'sideStyle', value });
- cacheSetting('sideStyle', value);
- },
- setLayoutStyle ({ commit, dispatch }, value) {
- disableTransition();
- commit('SET', { key: 'layoutStyle', value });
- cacheSetting('layoutStyle', value);
- dispatch('delayUpdateContentSize');
- },
- setSideMenuStyle ({ commit, dispatch }, value) {
- disableTransition();
- commit('SET', { key: 'sideMenuStyle', value });
- cacheSetting('sideMenuStyle', value);
- dispatch('delayUpdateContentSize');
- },
- setTabStyle ({ commit }, value) {
- commit('SET', { key: 'tabStyle', value });
- cacheSetting('tabStyle', value);
- },
- setTransitionName ({ commit }, value) {
- commit('SET', { key: 'transitionName', value });
- cacheSetting('transitionName', value);
- },
- setFixedHeader ({ commit }, value) {
- disableTransition();
- commit('SET', { key: 'fixedHeader', value });
- cacheSetting('fixedHeader', value);
- },
- setFixedSidebar ({ commit }, value) {
- disableTransition();
- commit('SET', { key: 'fixedSidebar', value });
- cacheSetting('fixedSidebar', value);
- },
- setFixedBody ({ commit }, value) {
- disableTransition();
- commit('SET', { key: 'fixedBody', value });
- cacheSetting('fixedBody', value);
- },
- setBodyFull ({ commit, dispatch }, value) {
- commit('SET', { key: 'bodyFull', value });
- cacheSetting('bodyFull', value);
- dispatch('delayUpdateContentSize');
- },
- setLogoAutoSize ({ commit }, value) {
- disableTransition();
- commit('SET', { key: 'logoAutoSize', value });
- cacheSetting('logoAutoSize', value);
- },
- setColorfulIcon ({ commit }, value) {
- commit('SET', { key: 'colorfulIcon', value });
- cacheSetting('colorfulIcon', value);
- },
- setSideUniqueOpen ({ commit }, value) {
- commit('SET', { key: 'sideUniqueOpen', value });
- cacheSetting('sideUniqueOpen', value);
- },
- setStyleResponsive ({ commit }, value) {
- changeStyleResponsive(value);
- commit('SET', { key: 'styleResponsive', value });
- cacheSetting('styleResponsive', value);
- },
- /**
- * 切换色弱模式
- * @param value 是否是色弱模式
- */
- setWeakMode ({ commit }, value) {
- return new Promise((resolve) => {
- changeWeakMode(value);
- commit('SET', { key: 'weakMode', value });
- cacheSetting('weakMode', value);
- resolve();
- });
- },
- /**
- * 切换暗黑模式
- * @param value 是否是暗黑模式
- */
- setDarkMode ({ commit, state }, value) {
- return new Promise((resolve, reject) => {
- changeTheme(state.color, value)
- .then(() => {
- commit('SET', { key: 'darkMode', value });
- cacheSetting('darkMode', value);
- resolve();
- })
- .catch((e) => {
- reject(e);
- });
- });
- },
- /**
- * 切换主题色
- * @param value 主题色
- */
- setColor ({ commit, state }, value) {
- return new Promise((resolve, reject) => {
- changeTheme(value, state.darkMode)
- .then(() => {
- commit('SET', { key: 'color', value });
- cacheSetting('color', value);
- resolve();
- })
- .catch((e) => {
- reject(e);
- });
- });
- },
- /**
- * 设置主页路由对应的组件名称
- * @param components 组件名称
- */
- setHomeComponents ({ commit }, value) {
- commit('SET', { key: 'homeComponents', value });
- },
- /**
- * 设置刷新路由信息
- * @param option 路由刷新参数
- */
- setRouteReload ({ commit }, value) {
- commit('SET', { key: 'routeReload', value });
- },
- /**
- * 更新屏幕尺寸
- */
- updateScreenSize ({ commit, dispatch }) {
- commit('SET', { key: 'screenWidth', value: screenWidth() });
- commit('SET', { key: 'screenHeight', value: screenHeight() });
- dispatch('updateContentSize');
- },
- /**
- * 更新内容区域尺寸
- */
- updateContentSize ({ commit }) {
- commit('SET', { key: 'contentWidth', value: contentWidth() });
- commit('SET', { key: 'contentHeight', value: contentHeight() });
- },
- /**
- * 延时更新内容区域尺寸
- * @param delay 延迟时间
- */
- delayUpdateContentSize ({ dispatch }, delay) {
- updateContentSizeTimer && clearTimeout(updateContentSizeTimer);
- updateContentSizeTimer = setTimeout(() => {
- dispatch('updateContentSize');
- }, delay ?? 100);
- },
- /**
- * 重置设置
- */
- resetSetting ({ commit, state }) {
- return new Promise((resolve, reject) => {
- disableTransition();
- [
- 'showTabs',
- 'showFooter',
- 'headStyle',
- 'sideStyle',
- 'layoutStyle',
- 'sideMenuStyle',
- 'tabStyle',
- 'transitionName',
- 'fixedHeader',
- 'fixedSidebar',
- 'fixedBody',
- 'bodyFull',
- 'logoAutoSize',
- 'colorfulIcon',
- 'sideUniqueOpen',
- 'styleResponsive',
- 'weakMode',
- 'darkMode',
- 'color'
- ].forEach((key) => {
- commit('SET', { key, value: DEFAULT_STATE[key] });
- });
- localStorage.removeItem(THEME_STORE_NAME);
- Promise.all([
- changeStyleResponsive(state.styleResponsive),
- changeWeakMode(state.weakMode),
- changeTheme(state.color, state.darkMode)
- ])
- .then(() => {
- resolve();
- })
- .catch((e) => {
- reject(e);
- });
- });
- },
- /**
- * 恢复主题
- */
- recoverTheme ({ state }) {
- // 关闭响应式布局
- if (!state.styleResponsive) {
- changeStyleResponsive(false);
- }
- // 恢复色弱模式
- if (state.weakMode) {
- changeWeakMode(true);
- }
- // 恢复主题色
- if (state.color || state.darkMode) {
- changeTheme(state.color, state.darkMode).catch((e) => {
- console.error(e);
- });
- }
- },
- /**
- * 添加页签或更新相同 key 的页签数据
- * @param data 页签数据
- */
- tabAdd ({ dispatch, state }, data) {
- if (Array.isArray(data)) {
- data.forEach((d) => {
- dispatch('tabAdd', d);
- });
- return;
- }
- const i = state.tabs.findIndex((d) => d.key === data.key);
- if (i === -1) {
- dispatch('setTabs', state.tabs.concat([data]));
- } else if (data.fullPath !== state.tabs[i].fullPath) {
- dispatch(
- 'setTabs',
- state.tabs
- .slice(0, i)
- .concat([data])
- .concat(state.tabs.slice(i + 1))
- );
- }
- },
- /**
- * 关闭页签
- * @param key 页签 key
- */
- async tabRemove ({ dispatch, state }, { key, active }) {
- const i = state.tabs.findIndex(
- (t) => t.key === key || t.fullPath === key
- );
- if (i === -1) {
- return {};
- }
- const t = state.tabs[i];
- if (!t.closable) {
- return Promise.reject();
- }
- const path = state.tabs[i - 1]?.fullPath;
- dispatch(
- 'setTabs',
- state.tabs.filter((_d, j) => j !== i)
- );
- return t.key === active ? { path, home: !path } : {};
- },
- /**
- * 关闭左侧页签
- */
- async tabRemoveLeft ({ dispatch, state }, { key, active }) {
- let index = -1; // 选中页签的 index
- for (let i = 0; i < state.tabs.length; i++) {
- if (state.tabs[i].key === active) {
- index = i;
- }
- if (state.tabs[i].key === key) {
- if (i === 0) {
- break;
- }
- const temp = state.tabs.filter((d, j) => !d.closable && j < i);
- if (temp.length === i + 1) {
- break;
- }
- const path = index === -1 ? void 0 : state.tabs[i].fullPath;
- dispatch('setTabs', temp.concat(state.tabs.slice(i)));
- return { path };
- }
- }
- return Promise.reject();
- },
- /**
- * 关闭右侧页签
- */
- async tabRemoveRight ({ dispatch, state }, { key, active }) {
- if (state.tabs.length) {
- let index = -1; // 选中页签的 index
- for (let i = 0; i < state.tabs.length; i++) {
- if (state.tabs[i].key === active) {
- index = i;
- }
- if (state.tabs[i].key === key) {
- if (i === state.tabs.length - 1) {
- return Promise.reject();
- }
- const temp = state.tabs.filter((d, j) => !d.closable && j > i);
- if (temp.length === state.tabs.length - i - 1) {
- return Promise.reject();
- }
- const path = index === -1 ? state.tabs[i].fullPath : void 0;
- dispatch(
- 'setTabs',
- state.tabs
- .slice(0, i + 1)
- .concat(state.tabs.filter((d, j) => !d.closable && j > i))
- );
- return { path };
- }
- }
- // 主页时关闭全部
- const temp = state.tabs.filter((d) => !d.closable);
- if (temp.length !== state.tabs.length) {
- dispatch('setTabs', temp);
- return { home: index !== -1 };
- }
- }
- return Promise.reject();
- },
- /**
- * 关闭其它页签
- */
- async tabRemoveOther ({ dispatch, state }, { key, active }) {
- let index = -1; // 选中页签的 index
- let path; // 关闭后跳转的 path
- const temp = state.tabs.filter((d, i) => {
- if (d.key === active) {
- index = i;
- }
- if (d.key === key) {
- path = d.fullPath;
- }
- return !d.closable || d.key === key;
- });
- if (temp.length === state.tabs.length) {
- return Promise.reject();
- }
- dispatch('setTabs', temp);
- if (index === -1) {
- return {};
- }
- return key === active ? {} : { path, home: !path };
- },
- /**
- * 关闭全部页签
- * @param active 选中页签的 key
- */
- async tabRemoveAll ({ dispatch, state }, active) {
- const t = state.tabs.find((d) => d.key === active);
- const home = typeof t !== 'undefined' && t.closable === true; // 是否跳转主页
- const temp = state.tabs.filter((d) => !d.closable);
- if (temp.length === state.tabs.length) {
- return Promise.reject();
- }
- dispatch('setTabs', temp);
- return { home };
- },
- /**
- * 修改页签
- * @param data 页签数据
- */
- tabSetItem ({ dispatch, state }, data) {
- let i = -1;
- if (data.key) {
- i = state.tabs.findIndex((d) => d.key === data.key);
- } else if (data.fullPath) {
- i = state.tabs.findIndex((d) => d.fullPath === data.fullPath);
- } else if (data.path) {
- i = state.tabs.findIndex((d) => d.path === data.path);
- }
- if (i !== -1) {
- const item = { ...state.tabs[i] };
- if (data.title) {
- item.title = data.title;
- }
- if (typeof data.closable === 'boolean') {
- item.closable = data.closable;
- }
- if (data.components) {
- item.components = data.components;
- }
- dispatch(
- 'setTabs',
- state.tabs
- .slice(0, i)
- .concat([item])
- .concat(state.tabs.slice(i + 1))
- );
- }
- }
- }
- };
|