浏览代码

quick fix

master
kelvin.yau 2 周前
父节点
当前提交
0d809c933b
共有 1 个文件被更改,包括 266 次插入201 次删除
  1. +266
    -201
      src/components/PickOrderSearch/LotTable.tsx

+ 266
- 201
src/components/PickOrderSearch/LotTable.tsx 查看文件

@@ -28,10 +28,10 @@ import { fetchStockInLineInfo } from "@/app/api/po/actions"; // Add this import
import PickExecutionForm from "./PickExecutionForm"; import PickExecutionForm from "./PickExecutionForm";
interface LotPickData { interface LotPickData {
id: number; id: number;
lotId: number | null;
lotNo: string | null;
lotId: number;
lotNo: string;
expiryDate: string; expiryDate: string;
location: string | null;
location: string;
stockUnit: string; stockUnit: string;
inQty: number; inQty: number;
availableQty: number; availableQty: number;
@@ -45,7 +45,6 @@ interface LotPickData {
stockOutLineId?: number; stockOutLineId?: number;
stockOutLineStatus?: string; stockOutLineStatus?: string;
stockOutLineQty?: number; stockOutLineQty?: number;
noLot?: boolean;
} }


interface PickQtyData { interface PickQtyData {
@@ -61,7 +60,7 @@ interface LotTableProps {
pickQtyData: PickQtyData; pickQtyData: PickQtyData;
selectedLotRowId: string | null; selectedLotRowId: string | null;
selectedLotId: number | null; selectedLotId: number | null;
onLotSelection: (uniqueLotId: string, lotId: number | null) => void;
onLotSelection: (uniqueLotId: string, lotId: number) => void;
onPickQtyChange: (lineId: number, lotId: number, value: number) => void; onPickQtyChange: (lineId: number, lotId: number, value: number) => void;
onSubmitPickQty: (lineId: number, lotId: number) => void; onSubmitPickQty: (lineId: number, lotId: number) => void;
onCreateStockOutLine: (inventoryLotLineId: number) => void; onCreateStockOutLine: (inventoryLotLineId: number) => void;
@@ -76,7 +75,6 @@ interface LotTableProps {
generateInputBody: () => any; generateInputBody: () => any;
onDataRefresh: () => Promise<void>; onDataRefresh: () => Promise<void>;
onLotDataRefresh: () => Promise<void>; onLotDataRefresh: () => Promise<void>;
onIssueNoLotStockOutLine: (stockOutLineId: number) => void;
} }


// QR Code Modal Component // QR Code Modal Component
@@ -238,7 +236,7 @@ const QrCodeModal: React.FC<{
const timer = setTimeout(() => { const timer = setTimeout(() => {
setQrScanSuccess(true); setQrScanSuccess(true);
onQrCodeSubmit(lot.lotNo??'');
onQrCodeSubmit(lot.lotNo);
onClose(); onClose();
setManualInput(''); setManualInput('');
setManualInputError(false); setManualInputError(false);
@@ -303,7 +301,9 @@ const QrCodeModal: React.FC<{
</Box> </Box>
)} )}
{/* Manual Input with Submit-Triggered Helper Text */} {/* Manual Input with Submit-Triggered Helper Text */}
{false &&(
<Box sx={{ mb: 2 }}> <Box sx={{ mb: 2 }}>
<Typography variant="body2" gutterBottom> <Typography variant="body2" gutterBottom>
<strong>{t("Manual Input")}:</strong> <strong>{t("Manual Input")}:</strong>
@@ -339,7 +339,8 @@ const QrCodeModal: React.FC<{
{t("Submit")} {t("Submit")}
</Button> </Button>
</Box> </Box>

)}
{/* Show QR Scan Status */} {/* Show QR Scan Status */}
{qrValues.length > 0 && ( {qrValues.length > 0 && (
<Box sx={{ <Box sx={{
@@ -390,28 +391,30 @@ const LotTable: React.FC<LotTableProps> = ({
generateInputBody, generateInputBody,
onDataRefresh, onDataRefresh,
onLotDataRefresh, onLotDataRefresh,
onIssueNoLotStockOutLine,
}) => { }) => {
const { t } = useTranslation("pickOrder"); const { t } = useTranslation("pickOrder");

const calculateRemainingRequiredQty = useCallback((lot: LotPickData) => { const calculateRemainingRequiredQty = useCallback((lot: LotPickData) => {
const requiredQty = lot.requiredQty || 0; const requiredQty = lot.requiredQty || 0;
const stockOutLineQty = lot.stockOutLineQty || 0; const stockOutLineQty = lot.stockOutLineQty || 0;
return Math.max(0, requiredQty - stockOutLineQty); return Math.max(0, requiredQty - stockOutLineQty);
}, []); }, []);
// Add QR scanner context
const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext(); const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext();
const [validationErrors, setValidationErrors] = useState<{[key: string]: string}>({}); const [validationErrors, setValidationErrors] = useState<{[key: string]: string}>({});
// Add state for QR input modal
const [qrModalOpen, setQrModalOpen] = useState(false); const [qrModalOpen, setQrModalOpen] = useState(false);
const [selectedLotForQr, setSelectedLotForQr] = useState<LotPickData | null>(null); const [selectedLotForQr, setSelectedLotForQr] = useState<LotPickData | null>(null);
const [manualQrInput, setManualQrInput] = useState<string>(''); const [manualQrInput, setManualQrInput] = useState<string>('');

// 分页控制器
const [lotTablePagingController, setLotTablePagingController] = useState({ const [lotTablePagingController, setLotTablePagingController] = useState({
pageNum: 0, pageNum: 0,
pageSize: 10, pageSize: 10,
}); });


// 添加状态消息生成函数
const getStatusMessage = useCallback((lot: LotPickData) => { const getStatusMessage = useCallback((lot: LotPickData) => {

switch (lot.stockOutLineStatus?.toLowerCase()) { switch (lot.stockOutLineStatus?.toLowerCase()) {
case 'pending': case 'pending':
return t("Please finish QR code scanand pick order."); return t("Please finish QR code scanand pick order.");
@@ -428,35 +431,23 @@ const LotTable: React.FC<LotTableProps> = ({
default: default:
return t("Please finish QR code scan and pick order."); return t("Please finish QR code scan and pick order.");
} }
}, [t]);
const handleOpenQrModal = useCallback((lot: LotPickData) => {
setSelectedLotForQr(lot);
setManualQrInput(lot.lotNo ?? "");
setValidationErrors({});
setQrModalOpen(true);
resetScan();
startScan();
}, [startScan, resetScan]);
const handleCloseQrModal = useCallback(() => {
setQrModalOpen(false);
setSelectedLotForQr(null);
stopScan();
resetScan();
}, [stopScan, resetScan]);
}, []);

const prepareLotTableData = useMemo(() => { const prepareLotTableData = useMemo(() => {
return lotData.map((lot) => ({ return lotData.map((lot) => ({
...lot, ...lot,
id: lot.lotId ?? lot.id,
id: lot.lotId,
})); }));
}, [lotData]); }, [lotData]);


// 分页数据
const paginatedLotTableData = useMemo(() => { const paginatedLotTableData = useMemo(() => {
const startIndex = lotTablePagingController.pageNum * lotTablePagingController.pageSize; const startIndex = lotTablePagingController.pageNum * lotTablePagingController.pageSize;
const endIndex = startIndex + lotTablePagingController.pageSize; const endIndex = startIndex + lotTablePagingController.pageSize;
return prepareLotTableData.slice(startIndex, endIndex); return prepareLotTableData.slice(startIndex, endIndex);
}, [prepareLotTableData, lotTablePagingController]); }, [prepareLotTableData, lotTablePagingController]);


// 分页处理函数
const handleLotTablePageChange = useCallback((event: unknown, newPage: number) => { const handleLotTablePageChange = useCallback((event: unknown, newPage: number) => {
setLotTablePagingController(prev => ({ setLotTablePagingController(prev => ({
...prev, ...prev,
@@ -471,25 +462,31 @@ const LotTable: React.FC<LotTableProps> = ({
pageSize: newPageSize, pageSize: newPageSize,
}); });
}, []); }, []);

const calculateRemainingAvailableQty = useCallback((lot: LotPickData) => { const calculateRemainingAvailableQty = useCallback((lot: LotPickData) => {
if (!selectedRowId || lot.noLot) return lot.availableQty;
const actualPickQty = pickQtyData[selectedRowId]?.[lot.lotId ?? 0] || 0;
const remainingQty = (lot.inQty || 0) - (lot.outQty || 0) - actualPickQty;
if (!selectedRowId) return lot.availableQty;
const lactualPickQty = lot.actualPickQty || 0;
const actualPickQty = pickQtyData[selectedRowId]?.[lot.lotId] || 0;
const remainingQty = lot.inQty - lot.outQty-actualPickQty;
// Ensure it doesn't go below 0
return Math.max(0, remainingQty); return Math.max(0, remainingQty);
}, [selectedRowId, pickQtyData]); }, [selectedRowId, pickQtyData]);

const validatePickQty = useCallback((lot: LotPickData, inputValue: number) => { const validatePickQty = useCallback((lot: LotPickData, inputValue: number) => {
const maxAllowed = Math.min(calculateRemainingAvailableQty(lot), calculateRemainingRequiredQty(lot));
if (inputValue > maxAllowed) {
return `${t('Input quantity cannot exceed')} ${maxAllowed}`;
}
if (inputValue < 0) {
return t('Quantity cannot be negative');
}
return null;
}, [calculateRemainingAvailableQty, calculateRemainingRequiredQty, t]);
const maxAllowed = Math.min(calculateRemainingAvailableQty(lot), calculateRemainingRequiredQty(lot));
if (inputValue > maxAllowed) {
return `${t('Input quantity cannot exceed')} ${maxAllowed}`;
}
if (inputValue < 0) {
return t('Quantity cannot be negative');
}
return null;
}, [calculateRemainingAvailableQty, calculateRemainingRequiredQty, t]);


// Handle QR code submission
const handleQrCodeSubmit = useCallback(async (lotNo: string) => { const handleQrCodeSubmit = useCallback(async (lotNo: string) => {
if (selectedLotForQr && selectedLotForQr.lotNo === lotNo) { if (selectedLotForQr && selectedLotForQr.lotNo === lotNo) {
console.log(` QR Code verified for lot: ${lotNo}`); console.log(` QR Code verified for lot: ${lotNo}`);
@@ -522,7 +519,7 @@ const LotTable: React.FC<LotTableProps> = ({
if (selectedRowId) { if (selectedRowId) {
// Add a small delay to ensure the data refresh is complete // Add a small delay to ensure the data refresh is complete
setTimeout(() => { setTimeout(() => {
onPickQtyChange(selectedRowId, lotId ?? 0, requiredQty);
onPickQtyChange(selectedRowId, lotId, requiredQty);
console.log(` Auto-set pick quantity to ${requiredQty} for lot ${lotNo}`); console.log(` Auto-set pick quantity to ${requiredQty} for lot ${lotNo}`);
}, 500); // 500ms delay to ensure refresh is complete }, 500); // 500ms delay to ensure refresh is complete
} }
@@ -540,10 +537,12 @@ const LotTable: React.FC<LotTableProps> = ({
alert(`QR scan mismatch! Expected: ${selectedLotForQr?.lotNo}, Scanned: ${lotNo}`); alert(`QR scan mismatch! Expected: ${selectedLotForQr?.lotNo}, Scanned: ${lotNo}`);
} }
}, [selectedLotForQr, selectedRowId, onPickQtyChange]); }, [selectedLotForQr, selectedRowId, onPickQtyChange]);
// PickExecutionForm 狀態與提交(保持原本邏輯)

// 添加 PickExecutionForm 相关的状态
const [pickExecutionFormOpen, setPickExecutionFormOpen] = useState(false); const [pickExecutionFormOpen, setPickExecutionFormOpen] = useState(false);
const [selectedLotForExecutionForm, setSelectedLotForExecutionForm] = useState<LotPickData | null>(null); const [selectedLotForExecutionForm, setSelectedLotForExecutionForm] = useState<LotPickData | null>(null);


// 添加处理函数
const handlePickExecutionForm = useCallback((lot: LotPickData) => { const handlePickExecutionForm = useCallback((lot: LotPickData) => {
console.log("=== Pick Execution Form ==="); console.log("=== Pick Execution Form ===");
console.log("Lot data:", lot); console.log("Lot data:", lot);
@@ -564,6 +563,8 @@ const LotTable: React.FC<LotTableProps> = ({
const handlePickExecutionFormSubmit = useCallback(async (data: any) => { const handlePickExecutionFormSubmit = useCallback(async (data: any) => {
try { try {
console.log("Pick execution form submitted:", data); console.log("Pick execution form submitted:", data);
// 调用 API 提交数据
const result = await recordPickExecutionIssue(data); const result = await recordPickExecutionIssue(data);
console.log("Pick execution issue recorded:", result); console.log("Pick execution issue recorded:", result);
@@ -576,6 +577,7 @@ const LotTable: React.FC<LotTableProps> = ({
setPickExecutionFormOpen(false); setPickExecutionFormOpen(false);
setSelectedLotForExecutionForm(null); setSelectedLotForExecutionForm(null);
// 刷新数据
if (onDataRefresh) { if (onDataRefresh) {
await onDataRefresh(); await onDataRefresh();
} }
@@ -601,7 +603,14 @@ const LotTable: React.FC<LotTableProps> = ({
<TableCell align="right">{t("Lot Required Pick Qty")}</TableCell> <TableCell align="right">{t("Lot Required Pick Qty")}</TableCell>
<TableCell align="right">{t("Original Available Qty")}</TableCell> <TableCell align="right">{t("Original Available Qty")}</TableCell>
<TableCell align="center">{t("Lot Actual Pick Qty")}</TableCell> <TableCell align="center">{t("Lot Actual Pick Qty")}</TableCell>
{/*<TableCell align="right">{t("Available Lot")}</TableCell>*/}
<TableCell align="right">{t("Remaining Available Qty")}</TableCell> <TableCell align="right">{t("Remaining Available Qty")}</TableCell>
{/*<TableCell align="center">{t("QR Code Scan")}</TableCell>*/}
{/*}
<TableCell align="center">{t("Reject")}</TableCell>
*/}

<TableCell align="center">{t("Action")}</TableCell> <TableCell align="center">{t("Action")}</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
@@ -617,7 +626,7 @@ const LotTable: React.FC<LotTableProps> = ({
) : ( ) : (
paginatedLotTableData.map((lot, index) => ( paginatedLotTableData.map((lot, index) => (
<TableRow <TableRow
key={lot.noLot ? `noLot_${lot.stockOutLineId}_${index}` : `lot_${lot.lotId}_${index}`}
key={lot.id}
sx={{ sx={{
backgroundColor: lot.lotAvailability === 'rejected' ? 'grey.100' : 'inherit', backgroundColor: lot.lotAvailability === 'rejected' ? 'grey.100' : 'inherit',
opacity: lot.lotAvailability === 'rejected' ? 0.6 : 1, opacity: lot.lotAvailability === 'rejected' ? 0.6 : 1,
@@ -627,30 +636,36 @@ const LotTable: React.FC<LotTableProps> = ({
}} }}
> >
<TableCell> <TableCell>
<Checkbox
checked={selectedLotRowId === `row_${index}`}
onChange={() => {
if (!lot.noLot && lot.lotId != null) {
onLotSelection(`row_${index}`, lot.lotId);
}
}}
disabled={
lot.noLot || // 無批次行不支援勾選
lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected'
}
value={`row_${index}`}
name="lot-selection"
/>
</TableCell>
<Checkbox
checked={selectedLotRowId === `row_${index}`}
onChange={() => onLotSelection(`row_${index}`, lot.lotId)}
// 禁用 rejected、expired 和 status_unavailable 的批次
disabled={lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected'} // 添加 rejected
value={`row_${index}`}
name="lot-selection"
/>
</TableCell>
<TableCell> <TableCell>
<Box> <Box>
<Typography>
{lot.noLot
? t('⚠️ No Stock Available')
: lot.lotNo}
<Typography
sx={{
color: lot.lotAvailability === 'rejected' ? 'text.disabled' : 'inherit',
opacity: lot.lotAvailability === 'rejected' ? 0.6 : 1
}}
>
{lot.lotNo}
</Typography> </Typography>
{/*
{lot.lotAvailability !== 'available' && (
<Typography variant="caption" color="error" display="block">
({lot.lotAvailability === 'expired' ? 'Expired' :
lot.lotAvailability === 'insufficient_stock' ? 'Insufficient' :
lot.lotAvailability === 'rejected' ? 'Rejected' : // 添加 rejected 显示
'Unavailable'})
</Typography>
)} */}
</Box> </Box>
</TableCell> </TableCell>
<TableCell>{lot.expiryDate}</TableCell> <TableCell>{lot.expiryDate}</TableCell>
@@ -661,140 +676,154 @@ const LotTable: React.FC<LotTableProps> = ({
{(() => { {(() => {
const inQty = lot.inQty || 0; const inQty = lot.inQty || 0;
const outQty = lot.outQty || 0; const outQty = lot.outQty || 0;
const result = inQty - outQty; const result = inQty - outQty;
return result.toLocaleString(); return result.toLocaleString();
})()} })()}
</TableCell> </TableCell>
<TableCell align="center"> <TableCell align="center">
{lot.stockOutLineStatus?.toLowerCase() === 'pending' ? (
<Button
variant="outlined"
size="small"
startIcon={<QrCodeIcon />}
onClick={() => handleOpenQrModal(lot)}
disabled={
lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected' ||
selectedLotRowId !== `row_${index}`
}
sx={{ fontSize: '0.7rem', minHeight: 40, minWidth: 100 }}
title={
selectedLotRowId !== `row_${index}`
? t("Please select this lot first to enable QR scanning")
: t("Click to scan QR code")
}
>
{t("Scan")}
</Button>
) : (
<Stack direction="row" spacing={1} alignItems="center" justifyContent="center">
<TextField
type="number"
size="small"
value={
selectedRowId && lot.lotId != null
? pickQtyData[selectedRowId]?.[lot.lotId] ?? ''
: ''
}
onChange={(e) => {
if (selectedRowId && lot.lotId != null) {
onPickQtyChange(selectedRowId, lot.lotId, Number(e.target.value) || 0);
}
}}
disabled={
lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected' ||
selectedLotRowId !== `row_${index}` ||
lot.stockOutLineStatus === 'completed'
}
error={!!validationErrors[`lot_${lot.lotId}`]}
helperText={validationErrors[`lot_${lot.lotId}`]}
inputProps={{ min: 0, max: calculateRemainingRequiredQty(lot) }}
sx={{ width: 70 }}
placeholder="0"
/>
<Button
variant="outlined"
size="small"
onClick={() => handlePickExecutionForm(lot)}
disabled={
lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected' ||
selectedLotRowId !== `row_${index}`
}
sx={{ fontSize: '0.7rem', minWidth: 70, borderColor: 'warning.main', color: 'warning.main' }}
title={t("Report missing or bad items")}
>
{t("Issue")}
</Button>
</Stack>
)}
</TableCell>
<TableCell align="right">
{calculateRemainingAvailableQty(lot).toLocaleString()}
</TableCell>
{/* Show QR Scan Button if not scanned, otherwise show TextField + Pick Form */}
{lot.stockOutLineStatus?.toLowerCase() === 'pending' ? (
<Button
variant="outlined"
size="small"
onClick={() => {
setSelectedLotForQr(lot);
setQrModalOpen(true);
resetScan();
}}
disabled={
(lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected') ||
selectedLotRowId !== `row_${index}`
}
sx={{
fontSize: '0.7rem',
py: 0.5,
minHeight: '40px',
whiteSpace: 'nowrap',
minWidth: '80px',
opacity: selectedLotRowId === `row_${index}` ? 1 : 0.5
}}
startIcon={<QrCodeIcon />}
title={
selectedLotRowId !== `row_${index}`
? "Please select this lot first to enable QR scanning"
: "Click to scan QR code"
}
>
{t("Scan")}
</Button>
) : (
<Stack
direction="row"
spacing={1}
alignItems="center"
justifyContent="center" // 添加水平居中
sx={{
width: '100%', // 确保占满整个单元格宽度
minHeight: '40px' // 设置最小高度确保垂直居中
}}
>
{/* 恢复 TextField 用于正常数量输入 */}
<TextField
type="number"
size="small"
value={pickQtyData[selectedRowId!]?.[lot.lotId] || ''}
onChange={(e) => {
if (selectedRowId) {
const inputValue = parseFloat(e.target.value) || 0;
const maxAllowed = Math.min(calculateRemainingAvailableQty(lot), calculateRemainingRequiredQty(lot));
onPickQtyChange(selectedRowId, lot.lotId, inputValue);
}
}}
disabled={
(lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected') ||
selectedLotRowId !== `row_${index}` ||
lot.stockOutLineStatus === 'completed'
}
error={!!validationErrors[`lot_${lot.lotId}`]}
helperText={validationErrors[`lot_${lot.lotId}`]}
inputProps={{
min: 0,
max: calculateRemainingRequiredQty(lot),
step: 0.01
}}
sx={{
width: '60px',
height: '28px',
'& .MuiInputBase-input': {
fontSize: '0.7rem',
textAlign: 'center',
padding: '6px 8px'
}
}}
placeholder="0"
/>
{/* 添加 Pick Form 按钮用于问题情况 */}
<Button
variant="outlined"
size="small"
onClick={() => handlePickExecutionForm(lot)}
disabled={
(lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected') ||
selectedLotRowId !== `row_${index}`
}
sx={{
fontSize: '0.7rem',
py: 0.5,
minHeight: '28px',
minWidth: '60px',
borderColor: 'warning.main',
color: 'warning.main'
}}
title="Report missing or bad items"
>
{t("Issue")}
</Button>
</Stack>
)}
</TableCell>
{/*<TableCell align="right">{lot.availableQty.toLocaleString()}</TableCell>*/}
<TableCell align="right">{calculateRemainingAvailableQty(lot).toLocaleString()}</TableCell>


{/* ✅ Action 欄位:區分 noLot / 正常 lot */}
<TableCell align="center">
<Stack direction="column" spacing={1} alignItems="center">
{lot.noLot ? (
// 沒有批次:只允許 Issue(報告 miss)
<Button
variant="outlined"
size="small"
onClick={() => {
if (lot.stockOutLineId) {
onIssueNoLotStockOutLine(lot.stockOutLineId);
}
}}
disabled={
lot.stockOutLineStatus === 'completed' ||
lot.lotAvailability === 'rejected'
}
sx={{
fontSize: '0.7rem',
py: 0.5,
minHeight: '28px',
minWidth: '60px',
borderColor: 'warning.main',
color: 'warning.main'
}}
title="Report missing items (no lot available)"
>
{t("Issue")}
</Button>
) : (
<Button
variant="contained"
onClick={() => {
if (selectedRowId && lot.lotId != null) {
onSubmitPickQty(selectedRowId, lot.lotId);
}
}}
disabled={
lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected' ||
!selectedRowId ||
!pickQtyData[selectedRowId]?.[lot.lotId ?? 0] ||
!lot.stockOutLineStatus ||
!['pending','checked', 'partially_completed'].includes(
lot.stockOutLineStatus.toLowerCase()
)
}
sx={{
fontSize: '0.75rem',
py: 0.5,
minHeight: '28px'
}}
>
{t("Submit")}
</Button>
)}
</Stack>
<TableCell align="center">

<Stack direction="column" spacing={1} alignItems="center">
<Button
variant="contained"
onClick={() => {
if (selectedRowId) {
onSubmitPickQty(selectedRowId, lot.lotId);
}
}}
disabled={
(lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected') || // 添加 rejected
!pickQtyData[selectedRowId!]?.[lot.lotId] ||
!lot.stockOutLineStatus ||
!['pending','checked', 'partially_completed'].includes(lot.stockOutLineStatus.toLowerCase())
}
// Allow submission for available AND insufficient_stock lots
sx={{
fontSize: '0.75rem',
py: 0.5,
minHeight: '28px'
}}
>
{t("Submit")}
</Button>
</Stack>
</TableCell> </TableCell>
</TableRow> </TableRow>
)) ))
@@ -802,14 +831,50 @@ const LotTable: React.FC<LotTableProps> = ({
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
{/* Status Messages Display */}
{paginatedLotTableData.length > 0 && (
<Box sx={{ mt: 2, p: 2, backgroundColor: 'grey.50', borderRadius: 1 }}>
{paginatedLotTableData.map((lot, index) => (
<Box key={lot.id} sx={{ mb: 1 }}>
<Typography variant="body2" color="text.secondary">
<strong>{t("Lot")} {lot.lotNo}:</strong> {getStatusMessage(lot)}
</Typography>
</Box>
))}
</Box>
)}


{/* Status message & pagination & modals 保持原有程式不變(略) */}
<TablePagination
component="div"
count={prepareLotTableData.length}
page={lotTablePagingController.pageNum}
rowsPerPage={lotTablePagingController.pageSize}
onPageChange={handleLotTablePageChange}
onRowsPerPageChange={handleLotTablePageSizeChange}
rowsPerPageOptions={[10, 25, 50]}
labelRowsPerPage={t("Rows per page")}
labelDisplayedRows={({ from, to, count }) =>
`${from}-${to} of ${count !== -1 ? count : `more than ${to}`}`
}
/>
{/* QR Code Modal */}
<QrCodeModal <QrCodeModal
open={qrModalOpen}
onClose={handleCloseQrModal}
lot={selectedLotForQr}
onQrCodeSubmit={handleQrCodeSubmit}
/>
open={qrModalOpen}
onClose={() => {
setQrModalOpen(false);
setSelectedLotForQr(null);
stopScan();
resetScan();
}}
lot={selectedLotForQr}
onQrCodeSubmit={handleQrCodeSubmit}
/>

{/* Pick Execution Form Modal */}
{pickExecutionFormOpen && selectedLotForExecutionForm && selectedRow && ( {pickExecutionFormOpen && selectedLotForExecutionForm && selectedRow && (
<PickExecutionForm <PickExecutionForm
open={pickExecutionFormOpen} open={pickExecutionFormOpen}


正在加载...
取消
保存