核心功能: - 项目初始化 (Nuxt 4 + Nuxt UI + Pinia + ofetch) - TypeScript 类型定义 (User, Article, Comment, API 响应) - 认证系统 (登录/登出、Cookie 支持、权限中间件) - 文章列表页 (筛选、分页、响应式布局) - 文章详情页 (Markdown 渲染、评论系统) - 文章编辑器 (左右分栏、实时预览、Markdown 工具栏) 管理后台: - 侧边栏布局、权限检查 - 数据分析 (数据统计卡片、热门文章、评论审核统计) - 文章管理 (表格、筛选、删除) - 评论管理 (审核通过/拒绝、删除) - 用户管理 (角色管理、删除) 全局组件: - 导航栏 (暗色模式切换、移动端菜单) - 页脚 - 403/404 错误页 配置文件: - .env.example 环境变量模板 - nuxt.config.ts 完整配置 - 自定义 CSS 样式
106 lines
2.4 KiB
TypeScript
106 lines
2.4 KiB
TypeScript
import type { User, LoginCredentials } from '~/types/models'
|
|
|
|
export function useAuth() {
|
|
const authStore = useAuthStore()
|
|
const { get, post, delete: deleteRequest } = useApi()
|
|
const router = useRouter()
|
|
|
|
const fetchUser = async (): Promise<User | null> => {
|
|
try {
|
|
const user = await get<User>('/me')
|
|
authStore.setUser(user)
|
|
return user
|
|
} catch {
|
|
authStore.clearUser()
|
|
return null
|
|
}
|
|
}
|
|
|
|
const checkAuth = async (): Promise<boolean> => {
|
|
authStore.setLoading(true)
|
|
try {
|
|
const user = await fetchUser()
|
|
return !!user
|
|
} finally {
|
|
authStore.setLoading(false)
|
|
}
|
|
}
|
|
|
|
const login = async (credentials: LoginCredentials): Promise<User> => {
|
|
authStore.setLoading(true)
|
|
authStore.setError(null)
|
|
try {
|
|
const response = await post<{ user: User }>('/login', credentials)
|
|
authStore.setUser(response.user)
|
|
|
|
const route = useRoute()
|
|
const from = route.query.from as string
|
|
if (from && !from.includes('/admin')) {
|
|
await router.push(from)
|
|
} else {
|
|
await router.push('/')
|
|
}
|
|
|
|
return response.user
|
|
} catch (err: any) {
|
|
authStore.setError(err.data?.message || '登录失败')
|
|
throw err
|
|
} finally {
|
|
authStore.setLoading(false)
|
|
}
|
|
}
|
|
|
|
const logout = async (): Promise<void> => {
|
|
try {
|
|
await deleteRequest('/logout')
|
|
} finally {
|
|
authStore.clearUser()
|
|
await router.push('/login')
|
|
}
|
|
}
|
|
|
|
const requireAuth = async (redirect = true): Promise<boolean> => {
|
|
if (authStore.isAuthenticated) {
|
|
return true
|
|
}
|
|
|
|
if (authStore.isLoading) {
|
|
await new Promise(resolve => setTimeout(resolve, 100))
|
|
return requireAuth(redirect)
|
|
}
|
|
|
|
if (redirect) {
|
|
const route = useRoute()
|
|
await router.push(`/login?from=${route.fullPath}`)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
const requireAdmin = async (): Promise<boolean> => {
|
|
const authenticated = await requireAuth()
|
|
if (!authenticated) return false
|
|
|
|
if (!authStore.isAdmin) {
|
|
await router.push('/403')
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
return {
|
|
user: computed(() => authStore.user),
|
|
isAuthenticated: computed(() => authStore.isAuthenticated),
|
|
isAdmin: computed(() => authStore.isAdmin),
|
|
isLoading: computed(() => authStore.isLoading),
|
|
error: computed(() => authStore.error),
|
|
login,
|
|
logout,
|
|
fetchUser,
|
|
checkAuth,
|
|
requireAuth,
|
|
requireAdmin,
|
|
}
|
|
}
|