| @@ -352,6 +352,8 @@ export interface AllJoborderProductProcessInfoResponse { | |||||
| uom: string; | uom: string; | ||||
| isDrink?: boolean | null; | isDrink?: boolean | null; | ||||
| stockInLineId: number; | stockInLineId: number; | ||||
| /** Stock-in-line current status (e.g. receiving/received/partially_completed/completed/rejected). */ | |||||
| stockInLineStatus?: string | null; | |||||
| jobOrderCode: string; | jobOrderCode: string; | ||||
| productProcessLineCount: number; | productProcessLineCount: number; | ||||
| FinishedProductProcessLineCount: number; | FinishedProductProcessLineCount: number; | ||||
| @@ -798,6 +800,8 @@ export const fetchJoborderProductProcessesPage = cache(async (params: { | |||||
| qcReady?: boolean | null; | qcReady?: boolean | null; | ||||
| type?: string | null; | type?: string | null; | ||||
| includePutaway?: boolean | null; | includePutaway?: boolean | null; | ||||
| /** all | completed | notCompleted */ | |||||
| putawayStatus?: string | null; | |||||
| page?: number; | page?: number; | ||||
| size?: number; | size?: number; | ||||
| }) => { | }) => { | ||||
| @@ -808,6 +812,7 @@ export const fetchJoborderProductProcessesPage = cache(async (params: { | |||||
| bomIds, | bomIds, | ||||
| qcReady, | qcReady, | ||||
| includePutaway, | includePutaway, | ||||
| putawayStatus, | |||||
| type, | type, | ||||
| page = 0, | page = 0, | ||||
| size = 50, | size = 50, | ||||
| @@ -825,6 +830,7 @@ export const fetchJoborderProductProcessesPage = cache(async (params: { | |||||
| if (includePutaway !== undefined && includePutaway !== null) { | if (includePutaway !== undefined && includePutaway !== null) { | ||||
| queryParts.push(`includePutaway=${includePutaway}`); | queryParts.push(`includePutaway=${includePutaway}`); | ||||
| } | } | ||||
| if (putawayStatus) queryParts.push(`putawayStatus=${encodeURIComponent(putawayStatus)}`); | |||||
| queryParts.push(`page=${page}`); | queryParts.push(`page=${page}`); | ||||
| queryParts.push(`size=${size}`); | queryParts.push(`size=${size}`); | ||||
| @@ -60,6 +60,9 @@ interface ProductProcessListProps { | |||||
| onSelectMatchingStock: (jobOrderId: number|undefined, productProcessId: number|undefined,pickOrderId: number|undefined) => void; | onSelectMatchingStock: (jobOrderId: number|undefined, productProcessId: number|undefined,pickOrderId: number|undefined) => void; | ||||
| printerCombo: PrinterCombo[]; | printerCombo: PrinterCombo[]; | ||||
| qcReady: boolean; | qcReady: boolean; | ||||
| includePutaway?: boolean | null; | |||||
| /** all | completed | notCompleted */ | |||||
| putawayStatus?: string | null; | |||||
| listPersistedState: ProductionProcessListPersistedState; | listPersistedState: ProductionProcessListPersistedState; | ||||
| onListPersistedStateChange: React.Dispatch< | onListPersistedStateChange: React.Dispatch< | ||||
| React.SetStateAction<ProductionProcessListPersistedState> | React.SetStateAction<ProductionProcessListPersistedState> | ||||
| @@ -93,6 +96,8 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ | |||||
| printerCombo, | printerCombo, | ||||
| onSelectMatchingStock, | onSelectMatchingStock, | ||||
| qcReady, | qcReady, | ||||
| includePutaway, | |||||
| putawayStatus, | |||||
| listPersistedState, | listPersistedState, | ||||
| onListPersistedStateChange, | onListPersistedStateChange, | ||||
| }) => { | }) => { | ||||
| @@ -258,7 +263,8 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ | |||||
| itemCode: appliedSearch.itemCode, | itemCode: appliedSearch.itemCode, | ||||
| jobOrderCode: appliedSearch.jobOrderCode, | jobOrderCode: appliedSearch.jobOrderCode, | ||||
| qcReady, | qcReady, | ||||
| includePutaway: qcReady ? true : null, | |||||
| includePutaway: includePutaway ?? (qcReady ? true : null), | |||||
| putawayStatus, | |||||
| type: typeParam, | type: typeParam, | ||||
| page, | page, | ||||
| size: PAGE_SIZE, | size: PAGE_SIZE, | ||||
| @@ -273,7 +279,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ | |||||
| } finally { | } finally { | ||||
| setLoading(false); | setLoading(false); | ||||
| } | } | ||||
| }, [listPersistedState, qcReady]); | |||||
| }, [listPersistedState, qcReady, includePutaway, putawayStatus]); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| fetchProcesses(); | fetchProcesses(); | ||||
| @@ -36,7 +36,10 @@ const ProductionProcessPage: React.FC<ProductionProcessPageProps> = ({ printerCo | |||||
| const [productionListState, setProductionListState] = useState( | const [productionListState, setProductionListState] = useState( | ||||
| createDefaultProductionProcessListPersistedState, | createDefaultProductionProcessListPersistedState, | ||||
| ); | ); | ||||
| const [finishedQcListState, setFinishedQcListState] = useState( | |||||
| const [waitingPutawayListState, setWaitingPutawayListState] = useState( | |||||
| createDefaultProductionProcessListPersistedState, | |||||
| ); | |||||
| const [putawayedListState, setPutawayedListState] = useState( | |||||
| createDefaultProductionProcessListPersistedState, | createDefaultProductionProcessListPersistedState, | ||||
| ); | ); | ||||
| const { data: session } = useSession() as { data: SessionWithTokens | null }; | const { data: session } = useSession() as { data: SessionWithTokens | null }; | ||||
| @@ -199,7 +202,8 @@ const ProductionProcessPage: React.FC<ProductionProcessPageProps> = ({ printerCo | |||||
| <Tabs value={tabIndex} onChange={handleTabChange} sx={{ mb: 2 }}> | <Tabs value={tabIndex} onChange={handleTabChange} sx={{ mb: 2 }}> | ||||
| <Tab label={t("Production Process")} /> | <Tab label={t("Production Process")} /> | ||||
| <Tab label={t("Finished QC Job Orders")} /> | |||||
| <Tab label={t("Waiting QC Put Away Job Orders")} /> | |||||
| <Tab label={t("Put Awayed Job Orders")} /> | |||||
| <Tab label={t("Job Process Status Dashboard")} /> | <Tab label={t("Job Process Status Dashboard")} /> | ||||
| <Tab label={t("Operator KPI Dashboard")} /> | <Tab label={t("Operator KPI Dashboard")} /> | ||||
| <Tab label={t("Production Equipment Status Dashboard")} /> | <Tab label={t("Production Equipment Status Dashboard")} /> | ||||
| @@ -231,8 +235,10 @@ const ProductionProcessPage: React.FC<ProductionProcessPageProps> = ({ printerCo | |||||
| <ProductionProcessList | <ProductionProcessList | ||||
| printerCombo={printerCombo} | printerCombo={printerCombo} | ||||
| qcReady={true} | qcReady={true} | ||||
| listPersistedState={finishedQcListState} | |||||
| onListPersistedStateChange={setFinishedQcListState} | |||||
| includePutaway={true} | |||||
| putawayStatus="notCompleted" | |||||
| listPersistedState={waitingPutawayListState} | |||||
| onListPersistedStateChange={setWaitingPutawayListState} | |||||
| onSelectProcess={(jobOrderId) => { | onSelectProcess={(jobOrderId) => { | ||||
| const id = jobOrderId ?? null; | const id = jobOrderId ?? null; | ||||
| if (id !== null) { | if (id !== null) { | ||||
| @@ -248,13 +254,36 @@ const ProductionProcessPage: React.FC<ProductionProcessPageProps> = ({ printerCo | |||||
| }} | }} | ||||
| /> | /> | ||||
| )} | )} | ||||
| {tabIndex === 2 && ( | |||||
| <JobProcessStatus /> | |||||
| {tabIndex === 2 && ( | |||||
| <ProductionProcessList | |||||
| printerCombo={printerCombo} | |||||
| qcReady={true} | |||||
| includePutaway={true} | |||||
| putawayStatus="completed" | |||||
| listPersistedState={putawayedListState} | |||||
| onListPersistedStateChange={setPutawayedListState} | |||||
| onSelectProcess={(jobOrderId) => { | |||||
| const id = jobOrderId ?? null; | |||||
| if (id !== null) { | |||||
| setSelectedProcessId(id); | |||||
| } | |||||
| }} | |||||
| onSelectMatchingStock={(jobOrderId, productProcessId, pickOrderId) => { | |||||
| setSelectedMatchingStock({ | |||||
| jobOrderId: jobOrderId || 0, | |||||
| productProcessId: productProcessId || 0, | |||||
| pickOrderId: pickOrderId || 0, | |||||
| }); | |||||
| }} | |||||
| /> | |||||
| )} | )} | ||||
| {tabIndex === 3 && ( | {tabIndex === 3 && ( | ||||
| <OperatorKpiDashboard /> | |||||
| <JobProcessStatus /> | |||||
| )} | )} | ||||
| {tabIndex === 4 && ( | {tabIndex === 4 && ( | ||||
| <OperatorKpiDashboard /> | |||||
| )} | |||||
| {tabIndex === 5 && ( | |||||
| <EquipmentStatusDashboard /> | <EquipmentStatusDashboard /> | ||||
| )} | )} | ||||
| </Box> | </Box> | ||||
| @@ -128,6 +128,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| ...defaultNewValue, | ...defaultNewValue, | ||||
| }, | }, | ||||
| }); | }); | ||||
| const { isSubmitting } = formProps.formState; | |||||
| const errors = formProps.formState.errors; | const errors = formProps.formState.errors; | ||||
| useEffect(() => { | useEffect(() => { | ||||
| @@ -646,7 +647,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| }, | }, | ||||
| }} | }} | ||||
| // onClick={formProps.handleSubmit()} | // onClick={formProps.handleSubmit()} | ||||
| disabled={!verified || qtyError != ""} | |||||
| disabled={!verified || qtyError != "" || isSubmitting} | |||||
| > | > | ||||
| {t("confirm putaway")} | {t("confirm putaway")} | ||||
| </Button> | </Button> | ||||
| @@ -12,6 +12,8 @@ | |||||
| "Please Select BOM": "請選擇 BOM", | "Please Select BOM": "請選擇 BOM", | ||||
| "No Lot": "沒有批號", | "No Lot": "沒有批號", | ||||
| "Select All": "全選", | "Select All": "全選", | ||||
| "Waiting QC Put Away Job Orders": "待QC上架工單", | |||||
| "Put Awayed Job Orders": "已上架工單", | |||||
| "Loading BOM Detail...": "正在載入 BOM 明細…", | "Loading BOM Detail...": "正在載入 BOM 明細…", | ||||
| "Output Quantity": "使用數量", | "Output Quantity": "使用數量", | ||||
| "Process & Equipment": "製程與設備", | "Process & Equipment": "製程與設備", | ||||