優化公共事業費:修正日期顯示、改善發票號碼輸入UX與調整介面欄位順序
All checks were successful
Koori-ERP-Deploy-System / deploy-demo (push) Successful in 44s
Koori-ERP-Deploy-System / deploy-production (push) Has been skipped

This commit is contained in:
2026-01-20 13:02:05 +08:00
parent 7bf892db19
commit b2a63bd1ed
4 changed files with 98 additions and 66 deletions

View File

@@ -15,6 +15,7 @@ import {
ArrowUp,
ArrowDown
} from 'lucide-react';
import { Label } from "@/Components/ui/label";
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout";
import { Head, router } from "@inertiajs/react";
import Pagination from "@/Components/shared/Pagination";
@@ -200,57 +201,69 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }:
<div className="bg-white rounded-lg shadow-sm border p-4 mb-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{/* Search */}
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
<Input
placeholder="搜尋發票、備註..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && handleSearch()}
className="pl-10"
/>
{searchTerm && (
<button
onClick={() => setSearchTerm("")}
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
>
<X className="h-4 w-4" />
</button>
)}
<div className="space-y-1">
<Label className="text-xs text-gray-500"></Label>
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
<Input
placeholder="搜尋發票、備註..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && handleSearch()}
className="pl-10"
/>
{searchTerm && (
<button
onClick={() => setSearchTerm("")}
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
>
<X className="h-4 w-4" />
</button>
)}
</div>
</div>
{/* Category Filter */}
<SearchableSelect
value={categoryFilter}
onValueChange={setCategoryFilter}
options={[
{ label: "所有類別", value: "all" },
...availableCategories.map(c => ({ label: c, value: c }))
]}
placeholder="篩選類別"
/>
{/* Date Range Start */}
<div className="relative">
<Calendar className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-400 pointer-events-none" />
<Input
type="date"
value={dateStart}
onChange={(e) => setDateStart(e.target.value)}
className="pl-9 bg-white block w-full"
placeholder="開始日期"
/>
<div className="space-y-1">
<Label className="text-xs text-gray-500"></Label>
<div className="relative">
<Calendar className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
<Input
type="date"
value={dateStart}
onChange={(e) => setDateStart(e.target.value)}
className="pl-9 bg-white block w-full"
placeholder="開始日期"
/>
</div>
</div>
{/* Date Range End */}
<div className="relative">
<Calendar className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-400 pointer-events-none" />
<Input
type="date"
value={dateEnd}
onChange={(e) => setDateEnd(e.target.value)}
className="pl-9 bg-white block w-full"
placeholder="結束日期"
<div className="space-y-1">
<Label className="text-xs text-gray-500"></Label>
<div className="relative">
<Calendar className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
<Input
type="date"
value={dateEnd}
onChange={(e) => setDateEnd(e.target.value)}
className="pl-9 bg-white block w-full"
placeholder="結束日期"
/>
</div>
</div>
{/* Category Filter */}
<div className="space-y-1">
<Label className="text-xs text-gray-500"></Label>
<SearchableSelect
value={categoryFilter}
onValueChange={setCategoryFilter}
options={[
{ label: "所有類別", value: "all" },
...availableCategories.map(c => ({ label: c, value: c }))
]}
placeholder="篩選類別"
/>
</div>
</div>
@@ -259,13 +272,13 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }:
<Button
variant="outline"
onClick={handleClearFilters}
className="button-outlined-primary h-9"
className="button-outlined-primary h-9 mt-auto"
>
</Button>
<Button
onClick={handleSearch}
className="button-filled-primary h-9 gap-2"
className="button-filled-primary h-9 gap-2 mt-auto"
>
<Filter className="h-4 w-4" />
</Button>
@@ -294,6 +307,14 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }:
<SortIcon field="category" />
</button>
</TableHead>
<TableHead>
<button
onClick={() => handleSort('invoice_number')}
className="flex items-center hover:text-gray-900"
>
<SortIcon field="invoice_number" />
</button>
</TableHead>
<TableHead className="text-right">
<div className="flex justify-end">
<button
@@ -304,14 +325,6 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }:
</button>
</div>
</TableHead>
<TableHead>
<button
onClick={() => handleSort('invoice_number')}
className="flex items-center hover:text-gray-900"
>
<SortIcon field="invoice_number" />
</button>
</TableHead>
<TableHead> / </TableHead>
<TableHead className="text-center w-[120px]"></TableHead>
</TableRow>
@@ -340,12 +353,12 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }:
{fee.category}
</Badge>
</TableCell>
<TableCell className="text-right font-bold text-gray-900">
$ {Number(fee.amount).toLocaleString()}
</TableCell>
<TableCell className="font-mono text-sm text-gray-600">
{formatInvoiceNumber(fee.invoice_number)}
</TableCell>
<TableCell className="text-right font-bold text-gray-900">
$ {Number(fee.amount).toLocaleString()}
</TableCell>
<TableCell className="max-w-xs truncate text-gray-600" title={fee.description}>
{fee.description || '-'}
</TableCell>