|
|
@@ -1,7 +1,8 @@ |
|
|
"use client"; |
|
|
"use client"; |
|
|
|
|
|
|
|
|
import { DoResult } from "@/app/api/do"; |
|
|
import { DoResult } from "@/app/api/do"; |
|
|
import { DoSearchAll, fetchDoSearch, releaseDo ,startBatchReleaseAsync, getBatchReleaseProgress} from "@/app/api/do/actions"; |
|
|
|
|
|
|
|
|
import { DoSearchAll, DoSearchLiteResponse, fetchDoSearch, fetchAllDoSearch, fetchDoSearchList, releaseDo ,startBatchReleaseAsync, getBatchReleaseProgress} from "@/app/api/do/actions"; |
|
|
|
|
|
|
|
|
import { useRouter } from "next/navigation"; |
|
|
import { useRouter } from "next/navigation"; |
|
|
import React, { ForwardedRef, useCallback, useEffect, useMemo, useState } from "react"; |
|
|
import React, { ForwardedRef, useCallback, useEffect, useMemo, useState } from "react"; |
|
|
import { useTranslation } from "react-i18next"; |
|
|
import { useTranslation } from "react-i18next"; |
|
|
@@ -71,33 +72,12 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
useState<GridRowSelectionModel>([]); |
|
|
useState<GridRowSelectionModel>([]); |
|
|
|
|
|
|
|
|
const [searchAllDos, setSearchAllDos] = useState<DoSearchAll[]>([]); |
|
|
const [searchAllDos, setSearchAllDos] = useState<DoSearchAll[]>([]); |
|
|
|
|
|
const [totalCount, setTotalCount] = useState(0); |
|
|
|
|
|
|
|
|
const [pagingController, setPagingController] = useState({ |
|
|
const [pagingController, setPagingController] = useState({ |
|
|
pageNum: 1, |
|
|
pageNum: 1, |
|
|
pageSize: 10, |
|
|
pageSize: 10, |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const handlePageChange = useCallback((event: unknown, newPage: number) => { |
|
|
|
|
|
const newPagingController = { |
|
|
|
|
|
...pagingController, |
|
|
|
|
|
pageNum: newPage + 1, |
|
|
|
|
|
}; |
|
|
|
|
|
setPagingController(newPagingController); |
|
|
|
|
|
},[pagingController]); |
|
|
|
|
|
|
|
|
|
|
|
const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { |
|
|
|
|
|
const newPageSize = parseInt(event.target.value, 10); |
|
|
|
|
|
const newPagingController = { |
|
|
|
|
|
pageNum: 1, |
|
|
|
|
|
pageSize: newPageSize, |
|
|
|
|
|
}; |
|
|
|
|
|
setPagingController(newPagingController); |
|
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
const pagedRows = useMemo(() => { |
|
|
|
|
|
const start = (pagingController.pageNum - 1) * pagingController.pageSize; |
|
|
|
|
|
return searchAllDos.slice(start, start + pagingController.pageSize); |
|
|
|
|
|
}, [searchAllDos, pagingController]); |
|
|
|
|
|
|
|
|
|
|
|
const [currentSearchParams, setCurrentSearchParams] = useState<SearchBoxInputs>({ |
|
|
const [currentSearchParams, setCurrentSearchParams] = useState<SearchBoxInputs>({ |
|
|
code: "", |
|
|
code: "", |
|
|
@@ -119,34 +99,24 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
const [hasSearched, setHasSearched] = useState(false); |
|
|
const [hasSearched, setHasSearched] = useState(false); |
|
|
const [hasResults, setHasResults] = useState(false); |
|
|
const [hasResults, setHasResults] = useState(false); |
|
|
|
|
|
|
|
|
useEffect(() =>{ |
|
|
|
|
|
|
|
|
// 当搜索条件变化时,重置到第一页 |
|
|
|
|
|
useEffect(() => { |
|
|
setPagingController(p => ({ |
|
|
setPagingController(p => ({ |
|
|
...p, |
|
|
...p, |
|
|
pageNum: 1, |
|
|
pageNum: 1, |
|
|
})); |
|
|
})); |
|
|
}, [searchAllDos]); |
|
|
|
|
|
|
|
|
}, [currentSearchParams.code, currentSearchParams.shopName, currentSearchParams.status, currentSearchParams.estimatedArrivalDate]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( |
|
|
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( |
|
|
() => [ |
|
|
() => [ |
|
|
{ label: t("Code"), paramName: "code", type: "text" }, |
|
|
{ label: t("Code"), paramName: "code", type: "text" }, |
|
|
/* |
|
|
|
|
|
{ |
|
|
|
|
|
label: t("Order Date From"), |
|
|
|
|
|
label2: t("Order Date To"), |
|
|
|
|
|
paramName: "orderDate", |
|
|
|
|
|
type: "dateRange", |
|
|
|
|
|
}, |
|
|
|
|
|
*/ |
|
|
|
|
|
{ label: t("Shop Name"), paramName: "shopName", type: "text" }, |
|
|
{ label: t("Shop Name"), paramName: "shopName", type: "text" }, |
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
label: t("Estimated Arrival"), |
|
|
label: t("Estimated Arrival"), |
|
|
//label2: t("Estimated Arrival To"), |
|
|
|
|
|
paramName: "estimatedArrivalDate", |
|
|
paramName: "estimatedArrivalDate", |
|
|
type: "date", |
|
|
type: "date", |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
label: t("Status"), |
|
|
label: t("Status"), |
|
|
paramName: "status", |
|
|
paramName: "status", |
|
|
@@ -164,12 +134,15 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
const onReset = useCallback(async () => { |
|
|
const onReset = useCallback(async () => { |
|
|
try { |
|
|
try { |
|
|
setSearchAllDos([]); |
|
|
setSearchAllDos([]); |
|
|
|
|
|
setTotalCount(0); |
|
|
setHasSearched(false); |
|
|
setHasSearched(false); |
|
|
setHasResults(false); |
|
|
setHasResults(false); |
|
|
|
|
|
setPagingController({ pageNum: 1, pageSize: 10 }); |
|
|
} |
|
|
} |
|
|
catch (error) { |
|
|
catch (error) { |
|
|
console.error("Error: ", error); |
|
|
console.error("Error: ", error); |
|
|
setSearchAllDos([]); |
|
|
setSearchAllDos([]); |
|
|
|
|
|
setTotalCount(0); |
|
|
} |
|
|
} |
|
|
}, []); |
|
|
}, []); |
|
|
|
|
|
|
|
|
@@ -180,23 +153,15 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
} |
|
|
} |
|
|
router.push(`/do/edit?id=${doResult.id}`); |
|
|
router.push(`/do/edit?id=${doResult.id}`); |
|
|
}, |
|
|
}, |
|
|
[router], |
|
|
|
|
|
|
|
|
[router, currentSearchParams], |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
const validationTest = useCallback( |
|
|
const validationTest = useCallback( |
|
|
( |
|
|
( |
|
|
newRow: GridRowModel<DoRow>, |
|
|
newRow: GridRowModel<DoRow>, |
|
|
// rowModel: GridRowSelectionModel |
|
|
|
|
|
): EntryError => { |
|
|
): EntryError => { |
|
|
const error: EntryError = {}; |
|
|
const error: EntryError = {}; |
|
|
console.log(newRow); |
|
|
console.log(newRow); |
|
|
// if (!newRow.lowerLimit) { |
|
|
|
|
|
// error["lowerLimit"] = "lower limit cannot be null" |
|
|
|
|
|
// } |
|
|
|
|
|
// if (newRow.lowerLimit && newRow.upperLimit && newRow.lowerLimit > newRow.upperLimit) { |
|
|
|
|
|
// error["lowerLimit"] = "lower limit should not be greater than upper limit" |
|
|
|
|
|
// error["upperLimit"] = "lower limit should not be greater than upper limit" |
|
|
|
|
|
// } |
|
|
|
|
|
return Object.keys(error).length > 0 ? error : undefined; |
|
|
return Object.keys(error).length > 0 ? error : undefined; |
|
|
}, |
|
|
}, |
|
|
[], |
|
|
[], |
|
|
@@ -204,12 +169,6 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
|
|
|
|
|
|
const columns = useMemo<GridColDef[]>( |
|
|
const columns = useMemo<GridColDef[]>( |
|
|
() => [ |
|
|
() => [ |
|
|
// { |
|
|
|
|
|
// name: "id", |
|
|
|
|
|
// label: t("Details"), |
|
|
|
|
|
// onClick: onDetailClick, |
|
|
|
|
|
// buttonIcon: <EditNote />, |
|
|
|
|
|
// }, |
|
|
|
|
|
{ |
|
|
{ |
|
|
field: "id", |
|
|
field: "id", |
|
|
headerName: t("Details"), |
|
|
headerName: t("Details"), |
|
|
@@ -240,7 +199,6 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
headerName: t("Supplier Name"), |
|
|
headerName: t("Supplier Name"), |
|
|
flex: 1, |
|
|
flex: 1, |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
field: "orderDate", |
|
|
field: "orderDate", |
|
|
headerName: t("Order Date"), |
|
|
headerName: t("Order Date"), |
|
|
@@ -250,9 +208,7 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
? arrayToDateString(params.row.orderDate) |
|
|
? arrayToDateString(params.row.orderDate) |
|
|
: "N/A"; |
|
|
: "N/A"; |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
field: "estimatedArrivalDate", |
|
|
field: "estimatedArrivalDate", |
|
|
headerName: t("Estimated Arrival"), |
|
|
headerName: t("Estimated Arrival"), |
|
|
@@ -272,7 +228,7 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
], |
|
|
], |
|
|
[t, arrayToDateString], |
|
|
|
|
|
|
|
|
[t, arrayToDateString, onDetailClick], |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
const onSubmit = useCallback<SubmitHandler<CreateConsoDoInput>>( |
|
|
const onSubmit = useCallback<SubmitHandler<CreateConsoDoInput>>( |
|
|
@@ -280,35 +236,24 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
const hasErrors = false; |
|
|
const hasErrors = false; |
|
|
console.log(errors); |
|
|
console.log(errors); |
|
|
}, |
|
|
}, |
|
|
[], |
|
|
|
|
|
|
|
|
[errors], |
|
|
); |
|
|
); |
|
|
const onSubmitError = useCallback<SubmitErrorHandler<CreateConsoDoInput>>( |
|
|
const onSubmitError = useCallback<SubmitErrorHandler<CreateConsoDoInput>>( |
|
|
(errors) => {}, |
|
|
(errors) => {}, |
|
|
[], |
|
|
[], |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
//SEARCH FUNCTION |
|
|
//SEARCH FUNCTION |
|
|
const handleSearch = useCallback(async (query: SearchBoxInputs) => { |
|
|
const handleSearch = useCallback(async (query: SearchBoxInputs) => { |
|
|
try { |
|
|
try { |
|
|
setCurrentSearchParams(query); |
|
|
setCurrentSearchParams(query); |
|
|
|
|
|
|
|
|
let orderStartDate = ""; |
|
|
|
|
|
let orderEndDate = ""; |
|
|
|
|
|
let estArrStartDate = query.estimatedArrivalDate; |
|
|
let estArrStartDate = query.estimatedArrivalDate; |
|
|
let estArrEndDate = query.estimatedArrivalDate; |
|
|
|
|
|
const time = "T00:00:00"; |
|
|
const time = "T00:00:00"; |
|
|
|
|
|
|
|
|
//if(orderStartDate != ""){ |
|
|
|
|
|
// orderStartDate = query.orderDate + time; |
|
|
|
|
|
//} |
|
|
|
|
|
//if(orderEndDate != ""){ |
|
|
|
|
|
// orderEndDate = query.orderDateTo + time; |
|
|
|
|
|
//} |
|
|
|
|
|
if(estArrStartDate != ""){ |
|
|
if(estArrStartDate != ""){ |
|
|
estArrStartDate = query.estimatedArrivalDate + time; |
|
|
estArrStartDate = query.estimatedArrivalDate + time; |
|
|
} |
|
|
} |
|
|
if(estArrEndDate != ""){ |
|
|
|
|
|
estArrEndDate = query.estimatedArrivalDate + time; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let status = ""; |
|
|
let status = ""; |
|
|
if(query.status == "All"){ |
|
|
if(query.status == "All"){ |
|
|
@@ -318,28 +263,33 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
status = query.status; |
|
|
status = query.status; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const data = await fetchDoSearch( |
|
|
|
|
|
|
|
|
// 调用新的 API,传入分页参数 |
|
|
|
|
|
const response = await fetchDoSearch( |
|
|
query.code || "", |
|
|
query.code || "", |
|
|
query.shopName || "", |
|
|
query.shopName || "", |
|
|
status, |
|
|
status, |
|
|
orderStartDate, |
|
|
|
|
|
orderEndDate, |
|
|
|
|
|
|
|
|
"", // orderStartDate - 不再使用 |
|
|
|
|
|
"", // orderEndDate - 不再使用 |
|
|
estArrStartDate, |
|
|
estArrStartDate, |
|
|
estArrEndDate |
|
|
|
|
|
|
|
|
"", // estArrEndDate - 不再使用 |
|
|
|
|
|
pagingController.pageNum, // 传入当前页码 |
|
|
|
|
|
pagingController.pageSize // 传入每页大小 |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
setSearchAllDos(data); |
|
|
|
|
|
|
|
|
setSearchAllDos(response.records); |
|
|
|
|
|
setTotalCount(response.total); // 设置总记录数 |
|
|
setHasSearched(true); |
|
|
setHasSearched(true); |
|
|
setHasResults(data.length > 0); |
|
|
|
|
|
|
|
|
setHasResults(response.records.length > 0); |
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error("Error: ", error); |
|
|
console.error("Error: ", error); |
|
|
setSearchAllDos([]); |
|
|
setSearchAllDos([]); |
|
|
|
|
|
setTotalCount(0); |
|
|
setHasSearched(true); |
|
|
setHasSearched(true); |
|
|
setHasResults(false); |
|
|
setHasResults(false); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
}, []); |
|
|
|
|
|
|
|
|
}, [pagingController]); |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
if (typeof window !== 'undefined') { |
|
|
if (typeof window !== 'undefined') { |
|
|
const savedSearchParams = sessionStorage.getItem('doSearchParams'); |
|
|
const savedSearchParams = sessionStorage.getItem('doSearchParams'); |
|
|
@@ -373,6 +323,7 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}, [handleSearch]); |
|
|
}, [handleSearch]); |
|
|
|
|
|
|
|
|
const debouncedSearch = useCallback((query: SearchBoxInputs) => { |
|
|
const debouncedSearch = useCallback((query: SearchBoxInputs) => { |
|
|
if (searchTimeout) { |
|
|
if (searchTimeout) { |
|
|
clearTimeout(searchTimeout); |
|
|
clearTimeout(searchTimeout); |
|
|
@@ -385,98 +336,254 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
setSearchTimeout(timeout); |
|
|
setSearchTimeout(timeout); |
|
|
}, [handleSearch, searchTimeout]); |
|
|
}, [handleSearch, searchTimeout]); |
|
|
|
|
|
|
|
|
|
|
|
// 分页变化时重新搜索 |
|
|
|
|
|
const handlePageChange = useCallback((event: unknown, newPage: number) => { |
|
|
|
|
|
const newPagingController = { |
|
|
|
|
|
...pagingController, |
|
|
|
|
|
pageNum: newPage + 1, |
|
|
|
|
|
}; |
|
|
|
|
|
setPagingController(newPagingController); |
|
|
|
|
|
// 如果已经搜索过,重新搜索 |
|
|
|
|
|
if (hasSearched && currentSearchParams) { |
|
|
|
|
|
// 使用新的分页参数重新搜索 |
|
|
|
|
|
const searchWithNewPage = async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
let estArrStartDate = currentSearchParams.estimatedArrivalDate; |
|
|
|
|
|
const time = "T00:00:00"; |
|
|
|
|
|
|
|
|
|
|
|
if(estArrStartDate != ""){ |
|
|
|
|
|
estArrStartDate = currentSearchParams.estimatedArrivalDate + time; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let status = ""; |
|
|
|
|
|
if(currentSearchParams.status == "All"){ |
|
|
|
|
|
status = ""; |
|
|
|
|
|
} |
|
|
|
|
|
else{ |
|
|
|
|
|
status = currentSearchParams.status; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const response = await fetchDoSearch( |
|
|
|
|
|
currentSearchParams.code || "", |
|
|
|
|
|
currentSearchParams.shopName || "", |
|
|
|
|
|
status, |
|
|
|
|
|
"", |
|
|
|
|
|
"", |
|
|
|
|
|
estArrStartDate, |
|
|
|
|
|
"", |
|
|
|
|
|
newPagingController.pageNum, |
|
|
|
|
|
newPagingController.pageSize |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
setSearchAllDos(response.records); |
|
|
|
|
|
setTotalCount(response.total); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error: ", error); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
searchWithNewPage(); |
|
|
|
|
|
} |
|
|
|
|
|
}, [pagingController, hasSearched, currentSearchParams]); |
|
|
|
|
|
|
|
|
|
|
|
const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { |
|
|
|
|
|
const newPageSize = parseInt(event.target.value, 10); |
|
|
|
|
|
const newPagingController = { |
|
|
|
|
|
pageNum: 1, // 改变每页大小时重置到第一页 |
|
|
|
|
|
pageSize: newPageSize, |
|
|
|
|
|
}; |
|
|
|
|
|
setPagingController(newPagingController); |
|
|
|
|
|
// 如果已经搜索过,重新搜索 |
|
|
|
|
|
if (hasSearched && currentSearchParams) { |
|
|
|
|
|
const searchWithNewPageSize = async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
let estArrStartDate = currentSearchParams.estimatedArrivalDate; |
|
|
|
|
|
const time = "T00:00:00"; |
|
|
|
|
|
|
|
|
|
|
|
if(estArrStartDate != ""){ |
|
|
|
|
|
estArrStartDate = currentSearchParams.estimatedArrivalDate + time; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let status = ""; |
|
|
|
|
|
if(currentSearchParams.status == "All"){ |
|
|
|
|
|
status = ""; |
|
|
|
|
|
} |
|
|
|
|
|
else{ |
|
|
|
|
|
status = currentSearchParams.status; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const response = await fetchDoSearch( |
|
|
|
|
|
currentSearchParams.code || "", |
|
|
|
|
|
currentSearchParams.shopName || "", |
|
|
|
|
|
status, |
|
|
|
|
|
"", |
|
|
|
|
|
"", |
|
|
|
|
|
estArrStartDate, |
|
|
|
|
|
"", |
|
|
|
|
|
1, // 重置到第一页 |
|
|
|
|
|
newPageSize |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
setSearchAllDos(response.records); |
|
|
|
|
|
setTotalCount(response.total); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error: ", error); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
searchWithNewPageSize(); |
|
|
|
|
|
} |
|
|
|
|
|
}, [hasSearched, currentSearchParams]); |
|
|
|
|
|
|
|
|
const handleBatchRelease = useCallback(async () => { |
|
|
const handleBatchRelease = useCallback(async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
// 根据当前搜索条件获取所有匹配的记录(不分页) |
|
|
|
|
|
let estArrStartDate = currentSearchParams.estimatedArrivalDate; |
|
|
|
|
|
const time = "T00:00:00"; |
|
|
|
|
|
|
|
|
|
|
|
if(estArrStartDate != ""){ |
|
|
|
|
|
estArrStartDate = currentSearchParams.estimatedArrivalDate + time; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let status = ""; |
|
|
|
|
|
if(currentSearchParams.status == "All"){ |
|
|
|
|
|
status = ""; |
|
|
|
|
|
} |
|
|
|
|
|
else{ |
|
|
|
|
|
status = currentSearchParams.status; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 显示加载提示 |
|
|
|
|
|
const loadingSwal = Swal.fire({ |
|
|
|
|
|
title: t("Loading"), |
|
|
|
|
|
text: t("Fetching all matching records..."), |
|
|
|
|
|
allowOutsideClick: false, |
|
|
|
|
|
allowEscapeKey: false, |
|
|
|
|
|
showConfirmButton: false, |
|
|
|
|
|
didOpen: () => { |
|
|
|
|
|
Swal.showLoading(); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
const totalDeliveryOrderLines = searchAllDos.reduce((sum, doItem) => { |
|
|
|
|
|
return sum + (doItem.deliveryOrderLines?.length || 0); |
|
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
|
|
|
|
const result = await Swal.fire({ |
|
|
|
|
|
icon: "question", |
|
|
|
|
|
title: t("Batch Release"), |
|
|
|
|
|
html: ` |
|
|
|
|
|
<div> |
|
|
|
|
|
<p>${t("Selected Shop(s): ")}${searchAllDos.length}</p> |
|
|
|
|
|
<p>${t("Selected Item(s): ")}${totalDeliveryOrderLines}</p> |
|
|
|
|
|
</div> |
|
|
|
|
|
`, |
|
|
|
|
|
showCancelButton: true, |
|
|
|
|
|
confirmButtonText: t("Confirm"), |
|
|
|
|
|
cancelButtonText: t("Cancel"), |
|
|
|
|
|
confirmButtonColor: "#8dba00", |
|
|
|
|
|
cancelButtonColor: "#F04438" |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// 获取所有匹配的记录 |
|
|
|
|
|
const allMatchingDos = await fetchAllDoSearch( |
|
|
|
|
|
currentSearchParams.code || "", |
|
|
|
|
|
currentSearchParams.shopName || "", |
|
|
|
|
|
status, |
|
|
|
|
|
estArrStartDate |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
if (result.isConfirmed) { |
|
|
|
|
|
const idsToRelease = searchAllDos.map(d => d.id); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
const startRes = await startBatchReleaseAsync({ ids: idsToRelease, userId: currentUserId ?? 1 }); |
|
|
|
|
|
const jobId = startRes?.entity?.jobId; |
|
|
|
|
|
|
|
|
Swal.close(); |
|
|
|
|
|
|
|
|
if (!jobId) { |
|
|
|
|
|
await Swal.fire({ icon: "error", title: t("Error"), text: t("Failed to start batch release") }); |
|
|
|
|
|
|
|
|
if (allMatchingDos.length === 0) { |
|
|
|
|
|
await Swal.fire({ |
|
|
|
|
|
icon: "warning", |
|
|
|
|
|
title: t("No Records"), |
|
|
|
|
|
text: t("No matching records found for batch release."), |
|
|
|
|
|
confirmButtonText: t("OK") |
|
|
|
|
|
}); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const progressSwal = Swal.fire({ |
|
|
|
|
|
title: t("Releasing"), |
|
|
|
|
|
text: "0% (0 / 0)", |
|
|
|
|
|
allowOutsideClick: false, |
|
|
|
|
|
allowEscapeKey: false, |
|
|
|
|
|
showConfirmButton: false, |
|
|
|
|
|
didOpen: () => { |
|
|
|
|
|
Swal.showLoading(); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const timer = setInterval(async () => { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 显示确认对话框 |
|
|
|
|
|
const result = await Swal.fire({ |
|
|
|
|
|
icon: "question", |
|
|
|
|
|
title: t("Batch Release"), |
|
|
|
|
|
html: ` |
|
|
|
|
|
<div> |
|
|
|
|
|
<p>${t("Selected Shop(s): ")}${allMatchingDos.length}</p> |
|
|
|
|
|
<p style="font-size: 0.9em; color: #666; margin-top: 8px;"> |
|
|
|
|
|
|
|
|
|
|
|
${currentSearchParams.code ? `${t("Code")}: ${currentSearchParams.code} ` : ""} |
|
|
|
|
|
${currentSearchParams.shopName ? `${t("Shop Name")}: ${currentSearchParams.shopName} ` : ""} |
|
|
|
|
|
${currentSearchParams.estimatedArrivalDate ? `${t("Estimated Arrival")}: ${currentSearchParams.estimatedArrivalDate} ` : ""} |
|
|
|
|
|
${status ? `${t("Status")}: ${status} ` : ""} |
|
|
|
|
|
</p> |
|
|
|
|
|
</div> |
|
|
|
|
|
`, |
|
|
|
|
|
showCancelButton: true, |
|
|
|
|
|
confirmButtonText: t("Confirm"), |
|
|
|
|
|
cancelButtonText: t("Cancel"), |
|
|
|
|
|
confirmButtonColor: "#8dba00", |
|
|
|
|
|
cancelButtonColor: "#F04438" |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (result.isConfirmed) { |
|
|
|
|
|
const idsToRelease = allMatchingDos.map(d => d.id); |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
const p = await getBatchReleaseProgress(jobId); |
|
|
|
|
|
|
|
|
|
|
|
const e = p?.entity || {}; |
|
|
|
|
|
const total = e.total ?? 0; |
|
|
|
|
|
const finished = e.finished ?? 0; |
|
|
|
|
|
const percentage = total > 0 ? Math.round((finished / total) * 100) : 0; |
|
|
|
|
|
|
|
|
|
|
|
const textContent = document.querySelector('.swal2-html-container'); |
|
|
|
|
|
if (textContent) { |
|
|
|
|
|
textContent.textContent = `${percentage}% (${finished} / ${total})`; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (p.code === "FINISHED" || e.running === false) { |
|
|
|
|
|
clearInterval(timer); |
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 500)); |
|
|
|
|
|
Swal.close(); |
|
|
|
|
|
|
|
|
|
|
|
await Swal.fire({ |
|
|
|
|
|
icon: "success", |
|
|
|
|
|
title: t("Completed"), |
|
|
|
|
|
text: t("Batch release completed successfully."), |
|
|
|
|
|
confirmButtonText: t("Confirm"), |
|
|
|
|
|
confirmButtonColor: "#8dba00" |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (currentSearchParams && Object.keys(currentSearchParams).length > 0) { |
|
|
|
|
|
await handleSearch(currentSearchParams); |
|
|
|
|
|
|
|
|
const startRes = await startBatchReleaseAsync({ ids: idsToRelease, userId: currentUserId ?? 1 }); |
|
|
|
|
|
const jobId = startRes?.entity?.jobId; |
|
|
|
|
|
|
|
|
|
|
|
if (!jobId) { |
|
|
|
|
|
await Swal.fire({ icon: "error", title: t("Error"), text: t("Failed to start batch release") }); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} catch (err) { |
|
|
|
|
|
console.error("progress poll error:", err); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const progressSwal = Swal.fire({ |
|
|
|
|
|
title: t("Releasing"), |
|
|
|
|
|
text: "0% (0 / 0)", |
|
|
|
|
|
allowOutsideClick: false, |
|
|
|
|
|
allowEscapeKey: false, |
|
|
|
|
|
showConfirmButton: false, |
|
|
|
|
|
didOpen: () => { |
|
|
|
|
|
Swal.showLoading(); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const timer = setInterval(async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
const p = await getBatchReleaseProgress(jobId); |
|
|
|
|
|
|
|
|
|
|
|
const e = p?.entity || {}; |
|
|
|
|
|
const total = e.total ?? 0; |
|
|
|
|
|
const finished = e.finished ?? 0; |
|
|
|
|
|
const percentage = total > 0 ? Math.round((finished / total) * 100) : 0; |
|
|
|
|
|
|
|
|
|
|
|
const textContent = document.querySelector('.swal2-html-container'); |
|
|
|
|
|
if (textContent) { |
|
|
|
|
|
textContent.textContent = `${percentage}% (${finished} / ${total})`; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (p.code === "FINISHED" || e.running === false) { |
|
|
|
|
|
clearInterval(timer); |
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 500)); |
|
|
|
|
|
Swal.close(); |
|
|
|
|
|
|
|
|
|
|
|
await Swal.fire({ |
|
|
|
|
|
icon: "success", |
|
|
|
|
|
title: t("Completed"), |
|
|
|
|
|
text: t("Batch release completed successfully."), |
|
|
|
|
|
confirmButtonText: t("Confirm"), |
|
|
|
|
|
confirmButtonColor: "#8dba00" |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (currentSearchParams && Object.keys(currentSearchParams).length > 0) { |
|
|
|
|
|
await handleSearch(currentSearchParams); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} catch (err) { |
|
|
|
|
|
console.error("progress poll error:", err); |
|
|
|
|
|
} |
|
|
|
|
|
}, 800); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Batch release error:", error); |
|
|
|
|
|
await Swal.fire({ |
|
|
|
|
|
icon: "error", |
|
|
|
|
|
title: t("Error"), |
|
|
|
|
|
text: t("An error occurred during batch release"), |
|
|
|
|
|
confirmButtonText: t("OK") |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
}, 800); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Batch release error:", error); |
|
|
|
|
|
await Swal.fire({ |
|
|
|
|
|
icon: "error", |
|
|
|
|
|
title: t("Error"), |
|
|
|
|
|
text: t("An error occurred during batch release"), |
|
|
|
|
|
confirmButtonText: t("OK") |
|
|
|
|
|
}); |
|
|
|
|
|
}} |
|
|
|
|
|
}, [t, currentUserId, searchAllDos, currentSearchParams, handleSearch]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error fetching all matching records:", error); |
|
|
|
|
|
await Swal.fire({ |
|
|
|
|
|
icon: "error", |
|
|
|
|
|
title: t("Error"), |
|
|
|
|
|
text: t("Failed to fetch matching records"), |
|
|
|
|
|
confirmButtonText: t("OK") |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
}, [t, currentUserId, currentSearchParams, handleSearch]); |
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
<> |
|
|
<> |
|
|
@@ -500,14 +607,6 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
alignItems="end" |
|
|
alignItems="end" |
|
|
> |
|
|
> |
|
|
<Stack spacing={2} direction="row"> |
|
|
<Stack spacing={2} direction="row"> |
|
|
{/*<Button |
|
|
|
|
|
name="submit" |
|
|
|
|
|
variant="contained" |
|
|
|
|
|
// startIcon={<Check />} |
|
|
|
|
|
type="submit" |
|
|
|
|
|
> |
|
|
|
|
|
{t("Create")} |
|
|
|
|
|
</Button>*/} |
|
|
|
|
|
{hasSearched && hasResults && ( |
|
|
{hasSearched && hasResults && ( |
|
|
<Button |
|
|
<Button |
|
|
name="batch_release" |
|
|
name="batch_release" |
|
|
@@ -517,22 +616,18 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
{t("Batch Release")} |
|
|
{t("Batch Release")} |
|
|
</Button> |
|
|
</Button> |
|
|
)} |
|
|
)} |
|
|
|
|
|
|
|
|
</Stack> |
|
|
</Stack> |
|
|
|
|
|
|
|
|
</Grid> |
|
|
</Grid> |
|
|
</Grid> |
|
|
</Grid> |
|
|
|
|
|
|
|
|
<SearchBox |
|
|
<SearchBox |
|
|
criteria={searchCriteria} |
|
|
criteria={searchCriteria} |
|
|
|
|
|
|
|
|
onSearch={handleSearch} |
|
|
onSearch={handleSearch} |
|
|
|
|
|
|
|
|
onReset={onReset} |
|
|
onReset={onReset} |
|
|
/> |
|
|
/> |
|
|
|
|
|
|
|
|
<StyledDataGrid |
|
|
<StyledDataGrid |
|
|
rows={pagedRows} |
|
|
|
|
|
|
|
|
rows={searchAllDos} |
|
|
columns={columns} |
|
|
columns={columns} |
|
|
checkboxSelection |
|
|
checkboxSelection |
|
|
rowSelectionModel={rowSelectionModel} |
|
|
rowSelectionModel={rowSelectionModel} |
|
|
@@ -547,17 +642,16 @@ const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSear |
|
|
/> |
|
|
/> |
|
|
|
|
|
|
|
|
<TablePagination |
|
|
<TablePagination |
|
|
component="div" |
|
|
|
|
|
count={searchAllDos.length} |
|
|
|
|
|
page={(pagingController.pageNum - 1)} |
|
|
|
|
|
rowsPerPage={pagingController.pageSize} |
|
|
|
|
|
onPageChange={handlePageChange} |
|
|
|
|
|
onRowsPerPageChange={handlePageSizeChange} |
|
|
|
|
|
rowsPerPageOptions={[10, 25, 50]} |
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
component="div" |
|
|
|
|
|
count={totalCount} |
|
|
|
|
|
page={(pagingController.pageNum - 1)} |
|
|
|
|
|
rowsPerPage={pagingController.pageSize} |
|
|
|
|
|
onPageChange={handlePageChange} |
|
|
|
|
|
onRowsPerPageChange={handlePageSizeChange} |
|
|
|
|
|
rowsPerPageOptions={[10, 25, 50]} |
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
</Stack> |
|
|
</Stack> |
|
|
|
|
|
|
|
|
</FormProvider> |
|
|
</FormProvider> |
|
|
</> |
|
|
</> |
|
|
); |
|
|
); |
|
|
|