228 lines
5.4 KiB
TypeScript
228 lines
5.4 KiB
TypeScript
// 管理员用户管理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: '不支持的请求方法'
|
||
})
|
||
})
|