refactor(project): Reorganize frontend and backend directories
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useAppStore = defineStore('admin-app', () => {
|
||||
// 侧边栏折叠状态
|
||||
const sidebarCollapsed = ref(false)
|
||||
|
||||
// 设备类型
|
||||
const device = ref<'desktop' | 'mobile'>('desktop')
|
||||
|
||||
// 切换侧边栏
|
||||
function toggleSidebar() {
|
||||
sidebarCollapsed.value = !sidebarCollapsed.value
|
||||
}
|
||||
|
||||
// 设置设备类型
|
||||
function setDevice(d: 'desktop' | 'mobile') {
|
||||
device.value = d
|
||||
if (d === 'mobile') {
|
||||
sidebarCollapsed.value = true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
sidebarCollapsed,
|
||||
device,
|
||||
toggleSidebar,
|
||||
setDevice
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
export { useUserStore } from './user.ts'
|
||||
export { useAppStore } from './app.ts'
|
||||
export { useTagsViewStore } from './tagsView.ts'
|
||||
@@ -0,0 +1,111 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import type { RouteLocationNormalized } from 'vue-router'
|
||||
|
||||
export interface TagView {
|
||||
path: string
|
||||
name: string
|
||||
title: string
|
||||
fullPath: string
|
||||
query?: Record<string, any>
|
||||
affix?: boolean
|
||||
}
|
||||
|
||||
export const useTagsViewStore = defineStore('admin-tagsView', () => {
|
||||
// 访问过的页面
|
||||
const visitedViews = ref<TagView[]>([])
|
||||
|
||||
// 缓存的页面名称
|
||||
const cachedViews = ref<string[]>([])
|
||||
|
||||
// 添加访问过的页面
|
||||
function addView(view: RouteLocationNormalized) {
|
||||
// 检查是否已存在
|
||||
const exists = visitedViews.value.some((v) => v.path === view.path)
|
||||
if (exists) return
|
||||
|
||||
// 添加新页面
|
||||
visitedViews.value.push({
|
||||
path: view.path,
|
||||
name: view.name as string,
|
||||
title: (view.meta?.title as string) || 'no-name',
|
||||
fullPath: view.fullPath,
|
||||
query: view.query as Record<string, any>,
|
||||
affix: view.meta?.affix as boolean
|
||||
})
|
||||
|
||||
// 添加缓存
|
||||
if (view.name && view.meta?.noCache !== true) {
|
||||
addCachedView(view.name as string)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加缓存页面
|
||||
function addCachedView(name: string) {
|
||||
if (cachedViews.value.includes(name)) return
|
||||
cachedViews.value.push(name)
|
||||
}
|
||||
|
||||
// 删除访问过的页面
|
||||
function delView(view: TagView) {
|
||||
// 删除访问记录
|
||||
const index = visitedViews.value.findIndex((v) => v.path === view.path)
|
||||
if (index > -1) {
|
||||
visitedViews.value.splice(index, 1)
|
||||
}
|
||||
|
||||
// 删除缓存
|
||||
if (view.name) {
|
||||
delCachedView(view.name)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除缓存页面
|
||||
function delCachedView(name: string) {
|
||||
const index = cachedViews.value.indexOf(name)
|
||||
if (index > -1) {
|
||||
cachedViews.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除其他页面
|
||||
function delOthersViews(view: TagView) {
|
||||
visitedViews.value = visitedViews.value.filter((v) => v.affix || v.path === view.path)
|
||||
cachedViews.value = cachedViews.value.filter((name) => name === view.name)
|
||||
}
|
||||
|
||||
// 删除所有页面
|
||||
function delAllViews() {
|
||||
visitedViews.value = visitedViews.value.filter((v) => v.affix)
|
||||
cachedViews.value = []
|
||||
}
|
||||
|
||||
// 删除左侧页面
|
||||
function delLeftViews(view: TagView) {
|
||||
const index = visitedViews.value.findIndex((v) => v.path === view.path)
|
||||
if (index > -1) {
|
||||
visitedViews.value = visitedViews.value.filter((v, i) => v.affix || i >= index)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除右侧页面
|
||||
function delRightViews(view: TagView) {
|
||||
const index = visitedViews.value.findIndex((v) => v.path === view.path)
|
||||
if (index > -1) {
|
||||
visitedViews.value = visitedViews.value.filter((v, i) => v.affix || i <= index)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
visitedViews,
|
||||
cachedViews,
|
||||
addView,
|
||||
addCachedView,
|
||||
delView,
|
||||
delCachedView,
|
||||
delOthersViews,
|
||||
delAllViews,
|
||||
delLeftViews,
|
||||
delRightViews
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,92 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { authApi, type LoginParams, type AdminUser } from '@/api/auth.ts'
|
||||
import router from '@/router'
|
||||
|
||||
const TOKEN_KEY = 'admin_token'
|
||||
const REFRESH_TOKEN_KEY = 'admin_refresh_token'
|
||||
const USER_INFO_KEY = 'admin_user_info'
|
||||
|
||||
export const useUserStore = defineStore('admin-user', () => {
|
||||
// State
|
||||
const token = ref<string>(localStorage.getItem(TOKEN_KEY) || '')
|
||||
const refreshToken = ref<string>(localStorage.getItem(REFRESH_TOKEN_KEY) || '')
|
||||
const userInfo = ref<AdminUser | null>(
|
||||
JSON.parse(localStorage.getItem(USER_INFO_KEY) || 'null')
|
||||
)
|
||||
|
||||
// Getters
|
||||
const isLoggedIn = computed(() => !!token.value)
|
||||
const userId = computed(() => userInfo.value?.id)
|
||||
const username = computed(() => userInfo.value?.username)
|
||||
const nickname = computed(() => userInfo.value?.nickname)
|
||||
const avatar = computed(() => userInfo.value?.avatar)
|
||||
const role = computed(() => userInfo.value?.role)
|
||||
|
||||
// Actions
|
||||
function setToken(accessToken: string, refresh?: string) {
|
||||
token.value = accessToken
|
||||
localStorage.setItem(TOKEN_KEY, accessToken)
|
||||
if (refresh) {
|
||||
refreshToken.value = refresh
|
||||
localStorage.setItem(REFRESH_TOKEN_KEY, refresh)
|
||||
}
|
||||
}
|
||||
|
||||
function setUserInfo(info: AdminUser) {
|
||||
userInfo.value = info
|
||||
localStorage.setItem(USER_INFO_KEY, JSON.stringify(info))
|
||||
}
|
||||
|
||||
async function login(params: LoginParams) {
|
||||
const result = await authApi.login(params)
|
||||
setToken(result.accessToken, result.refreshToken)
|
||||
return result
|
||||
}
|
||||
|
||||
async function fetchUserInfo() {
|
||||
const info = await authApi.getInfo()
|
||||
setUserInfo(info)
|
||||
return info
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
try {
|
||||
await authApi.logout()
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error)
|
||||
} finally {
|
||||
clearAuth()
|
||||
}
|
||||
}
|
||||
|
||||
function clearAuth() {
|
||||
token.value = ''
|
||||
refreshToken.value = ''
|
||||
userInfo.value = null
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
localStorage.removeItem(REFRESH_TOKEN_KEY)
|
||||
localStorage.removeItem(USER_INFO_KEY)
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
token,
|
||||
refreshToken,
|
||||
userInfo,
|
||||
// Getters
|
||||
isLoggedIn,
|
||||
userId,
|
||||
username,
|
||||
nickname,
|
||||
avatar,
|
||||
role,
|
||||
// Actions
|
||||
setToken,
|
||||
setUserInfo,
|
||||
login,
|
||||
fetchUserInfo,
|
||||
logout,
|
||||
clearAuth
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user