Files
star-erp/resources/js/Pages/Product/Show.tsx

205 lines
12 KiB
TypeScript
Raw Normal View History

/**
*
*/
import { Head, Link } from "@inertiajs/react";
import { ArrowLeft, Package, Tag, Layers, MapPin, DollarSign } from "lucide-react";
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout";
import { Button } from "@/Components/ui/button";
import { Badge } from "@/Components/ui/badge";
import { Label } from "@/Components/ui/label";
import { getShowBreadcrumbs } from "@/utils/breadcrumb";
import { Can } from "@/Components/Permission/Can";
interface Product {
id: string;
code: string;
barcode: string;
name: string;
categoryId: number;
category?: { id: number; name: string };
brand?: string;
specification?: string;
baseUnitId: number;
baseUnit?: { id: number; name: string };
largeUnitId?: number;
largeUnit?: { id: number; name: string };
purchaseUnitId?: number;
purchaseUnit?: { id: number; name: string };
conversionRate: number;
location?: string;
cost_price: number;
price: number;
member_price: number;
wholesale_price: number;
is_active: boolean;
}
interface Props {
product: Product;
}
export default function ProductShow({ product }: Props) {
return (
<AuthenticatedLayout breadcrumbs={getShowBreadcrumbs("products", `商品詳情 (${product.name})`)}>
<Head title={`商品詳情 - ${product.name}`} />
<div className="container mx-auto p-6 max-w-7xl">
{/* 返回按鈕 */}
<div className="mb-6">
<Link href={route('products.index')}>
<Button
variant="outline"
className="gap-2 button-outlined-primary mb-6"
>
<ArrowLeft className="h-4 w-4" />
</Button>
</Link>
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold text-grey-0 flex items-center gap-2">
<Package className="h-6 w-6 text-primary-main" />
</h1>
<p className="text-gray-500 mt-1"></p>
</div>
<div className="flex gap-2">
<Can permission="products.edit">
<Link href={route('products.edit', { product: product.id, from: 'show' })}>
<Button className="button-filled-primary">
</Button>
</Link>
</Can>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{/* 左側:基本資料 */}
<div className="md:col-span-2 space-y-6">
<div className="bg-white rounded-lg border border-border p-6 shadow-sm">
<div className="flex items-center gap-2 mb-4 text-primary font-bold">
<Tag className="h-4 w-4" />
<h3></h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<p className="mt-1 font-semibold text-lg">{product.name}</p>
</div>
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<p className="mt-1 font-mono text-gray-700">{product.code}</p>
</div>
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<p className="mt-1 font-mono text-gray-700">{product.barcode || "-"}</p>
</div>
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<p className="mt-1">{product.brand || "-"}</p>
</div>
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<div className="mt-1">
<Badge variant="outline">{product.category?.name || "未分類"}</Badge>
</div>
</div>
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<div className="mt-1">
<Badge className={product.is_active ? "bg-green-100 text-green-700 border-green-200" : "bg-gray-100 text-gray-500 border-gray-200"}>
{product.is_active ? "啟用中" : "已停用"}
</Badge>
</div>
</div>
</div>
</div>
{/* 規格與儲位 */}
<div className="bg-white rounded-lg border border-border p-6 shadow-sm">
<div className="flex items-center gap-2 mb-4 text-primary font-bold">
<MapPin className="h-4 w-4" />
<h3></h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="md:col-span-2">
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<p className="mt-1 whitespace-pre-wrap text-gray-700">{product.specification || "-"}</p>
</div>
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<p className="mt-1 font-medium">{product.location || "-"}</p>
</div>
</div>
</div>
</div>
{/* 右側:單位與價格 */}
<div className="space-y-6">
{/* 單位與換算 */}
<div className="bg-white rounded-lg border border-border p-6 shadow-sm">
<div className="flex items-center gap-2 mb-4 text-primary font-bold">
<Layers className="h-4 w-4" />
<h3></h3>
</div>
<div className="space-y-4">
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"> ()</Label>
<p className="mt-1 font-medium">{product.baseUnit?.name || "-"}</p>
</div>
{product.largeUnit && (
<>
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<p className="mt-1 font-medium">{product.largeUnit?.name || "-"}</p>
</div>
<div className="p-3 bg-gray-50 rounded border border-dashed text-sm">
1 {product.largeUnit.name} = <span className="font-bold text-primary-main">{product.conversionRate}</span> {product.baseUnit?.name}
</div>
</>
)}
<div>
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<p className="mt-1">{product.purchaseUnit?.name || product.baseUnit?.name || "-"}</p>
</div>
</div>
</div>
{/* 價格資訊 */}
<Can permission="inventory.view_cost">
<div className="bg-white rounded-lg border border-border p-6 shadow-sm">
<div className="flex items-center gap-2 mb-4 text-primary font-bold">
<DollarSign className="h-4 w-4" />
<h3></h3>
</div>
<div className="space-y-4">
<div className="flex justify-between items-center border-b pb-2">
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<span className="font-mono font-bold text-red-600">${product.cost_price.toLocaleString(undefined, { minimumFractionDigits: 2 })}</span>
</div>
<div className="flex justify-between items-center border-b pb-2">
<Label className="text-muted-foreground text-xs text-secondary-text"></Label>
<span className="font-mono font-bold text-primary-main">${product.price.toLocaleString(undefined, { minimumFractionDigits: 2 })}</span>
</div>
<div className="flex justify-between items-center border-b pb-2 text-sm">
<Label className="text-muted-foreground text-xs"></Label>
<span className="font-mono">${product.member_price.toLocaleString(undefined, { minimumFractionDigits: 2 })}</span>
</div>
<div className="flex justify-between items-center text-sm">
<Label className="text-muted-foreground text-xs"></Label>
<span className="font-mono">${product.wholesale_price.toLocaleString(undefined, { minimumFractionDigits: 2 })}</span>
</div>
</div>
</div>
</Can>
</div>
</div>
</div>
</AuthenticatedLayout>
);
}