import { useState } from "react"; import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout"; import { Head, Link, router } from "@inertiajs/react"; import { SearchableSelect } from "@/Components/ui/searchable-select"; import { Button } from "@/Components/ui/button"; import { Input } from "@/Components/ui/input"; import { Textarea } from "@/Components/ui/textarea"; import { Label } from "@/Components/ui/label"; import { StatusBadge } from "@/Components/shared/StatusBadge"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/Components/ui/table"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription, } from "@/Components/ui/dialog"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/Components/ui/alert-dialog"; import { toast } from "sonner"; import { Can } from "@/Components/Permission/Can"; import { usePermission } from "@/hooks/usePermission"; import { Store, SendHorizontal, CheckCircle2, XCircle, Pencil, Loader2, ArrowLeft, } from "lucide-react"; import { formatDate } from "@/lib/date"; function getStatusBadge(status: string) { const statusMap: Record = { draft: { label: "草稿", variant: "neutral" }, pending: { label: "待審核", variant: "warning" }, approved: { label: "已核准", variant: "success" }, rejected: { label: "已駁回", variant: "destructive" }, completed: { label: "已完成", variant: "success" }, cancelled: { label: "已取消", variant: "neutral" }, }; const config = statusMap[status]; if (!config) return {status}; return ( {config.label} ); } interface RequisitionItem { id: number; product_id: number; product_name: string; product_code: string; unit_name: string; requested_qty: number; approved_qty: number | null; current_stock: number; remark: string | null; } interface Requisition { id: number; doc_no: string; status: string; store_warehouse_id: number; store_warehouse_name: string; supply_warehouse_id: number | null; supply_warehouse_name: string; remark: string | null; reject_reason: string | null; creator_name: string; approver_name: string; submitted_at: string | null; approved_at: string | null; transfer_order_id: number | null; created_at: string; items: RequisitionItem[]; } interface Props { requisition: Requisition; warehouses: { id: number; name: string }[]; activities: any[]; } export default function Show({ requisition, warehouses }: Props) { usePermission(); const [submitting, setSubmitting] = useState(false); const [approving, setApproving] = useState(false); const [rejecting, setRejecting] = useState(false); // 核准狀態 const [showApproveDialog, setShowApproveDialog] = useState(false); const [supplyWarehouseId, setSupplyWarehouseId] = useState(""); const [approvedItems, setApprovedItems] = useState<{ id: number; approved_qty: string }[]>( requisition.items.map((item) => ({ id: item.id, approved_qty: item.requested_qty.toString(), })) ); // 駁回狀態 const [showRejectDialog, setShowRejectDialog] = useState(false); const [rejectReason, setRejectReason] = useState(""); // 提交確認 const [showSubmitDialog, setShowSubmitDialog] = useState(false); const handleSubmit = () => { setSubmitting(true); router.post(route("store-requisitions.submit", [requisition.id]), {}, { onFinish: () => { setSubmitting(false); setShowSubmitDialog(false); }, }); }; const handleApprove = () => { if (!supplyWarehouseId) { toast.error("請選擇供貨倉庫"); return; } // 確認每個核准數量 for (const item of approvedItems) { const qty = parseFloat(item.approved_qty); if (isNaN(qty) || qty < 0) { toast.error("核准數量不能為負數"); return; } } setApproving(true); router.post( route("store-requisitions.approve", [requisition.id]), { supply_warehouse_id: supplyWarehouseId, items: approvedItems.map((item) => ({ id: item.id, approved_qty: parseFloat(item.approved_qty), })), }, { onFinish: () => { setApproving(false); setShowApproveDialog(false); }, } ); }; const handleReject = () => { if (!rejectReason.trim()) { toast.error("請填寫駁回原因"); return; } setRejecting(true); router.post( route("store-requisitions.reject", [requisition.id]), { reject_reason: rejectReason }, { onFinish: () => { setRejecting(false); setShowRejectDialog(false); }, } ); }; const updateApprovedQty = (itemId: number, qty: string) => { setApprovedItems( approvedItems.map((item) => (item.id === itemId ? { ...item, approved_qty: qty } : item)) ); }; const isEditable = ["draft", "rejected"].includes(requisition.status); const isPending = requisition.status === "pending"; return (
{/* 返回按鈕 */}
{/* 頁面標題與操作 */}

{requisition.doc_no}

{getStatusBadge(requisition.status)} {formatDate(requisition.created_at)}
{/* 操作按鈕 */}
{isEditable && ( <> {requisition.status === "draft" && ( )} )} {isPending && ( <> )}
{/* 基本資訊 */}

基本資訊

申請倉庫

{requisition.store_warehouse_name}

供貨倉庫

{requisition.supply_warehouse_name || "-"}

申請人

{requisition.creator_name}

{requisition.submitted_at && (
提交時間

{formatDate(requisition.submitted_at)}

)} {requisition.approved_at && ( <>
審核人

{requisition.approver_name}

審核時間

{formatDate(requisition.approved_at)}

)} {requisition.remark && (
備註

{requisition.remark}

)} {requisition.reject_reason && (
駁回原因

{requisition.reject_reason}

)} {requisition.transfer_order_id && (
關聯調撥單

查看調撥單 →

)}
{/* 商品明細 */}

商品明細

# 商品編號 商品名稱 現有庫存 需求數量 單位 {["approved", "completed"].includes(requisition.status) && ( 核准數量 )} 備註 {requisition.items.map((item, index) => ( {index + 1} {item.product_code} {item.product_name} {Number(item.current_stock).toLocaleString()} {Number(item.requested_qty).toLocaleString()} {item.unit_name} {["approved", "completed"].includes(requisition.status) && ( {item.approved_qty !== null ? Number(item.approved_qty).toLocaleString() : "-"} )} {item.remark || "-"} ))}
{/* 提交確認 */} 確認提交審核? 提交後將無法修改叫貨單內容,並會通知相關人員進行審核。 取消 {submitting && } 確認提交 {/* 核准對話框 */} 核准叫貨單 選擇供貨倉庫,並確認各商品的核准數量。
w.id !== requisition.store_warehouse_id) .map((w) => ({ label: w.name, value: w.id.toString(), }))} placeholder="請選擇供貨倉庫" className="h-9" />
商品 需求數量 單位 核准數量 {requisition.items.map((item) => ( {item.product_code} {item.product_name} {Number(item.requested_qty).toLocaleString()} {item.unit_name} ai.id === item.id) ?.approved_qty || "" } onChange={(e) => updateApprovedQty(item.id, e.target.value) } className="h-8 text-right" /> ))}
{/* 駁回對話框 */} 駁回叫貨單 請說明駁回原因,申請人可根據原因修改後重新提交。