feat(other): init

This commit is contained in:
2026-01-19 03:06:04 +08:00
commit 2b97d4ef6c
195 changed files with 30912 additions and 0 deletions

7
src/store/index.js Normal file
View File

@@ -0,0 +1,7 @@
import { createPinia } from 'pinia'
export function setupStore(app) {
app.use(createPinia())
}
export * from './modules'

View File

@@ -0,0 +1,28 @@
import { defineStore } from 'pinia'
import { useDark } from '@vueuse/core'
const isDark = useDark()
export const useAppStore = defineStore('app', {
state() {
return {
collapsed: false,
isDark,
}
},
actions: {
switchCollapsed() {
this.collapsed = !this.collapsed
},
setCollapsed(collapsed) {
this.collapsed = collapsed
},
/** 设置暗黑模式 */
setDark(isDark) {
this.isDark = isDark
},
/** 切换/关闭 暗黑模式 */
toggleDark() {
this.isDark = !this.isDark
},
},
})

View File

@@ -0,0 +1,4 @@
export * from './app'
export * from './permission'
export * from './tags'
export * from './user'

View File

@@ -0,0 +1,132 @@
import { defineStore } from 'pinia'
import { basicRoutes } from '@/router/routes'
import { RouterView } from 'vue-router'
const Layout = () => import('@/layout/index.vue')
// 匹配views里面所有的.vue文件动态引入
const modules = import.meta.glob('/src/views/**/*.vue')
//
export function getModulesKey() {
return Object.keys(modules).map((item) => item.replace('/src/views/', '').replace('.vue', ''))
}
// 动态加载组件
export function loadRouteView(component) {
try {
const key = Object.keys(modules).find((key) => {
return key.includes(`${component}.vue`)
})
if (key) {
return modules[key]
}
throw Error(`找不到组件${component},请确保组件路径正确`)
} catch (error) {
console.error(error)
return RouterView
}
}
// function hasPermission(route, role) {
// // * 不需要权限直接返回true
// if (!route.meta?.requireAuth) return true
// const routeRole = route.meta?.role ? route.meta.role : []
// // * 登录用户没有角色或者路由没有设置角色判定为没有权限
// if (!role.length || !routeRole.length) return false
// // * 路由指定的角色包含任一登录用户角色则判定有权限
// return role.some((item) => routeRole.includes(item))
// }
// 过滤异步路由
function filterAsyncRoutes(routes = [], firstRoute = true) {
const ret = []
routes.forEach((route) => {
// 过滤掉type为3的路由
if (route.type === 3) return
const isHidden = route.is_show === 1 ? false : true
const meta = {
requireAuth: true,
title: route.name,
icon: route.icon,
order: route.sort,
}
const curRoute = {
path: route.route,
name: route.route,
isHidden,
meta,
children: [],
}
// if (route.route === '/' && firstRoute) {
// curRoute['redirect'] = route.subMenu[0].route
// } else if (route.subMenu && route.type === 1) {
// curRoute['redirect'] = `${route.subMenu[0].route}`
// }
if (route.subMenu && route.subMenu.length) {
curRoute.children = filterAsyncRoutes(route.subMenu, false)
} else {
Reflect.deleteProperty(curRoute, 'children')
}
switch (route.type) {
case 1:
curRoute.component = firstRoute ? Layout : RouterView
break
case 2:
curRoute.component = loadRouteView(route.components)
break
}
ret.push(curRoute)
})
return ret
}
// 递归寻找type为3的路由
function findType3Routes(routes = []) {
const ret = []
routes.forEach((route) => {
if (route.type === 3) {
ret.push(route.api_route)
}
if (route.subMenu && route.subMenu.length) {
ret.push(...findType3Routes(route.subMenu))
}
})
return ret
}
export const usePermissionStore = defineStore('permission', {
state() {
return {
accessRoutes: [],
}
},
getters: {
routes() {
return basicRoutes.concat(this.accessRoutes)
},
menus() {
return this.routes.filter((route) => route.name && !route.isHidden)
},
},
actions: {
generateRoutes() {
const menus = JSON.parse(localStorage.getItem('menu'))
const accessRoutes = filterAsyncRoutes(menus)
window.localStorage.setItem('roles', JSON.stringify(findType3Routes(menus)))
this.accessRoutes = accessRoutes
return accessRoutes
},
resetPermission() {
this.$reset()
},
},
})

