更新代码
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
|
||||
const useAuthStore = defineStore('appauth', {
|
||||
state: () => {
|
||||
return {
|
||||
isLogin: false,
|
||||
_userInfo: null,
|
||||
}
|
||||
},
|
||||
|
||||
persist: true,
|
||||
|
||||
getters: {
|
||||
userInfo(): IUser | null {
|
||||
return this._userInfo
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
login(data: any) {
|
||||
this.isLogin = true
|
||||
this._userInfo = data
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
export default useAuthStore
|
||||
@@ -0,0 +1,115 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
const color2rgb = (color: string) => {
|
||||
return color.startsWith('#') ? hex2rgb(color) : rgb2rgb(color)
|
||||
}
|
||||
|
||||
// rgb(255, 0, 0) | rgba(255, 0, 0) => [255, 0, 0]
|
||||
const rgb2rgb = (color: string) => {
|
||||
const colors = color.split('(')[1].split(')')[0].split(',')
|
||||
return colors.slice(0, 3).map(item => parseInt(item.trim()))
|
||||
}
|
||||
|
||||
// #FF0000 => [255, 0, 0]
|
||||
const hex2rgb = (color: string) => {
|
||||
color = color.replace('#', '')
|
||||
const matchs = color.match(/../g)
|
||||
|
||||
const rgbs: number[] = []
|
||||
for (let i = 0; i < matchs!.length; i++) {
|
||||
rgbs[i] = parseInt(matchs![i], 16)
|
||||
}
|
||||
|
||||
return rgbs
|
||||
}
|
||||
|
||||
const rgb2hex = (r: number, g: number, b: number) => {
|
||||
const hexs = [r.toString(16), g.toString(16), b.toString(16)]
|
||||
|
||||
for (let i = 0; i < hexs.length; i++) {
|
||||
if (hexs[i].length === 1) {
|
||||
hexs[i] = '0' + hexs[i]
|
||||
}
|
||||
}
|
||||
|
||||
return '#' + hexs.join('')
|
||||
}
|
||||
|
||||
// 颜色变亮
|
||||
const lighten = (color: string, level: number) => {
|
||||
const rgbs = color2rgb(color)
|
||||
|
||||
for (let i = 0; i < rgbs.length; i++) {
|
||||
rgbs[i] = Math.floor((255 - rgbs[i]) * level + rgbs[i])
|
||||
}
|
||||
|
||||
return rgb2hex(rgbs[0], rgbs[1], rgbs[2])
|
||||
}
|
||||
|
||||
// 颜色变暗
|
||||
const darken = (color: string, level: number) => {
|
||||
const rgbs = color2rgb(color)
|
||||
|
||||
for (let i = 0; i < rgbs.length; i++) {
|
||||
rgbs[i] = Math.floor(rgbs[i] * (1 - level))
|
||||
}
|
||||
|
||||
return rgb2hex(rgbs[0], rgbs[1], rgbs[2])
|
||||
}
|
||||
|
||||
const useColorStore = defineStore('appcolor', {
|
||||
state: () => {
|
||||
return {
|
||||
primary: '#409EFF',
|
||||
primaryPredefines: [
|
||||
'#409EFF',
|
||||
'#67C23A',
|
||||
'#E6A23C',
|
||||
'#F56C6C',
|
||||
'#909399',
|
||||
'#FF6B6B',
|
||||
'#4ECDC4',
|
||||
'#45B7D1',
|
||||
'#96CEB4',
|
||||
'#FFEAA7',
|
||||
'#DDA0DD',
|
||||
'#98D8C8'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
primaryChange(color: string | null) {
|
||||
if (!color) return
|
||||
|
||||
// 设置 CSS 变量
|
||||
document.documentElement.style.setProperty('--el-color-primary', color)
|
||||
|
||||
// 生成不同深浅的主题色
|
||||
const colors = {
|
||||
'primary': color,
|
||||
'primary-light-3': lighten(color, 0.3),
|
||||
'primary-light-5': lighten(color, 0.5),
|
||||
'primary-light-7': lighten(color, 0.7),
|
||||
'primary-light-8': lighten(color, 0.8),
|
||||
'primary-light-9': lighten(color, 0.9),
|
||||
'primary-dark-2': darken(color, 0.2)
|
||||
}
|
||||
|
||||
// 设置所有主题色变量
|
||||
Object.entries(colors).forEach(([key, value]) => {
|
||||
document.documentElement.style.setProperty(`--el-color-${key}`, value)
|
||||
})
|
||||
},
|
||||
|
||||
primarySave(color: string | null) {
|
||||
if (!color) return
|
||||
this.primary = color
|
||||
this.primaryChange(color)
|
||||
}
|
||||
},
|
||||
|
||||
persist: true,
|
||||
})
|
||||
|
||||
export default useColorStore
|
||||
@@ -0,0 +1,108 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
const idMap: Map<string, number> = new Map()
|
||||
|
||||
const useFastnavStore = defineStore('appfastnav', {
|
||||
state: () => {
|
||||
const datas: IFastnavItem[] = []
|
||||
const currPath: string = ''
|
||||
|
||||
return {
|
||||
datas,
|
||||
currPath,
|
||||
}
|
||||
},
|
||||
|
||||
persist: true,
|
||||
|
||||
actions: {
|
||||
addData(desc: string, path: string) {
|
||||
const data = this.datas.find(item => item.path == path)
|
||||
if (data) {
|
||||
this.currPath = path
|
||||
return
|
||||
}
|
||||
|
||||
this.datas.push({ desc, path })
|
||||
|
||||
this.currPath = path
|
||||
},
|
||||
removeData(path: string): string {
|
||||
if (this.datas.length <= 1) return ''
|
||||
|
||||
for (let i = 0; i < this.datas.length; i++) {
|
||||
const item = this.datas[i]
|
||||
if (item.path != path) continue
|
||||
|
||||
// 修改:删除数据
|
||||
this.datas.splice(i, 1)
|
||||
|
||||
if (item.path != this.currPath) return ''
|
||||
|
||||
return i == 0 ? this.datas[0].path : this.datas[i - 1].path
|
||||
}
|
||||
|
||||
return ''
|
||||
},
|
||||
removeOther(path: string): string {
|
||||
const data = this.datas.find(item => item.path == path)
|
||||
if (!data) return ''
|
||||
|
||||
this.idAddAll(this.datas, path)
|
||||
this.datas = [data]
|
||||
|
||||
return path == this.currPath ? '' : path
|
||||
},
|
||||
removeLeft(path: string): string {
|
||||
for (let i = 0; i < this.datas.length; i++) {
|
||||
const data = this.datas[i]
|
||||
if (data.path != path) continue
|
||||
|
||||
const removes = this.datas.splice(0, i)
|
||||
this.idAddAll(removes)
|
||||
|
||||
return path == this.currPath ? '' : path
|
||||
}
|
||||
|
||||
return ''
|
||||
},
|
||||
removeRight(path: string): string {
|
||||
for (let i = 0; i < this.datas.length; i++) {
|
||||
const data = this.datas[i]
|
||||
if (data.path != path) continue
|
||||
|
||||
const removes = this.datas.splice(i + 1)
|
||||
this.idAddAll(removes)
|
||||
|
||||
return path == this.currPath ? '' : path
|
||||
}
|
||||
|
||||
return ''
|
||||
},
|
||||
idGet(path: string): string {
|
||||
const id = idMap.get(path) ?? 1
|
||||
return path + id
|
||||
},
|
||||
idAdd(path: string): number {
|
||||
// 自增id并返回
|
||||
const id = (idMap.get(path) ?? 1) + 1
|
||||
idMap.set(path, id)
|
||||
return id
|
||||
},
|
||||
idAddAll(datas: IFastnavItem[], excludePath?: string) {
|
||||
datas.forEach(item => {
|
||||
if (item.path != excludePath) {
|
||||
this.idAdd(item.path)
|
||||
}
|
||||
})
|
||||
},
|
||||
isFirst(path: string): boolean {
|
||||
return this.datas.length > 0 && this.datas[0].path == path
|
||||
},
|
||||
isLast(path: string): boolean {
|
||||
return this.datas.length > 0 && this.datas[this.datas.length - 1].path == path
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export default useFastnavStore
|
||||
@@ -0,0 +1,6 @@
|
||||
//仓库大仓库
|
||||
import { createPinia } from 'pinia'
|
||||
//创建大仓库
|
||||
const pinia = createPinia()
|
||||
//对外暴露:入口文件需要安装仓库
|
||||
export default pinia
|
||||
@@ -0,0 +1,19 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
const useMenuStore = defineStore('appmenu', {
|
||||
state: () => {
|
||||
return {
|
||||
collapse: false,
|
||||
}
|
||||
},
|
||||
|
||||
getters: {
|
||||
width(): string {
|
||||
return this.collapse ? '64px' : '200px'
|
||||
}
|
||||
},
|
||||
|
||||
persist: true,
|
||||
})
|
||||
|
||||
export default useMenuStore
|
||||
@@ -0,0 +1,91 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { getUserMenus, getMenuList, getTempUserMenus, type MenuItem } from '@/api/menu'
|
||||
import ENV_CONFIG from '@/config/env'
|
||||
|
||||
interface MenuState {
|
||||
menus: MenuItem[]
|
||||
loading: boolean
|
||||
error: string | null
|
||||
}
|
||||
|
||||
interface ApiResponse<T> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
|
||||
const useMenuStore = defineStore('menu', {
|
||||
state: (): MenuState => ({
|
||||
menus: [],
|
||||
loading: false,
|
||||
error: null
|
||||
}),
|
||||
|
||||
getters: {
|
||||
// 获取菜单列表
|
||||
getMenus: (state) => state.menus,
|
||||
|
||||
// 获取加载状态
|
||||
getLoading: (state) => state.loading,
|
||||
|
||||
// 获取错误信息
|
||||
getError: (state) => state.error
|
||||
},
|
||||
|
||||
actions: {
|
||||
// 获取用户菜单(使用临时接口)
|
||||
async fetchUserMenus() {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const response = await getTempUserMenus() as unknown as ApiResponse<MenuItem[]>
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
this.menus = response.data
|
||||
} else {
|
||||
throw new Error(response.message || '获取菜单失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.error = error.message || '获取菜单失败'
|
||||
console.error('获取用户菜单失败:', error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 获取所有菜单(管理员用)
|
||||
async fetchAllMenus() {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const response = await getMenuList() as unknown as ApiResponse<MenuItem[]>
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
this.menus = response.data
|
||||
} else {
|
||||
throw new Error(response.message || '获取菜单失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.error = error.message || '获取菜单失败'
|
||||
console.error('获取所有菜单失败:', error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 清除菜单数据
|
||||
clearMenus() {
|
||||
this.menus = []
|
||||
this.error = null
|
||||
},
|
||||
|
||||
// 设置错误信息
|
||||
setError(error: string) {
|
||||
this.error = error
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default useMenuStore
|
||||
@@ -0,0 +1,146 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { login as loginApi, getUserInfo as getUserInfoApi, logout as logoutApi } from '@/api/user'
|
||||
import ENV_CONFIG from '@/config/env'
|
||||
|
||||
interface LoginForm {
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
|
||||
interface UserInfo {
|
||||
id: number
|
||||
username: string
|
||||
name: string
|
||||
avatar?: string
|
||||
role: string
|
||||
}
|
||||
|
||||
interface ApiResponse<T> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
|
||||
interface LoginResponse {
|
||||
token: string
|
||||
userInfo: UserInfo
|
||||
}
|
||||
|
||||
const useUserStore = defineStore('user', {
|
||||
state: () => {
|
||||
return {
|
||||
token: '',
|
||||
userInfo: null as UserInfo | null,
|
||||
isLogin: false
|
||||
}
|
||||
},
|
||||
|
||||
getters: {
|
||||
// 获取用户信息
|
||||
getUserInfo: (state) => state.userInfo,
|
||||
// 获取token
|
||||
getToken: (state) => state.token,
|
||||
// 是否已登录
|
||||
getIsLogin: (state) => state.isLogin
|
||||
},
|
||||
|
||||
actions: {
|
||||
// 用户登录
|
||||
async userLogin(loginForm: LoginForm) {
|
||||
try {
|
||||
const response = await loginApi(loginForm) as unknown as ApiResponse<LoginResponse>
|
||||
|
||||
// 假设API返回格式为 { code: 200, data: { token: string, userInfo: UserInfo } }
|
||||
if (response.code === 200 && response.data) {
|
||||
const { token, userInfo } = response.data
|
||||
|
||||
// 保存登录状态
|
||||
this.token = token
|
||||
this.userInfo = userInfo
|
||||
this.isLogin = true
|
||||
|
||||
// 保存到 localStorage
|
||||
localStorage.setItem(ENV_CONFIG.TOKEN_KEY, token)
|
||||
localStorage.setItem(ENV_CONFIG.USER_INFO_KEY, JSON.stringify(userInfo))
|
||||
|
||||
return userInfo
|
||||
} else {
|
||||
throw new Error(response.message || '登录失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
// 处理不同类型的错误
|
||||
if (error.response?.data?.message) {
|
||||
throw new Error(error.response.data.message)
|
||||
} else if (error.message) {
|
||||
throw new Error(error.message)
|
||||
} else {
|
||||
throw new Error('登录失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 用户登出
|
||||
async userLogout() {
|
||||
try {
|
||||
await logoutApi()
|
||||
} catch (error) {
|
||||
console.error('登出API调用失败:', error)
|
||||
} finally {
|
||||
this.token = ''
|
||||
this.userInfo = null
|
||||
this.isLogin = false
|
||||
|
||||
// 清除 localStorage
|
||||
localStorage.removeItem(ENV_CONFIG.TOKEN_KEY)
|
||||
localStorage.removeItem(ENV_CONFIG.USER_INFO_KEY)
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化用户状态(从 localStorage 恢复)
|
||||
async initUserState() {
|
||||
const token = localStorage.getItem(ENV_CONFIG.TOKEN_KEY)
|
||||
const userInfoStr = localStorage.getItem(ENV_CONFIG.USER_INFO_KEY)
|
||||
|
||||
if (token && userInfoStr) {
|
||||
try {
|
||||
// 验证token是否有效
|
||||
const response = await getUserInfoApi() as unknown as ApiResponse<UserInfo>
|
||||
if (response.code === 200 && response.data) {
|
||||
this.token = token
|
||||
this.userInfo = response.data
|
||||
this.isLogin = true
|
||||
} else {
|
||||
// token无效,清除本地存储但不调用logout API
|
||||
this.clearUserState()
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('获取用户信息失败:', error)
|
||||
// 网络错误时,不清除本地状态,保持用户登录状态
|
||||
// 只有在明确知道token无效时才清除
|
||||
if (error.response?.status === 401) {
|
||||
this.clearUserState()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 清除用户状态(不调用API)
|
||||
clearUserState() {
|
||||
this.token = ''
|
||||
this.userInfo = null
|
||||
this.isLogin = false
|
||||
|
||||
// 清除 localStorage
|
||||
localStorage.removeItem(ENV_CONFIG.TOKEN_KEY)
|
||||
localStorage.removeItem(ENV_CONFIG.USER_INFO_KEY)
|
||||
}
|
||||
},
|
||||
|
||||
persist: {
|
||||
key: 'user-store',
|
||||
storage: localStorage,
|
||||
paths: ['token', 'userInfo', 'isLogin']
|
||||
}
|
||||
})
|
||||
|
||||
export default useUserStore
|
||||
Reference in New Issue
Block a user