From 9b59521746f24b434943a6f06cb143b2ea57fe40 Mon Sep 17 00:00:00 2001 From: duxingchen Date: Wed, 12 Aug 2026 15:00:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=9C=8B=E6=9D=BF=E5=9C=A8=E5=88=B6?= =?UTF-8?q?=E5=93=81=E7=82=B9=E5=87=BB=E8=B7=B3=E8=BD=AC=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=85=A8=E6=99=AF=E5=B9=B6=E8=87=AA=E5=8A=A8=E5=B1=95=E5=BC=80?= =?UTF-8?q?=E6=B5=81=E8=BD=AC=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dashboard: WipRow 点击改为 nav(/admin/tasks?sn=xxx) AdminTasksPage: 读取 ?sn= 参数 → 自动搜索 → 产品加载后自动展开流转树 --- frontend/src/pages/admin/AdminDashboard.tsx | 2 +- frontend/src/pages/admin/AdminTasksPage.tsx | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/admin/AdminDashboard.tsx b/frontend/src/pages/admin/AdminDashboard.tsx index 160f1ae..baf3986 100644 --- a/frontend/src/pages/admin/AdminDashboard.tsx +++ b/frontend/src/pages/admin/AdminDashboard.tsx @@ -81,7 +81,7 @@ function WipRow({ t }: { t: WipTask }) { const nav = useNavigate(); const handleClick = () => { if (t.product_sn) { - nav(`/scan?sn=${t.product_sn}`); + nav(`/admin/tasks?sn=${t.product_sn}`); } }; return ( diff --git a/frontend/src/pages/admin/AdminTasksPage.tsx b/frontend/src/pages/admin/AdminTasksPage.tsx index aa58b27..f54ea75 100644 --- a/frontend/src/pages/admin/AdminTasksPage.tsx +++ b/frontend/src/pages/admin/AdminTasksPage.tsx @@ -1,5 +1,6 @@ /** 任务全景 Dashboard — 按订单聚合 + 关键词搜索 + 状态筛选 */ import { useState, useEffect, useMemo, useCallback } from "react"; +import { useSearchParams } from "react-router-dom"; import { Search, Loader2, Package, ChevronDown, ChevronRight, Warehouse, GitBranch, X, @@ -35,6 +36,7 @@ interface OrderGroup { export default function AdminTasksPage() { const { toast } = useToast(); const { user: currentUser } = useAuth(); + const [searchParams] = useSearchParams(); // 搜索 & 筛选 const [keyword, setKeyword] = useState(""); @@ -57,6 +59,9 @@ export default function AdminTasksPage() { const [submitting, setSubmitting] = useState(false); const [qrSerial, setQrSerial] = useState(null); // 🔧 QR弹窗 + // 从看板跳转: ?sn=xxx → 自动搜索 + 自动展开流转树 + const autoSn = searchParams.get("sn") || ""; + // ---- 加载产品列表(始终拉全量,不做服务端状态过滤) ---- async function loadProducts(kw: string) { setLoading(true); @@ -66,14 +71,27 @@ export default function AdminTasksPage() { if (kw.trim()) params.keyword = kw.trim(); const { data } = await api.get("/products/", { params }); setProducts(data); + return data; } catch { setError("加载产品列表失败,请检查后端服务"); + return []; } finally { setLoading(false); } } - useEffect(() => { loadProducts(keyword); }, []); // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => { + if (autoSn) { + setKeyword(autoSn); + loadProducts(autoSn).then((data) => { + // 产品加载完成后自动展开流转树 + const found = data.find((p: ProductResponse) => p.serial_number === autoSn); + if (found) toggleProductTree(found.serial_number); + }); + } else { + loadProducts(keyword); + } + }, []); // eslint-disable-line react-hooks/exhaustive-deps function handleSearch(e?: React.FormEvent) { e?.preventDefault();