228 lines
5.4 KiB
TypeScript
Raw Permalink Normal View History

2025-06-26 11:24:11 +08:00
// 管理员用户管理API
import { serverSupabaseClient, serverSupabaseUser } from '#supabase/server'
export default defineEventHandler(async (event) => {
const supabase = await serverSupabaseClient(event)
const user = await serverSupabaseUser(event)
if (!user) {
throw createError({
statusCode: 401,
statusMessage: '未授权访问'
})
}
// 验证管理员权限
const { data: profile } = await supabase
.from('profiles')
.select('role')
.eq('id', user.id)
.single()
if (!profile || profile.role !== 'admin') {
throw createError({
statusCode: 403,
statusMessage: '权限不足,需要管理员权限'
})
}
const method = getMethod(event)
if (method === 'GET') {
// 获取用户列表
const query = getQuery(event)
const page = parseInt(query.page as string) || 1
const limit = parseInt(query.limit as string) || 20
const search = query.search as string
const role = query.role as string
const status = query.status as string
let queryBuilder = supabase
.from('profiles')
.select(`
id, email, full_name, phone, company, department, role,
is_active, verification_status, specializations,
hourly_rate, timezone, created_at, last_login
`)
.order('created_at', { ascending: false })
// 搜索过滤
if (search) {
queryBuilder = queryBuilder.or(`
full_name.ilike.%${search}%,
email.ilike.%${search}%,
company.ilike.%${search}%
`)
}
// 角色过滤
if (role) {
queryBuilder = queryBuilder.eq('role', role)
}
// 状态过滤
if (status === 'active') {
queryBuilder = queryBuilder.eq('is_active', true)
} else if (status === 'inactive') {
queryBuilder = queryBuilder.eq('is_active', false)
}
// 分页
const from = (page - 1) * limit
const to = from + limit - 1
queryBuilder = queryBuilder.range(from, to)
const { data: users, error, count } = await queryBuilder
if (error) {
throw createError({
statusCode: 500,
statusMessage: '获取用户列表失败:' + error.message
})
}
return {
users,
pagination: {
page,
limit,
total: count || 0,
totalPages: Math.ceil((count || 0) / limit)
}
}
}
if (method === 'POST') {
// 创建新用户
const body = await readBody(event)
const { email, password, full_name, role, phone, company, department, specializations, hourly_rate, timezone } = body
if (!email || !password || !full_name || !role) {
throw createError({
statusCode: 400,
statusMessage: '缺少必要字段email, password, full_name, role'
})
}
// 创建认证用户
const { data: authData, error: authError } = await supabase.auth.admin.createUser({
email,
password,
email_confirm: true
})
if (authError) {
throw createError({
statusCode: 400,
statusMessage: '创建用户失败:' + authError.message
})
}
// 创建用户资料
const { data: profileData, error: profileError } = await supabase
.from('profiles')
.insert({
id: authData.user.id,
email,
full_name,
phone,
company,
department,
role,
specializations: specializations || [],
hourly_rate,
timezone: timezone || 'UTC',
verification_status: 'verified' // 管理员创建的用户自动验证
})
.select()
.single()
if (profileError) {
// 如果创建资料失败,删除已创建的认证用户
await supabase.auth.admin.deleteUser(authData.user.id)
throw createError({
statusCode: 500,
statusMessage: '创建用户资料失败:' + profileError.message
})
}
return {
message: '用户创建成功',
user: profileData
}
}
if (method === 'PUT') {
// 更新用户信息
const body = await readBody(event)
const { userId, ...updateData } = body
if (!userId) {
throw createError({
statusCode: 400,
statusMessage: '缺少用户ID'
})
}
// 更新用户资料
const { data: updatedUser, error } = await supabase
.from('profiles')
.update({
...updateData,
updated_at: new Date().toISOString()
})
.eq('id', userId)
.select()
.single()
if (error) {
throw createError({
statusCode: 500,
statusMessage: '更新用户失败:' + error.message
})
}
return {
message: '用户更新成功',
user: updatedUser
}
}
if (method === 'DELETE') {
// 删除用户
const body = await readBody(event)
const { userId } = body
if (!userId) {
throw createError({
statusCode: 400,
statusMessage: '缺少用户ID'
})
}
// 软删除:设置为非活跃状态
const { error } = await supabase
.from('profiles')
.update({
is_active: false,
updated_at: new Date().toISOString()
})
.eq('id', userId)
if (error) {
throw createError({
statusCode: 500,
statusMessage: '删除用户失败:' + error.message
})
}
return {
message: '用户删除成功'
}
}
throw createError({
statusCode: 405,
statusMessage: '不支持的请求方法'
})
})