feat: 宏观状态只同步主线+删除5s倒计时+序列号确认+分组切换(订单/设备)+序列号列
This commit is contained in:
@ -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>
|
||||
|
||||
Reference in New Issue
Block a user