[FEAT] 新增生產工單實際產量欄位與 UI 規範
- 新增 database/migrations/tenant 實際產量與耗損原因 - ProductionOrder API 狀態推進與實際產量計算 - 完工入庫新增實際產出數量原生數字輸入框 (step=1) - Create.tsx 補上前端資料驗證與狀態保護 - 建立並更新 UI 數字輸入框設計規範
This commit is contained in:
@@ -56,6 +56,8 @@ interface ProductionOrder {
|
||||
output_batch_number: string;
|
||||
output_box_count: string | null;
|
||||
output_quantity: number;
|
||||
actual_output_quantity: number | null;
|
||||
loss_reason: string | null;
|
||||
production_date: string;
|
||||
expiry_date: string | null;
|
||||
status: ProductionOrderStatus;
|
||||
@@ -88,12 +90,16 @@ export default function ProductionShow({ productionOrder, warehouses, auth }: Pr
|
||||
warehouseId?: number;
|
||||
batchNumber?: string;
|
||||
expiryDate?: string;
|
||||
actualOutputQuantity?: number;
|
||||
lossReason?: 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,
|
||||
actual_output_quantity: extraData?.actualOutputQuantity,
|
||||
loss_reason: extraData?.lossReason,
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
setIsWarehouseModalOpen(false);
|
||||
@@ -129,6 +135,8 @@ export default function ProductionShow({ productionOrder, warehouses, auth }: Pr
|
||||
processing={processing}
|
||||
productCode={productionOrder.product?.code}
|
||||
productId={productionOrder.product?.id}
|
||||
outputQuantity={Number(productionOrder.output_quantity)}
|
||||
unitName={productionOrder.product?.base_unit?.name}
|
||||
/>
|
||||
|
||||
<div className="container mx-auto p-6 max-w-7xl animate-in fade-in duration-500">
|
||||
@@ -276,7 +284,7 @@ export default function ProductionShow({ productionOrder, warehouses, auth }: Pr
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<p className="text-xs font-semibold text-grey-2 uppercase tracking-wider">預計/實際產量</p>
|
||||
<p className="text-xs font-semibold text-grey-2 uppercase tracking-wider">預計產量</p>
|
||||
<div className="flex items-baseline gap-1.5">
|
||||
<p className="font-bold text-grey-0 text-xl">
|
||||
{formatQuantity(productionOrder.output_quantity)}
|
||||
@@ -289,6 +297,28 @@ export default function ProductionShow({ productionOrder, warehouses, auth }: Pr
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{/* 實際產量與耗損(僅完成狀態顯示) */}
|
||||
{productionOrder.status === PRODUCTION_ORDER_STATUS.COMPLETED && productionOrder.actual_output_quantity != null && (
|
||||
<div className="space-y-1.5">
|
||||
<p className="text-xs font-semibold text-grey-2 uppercase tracking-wider">實際產量</p>
|
||||
<div className="flex items-baseline gap-1.5">
|
||||
<p className="font-bold text-grey-0 text-xl">
|
||||
{formatQuantity(productionOrder.actual_output_quantity)}
|
||||
</p>
|
||||
{productionOrder.product?.base_unit?.name && (
|
||||
<span className="text-grey-2 font-medium">{productionOrder.product.base_unit.name}</span>
|
||||
)}
|
||||
{Number(productionOrder.output_quantity) > Number(productionOrder.actual_output_quantity) && (
|
||||
<span className="ml-2 inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-orange-100 text-orange-700 text-xs font-bold border border-orange-200">
|
||||
耗損 {formatQuantity(Number(productionOrder.output_quantity) - Number(productionOrder.actual_output_quantity))}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{productionOrder.loss_reason && (
|
||||
<p className="text-xs text-orange-600 mt-1">原因:{productionOrder.loss_reason}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-1.5">
|
||||
<p className="text-xs font-semibold text-grey-2 uppercase tracking-wider">入庫倉庫</p>
|
||||
<div className="flex items-center gap-2 bg-grey-5 p-2 rounded-lg border border-grey-4">
|
||||
|
||||
Reference in New Issue
Block a user