Переглянути джерело

Merge branch 'MergeProblem1' of https://git.2fi-solutions.com/derek/FPSMS-frontend into MergeProblem1

MergeProblem1
kelvin.yau 3 дні тому
джерело
коміт
080aed9316
3 змінених файлів з 87 додано та 42 видалено
  1. +82
    -39
      src/components/Jodetail/newJobPickExecution.tsx
  2. +4
    -3
      src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx
  3. +1
    -0
      src/i18n/zh/jo.json

+ 82
- 39
src/components/Jodetail/newJobPickExecution.tsx Переглянути файл

@@ -186,7 +186,7 @@ const QrCodeModal: React.FC<{
const { t } = useTranslation("jo");
const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext();
const [manualInput, setManualInput] = useState<string>('');
// 楼层筛选状态
const [selectedFloor, setSelectedFloor] = useState<string | null>(null);
const [manualInputSubmitted, setManualInputSubmitted] = useState<boolean>(false);
const [manualInputError, setManualInputError] = useState<boolean>(false);
@@ -390,10 +390,15 @@ const QrCodeModal: React.FC<{
: ''
}
/>

<Button
variant="contained"
onClick={handleManualSubmit}
disabled={!manualInput.trim()}
disabled={
!manualInput.trim() ||
lot?.noLot === true ||
!lot?.lotId
}
size="small"
color="primary"
>
@@ -824,8 +829,7 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
// 使用辅助函数获取所有 lots(不再扁平化)
const allLots = getAllLotsFromHierarchical(jobOrderData);
// ... 其他逻辑保持不变 ...
} catch (error) {
console.error("❌ Error fetching job order data:", error);
@@ -1935,10 +1939,27 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
}
}, [handleSubmitPickQtyWithQty]);
const handleSubmitAllScanned = useCallback(async () => {
const scannedLots = combinedLotData.filter(lot =>
lot.stockOutLineStatus === 'checked' || lot.stockOutLineStatus === 'partially_completed'
);
const scannedLots = combinedLotData.filter(lot => {
const status = lot.stockOutLineStatus;
console.log("lot.noLot:", lot.noLot);
console.log("lot.status:", lot.stockOutLineStatus);
// ✅ no-lot:允許 pending / checked / partially_completed / PARTIALLY_COMPLETE
if (lot.noLot === true || !lot.lotId) {
return (
status === 'checked' ||
status === 'pending' ||
status === 'partially_completed' ||
status === 'PARTIALLY_COMPLETE'
);
}
// ✅ 有 lot:維持原本規則
return (
status === 'checked' ||
status === 'partially_completed' ||
status === 'PARTIALLY_COMPLETE'
);
});
if (scannedLots.length === 0) {
console.log("No scanned items to submit");
return;
@@ -1967,21 +1988,31 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
// ✅ 转换为 batchSubmitList 所需的格式
const lines: batchSubmitListLineRequest[] = scannedLots.map((lot) => {
const requiredQty = Number(lot.requiredQty || lot.pickOrderLineRequiredQty || 0);
const solId = Number(lot.stockOutLineId) || 0;
const issuePicked = solId > 0 ? issuePickedQtyBySolId[solId] : undefined;
const currentActualPickQty = Number(issuePicked ?? lot.actualPickQty ?? 0);
const onlyComplete = lot.stockOutLineStatus === 'partially_completed' || issuePicked !== undefined;

let targetActual: number;
let newStatus: string;
if (onlyComplete) {
targetActual = currentActualPickQty;
newStatus = 'completed';
} else {
const remainingQty = Math.max(0, requiredQty - currentActualPickQty);
targetActual = currentActualPickQty + remainingQty;
newStatus = (requiredQty > 0 && targetActual >= requiredQty) ? 'completed' : 'partially_completed';
}
const solId = Number(lot.stockOutLineId) || 0;
const issuePicked = solId > 0 ? issuePickedQtyBySolId[solId] : undefined;
const currentActualPickQty = Number(issuePicked ?? lot.actualPickQty ?? 0);
const isNoLot = lot.noLot === true || !lot.lotId;

// ✅ 只改狀態模式:有 issuePicked 或 noLot
const onlyComplete =
lot.stockOutLineStatus === 'partially_completed' ||
issuePicked !== undefined ||
isNoLot;

let targetActual: number;
let newStatus: string;

if (onlyComplete) {
targetActual = currentActualPickQty; // no‑lot = 0,一律只改狀態
newStatus = 'completed';
} else {
const remainingQty = Math.max(0, requiredQty - currentActualPickQty);
targetActual = currentActualPickQty + remainingQty;
newStatus =
requiredQty > 0 && targetActual >= requiredQty
? 'completed'
: 'partially_completed';
}
return {
stockOutLineId: Number(lot.stockOutLineId) || 0,
@@ -2056,9 +2087,27 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
}
}, [combinedLotData, fetchJobOrderData, checkAndAutoAssignNext, currentUserId, filterArgs?.pickOrderId, onBackToList, updateHandledBy, issuePickedQtyBySolId])
const scannedItemsCount = useMemo(() => {
return combinedLotData.filter(lot =>
lot.stockOutLineStatus === 'checked' || lot.stockOutLineStatus === 'partially_completed'
).length;
return combinedLotData.filter(lot => {
const status = lot.stockOutLineStatus;
const isNoLot = lot.noLot === true || !lot.lotId;
if (isNoLot) {
// no-lot:pending / checked / partially_completed 都算「已掃描」
return (
status === 'pending' ||
status === 'checked' ||
status === 'partially_completed' ||
status === 'PARTIALLY_COMPLETE'
);
}
// 有 lot:維持原規則
return (
status === 'checked' ||
status === 'partially_completed' ||
status === 'PARTIALLY_COMPLETE'
);
}).length;
}, [combinedLotData]);
// 先定义 filteredByFloor 和 availableFloors
@@ -2495,17 +2544,10 @@ const sortedData = [...sourceData].sort((a, b) => {
<TableCell>{lot.itemCode}</TableCell>
<TableCell>{lot.itemName+'('+lot.uomDesc+')'}</TableCell>
<TableCell>
<Box>
<Typography
sx={{
// color: lot.lotAvailability === 'rejected' ? 'text.disabled' : 'inherit',
//opacity: lot.lotAvailability === 'rejected' ? 0.6 : 1
}}
>
{lot.lotNo}
</Typography>
</Box>
</TableCell>
{lot.noLot === true || !lot.lotId
? t("Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.") // i18n key,下一步加文案
: (lot.lotNo || '-')}
</TableCell>
<TableCell align="right">
{(() => {
const requiredQty = lot.requiredQty || 0;
@@ -2589,6 +2631,7 @@ const sortedData = [...sourceData].sort((a, b) => {
// 正常 lot:显示按钮
return (
<Stack direction="row" spacing={1} alignItems="center">
<Button
variant="contained"
@@ -2621,7 +2664,7 @@ const sortedData = [...sourceData].sort((a, b) => {
size="small"
onClick={() => handlePickExecutionForm(lot)}
disabled={
lot.stockOutLineStatus === 'completed'
lot.stockOutLineStatus === 'completed' || lot.noLot === true || !lot.lotId
}
sx={{
fontSize: '0.7rem',
@@ -2649,7 +2692,7 @@ const sortedData = [...sourceData].sort((a, b) => {
}
await handleSubmitPickQtyWithQty(lot, lot.requiredQty || lot.pickOrderLineRequiredQty || 0);
}}
disabled={lot.stockOutLineStatus === 'completed'}
disabled={lot.stockOutLineStatus === 'completed' || lot.noLot === true || !lot.lotId}
sx={{ fontSize: '0.7rem', py: 0.5, minHeight: '28px', minWidth: '90px' }}
>
{t("Just Complete")}


+ 4
- 3
src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx Переглянути файл

@@ -185,8 +185,9 @@ const getStockAvailable = (line: JobOrderLineInfo) => {
const handleOpenPlanStartDialog = useCallback(() => {
// 将 processData.date 转换为 dayjs 对象
if (processData?.date) {
// processData.date 可能是字符串或 Date 对象
setPlanStartDate(dayjs(processData.date));
// 只取日期部分,避免时区换算导致前一天/后一天
const dateOnly = String(processData.date).slice(0, 10);
setPlanStartDate(dayjs(dateOnly));
} else {
setPlanStartDate(dayjs());
}
@@ -372,7 +373,7 @@ const handleRelease = useCallback(async ( jobOrderId: number) => {

<Grid item xs={6}>
<TextField
value={processData?.date ? dayjs(processData.date).format(OUTPUT_DATE_FORMAT) : ""}
value={processData?.date ? String(processData.date).slice(0, 10) : ""}
label={t("Target Production Date")}
fullWidth
disabled={true}


+ 1
- 0
src/i18n/zh/jo.json Переглянути файл

@@ -10,6 +10,7 @@
"Code": "工單編號",
"Name": "成品/半成品名稱",
"Picked Qty": "已提料數量",
"Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "請檢查周圍是否有QR碼,可能是剛剛入庫或轉移入庫或轉移出庫。",
"Confirm All": "確認所有提料",
"Wait Time [minutes]": "等待時間(分鐘)",
"Job Process Status Dashboard": "儀表板 - 工單狀態",


Завантаження…
Відмінити
Зберегти