perf: 流转树排他展开(手风琴模式)-同时只展开一个产品

This commit is contained in:
2026-08-10 13:40:46 +08:00
parent 4d93844637
commit 38263291d1

View File

@ -47,8 +47,8 @@ export default function AdminTasksPage() {
// 手风琴展开状态 // 手风琴展开状态
const [expandedOrders, setExpandedOrders] = useState<Set<string>>(new Set()); const [expandedOrders, setExpandedOrders] = useState<Set<string>>(new Set());
// 任务树展开 // 🔧 排他展开:同时只展开一个产品的流转树
const [expandedProducts, setExpandedProducts] = useState<Set<string>>(new Set()); const [activeTreeProductId, setActiveTreeProductId] = useState<string | null>(null);
const [taskTrees, setTaskTrees] = useState<Record<string, ProductScanResponse | null>>({}); const [taskTrees, setTaskTrees] = useState<Record<string, ProductScanResponse | null>>({});
const [treeLoading, setTreeLoading] = useState<Record<string, boolean>>({}); const [treeLoading, setTreeLoading] = useState<Record<string, boolean>>({});
@ -121,38 +121,22 @@ export default function AdminTasksPage() {
}); });
} }
// ---- 任务树展开/收起 ---- // ---- 排他展开(手风琴模式) ----
async function toggleProductTree(serialNumber: string) { async function toggleProductTree(serialNumber: string) {
setExpandedProducts((prev) => { // 点击已展开的树 → 收起
const next = new Set(prev); if (activeTreeProductId === serialNumber) {
if (next.has(serialNumber)) { setActiveTreeProductId(null);
next.delete(serialNumber); return;
return next; }
} // 展开新的 → 自动收起旧的
// 加载任务树 setActiveTreeProductId(serialNumber);
next.add(serialNumber); if (!taskTrees[serialNumber]) {
if (!taskTrees[serialNumber]) { setTreeLoading((s) => ({ ...s, [serialNumber]: true }));
setTreeLoading((s) => ({ ...s, [serialNumber]: true })); scanProduct(serialNumber)
scanProduct(serialNumber) .then((result) => setTaskTrees((s) => ({ ...s, [serialNumber]: result })))
.then((result) => { .catch((err: any) => toast(err?.response?.data?.detail ?? err?.message ?? "加载任务树失败", "error"))
setTaskTrees((s) => ({ ...s, [serialNumber]: result })); .finally(() => setTreeLoading((s) => ({ ...s, [serialNumber]: false })));
}) }
.catch((err: any) => {
const msg =
err?.response?.data?.detail ?? err?.message ?? "加载任务树失败";
toast(msg, "error");
setExpandedProducts((prev2) => {
const n2 = new Set(prev2);
n2.delete(serialNumber);
return n2;
});
})
.finally(() => {
setTreeLoading((s) => ({ ...s, [serialNumber]: false }));
});
}
return next;
});
} }
// ---- 任务操作 ---- // ---- 任务操作 ----
@ -378,7 +362,7 @@ export default function AdminTasksPage() {
{/* 产品行 */} {/* 产品行 */}
{group.products.map((p) => { {group.products.map((p) => {
const productExpanded = expandedProducts.has(p.serial_number); const productExpanded = activeTreeProductId === p.serial_number;
const isTreeLoading = treeLoading[p.serial_number]; const isTreeLoading = treeLoading[p.serial_number];
const tree = taskTrees[p.serial_number]; const tree = taskTrees[p.serial_number];
// 综合状态:优先流转树状态,兜底产品状态 // 综合状态:优先流转树状态,兜底产品状态