| @@ -96,9 +96,32 @@ export interface AllPickedStockTakeListReponse { | |||
| startTime: string | null; | |||
| endTime: string | null; | |||
| planStartDate: string | null; | |||
| stockTakeSectionDescription: string | null; | |||
| reStockTakeTrueFalse: boolean; | |||
| } | |||
| export const getApproverInventoryLotDetailsAll = async ( | |||
| stockTakeId?: number | null, | |||
| pageNum: number = 0, | |||
| pageSize: number = 100 | |||
| ) => { | |||
| const params = new URLSearchParams(); | |||
| params.append("pageNum", String(pageNum)); | |||
| params.append("pageSize", String(pageSize)); | |||
| if (stockTakeId != null && stockTakeId > 0) { | |||
| params.append("stockTakeId", String(stockTakeId)); | |||
| } | |||
| const url = `${BASE_API_URL}/stockTakeRecord/approverInventoryLotDetailsAll?${params.toString()}`; | |||
| const response = await serverFetchJson<RecordsRes<InventoryLotDetailResponse>>( | |||
| url, | |||
| { | |||
| method: "GET", | |||
| }, | |||
| ); | |||
| return response; | |||
| } | |||
| export const importStockTake = async (data: FormData) => { | |||
| const importStockTake = await serverFetchJson<string>( | |||
| `${BASE_API_URL}/stockTake/import`, | |||
| @@ -122,12 +145,20 @@ export const getStockTakeRecords = async () => { | |||
| } | |||
| export const getStockTakeRecordsPaged = async ( | |||
| pageNum: number, | |||
| pageSize: number | |||
| pageSize: number, | |||
| params?: { sectionDescription?: string; stockTakeSections?: string } | |||
| ) => { | |||
| const url = `${BASE_API_URL}/stockTakeRecord/AllPickedStockOutRecordList?pageNum=${pageNum}&pageSize=${pageSize}`; | |||
| const res = await serverFetchJson<RecordsRes<AllPickedStockTakeListReponse>>(url, { | |||
| method: "GET", | |||
| }); | |||
| const searchParams = new URLSearchParams(); | |||
| searchParams.set("pageNum", String(pageNum)); | |||
| searchParams.set("pageSize", String(pageSize)); | |||
| if (params?.sectionDescription && params.sectionDescription !== "All") { | |||
| searchParams.set("sectionDescription", params.sectionDescription); | |||
| } | |||
| if (params?.stockTakeSections?.trim()) { | |||
| searchParams.set("stockTakeSections", params.stockTakeSections.trim()); | |||
| } | |||
| const url = `${BASE_API_URL}/stockTakeRecord/AllPickedStockOutRecordList?${searchParams.toString()}`; | |||
| const res = await serverFetchJson<RecordsRes<AllPickedStockTakeListReponse>>(url, { method: "GET" }); | |||
| return res; | |||
| }; | |||
| export const getApproverStockTakeRecords = async () => { | |||
| @@ -228,6 +259,12 @@ export interface BatchSaveApproverStockTakeRecordResponse { | |||
| errors: string[]; | |||
| } | |||
| export interface BatchSaveApproverStockTakeAllRequest { | |||
| stockTakeId: number; | |||
| approverId: number; | |||
| variancePercentTolerance?: number | null; | |||
| } | |||
| export const saveApproverStockTakeRecord = async ( | |||
| request: SaveApproverStockTakeRecordRequest, | |||
| @@ -272,6 +309,17 @@ export const batchSaveApproverStockTakeRecords = cache(async (data: BatchSaveApp | |||
| } | |||
| ) | |||
| export const batchSaveApproverStockTakeRecordsAll = cache(async (data: BatchSaveApproverStockTakeAllRequest) => { | |||
| return serverFetchJson<BatchSaveApproverStockTakeRecordResponse>( | |||
| `${BASE_API_URL}/stockTakeRecord/batchSaveApproverStockTakeRecordsAll`, | |||
| { | |||
| method: "POST", | |||
| body: JSON.stringify(data), | |||
| headers: { "Content-Type": "application/json" }, | |||
| } | |||
| ) | |||
| }) | |||
| export const updateStockTakeRecordStatusToNotMatch = async ( | |||
| stockTakeRecordId: number | |||
| ) => { | |||
| @@ -61,22 +61,27 @@ const sectionDescriptionOptions = Array.from( | |||
| .filter((v): v is string => !!v) | |||
| ) | |||
| ); | |||
| /* | |||
| // 按 description + section 双条件过滤 | |||
| const filteredSessions = stockTakeSessions.filter((s) => { | |||
| const matchDesc = | |||
| filterSectionDescription === "All" || | |||
| s.stockTakeSectionDescription === filterSectionDescription; | |||
| const sessionParts = (filterStockTakeSession ?? "") | |||
| .split(",") | |||
| .map((p) => p.trim().toLowerCase()) | |||
| .filter(Boolean); | |||
| const matchSession = | |||
| !filterStockTakeSession || | |||
| (s.stockTakeSession ?? "") | |||
| .toString() | |||
| .toLowerCase() | |||
| .includes(filterStockTakeSession.toLowerCase()); | |||
| sessionParts.length === 0 || | |||
| sessionParts.some((part) => | |||
| (s.stockTakeSession ?? "").toString().toLowerCase().includes(part) | |||
| ); | |||
| return matchDesc && matchSession; | |||
| }); | |||
| */ | |||
| // SearchBox 的条件配置 | |||
| const criteria: Criterion<PickerSearchKey>[] = [ | |||
| @@ -88,7 +93,7 @@ const criteria: Criterion<PickerSearchKey>[] = [ | |||
| }, | |||
| { | |||
| type: "text", | |||
| label: t("Stock Take Section"), | |||
| label: t("Stock Take Section (can use , to search multiple sections)"), | |||
| paramName: "stockTakeSession", | |||
| placeholder: "", | |||
| }, | |||
| @@ -97,17 +102,24 @@ const criteria: Criterion<PickerSearchKey>[] = [ | |||
| const handleSearch = (inputs: Record<PickerSearchKey | `${PickerSearchKey}To`, string>) => { | |||
| setFilterSectionDescription(inputs.sectionDescription || "All"); | |||
| setFilterStockTakeSession(inputs.stockTakeSession || ""); | |||
| fetchStockTakeSessions(0, pageSize, { | |||
| sectionDescription: inputs.sectionDescription || "All", | |||
| stockTakeSections: inputs.stockTakeSession ?? "", | |||
| }); | |||
| }; | |||
| const handleResetSearch = () => { | |||
| setFilterSectionDescription("All"); | |||
| setFilterStockTakeSession(""); | |||
| fetchStockTakeSessions(0, pageSize, { | |||
| sectionDescription: "All", | |||
| stockTakeSections: "", | |||
| }); | |||
| }; | |||
| const fetchStockTakeSessions = useCallback( | |||
| async (pageNum: number, size: number) => { | |||
| async (pageNum: number, size: number, filterOverrides?: { sectionDescription: string; stockTakeSections: string }) => { | |||
| setLoading(true); | |||
| try { | |||
| const res = await getStockTakeRecordsPaged(pageNum, size); | |||
| const res = await getStockTakeRecordsPaged(pageNum, size, filterOverrides); | |||
| setStockTakeSessions(Array.isArray(res.records) ? res.records : []); | |||
| setTotal(res.total || 0); | |||
| setPage(pageNum); | |||
| @@ -252,7 +264,7 @@ const handleResetSearch = () => { | |||
| <Typography variant="body2" color="text.secondary"> | |||
| {t("Total Sections")}: {stockTakeSessions.length} | |||
| {t("Total Sections")}: {total} | |||
| </Typography> | |||
| <Typography variant="body2" color="text.secondary"> | |||
| {t("Start Stock Take Date")}: {planStartDate || "-"} | |||
| @@ -269,7 +281,7 @@ const handleResetSearch = () => { | |||
| </Box> | |||
| <Grid container spacing={2}> | |||
| {filteredSessions.map((session: AllPickedStockTakeListReponse) => { | |||
| {stockTakeSessions.map((session: AllPickedStockTakeListReponse) => { | |||
| const statusColor = getStatusColor(session.status || ""); | |||
| const lastStockTakeDate = session.lastStockTakeDate | |||
| ? dayjs(session.lastStockTakeDate).format(OUTPUT_DATE_FORMAT) | |||
| @@ -338,7 +350,7 @@ const handleResetSearch = () => { | |||
| })} | |||
| </Grid> | |||
| {stockTakeSessions.length > 0 && ( | |||
| {total > 0 && ( | |||
| <TablePagination | |||
| component="div" | |||
| count={total} | |||
| @@ -50,6 +50,7 @@ | |||
| "Process Start Time": "工序開始時間", | |||
| "Stock Req. Qty": "需求數", | |||
| "Staff No Required": "員工編號必填", | |||
| "Stock Take Section (can use , to search multiple sections)": "盤點區域(可使用逗號搜索多個區域)", | |||
| "User Not Found": "用戶不存在", | |||
| "Time Remaining": "剩餘時間", | |||
| "Select Printer": "選擇打印機", | |||
| @@ -8,6 +8,12 @@ | |||
| "UoM": "單位", | |||
| "mat": "物料", | |||
| "variance": "差異", | |||
| "Plan Start Date": "計劃開始日期", | |||
| "Total Items": "總貨品數量", | |||
| "Total Lots": "總批號數量", | |||
| "Stock Take Round": "盤點輪次", | |||
| "ApproverAll": "審核員", | |||
| "Stock Take Section (can use , to search multiple sections)": "盤點區域(可使用逗號搜索多個區域)", | |||
| "Variance %": "差異百分比", | |||
| "fg": "成品", | |||
| "Back to List": "返回列表", | |||
| @@ -17,6 +23,7 @@ | |||
| "available": "可用", | |||
| "Issue Qty": "問題數量", | |||
| "tke": "盤點", | |||
| "Total Stock Takes": "總盤點數量", | |||
| "Submit completed: {{success}} success, {{errors}} errors": "提交完成:{{success}} 成功,{{errors}} 錯誤", | |||
| "Submit All Inputted": "提交所有輸入", | |||
| "Submit Bad Item": "提交不良品", | |||