View File

@@ -0,0 +1,6 @@
import { sStorage } from '@/utils'
export const activeTag = sStorage.get('activeTag')
export const tags = sStorage.get('tags')
export const WITHOUT_TAG_PATHS = ['/404', '/login']

View File

@@ -0,0 +1,83 @@
import { defineStore } from 'pinia'
import { activeTag, tags, WITHOUT_TAG_PATHS } from './helpers'
import { router } from '@/router'
import { sStorage } from '@/utils'
export const useTagsStore = defineStore('tag', {
state() {
return {
tags: tags || [],
activeTag: activeTag || '',
reloading: false,
}
},
getters: {
activeIndex() {
return this.tags.findIndex((item) => item.path === this.activeTag)
},
},
actions: {
setActiveTag(path) {
this.activeTag = path
sStorage.set('activeTag', path)
},
setTags(tags) {
this.tags = tags
sStorage.set('tags', tags)
},
addTag(tag = {}) {
if (WITHOUT_TAG_PATHS.includes(tag.path)) return
let findItem = this.tags.find((item) => item.path === tag.path)
if (findItem) findItem = tag
else this.setTags([...this.tags, tag])
this.setActiveTag(tag.path)
},
async reloadTag(path, keepAlive) {
const findItem = this.tags.find((item) => item.path === path)
// 更新key可让keepAlive失效
if (findItem && keepAlive) findItem.keepAlive = false
$loadingBar.start()
this.reloading = true
await nextTick()
this.reloading = false
findItem.keepAlive = keepAlive
setTimeout(() => {
document.documentElement.scrollTo({ left: 0, top: 0 })
$loadingBar.finish()
}, 100)
},
removeTag(path) {
this.setTags(this.tags.filter((tag) => tag.path !== path))
if (path === this.activeTag) {
router.push(this.tags[this.tags.length - 1].path)
}
},
removeOther(curPath = this.activeTag) {
this.setTags(this.tags.filter((tag) => tag.path === curPath))
if (curPath !== this.activeTag) {
router.push(this.tags[this.tags.length - 1].path)
}
},
removeLeft(curPath) {
const curIndex = this.tags.findIndex((item) => item.path === curPath)
const filterTags = this.tags.filter((item, index) => index >= curIndex)
this.setTags(filterTags)
if (!filterTags.find((item) => item.path === this.activeTag)) {
router.push(filterTags[filterTags.length - 1].path)
}
},
removeRight(curPath) {
const curIndex = this.tags.findIndex((item) => item.path === curPath)
const filterTags = this.tags.filter((item, index) => index <= curIndex)
this.setTags(filterTags)
if (!filterTags.find((item) => item.path === this.activeTag)) {
router.push(filterTags[filterTags.length - 1].path)
}
},
resetTags() {
this.setTags([])
this.setActiveTag('')
},
},
})

View File

@@ -0,0 +1,52 @@
import { defineStore } from 'pinia'
// import { resetRouter } from '@/router'
import { useTagsStore, usePermissionStore } from '@/store'
import { removeToken, toLogin } from '@/utils'
// import api from '@/api'
export const useUserStore = defineStore('user', {
state() {
return {
userInfo: {},
}
},
getters: {
userId() {
return this.userInfo?.id
},
name() {
return this.userInfo?.name
},
avatar() {
return this.userInfo?.avatar || 'https://v2.xxapi.cn/api/head?return=302'
},
role() {
return this.userInfo?.role || []
},
},
actions: {
async getUserInfo() {
// try {
// const res = await api.getUser()
// const { id, name, avatar, role } = res.data
// this.userInfo = { id, name, avatar, role }
// return Promise.resolve(res.data)
// } catch (error) {
// return Promise.reject(error)
// }
},
async logout() {
const { resetTags } = useTagsStore()
const { resetPermission } = usePermissionStore()
removeToken()
resetTags()
resetPermission()
// resetRouter()
this.$reset()
toLogin()
},
setUserInfo(userInfo = {}) {
this.userInfo = { ...this.userInfo, ...userInfo }
},
},
})