Procházet zdrojové kódy

update scan lot

MergeProblem1
CANCERYS\kw093 před 2 dny
rodič
revize
30823cee8e
8 změnil soubory, kde provedl 177 přidání a 151 odebrání
  1. +16
    -5
      src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx
  2. +2
    -1
      src/components/Jodetail/JoPickOrderList.tsx
  3. +1
    -48
      src/components/Jodetail/JobPickExecutionForm.tsx
  4. +150
    -97
      src/components/Jodetail/newJobPickExecution.tsx
  5. +1
    -0
      src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx
  6. +3
    -0
      src/i18n/zh/common.json
  7. +3
    -0
      src/i18n/zh/jo.json
  8. +1
    -0
      src/i18n/zh/pickOrder.json

+ 16
- 5
src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx Zobrazit soubor

@@ -3208,9 +3208,23 @@ paginatedData.map((lot, index) => {
const isRejected = status === 'rejected' || lot.lotAvailability === 'rejected'; const isRejected = status === 'rejected' || lot.lotAvailability === 'rejected';
const isNoLot = !lot.lotNo; const isNoLot = !lot.lotNo;
// rejected lot:不显示任何按钮
// ✅ rejected lot:显示提示文本(换行显示)
if (isRejected && !isNoLot) { if (isRejected && !isNoLot) {
return null;
return (
<Typography
variant="body2"
color="error.main"
sx={{
textAlign: 'center',
whiteSpace: 'normal',
wordBreak: 'break-word',
maxWidth: '200px',
lineHeight: 1.5
}}
>
{t("This lot is rejected, please scan another lot.")}
</Typography>
);
} }
// noLot 情况:只显示 Issue 按钮 // noLot 情况:只显示 Issue 按钮
@@ -3264,10 +3278,7 @@ paginatedData.map((lot, index) => {
onClick={() => handlePickExecutionForm(lot)} onClick={() => handlePickExecutionForm(lot)}
disabled={ disabled={
lot.lotAvailability === 'expired' || lot.lotAvailability === 'expired' ||
//lot.lotAvailability === 'status_unavailable' ||
// lot.lotAvailability === 'rejected' ||
lot.stockOutLineStatus === 'completed' lot.stockOutLineStatus === 'completed'
//lot.stockOutLineStatus === 'pending'
} }
sx={{ sx={{
fontSize: '0.7rem', fontSize: '0.7rem',


+ 2
- 1
src/components/Jodetail/JoPickOrderList.tsx Zobrazit soubor

@@ -50,7 +50,8 @@ const JoPickOrderList: React.FC<Props> = ({ onSwitchToRecordTab }) =>{
const handleBackToList = useCallback(() => { const handleBackToList = useCallback(() => {
setSelectedPickOrderId(undefined); setSelectedPickOrderId(undefined);
setSelectedJobOrderId(undefined); setSelectedJobOrderId(undefined);
}, []);
fetchPickOrders();
}, [fetchPickOrders]);
// If a pick order is selected, show JobPickExecution detail view // If a pick order is selected, show JobPickExecution detail view
if (selectedPickOrderId !== undefined) { if (selectedPickOrderId !== undefined) {
return ( return (


+ 1
- 48
src/components/Jodetail/JobPickExecutionForm.tsx Zobrazit soubor

@@ -471,54 +471,7 @@ useEffect(() => {
</FormControl> </FormControl>
</Grid> </Grid>
{/* Show issue description and handler fields when bad items > 0 */}
{(formData.badItemQty && formData.badItemQty > 0) || ((formData as any).badPackageQty && (formData as any).badPackageQty > 0) ? (
<>
<Grid item xs={12}>
<TextField
fullWidth
id="issueRemark"
label={t('Issue Remark')}
multiline
rows={4}
value={formData.issueRemark || ''}
onChange={(e) => {
handleInputChange('issueRemark', e.target.value);
// Don't reset badItemQty when typing in issue remark
}}
error={!!errors.issueRemark}
helperText={errors.issueRemark}
//placeholder={t('Describe the issue with bad items')}
variant="outlined"
/>
</Grid>
<Grid item xs={12}>
<FormControl fullWidth error={!!errors.handledBy}>
<InputLabel>{t('handler')}</InputLabel>
<Select
value={formData.handledBy ? formData.handledBy.toString() : ''}
onChange={(e) => {
handleInputChange('handledBy', e.target.value ? parseInt(e.target.value) : undefined);
// Don't reset badItemQty when selecting handler
}}
label={t('handler')}
>
{handlers.map((handler) => (
<MenuItem key={handler.id} value={handler.id.toString()}>
{handler.name}
</MenuItem>
))}
</Select>
{errors.handledBy && (
<Typography variant="caption" color="error" sx={{ mt: 0.5, ml: 1.75 }}>
{errors.handledBy}
</Typography>
)}
</FormControl>
</Grid>
</>
) : null}
</Grid> </Grid>
</Box> </Box>
</DialogContent> </DialogContent>


+ 150
- 97
src/components/Jodetail/newJobPickExecution.tsx Zobrazit soubor

@@ -1686,6 +1686,11 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
if (completionResponse.code === "SUCCESS") { if (completionResponse.code === "SUCCESS") {
console.log(` Pick order ${lot.pickOrderConsoCode} completed successfully!`); console.log(` Pick order ${lot.pickOrderConsoCode} completed successfully!`);
setTimeout(() => {
if (onBackToList) {
onBackToList();
}
}, 1500);
} else if (completionResponse.message === "not completed") { } else if (completionResponse.message === "not completed") {
console.log(`⏳ Pick order not completed yet, more lines remaining`); console.log(`⏳ Pick order not completed yet, more lines remaining`);
} else { } else {
@@ -1756,6 +1761,11 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
if (completionResponse.code === "SUCCESS") { if (completionResponse.code === "SUCCESS") {
console.log(` Pick order ${lot.pickOrderConsoCode} completed successfully!`); console.log(` Pick order ${lot.pickOrderConsoCode} completed successfully!`);
setTimeout(() => {
if (onBackToList) {
onBackToList();
}
}, 1500);
} else if (completionResponse.message === "not completed") { } else if (completionResponse.message === "not completed") {
console.log(`⏳ Pick order not completed yet, more lines remaining`); console.log(`⏳ Pick order not completed yet, more lines remaining`);
} else { } else {
@@ -2229,10 +2239,10 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
<TableRow <TableRow
key={`${lot.pickOrderLineId}-${lot.lotId}`} key={`${lot.pickOrderLineId}-${lot.lotId}`}
sx={{ sx={{
backgroundColor: lot.lotAvailability === 'rejected' ? 'grey.100' : 'inherit',
opacity: lot.lotAvailability === 'rejected' ? 0.6 : 1,
// backgroundColor: lot.lotAvailability === 'rejected' ? 'grey.100' : 'inherit',
//opacity: lot.lotAvailability === 'rejected' ? 0.6 : 1,
'& .MuiTableCell-root': { '& .MuiTableCell-root': {
color: lot.lotAvailability === 'rejected' ? 'text.disabled' : 'inherit'
// color: lot.lotAvailability === 'rejected' ? 'text.disabled' : 'inherit'
} }
}} }}
> >
@@ -2253,8 +2263,8 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
<Box> <Box>
<Typography <Typography
sx={{ sx={{
color: lot.lotAvailability === 'rejected' ? 'text.disabled' : 'inherit',
opacity: lot.lotAvailability === 'rejected' ? 0.6 : 1
// color: lot.lotAvailability === 'rejected' ? 'text.disabled' : 'inherit',
//opacity: lot.lotAvailability === 'rejected' ? 0.6 : 1
}} }}
> >
{lot.lotNo} {lot.lotNo}
@@ -2269,98 +2279,141 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
</TableCell> </TableCell>
<TableCell align="center"> <TableCell align="center">
{lot.stockOutLineStatus?.toLowerCase() !== 'pending' ? (
<Box sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%'
}}>
<Checkbox
checked={lot.stockOutLineStatus?.toLowerCase() !== 'pending'}
disabled={true}
readOnly={true}
size="large"
sx={{
color: lot.stockOutLineStatus?.toLowerCase() !== 'pending' ? 'success.main' : 'grey.400',
'&.Mui-checked': {
color: 'success.main',
},
transform: 'scale(1.3)',
'& .MuiSvgIcon-root': {
fontSize: '1.5rem',
}
}}
/>
</Box>
) : null}
</TableCell>

<TableCell align="center">
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
<Stack direction="row" spacing={1} alignItems="center">
<Button
variant="contained"
onClick={() => {
const lotKey = `${lot.pickOrderLineId}-${lot.lotId}`;
const submitQty = lot.requiredQty || lot.pickOrderLineRequiredQty;
// Submit with default lot required pick qty
handlePickQtyChange(lotKey, submitQty);
handleSubmitPickQtyWithQty(lot, submitQty);
updateHandledBy(lot.pickOrderId, lot.itemId);
}}
disabled={
(lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected') ||
lot.stockOutLineStatus === 'completed' ||
lot.stockOutLineStatus === 'pending' // Disable when QR scan not passed
}
sx={{
fontSize: '0.75rem',
py: 0.5,
minHeight: '28px',
minWidth: '70px'
}}
>
{t("Submit")}
</Button>
<Button
variant="outlined"
size="small"
onClick={() => handlePickExecutionForm(lot)}
disabled={
// ✅ align with GoodPickExecutiondetail: Edit only disabled when completed
lot.stockOutLineStatus === 'completed'
}
sx={{
fontSize: '0.7rem',
py: 0.5,
minHeight: '28px',
minWidth: '60px',
borderColor: 'warning.main',
color: 'warning.main'
}}
title="Report missing or bad items"
>
{t("Edit")}
</Button>
<Button
variant="outlined"
size="small"
// ✅ align with GoodPickExecutiondetail: Just Complete submits requiredQty (not 0)
onClick={() => handleSubmitPickQtyWithQty(lot, lot.requiredQty || lot.pickOrderLineRequiredQty || 0)}
disabled={lot.stockOutLineStatus === 'completed'}
sx={{ fontSize: '0.7rem', py: 0.5, minHeight: '28px', minWidth: '90px' }}
>
{t("Just Complete")}
</Button>
</Stack>
</Box>
</TableCell>
{(() => {
const status = lot.stockOutLineStatus?.toLowerCase();
const isRejected = status === 'rejected' || lot.lotAvailability === 'rejected';
const isNoLot = !lot.lotNo;
// ✅ rejected lot:显示红色勾选(已扫描但被拒绝)
if (isRejected && !isNoLot) {
return (
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Checkbox
checked={true}
disabled={true}
readOnly={true}
size="large"
sx={{
color: 'error.main',
'&.Mui-checked': { color: 'error.main' },
transform: 'scale(1.3)',
}}
/>
</Box>
);
}
// ✅ 正常 lot:已扫描(checked/partially_completed/completed)
if (!isNoLot && status !== 'pending' && status !== 'rejected') {
return (
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Checkbox
checked={true}
disabled={true}
readOnly={true}
size="large"
sx={{
color: 'success.main',
'&.Mui-checked': { color: 'success.main' },
transform: 'scale(1.3)',
}}
/>
</Box>
);
}
return null;
})()}
</TableCell>

<TableCell align="center">
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
{(() => {
const status = lot.stockOutLineStatus?.toLowerCase();
const isRejected = status === 'rejected' || lot.lotAvailability === 'rejected';
const isNoLot = !lot.lotNo;
// ✅ rejected lot:显示提示文本(换行显示)
if (isRejected && !isNoLot) {
return (
<Typography
variant="body2"
color="error.main"
sx={{
textAlign: 'center',
whiteSpace: 'normal',
wordBreak: 'break-word',
maxWidth: '200px',
lineHeight: 1.5
}}
>
{t("This lot is rejected, please scan another lot.")}
</Typography>
);
}
// 正常 lot:显示按钮
return (
<Stack direction="row" spacing={1} alignItems="center">
<Button
variant="contained"
onClick={() => {
const lotKey = `${lot.pickOrderLineId}-${lot.lotId}`;
const submitQty = lot.requiredQty || lot.pickOrderLineRequiredQty;
handlePickQtyChange(lotKey, submitQty);
handleSubmitPickQtyWithQty(lot, submitQty);
updateHandledBy(lot.pickOrderId, lot.itemId);
}}
disabled={
(lot.lotAvailability === 'expired' ||
lot.lotAvailability === 'status_unavailable' ||
lot.lotAvailability === 'rejected') ||
lot.stockOutLineStatus === 'completed' ||
lot.stockOutLineStatus === 'pending'
}
sx={{
fontSize: '0.75rem',
py: 0.5,
minHeight: '28px',
minWidth: '70px'
}}
>
{t("Submit")}
</Button>
<Button
variant="outlined"
size="small"
onClick={() => handlePickExecutionForm(lot)}
disabled={
lot.stockOutLineStatus === 'completed'
}
sx={{
fontSize: '0.7rem',
py: 0.5,
minHeight: '28px',
minWidth: '60px',
borderColor: 'warning.main',
color: 'warning.main'
}}
title="Report missing or bad items"
>
{t("Edit")}
</Button>
<Button
variant="outlined"
size="small"
onClick={() => handleSubmitPickQtyWithQty(lot, lot.requiredQty || lot.pickOrderLineRequiredQty || 0)}
disabled={lot.stockOutLineStatus === 'completed'}
sx={{ fontSize: '0.7rem', py: 0.5, minHeight: '28px', minWidth: '90px' }}
>
{t("Just Complete")}
</Button>
</Stack>
);
})()}
</Box>
</TableCell>
</TableRow> </TableRow>
)) ))
)} )}


+ 1
- 0
src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx Zobrazit soubor

@@ -641,6 +641,7 @@ const handleRelease = useCallback(async ( jobOrderId: number) => {
color="primary" color="primary"
onClick={() => handleRelease(jobOrderId)} onClick={() => handleRelease(jobOrderId)}
//disabled={stockCounts.insufficient > 0 || processData?.jobOrderStatus !== "planning"} //disabled={stockCounts.insufficient > 0 || processData?.jobOrderStatus !== "planning"}
disabled={processData?.jobOrderStatus !== "planning"}
> >
{t("Release")} {t("Release")}
</Button> </Button>


+ 3
- 0
src/i18n/zh/common.json Zobrazit soubor

@@ -9,9 +9,12 @@
"Select Another Bag Lot": "選擇另一個包裝袋", "Select Another Bag Lot": "選擇另一個包裝袋",
"Finished QC Job Orders": "完成QC工單", "Finished QC Job Orders": "完成QC工單",
"Stock Issue": "出倉問題", "Stock Issue": "出倉問題",
"Step Start Time": "步驟開始時間",
"Overall Time Remaining": "總剩餘時間", "Overall Time Remaining": "總剩餘時間",
"Reset": "重置", "Reset": "重置",
"Search": "搜索", "Search": "搜索",
"This lot is rejected, please scan another lot.": "此批次已封存,請掃描另一個批號。",
"Process Start Time": "工序開始時間",
"Stock Req. Qty": "需求數(庫存單位)", "Stock Req. Qty": "需求數(庫存單位)",
"Staff No Required": "員工編號必填", "Staff No Required": "員工編號必填",
"User Not Found": "用戶不存在", "User Not Found": "用戶不存在",


+ 3
- 0
src/i18n/zh/jo.json Zobrazit soubor

@@ -12,9 +12,12 @@
"Confirm All": "確認所有提料", "Confirm All": "確認所有提料",
"Wait Time [minutes]": "等待時間(分鐘)", "Wait Time [minutes]": "等待時間(分鐘)",
"Job Process Status": "工單流程狀態", "Job Process Status": "工單流程狀態",
"This lot is rejected, please scan another lot.": "此批次已拒收,請掃描另一個批次。",
"Edit": "改數", "Edit": "改數",
"Just Complete": "已完成", "Just Complete": "已完成",
"Stock Req. Qty": "需求數(庫存單位)", "Stock Req. Qty": "需求數(庫存單位)",
"Bad Package Qty": "不良包裝數量",
"Progress": "進度",
"Search Job Order/ Create Job Order":"搜尋工單/建立工單", "Search Job Order/ Create Job Order":"搜尋工單/建立工單",
"UoM": "銷售單位", "UoM": "銷售單位",
"Select Another Bag Lot":"選擇另一個包裝袋", "Select Another Bag Lot":"選擇另一個包裝袋",


+ 1
- 0
src/i18n/zh/pickOrder.json Zobrazit soubor

@@ -21,6 +21,7 @@
"Required Date": "所需日期", "Required Date": "所需日期",
"Store": "位置", "Store": "位置",
"Available Orders": "可用訂單", "Available Orders": "可用訂單",
"This lot is rejected, please scan another lot.": "此批次已拒收,請掃描另一個批次。",
"Lane Code": "車線號碼", "Lane Code": "車線號碼",
"Fetching all matching records...": "正在獲取所有匹配的記錄...", "Fetching all matching records...": "正在獲取所有匹配的記錄...",
"Edit": "改數", "Edit": "改數",


Načítá se…
Zrušit
Uložit