RuoYi
2022-05-29 44ad220cdd7eb3c967a4ccac0b2e5b0c0e22738e
使用Pinia代替Vuex进行数据存储
已修改29个文件
已删除1个文件
1102 ■■■■■ 文件已修改
package.json 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/HeaderSearch/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SizeSelect/index.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/TopNav/index.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/permission/hasPermi.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/permission/hasRole.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/AppMain.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Navbar.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Settings/index.vue 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/Logo.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/index.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/TagsView/ScrollPane.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/TagsView/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/index.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/permission.js 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/auth.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/tab.js 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/getters.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/index.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/app.js 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/permission.js 87 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/settings.js 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/tagsView.js 354 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.js 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dynamicTitle.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/permission.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/userAvatar.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/auto-import.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -6,7 +6,7 @@
  "license": "MIT",
  "scripts": {
    "dev": "vite",
    "build:prod": "vite build",
    "build:prod": "vite build",
    "build:stage": "vite build --mode staging",
    "preview": "vite preview"
  },
@@ -25,10 +25,10 @@
    "js-cookie": "3.0.1",
    "jsencrypt": "3.2.1",
    "nprogress": "0.2.0",
    "pinia": "2.0.14",
    "vue": "3.2.31",
    "vue-cropper": "1.0.3",
    "vue-router": "4.0.14",
    "vuex": "4.0.2"
    "vue-router": "4.0.14"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "2.3.3",
src/components/HeaderSearch/index.vue
@@ -21,6 +21,7 @@
import Fuse from 'fuse.js'
import { getNormalPath } from '@/utils/ruoyi'
import { isHttp } from '@/utils/validate'
import usePermissionStore from '@/store/modules/permission'
const search = ref('');
const options = ref([]);
@@ -28,9 +29,8 @@
const show = ref(false);
const fuse = ref(undefined);
const headerSearchSelectRef = ref(null);
const store = useStore();
const router = useRouter();
const routes = computed(() => store.getters.permission_routes);
const routes = computed(() => usePermissionStore().routes);
function click() {
  show.value = !show.value
src/components/SizeSelect/index.vue
@@ -16,36 +16,24 @@
</template>
<script setup>
import { ElMessage } from 'element-plus'
import useAppStore from "@/store/modules/app";
const store = useStore();
const size = computed(() => store.getters.size);
const appStore = useAppStore();
const size = computed(() => appStore.size);
const route = useRoute();
const router = useRouter();
const {proxy} = getCurrentInstance();
const { proxy } = getCurrentInstance();
const sizeOptions = ref([
  { label: '较大', value: 'large' },
  { label: '默认', value: 'default' },
  { label: '稍小', value: 'small' },
])
  { label: "较大", value: "large" },
  { label: "默认", value: "default" },
  { label: "稍小", value: "small" },
]);
function refreshView() {
  // In order to make the cached page re-rendered
  store.dispatch('tagsView/delAllCachedViews', route)
  const { fullPath } = route
  nextTick(() => {
    router.replace({
      path: '/redirect' + fullPath
    })
  })
}
function handleSetSize(size) {
  proxy.$modal.loading("正在设置布局大小,请稍候...");
  store.dispatch('app/setSize', size)
  setTimeout("window.location.reload()", 1000)
};
  appStore.setSize(size);
  setTimeout("window.location.reload()", 1000);
}
</script>
<style lang='scss' scoped>
src/components/TopNav/index.vue
@@ -30,6 +30,9 @@
<script setup>
import { constantRoutes } from "@/router"
import { isHttp } from '@/utils/validate'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
// é¡¶éƒ¨æ åˆå§‹æ•°
const visibleNumber = ref(null);
@@ -38,14 +41,16 @@
// éšè—ä¾§è¾¹æ è·¯ç”±
const hideList = ['/index', '/user/profile'];
const store = useStore();
const appStore = useAppStore()
const settingsStore = useSettingsStore()
const permissionStore = usePermissionStore()
const route = useRoute();
const router = useRouter();
// ä¸»é¢˜é¢œè‰²
const theme = computed(() => store.state.settings.theme);
const theme = computed(() => settingsStore.theme);
// æ‰€æœ‰çš„路由信息
const routers = computed(() => store.state.permission.topbarRouters);
const routers = computed(() => permissionStore.topbarRouters);
// é¡¶éƒ¨æ˜¾ç¤ºèœå•
const topMenus = computed(() => {
@@ -91,10 +96,10 @@
  if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) {
    const tmpPath = path.substring(1, path.length);
    activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
    store.dispatch('app/toggleSideBarHide', false);
    appStore.toggleSideBarHide(false);
  } else if(!route.children) {
    activePath = path;
    store.dispatch('app/toggleSideBarHide', true);
    appStore.toggleSideBarHide(true);
  }
  activeRoutes(activePath);
  return activePath;
@@ -114,11 +119,11 @@
  } else if (!route || !route.children) {
    // æ²¡æœ‰å­è·¯ç”±è·¯å¾„内部打开
    router.push({ path: key });
    store.dispatch('app/toggleSideBarHide', true);
    appStore.toggleSideBarHide(true);
  } else {
    // æ˜¾ç¤ºå·¦ä¾§è”动菜单
    activeRoutes(key);
    store.dispatch('app/toggleSideBarHide', false);
    appStore.toggleSideBarHide(false);
  }
}
@@ -132,7 +137,7 @@
    });
  }
  if(routes.length > 0) {
    store.commit("SET_SIDEBAR_ROUTERS", routes);
    permissionStore.setSidebarRouters(routes);
  }
  return routes;
}
src/directive/permission/hasPermi.js
@@ -3,13 +3,13 @@
 * Copyright (c) 2019 ruoyi
 */
 
