171 lines
6.0 KiB
TypeScript
171 lines
6.0 KiB
TypeScript
|
||
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>
|
||
);
|
||
}
|