|
|
|
@@ -63,6 +63,7 @@ interface ProductProcessListProps { |
|
|
|
includePutaway?: boolean | null; |
|
|
|
/** all | completed | notCompleted */ |
|
|
|
putawayStatus?: string | null; |
|
|
|
disableDateFilter?: boolean; |
|
|
|
listPersistedState: ProductionProcessListPersistedState; |
|
|
|
onListPersistedStateChange: React.Dispatch< |
|
|
|
React.SetStateAction<ProductionProcessListPersistedState> |
|
|
|
@@ -98,6 +99,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
qcReady, |
|
|
|
includePutaway, |
|
|
|
putawayStatus, |
|
|
|
disableDateFilter = false, |
|
|
|
listPersistedState, |
|
|
|
onListPersistedStateChange, |
|
|
|
}) => { |
|
|
|
@@ -225,33 +227,30 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
const handleApplySearch = useCallback( |
|
|
|
(inputs: Record<SearchParam | `${SearchParam}To`, string>) => { |
|
|
|
const selectedProcessType = (inputs.processType || "all") as ProcessFilter; |
|
|
|
const fallback = defaultPlanStartRange(); |
|
|
|
const selectedDate = (inputs.date || "").trim() || fallback.from; |
|
|
|
onListPersistedStateChange((prev) => ({ |
|
|
|
...prev, |
|
|
|
filter: selectedProcessType, |
|
|
|
date: selectedDate, |
|
|
|
date: disableDateFilter ? "" : (inputs.date || "").trim(), |
|
|
|
itemCode: inputs.itemCode?.trim() ? inputs.itemCode.trim() : null, |
|
|
|
jobOrderCode: inputs.jobOrderCode?.trim() ? inputs.jobOrderCode.trim() : null, |
|
|
|
selectedItemCodes: [], |
|
|
|
page: 0, |
|
|
|
})); |
|
|
|
}, |
|
|
|
[onListPersistedStateChange], |
|
|
|
[disableDateFilter, onListPersistedStateChange], |
|
|
|
); |
|
|
|
|
|
|
|
const handleResetSearch = useCallback(() => { |
|
|
|
const r = defaultPlanStartRange(); |
|
|
|
onListPersistedStateChange((prev) => ({ |
|
|
|
...prev, |
|
|
|
filter: "all", |
|
|
|
date: r.from, |
|
|
|
date: disableDateFilter ? "" : defaultPlanStartRange().from, |
|
|
|
itemCode: null, |
|
|
|
jobOrderCode: null, |
|
|
|
selectedItemCodes: [], |
|
|
|
page: 0, |
|
|
|
})); |
|
|
|
}, [onListPersistedStateChange]); |
|
|
|
}, [disableDateFilter, onListPersistedStateChange]); |
|
|
|
|
|
|
|
const fetchProcesses = useCallback(async () => { |
|
|
|
setLoading(true); |
|
|
|
@@ -259,7 +258,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
const typeParam = filter === "all" ? undefined : filter; |
|
|
|
|
|
|
|
const data = await fetchJoborderProductProcessesPage({ |
|
|
|
date: appliedSearch.date, |
|
|
|
date: disableDateFilter ? undefined : appliedSearch.date, |
|
|
|
itemCode: appliedSearch.itemCode, |
|
|
|
jobOrderCode: appliedSearch.jobOrderCode, |
|
|
|
qcReady, |
|
|
|
@@ -279,7 +278,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
} finally { |
|
|
|
setLoading(false); |
|
|
|
} |
|
|
|
}, [listPersistedState, qcReady, includePutaway, putawayStatus]); |
|
|
|
}, [appliedSearch, disableDateFilter, filter, qcReady, includePutaway, putawayStatus, page]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
fetchProcesses(); |
|
|
|
@@ -370,15 +369,16 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
|
|
|
|
/** Reset 用 ±3 天;preFilled 用目前已套用的條件(與列表查詢一致) */ |
|
|
|
const searchCriteria: Criterion<SearchParam>[] = useMemo(() => { |
|
|
|
const r = defaultPlanStartRange(); |
|
|
|
return [ |
|
|
|
{ |
|
|
|
const base: Criterion<SearchParam>[] = [ |
|
|
|
...(disableDateFilter |
|
|
|
? [] |
|
|
|
: [{ |
|
|
|
type: "date", |
|
|
|
label: t("Search date"), |
|
|
|
paramName: "date", |
|
|
|
defaultValue: appliedSearch.date, |
|
|
|
preFilledValue: appliedSearch.date, |
|
|
|
}, |
|
|
|
} as Criterion<SearchParam>]), |
|
|
|
{ |
|
|
|
type: "text", |
|
|
|
label: "Item Code", |
|
|
|
@@ -399,18 +399,19 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
preFilledValue: filter, |
|
|
|
}, |
|
|
|
]; |
|
|
|
}, [appliedSearch, filter, t]); |
|
|
|
return base; |
|
|
|
}, [appliedSearch, disableDateFilter, filter, t]); |
|
|
|
|
|
|
|
/** SearchBox 內部 state 只在掛載時讀 preFilled;套用搜尋後需 remount 才會與 appliedSearch 一致 */ |
|
|
|
const searchBoxKey = useMemo( |
|
|
|
() => |
|
|
|
[ |
|
|
|
appliedSearch.date, |
|
|
|
disableDateFilter ? "" : appliedSearch.date, |
|
|
|
appliedSearch.itemCode ?? "", |
|
|
|
appliedSearch.jobOrderCode ?? "", |
|
|
|
filter, |
|
|
|
].join("|"), |
|
|
|
[appliedSearch, filter], |
|
|
|
[appliedSearch, disableDateFilter, filter], |
|
|
|
); |
|
|
|
|
|
|
|
const handleSelectedItemCodesChange = useCallback( |
|
|
|
@@ -458,14 +459,18 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ |
|
|
|
} |
|
|
|
/> |
|
|
|
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}> |
|
|
|
{t("Search date") /* 或在 zh/common.json 加鍵,例如「搜尋日期」 */}:{" "} |
|
|
|
{appliedSearch.date && dayjs(appliedSearch.date).isValid() |
|
|
|
? dayjs(appliedSearch.date).format(OUTPUT_DATE_FORMAT) |
|
|
|
: "-"} |
|
|
|
{" | "} |
|
|
|
{t("Total job orders")}: {totalJobOrders} |
|
|
|
{selectedItemCodes.length > 0 ? ` | ${t("Filtered")}: ${paged.length}` : ""} |
|
|
|
</Typography> |
|
|
|
{!disableDateFilter && ( |
|
|
|
<> |
|
|
|
{t("Search date")}:{" "} |
|
|
|
{appliedSearch.date && dayjs(appliedSearch.date).isValid() |
|
|
|
? dayjs(appliedSearch.date).format(OUTPUT_DATE_FORMAT) |
|
|
|
: "-"} |
|
|
|
{" | "} |
|
|
|
</> |
|
|
|
)} |
|
|
|
{t("Total job orders")}: {totalJobOrders} |
|
|
|
{selectedItemCodes.length > 0 ? ` | ${t("Filtered")}: ${paged.length}` : ""} |
|
|
|
</Typography> |
|
|
|
|
|
|
|
<Grid container spacing={2}> |
|
|
|
{paged.map((process) => { |
|
|
|
|