import { useEffect, useState } from "react"; import { Link } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { fetchEmployeeOrganization, type OrganizationDepartmentSection, type OrganizationTreeNode, } from "../api/employees"; import { EmployeeAvatar } from "../components/common/EmployeeAvatar"; import { ListWorkspace, WorkspaceHeader } from "../components/patterns/ListWorkspace"; import { Button } from "../components/ui/button"; function countNodes(nodes: OrganizationTreeNode[]): number { return nodes.reduce((total, node) => total + 1 + countNodes(node.children), 0); } function countExternalManagers(nodes: OrganizationTreeNode[]): number { return nodes.reduce( (total, node) => total + (node.externalManager ? 1 : 0) + countExternalManagers(node.children), 0, ); } function OrganizationNodeCard({ node, depth = 0 }: { node: OrganizationTreeNode; depth?: number }) { return (
{node.name}
{node.employeeNo} · {node.title || "未设置职位"} · {node.department?.name ?? "-"}
{node.externalManager ? (
跨部门汇报:{node.externalManager.department?.name ?? "未知部门"} · {node.externalManager.name}
) : null}
{node.children.length ? (
{node.children.map((child) => ( ))}
) : null}
); } export function OrganizationPage() { const organizationQuery = useQuery({ queryKey: ["employee-organization"], queryFn: fetchEmployeeOrganization, }); const [expandedDepartments, setExpandedDepartments] = useState>({}); useEffect(() => { if (!organizationQuery.data?.items.length) { return; } setExpandedDepartments((current) => { const next = { ...current }; for (const item of organizationQuery.data.items) { const key = item.department?.id ?? item.department?.name ?? "unknown"; if (!(key in next)) { next[key] = true; } } return next; }); }, [organizationQuery.data?.items]); if (organizationQuery.isLoading) { return (
加载组织架构中...
); } if (organizationQuery.isError) { return (
加载组织架构失败
); } const sections = organizationQuery.data?.items ?? []; const totalEmployees = sections.reduce((total, section) => total + countNodes(section.roots), 0); const externalManagerCount = sections.reduce((total, section) => total + countExternalManagers(section.roots), 0); const expandedCount = sections.filter((section) => { const key = section.department?.id ?? section.department?.name ?? "unknown"; return expandedDepartments[key] ?? true; }).length; return ( } />
部门分组
{sections.length}
展示员工
{totalEmployees}
已展开
{expandedCount}
跨部门汇报
{externalManagerCount}
视图模式
只读
{sections.length ? (
{sections.map((section: OrganizationDepartmentSection) => { const sectionKey = section.department?.id ?? section.department?.name ?? "unknown"; const expanded = expandedDepartments[sectionKey] ?? true; const totalNodes = countNodes(section.roots); return (

{section.department?.name ?? "未分配部门"}

{totalNodes} 名员工 · {expanded ? "已展开" : "已折叠"}
{expanded ? (
{section.roots.length ? ( section.roots.map((root) => ) ) : (
当前部门暂无可展示节点
)}
) : null}
); })}
) : (
当前没有可展示的 active 员工。
)}
); } export default OrganizationPage;