[release] 4.0.0 (#1291)
* fix[ExternalLink]: fixed bug when url include chinese #1182 * feature: support Spanish(#1196) * fix[MockJS]: fix bug with withCredentials after using mockjs (#1194) * 修复 Mock 导致请求丢失 Cookie 的问题 修复 Mock 导致 Cookie 丢失的问题,只有在 XHR.open() 周期时,自定义的 withCredentials 会被挂载,此时检查是否是未被拦截的 xhr,并挂载自定义的 withCredentials ,无则默认为 false * update readme * perf[tagsView]: refactor the moveToTarget function (#1195) * fix[tagsView]:fixed visited view move to currentTag * edit the scroll regular friendly * tweak * fix[tagsView]: fixed moveToCurrentTag bug * feature: add pagination component (#1213) * fix[TagsView]: fixed update tags title demo bug (#1223) * chore: temporary hack cssnano bug #1222 * [release] 3.9.2 * chore: restore the hack of cssnano bug https://github.com/cssnano/cssnano/issues/643 * add an example of sort data by table (#1236) * feature: add drag select component (#1249) * feat: perfect migrate to @vue/cli-service, upgrade vue babel version (#1267) * feat: perfect migrate to @vue/cli-service, upgrade vue babel version 1. update to @vue/cli-service@3.0.5, @babel/core@7.0.0 2. use vue-cli service replace config file in build/ and config/ 3. upgrade vue and babel configuration 4. solve the svg-sprite config problem #980 refs: #932 #1087 #980 #1056 * fix: fix breadcrumb dependency * fix: fix index template and static assets load with vue-cli 3 * fix: fix import driver.js in guide page * refactor(mock): mak mock api compatible with both web-view and webpack server 1. 把 Mockjs 功能移到 server 端中间件,同时也兼容前端直接劫持 XHR 2. dev 环境下默认作为 express 中间件通过 webpack server 提供 mock api 3. prod 构建时,默认在前端用 Mockjs 劫持 XHR benefits: - dev 开发调试时能直接看到 XHR 请求,方便调试网络,能和后端对接联调 - 避开在开发时因为 Mockjs 引起的网络 bug - prod 构建时劫持 XHR,保证本项目的 Github Pages preview 能正常显示 (逻辑和 error-log 一样) - 前后台使用的 mock 是同一份代码,不会增加维护负担 ref: [#562](https://github.com/PanJiaChen/vue-element-admin/issues/562#issuecomment-378116233) * update requires the lowest version of node * add favicon * fix(TreeTable): fix `Array.prototype.concat` on custom-tree-table page * update * add test * fix bug * fix[Charts]: fixed charts resize mixins bug #1285 (#1290) * perf[Tinymce]: add searchreplace plugin * perf[avatar]:minimize the selected area of avatar on the mobile phone when user clicked avatar (#1304) * refine css * fix[DragSelect]: fixed querySelectorAll bug * perf[DragSelect]: add $listeners * fix link * fix[Breadcurmb]: fixed pathCompile bug * fix[Breadcurmb]: fixed router-link bug * perf[style]: use webpack alias instead of hard code src path (#1338) * perf[style]: use webpack alias instead of hard code src path * add sponsors * fix import path bug * update vue-router to fixed url path for non ascii urls #1362 * fix[Pagination]: apply PageSizes property to el-pagination (#1355) Apply PageSizes property to el-pagination * update dependence * add tui.editor (#1374) * tweak * add preview * fix return back bug * update guide page * fix[Tinymce]: fixed fullScreen bug #1400 * feat[Breadcrumb]: add hide Breadcrumb option #1442 * perf: use WeChat 7.0 new version icon color * refactor[login]: refactor login page style * perf[ScrollPane]: refine moveToTarget code (#1460) * feature[PDF]: add PDF demo (#1469) * perf[v-permission]: refine v-permission demo * perf[Sidebar]: refine sidebar store #1473 (#1474) * refine: GetUserInfo error message * fix typo (#1505) * perf: add sidebar width to variables.scss (#1494) * tweak * fix[ThemePicker]: fixed bug when oldVal is null (#1517) * update README.md * fix[Breadcrumb]: fixed eslint error (#1521) * fix[DndList]: fixed drag bug (#1527) https://github.com/PanJiaChen/vue-element-admin/issues/1524 * pref[Hamburger]: refactor Hamburger component (#1528) * 美化侧栏菜单切换按钮 * tweak * perf[Login Form]: optimize eye icon style (#1545) * optimiz: eye icon style for login form * change eye-open svg * perf[Sticky]: export reset method (#1550) * perf[Sticky]: refine width default value * perf[utils]: refine parseTime function (#1546) * 优化 parseTime 修复传入的时间戳是字符串类型,不能转换时间的问题 例:parseTime("1548221490638") * Update index.js * perf[UploadExcel]: optimized code (#1552) * perf: adjust the import order to make it more elegant #1537 * perf[Sidebar]: use sass variables in vue template * perf[Style]: optimize the sidebar style to make it better to set (#1568) * perf[SizeSelect]: add default size option (#1566) * fix[SIdebar]: fixed bug in mobile #1567 (#1569) * perf: fixed eslint errors * perf[Lang]: make up for miss keywords * perf: optimize some code * perf[Navbar]: refactor navbar style * perf[Login]: refine css * feature[Navbar]: add header-search component(#1591) * fix[Screenfull]: fix screenfull click bug * perf[Screenfull]: refactor screenfull component * fix[Screenfull]: fix screenfull bug (#1603) * fix typo * fearure[TagsView]: add affix option (#1577) * perf[utils]: optimize code * perf[utils]: optimizate variable name * perf[Navbar]: add scroll bar when the subMenu is too long (#1619) * perf[ThemePicker]: refine updateStyle function (#554) * theme replacing should cut tons of irrelevant css * perf[ResizeHandler]: optimized the judgment of isMobile (#1633) perf[ResizeHandler]: optimized the judgment of isMobile * fix[Sidebar]: fixed infinite loop bug(#1333) * fixed infinite loop Bug when in hasOneShowingChild Edit the onlyOneChild * tweak * fix[Sidebar]: data should return a object * perf[Sidebar]: optimize code logic (#1349) * fix[TagsView]: fixed refresh affixed-tag bug (#1653) * perf[utils.js]: refactor byteLength function (#1650) * perf[TagsView]: refine code * perf[TagsView]: set the scrollPane as a business component (#1660) * fix[DragTable]: support multiple drag-table (#1666) * perf[Tree-Table]: refactor tree-table * perf[Tree-Table]: organize the structure and add documentation (#1673) * fix[Sidebar]: fixed nested router hover bug * update version * set preserveWhitespace * lint code * fix jest test case * update config * bump * remove empty file * docs: add link * fix[Sidebar]: fixed collapse animation problem (#1690) * fix[Tree-Table]: fixed update item data bug (#1692) * fix[Waves-Directive]: fixed v-waves does not support update (#1705) * update husky * rm cli-plugin-eslint * add settings (#1707) * refine settings * fix[utils]: fixed param2Obj not decoding plus sign (#1712) * feature[Directive]: add auto-height table directive (#1702) * fix bug * feature[Permission]: add role permission management page (#1605) * feature[Excel]: support export merged header export (#1718) * feature[Excel]: add export merge header excel demo * lint * refine theme color * add role mock * tweak mock * fix[Excel]: fixed export merge-header excel bug * refine code * add ThemePicker to setting * fix[HeaderSearch]: fixed bug in vue2.6+ (#1733) * fix[Sticky]: fixed bug when set stickyTop * perf[Sticky]: refine demo * refine code * tweak mock * vuex add namespaced * fix[Excel]: fixed export bug (#1736) * rm * refactor permission * perf[ThemePicker]: add predefine (#1743) * fix[Utils]: fixed deepClone error msg (#1748) * feature: add fixedHeader settings * fix style in mobile * fix chore * perf[Eslint]: update eslint rules * feature: add create template (#1762) * add comment * update vue.config.js * feature: add sidebar logo (#1767) * rm * perf settings * bump * refine script and css * update * refine settings * refine config * update docs * refine * rm * fix jest * add theme setting * dump vue-cli * perf: remove redundant code * update element-ui * fix sticky demo bug * docs * fixed password input bug * refine login form css * remove tree-table * update version * mock error * refine layout name * refine
This commit is contained in:
		@@ -1,59 +1,64 @@
 | 
			
		||||
import Cookies from 'js-cookie'
 | 
			
		||||
 | 
			
		||||
const app = {
 | 
			
		||||
  state: {
 | 
			
		||||
    sidebar: {
 | 
			
		||||
      opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
 | 
			
		||||
      withoutAnimation: false
 | 
			
		||||
    },
 | 
			
		||||
    device: 'desktop',
 | 
			
		||||
    language: Cookies.get('language') || 'en',
 | 
			
		||||
    size: Cookies.get('size') || 'medium'
 | 
			
		||||
const state = {
 | 
			
		||||
  sidebar: {
 | 
			
		||||
    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
 | 
			
		||||
    withoutAnimation: false
 | 
			
		||||
  },
 | 
			
		||||
  mutations: {
 | 
			
		||||
    TOGGLE_SIDEBAR: state => {
 | 
			
		||||
      state.sidebar.opened = !state.sidebar.opened
 | 
			
		||||
      state.sidebar.withoutAnimation = false
 | 
			
		||||
      if (state.sidebar.opened) {
 | 
			
		||||
        Cookies.set('sidebarStatus', 1)
 | 
			
		||||
      } else {
 | 
			
		||||
        Cookies.set('sidebarStatus', 0)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    CLOSE_SIDEBAR: (state, withoutAnimation) => {
 | 
			
		||||
  device: 'desktop',
 | 
			
		||||
  language: Cookies.get('language') || 'en',
 | 
			
		||||
  size: Cookies.get('size') || 'medium'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mutations = {
 | 
			
		||||
  TOGGLE_SIDEBAR: state => {
 | 
			
		||||
    state.sidebar.opened = !state.sidebar.opened
 | 
			
		||||
    state.sidebar.withoutAnimation = false
 | 
			
		||||
    if (state.sidebar.opened) {
 | 
			
		||||
      Cookies.set('sidebarStatus', 1)
 | 
			
		||||
    } else {
 | 
			
		||||
      Cookies.set('sidebarStatus', 0)
 | 
			
		||||
      state.sidebar.opened = false
 | 
			
		||||
      state.sidebar.withoutAnimation = withoutAnimation
 | 
			
		||||
    },
 | 
			
		||||
    TOGGLE_DEVICE: (state, device) => {
 | 
			
		||||
      state.device = device
 | 
			
		||||
    },
 | 
			
		||||
    SET_LANGUAGE: (state, language) => {
 | 
			
		||||
      state.language = language
 | 
			
		||||
      Cookies.set('language', language)
 | 
			
		||||
    },
 | 
			
		||||
    SET_SIZE: (state, size) => {
 | 
			
		||||
      state.size = size
 | 
			
		||||
      Cookies.set('size', size)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    toggleSideBar({ commit }) {
 | 
			
		||||
      commit('TOGGLE_SIDEBAR')
 | 
			
		||||
    },
 | 
			
		||||
    closeSideBar({ commit }, { withoutAnimation }) {
 | 
			
		||||
      commit('CLOSE_SIDEBAR', withoutAnimation)
 | 
			
		||||
    },
 | 
			
		||||
    toggleDevice({ commit }, device) {
 | 
			
		||||
      commit('TOGGLE_DEVICE', device)
 | 
			
		||||
    },
 | 
			
		||||
    setLanguage({ commit }, language) {
 | 
			
		||||
      commit('SET_LANGUAGE', language)
 | 
			
		||||
    },
 | 
			
		||||
    setSize({ commit }, size) {
 | 
			
		||||
      commit('SET_SIZE', size)
 | 
			
		||||
    }
 | 
			
		||||
  CLOSE_SIDEBAR: (state, withoutAnimation) => {
 | 
			
		||||
    Cookies.set('sidebarStatus', 0)
 | 
			
		||||
    state.sidebar.opened = false
 | 
			
		||||
    state.sidebar.withoutAnimation = withoutAnimation
 | 
			
		||||
  },
 | 
			
		||||
  TOGGLE_DEVICE: (state, device) => {
 | 
			
		||||
    state.device = device
 | 
			
		||||
  },
 | 
			
		||||
  SET_LANGUAGE: (state, language) => {
 | 
			
		||||
    state.language = language
 | 
			
		||||
    Cookies.set('language', language)
 | 
			
		||||
  },
 | 
			
		||||
  SET_SIZE: (state, size) => {
 | 
			
		||||
    state.size = size
 | 
			
		||||
    Cookies.set('size', size)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default app
 | 
			
		||||
const actions = {
 | 
			
		||||
  toggleSideBar({ commit }) {
 | 
			
		||||
    commit('TOGGLE_SIDEBAR')
 | 
			
		||||
  },
 | 
			
		||||
  closeSideBar({ commit }, { withoutAnimation }) {
 | 
			
		||||
    commit('CLOSE_SIDEBAR', withoutAnimation)
 | 
			
		||||
  },
 | 
			
		||||
  toggleDevice({ commit }, device) {
 | 
			
		||||
    commit('TOGGLE_DEVICE', device)
 | 
			
		||||
  },
 | 
			
		||||
  setLanguage({ commit }, language) {
 | 
			
		||||
    commit('SET_LANGUAGE', language)
 | 
			
		||||
  },
 | 
			
		||||
  setSize({ commit }, size) {
 | 
			
		||||
    commit('SET_SIZE', size)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  namespaced: true,
 | 
			
		||||
  state,
 | 
			
		||||
  mutations,
 | 
			
		||||
  actions
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,23 @@
 | 
			
		||||
const errorLog = {
 | 
			
		||||
  state: {
 | 
			
		||||
    logs: []
 | 
			
		||||
  },
 | 
			
		||||
  mutations: {
 | 
			
		||||
    ADD_ERROR_LOG: (state, log) => {
 | 
			
		||||
      state.logs.push(log)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    addErrorLog({ commit }, log) {
 | 
			
		||||
      commit('ADD_ERROR_LOG', log)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
const state = {
 | 
			
		||||
  logs: []
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mutations = {
 | 
			
		||||
  ADD_ERROR_LOG: (state, log) => {
 | 
			
		||||
    state.logs.push(log)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default errorLog
 | 
			
		||||
const actions = {
 | 
			
		||||
  addErrorLog({ commit }, log) {
 | 
			
		||||
    commit('ADD_ERROR_LOG', log)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  namespaced: true,
 | 
			
		||||
  state,
 | 
			
		||||
  mutations,
 | 
			
		||||
  actions
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,32 +34,36 @@ export function filterAsyncRoutes(routes, roles) {
 | 
			
		||||
  return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const permission = {
 | 
			
		||||
  state: {
 | 
			
		||||
    routes: [],
 | 
			
		||||
    addRoutes: []
 | 
			
		||||
  },
 | 
			
		||||
  mutations: {
 | 
			
		||||
    SET_ROUTES: (state, routes) => {
 | 
			
		||||
      state.addRoutes = routes
 | 
			
		||||
      state.routes = constantRoutes.concat(routes)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    GenerateRoutes({ commit }, data) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        const { roles } = data
 | 
			
		||||
        let accessedRoutes
 | 
			
		||||
        if (roles.includes('admin')) {
 | 
			
		||||
          accessedRoutes = asyncRoutes
 | 
			
		||||
        } else {
 | 
			
		||||
          accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
 | 
			
		||||
        }
 | 
			
		||||
        commit('SET_ROUTES', accessedRoutes)
 | 
			
		||||
        resolve(accessedRoutes)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
const state = {
 | 
			
		||||
  routes: [],
 | 
			
		||||
  addRoutes: []
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mutations = {
 | 
			
		||||
  SET_ROUTES: (state, routes) => {
 | 
			
		||||
    state.addRoutes = routes
 | 
			
		||||
    state.routes = constantRoutes.concat(routes)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default permission
 | 
			
		||||
const actions = {
 | 
			
		||||
  generateRoutes({ commit }, roles) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      let accessedRoutes
 | 
			
		||||
      if (roles.includes('admin')) {
 | 
			
		||||
        accessedRoutes = asyncRoutes
 | 
			
		||||
      } else {
 | 
			
		||||
        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
 | 
			
		||||
      }
 | 
			
		||||
      commit('SET_ROUTES', accessedRoutes)
 | 
			
		||||
      resolve(accessedRoutes)
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  namespaced: true,
 | 
			
		||||
  state,
 | 
			
		||||
  mutations,
 | 
			
		||||
  actions
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								src/store/modules/settings.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/store/modules/settings.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
import defaultSettings from '@/settings'
 | 
			
		||||
const { showSettings, tagsView, fixedHeader, sidebarLogo, theme } = defaultSettings
 | 
			
		||||
 | 
			
		||||
const state = {
 | 
			
		||||
  theme: theme,
 | 
			
		||||
  showSettings: showSettings,
 | 
			
		||||
  tagsView: tagsView,
 | 
			
		||||
  fixedHeader: fixedHeader,
 | 
			
		||||
  sidebarLogo: sidebarLogo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mutations = {
 | 
			
		||||
  CHANGE_SETTING: (state, { key, value }) => {
 | 
			
		||||
    if (state.hasOwnProperty(key)) {
 | 
			
		||||
      state[key] = value
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const actions = {
 | 
			
		||||
  changeSetting({ commit }, data) {
 | 
			
		||||
    commit('CHANGE_SETTING', data)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  namespaced: true,
 | 
			
		||||
  state,
 | 
			
		||||
  mutations,
 | 
			
		||||
  actions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,161 +1,166 @@
 | 
			
		||||
const tagsView = {
 | 
			
		||||
  state: {
 | 
			
		||||
    visitedViews: [],
 | 
			
		||||
    cachedViews: []
 | 
			
		||||
  },
 | 
			
		||||
  mutations: {
 | 
			
		||||
    ADD_VISITED_VIEW: (state, view) => {
 | 
			
		||||
      if (state.visitedViews.some(v => v.path === view.path)) return
 | 
			
		||||
      state.visitedViews.push(
 | 
			
		||||
        Object.assign({}, view, {
 | 
			
		||||
          title: view.meta.title || 'no-name'
 | 
			
		||||
        })
 | 
			
		||||
      )
 | 
			
		||||
    },
 | 
			
		||||
    ADD_CACHED_VIEW: (state, view) => {
 | 
			
		||||
      if (state.cachedViews.includes(view.name)) return
 | 
			
		||||
      if (!view.meta.noCache) {
 | 
			
		||||
        state.cachedViews.push(view.name)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    DEL_VISITED_VIEW: (state, view) => {
 | 
			
		||||
      for (const [i, v] of state.visitedViews.entries()) {
 | 
			
		||||
        if (v.path === view.path) {
 | 
			
		||||
          state.visitedViews.splice(i, 1)
 | 
			
		||||
          break
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    DEL_CACHED_VIEW: (state, view) => {
 | 
			
		||||
      for (const i of state.cachedViews) {
 | 
			
		||||
        if (i === view.name) {
 | 
			
		||||
          const index = state.cachedViews.indexOf(i)
 | 
			
		||||
          state.cachedViews.splice(index, 1)
 | 
			
		||||
          break
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
const state = {
 | 
			
		||||
  visitedViews: [],
 | 
			
		||||
  cachedViews: []
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    DEL_OTHERS_VISITED_VIEWS: (state, view) => {
 | 
			
		||||
      state.visitedViews = state.visitedViews.filter(v => {
 | 
			
		||||
        return v.meta.affix || v.path === view.path
 | 
			
		||||
const mutations = {
 | 
			
		||||
  ADD_VISITED_VIEW: (state, view) => {
 | 
			
		||||
    if (state.visitedViews.some(v => v.path === view.path)) return
 | 
			
		||||
    state.visitedViews.push(
 | 
			
		||||
      Object.assign({}, view, {
 | 
			
		||||
        title: view.meta.title || 'no-name'
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    DEL_OTHERS_CACHED_VIEWS: (state, view) => {
 | 
			
		||||
      for (const i of state.cachedViews) {
 | 
			
		||||
        if (i === view.name) {
 | 
			
		||||
          const index = state.cachedViews.indexOf(i)
 | 
			
		||||
          state.cachedViews = state.cachedViews.slice(index, index + 1)
 | 
			
		||||
          break
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    )
 | 
			
		||||
  },
 | 
			
		||||
  ADD_CACHED_VIEW: (state, view) => {
 | 
			
		||||
    if (state.cachedViews.includes(view.name)) return
 | 
			
		||||
    if (!view.meta.noCache) {
 | 
			
		||||
      state.cachedViews.push(view.name)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
    DEL_ALL_VISITED_VIEWS: state => {
 | 
			
		||||
      // keep affix tags
 | 
			
		||||
      const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
 | 
			
		||||
      state.visitedViews = affixTags
 | 
			
		||||
    },
 | 
			
		||||
    DEL_ALL_CACHED_VIEWS: state => {
 | 
			
		||||
      state.cachedViews = []
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    UPDATE_VISITED_VIEW: (state, view) => {
 | 
			
		||||
      for (let v of state.visitedViews) {
 | 
			
		||||
        if (v.path === view.path) {
 | 
			
		||||
          v = Object.assign(v, view)
 | 
			
		||||
          break
 | 
			
		||||
        }
 | 
			
		||||
  DEL_VISITED_VIEW: (state, view) => {
 | 
			
		||||
    for (const [i, v] of state.visitedViews.entries()) {
 | 
			
		||||
      if (v.path === view.path) {
 | 
			
		||||
        state.visitedViews.splice(i, 1)
 | 
			
		||||
        break
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  DEL_CACHED_VIEW: (state, view) => {
 | 
			
		||||
    for (const i of state.cachedViews) {
 | 
			
		||||
      if (i === view.name) {
 | 
			
		||||
        const index = state.cachedViews.indexOf(i)
 | 
			
		||||
        state.cachedViews.splice(index, 1)
 | 
			
		||||
        break
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    addView({ dispatch }, view) {
 | 
			
		||||
      dispatch('addVisitedView', view)
 | 
			
		||||
      dispatch('addCachedView', view)
 | 
			
		||||
    },
 | 
			
		||||
    addVisitedView({ commit }, view) {
 | 
			
		||||
      commit('ADD_VISITED_VIEW', view)
 | 
			
		||||
    },
 | 
			
		||||
    addCachedView({ commit }, view) {
 | 
			
		||||
      commit('ADD_CACHED_VIEW', view)
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    delView({ dispatch, state }, view) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        dispatch('delVisitedView', view)
 | 
			
		||||
        dispatch('delCachedView', view)
 | 
			
		||||
        resolve({
 | 
			
		||||
          visitedViews: [...state.visitedViews],
 | 
			
		||||
          cachedViews: [...state.cachedViews]
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    delVisitedView({ commit, state }, view) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        commit('DEL_VISITED_VIEW', view)
 | 
			
		||||
        resolve([...state.visitedViews])
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    delCachedView({ commit, state }, view) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        commit('DEL_CACHED_VIEW', view)
 | 
			
		||||
        resolve([...state.cachedViews])
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
  DEL_OTHERS_VISITED_VIEWS: (state, view) => {
 | 
			
		||||
    state.visitedViews = state.visitedViews.filter(v => {
 | 
			
		||||
      return v.meta.affix || v.path === view.path
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  DEL_OTHERS_CACHED_VIEWS: (state, view) => {
 | 
			
		||||
    for (const i of state.cachedViews) {
 | 
			
		||||
      if (i === view.name) {
 | 
			
		||||
        const index = state.cachedViews.indexOf(i)
 | 
			
		||||
        state.cachedViews = state.cachedViews.slice(index, index + 1)
 | 
			
		||||
        break
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
    delOthersViews({ dispatch, state }, view) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        dispatch('delOthersVisitedViews', view)
 | 
			
		||||
        dispatch('delOthersCachedViews', view)
 | 
			
		||||
        resolve({
 | 
			
		||||
          visitedViews: [...state.visitedViews],
 | 
			
		||||
          cachedViews: [...state.cachedViews]
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    delOthersVisitedViews({ commit, state }, view) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        commit('DEL_OTHERS_VISITED_VIEWS', view)
 | 
			
		||||
        resolve([...state.visitedViews])
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    delOthersCachedViews({ commit, state }, view) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        commit('DEL_OTHERS_CACHED_VIEWS', view)
 | 
			
		||||
        resolve([...state.cachedViews])
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
  DEL_ALL_VISITED_VIEWS: state => {
 | 
			
		||||
    // keep affix tags
 | 
			
		||||
    const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
 | 
			
		||||
    state.visitedViews = affixTags
 | 
			
		||||
  },
 | 
			
		||||
  DEL_ALL_CACHED_VIEWS: state => {
 | 
			
		||||
    state.cachedViews = []
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
    delAllViews({ dispatch, state }, view) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        dispatch('delAllVisitedViews', view)
 | 
			
		||||
        dispatch('delAllCachedViews', view)
 | 
			
		||||
        resolve({
 | 
			
		||||
          visitedViews: [...state.visitedViews],
 | 
			
		||||
          cachedViews: [...state.cachedViews]
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    delAllVisitedViews({ commit, state }) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        commit('DEL_ALL_VISITED_VIEWS')
 | 
			
		||||
        resolve([...state.visitedViews])
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    delAllCachedViews({ commit, state }) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        commit('DEL_ALL_CACHED_VIEWS')
 | 
			
		||||
        resolve([...state.cachedViews])
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateVisitedView({ commit }, view) {
 | 
			
		||||
      commit('UPDATE_VISITED_VIEW', view)
 | 
			
		||||
  UPDATE_VISITED_VIEW: (state, view) => {
 | 
			
		||||
    for (let v of state.visitedViews) {
 | 
			
		||||
      if (v.path === view.path) {
 | 
			
		||||
        v = Object.assign(v, view)
 | 
			
		||||
        break
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default tagsView
 | 
			
		||||
const actions = {
 | 
			
		||||
  addView({ dispatch }, view) {
 | 
			
		||||
    dispatch('addVisitedView', view)
 | 
			
		||||
    dispatch('addCachedView', view)
 | 
			
		||||
  },
 | 
			
		||||
  addVisitedView({ commit }, view) {
 | 
			
		||||
    commit('ADD_VISITED_VIEW', view)
 | 
			
		||||
  },
 | 
			
		||||
  addCachedView({ commit }, view) {
 | 
			
		||||
    commit('ADD_CACHED_VIEW', view)
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  delView({ dispatch, state }, view) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      dispatch('delVisitedView', view)
 | 
			
		||||
      dispatch('delCachedView', view)
 | 
			
		||||
      resolve({
 | 
			
		||||
        visitedViews: [...state.visitedViews],
 | 
			
		||||
        cachedViews: [...state.cachedViews]
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  delVisitedView({ commit, state }, view) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      commit('DEL_VISITED_VIEW', view)
 | 
			
		||||
      resolve([...state.visitedViews])
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  delCachedView({ commit, state }, view) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      commit('DEL_CACHED_VIEW', view)
 | 
			
		||||
      resolve([...state.cachedViews])
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  delOthersViews({ dispatch, state }, view) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      dispatch('delOthersVisitedViews', view)
 | 
			
		||||
      dispatch('delOthersCachedViews', view)
 | 
			
		||||
      resolve({
 | 
			
		||||
        visitedViews: [...state.visitedViews],
 | 
			
		||||
        cachedViews: [...state.cachedViews]
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  delOthersVisitedViews({ commit, state }, view) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      commit('DEL_OTHERS_VISITED_VIEWS', view)
 | 
			
		||||
      resolve([...state.visitedViews])
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  delOthersCachedViews({ commit, state }, view) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      commit('DEL_OTHERS_CACHED_VIEWS', view)
 | 
			
		||||
      resolve([...state.cachedViews])
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  delAllViews({ dispatch, state }, view) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      dispatch('delAllVisitedViews', view)
 | 
			
		||||
      dispatch('delAllCachedViews', view)
 | 
			
		||||
      resolve({
 | 
			
		||||
        visitedViews: [...state.visitedViews],
 | 
			
		||||
        cachedViews: [...state.cachedViews]
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  delAllVisitedViews({ commit, state }) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      commit('DEL_ALL_VISITED_VIEWS')
 | 
			
		||||
      resolve([...state.visitedViews])
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  delAllCachedViews({ commit, state }) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      commit('DEL_ALL_CACHED_VIEWS')
 | 
			
		||||
      resolve([...state.cachedViews])
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  updateVisitedView({ commit }, view) {
 | 
			
		||||
    commit('UPDATE_VISITED_VIEW', view)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  namespaced: true,
 | 
			
		||||
  state,
 | 
			
		||||
  mutations,
 | 
			
		||||
  actions
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,144 +1,128 @@
 | 
			
		||||
import { loginByUsername, logout, getUserInfo } from '@/api/login'
 | 
			
		||||
import { login, logout, getInfo } from '@/api/user'
 | 
			
		||||
import { getToken, setToken, removeToken } from '@/utils/auth'
 | 
			
		||||
import router, { resetRouter } from '@/router'
 | 
			
		||||
 | 
			
		||||
const user = {
 | 
			
		||||
  state: {
 | 
			
		||||
    user: '',
 | 
			
		||||
    status: '',
 | 
			
		||||
    code: '',
 | 
			
		||||
    token: getToken(),
 | 
			
		||||
    name: '',
 | 
			
		||||
    avatar: '',
 | 
			
		||||
    introduction: '',
 | 
			
		||||
    roles: [],
 | 
			
		||||
    setting: {
 | 
			
		||||
      articlePlatform: []
 | 
			
		||||
    }
 | 
			
		||||
const state = {
 | 
			
		||||
  token: getToken(),
 | 
			
		||||
  name: '',
 | 
			
		||||
  avatar: '',
 | 
			
		||||
  introduction: '',
 | 
			
		||||
  roles: []
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mutations = {
 | 
			
		||||
  SET_TOKEN: (state, token) => {
 | 
			
		||||
    state.token = token
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  mutations: {
 | 
			
		||||
    SET_CODE: (state, code) => {
 | 
			
		||||
      state.code = code
 | 
			
		||||
    },
 | 
			
		||||
    SET_TOKEN: (state, token) => {
 | 
			
		||||
      state.token = token
 | 
			
		||||
    },
 | 
			
		||||
    SET_INTRODUCTION: (state, introduction) => {
 | 
			
		||||
      state.introduction = introduction
 | 
			
		||||
    },
 | 
			
		||||
    SET_SETTING: (state, setting) => {
 | 
			
		||||
      state.setting = setting
 | 
			
		||||
    },
 | 
			
		||||
    SET_STATUS: (state, status) => {
 | 
			
		||||
      state.status = status
 | 
			
		||||
    },
 | 
			
		||||
    SET_NAME: (state, name) => {
 | 
			
		||||
      state.name = name
 | 
			
		||||
    },
 | 
			
		||||
    SET_AVATAR: (state, avatar) => {
 | 
			
		||||
      state.avatar = avatar
 | 
			
		||||
    },
 | 
			
		||||
    SET_ROLES: (state, roles) => {
 | 
			
		||||
      state.roles = roles
 | 
			
		||||
    }
 | 
			
		||||
  SET_INTRODUCTION: (state, introduction) => {
 | 
			
		||||
    state.introduction = introduction
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  actions: {
 | 
			
		||||
    // 用户名登录
 | 
			
		||||
    LoginByUsername({ commit }, userInfo) {
 | 
			
		||||
      const username = userInfo.username.trim()
 | 
			
		||||
      return new Promise((resolve, reject) => {
 | 
			
		||||
        loginByUsername(username, userInfo.password).then(response => {
 | 
			
		||||
          const data = response.data
 | 
			
		||||
          commit('SET_TOKEN', data.token)
 | 
			
		||||
          setToken(response.data.token)
 | 
			
		||||
          resolve()
 | 
			
		||||
        }).catch(error => {
 | 
			
		||||
          reject(error)
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 获取用户信息
 | 
			
		||||
    GetUserInfo({ commit, state }) {
 | 
			
		||||
      return new Promise((resolve, reject) => {
 | 
			
		||||
        getUserInfo(state.token).then(response => {
 | 
			
		||||
          // 由于mockjs 不支持自定义状态码只能这样hack
 | 
			
		||||
          if (!response.data) {
 | 
			
		||||
            reject('Verification failed, please login again.')
 | 
			
		||||
          }
 | 
			
		||||
          const data = response.data
 | 
			
		||||
 | 
			
		||||
          if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
 | 
			
		||||
            commit('SET_ROLES', data.roles)
 | 
			
		||||
          } else {
 | 
			
		||||
            reject('getInfo: roles must be a non-null array!')
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          commit('SET_NAME', data.name)
 | 
			
		||||
          commit('SET_AVATAR', data.avatar)
 | 
			
		||||
          commit('SET_INTRODUCTION', data.introduction)
 | 
			
		||||
          resolve(response)
 | 
			
		||||
        }).catch(error => {
 | 
			
		||||
          reject(error)
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 第三方验证登录
 | 
			
		||||
    // LoginByThirdparty({ commit, state }, code) {
 | 
			
		||||
    //   return new Promise((resolve, reject) => {
 | 
			
		||||
    //     commit('SET_CODE', code)
 | 
			
		||||
    //     loginByThirdparty(state.status, state.email, state.code).then(response => {
 | 
			
		||||
    //       commit('SET_TOKEN', response.data.token)
 | 
			
		||||
    //       setToken(response.data.token)
 | 
			
		||||
    //       resolve()
 | 
			
		||||
    //     }).catch(error => {
 | 
			
		||||
    //       reject(error)
 | 
			
		||||
    //     })
 | 
			
		||||
    //   })
 | 
			
		||||
    // },
 | 
			
		||||
 | 
			
		||||
    // 登出
 | 
			
		||||
    LogOut({ commit, state }) {
 | 
			
		||||
      return new Promise((resolve, reject) => {
 | 
			
		||||
        logout(state.token).then(() => {
 | 
			
		||||
          commit('SET_TOKEN', '')
 | 
			
		||||
          commit('SET_ROLES', [])
 | 
			
		||||
          removeToken()
 | 
			
		||||
          resolve()
 | 
			
		||||
        }).catch(error => {
 | 
			
		||||
          reject(error)
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 前端 登出
 | 
			
		||||
    FedLogOut({ commit }) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        commit('SET_TOKEN', '')
 | 
			
		||||
        removeToken()
 | 
			
		||||
        resolve()
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 动态修改权限
 | 
			
		||||
    ChangeRoles({ commit, dispatch }, role) {
 | 
			
		||||
      return new Promise(resolve => {
 | 
			
		||||
        commit('SET_TOKEN', role)
 | 
			
		||||
        setToken(role)
 | 
			
		||||
        getUserInfo(role).then(response => {
 | 
			
		||||
          const data = response.data
 | 
			
		||||
          commit('SET_ROLES', data.roles)
 | 
			
		||||
          commit('SET_NAME', data.name)
 | 
			
		||||
          commit('SET_AVATAR', data.avatar)
 | 
			
		||||
          commit('SET_INTRODUCTION', data.introduction)
 | 
			
		||||
          dispatch('GenerateRoutes', data) // 动态修改权限后 重绘侧边菜单
 | 
			
		||||
          resolve()
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  SET_NAME: (state, name) => {
 | 
			
		||||
    state.name = name
 | 
			
		||||
  },
 | 
			
		||||
  SET_AVATAR: (state, avatar) => {
 | 
			
		||||
    state.avatar = avatar
 | 
			
		||||
  },
 | 
			
		||||
  SET_ROLES: (state, roles) => {
 | 
			
		||||
    state.roles = roles
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default user
 | 
			
		||||
const actions = {
 | 
			
		||||
  // user login
 | 
			
		||||
  login({ commit }, userInfo) {
 | 
			
		||||
    const { username, password } = userInfo
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      login({ username: username.trim(), password: password }).then(response => {
 | 
			
		||||
        const { data } = response
 | 
			
		||||
        commit('SET_TOKEN', data.token)
 | 
			
		||||
        setToken(data.token)
 | 
			
		||||
        resolve()
 | 
			
		||||
      }).catch(error => {
 | 
			
		||||
        reject(error)
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // get user info
 | 
			
		||||
  getInfo({ commit, state }) {
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      getInfo(state.token).then(response => {
 | 
			
		||||
        const { data } = response
 | 
			
		||||
 | 
			
		||||
        if (!data) {
 | 
			
		||||
          reject('Verification failed, please Login again.')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const { roles, name, avatar, introduction } = data
 | 
			
		||||
 | 
			
		||||
        // roles must be a non-empty array
 | 
			
		||||
        if (!roles || roles.length <= 0) {
 | 
			
		||||
          reject('getInfo: roles must be a non-null array!')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        commit('SET_ROLES', roles)
 | 
			
		||||
        commit('SET_NAME', name)
 | 
			
		||||
        commit('SET_AVATAR', avatar)
 | 
			
		||||
        commit('SET_INTRODUCTION', introduction)
 | 
			
		||||
        resolve(data)
 | 
			
		||||
      }).catch(error => {
 | 
			
		||||
        reject(error)
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // user logout
 | 
			
		||||
  logout({ commit, state }) {
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      logout(state.token).then(() => {
 | 
			
		||||
        commit('SET_TOKEN', '')
 | 
			
		||||
        commit('SET_ROLES', [])
 | 
			
		||||
        removeToken()
 | 
			
		||||
        resetRouter()
 | 
			
		||||
        resolve()
 | 
			
		||||
      }).catch(error => {
 | 
			
		||||
        reject(error)
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // remove token
 | 
			
		||||
  resetToken({ commit }) {
 | 
			
		||||
    return new Promise(resolve => {
 | 
			
		||||
      commit('SET_TOKEN', '')
 | 
			
		||||
      commit('SET_ROLES', [])
 | 
			
		||||
      removeToken()
 | 
			
		||||
      resolve()
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // Dynamically modify permissions
 | 
			
		||||
  changeRoles({ commit, dispatch }, role) {
 | 
			
		||||
    return new Promise(async resolve => {
 | 
			
		||||
      const token = role + '-token'
 | 
			
		||||
 | 
			
		||||
      commit('SET_TOKEN', token)
 | 
			
		||||
      setToken(token)
 | 
			
		||||
 | 
			
		||||
      const { roles } = await dispatch('getInfo')
 | 
			
		||||
 | 
			
		||||
      resetRouter()
 | 
			
		||||
 | 
			
		||||
      // generate accessible routes map based on roles
 | 
			
		||||
      const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
 | 
			
		||||
 | 
			
		||||
      // dynamically add accessible routes
 | 
			
		||||
      router.addRoutes(accessRoutes)
 | 
			
		||||
 | 
			
		||||
      resolve()
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  namespaced: true,
 | 
			
		||||
  state,
 | 
			
		||||
  mutations,
 | 
			
		||||
  actions
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user