Files
star-erp/resources/js/Components/Vendor/VendorTable.tsx
sky121113 106de4e945
All checks were successful
Koori-ERP-Deploy-System / deploy-demo (push) Successful in 53s
Koori-ERP-Deploy-System / deploy-production (push) Has been skipped
feat: 修正庫存與撥補單邏輯並整合文件
1. 修復倉庫統計數據加總與樣式。
2. 修正可用庫存計算邏輯(排除不可銷售倉庫)。
3. 撥補單商品列表加入批號與效期顯示。
4. 修正撥補單儲存邏輯以支援精確批號轉移。
5. 整合 FEATURES.md 至 README.md。
2026-01-26 14:59:24 +08:00

172 lines
8.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/Components/ui/table";
import { Button } from "@/Components/ui/button";
import { Pencil, Trash2, Eye, ArrowUpDown, ArrowUp, ArrowDown } from "lucide-react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/Components/ui/alert-dialog";
import { Can } from "@/Components/Permission/Can";
import type { Vendor } from "@/Pages/Vendor/Index";
interface VendorTableProps {
vendors: Vendor[];
onView: (vendor: Vendor) => void;
onEdit: (vendor: Vendor) => void;
onDelete: (id: string) => void;
sortField: string | null;
sortDirection: "asc" | "desc" | null;
onSort: (field: string) => void;
}
export default function VendorTable({
vendors,
onView,
onEdit,
onDelete,
sortField,
sortDirection,
onSort,
}: VendorTableProps) {
const SortIcon = ({ field }: { field: string }) => {
if (sortField !== field) {
return <ArrowUpDown className="h-4 w-4 text-muted-foreground ml-1" />;
}
if (sortDirection === "asc") {
return <ArrowUp className="h-4 w-4 text-primary ml-1" />;
}
if (sortDirection === "desc") {
return <ArrowDown className="h-4 w-4 text-primary ml-1" />;
}
return <ArrowUpDown className="h-4 w-4 text-muted-foreground ml-1" />;
};
return (
<div className="bg-white rounded-lg shadow-sm border">
<Table>
<TableHeader className="bg-gray-50">
<TableRow>
<TableHead className="w-[50px] text-center">#</TableHead>
<TableHead>
<button onClick={() => onSort("code")} className="flex items-center hover:text-gray-900">
<SortIcon field="code" />
</button>
</TableHead>
<TableHead>
<button onClick={() => onSort("name")} className="flex items-center hover:text-gray-900">
<SortIcon field="name" />
</button>
</TableHead>
<TableHead>
<button onClick={() => onSort("owner")} className="flex items-center hover:text-gray-900">
<SortIcon field="owner" />
</button>
</TableHead>
<TableHead>
<button onClick={() => onSort("contact_name")} className="flex items-center hover:text-gray-900">
<SortIcon field="contact_name" />
</button>
</TableHead>
<TableHead>
<button onClick={() => onSort("phone")} className="flex items-center hover:text-gray-900">
<SortIcon field="phone" />
</button>
</TableHead>
<TableHead className="text-center"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{vendors.length === 0 ? (
<TableRow>
<TableCell colSpan={7} className="text-center py-8 text-gray-500">
</TableCell>
</TableRow>
) : (
vendors.map((vendor, index) => (
<TableRow key={vendor.id}>
<TableCell className="text-gray-500 font-medium text-center">
{index + 1}
</TableCell>
<TableCell className="font-mono text-sm text-gray-700">
{vendor.code}
</TableCell>
<TableCell>
<div className="flex flex-col">
<span className="font-medium">{vendor.name}</span>
{vendor.shortName && <span className="text-xs text-gray-400">{vendor.shortName}</span>}
</div>
</TableCell>
<TableCell>{vendor.owner || '-'}</TableCell>
<TableCell>{vendor.contactName || '-'}</TableCell>
<TableCell>{vendor.phone || vendor.tel || '-'}</TableCell>
<TableCell className="text-center">
<div className="flex justify-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => onView(vendor)}
className="button-outlined-primary"
>
<Eye className="h-4 w-4" />
</Button>
<Can permission="vendors.edit">
<Button
variant="outline"
size="sm"
onClick={() => onEdit(vendor)}
className="button-outlined-primary"
>
<Pencil className="h-4 w-4" />
</Button>
</Can>
<Can permission="vendors.delete">
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="outline" size="sm" className="button-outlined-error">
<Trash2 className="h-4 w-4" />
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle></AlertDialogTitle>
<AlertDialogDescription>
{vendor.name}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction
onClick={() => onDelete(vendor.id)}
className="bg-red-600 hover:bg-red-700"
>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</Can>
</div>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
);
}