refactor(project): Reorganize frontend and backend directories

This commit is contained in:
2026-03-18 10:45:15 +08:00
parent cc9eaf4cdf
commit 92a139e470
513 changed files with 28251 additions and 287 deletions
@@ -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
}
})