生產工單BOM以及批號完善
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogFooter,
|
||||
} from "@/Components/ui/dialog";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { Input } from "@/Components/ui/input";
|
||||
import { Label } from "@/Components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/Components/ui/select";
|
||||
import { AlertCircle } from "lucide-react";
|
||||
|
||||
interface BatchAdjustmentModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onConfirm: (data: {
|
||||
operation: "add" | "subtract" | "set";
|
||||
quantity: number;
|
||||
reason: string;
|
||||
}) => void;
|
||||
batch?: {
|
||||
id: string;
|
||||
batchNumber: string;
|
||||
currentQuantity: number;
|
||||
productName: string;
|
||||
};
|
||||
processing?: boolean;
|
||||
}
|
||||
|
||||
export default function BatchAdjustmentModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
onConfirm,
|
||||
batch,
|
||||
processing = false,
|
||||
}: BatchAdjustmentModalProps) {
|
||||
const [operation, setOperation] = useState<"add" | "subtract" | "set">("add");
|
||||
const [quantity, setQuantity] = useState<string>("");
|
||||
const [reason, setReason] = useState<string>("手動調整庫存");
|
||||
|
||||
// 當開啟時重置
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setOperation("add");
|
||||
setQuantity("");
|
||||
setReason("手動調整庫存");
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const handleConfirm = () => {
|
||||
const numQty = parseFloat(quantity);
|
||||
if (isNaN(numQty) || numQty <= 0 && operation !== "set") {
|
||||
return;
|
||||
}
|
||||
|
||||
onConfirm({
|
||||
operation,
|
||||
quantity: numQty,
|
||||
reason,
|
||||
});
|
||||
};
|
||||
|
||||
const previewQuantity = () => {
|
||||
if (!batch) return 0;
|
||||
const numQty = parseFloat(quantity) || 0;
|
||||
if (operation === "add") return batch.currentQuantity + numQty;
|
||||
if (operation === "subtract") return Math.max(0, batch.currentQuantity - numQty);
|
||||
if (operation === "set") return numQty;
|
||||
return batch.currentQuantity;
|
||||
};
|
||||
|
||||
if (!batch) return null;
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
庫存調整 - {batch.productName}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="bg-gray-50 p-3 rounded-md border text-sm space-y-1">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-500">批號:</span>
|
||||
<span className="font-mono font-medium">{batch.batchNumber || "-"}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-500">當前數量:</span>
|
||||
<span className="font-medium text-primary-main">{batch.currentQuantity}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>調整方式</Label>
|
||||
<Select
|
||||
value={operation}
|
||||
onValueChange={(value: any) => setOperation(value)}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="選擇調整方式" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="add">增加 (+)</SelectItem>
|
||||
<SelectItem value="subtract">扣除 (-)</SelectItem>
|
||||
<SelectItem value="set">設定為固定值 (=)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="adj-qty">數量</Label>
|
||||
<Input
|
||||
id="adj-qty"
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0"
|
||||
value={quantity}
|
||||
onChange={(e) => setQuantity(e.target.value)}
|
||||
placeholder="請輸入數量"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="adj-reason">調整原因</Label>
|
||||
<Input
|
||||
id="adj-reason"
|
||||
value={reason}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
placeholder="例:手動盤點修正"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 mt-2 p-3 bg-primary/5 rounded-md border border-primary/20 text-sm">
|
||||
<AlertCircle className="h-4 w-4 text-primary-main" />
|
||||
<span>
|
||||
調整後預計數量:
|
||||
<span className="font-bold text-primary-main ml-1">
|
||||
{previewQuantity()}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={onClose} disabled={processing}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleConfirm}
|
||||
disabled={processing || !quantity || parseFloat(quantity) < 0}
|
||||
className="button-filled-primary"
|
||||
>
|
||||
確認調整
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user