146 lines
4.1 KiB
TypeScript
146 lines
4.1 KiB
TypeScript
/**
|
||
* useDepartmentOperations Hook
|
||
*
|
||
* 部门操作Hook
|
||
* 统一管理部门相关的操作(创建、删除、重命名等)
|
||
* 包括数据验证、错误处理、Toast通知
|
||
*
|
||
* @created 2025-01-XX(从 page.tsx 提取)
|
||
* @hook
|
||
*/
|
||
|
||
'use client'
|
||
|
||
import { useCallback } from 'react'
|
||
import type { Department } from '../_components/types'
|
||
import { parseErrorResponse } from '../_utils/api'
|
||
import { validateDepartmentName } from '../_utils/validators'
|
||
import type { ToastFn } from '../_components/types'
|
||
|
||
interface UseDepartmentOperationsOptions {
|
||
departments: Department[]
|
||
setDepartments: React.Dispatch<React.SetStateAction<Department[]>>
|
||
showToast: ToastFn
|
||
fetchDepartments: () => Promise<void>
|
||
loadUsersData: () => Promise<void>
|
||
}
|
||
|
||
export function useDepartmentOperations({
|
||
departments,
|
||
setDepartments,
|
||
showToast,
|
||
fetchDepartments,
|
||
loadUsersData,
|
||
}: UseDepartmentOperationsOptions) {
|
||
const createDepartment = useCallback(
|
||
async (name: string) => {
|
||
const nameValidation = validateDepartmentName(name)
|
||
if (!nameValidation.valid) {
|
||
showToast(nameValidation.error || '部门名称不能为空', 'error')
|
||
return false
|
||
}
|
||
|
||
const trimmed = name.trim()
|
||
|
||
try {
|
||
const response = await fetch('/api/departments', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ name: trimmed }),
|
||
})
|
||
|
||
if (response.ok) {
|
||
await fetchDepartments()
|
||
showToast('部门添加成功')
|
||
return true
|
||
}
|
||
const errorData = await parseErrorResponse(response)
|
||
showToast(errorData.error || '添加失败', 'error')
|
||
return false
|
||
} catch (error) {
|
||
console.error('Add department error:', error)
|
||
showToast('添加失败,请稍后重试', 'error')
|
||
return false
|
||
}
|
||
},
|
||
[fetchDepartments, showToast]
|
||
)
|
||
|
||
const deleteDepartment = useCallback(
|
||
async (id: string, name: string) => {
|
||
try {
|
||
const response = await fetch(`/api/departments?id=${id}`, {
|
||
method: 'DELETE',
|
||
})
|
||
|
||
if (response.ok) {
|
||
const result = await response.json().catch(() => ({})) as { message?: string }
|
||
await Promise.all([fetchDepartments(), loadUsersData()])
|
||
showToast(result.message || '部门删除成功')
|
||
return true
|
||
}
|
||
const errorData = await parseErrorResponse(response)
|
||
showToast(errorData.error || '删除失败', 'error')
|
||
return false
|
||
} catch (error) {
|
||
console.error('Delete department error:', error)
|
||
showToast('删除失败,请稍后重试', 'error')
|
||
return false
|
||
}
|
||
},
|
||
[fetchDepartments, loadUsersData, showToast]
|
||
)
|
||
|
||
const renameDepartment = useCallback(
|
||
async (deptId: string, newName: string) => {
|
||
const nameValidation = validateDepartmentName(newName)
|
||
if (!nameValidation.valid) {
|
||
showToast(nameValidation.error || '部门名称不能为空', 'error')
|
||
return false
|
||
}
|
||
|
||
if (!deptId) {
|
||
showToast('部门ID不能为空', 'error')
|
||
return false
|
||
}
|
||
|
||
const trimmed = newName.trim()
|
||
|
||
try {
|
||
const response = await fetch('/api/departments', {
|
||
method: 'PATCH',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ id: deptId, name: trimmed }),
|
||
})
|
||
|
||
if (response.ok) {
|
||
await fetchDepartments()
|
||
showToast('部门重命名成功')
|
||
return true
|
||
}
|
||
const errorData = await parseErrorResponse(response)
|
||
showToast(errorData.error || '重命名失败', 'error')
|
||
return false
|
||
} catch (error) {
|
||
console.error('Error renaming department:', error)
|
||
showToast('重命名失败', 'error')
|
||
return false
|
||
}
|
||
},
|
||
[fetchDepartments, showToast]
|
||
)
|
||
|
||
return {
|
||
createDepartment,
|
||
deleteDepartment,
|
||
renameDepartment,
|
||
}
|
||
}
|
||
|
||
export type UseDepartmentOperationsReturn = ReturnType<typeof useDepartmentOperations>
|
||
|