import { useMemo, useState } from "react"; import { Link, useSearchParams } from "react-router-dom"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { mapApiErrorMessage } from "../api/errorMessages"; import { isApiError } from "../api/types"; import { archiveDepartment, createDepartment, fetchDepartments, type DepartmentItem, } from "../api/departments"; import { PageHeader } from "../components/common/PageHeader"; import { Button } from "../components/ui/button"; import { Card } from "../components/ui/card"; import { Input } from "../components/ui/input"; import { Label } from "../components/ui/label"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table"; export function DepartmentsPage() { const queryClient = useQueryClient(); const [searchParams, setSearchParams] = useSearchParams(); const includeArchivedRaw = searchParams.get("includeArchived") ?? "0"; const includeArchived = includeArchivedRaw === "1" || includeArchivedRaw === "true"; const [name, setName] = useState(""); const [parentId, setParentId] = useState(""); const [error, setError] = useState(""); const listQuery = useQuery({ queryKey: ["departments", includeArchived], queryFn: () => fetchDepartments({ includeArchived }), }); const departments = listQuery.data?.items ?? []; const departmentById = useMemo(() => { const map = new Map(); for (const dept of departments) { map.set(dept.id, dept); } return map; }, [departments]); const createMutation = useMutation({ mutationFn: () => createDepartment({ name: name.trim(), parentId: parentId ? parentId : null, }), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["departments"] }); setName(""); setParentId(""); setError(""); }, onError: (err) => { if (isApiError(err)) { setError(`${err.code}: ${mapApiErrorMessage(err.code, err.details, err.message)}`); return; } setError(err instanceof Error ? err.message : "创建部门失败"); }, }); const archiveMutation = useMutation({ mutationFn: (departmentId: string) => archiveDepartment(departmentId), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["departments"] }); setError(""); }, onError: (err) => { if (isApiError(err)) { setError(`${err.code}: ${mapApiErrorMessage(err.code, err.details, err.message)}`); return; } setError(err instanceof Error ? err.message : "归档部门失败"); }, }); return (
返回用户管理 } /> {error ? (

{error}

) : null}

新建部门

setName(event.target.value)} />

部门列表

{listQuery.isLoading ?

加载中...

: null} {listQuery.isError ? (

{isApiError(listQuery.error) ? `${listQuery.error.code}: ${mapApiErrorMessage( listQuery.error.code, listQuery.error.details, listQuery.error.message, )}` : "加载部门列表失败"}

) : null} {!listQuery.isLoading && !listQuery.isError ? (
名称上级部门归档时间操作 {departments.length ? ( departments.map((item) => { const parentName = item.parentId ? departmentById.get(item.parentId)?.name ?? "-" : "-"; return (
{item.name}
{item.id}
{parentName} {item.archivedAt ? item.archivedAt.slice(0, 19).replace("T", " ") : "-"} {!item.archivedAt ? ( ) : ( 已归档 )}
); }) ) : ( 暂无部门 )}
) : null}
); }