|
|
|
@@ -24,102 +24,101 @@ import { |
|
|
|
Accordion, |
|
|
|
AccordionSummary, |
|
|
|
AccordionDetails, |
|
|
|
Checkbox, // ✅ Add Checkbox import |
|
|
|
} from "@mui/material"; |
|
|
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; |
|
|
|
import { useCallback, useEffect, useState, useRef, useMemo } from "react"; |
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
import { useRouter } from "next/navigation"; |
|
|
|
import { |
|
|
|
fetchALLPickOrderLineLotDetails, |
|
|
|
updateStockOutLineStatus, |
|
|
|
createStockOutLine, |
|
|
|
recordPickExecutionIssue, |
|
|
|
fetchFGPickOrders, |
|
|
|
FGPickOrderResponse, |
|
|
|
autoAssignAndReleasePickOrder, |
|
|
|
AutoAssignReleaseResponse, |
|
|
|
checkPickOrderCompletion, |
|
|
|
PickOrderCompletionResponse, |
|
|
|
checkAndCompletePickOrderByConsoCode, |
|
|
|
fetchCompletedDoPickOrders, // ✅ 新增:使用新的 API |
|
|
|
CompletedDoPickOrderResponse, |
|
|
|
CompletedDoPickOrderSearchParams, |
|
|
|
fetchLotDetailsByPickOrderId // ✅ 修复:导入类型 |
|
|
|
} from "@/app/api/pickOrder/actions"; |
|
|
|
fetchCompletedJobOrderPickOrdersWithCompletedSecondScan, |
|
|
|
fetchCompletedJobOrderPickOrderLotDetails |
|
|
|
} from "@/app/api/jo/actions"; |
|
|
|
import { fetchNameList, NameList } from "@/app/api/user/actions"; |
|
|
|
import { |
|
|
|
FormProvider, |
|
|
|
useForm, |
|
|
|
} from "react-hook-form"; |
|
|
|
import SearchBox, { Criterion } from "../SearchBox"; |
|
|
|
import { CreateStockOutLine } from "@/app/api/pickOrder/actions"; |
|
|
|
import { updateInventoryLotLineQuantities } from "@/app/api/inventory/actions"; |
|
|
|
import QrCodeIcon from '@mui/icons-material/QrCode'; |
|
|
|
import { useQrCodeScannerContext } from '../QrCodeScannerProvider/QrCodeScannerProvider'; |
|
|
|
import { useSession } from "next-auth/react"; |
|
|
|
import { SessionWithTokens } from "@/config/authConfig"; |
|
|
|
import { fetchStockInLineInfo } from "@/app/api/po/actions"; |
|
|
|
import GoodPickExecutionForm from "./JobPickExecutionForm"; |
|
|
|
import FGPickOrderCard from "./FGPickOrderCard"; |
|
|
|
|
|
|
|
interface Props { |
|
|
|
filterArgs: Record<string, any>; |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ 新增:已完成的 DO Pick Order 接口 |
|
|
|
interface CompletedDoPickOrder { |
|
|
|
// ✅ 修改:已完成的 Job Order Pick Order 接口 |
|
|
|
interface CompletedJobOrderPickOrder { |
|
|
|
id: number; |
|
|
|
pickOrderId: number; |
|
|
|
pickOrderCode: string; |
|
|
|
pickOrderConsoCode: string; |
|
|
|
pickOrderTargetDate: string; |
|
|
|
pickOrderStatus: string; |
|
|
|
deliveryOrderId: number; |
|
|
|
deliveryNo: string; |
|
|
|
deliveryDate: string; |
|
|
|
shopId: number; |
|
|
|
shopCode: string; |
|
|
|
shopName: string; |
|
|
|
shopAddress: string; |
|
|
|
ticketNo: string; |
|
|
|
shopPoNo: string; |
|
|
|
numberOfCartons: number; |
|
|
|
truckNo: string; |
|
|
|
storeId: string; |
|
|
|
completedDate: string; |
|
|
|
fgPickOrders: FGPickOrderResponse[]; |
|
|
|
jobOrderId: number; |
|
|
|
jobOrderCode: string; |
|
|
|
jobOrderName: string; |
|
|
|
reqQty: number; |
|
|
|
uom: string; |
|
|
|
planStart: string; |
|
|
|
planEnd: string; |
|
|
|
secondScanCompleted: boolean; |
|
|
|
totalItems: number; |
|
|
|
completedItems: number; |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ 新增:Pick Order 数据接口 |
|
|
|
interface PickOrderData { |
|
|
|
// ✅ 新增:Lot 详情接口 |
|
|
|
interface LotDetail { |
|
|
|
lotId: number; |
|
|
|
lotNo: string; |
|
|
|
expiryDate: string; |
|
|
|
location: string; |
|
|
|
availableQty: number; |
|
|
|
requiredQty: number; |
|
|
|
actualPickQty: number; |
|
|
|
processingStatus: string; |
|
|
|
lotAvailability: string; |
|
|
|
pickOrderId: number; |
|
|
|
pickOrderCode: string; |
|
|
|
pickOrderConsoCode: string; |
|
|
|
pickOrderStatus: string; |
|
|
|
completedDate: string; |
|
|
|
lots: any[]; |
|
|
|
pickOrderLineId: number; |
|
|
|
stockOutLineId: number; |
|
|
|
stockOutLineStatus: string; |
|
|
|
routerIndex: number; |
|
|
|
routerArea: string; |
|
|
|
routerRoute: string; |
|
|
|
uomShortDesc: string; |
|
|
|
secondQrScanStatus: string; |
|
|
|
itemId: number; |
|
|
|
itemCode: string; |
|
|
|
itemName: string; |
|
|
|
uomCode: string; |
|
|
|
uomDesc: string; |
|
|
|
} |
|
|
|
|
|
|
|
const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
const { t } = useTranslation("pickOrder"); |
|
|
|
const { t } = useTranslation("jo"); |
|
|
|
const router = useRouter(); |
|
|
|
const { data: session } = useSession() as { data: SessionWithTokens | null }; |
|
|
|
|
|
|
|
const currentUserId = session?.id ? parseInt(session.id) : undefined; |
|
|
|
|
|
|
|
// ✅ 新增:已完成 DO Pick Orders 状态 |
|
|
|
const [completedDoPickOrders, setCompletedDoPickOrders] = useState<CompletedDoPickOrder[]>([]); |
|
|
|
const [completedDoPickOrdersLoading, setCompletedDoPickOrdersLoading] = useState(false); |
|
|
|
// ✅ 修改:已完成 Job Order Pick Orders 状态 |
|
|
|
const [completedJobOrderPickOrders, setCompletedJobOrderPickOrders] = useState<CompletedJobOrderPickOrder[]>([]); |
|
|
|
const [completedJobOrderPickOrdersLoading, setCompletedJobOrderPickOrdersLoading] = useState(false); |
|
|
|
|
|
|
|
// ✅ 新增:详情视图状态 |
|
|
|
const [selectedDoPickOrder, setSelectedDoPickOrder] = useState<CompletedDoPickOrder | null>(null); |
|
|
|
// ✅ 修改:详情视图状态 |
|
|
|
const [selectedJobOrderPickOrder, setSelectedJobOrderPickOrder] = useState<CompletedJobOrderPickOrder | null>(null); |
|
|
|
const [showDetailView, setShowDetailView] = useState(false); |
|
|
|
const [detailLotData, setDetailLotData] = useState<any[]>([]); |
|
|
|
const [detailLotData, setDetailLotData] = useState<LotDetail[]>([]); |
|
|
|
const [detailLotDataLoading, setDetailLotDataLoading] = useState(false); |
|
|
|
|
|
|
|
// ✅ 新增:搜索状态 |
|
|
|
// ✅ 修改:搜索状态 |
|
|
|
const [searchQuery, setSearchQuery] = useState<Record<string, any>>({}); |
|
|
|
const [filteredDoPickOrders, setFilteredDoPickOrders] = useState<CompletedDoPickOrder[]>([]); |
|
|
|
const [filteredJobOrderPickOrders, setFilteredJobOrderPickOrders] = useState<CompletedJobOrderPickOrder[]>([]); |
|
|
|
|
|
|
|
// ✅ 新增:分页状态 |
|
|
|
// ✅ 修改:分页状态 |
|
|
|
const [paginationController, setPaginationController] = useState({ |
|
|
|
pageNum: 0, |
|
|
|
pageSize: 10, |
|
|
|
@@ -128,58 +127,82 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
const formProps = useForm(); |
|
|
|
const errors = formProps.formState.errors; |
|
|
|
|
|
|
|
// ✅ 修改:使用新的 API 获取已完成的 DO Pick Orders |
|
|
|
const fetchCompletedDoPickOrdersData = useCallback(async (searchParams?: CompletedDoPickOrderSearchParams) => { |
|
|
|
// ✅ 修改:使用新的 Job Order API 获取已完成的 Job Order Pick Orders |
|
|
|
const fetchCompletedJobOrderPickOrdersData = useCallback(async () => { |
|
|
|
if (!currentUserId) return; |
|
|
|
|
|
|
|
setCompletedDoPickOrdersLoading(true); |
|
|
|
setCompletedJobOrderPickOrdersLoading(true); |
|
|
|
try { |
|
|
|
console.log("🔍 Fetching completed DO pick orders with params:", searchParams); |
|
|
|
console.log("🔍 Fetching completed Job Order pick orders..."); |
|
|
|
|
|
|
|
const completedDoPickOrders = await fetchCompletedDoPickOrders(currentUserId, searchParams); |
|
|
|
const completedJobOrderPickOrders = await fetchCompletedJobOrderPickOrdersWithCompletedSecondScan(currentUserId); |
|
|
|
|
|
|
|
setCompletedDoPickOrders(completedDoPickOrders); |
|
|
|
setFilteredDoPickOrders(completedDoPickOrders); |
|
|
|
console.log("✅ Fetched completed DO pick orders:", completedDoPickOrders); |
|
|
|
setCompletedJobOrderPickOrders(completedJobOrderPickOrders); |
|
|
|
setFilteredJobOrderPickOrders(completedJobOrderPickOrders); |
|
|
|
console.log("✅ Fetched completed Job Order pick orders:", completedJobOrderPickOrders); |
|
|
|
} catch (error) { |
|
|
|
console.error("❌ Error fetching completed DO pick orders:", error); |
|
|
|
setCompletedDoPickOrders([]); |
|
|
|
setFilteredDoPickOrders([]); |
|
|
|
console.error("❌ Error fetching completed Job Order pick orders:", error); |
|
|
|
setCompletedJobOrderPickOrders([]); |
|
|
|
setFilteredJobOrderPickOrders([]); |
|
|
|
} finally { |
|
|
|
setCompletedDoPickOrdersLoading(false); |
|
|
|
setCompletedJobOrderPickOrdersLoading(false); |
|
|
|
} |
|
|
|
}, [currentUserId]); |
|
|
|
|
|
|
|
// ✅ 初始化时获取数据 |
|
|
|
// ✅ 新增:获取 lot 详情数据 |
|
|
|
const fetchLotDetailsData = useCallback(async (pickOrderId: number) => { |
|
|
|
setDetailLotDataLoading(true); |
|
|
|
try { |
|
|
|
console.log("🔍 Fetching lot details for pick order:", pickOrderId); |
|
|
|
|
|
|
|
const lotDetails = await fetchCompletedJobOrderPickOrderLotDetails(pickOrderId); |
|
|
|
|
|
|
|
setDetailLotData(lotDetails); |
|
|
|
console.log("✅ Fetched lot details:", lotDetails); |
|
|
|
} catch (error) { |
|
|
|
console.error("❌ Error fetching lot details:", error); |
|
|
|
setDetailLotData([]); |
|
|
|
} finally { |
|
|
|
setDetailLotDataLoading(false); |
|
|
|
} |
|
|
|
}, []); |
|
|
|
|
|
|
|
// ✅ 修改:初始化时获取数据 |
|
|
|
useEffect(() => { |
|
|
|
if (currentUserId) { |
|
|
|
fetchCompletedDoPickOrdersData(); |
|
|
|
fetchCompletedJobOrderPickOrdersData(); |
|
|
|
} |
|
|
|
}, [currentUserId, fetchCompletedDoPickOrdersData]); |
|
|
|
}, [currentUserId, fetchCompletedJobOrderPickOrdersData]); |
|
|
|
|
|
|
|
// ✅ 修改:搜索功能使用新的 API |
|
|
|
// ✅ 修改:搜索功能 |
|
|
|
const handleSearch = useCallback((query: Record<string, any>) => { |
|
|
|
setSearchQuery({ ...query }); |
|
|
|
console.log("Search query:", query); |
|
|
|
|
|
|
|
const searchParams: CompletedDoPickOrderSearchParams = { |
|
|
|
pickOrderCode: query.pickOrderCode || undefined, |
|
|
|
shopName: query.shopName || undefined, |
|
|
|
deliveryNo: query.deliveryNo || undefined, |
|
|
|
//ticketNo: query.ticketNo || undefined, |
|
|
|
}; |
|
|
|
|
|
|
|
// 使用新的 API 进行搜索 |
|
|
|
fetchCompletedDoPickOrdersData(searchParams); |
|
|
|
}, [fetchCompletedDoPickOrdersData]); |
|
|
|
const filtered = completedJobOrderPickOrders.filter((pickOrder) => { |
|
|
|
const pickOrderCodeMatch = !query.pickOrderCode || |
|
|
|
pickOrder.pickOrderCode?.toLowerCase().includes((query.pickOrderCode || "").toLowerCase()); |
|
|
|
|
|
|
|
const jobOrderCodeMatch = !query.jobOrderCode || |
|
|
|
pickOrder.jobOrderCode?.toLowerCase().includes((query.jobOrderCode || "").toLowerCase()); |
|
|
|
|
|
|
|
const jobOrderNameMatch = !query.jobOrderName || |
|
|
|
pickOrder.jobOrderName?.toLowerCase().includes((query.jobOrderName || "").toLowerCase()); |
|
|
|
|
|
|
|
return pickOrderCodeMatch && jobOrderCodeMatch && jobOrderNameMatch; |
|
|
|
}); |
|
|
|
|
|
|
|
setFilteredJobOrderPickOrders(filtered); |
|
|
|
console.log("Filtered Job Order pick orders count:", filtered.length); |
|
|
|
}, [completedJobOrderPickOrders]); |
|
|
|
|
|
|
|
// ✅ 修复:重命名函数避免重复声明 |
|
|
|
// ✅ 修改:重置搜索 |
|
|
|
const handleSearchReset = useCallback(() => { |
|
|
|
setSearchQuery({}); |
|
|
|
fetchCompletedDoPickOrdersData(); // 重新获取所有数据 |
|
|
|
}, [fetchCompletedDoPickOrdersData]); |
|
|
|
setFilteredJobOrderPickOrders(completedJobOrderPickOrders); |
|
|
|
}, [completedJobOrderPickOrders]); |
|
|
|
|
|
|
|
// ✅ 分页功能 |
|
|
|
// ✅ 修改:分页功能 |
|
|
|
const handlePageChange = useCallback((event: unknown, newPage: number) => { |
|
|
|
setPaginationController(prev => ({ |
|
|
|
...prev, |
|
|
|
@@ -195,14 +218,14 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
}); |
|
|
|
}, []); |
|
|
|
|
|
|
|
// ✅ 分页数据 |
|
|
|
// ✅ 修改:分页数据 |
|
|
|
const paginatedData = useMemo(() => { |
|
|
|
const startIndex = paginationController.pageNum * paginationController.pageSize; |
|
|
|
const endIndex = startIndex + paginationController.pageSize; |
|
|
|
return filteredDoPickOrders.slice(startIndex, endIndex); |
|
|
|
}, [filteredDoPickOrders, paginationController]); |
|
|
|
return filteredJobOrderPickOrders.slice(startIndex, endIndex); |
|
|
|
}, [filteredJobOrderPickOrders, paginationController]); |
|
|
|
|
|
|
|
// ✅ 搜索条件 |
|
|
|
// ✅ 修改:搜索条件 |
|
|
|
const searchCriteria: Criterion<any>[] = [ |
|
|
|
{ |
|
|
|
label: t("Pick Order Code"), |
|
|
|
@@ -210,59 +233,42 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
type: "text", |
|
|
|
}, |
|
|
|
{ |
|
|
|
label: t("Shop Name"), |
|
|
|
paramName: "shopName", |
|
|
|
label: t("Job Order Code"), |
|
|
|
paramName: "jobOrderCode", |
|
|
|
type: "text", |
|
|
|
}, |
|
|
|
{ |
|
|
|
label: t("Delivery No"), |
|
|
|
paramName: "deliveryNo", |
|
|
|
label: t("Job Order Item Name"), |
|
|
|
paramName: "jobOrderName", |
|
|
|
type: "text", |
|
|
|
} |
|
|
|
]; |
|
|
|
|
|
|
|
const handleDetailClick = useCallback(async (doPickOrder: CompletedDoPickOrder) => { |
|
|
|
setSelectedDoPickOrder(doPickOrder); |
|
|
|
// ✅ 修改:详情点击处理 |
|
|
|
const handleDetailClick = useCallback(async (jobOrderPickOrder: CompletedJobOrderPickOrder) => { |
|
|
|
setSelectedJobOrderPickOrder(jobOrderPickOrder); |
|
|
|
setShowDetailView(true); |
|
|
|
|
|
|
|
// ✅ 修复:使用新的 API 根据 pickOrderId 获取 lot 详情 |
|
|
|
try { |
|
|
|
const lotDetails = await fetchLotDetailsByPickOrderId(doPickOrder.pickOrderId); |
|
|
|
setDetailLotData(lotDetails); |
|
|
|
console.log("✅ Loaded detail lot data for pick order:", doPickOrder.pickOrderCode, lotDetails); |
|
|
|
|
|
|
|
// ✅ 触发打印按钮状态更新 - 基于详情数据 |
|
|
|
const allCompleted = lotDetails.length > 0 && lotDetails.every(lot => |
|
|
|
lot.processingStatus === 'completed' |
|
|
|
); |
|
|
|
|
|
|
|
// ✅ 发送事件,包含标签页信息 |
|
|
|
window.dispatchEvent(new CustomEvent('pickOrderCompletionStatus', { |
|
|
|
detail: { |
|
|
|
allLotsCompleted: allCompleted, |
|
|
|
tabIndex: 2 // ✅ 明确指定这是来自标签页 2 的事件 |
|
|
|
} |
|
|
|
})); |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error("❌ Error loading detail lot data:", error); |
|
|
|
setDetailLotData([]); |
|
|
|
|
|
|
|
// ✅ 如果加载失败,禁用打印按钮 |
|
|
|
window.dispatchEvent(new CustomEvent('pickOrderCompletionStatus', { |
|
|
|
detail: { |
|
|
|
allLotsCompleted: false, |
|
|
|
tabIndex: 2 |
|
|
|
} |
|
|
|
})); |
|
|
|
} |
|
|
|
}, []); |
|
|
|
|
|
|
|
// ✅ 获取 lot 详情数据 |
|
|
|
await fetchLotDetailsData(jobOrderPickOrder.pickOrderId); |
|
|
|
|
|
|
|
// ✅ 触发打印按钮状态更新 - 基于详情数据 |
|
|
|
const allCompleted = jobOrderPickOrder.secondScanCompleted; |
|
|
|
|
|
|
|
// ✅ 发送事件,包含标签页信息 |
|
|
|
window.dispatchEvent(new CustomEvent('pickOrderCompletionStatus', { |
|
|
|
detail: { |
|
|
|
allLotsCompleted: allCompleted, |
|
|
|
tabIndex: 2 // ✅ 明确指定这是来自标签页 2 的事件 |
|
|
|
} |
|
|
|
})); |
|
|
|
|
|
|
|
}, [fetchLotDetailsData]); |
|
|
|
|
|
|
|
// ✅ 返回列表视图 |
|
|
|
// ✅ 修改:返回列表视图 |
|
|
|
const handleBackToList = useCallback(() => { |
|
|
|
setShowDetailView(false); |
|
|
|
setSelectedDoPickOrder(null); |
|
|
|
setSelectedJobOrderPickOrder(null); |
|
|
|
setDetailLotData([]); |
|
|
|
|
|
|
|
// ✅ 返回列表时禁用打印按钮 |
|
|
|
@@ -274,9 +280,8 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
})); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
// ✅ 如果显示详情视图,渲染类似 GoodPickExecution 的表格 |
|
|
|
if (showDetailView && selectedDoPickOrder) { |
|
|
|
// ✅ 修改:如果显示详情视图,渲染 Job Order 详情和 Lot 信息 |
|
|
|
if (showDetailView && selectedJobOrderPickOrder) { |
|
|
|
return ( |
|
|
|
<FormProvider {...formProps}> |
|
|
|
<Box> |
|
|
|
@@ -286,64 +291,166 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
{t("Back to List")} |
|
|
|
</Button> |
|
|
|
<Typography variant="h6"> |
|
|
|
{t("Pick Order Details")}: {selectedDoPickOrder.pickOrderCode} |
|
|
|
{t("Job Order Pick Order Details")}: {selectedJobOrderPickOrder.pickOrderCode} |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
|
|
|
|
{/* FG Pick Orders 信息 */} |
|
|
|
<Box sx={{ mb: 2 }}> |
|
|
|
{selectedDoPickOrder.fgPickOrders.map((fgOrder, index) => ( |
|
|
|
<FGPickOrderCard |
|
|
|
key={index} |
|
|
|
fgOrder={fgOrder} |
|
|
|
onQrCodeClick={() => {}} // 只读模式 |
|
|
|
/> |
|
|
|
))} |
|
|
|
</Box> |
|
|
|
{/* Job Order 信息卡片 */} |
|
|
|
<Card sx={{ mb: 2 }}> |
|
|
|
<CardContent> |
|
|
|
<Stack direction="row" spacing={4} useFlexGap flexWrap="wrap"> |
|
|
|
<Typography variant="subtitle1"> |
|
|
|
<strong>{t("Pick Order Code")}:</strong> {selectedJobOrderPickOrder.pickOrderCode} |
|
|
|
</Typography> |
|
|
|
<Typography variant="subtitle1"> |
|
|
|
<strong>{t("Job Order Code")}:</strong> {selectedJobOrderPickOrder.jobOrderCode} |
|
|
|
</Typography> |
|
|
|
<Typography variant="subtitle1"> |
|
|
|
<strong>{t("Job Order Item Name")}:</strong> {selectedJobOrderPickOrder.jobOrderName} |
|
|
|
</Typography> |
|
|
|
<Typography variant="subtitle1"> |
|
|
|
<strong>{t("Target Date")}:</strong> {selectedJobOrderPickOrder.pickOrderTargetDate} |
|
|
|
</Typography> |
|
|
|
</Stack> |
|
|
|
|
|
|
|
<Stack direction="row" spacing={4} useFlexGap flexWrap="wrap" sx={{ mt: 2 }}> |
|
|
|
<Typography variant="subtitle1"> |
|
|
|
<strong>{t("Required Qty")}:</strong> {selectedJobOrderPickOrder.reqQty} {selectedJobOrderPickOrder.uom} |
|
|
|
</Typography> |
|
|
|
|
|
|
|
</Stack> |
|
|
|
</CardContent> |
|
|
|
</Card> |
|
|
|
|
|
|
|
{/* 类似 GoodPickExecution 的表格 */} |
|
|
|
<TableContainer component={Paper}> |
|
|
|
<Table> |
|
|
|
<TableHead> |
|
|
|
<TableRow> |
|
|
|
<TableCell>{t("Pick Order Code")}</TableCell> |
|
|
|
<TableCell>{t("Item Code")}</TableCell> |
|
|
|
<TableCell>{t("Item Name")}</TableCell> |
|
|
|
<TableCell>{t("Lot No")}</TableCell> |
|
|
|
<TableCell>{t("Location")}</TableCell> |
|
|
|
<TableCell>{t("Required Qty")}</TableCell> |
|
|
|
<TableCell>{t("Actual Pick Qty")}</TableCell> |
|
|
|
<TableCell>{t("Submitted Status")}</TableCell> |
|
|
|
</TableRow> |
|
|
|
</TableHead> |
|
|
|
<TableBody> |
|
|
|
{detailLotData.map((lot, index) => ( |
|
|
|
<TableRow key={index}> |
|
|
|
<TableCell>{lot.pickOrderCode}</TableCell> |
|
|
|
<TableCell>{lot.itemCode}</TableCell> |
|
|
|
<TableCell>{lot.itemName}</TableCell> |
|
|
|
<TableCell>{lot.lotNo}</TableCell> |
|
|
|
<TableCell>{lot.location}</TableCell> |
|
|
|
<TableCell>{lot.requiredQty}</TableCell> |
|
|
|
<TableCell>{lot.actualPickQty}</TableCell> |
|
|
|
<TableCell> |
|
|
|
<Chip |
|
|
|
label={lot.processingStatus} |
|
|
|
color={lot.processingStatus === 'completed' ? 'success' : 'default'} |
|
|
|
size="small" |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
))} |
|
|
|
</TableBody> |
|
|
|
</Table> |
|
|
|
</TableContainer> |
|
|
|
{/* ✅ 修改:Lot 详情表格 - 添加复选框列 */} |
|
|
|
<Card> |
|
|
|
<CardContent> |
|
|
|
<Typography variant="h6" gutterBottom> |
|
|
|
{t("Lot Details")} |
|
|
|
</Typography> |
|
|
|
|
|
|
|
{detailLotDataLoading ? ( |
|
|
|
<Box sx={{ display: 'flex', justifyContent: 'center', p: 2 }}> |
|
|
|
<CircularProgress /> |
|
|
|
</Box> |
|
|
|
) : ( |
|
|
|
<TableContainer component={Paper}> |
|
|
|
<Table> |
|
|
|
<TableHead> |
|
|
|
<TableRow> |
|
|
|
<TableCell>{t("Index")}</TableCell> |
|
|
|
<TableCell>{t("Route")}</TableCell> |
|
|
|
<TableCell>{t("Item Code")}</TableCell> |
|
|
|
<TableCell>{t("Item Name")}</TableCell> |
|
|
|
<TableCell>{t("Lot No")}</TableCell> |
|
|
|
<TableCell>{t("Location")}</TableCell> |
|
|
|
<TableCell align="right">{t("Required Qty")}</TableCell> |
|
|
|
<TableCell align="right">{t("Actual Pick Qty")}</TableCell> |
|
|
|
<TableCell align="center">{t("Processing Status")}</TableCell> |
|
|
|
<TableCell align="center">{t("Second Scan Status")}</TableCell> |
|
|
|
</TableRow> |
|
|
|
</TableHead> |
|
|
|
<TableBody> |
|
|
|
{detailLotData.length === 0 ? ( |
|
|
|
<TableRow> |
|
|
|
<TableCell colSpan={10} align="center"> {/* ✅ 恢复原来的 colSpan */} |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{t("No lot details available")} |
|
|
|
</Typography> |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
) : ( |
|
|
|
detailLotData.map((lot, index) => ( |
|
|
|
<TableRow key={lot.lotId}> |
|
|
|
<TableCell> |
|
|
|
<Typography variant="body2" fontWeight="bold"> |
|
|
|
{index + 1} |
|
|
|
</Typography> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<Typography variant="body2"> |
|
|
|
{lot.routerRoute || '-'} |
|
|
|
</Typography> |
|
|
|
</TableCell> |
|
|
|
<TableCell>{lot.itemCode}</TableCell> |
|
|
|
<TableCell>{lot.itemName}</TableCell> |
|
|
|
<TableCell>{lot.lotNo}</TableCell> |
|
|
|
<TableCell>{lot.location}</TableCell> |
|
|
|
<TableCell align="right"> |
|
|
|
{lot.requiredQty?.toLocaleString() || 0} ({lot.uomShortDesc}) |
|
|
|
</TableCell> |
|
|
|
<TableCell align="right"> |
|
|
|
{lot.actualPickQty?.toLocaleString() || 0} ({lot.uomShortDesc}) |
|
|
|
</TableCell> |
|
|
|
{/* ✅ 修改:Processing Status 使用复选框 */} |
|
|
|
<TableCell align="center"> |
|
|
|
<Box sx={{ |
|
|
|
display: 'flex', |
|
|
|
justifyContent: 'center', |
|
|
|
alignItems: 'center', |
|
|
|
width: '100%', |
|
|
|
height: '100%' |
|
|
|
}}> |
|
|
|
<Checkbox |
|
|
|
checked={lot.processingStatus === 'completed'} |
|
|
|
disabled={true} |
|
|
|
readOnly={true} |
|
|
|
size="large" |
|
|
|
sx={{ |
|
|
|
color: lot.processingStatus === 'completed' ? 'success.main' : 'grey.400', |
|
|
|
'&.Mui-checked': { |
|
|
|
color: 'success.main', |
|
|
|
}, |
|
|
|
transform: 'scale(1.3)', |
|
|
|
'& .MuiSvgIcon-root': { |
|
|
|
fontSize: '1.5rem', |
|
|
|
} |
|
|
|
}} |
|
|
|
/> |
|
|
|
</Box> |
|
|
|
</TableCell> |
|
|
|
{/* ✅ 修改:Second Scan Status 使用复选框 */} |
|
|
|
<TableCell align="center"> |
|
|
|
<Box sx={{ |
|
|
|
display: 'flex', |
|
|
|
justifyContent: 'center', |
|
|
|
alignItems: 'center', |
|
|
|
width: '100%', |
|
|
|
height: '100%' |
|
|
|
}}> |
|
|
|
<Checkbox |
|
|
|
checked={lot.secondQrScanStatus === 'completed'} |
|
|
|
disabled={true} |
|
|
|
readOnly={true} |
|
|
|
size="large" |
|
|
|
sx={{ |
|
|
|
color: lot.secondQrScanStatus === 'completed' ? 'success.main' : 'grey.400', |
|
|
|
'&.Mui-checked': { |
|
|
|
color: 'success.main', |
|
|
|
}, |
|
|
|
transform: 'scale(1.3)', |
|
|
|
'& .MuiSvgIcon-root': { |
|
|
|
fontSize: '1.5rem', |
|
|
|
} |
|
|
|
}} |
|
|
|
/> |
|
|
|
</Box> |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
)) |
|
|
|
)} |
|
|
|
</TableBody> |
|
|
|
</Table> |
|
|
|
</TableContainer> |
|
|
|
)} |
|
|
|
</CardContent> |
|
|
|
</Card> |
|
|
|
</Box> |
|
|
|
</FormProvider> |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ 默认列表视图 |
|
|
|
// ✅ 修改:默认列表视图 |
|
|
|
return ( |
|
|
|
<FormProvider {...formProps}> |
|
|
|
<Box> |
|
|
|
@@ -357,7 +464,7 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
</Box> |
|
|
|
|
|
|
|
{/* 加载状态 */} |
|
|
|
{completedDoPickOrdersLoading ? ( |
|
|
|
{completedJobOrderPickOrdersLoading ? ( |
|
|
|
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}> |
|
|
|
<CircularProgress /> |
|
|
|
</Box> |
|
|
|
@@ -365,50 +472,59 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
<Box> |
|
|
|
{/* 结果统计 */} |
|
|
|
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}> |
|
|
|
{t("Total")}: {filteredDoPickOrders.length} {t("completed DO pick orders")} |
|
|
|
{t("Total")}: {filteredJobOrderPickOrders.length} {t("completed Job Order pick orders with matching")} |
|
|
|
</Typography> |
|
|
|
|
|
|
|
{/* 列表 */} |
|
|
|
{filteredDoPickOrders.length === 0 ? ( |
|
|
|
{filteredJobOrderPickOrders.length === 0 ? ( |
|
|
|
<Box sx={{ p: 3, textAlign: 'center' }}> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{t("No completed DO pick orders found")} |
|
|
|
{t("No completed Job Order pick orders with matching found")} |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
) : ( |
|
|
|
<Stack spacing={2}> |
|
|
|
{paginatedData.map((doPickOrder) => ( |
|
|
|
<Card key={doPickOrder.id}> |
|
|
|
{paginatedData.map((jobOrderPickOrder) => ( |
|
|
|
<Card key={jobOrderPickOrder.id}> |
|
|
|
<CardContent> |
|
|
|
<Stack direction="row" justifyContent="space-between" alignItems="center"> |
|
|
|
<Box> |
|
|
|
<Typography variant="h6"> |
|
|
|
{doPickOrder.pickOrderCode} |
|
|
|
{jobOrderPickOrder.pickOrderCode} |
|
|
|
</Typography> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{jobOrderPickOrder.jobOrderName} - {jobOrderPickOrder.jobOrderCode} |
|
|
|
</Typography> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{doPickOrder.shopName} - {doPickOrder.deliveryNo} |
|
|
|
{t("Completed")}: {new Date(jobOrderPickOrder.completedDate).toLocaleString()} |
|
|
|
</Typography> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{t("Completed")}: {new Date(doPickOrder.completedDate).toLocaleString()} |
|
|
|
{t("Target Date")}: {jobOrderPickOrder.pickOrderTargetDate} |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
<Box> |
|
|
|
<Chip |
|
|
|
label={doPickOrder.pickOrderStatus} |
|
|
|
color={doPickOrder.pickOrderStatus === 'completed' ? 'success' : 'default'} |
|
|
|
label={jobOrderPickOrder.pickOrderStatus} |
|
|
|
color={jobOrderPickOrder.pickOrderStatus === 'completed' ? 'success' : 'default'} |
|
|
|
size="small" |
|
|
|
sx={{ mb: 1 }} |
|
|
|
/> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{doPickOrder.fgPickOrders.length} {t("FG orders")} |
|
|
|
{jobOrderPickOrder.completedItems}/{jobOrderPickOrder.totalItems} {t("items completed")} |
|
|
|
</Typography> |
|
|
|
<Chip |
|
|
|
label={jobOrderPickOrder.secondScanCompleted ? t("Second Scan Completed") : t("Second Scan Pending")} |
|
|
|
color={jobOrderPickOrder.secondScanCompleted ? 'success' : 'warning'} |
|
|
|
size="small" |
|
|
|
sx={{ mt: 1 }} |
|
|
|
/> |
|
|
|
</Box> |
|
|
|
</Stack> |
|
|
|
</CardContent> |
|
|
|
<CardActions> |
|
|
|
<Button |
|
|
|
variant="outlined" |
|
|
|
onClick={() => handleDetailClick(doPickOrder)} |
|
|
|
onClick={() => handleDetailClick(jobOrderPickOrder)} |
|
|
|
> |
|
|
|
{t("View Details")} |
|
|
|
</Button> |
|
|
|
@@ -419,10 +535,10 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
)} |
|
|
|
|
|
|
|
{/* 分页 */} |
|
|
|
{filteredDoPickOrders.length > 0 && ( |
|
|
|
{filteredJobOrderPickOrders.length > 0 && ( |
|
|
|
<TablePagination |
|
|
|
component="div" |
|
|
|
count={filteredDoPickOrders.length} |
|
|
|
count={filteredJobOrderPickOrders.length} |
|
|
|
page={paginationController.pageNum} |
|
|
|
rowsPerPage={paginationController.pageSize} |
|
|
|
onPageChange={handlePageChange} |
|
|
|
|