feat: 宏观状态只同步主线+删除5s倒计时+序列号确认+分组切换(订单/设备)+序列号列

This commit is contained in:
2026-08-10 10:37:56 +08:00
parent ad9fb8d37e
commit 4854eb626e
3 changed files with 63 additions and 17 deletions

View File

@ -39,6 +39,7 @@ export default function AdminTasksPage() {
// 搜索 & 筛选
const [keyword, setKeyword] = useState("");
const [statusFilter, setStatusFilter] = useState("");
const [groupBy, setGroupBy] = useState<"order" | "device">("order"); // 🔧 分组维度
const [products, setProducts] = useState<ProductResponse[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
@ -81,7 +82,7 @@ export default function AdminTasksPage() {
loadProducts(keyword);
}
// ---- 按订单分组 + 本地状态过滤(单一数据源: macro_status || status) ----
// ---- 按订单/设备分组 + 本地状态过滤 ----
const orderGroups = useMemo<OrderGroup[]>(() => {
const map = new Map<string, ProductResponse[]>();
for (const p of products) {
@ -89,7 +90,9 @@ export default function AdminTasksPage() {
const currentStatus = (p.macro_status || p.status).toUpperCase();
if (currentStatus !== statusFilter) continue;
}
const key = p.order_no || "未绑定订单";
const key = groupBy === "device"
? (p.material_name || p.material_id || "未命名设备")
: (p.order_no || "未绑定订单");
if (!map.has(key)) map.set(key, []);
map.get(key)!.push(p);
}
@ -102,7 +105,7 @@ export default function AdminTasksPage() {
(p) => p.current_location_id === "virtual_warehouse"
),
}));
}, [products, statusFilter]);
}, [products, statusFilter, groupBy]);
// ---- 手风琴切换 ----
function toggleOrder(orderNo: string) {
@ -228,6 +231,15 @@ export default function AdminTasksPage() {
{/* ---- 搜索 + 筛选 ---- */}
<div className="mb-6 rounded-xl bg-white p-4 shadow-sm">
<div className="mb-3 flex items-center gap-2">
<span className="text-xs text-gray-400">分组:</span>
{(["order", "device"] as const).map(m => (
<button key={m} onClick={() => setGroupBy(m)}
className={`rounded-full px-3 py-1 text-xs font-medium transition-colors ${groupBy === m ? "bg-blue-600 text-white" : "bg-gray-100 text-gray-500 hover:bg-gray-200"}`}>
{m === "order" ? "按订单" : "按设备"}
</button>
))}
</div>
<form onSubmit={handleSearch} className="flex items-center gap-2">
<div className="relative flex-1 max-w-xl">
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
@ -339,8 +351,9 @@ export default function AdminTasksPage() {
{isOpen && (
<div className="border-t border-gray-100">
{/* 表头 */}
<div className="grid grid-cols-12 gap-2 bg-gray-50 px-5 py-2 text-xs font-medium text-gray-500">
<div className="grid gap-2" style="grid-template-columns: 2fr 1fr 2fr 1fr 1fr 2fr 2fr 2fr" bg-gray-50 px-5 py-2 text-xs font-medium text-gray-500">
<div className="col-span-2">产品身份证</div>
<div className="col-span-1">序列号</div>
<div className="col-span-2">规格型号</div>
<div className="col-span-1">宏观状态</div>
<div className="col-span-1">任务状态</div>
@ -361,10 +374,13 @@ export default function AdminTasksPage() {
return (
<div key={p.id}>
<div className="grid grid-cols-12 gap-2 border-t border-gray-50 px-5 py-3 items-center text-sm hover:bg-gray-50/50">
<div className="grid gap-2" style="grid-template-columns: 2fr 1fr 2fr 1fr 1fr 2fr 2fr 2fr" border-t border-gray-50 px-5 py-3 items-center text-sm hover:bg-gray-50/50">
<div className="col-span-2 font-mono text-xs font-semibold text-gray-800 tracking-wider">
{p.serial_number}
</div>
<div className="col-span-1 font-mono text-xs text-gray-600 truncate">
{p.external_serial || "—"}
</div>
<div className="col-span-2 text-xs text-gray-500 truncate">
{p.spec_model || p.material_name || p.material_id || "—"}
</div>