feat: 實作庫存列表展開狀態保留 (使用 sessionStorage) 改良顯示與修正相關問題

This commit is contained in:
2026-02-10 13:02:11 +08:00
parent e098e40fb8
commit 8b950f6529
3 changed files with 33 additions and 15 deletions

View File

@@ -3,7 +3,8 @@
* 顯示庫存項目列表(依商品分組並支援折疊) * 顯示庫存項目列表(依商品分組並支援折疊)
*/ */
import { useState } from "react"; import { useState, useEffect } from "react";
import { AlertTriangle, Trash2, Eye, ChevronDown, ChevronRight, CheckCircle, Package } from "lucide-react"; import { AlertTriangle, Trash2, Eye, ChevronDown, ChevronRight, CheckCircle, Package } from "lucide-react";
import { import {
Table, Table,
@@ -47,10 +48,29 @@ export default function InventoryTable({
// 判斷是否為販賣機倉庫 // 判斷是否為販賣機倉庫
const isVending = warehouse?.type === "vending"; const isVending = warehouse?.type === "vending";
// 每個商品的展開/折疊狀態 // 每個商品的展開/折疊狀態 - 使用 sessionStorage 保留狀態 (改用 Array 以利序列化)
const [expandedProducts, setExpandedProducts] = useState<Set<string>>(new Set()); // 解決使用 Link 返回時 State 被重置的問題
const storageKey = `inventory_expanded_${warehouse.id}`;
const [expandedProducts, setExpandedProducts] = useState<string[]>(() => {
if (typeof window === 'undefined') return [];
try {
const saved = sessionStorage.getItem(storageKey);
return saved ? JSON.parse(saved) : [];
} catch (e) {
console.error("Failed to parse expanded state", e);
return [];
}
});
useEffect(() => {
try {
sessionStorage.setItem(storageKey, JSON.stringify(expandedProducts));
} catch (e) {
console.error("Failed to save expanded state", e);
}
}, [expandedProducts, storageKey]);
// console.log('InventoryTable Rendered', { warehouseId: warehouse.id, expandedProducts });
if (inventories.length === 0) { if (inventories.length === 0) {
return ( return (
@@ -68,13 +88,11 @@ export default function InventoryTable({
const toggleProduct = (productId: string) => { const toggleProduct = (productId: string) => {
setExpandedProducts((prev) => { setExpandedProducts((prev) => {
const newSet = new Set(prev); if (prev.includes(productId)) {
if (newSet.has(productId)) { return prev.filter(id => id !== productId);
newSet.delete(productId);
} else { } else {
newSet.add(productId); return [...prev, productId];
} }
return newSet;
}); });
}; };
@@ -111,7 +129,7 @@ export default function InventoryTable({
const status = group.status; const status = group.status;
const isLowStock = status === "低於"; const isLowStock = status === "低於";
const isExpanded = expandedProducts.has(group.productId); const isExpanded = expandedProducts.includes(group.productId);
const hasInventory = group.batches.length > 0; const hasInventory = group.batches.length > 0;
return ( return (

View File

@@ -42,7 +42,7 @@ export default function TransactionTable({ transactions, showBatchNumber = false
<th className="px-4 py-3"></th> <th className="px-4 py-3"></th>
<th className="px-4 py-3 text-right"></th> <th className="px-4 py-3 text-right"></th>
<th className="px-4 py-3 text-right"></th> <th className="px-4 py-3 text-right"></th>
{shouldShowSlot && <th className="px-4 py-3"></th>} {shouldShowSlot && <th className="px-4 py-3"></th>}
<th className="px-4 py-3"></th> <th className="px-4 py-3"></th>
<th className="px-4 py-3">/</th> <th className="px-4 py-3">/</th>
</tr> </tr>

View File

@@ -1,4 +1,5 @@
import { Head, router, useRemember } from "@inertiajs/react"; import { useState } from "react";
import { Head, router } from "@inertiajs/react";
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout"; import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout";
import { import {
Search, Search,
@@ -120,10 +121,9 @@ export default function StockQueryIndex({
warehouses, warehouses,
categories, categories,
}: Props) { }: Props) {
const [search, setSearch] = useRemember(filters.search || "", "StockQuery/search"); const [search, setSearch] = useState(filters.search || "");
const [perPage, setPerPage] = useRemember( const [perPage, setPerPage] = useState<string>(
filters.per_page || "10", filters.per_page || "10"
"StockQuery/perPage"
); );
// 執行篩選 // 執行篩選