diff --git a/app/Modules/Inventory/Controllers/InventoryReportController.php b/app/Modules/Inventory/Controllers/InventoryReportController.php index 4359257..0e065a5 100644 --- a/app/Modules/Inventory/Controllers/InventoryReportController.php +++ b/app/Modules/Inventory/Controllers/InventoryReportController.php @@ -24,9 +24,17 @@ class InventoryReportController extends Controller public function index(Request $request) { $filters = $request->only([ - 'date_from', 'date_to', 'warehouse_id', 'category_id', 'search', 'per_page' + 'date_from', 'date_to', 'warehouse_id', 'category_id', 'search', 'per_page', + 'sort_by', 'sort_order' ]); + if (!isset($filters['date_from'])) { + $filters['date_from'] = date('Y-m-d'); + } + if (!isset($filters['date_to'])) { + $filters['date_to'] = date('Y-m-d'); + } + $reportData = $this->reportService->getReportData($filters, $request->input('per_page', 10)); $summary = $this->reportService->getSummary($filters); diff --git a/app/Modules/Inventory/Exports/InventoryReportExport.php b/app/Modules/Inventory/Exports/InventoryReportExport.php index 2154fe6..a3c177b 100644 --- a/app/Modules/Inventory/Exports/InventoryReportExport.php +++ b/app/Modules/Inventory/Exports/InventoryReportExport.php @@ -34,6 +34,8 @@ class InventoryReportExport implements FromCollection, WithHeadings, WithMapping '分類', '進貨量', '出貨量', + '調撥入', + '調撥出', '調整量', '淨變動', ]; @@ -47,6 +49,8 @@ class InventoryReportExport implements FromCollection, WithHeadings, WithMapping $row->category_name ?? '-', $row->inbound_qty, $row->outbound_qty, + $row->transfer_in_qty, + $row->transfer_out_qty, $row->adjust_qty, $row->net_change, ]; diff --git a/app/Modules/Inventory/Services/InventoryReportService.php b/app/Modules/Inventory/Services/InventoryReportService.php index 5b682b6..152d605 100644 --- a/app/Modules/Inventory/Services/InventoryReportService.php +++ b/app/Modules/Inventory/Services/InventoryReportService.php @@ -30,6 +30,8 @@ class InventoryReportService $warehouseId = $filters['warehouse_id'] ?? null; $categoryId = $filters['category_id'] ?? null; $search = $filters['search'] ?? null; + $sortBy = $filters['sort_by'] ?? 'product_code'; + $sortOrder = $filters['sort_order'] ?? 'asc'; // 若無任何篩選條件,直接回傳空資料 if (!$dateFrom && !$dateTo && !$warehouseId && !$categoryId && !$search) { @@ -54,9 +56,12 @@ class InventoryReportService DB::raw("SUM(CASE WHEN inventory_transactions.type IN ('入庫', '手動入庫') AND inventory_transactions.quantity > 0 THEN inventory_transactions.quantity ELSE 0 END) as inbound_qty"), // 出貨量:type 為 出庫 (排除 調撥出庫) (取絕對值) DB::raw("ABS(SUM(CASE WHEN inventory_transactions.type IN ('出庫') AND inventory_transactions.quantity < 0 THEN inventory_transactions.quantity ELSE 0 END)) as outbound_qty"), + // 調撥入:type 為 調撥入庫 + DB::raw("SUM(CASE WHEN inventory_transactions.type = '調撥入庫' AND inventory_transactions.quantity > 0 THEN inventory_transactions.quantity ELSE 0 END) as transfer_in_qty"), + // 調撥出:type 為 調撥出庫 (取絕對值) + DB::raw("ABS(SUM(CASE WHEN inventory_transactions.type = '調撥出庫' AND inventory_transactions.quantity < 0 THEN inventory_transactions.quantity ELSE 0 END)) as transfer_out_qty"), // 調整量:type 為 庫存調整, 手動編輯 DB::raw("SUM(CASE WHEN inventory_transactions.type IN ('庫存調整', '手動編輯') THEN inventory_transactions.quantity ELSE 0 END) as adjust_qty"), - // 調撥淨額 (隱藏欄位,但包含在 net_change) // 淨變動:總和 (包含所有類型:進貨、出貨、調整、調撥) DB::raw("SUM(inventory_transactions.quantity) as net_change"), ]) @@ -92,7 +97,7 @@ class InventoryReportService }); } - // 分組與排序 + // 分組 $query->groupBy([ 'products.id', 'products.code', @@ -100,7 +105,20 @@ class InventoryReportService 'categories.name' ]); - $query->orderBy('products.code', 'asc'); + // 動態排序 + $allowedSortFields = [ + 'product_code' => 'products.code', + 'product_name' => 'products.name', + 'inbound_qty' => 'inbound_qty', + 'outbound_qty' => 'outbound_qty', + 'transfer_in_qty' => 'transfer_in_qty', + 'transfer_out_qty' => 'transfer_out_qty', + 'adjust_qty' => 'adjust_qty', + 'net_change' => 'net_change', + ]; + + $sortColumn = $allowedSortFields[$sortBy] ?? 'products.code'; + $query->orderBy($sortColumn, $sortOrder === 'desc' ? 'desc' : 'asc'); if ($perPage) { @@ -169,6 +187,8 @@ class InventoryReportService return $query->select([ DB::raw("SUM(CASE WHEN inventory_transactions.type IN ('入庫', '手動入庫') AND inventory_transactions.quantity > 0 THEN inventory_transactions.quantity ELSE 0 END) as total_inbound"), DB::raw("ABS(SUM(CASE WHEN inventory_transactions.type IN ('出庫') AND inventory_transactions.quantity < 0 THEN inventory_transactions.quantity ELSE 0 END)) as total_outbound"), + DB::raw("SUM(CASE WHEN inventory_transactions.type = '調撥入庫' AND inventory_transactions.quantity > 0 THEN inventory_transactions.quantity ELSE 0 END) as total_transfer_in"), + DB::raw("ABS(SUM(CASE WHEN inventory_transactions.type = '調撥出庫' AND inventory_transactions.quantity < 0 THEN inventory_transactions.quantity ELSE 0 END)) as total_transfer_out"), DB::raw("SUM(CASE WHEN inventory_transactions.type IN ('庫存調整', '手動編輯') THEN inventory_transactions.quantity ELSE 0 END) as total_adjust"), DB::raw("SUM(inventory_transactions.quantity) as total_net_change"), ])->first(); diff --git a/app/Modules/Sales/Controllers/SalesImportController.php b/app/Modules/Sales/Controllers/SalesImportController.php index 2718256..8e40743 100644 --- a/app/Modules/Sales/Controllers/SalesImportController.php +++ b/app/Modules/Sales/Controllers/SalesImportController.php @@ -16,8 +16,17 @@ class SalesImportController extends Controller public function index(Request $request) { $perPage = $request->input('per_page', 10); + $search = $request->input('search'); $batches = SalesImportBatch::with('importer') + ->when($search, function ($query, $search) { + $query->where(function ($q) use ($search) { + $q->where('id', 'like', "%{$search}%") + ->orWhereHas('importer', function ($u) use ($search) { + $u->where('name', 'like', "%{$search}%"); + }); + }); + }) ->orderByDesc('created_at') ->paginate($perPage) ->withQueryString(); @@ -25,7 +34,8 @@ class SalesImportController extends Controller return Inertia::render('Sales/Import/Index', [ 'batches' => $batches, 'filters' => [ - 'per_page' => $perPage, + 'per_page' => (string) $perPage, + 'search' => $search, ], ]); } diff --git a/resources/js/Layouts/AuthenticatedLayout.tsx b/resources/js/Layouts/AuthenticatedLayout.tsx index 7f63942..693bd70 100644 --- a/resources/js/Layouts/AuthenticatedLayout.tsx +++ b/resources/js/Layouts/AuthenticatedLayout.tsx @@ -425,6 +425,7 @@ export default function AuthenticatedLayout({ setIsMobileOpen(false)} + preserveScroll={true} className={cn( "w-full flex items-center transition-all rounded-lg group", level === 0 ? "px-3 py-2.5" : "px-3 py-2", @@ -483,7 +484,7 @@ export default function AuthenticatedLayout({ > {isMobileOpen ? : } - + {branding?.short_name || 'Star'} ERP @@ -510,6 +511,7 @@ export default function AuthenticatedLayout({ @@ -551,7 +553,7 @@ export default function AuthenticatedLayout({ )} -
+
@@ -596,7 +598,7 @@ export default function AuthenticatedLayout({
-
+
diff --git a/resources/js/Pages/Accounting/Report.tsx b/resources/js/Pages/Accounting/Report.tsx index d933fbe..764bd8e 100644 --- a/resources/js/Pages/Accounting/Report.tsx +++ b/resources/js/Pages/Accounting/Report.tsx @@ -174,8 +174,9 @@ export default function AccountingReport({ records, summary, filters }: PageProp {/* Filters with Quick Date Range */}
-
-
+ {/* Top Config: Date Range & Quick Buttons */} +
+
{[ @@ -201,8 +202,9 @@ export default function AccountingReport({ records, summary, filters }: PageProp
-
-
+ {/* Date Inputs */} +
+
@@ -237,22 +239,25 @@ export default function AccountingReport({ records, summary, filters }: PageProp
- {/* Action Buttons */} -
- - + {/* Row 2: Actions */} +
+
+
+ + +
diff --git a/resources/js/Pages/Inventory/GoodsReceipt/Index.tsx b/resources/js/Pages/Inventory/GoodsReceipt/Index.tsx index 87148fb..1bfa3f8 100644 --- a/resources/js/Pages/Inventory/GoodsReceipt/Index.tsx +++ b/resources/js/Pages/Inventory/GoodsReceipt/Index.tsx @@ -1,7 +1,7 @@ import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; import { Head, Link, router } from '@inertiajs/react'; import { Button } from '@/Components/ui/button'; -import { Plus, Search, FileText, RotateCcw, Calendar, ChevronDown, ChevronUp } from 'lucide-react'; +import { Plus, Search, FileText, RotateCcw, Calendar } from 'lucide-react'; import { Input } from '@/Components/ui/input'; import { Label } from '@/Components/ui/label'; import { SearchableSelect } from '@/Components/ui/searchable-select'; @@ -49,9 +49,7 @@ export default function GoodsReceiptIndex({ receipts, filters, warehouses }: Pro const [dateRangeType, setDateRangeType] = useState('custom'); // Advanced Filter Toggle - const [showAdvanced, setShowAdvanced] = useState( - !!(filters.date_start || filters.date_end) - ); + // Sync filters from props useEffect(() => { @@ -149,55 +147,12 @@ export default function GoodsReceiptIndex({ receipts, filters, warehouses }: Pro
{/* Filter Bar */} -
- {/* Row 1: Search, Status, Warehouse */} -
-
- -
- - setSearch(e.target.value)} - className="pl-10 h-9 block" - onKeyDown={(e) => e.key === 'Enter' && handleFilter()} - /> -
-
- -
- - -
- -
- - 10} - /> -
-
- - {/* Row 2: Date Filters (Collapsible) */} - {showAdvanced && ( -
-
- +
+
+ {/* Row 1: Date Range & Quick Buttons */} +
+
+
{[ { label: "今日", value: "today" }, @@ -222,8 +177,9 @@ export default function GoodsReceiptIndex({ receipts, filters, warehouses }: Pro
-
-
+ {/* Date Inputs */} +
+
@@ -257,45 +213,71 @@ export default function GoodsReceiptIndex({ receipts, filters, warehouses }: Pro
- )} -
- - - + {/* Row 2: Filters & Actions */} +
+ {/* Search */} +
+ +
+ + setSearch(e.target.value)} + className="pl-10 h-9 block" + onKeyDown={(e) => e.key === 'Enter' && handleFilter()} + /> +
+
+ + {/* Status */} +
+ + +
+ + {/* Warehouse */} +
+ + 10} + /> +
+ + {/* Actions */} +
+ + +
+
diff --git a/resources/js/Pages/Inventory/Report/Index.tsx b/resources/js/Pages/Inventory/Report/Index.tsx index fe3eb57..077b58b 100644 --- a/resources/js/Pages/Inventory/Report/Index.tsx +++ b/resources/js/Pages/Inventory/Report/Index.tsx @@ -12,7 +12,10 @@ import { ArrowUpFromLine, ArrowDownToLine, ArrowRightLeft, - TrendingUp + TrendingUp, + ArrowUpDown, + ArrowUp, + ArrowDown } from 'lucide-react'; import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout"; import { Head, Link, router } from "@inertiajs/react"; @@ -29,6 +32,12 @@ import Pagination from "@/Components/shared/Pagination"; import { SearchableSelect } from "@/Components/ui/searchable-select"; import { Can } from "@/Components/Permission/Can"; import { PageProps } from "@/types/global"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/Components/ui/tooltip"; interface ReportData { product_code: string; @@ -37,6 +46,8 @@ interface ReportData { product_id: number; inbound_qty: number; outbound_qty: number; + transfer_in_qty: number; + transfer_out_qty: number; adjust_qty: number; net_change: number; } @@ -44,6 +55,8 @@ interface ReportData { interface SummaryData { total_inbound: number; total_outbound: number; + total_transfer_in: number; + total_transfer_out: number; total_adjust: number; total_net_change: number; } @@ -67,6 +80,8 @@ interface InventoryReportProps extends PageProps { category_id: string; search: string; per_page?: number; + sort_by?: string; + sort_order?: 'asc' | 'desc'; }; } @@ -120,7 +135,7 @@ export default function InventoryReportIndex({ reportData, summary, warehouses, search: search, per_page: perPage, }, - { preserveState: true } + { preserveState: true, preserveScroll: true } ); }, [dateStart, dateEnd, warehouseId, categoryId, search, perPage]); @@ -136,7 +151,7 @@ export default function InventoryReportIndex({ reportData, summary, warehouses, search: search, per_page: value, }, - { preserveState: true } + { preserveState: true, preserveScroll: true } ); }; @@ -161,10 +176,51 @@ export default function InventoryReportIndex({ reportData, summary, warehouses, warehouse_id: warehouseId === "all" ? "" : warehouseId, category_id: categoryId === "all" ? "" : categoryId, search: search, + sort_by: filters.sort_by, + sort_order: filters.sort_order, }; window.location.href = route("inventory.report.export", query); }; + const handleSort = (field: string) => { + let newSortBy: string | undefined = field; + let newSortOrder: 'asc' | 'desc' | undefined = 'asc'; + + if (filters.sort_by === field) { + if (filters.sort_order === 'asc') { + newSortOrder = 'desc'; + } else { + newSortBy = undefined; + newSortOrder = undefined; + } + } + + router.get( + route("inventory.report.index"), + { + date_from: dateStart, + date_to: dateEnd, + warehouse_id: warehouseId === "all" ? "" : warehouseId, + category_id: categoryId === "all" ? "" : categoryId, + search: search, + per_page: perPage, + sort_by: newSortBy, + sort_order: newSortOrder, + }, + { preserveState: true, preserveScroll: true } + ); + }; + + const SortIcon = ({ field }: { field: string }) => { + if (filters.sort_by !== field) { + return ; + } + if (filters.sort_order === "asc") { + return ; + } + return ; + }; + return ( @@ -271,7 +327,7 @@ export default function InventoryReportIndex({ reportData, summary, warehouses, {/* Detailed Filters row */}
{/* Warehouse & Category */} -
+
-
+
{/* Search */} -
+
e.key === 'Enter' && handleFilter()} />
-
- {/* Action Buttons */} -
- - + {/* Action Buttons Integrated */} +
+ + +
{/* Summary Cards */} -
-
- -
- 總進貨量 - {Number(summary?.total_inbound || 0).toLocaleString()} + +
+
+ +
+ 進貨量 + + + {Number(summary?.total_inbound || 0).toLocaleString()} + + +

{Number(summary?.total_inbound || 0).toLocaleString()}

+
+
+
-
-
- -
- 總出貨量 - {Number(summary?.total_outbound || 0).toLocaleString()} +
+ +
+ 出貨量 + + + {Number(summary?.total_outbound || 0).toLocaleString()} + + +

{Number(summary?.total_outbound || 0).toLocaleString()}

+
+
+
-
-
- -
- 調整量 - {Number(summary?.total_adjust || 0).toLocaleString()} +
+ +
+ 調撥入 + + + {Number(summary?.total_transfer_in || 0).toLocaleString()} + + +

{Number(summary?.total_transfer_in || 0).toLocaleString()}

+
+
+
-
-
- -
- 淨變動 - = 0 ? "text-emerald-600" : "text-red-600"}`}> - {summary?.total_net_change > 0 ? "+" : ""}{Number(summary?.total_net_change || 0).toLocaleString()} - +
+ +
+ 調撥出 + + + {Number(summary?.total_transfer_out || 0).toLocaleString()} + + +

{Number(summary?.total_transfer_out || 0).toLocaleString()}

+
+
+
+
+ +
+ +
+ 調整量 + + + {Number(summary?.total_adjust || 0).toLocaleString()} + + +

{Number(summary?.total_adjust || 0).toLocaleString()}

+
+
+
+
+ +
+ +
+ 淨變動 + + + = 0 ? "text-emerald-600" : "text-red-600"}`}> + {summary?.total_net_change > 0 ? "+" : ""}{Number(summary?.total_net_change || 0).toLocaleString()} + + + +

{summary?.total_net_change > 0 ? "+" : ""}{Number(summary?.total_net_change || 0).toLocaleString()}

+
+
+
-
+ {/* Results Table */}
@@ -368,18 +484,32 @@ export default function InventoryReportIndex({ reportData, summary, warehouses, 商品代碼 - 商品名稱 + 商品名稱 分類 - 進貨量 - 出貨量 - 調整量 - 淨變動 + handleSort('inbound_qty')}> +
進貨量
+
+ handleSort('outbound_qty')}> +
出貨量
+
+ handleSort('transfer_in_qty')}> +
調撥入
+
+ handleSort('transfer_out_qty')}> +
調撥出
+
+ handleSort('adjust_qty')}> +
調整量
+
+ handleSort('net_change')}> +
淨變動
+
{reportData.data.length === 0 ? ( - +

無符合條件的報表資料

@@ -431,6 +561,12 @@ export default function InventoryReportIndex({ reportData, summary, warehouses, {row.outbound_qty > 0 ? `-${row.outbound_qty}` : "-"} + + {row.transfer_in_qty > 0 ? `+${row.transfer_in_qty}` : "-"} + + + {row.transfer_out_qty > 0 ? `-${row.transfer_out_qty}` : "-"} + {row.adjust_qty !== 0 ? (row.adjust_qty > 0 ? `+${row.adjust_qty}` : row.adjust_qty) : "-"} diff --git a/resources/js/Pages/PurchaseOrder/Index.tsx b/resources/js/Pages/PurchaseOrder/Index.tsx index 1059dca..91abb91 100644 --- a/resources/js/Pages/PurchaseOrder/Index.tsx +++ b/resources/js/Pages/PurchaseOrder/Index.tsx @@ -3,7 +3,7 @@ */ import { useState, useEffect } from "react"; -import { Plus, ShoppingCart, Search, RotateCcw, Calendar, ChevronDown, ChevronUp } from 'lucide-react'; +import { Plus, ShoppingCart, Search, RotateCcw, Calendar } from 'lucide-react'; import { Button } from "@/Components/ui/button"; import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout"; import { Head, router } from "@inertiajs/react"; @@ -57,9 +57,7 @@ export default function PurchaseOrderIndex({ orders, filters, warehouses }: Prop const [dateRangeType, setDateRangeType] = useState('custom'); // Advanced Filter Toggle - const [showAdvancedFilter, setShowAdvancedFilter] = useState( - !!(filters.date_start || filters.date_end) - ); + // 同步 URL 參數到 State (雖有初始值,但若由外部連結進入可確保同步) useEffect(() => { @@ -152,60 +150,13 @@ export default function PurchaseOrderIndex({ orders, filters, warehouses }: Prop
{/* 篩選區塊 */} -
- {/* Row 1: Search, Status, Warehouse */} -
-
- -
- - setSearch(e.target.value)} - className="pl-10 h-9 block" - onKeyDown={(e) => e.key === 'Enter' && handleFilter()} - /> -
-
- -
- - -
- -
- - ({ label: w.name, value: String(w.id) })) - ]} - placeholder="選擇倉庫" - className="w-full h-9" - /> -
-
- - {/* Row 2: Date Filters (Collapsible) */} - {showAdvancedFilter && ( -
-
- + {/* 篩選區塊 */} +
+
+ {/* Row 1: Date Range & Quick Buttons */} +
+
+
{[ { label: "今日", value: "today" }, @@ -230,8 +181,9 @@ export default function PurchaseOrderIndex({ orders, filters, warehouses }: Prop
-
-
+ {/* Date Inputs */} +
+
@@ -265,45 +217,76 @@ export default function PurchaseOrderIndex({ orders, filters, warehouses }: Prop
- )} -
- - - + {/* Row 2: Filters & Actions */} +
+ {/* Search */} +
+ +
+ + setSearch(e.target.value)} + className="pl-10 h-9 block" + onKeyDown={(e) => e.key === 'Enter' && handleFilter()} + /> +
+
+ + {/* Status */} +
+ + +
+ + {/* Warehouse */} +
+ + ({ label: w.name, value: String(w.id) })) + ]} + placeholder="選擇倉庫" + className="w-full h-9" + /> +
+ + {/* Actions */} +
+ + +
+
diff --git a/resources/js/Pages/Sales/Import/Index.tsx b/resources/js/Pages/Sales/Import/Index.tsx index 2b3861e..41e383c 100644 --- a/resources/js/Pages/Sales/Import/Index.tsx +++ b/resources/js/Pages/Sales/Import/Index.tsx @@ -21,11 +21,12 @@ import { AlertDialogTrigger, } from "@/Components/ui/alert-dialog"; import { Badge } from "@/Components/ui/badge"; -import { Plus, FileUp, Eye, Trash2 } from 'lucide-react'; +import { Plus, FileUp, Eye, Trash2, Search, X } from 'lucide-react'; import { useState, useEffect } from "react"; import { format } from 'date-fns'; import Pagination from "@/Components/shared/Pagination"; import { SearchableSelect } from "@/Components/ui/searchable-select"; +import { Input } from "@/Components/ui/input"; import { router } from "@inertiajs/react"; import { usePermission } from "@/hooks/usePermission"; import SalesImportDialog from "@/Components/Sales/SalesImportDialog"; @@ -47,27 +48,41 @@ interface Props { data: ImportBatch[]; links: any[]; // Pagination links }; - filters?: { // Add filters prop if not present, though we main need per_page state + filters?: { per_page?: string; + search?: string; } } export default function SalesImportIndex({ batches, filters = {} }: Props) { const { can } = usePermission(); const [perPage, setPerPage] = useState(filters?.per_page?.toString() || "10"); + const [search, setSearch] = useState(filters?.search || ""); const [isImportDialogOpen, setIsImportDialogOpen] = useState(false); useEffect(() => { if (filters?.per_page) { setPerPage(filters.per_page.toString()); } - }, [filters?.per_page]); + setSearch(filters?.search || ""); + }, [filters]); + + const handleFilter = () => { + router.get( + route("sales-imports.index"), + { + per_page: perPage, + search: search + }, + { preserveState: true, replace: true } + ); + }; const handlePerPageChange = (value: string) => { setPerPage(value); router.get( route("sales-imports.index"), - { per_page: value }, + { ...filters, per_page: value }, { preserveState: true, preserveScroll: true, replace: true } ); }; @@ -92,15 +107,56 @@ export default function SalesImportIndex({ batches, filters = {} }: Props) { 匯入並管理銷售出貨紀錄

- {can('sales_imports.create') && ( - - )} +
+ + {/* Toolbar (Aligned with Recipe Management) */} +
+
+ {/* Search */} +
+ + setSearch(e.target.value)} + className="pl-10 pr-10 h-9" + onKeyDown={(e) => e.key === 'Enter' && handleFilter()} + /> + {search && ( + + )} +
+ + {/* Action Buttons */} +
+ + + {can('sales_imports.create') && ( + + )} +
+
- ID + # 匯入日期 匯入人員 總數量 @@ -129,9 +185,11 @@ export default function SalesImportIndex({ batches, filters = {} }: Props) { ) : ( - batches.data.map((batch) => ( + batches.data.map((batch, index) => ( - #{batch.id} + + {(batches as any).from + index} + {format(new Date(batch.created_at), 'yyyy/MM/dd HH:mm')} diff --git a/resources/js/Pages/UtilityFee/Index.tsx b/resources/js/Pages/UtilityFee/Index.tsx index eb9155e..59955e6 100644 --- a/resources/js/Pages/UtilityFee/Index.tsx +++ b/resources/js/Pages/UtilityFee/Index.tsx @@ -13,9 +13,7 @@ import { RotateCcw, ArrowUpDown, ArrowUp, - ArrowDown, - ChevronDown, - ChevronUp + ArrowDown } from 'lucide-react'; import { Label } from "@/Components/ui/label"; import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout"; @@ -81,10 +79,7 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }: const [editingFee, setEditingFee] = useState(null); const [deletingFeeId, setDeletingFeeId] = useState(null); - // Advanced Filter Toggle - const [showAdvancedFilter, setShowAdvancedFilter] = useState( - !!(filters.date_start || filters.date_end) - ); + // Sorting const [sortField, setSortField] = useState(filters.sort_field || null); @@ -236,11 +231,76 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }:
-
- {/* Row 1: Search and Category */} -
-
- +
+ {/* Row 1: Date Range & Quick Buttons (Aligned with Inventory Report) */} +
+
+ +
+ {[ + { label: "今日", value: "today" }, + { label: "昨日", value: "yesterday" }, + { label: "本週", value: "this_week" }, + { label: "本月", value: "this_month" }, + { label: "上月", value: "last_month" }, + ].map((opt) => ( + + ))} +
+
+ + {/* Date Inputs */} +
+
+
+ +
+ + { + setDateStart(e.target.value); + setDateRangeType('custom'); + }} + className="pl-9 block w-full h-9 bg-white" + /> +
+
+
+ +
+ + { + setDateEnd(e.target.value); + setDateRangeType('custom'); + }} + className="pl-9 block w-full h-9 bg-white" + /> +
+
+
+
+
+ + {/* Row 2: Search, Category & Actions */} +
+
+
setSearchTerm(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleSearch()} - className="pl-10 h-9 block" + className="pl-10 h-9 block bg-white" /> {searchTerm && (
- + ({ label: c, value: c })) ]} placeholder="篩選類別" - className="h-9" + className="h-9 w-full" />
-
- {/* Row 2: Date Filters (Collapsible) */} - {showAdvancedFilter && ( -
-
- -
- {[ - { label: "今日", value: "today" }, - { label: "昨日", value: "yesterday" }, - { label: "本週", value: "this_week" }, - { label: "本月", value: "this_month" }, - { label: "上月", value: "last_month" }, - ].map((opt) => ( - - ))} -
-
- -
-
-
- -
- - { - setDateStart(e.target.value); - setDateRangeType('custom'); - }} - className="pl-9 block w-full h-9 bg-white" - /> -
-
-
- -
- - { - setDateEnd(e.target.value); - setDateRangeType('custom'); - }} - className="pl-9 block w-full h-9 bg-white" - /> -
-
-
-
+ {/* Actions Buttons Group */} +
+ +
- )} - - {/* Action Buttons */} -
- - -