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 (
}
/>
跨部门汇报
{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;