diff --git a/package.json b/package.json index de586a08..98decf67 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "nprogress": "^0.2.0", "path-browserify": "^1.0.1", "path-to-regexp": "^6.2.0", + "pinia": "^2.0.6", "screenfull": "^6.0.0", "vue": "^3.2.16", "vue-router": "^4.0.12", diff --git a/src/api/system/role.ts b/src/api/system/role.ts index 1fcff589..52360f8f 100644 --- a/src/api/system/role.ts +++ b/src/api/system/role.ts @@ -110,7 +110,7 @@ export function updateRoleMenu(roleId: number, menuIds: Array) { * * @param roleId */ -export function listRolePerms(roleId: number) { +export function listRolePermission(roleId: number) { return request({ url: '/youlai-admin/api/v1/roles/' + roleId + '/permissions', method: 'get', @@ -124,10 +124,10 @@ export function listRolePerms(roleId: number) { * @param roleId * @param permIds */ -export function saveRolePerms(menuId: number, roleId: number, permIds: Array) { +export function updateRolePermission(menuId: number, roleId: number, permIds: Array) { return request({ url: '/youlai-admin/api/v1/roles/' + roleId + '/permissions', method: 'put', data: {menuId: menuId, permIds: permIds} }) -} \ No newline at end of file +} diff --git a/src/main.ts b/src/main.ts index 9ceb772e..324b9c71 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,8 @@ import {createApp} from 'vue' import App from './App.vue' import router from "./router"; -import {store, key} from './store' +// import {store, key} from './store' +import { setupStore } from "@/store"; import '@/styles/index.scss' import ElementPlus from 'element-plus' @@ -29,10 +30,8 @@ for (let iconName in ElIconModules) { // 全局方法 app.config.globalProperties.$getDictItemsByCode = getDictItemsByCode - -app - .component('Pagination', Pagination) // 全局组件 +setupStore(app); +app.component('Pagination', Pagination) // 全局组件 .use(router) - .use(store, key) .use(ElementPlus, {locale}) - .mount('#app') \ No newline at end of file + .mount('#app') diff --git a/src/permission.ts b/src/permission.ts index 86732f07..3605504e 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -1,8 +1,8 @@ import router from "@router"; import NProgress from 'nprogress'; import {ElMessage} from "element-plus"; -import {store} from "@store"; - +import { usePermissionStoreHook } from "@/store/modules/permission"; +import { useUserStoreHook } from "@/store/modules/user"; NProgress.configure({showSpinner: false}) // 白名单 @@ -11,28 +11,28 @@ const whiteList = ['/login', '/auth-redirect'] router.beforeEach(async (to, form, next) => { NProgress.start() - const hasToken = store.state.user.token + const hasToken =useUserStoreHook().token if (hasToken) { // 如果登录成功,跳转到首页 if (to.path === '/login') { next({path: '/'}) NProgress.done() } else { - const hasGetUserInfo = store.state.user.roles.length > 0 + const hasGetUserInfo =useUserStoreHook().roles.length > 0 if (hasGetUserInfo) { next() } else { try { - await store.dispatch('user/getUserInfo') - const roles = store.state.user.roles - const accessRoutes = await store.dispatch('permission/generateRoutes', roles) + await useUserStoreHook().getUserInfo() + const roles =useUserStoreHook().roles + const accessRoutes:any = await usePermissionStoreHook().generateRoutes(roles) accessRoutes.forEach((route: any) => { router.addRoute(route) }) next({...to, replace: true}) } catch (error) { // remove token and go to login page to re-login - await store.dispatch('user/resetToken') + await useUserStoreHook().resetToken() ElMessage.error(error as any || 'Has Error') next(`/login?redirect=${to.path}`) NProgress.done() @@ -52,4 +52,4 @@ router.beforeEach(async (to, form, next) => { router.afterEach(() => { NProgress.done() -}) \ No newline at end of file +}) diff --git a/src/store/index.ts b/src/store/index.ts index 62e7cd87..96851e65 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,27 +1,9 @@ -import {InjectionKey} from 'vue' -import {createStore,useStore as baseUseStore ,Store} from 'vuex' -import {RootStateTypes} from "@store/interface"; +import type { App } from "vue"; +import { createPinia } from "pinia"; +const store = createPinia(); -// Vite 使用特殊的 import.meta.glob 函数从文件系统导入多个模块 -// @see https://cn.vitejs.dev/guide/features.html#glob-import -const moduleFiles = import.meta.globEager('./modules/*.ts') -const paths:string[]=[] - -for (const path in moduleFiles) { - paths.push(path) -} - -const modules = paths.reduce((modules: { [x: string]: any }, modulePath: string) => { - const moduleKey = modulePath.replace(/^\.\/modules\/(.*)\.\w+$/, '$1'); - modules[moduleKey] = moduleFiles[modulePath].default; - return modules; -}, {}); - -export const key: InjectionKey> = Symbol() - -export const store = createStore({modules}) - -export function useStore(){ - return baseUseStore(key) +export function setupStore(app: App) { + app.use(store); } +export { store }; diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index 7f050ccc..d1f3a648 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -1,18 +1,24 @@ -import {Module} from "vuex"; -import {AppState,RootStateTypes} from "@store/interface"; +// import {Module} from "vuex"; +import {AppState} from "@store/interface"; import {Local} from "@utils/storage"; -const appModule: Module = { - namespaced: true, - state: { +// import { storageLocal } from "/@/utils/storage"; +import { store } from "@/store"; +// import { appType } from "./types"; +import { defineStore } from "pinia"; +// import { getConfig } from "/@/config"; + +export const useAppStore = defineStore({ + id: "youlai-app", + state: ():AppState=>({ device: 'desktop', sidebar: { opened: Local.get('sidebarStatus') ? !!+Local.get('sidebarStatus') : true, withoutAnimation: false } - }, - mutations: { - TOGGLE_SIDEBAR: state => { + }), + actions: { + async TOGGLE_SIDEBAR(state:any) { state.sidebar.opened = !state.sidebar.opened console.log('state.sidebar.opened',state.sidebar.opened) state.sidebar.withoutAnimation = false @@ -22,28 +28,26 @@ const appModule: Module = { Local.set('sidebarStatus', 0) } }, - CLOSE_SIDEBAR: (state, withoutAnimation) => { + async CLOSE_SIDEBAR (state:any, withoutAnimation:any) { Local.set('sidebarStatus', 0) state.sidebar.opened = false state.sidebar.withoutAnimation = withoutAnimation }, - TOGGLE_DEVICE: (state, device) => { + async TOGGLE_DEVICE(state:any, device:any) { console.log('TOGGLE_DEVICE',device) state.device = device - } - }, - actions: { - toggleSideBar({commit}) { - commit('TOGGLE_SIDEBAR') }, - closeSideBar({commit}, {withoutAnimation}) { - commit('CLOSE_SIDEBAR', withoutAnimation) - }, - async toggleDevice({commit}, device) { - commit('TOGGLE_DEVICE', device) - } + // toggleSideBar({commit}) { + // commit('TOGGLE_SIDEBAR') + // }, + // closeSideBar({commit}, {withoutAnimation}) { + // commit('CLOSE_SIDEBAR', withoutAnimation) + // }, + // async toggleDevice({commit}, device) { + // commit('TOGGLE_DEVICE', device) + // } } +}) +export function useAppStoreHook() { + return useAppStore(store); } - -export default appModule; - diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index c918c2f2..0c83d07e 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -1,9 +1,10 @@ -import {Module} from "vuex"; +// import {Module} from "vuex"; import {PermissionState, RootStateTypes} from "@store/interface"; import {RouteRecordRaw} from 'vue-router' import {constantRoutes} from '@/router' import {listRoutes} from "@/api/system/menu"; - +import { defineStore } from "pinia"; +import { store } from "@/store"; const modules = import.meta.glob("../../views/**/**.vue"); export const Layout = () => import( '@/layout/index.vue') @@ -45,20 +46,18 @@ export const filterAsyncRoutes = (routes: RouteRecordRaw[], roles: string[]) => } -const permissionModule: Module = { - namespaced: true, - state: { +export const usePermissionStore = defineStore({ + id:"youlai-permission", + state:():PermissionState=>( { routes: [], addRoutes: [] - }, - mutations: { - SET_ROUTES: (state: PermissionState, routes: RouteRecordRaw[]) => { - state.addRoutes = routes - state.routes = constantRoutes.concat(routes) - } - }, + }), actions: { - generateRoutes({commit}, roles: string[]) { + async SET_ROUTES( routes: RouteRecordRaw[]){ + this.addRoutes = routes + this.routes = constantRoutes.concat(routes) + }, + generateRoutes( roles: string[]) { return new Promise((resolve, reject) => { listRoutes().then(response => { const asyncRoutes = response.data @@ -68,7 +67,7 @@ const permissionModule: Module = { } else { accessedRoutes = filterAsyncRoutes(asyncRoutes, roles) } - commit('SET_ROUTES', accessedRoutes) + this.SET_ROUTES(accessedRoutes) resolve(accessedRoutes) }).catch(error => { reject(error) @@ -76,5 +75,7 @@ const permissionModule: Module = { }) } } +}) +export function usePermissionStoreHook() { + return usePermissionStore(store); } -export default permissionModule; diff --git a/src/store/modules/settings.ts b/src/store/modules/settings.ts index 8c50bbf8..4cfb7812 100644 --- a/src/store/modules/settings.ts +++ b/src/store/modules/settings.ts @@ -1,49 +1,50 @@ -import {Module} from "vuex"; +import { defineStore } from "pinia"; +import { store } from "@/store"; +// import {Module} from "vuex"; import {SettingState, RootStateTypes} from "@store/interface"; import defaultSettings from '../../settings' const {showSettings, tagsView, fixedHeader, sidebarLogo} = defaultSettings -const settingModule: Module = { - namespaced: true, - state: { +export const useSettingStore = defineStore({ + id: "pure-setting", + state:():SettingState =>({ theme: '', showSettings: showSettings, tagsView: tagsView, fixedHeader: fixedHeader, sidebarLogo: sidebarLogo, - }, - mutations: { - CHANGE_SETTING: (state: SettingState, payload: { key: string, value: any }) => { + }), + actions: { + async CHANGE_SETTING( payload: { key: string, value: any }){ const {key, value} = payload switch (key) { case 'theme': - state.theme = value + this.theme = value break case 'showSettings': - state.showSettings = value + this.showSettings = value break case 'fixedHeader': - state.fixedHeader = value + this.fixedHeader = value break case 'tagsView': - state.tagsView = value + this.tagsView = value break case 'sidebarLogo': - state.sidebarLogo = value + this.sidebarLogo = value break default: break } - } - }, - actions: { - changeSetting({commit}, data) { - commit('CHANGE_SETTING', data) + }, + changeSetting(data:any) { + this.CHANGE_SETTING(data) } } +}) + +export function useSettingStoreHook() { + return useSettingStore(store); } -export default settingModule; - - diff --git a/src/store/modules/tagsView.ts b/src/store/modules/tagsView.ts index 5b899588..36f3aad2 100644 --- a/src/store/modules/tagsView.ts +++ b/src/store/modules/tagsView.ts @@ -1,158 +1,161 @@ -import {Module} from "vuex"; +import { defineStore } from "pinia"; +import { store } from "@/store"; +// import {Module} from "vuex"; import {TagsViewState,RootStateTypes} from "@store/interface"; -const tagsViewModule: Module = { - namespaced: true, - state: { +const tagsViewStore=defineStore({ + id:"youlai-tagsView", + state:():TagsViewState=>( { visitedViews: [], cachedViews: [] - }, - mutations: { - ADD_VISITED_VIEW: (state, view) => { - if (state.visitedViews.some(v => v.path === view.path)) return - state.visitedViews.push( + }), + actions: { + async ADD_VISITED_VIEW ( view:any) { + if (this.visitedViews.some(v => v.path === view.path)) return + this.visitedViews.push( Object.assign({}, view, { title: view.meta?.title || 'no-name' }) ) }, - ADD_CACHED_VIEW: (state, view) => { - if (state.cachedViews.includes(view.name)) return + async ADD_CACHED_VIEW(view:any) { + if (this.cachedViews.includes(view.name)) return if (!view.meta.noCache) { - state.cachedViews.push(view.name) + this.cachedViews.push(view.name) } }, - DEL_VISITED_VIEW: (state, view) => { - for (const [i, v] of state.visitedViews.entries()) { + async DEL_VISITED_VIEW( view:any) { + for (const [i, v] of this.visitedViews.entries()) { if (v.path === view.path) { - state.visitedViews.splice(i, 1) + this.visitedViews.splice(i, 1) break } } }, - DEL_CACHED_VIEW: (state, view) => { - const index = state.cachedViews.indexOf(view.name) - index > -1 && state.cachedViews.splice(index, 1) + async DEL_CACHED_VIEW ( view:any) { + const index = this.cachedViews.indexOf(view.name) + index > -1 && this.cachedViews.splice(index, 1) }, - DEL_OTHERS_VISITED_VIEWS: (state, view) => { - state.visitedViews = state.visitedViews.filter(v => { + async DEL_OTHERS_VISITED_VIEWS (view:any) { + this.visitedViews = this.visitedViews.filter(v => { return v.meta?.affix || v.path === view.path }) }, - DEL_OTHERS_CACHED_VIEWS: (state, view) => { - const index = state.cachedViews.indexOf(view.name) + async DEL_OTHERS_CACHED_VIEWS( view:any) { + const index = this.cachedViews.indexOf(view.name) if (index > -1) { - state.cachedViews = state.cachedViews.slice(index, index + 1) + this.cachedViews = this.cachedViews.slice(index, index + 1) } else { // if index = -1, there is no cached tags - state.cachedViews = [] + this.cachedViews = [] } }, - DEL_ALL_VISITED_VIEWS: state => { + DEL_ALL_VISITED_VIEWS() { // keep affix tags - const affixTags = state.visitedViews.filter(tag => tag.meta?.affix) - state.visitedViews = affixTags + const affixTags = this.visitedViews.filter(tag => tag.meta?.affix) + this.visitedViews = affixTags }, - DEL_ALL_CACHED_VIEWS: state => { - state.cachedViews = [] + DEL_ALL_CACHED_VIEWS() { + this.cachedViews = [] }, - UPDATE_VISITED_VIEW: (state, view) => { - for (let v of state.visitedViews) { + UPDATE_VISITED_VIEW (view:any) { + for (let v of this.visitedViews) { if (v.path === view.path) { v = Object.assign(v, view) break } } - } - }, - actions: { - addView({ dispatch }, view) { - dispatch('addVisitedView', view) - dispatch('addCachedView', view) }, - addVisitedView({ commit }, view) { - commit('ADD_VISITED_VIEW', view) + addView( view:any) { + this.addVisitedView( view) + this.addCachedView(view) }, - addCachedView({ commit }, view) { - commit('ADD_CACHED_VIEW', view) + addVisitedView( view:any) { + this.ADD_VISITED_VIEW( view) }, - delView({ dispatch, state }, view) { + addCachedView( view:any) { + this.ADD_CACHED_VIEW(view) + }, + delView( view:any) { return new Promise(resolve => { - dispatch('delVisitedView', view) - dispatch('delCachedView', view) + this.delVisitedView(view) + this.delCachedView( view) resolve({ - visitedViews: [...state.visitedViews], - cachedViews: [...state.cachedViews] + visitedViews: [...this.visitedViews], + cachedViews: [...this.cachedViews] }) }) }, - delVisitedView({ commit, state }, view) { + delVisitedView( view:any) { return new Promise(resolve => { - commit('DEL_VISITED_VIEW', view) - resolve([...state.visitedViews]) + this.DEL_VISITED_VIEW( view) + resolve([...this.visitedViews]) }) }, - delCachedView({ commit, state }, view) { + delCachedView( view:any) { return new Promise(resolve => { - commit('DEL_CACHED_VIEW', view) - resolve([...state.cachedViews]) + this.DEL_CACHED_VIEW(view) + resolve([...this.cachedViews]) }) }, - delOthersViews({ dispatch, state }, view) { + delOthersViews( view:any) { return new Promise(resolve => { - dispatch('delOthersVisitedViews', view) - dispatch('delOthersCachedViews', view) + this.delOthersVisitedViews(view) + this.delOthersCachedViews(view) resolve({ - visitedViews: [...state.visitedViews], - cachedViews: [...state.cachedViews] + visitedViews: [...this.visitedViews], + cachedViews: [...this.cachedViews] }) }) }, - delOthersVisitedViews({ commit, state }, view) { + delOthersVisitedViews( view:any) { return new Promise(resolve => { - commit('DEL_OTHERS_VISITED_VIEWS', view) - resolve([...state.visitedViews]) + this.DEL_OTHERS_VISITED_VIEWS(view) + resolve([...this.visitedViews]) }) }, - delOthersCachedViews({ commit, state }, view) { + delOthersCachedViews( view:any) { return new Promise(resolve => { - commit('DEL_OTHERS_CACHED_VIEWS', view) - resolve([...state.cachedViews]) + this.DEL_OTHERS_CACHED_VIEWS(view) + resolve([...this.cachedViews]) }) }, - delAllViews({ dispatch, state }, view) { + delAllViews( view:any) { return new Promise(resolve => { - dispatch('delAllVisitedViews', view) - dispatch('delAllCachedViews', view) + this.delAllVisitedViews() + this.delAllCachedViews() resolve({ - visitedViews: [...state.visitedViews], - cachedViews: [...state.cachedViews] + visitedViews: [...this.visitedViews], + cachedViews: [...this.cachedViews] }) }) }, - delAllVisitedViews({ commit, state }) { + delAllVisitedViews() { return new Promise(resolve => { - commit('DEL_ALL_VISITED_VIEWS') - resolve([...state.visitedViews]) + this.DEL_ALL_VISITED_VIEWS + resolve([...this.visitedViews]) }) }, - delAllCachedViews({ commit, state }) { + delAllCachedViews() { return new Promise(resolve => { - commit('DEL_ALL_CACHED_VIEWS') - resolve([...state.cachedViews]) + this.DEL_ALL_CACHED_VIEWS + resolve([...this.cachedViews]) }) }, - updateVisitedView({ commit }, view) { - commit('UPDATE_VISITED_VIEW', view) + updateVisitedView( view:any) { + this.UPDATE_VISITED_VIEW(view) } } +}) + + +export function tagsViewStoreHook() { + return tagsViewStore(store); } -export default tagsViewModule; - diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index b03b401e..ebee89b9 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,4 +1,5 @@ -import {Module} from "vuex"; +import { defineStore } from "pinia"; +import { store } from "@/store"; import {UserState, RootStateTypes} from "@store/interface"; import {Local} from "@utils/storage"; import {getUserInfo, login, logout} from "@api/login"; @@ -15,36 +16,35 @@ const getDefaultState = () => { } } -const userModule: Module = { - namespaced: true, - state: { +export const useUserStore = defineStore({ + id:"youlai-user", + state: ():UserState=>({ token: Local.get('token') || '', nickname: '', avatar: '', roles: [], perms: [] - }, - mutations: { - RESET_STATE: (state) => { - Object.assign(state, getDefaultState()) - }, - SET_TOKEN(state: UserState, token: string) { - state.token = token - }, - SET_NICKNAME(state: UserState, nickname: string) { - state.nickname = nickname - }, - SET_AVATAR(state: UserState, avatar: string) { - state.avatar = avatar - }, - SET_ROLES(state: UserState, roles: string[]) { - state.roles = roles - }, - SET_PERMS(state: UserState, perms: string[]) { - state.perms = perms - } - }, + }), actions: { + async RESET_STATE () { + // Object.assign(this.state, getDefaultState()) + this.$reset() + }, + async SET_TOKEN(token: string) { + this.token = token + }, + async SET_NICKNAME( nickname: string) { + this.nickname = nickname + }, + async SET_AVATAR(avatar: string) { + this.avatar = avatar + }, + async SET_ROLES(roles: string[]) { + this.roles = roles + }, + async SET_PERMS( perms: string[]) { + this.perms = perms + }, /** * 用户登录请求 * @param userInfo 登录用户信息 @@ -53,7 +53,7 @@ const userModule: Module = { * code: 验证码 * uuid: 匹配正确验证码的 key */ - login({commit}, userInfo: { username: string, password: string, code: string, uuid: string }) { + login(userInfo: { username: string, password: string, code: string, uuid: string }) { const {username, password, code, uuid} = userInfo return new Promise((resolve, reject) => { login( @@ -68,7 +68,7 @@ const userModule: Module = { const {access_token, token_type} = response.data const accessToken = token_type + " " + access_token Local.set("token", accessToken) - commit('SET_TOKEN', accessToken) + this.SET_TOKEN(accessToken) resolve(access_token) }).catch(error => { reject(error) @@ -78,7 +78,7 @@ const userModule: Module = { /** * 获取用户信息(昵称、头像、角色集合、权限集合) */ - getUserInfo({commit, state}) { + getUserInfo() { return new Promise(((resolve, reject) => { getUserInfo().then(response => { const {data} = response @@ -90,10 +90,10 @@ const userModule: Module = { if (!roles || roles.length <= 0) { reject('getUserInfo: roles must be a non-null array!') } - commit('SET_NICKNAME', nickname) - commit('SET_AVATAR', avatar) - commit('SET_ROLES', roles) - commit('SET_PERMS', perms) + this.SET_NICKNAME(nickname) + this.SET_AVATAR( avatar) + this.SET_ROLES( roles) + this.SET_PERMS( perms) resolve(data) }).catch(error => { @@ -106,11 +106,11 @@ const userModule: Module = { /** * 注销 */ - logout({commit, state}) { + logout() { return new Promise(((resolve, reject) => { logout().then(() => { Local.remove('token') - commit('RESET_STATE') + this.RESET_STATE() resetRouter() resolve(null) }).catch(error => { @@ -122,15 +122,17 @@ const userModule: Module = { /** * 清除 Token */ - resetToken({commit}){ + resetToken(){ return new Promise(resolve=>{ Local.remove('token') - commit('RESET_STATE') + this.RESET_STATE() resolve(null) }) } } +}) + +export function useUserStoreHook() { + return useUserStore(store); } -export default userModule; -