/** * 生產工單詳情頁面 * 含追溯資訊:成品批號 → 原物料批號 → 來源採購單 */ import { Factory, ArrowLeft, Package, Calendar, User, Warehouse, FileText, Link2, Send, CheckCircle2, PlayCircle, Ban, ArrowRightCircle } from 'lucide-react'; import { formatQuantity } from "@/lib/utils"; import { Button } from "@/Components/ui/button"; import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout"; import { Head, Link, useForm, router } from "@inertiajs/react"; import { getBreadcrumbs } from "@/utils/breadcrumb"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/Components/ui/table"; import { Badge } from "@/Components/ui/badge"; import ProductionOrderStatusBadge from '@/Components/ProductionOrder/ProductionOrderStatusBadge'; import { ProductionStatusProgressBar } from '@/Components/ProductionOrder/ProductionStatusProgressBar'; import { PRODUCTION_ORDER_STATUS, ProductionOrderStatus } from '@/constants/production-order'; import WarehouseSelectionModal from '@/Components/ProductionOrder/WarehouseSelectionModal'; import { useState } from 'react'; import { formatDate } from '@/lib/date'; interface Warehouse { id: number; name: string; } interface ProductionOrderItem { // ... (後面保持不變) id: number; quantity_used: number; unit?: { id: number; name: string } | null; inventory: { id: number; batch_number: string; box_number: string | null; arrival_date: string | null; origin_country: string | null; product: { id: number; name: string; code: string } | null; warehouse?: { id: number; name: string } | null; source_purchase_order?: { id: number; code: string; vendor?: { id: number; name: string } | null; } | null; } | null; } interface ProductionOrder { id: number; code: string; product: { id: number; name: string; code: string; base_unit?: { name: string } | null } | null; product_id: number; warehouse: { id: number; name: string } | null; warehouse_id: number | null; user: { id: number; name: string } | null; output_batch_number: string; output_box_count: string | null; output_quantity: number; production_date: string; expiry_date: string | null; status: ProductionOrderStatus; remark: string | null; created_at: string; items: ProductionOrderItem[]; } interface Props { productionOrder: ProductionOrder; warehouses: Warehouse[]; auth: { user: { id: number; name: string; roles: string[]; permissions: string[]; } | null; }; } export default function ProductionShow({ productionOrder, warehouses, auth }: Props) { const [isWarehouseModalOpen, setIsWarehouseModalOpen] = useState(false); const { processing } = useForm({ status: '' as ProductionOrderStatus, warehouse_id: null as number | null, }); const handleStatusUpdate = (newStatus: string, extraData?: { warehouseId?: number; batchNumber?: string; expiryDate?: string; }) => { router.patch(route('production-orders.update-status', productionOrder.id), { status: newStatus, warehouse_id: extraData?.warehouseId, output_batch_number: extraData?.batchNumber, expiry_date: extraData?.expiryDate, }, { onSuccess: () => { setIsWarehouseModalOpen(false); }, preserveScroll: true, }); }; const userPermissions = auth.user?.permissions || []; const hasPermission = (permission: string) => auth.user?.roles?.includes('super-admin') || userPermissions.includes(permission); // 權限判斷 const canApprove = hasPermission('production_orders.approve'); const canCancel = hasPermission('production_orders.cancel'); const canEdit = hasPermission('production_orders.edit'); return ( setIsWarehouseModalOpen(false)} onConfirm={(data) => handleStatusUpdate(PRODUCTION_ORDER_STATUS.COMPLETED, data)} warehouses={warehouses} processing={processing} productCode={productionOrder.product?.code} productId={productionOrder.product?.id} />
{/* Header 區塊 */}
{/* 返回按鈕 (統一規範:標題上方,mb-4) */}

生產工單:{productionOrder.code}

建立人員:{productionOrder.user?.name || '-'} | 建立時間:{formatDate(productionOrder.created_at)}

{/* 操作按鈕區 (統一規範樣式類別) */}
{/* 草稿 -> 提交審核 */} {productionOrder.status === PRODUCTION_ORDER_STATUS.DRAFT && ( <> {canEdit && ( )} )} {/* 待審核 -> 核准 / 駁回 */} {productionOrder.status === PRODUCTION_ORDER_STATUS.PENDING && canApprove && ( <> )} {/* 已核准 -> 開始製作 */} {productionOrder.status === PRODUCTION_ORDER_STATUS.APPROVED && ( )} {/* 製作中 -> 完成製作 */} {productionOrder.status === PRODUCTION_ORDER_STATUS.IN_PROGRESS && ( )} {/* 可作廢狀態 (非已完成/已作廢/草稿之外) */} {!([PRODUCTION_ORDER_STATUS.COMPLETED, PRODUCTION_ORDER_STATUS.CANCELLED, PRODUCTION_ORDER_STATUS.DRAFT] as ProductionOrderStatus[]).includes(productionOrder.status) && canCancel && ( )}
{/* 狀態進度條 */}
{/* 成品資訊 (統一規範:bg-white rounded-xl border border-gray-200 shadow-sm p-6) */}

成品資訊

成品商品

{productionOrder.product?.name || '-'}

{productionOrder.product?.code || '-'}

生產批號

{productionOrder.output_batch_number}

預計/實際產量

{formatQuantity(productionOrder.output_quantity)}

{productionOrder.product?.base_unit?.name && ( {productionOrder.product.base_unit.name} )} {productionOrder.output_box_count && ( ({productionOrder.output_box_count} 箱) )}

入庫倉庫

{productionOrder.warehouse?.name || (productionOrder.status === PRODUCTION_ORDER_STATUS.COMPLETED ? '系統錯誤' : '待選取')}

{productionOrder.remark && (

備註資訊

{productionOrder.remark}

)}
{/* 次要資訊 */}

時間與人員

生產日期

{formatDate(productionOrder.production_date)}

成品效期

{formatDate(productionOrder.expiry_date)}

執行人員

{productionOrder.user?.name || '-'}

{/* 原物料使用明細 (BOM) (統一規範:bg-white rounded-xl border border-gray-200 shadow-sm p-6) */}

原料耗用與追溯

共 {productionOrder.items.length} 項物料
{productionOrder.items.length === 0 ? (

無原物料消耗記錄

) : (
原物料 來源倉庫 使用批號 來源國家 使用數量 來源單據 {productionOrder.items.map((item) => (
{item.inventory?.product?.name || '-'}
{item.inventory?.product?.code || '-'}
{item.inventory?.warehouse?.name || '-'}
{item.inventory?.batch_number || '-'} {item.inventory?.box_number && ( #{item.inventory.box_number} )}
{item.inventory?.origin_country || '-'}
{formatQuantity(item.quantity_used)} {item.unit?.name && ( {item.unit.name} )}
{item.inventory?.source_purchase_order ? (
{item.inventory.source_purchase_order.code} {item.inventory.source_purchase_order.vendor && ( {item.inventory.source_purchase_order.vendor.name} )}
) : ( )}
))}
)}
); }