167 lines
9.6 KiB
TypeScript
167 lines
9.6 KiB
TypeScript
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/Components/ui/dialog";
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@/Components/ui/table";
|
|
import { StatusBadge } from "@/Components/shared/StatusBadge";
|
|
import { Loader2, Package, Calendar, Clock, BookOpen } from "lucide-react";
|
|
|
|
interface RecipeDetailModalProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
recipe: any | null; // Detailed recipe object with items
|
|
isLoading?: boolean;
|
|
}
|
|
|
|
export function RecipeDetailModal({ isOpen, onClose, recipe, isLoading }: RecipeDetailModalProps) {
|
|
if (!isOpen) return null;
|
|
|
|
return (
|
|
<Dialog open={isOpen} onOpenChange={onClose}>
|
|
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto p-0 gap-0">
|
|
<DialogHeader className="p-6 pb-4 border-b pr-12">
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<DialogTitle className="text-xl font-bold text-gray-900">
|
|
配方明細
|
|
</DialogTitle>
|
|
{recipe && (
|
|
<StatusBadge variant={recipe.is_active ? "success" : "neutral"} className="text-xs font-normal">
|
|
{recipe.is_active ? "啟用中" : "已停用"}
|
|
</StatusBadge>
|
|
)}
|
|
</div>
|
|
|
|
{/* 現代化元數據條 */}
|
|
{recipe && (
|
|
<div className="flex flex-wrap items-center gap-6 pt-2 text-sm text-gray-500">
|
|
<div className="flex items-center gap-2">
|
|
<BookOpen className="w-4 h-4 text-gray-400" />
|
|
<span className="font-medium text-gray-700">{recipe.code}</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Calendar className="w-4 h-4 text-gray-400" />
|
|
<span>建立於 {new Date(recipe.created_at).toLocaleDateString()}</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Clock className="w-4 h-4 text-gray-400" />
|
|
<span>更新於 {new Date(recipe.updated_at).toLocaleDateString()}</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</DialogHeader>
|
|
|
|
<div className="bg-gray-50/50 p-6 min-h-[300px]">
|
|
{isLoading ? (
|
|
<div className="flex justify-center items-center py-12">
|
|
<Loader2 className="h-8 w-8 animate-spin text-primary-main" />
|
|
</div>
|
|
) : recipe ? (
|
|
<div className="space-y-6">
|
|
{/* 基本資訊區塊 */}
|
|
<div className="border rounded-md overflow-hidden bg-white shadow-sm">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow className="bg-gray-50/50 hover:bg-gray-50/50">
|
|
<TableHead className="w-[150px]">欄位</TableHead>
|
|
<TableHead>內容</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
<TableRow>
|
|
<TableCell className="font-medium text-gray-700">配方名稱</TableCell>
|
|
<TableCell className="text-gray-900 font-medium">{recipe.name}</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableCell className="font-medium text-gray-700">對應成品</TableCell>
|
|
<TableCell className="text-gray-900 font-medium">
|
|
<div className="flex items-center gap-2">
|
|
<span>{recipe.product?.name || '-'}</span>
|
|
<span className="text-gray-400 text-xs bg-gray-100 px-1.5 py-0.5 rounded">{recipe.product?.code}</span>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableCell className="font-medium text-gray-700">標準產量</TableCell>
|
|
<TableCell className="text-gray-900 font-medium">
|
|
{Number(recipe.yield_quantity).toLocaleString()} {recipe.product?.base_unit?.name || '份'}
|
|
</TableCell>
|
|
</TableRow>
|
|
{recipe.description && (
|
|
<TableRow>
|
|
<TableCell className="font-medium text-gray-700 align-top pt-3">備註說明</TableCell>
|
|
<TableCell className="text-gray-600 leading-relaxed py-3">
|
|
{recipe.description}
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
|
|
{/* BOM 表格區塊 */}
|
|
<div>
|
|
<h3 className="text-sm font-bold text-gray-900 flex items-center gap-2 px-1 mb-3">
|
|
<Package className="w-4 h-4 text-primary-main" />
|
|
原物料清單 (BOM)
|
|
</h3>
|
|
<div className="border rounded-md overflow-hidden bg-white shadow-sm">
|
|
<Table>
|
|
<TableHeader className="bg-gray-50/50">
|
|
<TableRow>
|
|
<TableHead>原物料名稱 / 料號</TableHead>
|
|
<TableHead className="text-right">標準用量</TableHead>
|
|
<TableHead>單位</TableHead>
|
|
<TableHead>備註</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{recipe.items?.length > 0 ? (
|
|
recipe.items.map((item: any, index: number) => (
|
|
<TableRow key={index} className="hover:bg-gray-50/50">
|
|
<TableCell className="font-medium">
|
|
<div className="flex flex-col">
|
|
<span className="text-gray-900">{item.product?.name || 'Unknown'}</span>
|
|
<span className="text-xs text-gray-400">{item.product?.code}</span>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="text-right font-medium text-gray-900">
|
|
{Number(item.quantity).toLocaleString()}
|
|
</TableCell>
|
|
<TableCell className="text-gray-600">
|
|
{item.unit?.name || '-'}
|
|
</TableCell>
|
|
<TableCell className="text-gray-500 text-sm">
|
|
{item.remark || '-'}
|
|
</TableCell>
|
|
</TableRow>
|
|
))
|
|
) : (
|
|
<TableRow>
|
|
<TableCell colSpan={4} className="h-24 text-center text-gray-500">
|
|
此配方尚未設定原物料
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="py-12 text-center text-gray-500">無法載入配方資料</div>
|
|
)}
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|