Procházet zdrojové kódy

productprocess

MergeProblem1
CANCERYS\kw093 před 2 týdny
rodič
revize
770d569f9b
6 změnil soubory, kde provedl 132 přidání a 40 odebrání
  1. +26
    -5
      src/app/api/jo/actions.ts
  2. +2
    -0
      src/app/api/stockIn/index.ts
  3. +1
    -1
      src/components/ProductionProcess/JobProcessStatus.tsx
  4. +28
    -2
      src/components/ProductionProcess/ProductionProcessDetail.tsx
  5. +74
    -31
      src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx
  6. +1
    -1
      src/components/Qc/QcStockInModal.tsx

+ 26
- 5
src/app/api/jo/actions.ts Zobrazit soubor

@@ -246,6 +246,7 @@ export interface ProductProcessLineResponse {
postProdTimeInMinutes: number,
startTime: string,
endTime: string,
isOringinal: boolean,
}

export interface ProductProcessWithLinesResponse {
@@ -454,18 +455,29 @@ export interface JobOrderProcessLineDetailResponse {
}
export interface JobOrderLineInfo {
id: number,
jobOrderId: number,
jobOrderCode: string,
itemId: number,
itemCode: string,
itemName: string,
type: string,

reqQty: number,
baseReqQty: number,
stockReqQty: number,

stockQty: number,
uom: string,
shortUom: string,
baseStockQty: number,

reqUom: string,
reqBaseUom: string,

stockUom: string,
stockBaseUom: string,
availableStatus: string,
bomProcessId: number,
bomProcessSeqNo: number,
isOringinal: boolean

}
export interface ProductProcessLineInfoResponse {
@@ -1208,6 +1220,7 @@ export interface JobProcessStatusResponse {
jobOrderCode: string;
itemCode: string;
itemName: string;
status: string;
processingTime: number | null;
setupTime: number | null;
changeoverTime: number | null;
@@ -1225,5 +1238,13 @@ export const fetchJobProcessStatus = cache(async () => {
}
);
});

export const deleteProductProcessLine = async (lineId: number) => {
return serverFetchJson<any>(
`${BASE_API_URL}/product-process/Demo/ProcessLine/delete/${lineId}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
}
);
};
;

+ 2
- 0
src/app/api/stockIn/index.ts Zobrazit soubor

@@ -124,6 +124,8 @@ export interface StockInLine {
lotNo?: string;
poCode?: string;
uom?: Uom;
joCode?: string;
warehouseCode?: string;
defaultWarehouseId: number; // id for now
dnNo?: string;
dnDate?: number[];


+ 1
- 1
src/components/ProductionProcess/JobProcessStatus.tsx Zobrazit soubor

@@ -263,7 +263,7 @@ const JobProcessStatus: React.FC = () => {
</TableCell>
<TableCell>

{calculateRemainingTime(row.planEndTime, row.processingTime, row.setupTime, row.changeoverTime)}
{row.status === 'pending' ? '-' : calculateRemainingTime(row.planEndTime, row.processingTime, row.setupTime, row.changeoverTime)}
</TableCell>
{row.processes.map((process, index) => {
const isLastProcess = index === row.processes.length - 1 ||


+ 28
- 2
src/components/ProductionProcess/ProductionProcessDetail.tsx Zobrazit soubor

@@ -2,6 +2,7 @@
import React, { useCallback, useEffect, useState, useRef } from "react";
import EditIcon from "@mui/icons-material/Edit";
import AddIcon from '@mui/icons-material/Add';
import DeleteIcon from '@mui/icons-material/Delete';
import Fab from '@mui/material/Fab';
import {
Box,
@@ -50,6 +51,7 @@ import {
newProductProcessLine,
updateProductProcessLineProcessingTimeSetupTimeChangeoverTime,
UpdateProductProcessLineProcessingTimeSetupTimeChangeoverTimeRequest,
deleteProductProcessLine,
} from "@/app/api/jo/actions";
import { updateProductProcessLineStatus } from "@/app/api/jo/actions";

@@ -265,7 +267,19 @@ const fetchProcessDetailRef = useRef<() => Promise<void>>();
alert(t("Failed to create new line. Please try again."));
}
}, [fetchProcessDetail, t]);
// 提交产出数据
const handleDeleteLine = useCallback(async (lineId: number) => {
if (!confirm(t("Are you sure you want to delete this process?"))) {
return;
}
try {
await deleteProductProcessLine(lineId);
// 刷新数据
await fetchProcessDetail();
} catch (error) {
console.error("Error deleting line:", error);
alert(t("Failed to delete line. Please try again."));
}
}, [fetchProcessDetail, t]);
const processQrCode = useCallback((qrValue: string, lineId: number) => {
// 设备快捷格式:{2fitesteXXX} - XXX 直接作为设备代码
// 格式:{2fitesteXXX} = equipmentCode: "XXX"
@@ -614,7 +628,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => {
const status = (line as any).status || '';
const statusLower = status.toLowerCase();
const equipmentName = line.equipment_name || "-";
const isPlanning = processData?.jobOrderStatus === "planning";
const isCompleted = statusLower === 'completed';
const isInProgress = statusLower === 'inprogress' || statusLower === 'in progress';
const isPaused = statusLower === 'paused';
@@ -624,6 +638,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => {
return (
<TableRow key={line.id}>
<TableCell>
{isPlanning && (
<Fab
size="small"
color="primary"
@@ -639,6 +654,17 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => {
>
<AddIcon fontSize="small" />
</Fab>
)}
{isPlanning && line.isOringinal !== true && (
<IconButton
size="small"
color="error"
onClick={() => handleDeleteLine(line.id)}
sx={{ padding: 0.5 }}
>
<DeleteIcon fontSize="small" />
</IconButton>
)}
</TableCell>
<TableCell>
<Stack direction="row" spacing={1} alignItems="center">


+ 74
- 31
src/components/ProductionProcess/ProductionProcessJobOrderDetail.tsx Zobrazit soubor

@@ -23,7 +23,7 @@ import {
} from "@mui/material";
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { useTranslation } from "react-i18next";
import { fetchProductProcessesByJobOrderId ,deleteJobOrder, updateProductProcessPriority, updateJoPlanStart,updateJoReqQty,newProductProcessLine} from "@/app/api/jo/actions";
import { fetchProductProcessesByJobOrderId ,deleteJobOrder, updateProductProcessPriority, updateJoPlanStart,updateJoReqQty,newProductProcessLine,JobOrderLineInfo} from "@/app/api/jo/actions";
import ProductionProcessDetail from "./ProductionProcessDetail";
import { BomCombo } from "@/app/api/bom";
import { fetchBomCombo } from "@/app/api/bom/index";
@@ -44,20 +44,7 @@ import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { dayjsToDateString } from "@/app/utils/formatUtil";

interface JobOrderLine {
id: number;
jobOrderId: number;
jobOrderCode: string;
itemId: number;
itemCode: string;
itemName: string;
reqQty: number;
stockQty: number;
uom: string;
shortUom: string;
availableStatus: string;
type: string;
}


interface ProductProcessJobOrderDetailProps {
jobOrderId: number;
@@ -73,7 +60,7 @@ const ProductionProcessJobOrderDetail: React.FC<ProductProcessJobOrderDetailProp
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [processData, setProcessData] = useState<any>(null);
const [jobOrderLines, setJobOrderLines] = useState<JobOrderLine[]>([]);
const [jobOrderLines, setJobOrderLines] = useState<JobOrderLineInfo[]>([]);
const [inventoryData, setInventoryData] = useState<InventoryResult[]>([]);
const [tabIndex, setTabIndex] = useState(0);
const [selectedProcessId, setSelectedProcessId] = useState<number | null>(null);
@@ -85,7 +72,7 @@ const ProductionProcessJobOrderDetail: React.FC<ProductProcessJobOrderDetailProp
const [reqQtyMultiplier, setReqQtyMultiplier] = useState<number>(1);
const [selectedBomForReqQty, setSelectedBomForReqQty] = useState<BomCombo | null>(null);
const [bomCombo, setBomCombo] = useState<BomCombo[]>([]);
const [showBaseQty, setShowBaseQty] = useState<boolean>(false);
const fetchData = useCallback(async () => {
setLoading(true);
@@ -102,7 +89,9 @@ const [bomCombo, setBomCombo] = useState<BomCombo[]>([]);
setLoading(false);
}
}, [jobOrderId]);

const toggleBaseQty = useCallback(() => {
setShowBaseQty(prev => !prev);
}, []);
// 4. 添加处理函数(约第 166 行后)
const handleOpenReqQtyDialog = useCallback(async () => {
@@ -181,7 +170,7 @@ const [bomCombo, setBomCombo] = useState<BomCombo[]>([]);
fetchData();
}, [fetchData]);
// PickTable 组件内容
const getStockAvailable = (line: JobOrderLine) => {
const getStockAvailable = (line: JobOrderLineInfo) => {
if (line.type?.toLowerCase() === "consumables" || line.type?.toLowerCase() === "nm") {
return null;
}
@@ -244,7 +233,7 @@ const handleConfirmPriority = async () => {
await handleUpdateOperationPriority(processData.id, Number(operationPriority));
setOpenOperationPriorityDialog(false);
};
const isStockSufficient = (line: JobOrderLine) => {
const isStockSufficient = (line: JobOrderLineInfo) => {
if (line.type?.toLowerCase() === "consumables") {
return false;
}
@@ -489,8 +478,8 @@ const handleRelease = useCallback(async ( jobOrderId: number) => {
field: "itemName",
headerName: t("Item Name"),
flex: 1,
renderCell: (params: GridRenderCellParams<JobOrderLine>) => {
return `${params.value} (${params.row.uom})`;
renderCell: (params: GridRenderCellParams<JobOrderLineInfo>) => {
return `${params.value} (${params.row.reqUom})`;
},
},
{
@@ -499,12 +488,53 @@ const handleRelease = useCallback(async ( jobOrderId: number) => {
flex: 0.7,
align: "right",
headerAlign: "right",
renderCell: (params: GridRenderCellParams<JobOrderLine>) => {
renderCell: (params: GridRenderCellParams<JobOrderLineInfo>) => {
const qty = showBaseQty ? params.row.baseReqQty : params.value;
const uom = showBaseQty ? params.row.reqBaseUom : params.row.reqUom;
return (
<Box
onClick={toggleBaseQty}
sx={{
cursor: "pointer",
userSelect: "none",
"&:hover": {
textDecoration: "underline",
},
}}
>
{decimalFormatter.format(qty || 0)} ({uom || ""})
</Box>
);
},
},
{
field: "stockReqQty",
headerName: t("Stock Req. Qty"),
flex: 0.7,
align: "right",
headerAlign: "right",
renderCell: (params: GridRenderCellParams<JobOrderLineInfo>) => {
const qty = showBaseQty ? params.row.baseReqQty : params.value;
const uom = showBaseQty ? params.row.reqBaseUom : params.row.stockUom;
return `${decimalFormatter.format(params.value)} (${params.row.shortUom})`;
return (
<Box
onClick={toggleBaseQty}
sx={{
cursor: "pointer",
userSelect: "none",
"&:hover": {
textDecoration: "underline",
},
}}
>
{decimalFormatter.format(qty || 0)} ({uom || ""})
</Box>
);
},
},

{
field: "stockAvailable",
headerName: t("Stock Available"),
@@ -512,12 +542,25 @@ const handleRelease = useCallback(async ( jobOrderId: number) => {
align: "right",
headerAlign: "right",
type: "number",
renderCell: (params: GridRenderCellParams<JobOrderLine>) => {
// 如果是 consumables,显示 N/A
renderCell: (params: GridRenderCellParams<JobOrderLineInfo>) => {
const stockAvailable = getStockAvailable(params.row);
return `${decimalFormatter.format(stockAvailable || 0)} (${params.row.shortUom})`;
const qty = showBaseQty ? params.row.baseStockQty : (stockAvailable || 0);
const uom = showBaseQty ? params.row.stockBaseUom : params.row.stockUom;
return (
<Box
onClick={toggleBaseQty}
sx={{
cursor: "pointer",
userSelect: "none",
"&:hover": {
textDecoration: "underline",
},
}}
>
{decimalFormatter.format(qty || 0)} ({uom || ""})
</Box>
);
},
},
{
@@ -545,7 +588,7 @@ const handleRelease = useCallback(async ( jobOrderId: number) => {
align: "center",
headerAlign: "center",
type: "boolean",
renderCell: (params: GridRenderCellParams<JobOrderLine>) => {
renderCell: (params: GridRenderCellParams<JobOrderLineInfo>) => {
return isStockSufficient(params.row)
? <CheckCircleOutlineOutlinedIcon fontSize={"large"} color="success" />


+ 1
- 1
src/components/Qc/QcStockInModal.tsx Zobrazit soubor

@@ -172,7 +172,7 @@ const QcStockInModal: React.FC<Props> = ({
expiryDate: d.expiryDate ? (Array.isArray(d.expiryDate) ? arrayToDateString(d.expiryDate, "input") : d.expiryDate) : undefined,
receiptDate: d.receiptDate ? arrayToDateString(d.receiptDate, "input")
: dayjs().add(0, "month").format(INPUT_DATE_FORMAT),
acceptQty: d.status != StockInStatus.REJECTED ? (d.demandQty?? d.acceptedQty) : 0,
acceptQty: d.status != StockInStatus.REJECTED ? (d.acceptedQty ?? d.receivedQty ?? d.demandQty) : 0,
// escResult: (d.escResult && d.escResult?.length > 0) ? d.escResult : [],
// qcResult: (d.qcResult && d.qcResult?.length > 0) ? d.qcResult : [],//[...dummyQCData],
warehouseId: d.defaultWarehouseId ?? 1,


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