import store from '@/store'
import useUserStore from '@/store/modules/user'
export default {
  mounted(el, binding, vnode) {
    const { value } = binding
    const all_permission = "*:*:*";
    const permissions = store.getters && store.getters.permissions
    const permissions = useUserStore().permissions
    if (value && value instanceof Array && value.length > 0) {
      const permissionFlag = value
src/directive/permission/hasRole.js
@@ -3,13 +3,13 @@
 * Copyright (c) 2019 ruoyi
 */
 
import store from '@/store'
import useUserStore from '@/store/modules/user'
export default {
  mounted(el, binding, vnode) {
    const { value } = binding
    const super_admin = "admin";
    const roles = store.getters && store.getters.roles
    const roles = useUserStore().roles
    if (value && value instanceof Array && value.length > 0) {
      const roleFlag = value
src/layout/components/AppMain.vue
@@ -11,11 +11,13 @@
</template>
<script setup>
let store = useStore()
import useTagsViewStore from '@/store/modules/tagsview'
const tagsViewStore = useTagsViewStore()
const route = useRoute()
store.dispatch('tagsView/addCachedView', route)
tagsViewStore.addCachedView(route)
const cachedViews = computed(() => {
    return store.state.tagsView.cachedViews
    return tagsViewStore.cachedViews
})
</script>
src/layout/components/Navbar.vue
@@ -1,11 +1,11 @@
<template>
  <div class="navbar">
    <hamburger id="hamburger-container" :is-active="getters.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
    <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!$store.state.settings.topNav" />
    <top-nav id="topmenu-container" class="topmenu-container" v-if="$store.state.settings.topNav" />
    <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
    <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
    <top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
    <div class="right-menu">
      <template v-if="getters.device !== 'mobile'">
      <template v-if="appStore.device !== 'mobile'">
        <header-search id="header-search" class="right-menu-item" />
        <el-tooltip content="源码地址" effect="dark" placement="bottom">
@@ -25,7 +25,7 @@
      <div class="avatar-container">
        <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
          <div class="avatar-wrapper">
            <img :src="getters.avatar" class="user-avatar" />
            <img :src="userStore.avatar" class="user-avatar" />
            <el-icon><caret-bottom /></el-icon>
          </div>
          <template #dropdown>
@@ -57,12 +57,16 @@
import HeaderSearch from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
import useAppStore from '@/store/modules/app'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
const store = useStore();
const getters = computed(() => store.getters);
const appStore = useAppStore()
const userStore = useUserStore()
const settingsStore = useSettingsStore()
function toggleSideBar() {
  store.dispatch('app/toggleSideBar')
  appStore.toggleSideBar()
}
function handleCommand(command) {
@@ -84,7 +88,7 @@
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    store.dispatch('LogOut').then(() => {
    userStore.logOut().then(() => {
      location.href = '/index';
    })
  }).catch(() => { });
src/layout/components/Settings/index.vue
@@ -84,26 +84,28 @@
import axios from 'axios'
import { ElLoading, ElMessage } from 'element-plus'
import { useDynamicTitle } from '@/utils/dynamicTitle'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
const { proxy } = getCurrentInstance();
const store = useStore();
const appStore = useAppStore()
const settingsStore = useSettingsStore()
const permissionStore = usePermissionStore()
const showSettings = ref(false);
const theme = ref(store.state.settings.theme);
const sideTheme = ref(store.state.settings.sideTheme);
const storeSettings = computed(() => store.state.settings);
const theme = ref(settingsStore.theme);
const sideTheme = ref(settingsStore.sideTheme);
const storeSettings = computed(() => settingsStore);
const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
/** æ˜¯å¦éœ€è¦topnav */
const topNav = computed({
  get: () => storeSettings.value.topNav,
  set: (val) => {
    store.dispatch('settings/changeSetting', {
      key: 'topNav',
      value: val
    })
    settingsStore.changeSetting({ key: 'topNav', value: val })
    if (!val) {
      store.dispatch('app/toggleSideBarHide', false);
      store.commit("SET_SIDEBAR_ROUTERS", store.state.permission.defaultRoutes);
      appStore.toggleSideBarHide(false);
      permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
    }
  }
})
@@ -111,57 +113,39 @@
const tagsView = computed({
  get: () => storeSettings.value.tagsView,
  set: (val) => {
    store.dispatch('settings/changeSetting', {
      key: 'tagsView',
      value: val
    })
    settingsStore.changeSetting({ key: 'tagsView', value: val })
  }
})
/**是否需要固定头部 */
const fixedHeader = computed({
  get: () => storeSettings.value.fixedHeader,
  set: (val) => {
    store.dispatch('settings/changeSetting', {
      key: 'fixedHeader',
      value: val
    })
    settingsStore.changeSetting({ key: 'fixedHeader', value: val })
  }
})
/**是否需要侧边栏的logo */
const sidebarLogo = computed({
  get: () => storeSettings.value.sidebarLogo,
  set: (val) => {
    store.dispatch('settings/changeSetting', {
      key: 'sidebarLogo',
      value: val
    })
    settingsStore.changeSetting({ key: 'sidebarLogo', value: val })
  }
})
/**是否需要侧边栏的动态网页的title */
const dynamicTitle = computed({
  get: () => storeSettings.value.dynamicTitle,
  set: (val) => {
    store.dispatch('settings/changeSetting', {
      key: 'dynamicTitle',
      value: val
    })
    settingsStore.changeSetting({ key: 'dynamicTitle', value: val })
    // åŠ¨æ€è®¾ç½®ç½‘é¡µæ ‡é¢˜
    useDynamicTitle()
  }
})
function themeChange(val) {
  store.dispatch('settings/changeSetting', {
    key: 'theme',
    value: val
  })
  settingsStore.changeSetting({ key: 'theme', value: val })
  theme.value = val;
}
function handleTheme(val) {
  store.dispatch('settings/changeSetting', {
    key: 'sideTheme',
    value: val
  })
  settingsStore.changeSetting({ key: 'sideTheme', value: val })
  sideTheme.value = val;
}
function saveSetting() {
src/layout/components/Sidebar/Logo.vue
@@ -16,6 +16,7 @@
<script setup>
import variables from '@/assets/styles/variables.module.scss'
import logo from '@/assets/logo/logo.png'
import useSettingsStore from '@/store/modules/settings'
defineProps({
  collapse: {
@@ -25,8 +26,8 @@
})
const title = ref('若依管理系统');
const store = useStore();
const sideTheme = computed(() => store.state.settings.sideTheme);
const settingsStore = useSettingsStore();
const sideTheme = computed(() => settingsStore.sideTheme);
</script>
<style lang="scss" scoped>
src/layout/components/Sidebar/index.vue
@@ -27,15 +27,20 @@
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/assets/styles/variables.module.scss'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
const route = useRoute();
const store = useStore();
const appStore = useAppStore()
const settingsStore = useSettingsStore()
const permissionStore = usePermissionStore()
const sidebarRouters =  computed(() => store.getters.sidebarRouters);
const showLogo = computed(() => store.state.settings.sidebarLogo);
const sideTheme = computed(() => store.state.settings.sideTheme);
const theme = computed(() => store.state.settings.theme);
const isCollapse = computed(() => !store.state.app.sidebar.opened);
const sidebarRouters =  computed(() => permissionStore.sidebarRouters);
const showLogo = computed(() => settingsStore.sidebarLogo);
const sideTheme = computed(() => settingsStore.sideTheme);
const theme = computed(() => settingsStore.theme);
const isCollapse = computed(() => !appStore.sidebar.opened);
const activeMenu = computed(() => {
  const { meta, path } = route;
src/layout/components/TagsView/ScrollPane.vue
@@ -10,6 +10,8 @@
</template>
<script setup>
import useTagsViewStore from '@/store/modules/tagsview'
const tagAndTagSpacing = ref(4);
const { proxy } = getCurrentInstance();
@@ -32,8 +34,8 @@
  emits('scroll')
}
const store = useStore();
const visitedViews = computed(() => store.state.tagsView.visitedViews);
const tagsViewStore = useTagsViewStore()
const visitedViews = computed(() => tagsViewStore.visitedViews);
function moveToTarget(currentTag) {
  const $container = proxy.$refs.scrollContainer.$el
src/layout/components/TagsView/index.vue
@@ -44,6 +44,9 @@
<script setup>
import ScrollPane from './ScrollPane'
import { getNormalPath } from '@/utils/ruoyi'
import useTagsViewStore from '@/store/modules/tagsview'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
const visible = ref(false);
const top = ref(0);
@@ -53,13 +56,12 @@
const scrollPaneRef = ref(null);
const { proxy } = getCurrentInstance();
const store = useStore();
const route = useRoute();
const router = useRouter();
const visitedViews = computed(() => store.state.tagsView.visitedViews);
const routes = computed(() => store.state.permission.routes);
const theme = computed(() => store.state.settings.theme);
const visitedViews = computed(() => useTagsViewStore().visitedViews);
const routes = computed(() => usePermissionStore().routes);
const theme = computed(() => useSettingsStore().theme);
watch(route, () => {
  addTags()
@@ -131,14 +133,14 @@
  for (const tag of res) {
    // Must have tag name
    if (tag.name) {
      store.dispatch('tagsView/addVisitedView', tag)
       useTagsViewStore().addVisitedView(tag)
    }
  }
}
function addTags() {
  const { name } = route
  if (name) {
    store.dispatch('tagsView/addView', route)
    useTagsViewStore().addView(route)
  }
  return false
}
@@ -149,7 +151,7 @@
        scrollPaneRef.value.moveToTarget(r);
        // when query is different then update
        if (r.fullPath !== route.fullPath) {
          store.dispatch('tagsView/updateVisitedView', route)
          useTagsViewStore().updateVisitedView(route)
        }
      }
    }
src/layout/index.vue
@@ -19,13 +19,16 @@
import { AppMain, Navbar, Settings, TagsView } from './components'
import defaultSettings from '@/settings'
const store = useStore();
const theme = computed(() => store.state.settings.theme);
const sideTheme = computed(() => store.state.settings.sideTheme);
const sidebar = computed(() => store.state.app.sidebar);
const device = computed(() => store.state.app.device);
const needTagsView = computed(() => store.state.settings.tagsView);
const fixedHeader = computed(() => store.state.settings.fixedHeader);
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
const settingsStore = useSettingsStore()
const theme = computed(() => settingsStore.theme);
const sideTheme = computed(() => settingsStore.sideTheme);
const sidebar = computed(() => useAppStore().sidebar);
const device = computed(() => useAppStore().device);
const needTagsView = computed(() => settingsStore.tagsView);
const fixedHeader = computed(() => settingsStore.fixedHeader);
const classObj = computed(() => ({
  hideSidebar: !sidebar.value.opened,
@@ -39,18 +42,18 @@
watchEffect(() => {
  if (device.value === 'mobile' && sidebar.value.opened) {
    store.dispatch('app/closeSideBar', { withoutAnimation: false })
    useAppStore().closeSideBar({ withoutAnimation: false })
  }
  if (width.value - 1 < WIDTH) {
    store.dispatch('app/toggleDevice', 'mobile')
    store.dispatch('app/closeSideBar', { withoutAnimation: true })
    useAppStore().toggleDevice('mobile')
    useAppStore().closeSideBar({ withoutAnimation: true })
  } else {
    store.dispatch('app/toggleDevice', 'desktop')
    useAppStore().toggleDevice('desktop')
  }
})
function handleClickOutside() {
  store.dispatch('app/closeSideBar', { withoutAnimation: false })
  useAppStore().closeSideBar({ withoutAnimation: false })
}
const settingRef = ref(null);
src/permission.js
@@ -1,11 +1,13 @@
import router from './router'
import store from './store'
import { ElMessage } from 'element-plus'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isHttp } from '@/utils/validate'
import { isRelogin } from '@/utils/request'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
NProgress.configure({ showSpinner: false });
@@ -14,18 +16,18 @@
router.beforeEach((to, from, next) => {
  NProgress.start()
  if (getToken()) {
    to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
    to.meta.title && useSettingsStore().setTitle(to.meta.title)
    /* has token*/
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      if (store.getters.roles.length === 0) {
      if (useUserStore().roles.length === 0) {
        isRelogin.show = true
        // åˆ¤æ–­å½“前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(() => {
        useUserStore().getInfo().then(() => {
          isRelogin.show = false
          store.dispatch('GenerateRoutes').then(accessRoutes => {
          usePermissionStore().generateRoutes().then(accessRoutes => {
            // æ ¹æ®roles权限生成可访问的路由表
            accessRoutes.forEach(route => {
              if (!isHttp(route.path)) {
@@ -35,7 +37,7 @@
            next({ ...to, replace: true }) // hack方法 ç¡®ä¿addRoutes已完成
          })
        }).catch(err => {
          store.dispatch('LogOut').then(() => {
          useUserStore().logOut().then(() => {
            ElMessage.error(err)
            next({ path: '/' })
          })
src/plugins/auth.js
@@ -1,8 +1,8 @@
import store from '@/store'
import useUserStore from '@/store/modules/user'
function authPermission(permission) {
  const all_permission = "*:*:*";
  const permissions = store.getters && store.getters.permissions
  const permissions = useUserStore().permissions
  if (permission && permission.length > 0) {
    return permissions.some(v => {
      return all_permission === v || v === permission
@@ -14,7 +14,7 @@
function authRole(role) {
  const super_admin = "admin";
  const roles = store.getters && store.getters.roles
  const roles = useUserStore().roles
  if (role && role.length > 0) {
    return roles.some(v => {
      return super_admin === v || v === role
src/plugins/tab.js
@@ -1,4 +1,4 @@
import store from '@/store'
import useTagsViewStore from '@/store/modules/tagsview'
import router from '@/router'
export default {
@@ -14,7 +14,7 @@
        }
      });
    }
    return store.dispatch('tagsView/delCachedView', obj).then(() => {
    return useTagsViewStore().delCachedView(obj).then(() => {
      const { path, query } = obj
      router.replace({
        path: '/redirect' + path,
@@ -24,7 +24,7 @@
  },
  // å…³é—­å½“前tab页签,打开新页签
  closeOpenPage(obj) {
    store.dispatch("tagsView/delView", router.currentRoute.value);
    useTagsViewStore().delView(router.currentRoute.value);
    if (obj !== undefined) {
      return router.push(obj);
    }
@@ -32,27 +32,27 @@
  // å…³é—­æŒ‡å®štab页签
  closePage(obj) {
    if (obj === undefined) {
      return store.dispatch('tagsView/delView', router.currentRoute.value).then(({ lastPath }) => {
      return useTagsViewStore().delView(router.currentRoute.value).then(({ lastPath }) => {
        return router.push(lastPath || '/index');
      });
    }
    return store.dispatch('tagsView/delView', obj);
    return useTagsViewStore().delView(obj);
  },
  // å…³é—­æ‰€æœ‰tab页签
  closeAllPage() {
    return store.dispatch('tagsView/delAllViews');
    return useTagsViewStore().delAllViews();
  },
  // å…³é—­å·¦ä¾§tab页签
  closeLeftPage(obj) {
    return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute.value);
    return useTagsViewStore().delLeftTags(obj || router.currentRoute.value);
  },
  // å…³é—­å³ä¾§tab页签
  closeRightPage(obj) {
    return store.dispatch('tagsView/delRightTags', obj || router.currentRoute.value);
    return useTagsViewStore().delRightTags(obj || router.currentRoute.value);
  },
  // å…³é—­å…¶ä»–tab页签
  closeOtherPage(obj) {
    return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute.value);
    return useTagsViewStore().delOthersViews(obj || router.currentRoute.value);
  },
  // æ‰“å¼€tab页签
  openPage(url) {
@@ -60,6 +60,6 @@
  },
  // ä¿®æ”¹tab页签
  updatePage(obj) {
    return store.dispatch('tagsView/updateVisitedView', obj);
    return useTagsViewStore().updateVisitedView(obj);
  }
}
src/store/getters.js
ÎļþÒÑɾ³ý
src/store/index.js
@@ -1,21 +1,3 @@
import { createStore } from 'vuex'
import app from './modules/app'
import user from './modules/user'
import tagsView from './modules/tagsView'
import permission from './modules/permission'
import settings from './modules/settings'
import getters from './getters'
const store = createStore({
  modules: {
    app,
    user,
    tagsView,
    permission,
    settings
  },
  getters
});
const store = createPinia()
export default store
src/store/modules/app.js
@@ -1,66 +1,47 @@
import Cookies from 'js-cookie'
const state = {
  sidebar: {
    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
    withoutAnimation: false,
    hide: false
  },
  device: 'desktop',
  size: Cookies.get('size') || 'default'
}
const mutations = {
  TOGGLE_SIDEBAR: state => {
    if (state.sidebar.hide) {
      return false;
const useAppStore = defineStore(
  'app',
  {
    state: () => ({
      sidebar: {
        opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
        withoutAnimation: false,
        hide: false
      },
      device: 'desktop',
      size: Cookies.get('size') || 'default'
    }),
    actions: {
      toggleSideBar(withoutAnimation) {
        if (this.sidebar.hide) {
          return false;
        }
        this.sidebar.opened = !this.sidebar.opened
        this.sidebar.withoutAnimation = withoutAnimation
        if (this.sidebar.opened) {
          Cookies.set('sidebarStatus', 1)
        } else {
          Cookies.set('sidebarStatus', 0)
        }
      },
      closeSideBar(withoutAnimation) {
        Cookies.set('sidebarStatus', 0)
        this.sidebar.opened = false
        this.sidebar.withoutAnimation = withoutAnimation
      },
      toggleDevice(device) {
        this.device = device
      },
      setSize(size) {
        this.size = size;
        Cookies.set('size', size)
      },
      toggleSideBarHide(status) {
        this.sidebar.hide = status
      }
    }
    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) => {
    Cookies.set('sidebarStatus', 0)
    state.sidebar.opened = false
    state.sidebar.withoutAnimation = withoutAnimation
  },
  TOGGLE_DEVICE: (state, device) => {
    state.device = device
  },
  SET_SIZE: (state, size) => {
    state.size = size
    Cookies.set('size', size)
  },
  SET_SIDEBAR_HIDE: (state, status) => {
    state.sidebar.hide = status
  }
}
  })
const actions = {
  toggleSideBar({ commit }) {
    commit('TOGGLE_SIDEBAR')
  },
  closeSideBar({ commit }, { withoutAnimation }) {
    commit('CLOSE_SIDEBAR', withoutAnimation)
  },
  toggleDevice({ commit }, device) {
    commit('TOGGLE_DEVICE', device)
  },
  setSize({ commit }, size) {
    commit('SET_SIZE', size)
  },
  toggleSideBarHide({ commit }, status) {
    commit('SET_SIDEBAR_HIDE', status)
  }
}
export default {
  namespaced: true,
  state,
  mutations,
  actions
}
export default useAppStore
src/store/modules/permission.js
@@ -7,51 +7,50 @@
// åŒ¹é…views里面所有的.vue文件
const modules = import.meta.glob('./../../views/**/*.vue')
const permission = {
  state: {
    routes: [],
    addRoutes: [],
    defaultRoutes: [],
    topbarRouters: [],
    sidebarRouters: []
  },
  mutations: {
    SET_ROUTES: (state, routes) => {
      state.addRoutes = routes
      state.routes = constantRoutes.concat(routes)
    },
    SET_DEFAULT_ROUTES: (state, routes) => {
      state.defaultRoutes = constantRoutes.concat(routes)
    },
    SET_TOPBAR_ROUTES: (state, routes) => {
      state.topbarRouters = routes
    },
    SET_SIDEBAR_ROUTERS: (state, routes) => {
      state.sidebarRouters = routes
    },
  },
  actions: {
    // ç”Ÿæˆè·¯ç”±
    GenerateRoutes({ commit }) {
      return new Promise(resolve => {
        // å‘后端请求路由数据
        getRouters().then(res => {
          const sdata = JSON.parse(JSON.stringify(res.data))
          const rdata = JSON.parse(JSON.stringify(res.data))
          const defaultData = JSON.parse(JSON.stringify(res.data))
          const sidebarRoutes = filterAsyncRouter(sdata)
          const rewriteRoutes = filterAsyncRouter(rdata, false, true)
          const defaultRoutes = filterAsyncRouter(defaultData)
          commit('SET_ROUTES', rewriteRoutes)
          commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
          commit('SET_DEFAULT_ROUTES', sidebarRoutes)
          commit('SET_TOPBAR_ROUTES', defaultRoutes)
          resolve(rewriteRoutes)
const usePermissionStore = defineStore(
  'permission',
  {
    state: () => ({
      routes: [],
      addRoutes: [],
      defaultRoutes: [],
      topbarRouters: [],
      sidebarRouters: []
    }),
    actions: {
      setRoutes(routes) {
        this.addRoutes = routes
        this.routes = constantRoutes.concat(routes)
      },
      setDefaultRoutes(routes) {
        this.defaultRoutes = constantRoutes.concat(routes)
      },
      setTopbarRoutes(routes) {
        this.topbarRouters = routes
      },
      setSidebarRouters(routes) {
        this.sidebarRouters = routes
      },
      generateRoutes(roles) {
        return new Promise(resolve => {
          // å‘后端请求路由数据
          getRouters().then(res => {
            const sdata = JSON.parse(JSON.stringify(res.data))
            const rdata = JSON.parse(JSON.stringify(res.data))
            const defaultData = JSON.parse(JSON.stringify(res.data))
            const sidebarRoutes = filterAsyncRouter(sdata)
            const rewriteRoutes = filterAsyncRouter(rdata, false, true)
            const defaultRoutes = filterAsyncRouter(defaultData)
            this.setRoutes(rewriteRoutes)
            this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
            this.setDefaultRoutes(sidebarRoutes)
            this.setTopbarRoutes(defaultRoutes)
            resolve(rewriteRoutes)
          })
        })
      })
      }
    }
  }
}
  })
// éåŽ†åŽå°ä¼ æ¥çš„è·¯ç”±å­—ç¬¦ä¸²ï¼Œè½¬æ¢ä¸ºç»„ä»¶å¯¹è±¡
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
@@ -116,4 +115,4 @@
  return res;
}
export default permission
export default usePermissionStore
src/store/modules/settings.js
@@ -4,41 +4,35 @@
const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
const state = {
  title: '',
  theme: storageSetting.theme || '#409EFF',
  sideTheme: storageSetting.sideTheme || sideTheme,
  showSettings: showSettings,
  topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
  tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
  fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
  sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
  dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
}
const mutations = {
  CHANGE_SETTING: (state, { key, value }) => {
    if (state.hasOwnProperty(key)) {
      state[key] = value
const useSettingsStore = defineStore(
  'settings',
  {
    state: () => ({
      title: '',
      theme: storageSetting.theme || '#409EFF',
      sideTheme: storageSetting.sideTheme || sideTheme,
      showSettings: showSettings,
      topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
      tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
      fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
      sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
      dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
    }),
    actions: {
      // ä¿®æ”¹å¸ƒå±€è®¾ç½®
      changeSetting(data) {
        const { key, value } = data
        if (this.hasOwnProperty(key)) {
          this[key] = value
        }
      },
      // è®¾ç½®ç½‘页标题
      setTitle(title) {
        this.title = title
        useDynamicTitle();
      }
    }
  }
}
  })
const actions = {
  // ä¿®æ”¹å¸ƒå±€è®¾ç½®
  changeSetting({ commit }, data) {
    commit('CHANGE_SETTING', data)
  },
  // è®¾ç½®ç½‘页标题
  setTitle({ commit }, title) {
    state.title = title
    useDynamicTitle();
  }
}
export default {
  namespaced: true,
  state,
  mutations,
  actions
}
export default useSettingsStore
src/store/modules/tagsView.js
@@ -1,207 +1,153 @@
const state = {
  visitedViews: [],
  cachedViews: []
}
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'
      })
    )
  },
  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
const useTagsViewStore = defineStore(
  'tags-view',
  {
    state: () => ({
      visitedViews: [],
      cachedViews: []
    }),
    actions: {
      addView(view) {
        this.addVisitedView(view)
        this.addCachedView(view)
      },
      addVisitedView(view) {
        if (this.visitedViews.some(v => v.path === view.path)) return
        this.visitedViews.push(
          Object.assign({}, view, {
            title: view.meta.title || 'no-name'
          })
        )
      },
      addCachedView(view) {
        if (this.cachedViews.includes(view.name)) return
        if (!view.meta.noCache) {
          this.cachedViews.push(view.name)
        }
      },
      delView(view) {
        return new Promise(resolve => {
          this.delVisitedView(view)
          this.delCachedView(view)
          resolve({
            visitedViews: [...this.visitedViews],
            cachedViews: [...this.cachedViews]
          })
        })
      },
      delVisitedView(view) {
        return new Promise(resolve => {
          for (const [i, v] of this.visitedViews.entries()) {
            if (v.path === view.path) {
              this.visitedViews.splice(i, 1)
              break
            }
          }
          resolve([...this.visitedViews])
        })
      },
      delCachedView(view) {
        return new Promise(resolve => {
          const index = this.cachedViews.indexOf(view.name)
          index > -1 && this.cachedViews.splice(index, 1)
          resolve([...this.cachedViews])
        })
      },
      delOthersViews(view) {
        return new Promise(resolve => {
          this.delOthersVisitedViews(view)
          this.delOthersCachedViews(view)
          resolve({
            visitedViews: [...this.visitedViews],
            cachedViews: [...this.cachedViews]
          })
        })
      },
      delOthersVisitedViews(view) {
        return new Promise(resolve => {
          this.visitedViews = this.visitedViews.filter(v => {
            return v.meta.affix || v.path === view.path
          })
          resolve([...this.visitedViews])
        })
      },
      delOthersCachedViews(view) {
        return new Promise(resolve => {
          const index = this.cachedViews.indexOf(view.name)
          if (index > -1) {
            this.cachedViews = this.cachedViews.slice(index, index + 1)
          } else {
            this.cachedViews = []
          }
          resolve([...this.cachedViews])
        })
      },
      delAllViews(view) {
        return new Promise(resolve => {
          this.delAllVisitedViews(view)
          this.delAllCachedViews(view)
          resolve({
            visitedViews: [...this.visitedViews],
            cachedViews: [...this.cachedViews]
          })
        })
      },
      delAllVisitedViews(view) {
        return new Promise(resolve => {
          const affixTags = this.visitedViews.filter(tag => tag.meta.affix)
          this.visitedViews = affixTags
          resolve([...this.visitedViews])
        })
      },
      delAllCachedViews(view) {
        return new Promise(resolve => {
          this.cachedViews = []
          resolve([...this.cachedViews])
        })
      },
      updateVisitedView(view) {
        for (let v of this.visitedViews) {
          if (v.path === view.path) {
            v = Object.assign(v, view)
            break
          }
        }
      },
      delRightTags(view) {
        return new Promise(resolve => {
          const index = this.visitedViews.findIndex(v => v.path === view.path)
          if (index === -1) {
            return
          }
          this.visitedViews = this.visitedViews.filter((item, idx) => {
            if (idx <= index || (item.meta && item.meta.affix)) {
              return true
            }
            const i = this.cachedViews.indexOf(item.name)
            if (i > -1) {
              this.cachedViews.splice(i, 1)
            }
            return false
          })
          resolve([...this.visitedViews])
        })
      },
      delLeftTags(view) {
        const index = this.visitedViews.findIndex(v => v.path === view.path)
        if (index === -1) {
          return
        }
        this.visitedViews = this.visitedViews.filter((item, idx) => {
          if (idx >= index || (item.meta && item.meta.affix)) {
            return true
          }
          const i = this.cachedViews.indexOf(item.name)
          if (i > -1) {
            this.cachedViews.splice(i, 1)
          }
          return false
        })
      }
    }
  },
  DEL_CACHED_VIEW: (state, view) => {
    const index = state.cachedViews.indexOf(view.name)
    index > -1 && state.cachedViews.splice(index, 1)
  },
  })
  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) => {
    const index = state.cachedViews.indexOf(view.name)
    if (index > -1) {
      state.cachedViews = state.cachedViews.slice(index, index + 1)
    } else {
      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 = []
  },
  UPDATE_VISITED_VIEW: (state, view) => {
    for (let v of state.visitedViews) {
      if (v.path === view.path) {
        v = Object.assign(v, view)
        break
      }
    }
  },
  DEL_RIGHT_VIEWS: (state, view) => {
    const index = state.visitedViews.findIndex(v => v.path === view.path)
    if (index === -1) {
      return
    }
    state.visitedViews = state.visitedViews.filter((item, idx) => {
      if (idx <= index || (item.meta && item.meta.affix)) {
        return true
      }
      const i = state.cachedViews.indexOf(item.name)
      if (i > -1) {
        state.cachedViews.splice(i, 1)
      }
      return false
    })
  },
  DEL_LEFT_VIEWS: (state, view) => {
    const index = state.visitedViews.findIndex(v => v.path === view.path)
    if (index === -1) {
      return
    }
    state.visitedViews = state.visitedViews.filter((item, idx) => {
      if (idx >= index || (item.meta && item.meta.affix)) {
        return true
      }
      const i = state.cachedViews.indexOf(item.name)
      if (i > -1) {
        state.cachedViews.splice(i, 1)
      }
      return false
    })
  }
}
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)
  },
  delRightTags({ commit }, view) {
    return new Promise(resolve => {
      commit('DEL_RIGHT_VIEWS', view)
      resolve([...state.visitedViews])
    })
  },
  delLeftTags({ commit }, view) {
    return new Promise(resolve => {
      commit('DEL_LEFT_VIEWS', view)
      resolve([...state.visitedViews])
    })
  },
}
export default {
  namespaced: true,
  state,
  mutations,
  actions
}
export default useTagsViewStore
src/store/modules/user.js
@@ -2,97 +2,69 @@
import { getToken, setToken, removeToken } from '@/utils/auth'
import defAva from '@/assets/images/profile.jpg'
const user = {
  state: {
    token: getToken(),
    name: '',
    avatar: '',
    roles: [],
    permissions: []
  },
const useUserStore = defineStore(
  'user',
  {
    state: () => ({
      token: getToken(),
      name: '',
      avatar: '',
      roles: [],
      permissions: []
    }),
    actions: {
      // ç™»å½•
      login(userInfo) {
        const username = userInfo.username.trim()
        const password = userInfo.password
        const code = userInfo.code
        const uuid = userInfo.uuid
        return new Promise((resolve, reject) => {
          login(username, password, code, uuid).then(res => {
            setToken(res.token)
            this.token = res.token
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },
      // èŽ·å–ç”¨æˆ·ä¿¡æ¯
      getInfo() {
        return new Promise((resolve, reject) => {
          getInfo().then(res => {
            const user = res.user
            const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar;
  mutations: {
    SET_TOKEN: (state, token) => {
      state.token = token
    },
    SET_NAME: (state, name) => {
      state.name = name
    },
    SET_AVATAR: (state, avatar) => {
      state.avatar = avatar
    },
    SET_ROLES: (state, roles) => {
      state.roles = roles
    },
    SET_PERMISSIONS: (state, permissions) => {
      state.permissions = permissions
            if (res.roles && res.roles.length > 0) { // éªŒè¯è¿”回的roles是否是一个非空数组
              this.roles = res.roles
              this.permissions = res.permissions
            } else {
              this.setRoutes = ['ROLE_DEFAULT']
            }
            this.name = user.userName
            this.avatar = avatar;
            resolve(res)
          }).catch(error => {
            reject(error)
          })
        })
      },
      // é€€å‡ºç³»ç»Ÿ
      logOut() {
        return new Promise((resolve, reject) => {
          logout(this.token).then(() => {
            this.token = ''
            this.roles = []
            this.permissions = []
            removeToken()
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      }
    }
  },
  })
  actions: {
    // ç™»å½•
    Login({ commit }, userInfo) {
      const username = userInfo.username.trim()
      const password = userInfo.password
      const code = userInfo.code
      const uuid = userInfo.uuid
      return new Promise((resolve, reject) => {
        login(username, password, code, uuid).then(res => {
          setToken(res.token)
          commit('SET_TOKEN', res.token)
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },
    // èŽ·å–ç”¨æˆ·ä¿¡æ¯
    GetInfo({ commit, state }) {
      return new Promise((resolve, reject) => {
        getInfo().then(res => {
          const user = res.user
          const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar;
          if (res.roles && res.roles.length > 0) { // éªŒè¯è¿”回的roles是否是一个非空数组
            commit('SET_ROLES', res.roles)
            commit('SET_PERMISSIONS', res.permissions)
          } else {
            commit('SET_ROLES', ['ROLE_DEFAULT'])
          }
          commit('SET_NAME', user.userName)
          commit('SET_AVATAR', avatar)
          resolve(res)
        }).catch(error => {
          reject(error)
        })
      })
    },
    // é€€å‡ºç³»ç»Ÿ
    LogOut({ commit, state }) {
      return new Promise((resolve, reject) => {
        logout(state.token).then(() => {
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          commit('SET_PERMISSIONS', [])
          removeToken()
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },
    // å‰ç«¯ ç™»å‡º
    FedLogOut({ commit }) {
      return new Promise(resolve => {
        commit('SET_TOKEN', '')
        removeToken()
        resolve()
      })
    }
  }
}
export default user
export default useUserStore
src/utils/dynamicTitle.js
@@ -1,12 +1,14 @@
import store from '@/store'
import defaultSettings from '@/settings'
import useSettingsStore from '@/store/modules/settings'
/**
 * åŠ¨æ€ä¿®æ”¹æ ‡é¢˜
 */
export function useDynamicTitle() {
  if (store.state.settings.dynamicTitle) {
    document.title = store.state.settings.title + ' - ' + defaultSettings.title;
  const settingsStore = useSettingsStore();
  if (settingsStore.dynamicTitle) {
    document.title = settingsStore.title + ' - ' + defaultSettings.title;
  } else {
    document.title = defaultSettings.title;
  }
src/utils/permission.js
@@ -1,4 +1,4 @@
import store from '@/store'
import useUserStore from '@/store/modules/user'
/**
 * å­—符权限校验
@@ -7,7 +7,7 @@
 */
export function checkPermi(value) {
  if (value && value instanceof Array && value.length > 0) {
    const permissions = store.getters && store.getters.permissions
    const permissions = useUserStore().permissions
    const permissionDatas = value
    const all_permission = "*:*:*";
@@ -32,7 +32,7 @@
 */
export function checkRole(value) {
  if (value && value instanceof Array && value.length > 0) {
    const roles = store.getters && store.getters.roles
    const roles = useUserStore().roles
    const permissionRoles = value
    const super_admin = "admin";
src/utils/request.js
@@ -1,11 +1,11 @@
import axios from 'axios'
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from '@/utils/ruoyi'
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
import useUserStore from '@/store/modules/user'
let downloadLoadingInstance;
// æ˜¯å¦æ˜¾ç¤ºé‡æ–°ç™»å½•
@@ -85,7 +85,7 @@
        }
      ).then(() => {
        isRelogin.show = false;
        store.dispatch('LogOut').then(() => {
        useUserStore().logOut().then(() => {
          location.href = '/index';
        })
      }).catch(() => {
src/views/login.vue
@@ -68,8 +68,9 @@
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import useUserStore from '@/store/modules/user'
const store = useStore();
const userStore = useUserStore()
const router = useRouter();
const { proxy } = getCurrentInstance();
@@ -111,7 +112,7 @@
        Cookies.remove("rememberMe");
      }
      // è°ƒç”¨action的登录方法
      store.dispatch("Login", loginForm.value).then(() => {
      userStore.login(loginForm.value).then(() => {
        router.push({ path: redirect.value || "/" });
      }).catch(() => {
        loading.value = false;
src/views/system/user/profile/userAvatar.vue
@@ -54,8 +54,9 @@
import "vue-cropper/dist/index.css";
import { VueCropper } from "vue-cropper";
import { uploadAvatar } from "@/api/system/user";
import useUserStore from '@/store/modules/user'
const store = useStore();
const userStore = useUserStore()
const { proxy } = getCurrentInstance();
const open = ref(false);
@@ -64,7 +65,7 @@
//图片裁剪数据
const options = reactive({
  img: store.getters.avatar, // è£å‰ªå›¾ç‰‡çš„地址
  img: userStore.avatar, // è£å‰ªå›¾ç‰‡çš„地址
  autoCrop: true, // æ˜¯å¦é»˜è®¤ç”Ÿæˆæˆªå›¾æ¡†
  autoCropWidth: 200, // é»˜è®¤ç”Ÿæˆæˆªå›¾æ¡†å®½åº¦
  autoCropHeight: 200, // é»˜è®¤ç”Ÿæˆæˆªå›¾æ¡†é«˜åº¦
@@ -116,7 +117,7 @@
    uploadAvatar(formData).then(response => {
      open.value = false;
      options.img = import.meta.env.VITE_APP_BASE_API + response.imgUrl;
      store.commit("SET_AVATAR", options.img);
      userStore.avatar = options.img;
      proxy.$modal.msgSuccess("修改成功");
      visible.value = false;
    });
@@ -128,7 +129,7 @@
};
/** å…³é—­çª—口 */
function closeDialog() {
  options.img = store.getters.avatar;
  options.img = userStore.avatar;
  options.visible = false;
};
</script>
vite/plugins/auto-import.js
@@ -5,9 +5,7 @@
        imports: [
            'vue',
            'vue-router',
            {
                'vuex': ['useStore']
            }
            'pinia'
        ],
        dts: false
    })