flnxi-Wu/app/admin/_hooks/useUserOperations.ts
WuYongJie e4dcb6260a
Some checks failed
CI Check / check (push) Has been cancelled
feat: Admin页面重构 & UI三层架构系统
- 创建统一UI三层架构系统(基础层、颜色层、组合层)
- 拆分Admin页面为独立Tab组件(MonitorTab、UsersTab、DepartmentsTab等)
- 提取公共逻辑到Hooks(useToast、useDataFetch、useUserOperations等)
- 提取工具函数(validators、formatters、api等)
- 创建统一弹窗组件(Modal)和useModal Hook
- 添加错误边界和统一状态组件
- 完善类型定义和可访问性支持
- 更新文档(优化记录、优化计划、更新日志)
2025-11-22 15:17:10 +08:00

265 lines
8.0 KiB
TypeScript

/**
* 用户操作 Hook
* 统一管理用户相关的操作(更新、删除、切换状态等)
*/
'use client'
import { useCallback } from 'react'
import type { User, Department, ApiSuccessResponse } from '../_components/types'
import { parseErrorResponse } from '../_utils/api'
import type { ToastFn } from '../_components/types'
interface UseUserOperationsOptions {
users: User[]
setUsers: React.Dispatch<React.SetStateAction<User[]>>
showToast: ToastFn
fetchData: () => Promise<void>
findDepartmentManagers: (departmentName: string | null | undefined) => User[] | null
}
export function useUserOperations({
users,
setUsers,
showToast,
fetchData,
findDepartmentManagers,
}: UseUserOperationsOptions) {
const updateUser = useCallback(
async (user: User, payload: { username: string; department: string }) => {
const { username, department } = payload
const usernameChanged = username !== user.username
const departmentChanged = department !== (user.department || '')
if (!usernameChanged && !departmentChanged) {
showToast('未做任何修改', 'error')
return false
}
try {
let materialsUpdated = false
let parentIdToSet: string | null = null
if (departmentChanged && department) {
const managers = findDepartmentManagers(department) || []
if (managers.length > 0) {
const firstManager = managers.find((manager) => manager.id !== user.id) || managers[0]
parentIdToSet = firstManager.id
}
}
if (usernameChanged || departmentChanged) {
const response = await fetch('/api/admin/users/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userId: user.id,
username,
department,
}),
})
if (!response.ok) {
const errorData = await parseErrorResponse(response)
showToast(errorData.error || '更新失败', 'error')
return false
}
const successData = (await response.json()) as ApiSuccessResponse<{ materialsUpdated?: boolean }>
materialsUpdated = Boolean(successData.materialsUpdated)
if (departmentChanged && parentIdToSet) {
const hierarchyResponse = await fetch('/api/admin/users/update-hierarchy', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userId: user.id,
parentId: parentIdToSet,
}),
})
if (!hierarchyResponse.ok) {
const errorData = await parseErrorResponse(hierarchyResponse)
showToast(errorData.error || '调整上下级失败', 'error')
return false
}
}
}
await fetchData()
showToast(materialsUpdated ? '用户信息已更新,素材信息已同步' : '用户信息已更新')
return true
} catch (error) {
console.error('Update user error:', error)
showToast('更新失败,请稍后重试', 'error')
return false
}
},
[showToast, fetchData, findDepartmentManagers]
)
const deleteUser = useCallback(
async (id: string) => {
try {
const response = await fetch(`/api/admin/users?id=${id}`, {
method: 'DELETE',
})
if (response.ok) {
setUsers((prevUsers) => prevUsers.filter((u) => u.id !== id))
showToast('删除成功')
return true
}
const errorData = await parseErrorResponse(response)
showToast(errorData.error || '删除失败', 'error')
return false
} catch (error) {
console.error('Error deleting user:', error)
showToast('删除失败', 'error')
return false
}
},
[setUsers, showToast]
)
const toggleDownload = useCallback(
async (userId: string, currentCanDownload: boolean) => {
const action = currentCanDownload ? '关闭' : '开启'
try {
const response = await fetch('/api/admin/users/toggle-download', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ userId }),
})
if (response.ok) {
// 直接更新本地状态,避免重新加载整个列表
setUsers((prevUsers) =>
prevUsers.map((user) =>
user.id === userId ? { ...user, canDownload: !currentCanDownload } : user
)
)
showToast(`下载权限已${action}`)
} else {
const errorData = await parseErrorResponse(response)
showToast(errorData.error || '操作失败', 'error')
}
} catch (error) {
console.error('Error toggling download permission:', error)
showToast('操作失败', 'error')
}
},
[setUsers, showToast]
)
const toggleActive = useCallback(
async (userId: string, currentStatus: boolean) => {
const action = currentStatus ? '禁用' : '激活'
try {
const response = await fetch('/api/admin/users/toggle-active', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userId,
isActive: !currentStatus,
}),
})
if (response.ok) {
// 直接更新本地状态
setUsers((prevUsers) =>
prevUsers.map((user) => (user.id === userId ? { ...user, isActive: !currentStatus } : user))
)
showToast(`${action}成功`)
} else {
const errorData = await parseErrorResponse(response)
showToast(errorData.error || `${action}失败`, 'error')
}
} catch (error) {
console.error('Toggle active error:', error)
showToast(`${action}失败`, 'error')
}
},
[setUsers, showToast]
)
const setRole = useCallback(
async (userId: string, currentRole: string) => {
const newRole = currentRole === 'ADMIN' ? 'USER' : 'ADMIN'
const action = newRole === 'ADMIN' ? '设置为管理员' : '取消管理员权限'
try {
const response = await fetch('/api/admin/users/set-role', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userId,
role: newRole,
}),
})
if (response.ok) {
// 刷新数据,用户树会同步更新最新的管理员信息
await fetchData()
showToast(`${action}成功`)
} else {
const errorData = await parseErrorResponse(response)
showToast(errorData.error || `${action}失败`, 'error')
}
} catch (error) {
console.error('Set role error:', error)
showToast(`${action}失败`, 'error')
}
},
[showToast, fetchData]
)
const transferSuperAdmin = useCallback(
async (targetEmail: string, password: string) => {
try {
const res = await fetch('/api/admin/transfer-superadmin', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ targetEmail, password }),
})
if (res.ok) {
showToast('最高权限已转移')
await fetchData()
return true
}
const errorData = await parseErrorResponse(res)
showToast(errorData.error || '操作失败', 'error')
return false
} catch (err) {
console.error('transfer super admin error:', err)
showToast('操作失败,请稍后重试', 'error')
return false
}
},
[showToast, fetchData]
)
return {
updateUser,
deleteUser,
toggleDownload,
toggleActive,
setRole,
transferSuperAdmin,
}
}
export type UseUserOperationsReturn = ReturnType<typeof useUserOperations>