| @@ -712,9 +712,9 @@ export const fetchJobOrderLotsHierarchicalByPickOrderId = cache(async (pickOrder | |||||
| }); | }); | ||||
| // NOTE: Do NOT wrap in `cache()` because the list needs to reflect just-completed lines | // NOTE: Do NOT wrap in `cache()` because the list needs to reflect just-completed lines | ||||
| // immediately when navigating back from JobPickExecution. | // immediately when navigating back from JobPickExecution. | ||||
| export const fetchAllJoPickOrders = async (isDrink?: boolean | null, floor?: string | null) => { | |||||
| export const fetchAllJoPickOrders = async (type?: string | null, floor?: string | null) => { | |||||
| const params = new URLSearchParams(); | const params = new URLSearchParams(); | ||||
| if (isDrink !== undefined && isDrink !== null) params.set("isDrink", String(isDrink)); | |||||
| if (type) params.set("type", type); | |||||
| if (floor) params.set("floor", floor); | if (floor) params.set("floor", floor); | ||||
| const query = params.toString() ? `?${params.toString()}` : ""; | const query = params.toString() ? `?${params.toString()}` : ""; | ||||
| return serverFetchJson<AllJoPickOrderResponse[]>( | return serverFetchJson<AllJoPickOrderResponse[]>( | ||||
| @@ -775,9 +775,9 @@ export const newUpdateProductProcessLineQrscan = cache(async (request: NewProduc | |||||
| } | } | ||||
| ); | ); | ||||
| }); | }); | ||||
| export const fetchAllJoborderProductProcessInfo = cache(async (isDrink?: boolean | null) => { | |||||
| const query = isDrink !== undefined && isDrink !== null | |||||
| ? `?isDrink=${isDrink}` | |||||
| export const fetchAllJoborderProductProcessInfo = cache(async (type?: string | null) => { | |||||
| const query = type | |||||
| ? `?type=${encodeURIComponent(type)}` | |||||
| : ""; | : ""; | ||||
| return serverFetchJson<AllJoborderProductProcessInfoResponse[]>( | return serverFetchJson<AllJoborderProductProcessInfoResponse[]>( | ||||
| @@ -796,7 +796,7 @@ export const fetchJoborderProductProcessesPage = cache(async (params: { | |||||
| jobOrderCode?: string | null; | jobOrderCode?: string | null; | ||||
| bomIds?: number[] | null; | bomIds?: number[] | null; | ||||
| qcReady?: boolean | null; | qcReady?: boolean | null; | ||||
| isDrink?: boolean | null; | |||||
| type?: string | null; | |||||
| page?: number; | page?: number; | ||||
| size?: number; | size?: number; | ||||
| }) => { | }) => { | ||||
| @@ -806,7 +806,7 @@ export const fetchJoborderProductProcessesPage = cache(async (params: { | |||||
| jobOrderCode, | jobOrderCode, | ||||
| bomIds, | bomIds, | ||||
| qcReady, | qcReady, | ||||
| isDrink, | |||||
| type, | |||||
| page = 0, | page = 0, | ||||
| size = 50, | size = 50, | ||||
| } = params; | } = params; | ||||
| @@ -819,7 +819,7 @@ export const fetchJoborderProductProcessesPage = cache(async (params: { | |||||
| if (jobOrderCode) queryParts.push(`jobOrderCode=${encodeURIComponent(jobOrderCode)}`); | if (jobOrderCode) queryParts.push(`jobOrderCode=${encodeURIComponent(jobOrderCode)}`); | ||||
| if (bomIds && bomIds.length > 0) queryParts.push(`bomIds=${bomIds.join(",")}`); | if (bomIds && bomIds.length > 0) queryParts.push(`bomIds=${bomIds.join(",")}`); | ||||
| if (qcReady !== undefined && qcReady !== null) queryParts.push(`qcReady=${qcReady}`); | if (qcReady !== undefined && qcReady !== null) queryParts.push(`qcReady=${qcReady}`); | ||||
| if (isDrink !== undefined && isDrink !== null) queryParts.push(`isDrink=${isDrink}`); | |||||
| if (type) queryParts.push(`type=${encodeURIComponent(type)}`); | |||||
| queryParts.push(`page=${page}`); | queryParts.push(`page=${page}`); | ||||
| queryParts.push(`size=${size}`); | queryParts.push(`size=${size}`); | ||||
| @@ -25,17 +25,16 @@ const JoPickOrderList: React.FC<Props> = ({ onSwitchToRecordTab }) =>{ | |||||
| const [pickOrders, setPickOrders] = useState<AllJoPickOrderResponse[]>([]); | const [pickOrders, setPickOrders] = useState<AllJoPickOrderResponse[]>([]); | ||||
| const [selectedPickOrderId, setSelectedPickOrderId] = useState<number | undefined>(undefined); | const [selectedPickOrderId, setSelectedPickOrderId] = useState<number | undefined>(undefined); | ||||
| const [selectedJobOrderId, setSelectedJobOrderId] = useState<number | undefined>(undefined); | const [selectedJobOrderId, setSelectedJobOrderId] = useState<number | undefined>(undefined); | ||||
| type PickOrderFilter = "all" | "drink" | "other"; | |||||
| type PickOrderFilter = "all" | "drink" | "Powder_Mixture" | "other"; | |||||
| const [filter, setFilter] = useState<PickOrderFilter>("all"); | const [filter, setFilter] = useState<PickOrderFilter>("all"); | ||||
| type FloorFilter = "ALL" | "2F" | "3F" | "4F" | "NO_LOT"; | type FloorFilter = "ALL" | "2F" | "3F" | "4F" | "NO_LOT"; | ||||
| const [floorFilter, setFloorFilter] = useState<FloorFilter>("ALL"); | const [floorFilter, setFloorFilter] = useState<FloorFilter>("ALL"); | ||||
| const fetchPickOrders = useCallback(async () => { | const fetchPickOrders = useCallback(async () => { | ||||
| setLoading(true); | setLoading(true); | ||||
| try { | try { | ||||
| const isDrinkParam = | |||||
| filter === "all" ? undefined : filter === "drink" ? true : false; | |||||
| const typeParam = filter === "all" ? undefined : filter; | |||||
| const floorParam = floorFilter === "ALL" ? undefined : floorFilter; | const floorParam = floorFilter === "ALL" ? undefined : floorFilter; | ||||
| const data = await fetchAllJoPickOrders(isDrinkParam, floorParam); | |||||
| const data = await fetchAllJoPickOrders(typeParam, floorParam); | |||||
| setPickOrders(Array.isArray(data) ? data : []); | setPickOrders(Array.isArray(data) ? data : []); | ||||
| } catch (e) { | } catch (e) { | ||||
| console.error(e); | console.error(e); | ||||
| @@ -99,6 +98,13 @@ const JoPickOrderList: React.FC<Props> = ({ onSwitchToRecordTab }) =>{ | |||||
| > | > | ||||
| {t("Drink")} | {t("Drink")} | ||||
| </Button> | </Button> | ||||
| <Button | |||||
| variant={filter === 'Powder_Mixture' ? 'contained' : 'outlined'} | |||||
| size="small" | |||||
| onClick={() => setFilter('Powder_Mixture')} | |||||
| > | |||||
| {t("Powder Mixture")} | |||||
| </Button> | |||||
| <Button | <Button | ||||
| variant={filter === 'other' ? 'contained' : 'outlined'} | variant={filter === 'other' ? 'contained' : 'outlined'} | ||||
| size="small" | size="small" | ||||
| @@ -50,7 +50,7 @@ export type ProductionProcessListPersistedState = { | |||||
| date: string; | date: string; | ||||
| itemCode: string | null; | itemCode: string | null; | ||||
| jobOrderCode: string | null; | jobOrderCode: string | null; | ||||
| filter: "all" | "drink" | "other"; | |||||
| filter: "all" | "drink" | "Powder_Mixture" | "other"; | |||||
| page: number; | page: number; | ||||
| selectedItemCodes: string[]; | selectedItemCodes: string[]; | ||||
| }; | }; | ||||
| @@ -107,7 +107,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ | |||||
| const abilities = session?.abilities ?? session?.user?.abilities ?? []; | const abilities = session?.abilities ?? session?.user?.abilities ?? []; | ||||
| // 依照 DB `authority.authority = 'ADMIN'` 的逻辑:僅 abilities 明確包含 ADMIN 才能操作 | // 依照 DB `authority.authority = 'ADMIN'` 的逻辑:僅 abilities 明確包含 ADMIN 才能操作 | ||||
| const canManageUpdateJo = abilities.some((a) => a.trim() === AUTH.ADMIN); | const canManageUpdateJo = abilities.some((a) => a.trim() === AUTH.ADMIN); | ||||
| type ProcessFilter = "all" | "drink" | "other"; | |||||
| type ProcessFilter = "all" | "drink" | "Powder_Mixture" | "other"; | |||||
| const [suggestedLocationCode, setSuggestedLocationCode] = useState<string | null>(null); | const [suggestedLocationCode, setSuggestedLocationCode] = useState<string | null>(null); | ||||
| const appliedSearch = useMemo( | const appliedSearch = useMemo( | ||||
| @@ -251,15 +251,14 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ | |||||
| const fetchProcesses = useCallback(async () => { | const fetchProcesses = useCallback(async () => { | ||||
| setLoading(true); | setLoading(true); | ||||
| try { | try { | ||||
| const isDrinkParam = | |||||
| filter === "all" ? undefined : filter === "drink" ? true : false; | |||||
| const typeParam = filter === "all" ? undefined : filter; | |||||
| const data = await fetchJoborderProductProcessesPage({ | const data = await fetchJoborderProductProcessesPage({ | ||||
| date: appliedSearch.date, | date: appliedSearch.date, | ||||
| itemCode: appliedSearch.itemCode, | itemCode: appliedSearch.itemCode, | ||||
| jobOrderCode: appliedSearch.jobOrderCode, | jobOrderCode: appliedSearch.jobOrderCode, | ||||
| qcReady, | qcReady, | ||||
| isDrink: isDrinkParam, | |||||
| type: typeParam, | |||||
| page, | page, | ||||
| size: PAGE_SIZE, | size: PAGE_SIZE, | ||||
| }); | }); | ||||
| @@ -389,7 +388,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ | |||||
| type: "select", | type: "select", | ||||
| label: "Type", | label: "Type", | ||||
| paramName: "processType", | paramName: "processType", | ||||
| options: ["all", "drink", "other"], | |||||
| options: ["all", "drink", "Powder_Mixture", "other"], | |||||
| preFilledValue: filter, | preFilledValue: filter, | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| @@ -430,6 +430,8 @@ | |||||
| "District Reference": "區域參考", | "District Reference": "區域參考", | ||||
| "Store ID": "樓層", | "Store ID": "樓層", | ||||
| "Remark": "備註", | "Remark": "備註", | ||||
| "Powder_Mixture": "箱料粉", | |||||
| "Powder Mixture": "箱料粉", | |||||
| "Not Match": "數值不符", | "Not Match": "數值不符", | ||||
| "Pass": "通過", | "Pass": "通過", | ||||
| "pass": "通過", | "pass": "通過", | ||||
| @@ -26,6 +26,8 @@ | |||||
| "UoM": "銷售單位", | "UoM": "銷售單位", | ||||
| "Select Another Bag Lot":"選擇另一個包裝袋", | "Select Another Bag Lot":"選擇另一個包裝袋", | ||||
| "No": "沒有", | "No": "沒有", | ||||
| "Powder Mixture": "箱料粉", | |||||
| "Powder_Mixture": "箱料粉", | |||||
| "Qty will submit": "提交數量", | "Qty will submit": "提交數量", | ||||
| "Packaging":"提料中", | "Packaging":"提料中", | ||||
| "Overall Time Remaining": "總剩餘時間", | "Overall Time Remaining": "總剩餘時間", | ||||
| @@ -464,5 +464,6 @@ | |||||
| "is unavable. Please check around have available QR code or not.": "此批號不可用,請檢查周圍是否有可用的 QR 碼。", | "is unavable. Please check around have available QR code or not.": "此批號不可用,請檢查周圍是否有可用的 QR 碼。", | ||||
| "Lot switch failed; pick line was not marked as checked.": "換批失敗;揀貨行未標為已核對。", | "Lot switch failed; pick line was not marked as checked.": "換批失敗;揀貨行未標為已核對。", | ||||
| "Lot confirmation failed. Please try again.": "確認批號失敗,請重試。", | "Lot confirmation failed. Please try again.": "確認批號失敗,請重試。", | ||||
| "Powder Mixture": "箱料粉", | |||||
| "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.": "批號狀態為「不可用」,無法換批或綁定;揀貨行未更新。" | ||||
| } | } | ||||