first commit
This commit is contained in:
248
frontend/src/stores/admin.ts
Normal file
248
frontend/src/stores/admin.ts
Normal file
@@ -0,0 +1,248 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { adminAPI } from '@/utils/api'
|
||||
import { adminAuth } from '@/utils/auth'
|
||||
import type { User, PaginatedResponse } from '@/types'
|
||||
|
||||
export const useAdminStore = defineStore('admin', () => {
|
||||
// 状态
|
||||
const admin = ref<User | null>(null)
|
||||
const token = ref<string | null>(null)
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
const users = ref<User[]>([])
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
totalPages: 0
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
const isLoggedIn = computed(() => !!token.value && !!admin.value)
|
||||
|
||||
// 初始化认证状态
|
||||
const initAuth = () => {
|
||||
const storedToken = adminAuth.getToken()
|
||||
const storedAdmin = adminAuth.getAdminInfo()
|
||||
|
||||
if (storedToken && storedAdmin) {
|
||||
token.value = storedToken
|
||||
admin.value = storedAdmin
|
||||
}
|
||||
}
|
||||
|
||||
// 管理员登录
|
||||
const login = async (data: { username: string; password: string }) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.login(data)
|
||||
|
||||
// 保存认证信息
|
||||
token.value = response.token
|
||||
admin.value = response.admin
|
||||
adminAuth.setLogin(response.token, response.admin)
|
||||
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '登录失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 管理员登出
|
||||
const logout = async () => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
// 清除本地状态
|
||||
token.value = null
|
||||
admin.value = null
|
||||
users.value = []
|
||||
adminAuth.logout()
|
||||
} catch (err) {
|
||||
console.warn('Admin logout failed:', err)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
const loadUsers = async (params?: { page?: number; limit?: number; search?: string }) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.getUsers(params)
|
||||
users.value = response.users
|
||||
pagination.value = response.pagination
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '获取用户列表失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
const createUser = async (data: {
|
||||
username: string
|
||||
password: string
|
||||
role: string
|
||||
}) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.createUser(data)
|
||||
// 重新加载用户列表
|
||||
await loadUsers()
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '创建用户失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户
|
||||
const updateUser = async (userId: string, data: any) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.updateUser(userId, data)
|
||||
// 重新加载用户列表
|
||||
await loadUsers()
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '更新用户失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户账号权限
|
||||
const updateUserAccounts = async (userId: string, accountIds: string[]) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.updateUserAccounts(userId, accountIds)
|
||||
// 重新加载用户列表
|
||||
await loadUsers()
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '更新用户账号权限失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
const deleteUser = async (userId: string) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.deleteUser(userId)
|
||||
// 重新加载用户列表
|
||||
await loadUsers()
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '删除用户失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取统计数据
|
||||
const getStats = async () => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.getStats()
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '获取统计数据失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取最近活动
|
||||
const getRecentActivities = async () => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.getRecentActivities()
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '获取最近活动失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取账号列表
|
||||
const getAccounts = async (params?: { page?: number; limit?: number; search?: string; status?: string }) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await adminAPI.getAccounts(params)
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '获取账号列表失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 清除错误
|
||||
const clearError = () => {
|
||||
error.value = null
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
admin,
|
||||
token,
|
||||
loading,
|
||||
error,
|
||||
users,
|
||||
pagination,
|
||||
|
||||
// 计算属性
|
||||
isLoggedIn,
|
||||
|
||||
// 方法
|
||||
initAuth,
|
||||
login,
|
||||
logout,
|
||||
loadUsers,
|
||||
createUser,
|
||||
updateUser,
|
||||
updateUserAccounts,
|
||||
deleteUser,
|
||||
getStats,
|
||||
getRecentActivities,
|
||||
getAccounts,
|
||||
clearError
|
||||
}
|
||||
})
|
||||
247
frontend/src/stores/auth.ts
Normal file
247
frontend/src/stores/auth.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { authAPI } from '@/utils/api'
|
||||
import { userAuth } from '@/utils/auth'
|
||||
import type { User } from '@/types'
|
||||
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
// 状态
|
||||
const user = ref<User | null>(null)
|
||||
const token = ref<string | null>(null)
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
// 计算属性
|
||||
const isLoggedIn = computed(() => !!token.value && !!user.value)
|
||||
|
||||
// 初始化认证状态
|
||||
const initAuth = () => {
|
||||
const storedToken = userAuth.getToken()
|
||||
const storedUser = userAuth.getUserInfo()
|
||||
|
||||
if (storedToken && storedUser) {
|
||||
token.value = storedToken
|
||||
user.value = storedUser
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 用户注册
|
||||
const register = async (data: {
|
||||
username: string
|
||||
password: string
|
||||
confirmPassword: string
|
||||
}) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.register(data)
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '注册失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 用户登录
|
||||
const login = async (data: {
|
||||
username: string
|
||||
password: string
|
||||
}) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.login(data)
|
||||
|
||||
// 保存认证信息
|
||||
token.value = response.token
|
||||
user.value = response.user
|
||||
userAuth.setLogin(response.token, response.user)
|
||||
|
||||
return response
|
||||
} catch (err: any) {
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 邮箱验证
|
||||
const verifyEmail = async (token: string) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.verifyEmail(token)
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '邮箱验证失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重新发送验证邮件
|
||||
const resendVerification = async (email: string) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.resendVerification(email)
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '发送验证邮件失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 忘记密码
|
||||
const forgotPassword = async (email: string) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.forgotPassword(email)
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '发送重置邮件失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置密码
|
||||
const resetPassword = async (data: {
|
||||
token: string
|
||||
password: string
|
||||
}) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.resetPassword(data)
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '重置密码失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 设置TOTP
|
||||
const setupTOTP = async () => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.setupTOTP()
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '设置二步验证失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 验证TOTP
|
||||
const verifyTOTP = async (totpToken: string) => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.verifyTOTP(totpToken)
|
||||
|
||||
// 更新用户信息
|
||||
if (user.value && token.value) {
|
||||
user.value.totpEnabled = true
|
||||
userAuth.setLogin(token.value, user.value)
|
||||
}
|
||||
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '验证失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
const getProfile = async () => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await authAPI.getProfile()
|
||||
user.value = response.user
|
||||
if (token.value) {
|
||||
userAuth.setLogin(token.value, response.user)
|
||||
}
|
||||
return response
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.message || '获取用户信息失败'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 用户登出
|
||||
const logout = async () => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
await authAPI.logout()
|
||||
} catch (err: any) {
|
||||
console.error('登出API调用失败:', err)
|
||||
} finally {
|
||||
// 清除本地状态
|
||||
token.value = null
|
||||
user.value = null
|
||||
userAuth.logout()
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 清除错误
|
||||
const clearError = () => {
|
||||
error.value = null
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
user,
|
||||
token,
|
||||
loading,
|
||||
error,
|
||||
|
||||
// 计算属性
|
||||
isLoggedIn,
|
||||
|
||||
// 方法
|
||||
initAuth,
|
||||
register,
|
||||
login,
|
||||
verifyEmail,
|
||||
resendVerification,
|
||||
forgotPassword,
|
||||
resetPassword,
|
||||
setupTOTP,
|
||||
verifyTOTP,
|
||||
getProfile,
|
||||
logout,
|
||||
clearError
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user