Sfoglia il codice sorgente

up date jo/do eaxpiry scan result no yellow click box.

Do lot text smaller, item name code text larger
production
CANCERYS\kw093 9 ore fa
parent
commit
b63269e071
3 ha cambiato i file con 123 aggiunte e 110 eliminazioni
  1. +114
    -84
      src/components/DoWorkbench/WorkbenchGoodPickExecutionDetail.tsx
  2. +5
    -24
      src/components/JoWorkbench/newJobPickExecution.tsx
  3. +4
    -2
      src/i18n/zh/pickOrder.json

+ 114
- 84
src/components/DoWorkbench/WorkbenchGoodPickExecutionDetail.tsx Vedi File

@@ -1671,9 +1671,21 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
processedQrCombinations, processedQrCombinations,
) )
) { ) {
const itemRows = indexes.byItemId.get(scannedItemId) ?? [];
const errMsg =
itemRows.length === 0
? t("QR code does not match any item in current orders.")
: t(
"No pending pick line left for this item. It may already be completed or fully processed.",
);
console.log( console.log(
` [SKIP] No pending stock-out line left for itemId=${scannedItemId}, stockInLineId=${scannedStockInLineId}`, ` [SKIP] No pending stock-out line left for itemId=${scannedItemId}, stockInLineId=${scannedStockInLineId}`,
); );
startTransition(() => {
setQrScanError(true);
setQrScanSuccess(false);
setQrScanErrorMsg(errMsg);
});
return; return;
} }
@@ -2275,9 +2287,21 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
) )
) { ) {
const mismatchCheckTime = performance.now() - mismatchCheckStartTime; const mismatchCheckTime = performance.now() - mismatchCheckStartTime;
const itemRows = indexes.byItemId.get(scannedItemId) ?? [];
const errMsg =
itemRows.length === 0
? t("QR code does not match any item in current orders.")
: t(
"No pending pick line left for this item. It may already be completed or fully processed.",
);
console.log( console.log(
` [SKIP] No pending stock-out line left for mismatch path (check time: ${mismatchCheckTime.toFixed(2)}ms)`, ` [SKIP] No pending stock-out line left for mismatch path (check time: ${mismatchCheckTime.toFixed(2)}ms)`,
); );
startTransition(() => {
setQrScanError(true);
setQrScanSuccess(false);
setQrScanErrorMsg(errMsg);
});
return; return;
} }
const mismatchCheckTime = performance.now() - mismatchCheckStartTime; const mismatchCheckTime = performance.now() - mismatchCheckStartTime;
@@ -3395,6 +3419,7 @@ const handleStartScan = useCallback(() => {
lastConsumedQrValuesLengthRef.current = qrValues.length; lastConsumedQrValuesLengthRef.current = qrValues.length;
setQrScanError(false); setQrScanError(false);
setQrScanSuccess(false); setQrScanSuccess(false);
setQrScanErrorMsg('');
const beforeStartScanTime = performance.now(); const beforeStartScanTime = performance.now();
startScan(); startScan();
@@ -3427,6 +3452,7 @@ const handleStartScan = useCallback(() => {
setIsManualScanning(false); setIsManualScanning(false);
setQrScanError(false); setQrScanError(false);
setQrScanSuccess(false); setQrScanSuccess(false);
setQrScanErrorMsg('');
stopScan(); stopScan();
resetScan(); resetScan();
lastConsumedQrValuesLengthRef.current = 0; lastConsumedQrValuesLengthRef.current = 0;
@@ -3850,7 +3876,10 @@ const handleSubmitAllScanned = useCallback(async () => {
<ScanStatusAlert <ScanStatusAlert
error={qrScanError} error={qrScanError}
success={qrScanSuccess} success={qrScanSuccess}
errorMessage={t("QR code does not match any item in current orders.")}
errorMessage={
qrScanErrorMsg ||
t("QR code does not match any item in current orders.")
}
successMessage={t("QR code verified.")} successMessage={t("QR code verified.")}
/> />
</Box> </Box>
@@ -4116,76 +4145,85 @@ paginatedData.map((row, index) => {
{lot.routerRoute || '-'} {lot.routerRoute || '-'}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell>
<Stack direction="row" spacing={1} alignItems="flex-start">
<Box sx={{ flex: 1, minWidth: 0 }}>
<Typography
sx={{
color:
rejectDisplay || isSolRejected
? 'error.main'
: isInventoryLotLineUnavailable(lot)
? 'error.main'
: lot.lotAvailability === 'expired'
? 'warning.main'
: 'inherit',
}}
>
{lot.lotNo ? (
rejectDisplay ? (
<>
{lot.lotNo}
<Box
component="span"
sx={{ display: 'block', mt: 0.25, typography: 'body2', fontWeight: 400 }}
>
{rejectDisplay}
</Box>
</>
) :
lot.lotAvailability === 'expired' ? (
<>
{lot.lotNo}{' '}
{t('is expired. Please check around have available QR code or not.')}
</>
) : isInventoryLotLineUnavailable(lot) ? (
<>
{lot.lotNo}{' '}
{t('is unavable. Please check around have available QR code or not.')}
</>
) : (
lot.lotNo
)
) : (
<Box component="span" sx={{ fontSize: "0.85rem", lineHeight: 1.4 }}>
{rejectDisplay ||
<TableCell>
<Stack direction="row" spacing={1} alignItems="flex-start">
<Box sx={{ flex: 1, minWidth: 0 }}>
{(() => {
const hasLotNo = Boolean(lot.lotNo);
const isExpired = lot.lotAvailability === 'expired';
const isUnavailable = isInventoryLotLineUnavailable(lot);
const isNoLotHint = !hasLotNo && !rejectDisplay; // 顯示「請檢查周圍…」那種
const isIssueText =
Boolean(rejectDisplay) || !hasLotNo || isExpired || isUnavailable;
const textColor =
isNoLotHint
? 'error.main' // 或 'text.primary':固定黑,不受 handled / unavailable 影響
: rejectDisplay || isSolRejected || isUnavailable
? 'error.main'
: isExpired
? 'warning.main'
: 'inherit';
return (
<Typography
variant={isIssueText ? "body2" : "body1"}
sx={{
color: textColor,
whiteSpace: 'pre-wrap',
wordBreak: 'break-word',
}}
>
{hasLotNo ? (
rejectDisplay ? (
<>
{lot.lotNo}
<Box component="span" sx={{ display: 'block', mt: 0.5, color: 'error.main' }}>
{rejectDisplay}
</Box>
</>
) : isExpired ? (
<>
{lot.lotNo}{' '}
{t('is expired. Please check around have available QR code or not.')}
</>
) : isUnavailable ? (
<>
{lot.lotNo}{' '}
{t('is unavailable. Please check around have available QR code or not.')}
</>
) : (
lot.lotNo
)
) : (
rejectDisplay ||
t( t(
"Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.", "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.",
)}
</Box>
)}
</Typography>
)
)}
</Typography>
);
})()}
</Box> </Box>
{Number(lot.stockOutLineId) > 0 && Number(lot.itemId) > 0 ? (
<Button
variant="outlined"
size="small"
onClick={() => openWorkbenchLotLabelModalForLot(lot)}
sx={{
flexShrink: 0,
fontSize: "0.7rem",
py: 0.25,
minWidth: "auto",
px: 1,
whiteSpace: "nowrap",
}}
>
{t("lot QR code")}
</Button>
) : null}
</Stack>
</TableCell>

{/* Lot QR Code Button */}
{Number(lot.stockOutLineId) > 0 && Number(lot.itemId) > 0 && (
<Button
variant="outlined"
size="small"
onClick={() => openWorkbenchLotLabelModalForLot(lot)}
sx={{
flexShrink: 0,
fontSize: "0.75rem",
py: 0.25,
minWidth: "auto",
px: 1,
whiteSpace: "nowrap",
}}
>
{t("lot QR code")}
</Button>
)}
</Stack>
</TableCell>
<TableCell align="right"> <TableCell align="right">
{(() => { {(() => {
const requiredQty = lot.requiredQty || 0; const requiredQty = lot.requiredQty || 0;
@@ -4219,22 +4257,14 @@ paginatedData.map((row, index) => {
} }


// 過期批號:與 noLot 同類——視為已掃到/可處理(含 pending),顯示警示色勾選 // 過期批號:與 noLot 同類——視為已掃到/可處理(含 pending),顯示警示色勾選
if (isLotAvailabilityExpired(lot) && status !== "rejected") {
return (
<Box sx={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
<Checkbox
checked={true}
disabled={true}
readOnly={true}
size="large"
sx={{
color: "warning.main",
"&.Mui-checked": { color: "warning.main" },
transform: "scale(1.3)",
}}
/>
</Box>
);
if (
isLotAvailabilityExpired(lot) &&
status !== "rejected" &&
status !== "completed" &&
status !== "partially_completed" &&
status !== "partially_complete"
) {
return null;
} }


// 正常 lot:已扫描(checked/partially_completed/completed) // 正常 lot:已扫描(checked/partially_completed/completed)


+ 5
- 24
src/components/JoWorkbench/newJobPickExecution.tsx Vedi File

@@ -4274,31 +4274,12 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList, printerCo


if ( if (
isLotAvailabilityExpired(lot) && isLotAvailabilityExpired(lot) &&
status !== "rejected"
status !== "rejected" &&
status !== "completed" &&
status !== "partially_completed" &&
status !== "partially_complete"
) { ) {
return (
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Checkbox
checked={true}
disabled={true}
readOnly={true}
size="large"
sx={{
color: "warning.main",
"&.Mui-checked": {
color: "warning.main",
},
transform: "scale(1.3)",
}}
/>
</Box>
);
return null;
} }


if ( if (


+ 4
- 2
src/i18n/zh/pickOrder.json Vedi File

@@ -12,6 +12,7 @@
"N/A": "不適用", "N/A": "不適用",
"Release Pick Orders": "放單", "Release Pick Orders": "放單",
"released": "已放單", "released": "已放單",
"is unavailable. Please check around have available QR code or not.": "不可用。請檢查周圍是否有可用的 QR 碼。",
"No lot rows. Select a pick order above.": "沒有批次行。請選擇一個提料單。", "No lot rows. Select a pick order above.": "沒有批次行。請選擇一個提料單。",
"Loading...": "載入中...", "Loading...": "載入中...",
"Suggestion success": "建議成功", "Suggestion success": "建議成功",
@@ -506,7 +507,7 @@
"packaging": "提料中", "packaging": "提料中",
"No Stock Available": "沒有庫存可用", "No Stock Available": "沒有庫存可用",
"This lot is not available, please scan another lot.": "此批號不可用,請掃描其他批號。", "This lot is not available, please scan another lot.": "此批號不可用,請掃描其他批號。",
"Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "請檢查周圍是否有 QR 碼,可能有剛剛入庫、轉移入庫或轉移出庫的 QR 碼。",
"Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "請檢查周圍是否有其他可用 QR 碼。",
"Lot is expired (expiry={{expiry}})": "掃描批號已過期(到期日={{expiry}})", "Lot is expired (expiry={{expiry}})": "掃描批號已過期(到期日={{expiry}})",
"Day After Tomorrow": "後日", "Day After Tomorrow": "後日",
"Lot line is unavailable": "掃描批次不可用", "Lot line is unavailable": "掃描批次不可用",
@@ -561,5 +562,6 @@
"Reject switch lot: picked {{picked}} already greater or equal required {{required}}": "換批被拒:已揀數量({{picked}})已達或超過建議量({{required}}),無法再拆分換批。", "Reject switch lot: picked {{picked}} already greater or equal required {{required}}": "換批被拒:已揀數量({{picked}})已達或超過建議量({{required}}),無法再拆分換批。",
"Lot status is unavailable. Cannot switch or bind; pick line was not updated.": "批號狀態為「不可用」,無法換批或綁定;揀貨行未更新。", "Lot status is unavailable. Cannot switch or bind; pick line was not updated.": "批號狀態為「不可用」,無法換批或綁定;揀貨行未更新。",
"No lot rows. Select a line in the table above.": "尚無批號資料。請在上方表格勾選一行提料單明細。", "No lot rows. Select a line in the table above.": "尚無批號資料。請在上方表格勾選一行提料單明細。",
"No stock out line for this lot": "此批號尚無出庫行,無法提交。"
"No stock out line for this lot": "此批號尚無出庫行,無法提交。",
"No pending pick line left for this item. It may already be completed or fully processed.": "此貨品已無待揀行,可能已完成或不在本單可掃範圍。"
} }

Caricamento…
Annulla
Salva