Files
star-erp/resources/js/Pages/Inventory/GoodsReceipt/components/DuplicateWarningDialog.tsx
sky121113 ad91b08dbc
All checks were successful
ERP-Deploy-Production / deploy-production (push) Successful in 1m9s
ERP-Deploy-Demo / deploy-demo (push) Successful in 1m10s
refactor: 重構 VendorProduct API 與新增進貨單重複檢查前端邏輯
1. 將 VendorProductController 中的 Eloquent 關聯操作改為透過 ProcurementService 使用 DB 操作,解除跨模組 Model 直接依賴。
2. ProcurementService 加入 vendor product 的資料存取方法。
3. 進貨單建立前端 (GoodsReceipt/Create.tsx) 新增重複進貨檢查與警告對話框邏輯。
2026-02-25 11:11:28 +08:00

177 lines
10 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 {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from "@/Components/ui/dialog";
import { Button } from "@/Components/ui/button";
import { AlertTriangle, ArrowRight } from "lucide-react";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/Components/ui/table";
import { StatusBadge } from "@/Components/shared/StatusBadge";
interface DuplicateWarningDialogProps {
open: boolean;
onClose: () => void;
onConfirm: () => void;
warnings: any[];
processing?: boolean;
}
export function DuplicateWarningDialog({ open, onClose, onConfirm, warnings, processing }: DuplicateWarningDialogProps) {
return (
<Dialog open={open} onOpenChange={(val) => !val && onClose()}>
<DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
<DialogHeader>
<div className="flex items-center gap-2 text-amber-600 mb-2">
<AlertTriangle className="h-6 w-6" />
<DialogTitle className="text-xl font-bold"></DialogTitle>
</div>
<p className="text-gray-500">
</p>
</DialogHeader>
<div className="py-4 space-y-6">
{warnings.map((warning, idx) => (
<div key={idx} className={`p-4 rounded-lg border ${warning.level === 'high' ? 'bg-red-50 border-red-100' : 'bg-amber-50 border-amber-100'}`}>
<div className="flex items-center gap-2 mb-3">
<div className={`w-2 h-2 rounded-full ${warning.level === 'high' ? 'bg-red-500' : 'bg-amber-500'}`} />
<h4 className={`font-bold ${warning.level === 'high' ? 'text-red-900' : 'text-amber-900'}`}>
{warning.title}
</h4>
</div>
<p className="text-sm text-gray-700 mb-4">{warning.message}</p>
{/* Same PO Warning Details */}
{warning.type === 'same_po' && warning.related_receipts && (
<div className="bg-white rounded border overflow-hidden">
<Table>
<TableHeader className="bg-gray-50">
<TableRow>
<TableHead className="text-xs"></TableHead>
<TableHead className="text-xs"></TableHead>
<TableHead className="text-xs"></TableHead>
<TableHead className="text-xs text-center"></TableHead>
</TableRow>
</TableHeader>
<TableBody className="text-xs">
{warning.related_receipts.map((r: any) => (
<TableRow key={r.id}>
<TableCell className="font-medium text-blue-600">{r.code}</TableCell>
<TableCell>{r.received_date}</TableCell>
<TableCell>
<StatusBadge variant="neutral">{r.status}</StatusBadge>
</TableCell>
<TableCell className="text-center">{r.item_count} </TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
{/* Recent Products Warning Details */}
{warning.type === 'recent_duplicate_product' && warning.duplicated_items && (
<div className="bg-white rounded border overflow-hidden">
<Table>
<TableHeader className="bg-gray-50">
<TableRow>
<TableHead className="text-xs"></TableHead>
<TableHead className="text-xs"> / </TableHead>
<TableHead className="text-xs text-right"></TableHead>
<TableHead className="text-xs text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody className="text-xs">
{warning.duplicated_items.map((item: any, i: number) => (
<TableRow key={i}>
<TableCell>
<div>{item.product_name}</div>
<div className="text-[10px] text-gray-400">{item.product_id}</div>
</TableCell>
<TableCell>
<div>{item.last_receipt_date}</div>
<div className="text-[10px] text-gray-400">{item.last_receipt_code}</div>
</TableCell>
<TableCell className="text-right">{item.last_quantity}</TableCell>
<TableCell className="text-right font-bold flex items-center justify-end gap-1">
<ArrowRight className="h-3 w-3 text-gray-300" />
{item.current_quantity}
{item.is_high_risk && <span className="text-[10px] bg-red-100 text-red-600 px-1 rounded"></span>}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
{/* Stale Price Warning Details */}
{warning.type === 'stale_price' && warning.stale_items && (
<div className="bg-white rounded border overflow-hidden">
<Table>
<TableHeader className="bg-gray-50">
<TableRow>
<TableHead className="text-xs"></TableHead>
<TableHead className="text-xs text-right"></TableHead>
<TableHead className="text-xs text-center"></TableHead>
<TableHead className="text-xs"></TableHead>
</TableRow>
</TableHeader>
<TableBody className="text-xs">
{warning.stale_items.map((item: any, i: number) => (
<TableRow key={i}>
<TableCell>
<div>{item.product_name}</div>
<div className="text-[10px] text-gray-400">{item.product_id}</div>
</TableCell>
<TableCell className="text-right font-mono font-bold text-amber-700">
${item.unit_price.toLocaleString()}
</TableCell>
<TableCell className="text-center">
{item.record_count}
</TableCell>
<TableCell>
<div>{item.earliest_date} ~ {item.latest_date}</div>
<div className="text-[10px] text-gray-400">{item.latest_code}</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
</div>
))}
</div>
<DialogFooter className="gap-2">
<Button
variant="outline"
onClick={onClose}
disabled={processing}
className="button-outlined-primary"
>
</Button>
<Button
onClick={onConfirm}
className="button-filled-primary"
disabled={processing}
>
{processing ? '處理中...' : '確認無重複,繼續建立'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}