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