FPSMS-frontend
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

720 行
22 KiB

  1. "use client";
  2. import { PickOrderResult } from "@/app/api/pickOrder";
  3. import { useCallback, useEffect, useMemo, useState } from "react";
  4. import { useTranslation } from "react-i18next";
  5. import SearchBox, { Criterion } from "../SearchBox";
  6. import {
  7. flatten,
  8. intersectionWith,
  9. isEmpty,
  10. sortBy,
  11. uniqBy,
  12. upperCase,
  13. upperFirst,
  14. } from "lodash";
  15. import {
  16. arrayToDayjs,
  17. } from "@/app/utils/formatUtil";
  18. import { Button, Grid, Stack, Tab, Tabs, TabsProps, Typography, Box, TextField } from "@mui/material";
  19. import PickOrders from "./FinishedGood";
  20. import ConsolidatedPickOrders from "./ConsolidatedPickOrders";
  21. import PickExecution from "./GoodPickExecution";
  22. import CreatePickOrderModal from "./CreatePickOrderModal";
  23. import NewCreateItem from "./newcreatitem";
  24. import AssignAndRelease from "./AssignAndRelease";
  25. import AssignTo from "./assignTo";
  26. import { fetchAllItemsInClient, ItemCombo } from "@/app/api/settings/item/actions";
  27. import { fetchPickOrderClient, autoAssignAndReleasePickOrder, autoAssignAndReleasePickOrderByStore, fetchReleasedDoPickOrders } from "@/app/api/pickOrder/actions";
  28. import Jobcreatitem from "./Jobcreatitem";
  29. import { useSession } from "next-auth/react";
  30. import { SessionWithTokens } from "@/config/authConfig";
  31. import PickExecutionDetail from "./GoodPickExecutiondetail";
  32. import GoodPickExecutionRecord from "./GoodPickExecutionRecord";
  33. import Swal from "sweetalert2";
  34. import { printDN, printDNLabels } from "@/app/api/do/actions";
  35. import { FGPickOrderResponse, fetchStoreLaneSummary, assignByLane,type StoreLaneSummary } from "@/app/api/pickOrder/actions";
  36. import FGPickOrderCard from "./FGPickOrderCard";
  37. import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
  38. import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
  39. import { DatePicker } from '@mui/x-date-pickers/DatePicker';
  40. import dayjs, { Dayjs } from 'dayjs';
  41. import { PrinterCombo } from "@/app/api/settings/printer";
  42. import { Autocomplete } from "@mui/material";
  43. import FGPickOrderTicketReleaseTable from "./FGPickOrderTicketReleaseTable";
  44. interface Props {
  45. pickOrders: PickOrderResult[];
  46. printerCombo: PrinterCombo[];
  47. }
  48. type SearchQuery = Partial<
  49. Omit<PickOrderResult, "id" | "consoCode" | "completeDate">
  50. >;
  51. type SearchParamNames = keyof SearchQuery;
  52. const PickOrderSearch: React.FC<Props> = ({ pickOrders, printerCombo }) => {
  53. const { t } = useTranslation("pickOrder");
  54. const { data: session } = useSession() as { data: SessionWithTokens | null };
  55. const currentUserId = session?.id ? parseInt(session.id) : undefined;
  56. const [isOpenCreateModal, setIsOpenCreateModal] = useState(false)
  57. const [items, setItems] = useState<ItemCombo[]>([])
  58. const [printButtonsEnabled, setPrintButtonsEnabled] = useState(false);
  59. const [filteredPickOrders, setFilteredPickOrders] = useState(pickOrders);
  60. const [filterArgs, setFilterArgs] = useState<Record<string, any>>({});
  61. const [searchQuery, setSearchQuery] = useState<Record<string, any>>({});
  62. const [tabIndex, setTabIndex] = useState(0);
  63. const [totalCount, setTotalCount] = useState<number>();
  64. const [isAssigning, setIsAssigning] = useState(false);
  65. // const [summary2F, setSummary2F] = useState<StoreLaneSummary | null>(null);
  66. // const [summary4F, setSummary4F] = useState<StoreLaneSummary | null>(null);
  67. const [isLoadingSummary, setIsLoadingSummary] = useState(false);
  68. const [selectedPrinterForAllDraft, setSelectedPrinterForAllDraft] = useState<PrinterCombo | null>(null);
  69. const [selectedPrinterForDraft, setSelectedPrinterForDraft] = useState<PrinterCombo | null>(null);
  70. const [selectedPrinterForRecord, setSelectedPrinterForRecord] = useState<PrinterCombo | null>(null);
  71. const [hideCompletedUntilNext, setHideCompletedUntilNext] = useState<boolean>(
  72. typeof window !== 'undefined' && localStorage.getItem('hideCompletedUntilNext') === 'true'
  73. );
  74. const [fgPickOrdersData, setFgPickOrdersData] = useState<FGPickOrderResponse[]>([]);
  75. const [releasedOrderCount, setReleasedOrderCount] = useState<number>(0);
  76. const fetchReleasedOrderCount = useCallback(async () => {
  77. try {
  78. const releasedOrders = await fetchReleasedDoPickOrders();
  79. const validCount = releasedOrders.length;
  80. setReleasedOrderCount(validCount);
  81. } catch (error) {
  82. console.error("Error fetching released order count:", error);
  83. setReleasedOrderCount(0);
  84. }
  85. }, []);
  86. /*
  87. const loadSummaries = useCallback(async () => {
  88. setIsLoadingSummary(true);
  89. try {
  90. const [s2, s4] = await Promise.all([
  91. fetchStoreLaneSummary("2/F"),
  92. fetchStoreLaneSummary("4/F")
  93. ]);
  94. setSummary2F(s2);
  95. setSummary4F(s4);
  96. } catch (error) {
  97. console.error("Error loading summaries:", error);
  98. } finally {
  99. setIsLoadingSummary(false);
  100. }
  101. }, []);
  102. useEffect(() => {
  103. loadSummaries();
  104. // 每30秒刷新一次
  105. }, [loadSummaries]);
  106. */
  107. const handleDraft = useCallback(async () =>{
  108. try{
  109. if (fgPickOrdersData.length === 0) {
  110. console.error("No FG Pick order data available");
  111. Swal.fire({
  112. title: "",
  113. text: t("Please take one pick order before printing the draft."),
  114. icon: "info"
  115. })
  116. return;
  117. }
  118. if (!selectedPrinterForDraft) {
  119. Swal.fire({
  120. position: "bottom-end",
  121. icon: "warning",
  122. text: t("Please select a printer first"),
  123. showConfirmButton: false,
  124. timer: 1500
  125. });
  126. return;
  127. }
  128. const currentFgOrder = fgPickOrdersData[0];
  129. const printRequest = {
  130. printerId: selectedPrinterForDraft.id,
  131. printQty: 1,
  132. isDraft: true,
  133. numOfCarton: 0,
  134. doPickOrderId: currentFgOrder.doPickOrderId
  135. };
  136. console.log("Printing draft with request: ", printRequest);
  137. const response = await printDN(printRequest);
  138. console.log("Print Draft response: ", response);
  139. if(response.success){
  140. Swal.fire({
  141. position: "bottom-end",
  142. icon: "success",
  143. text: t("Printed Successfully."),
  144. showConfirmButton: false,
  145. timer: 1500
  146. });
  147. } else {
  148. console.error("Print failed: ", response.message);
  149. Swal.fire({
  150. title: "",
  151. text: t("Please take one pick order before printing the draft."),
  152. icon: "info"
  153. })
  154. }
  155. } catch(error){
  156. console.error("error: ", error)
  157. }
  158. },[t, fgPickOrdersData, selectedPrinterForDraft]);
  159. const handleAllDraft = useCallback(async () =>{
  160. try {
  161. const releasedOrders = await fetchReleasedDoPickOrders();
  162. console.log('fgPickOrdersData length:' + releasedOrders.length)
  163. if (!selectedPrinterForAllDraft) {
  164. Swal.fire({
  165. position: "bottom-end",
  166. icon: "warning",
  167. text: t("Please select a printer first"),
  168. showConfirmButton: false,
  169. timer: 1500
  170. });
  171. return;
  172. }
  173. if(releasedOrders.length === 0) {
  174. console.log("No released do_pick_order records found");
  175. Swal.fire({
  176. title: "",
  177. text: t("No released pick order records found."),
  178. icon: "info"
  179. })
  180. return;
  181. }
  182. console.log("Found released orders:", releasedOrders);
  183. const confirmResult = await Swal.fire({
  184. title: t("Batch Print"),
  185. text: t("Confirm print: (") + releasedOrders.length.toString() + t("piece(s))"),
  186. icon: "question",
  187. showCancelButton: true,
  188. confirmButtonText: t("Confirm"),
  189. cancelButtonText: t("Cancel"),
  190. confirmButtonColor: "#8dba00",
  191. cancelButtonColor: "#F04438"
  192. });
  193. if (!confirmResult.isConfirmed) {
  194. return;
  195. }
  196. Swal.fire({
  197. title: t("Printing..."),
  198. text: t("Please wait..."),
  199. allowOutsideClick: false,
  200. allowEscapeKey: false,
  201. didOpen: () => {
  202. Swal.showLoading();
  203. }
  204. });
  205. for (const order of releasedOrders) {
  206. const doPickOrderId = order.id
  207. console.log(`Processing order - DoPickOrder ID: ${doPickOrderId}, Ticket No: ${order.ticketNo}`);
  208. const printRequest = {
  209. printerId: selectedPrinterForAllDraft.id,
  210. printQty: 1,
  211. isDraft: true,
  212. numOfCarton: 0,
  213. doPickOrderId: doPickOrderId
  214. };
  215. console.log("Printing draft with request:", printRequest)
  216. const response = await printDN(printRequest);
  217. if(!response.success) {
  218. console.error(`Print failed for order ${order.ticketNo}:`, response.message);
  219. }
  220. }
  221. Swal.fire({
  222. position: "bottom-end",
  223. icon: "success",
  224. text: t("Printed Successfully."),
  225. showConfirmButton: false,
  226. timer: 1500
  227. });
  228. } catch(error){
  229. console.error("Error in handleAllDraft:",error);
  230. }
  231. },[t, fgPickOrdersData, selectedPrinterForAllDraft]);
  232. useEffect(() => {
  233. fetchReleasedOrderCount();
  234. }, [fetchReleasedOrderCount]);
  235. useEffect(() => {
  236. const onAssigned = () => {
  237. localStorage.removeItem('hideCompletedUntilNext');
  238. setHideCompletedUntilNext(false);
  239. // loadSummaries();
  240. };
  241. window.addEventListener('pickOrderAssigned', onAssigned);
  242. return () => window.removeEventListener('pickOrderAssigned', onAssigned);
  243. }, []);
  244. // ... existing code ...
  245. useEffect(() => {
  246. const handleCompletionStatusChange = (event: CustomEvent) => {
  247. const { allLotsCompleted, tabIndex: eventTabIndex } = event.detail;
  248. // ✅ 修复:根据标签页和事件来源决定是否更新打印按钮状态
  249. if (eventTabIndex === undefined || eventTabIndex === tabIndex) {
  250. setPrintButtonsEnabled(allLotsCompleted);
  251. console.log(`Print buttons enabled for tab ${tabIndex}:`, allLotsCompleted);
  252. }
  253. };
  254. window.addEventListener('pickOrderCompletionStatus', handleCompletionStatusChange as EventListener);
  255. return () => {
  256. window.removeEventListener('pickOrderCompletionStatus', handleCompletionStatusChange as EventListener);
  257. };
  258. }, [tabIndex]); // ✅ 添加 tabIndex 依赖
  259. // ✅ 新增:处理标签页切换时的打印按钮状态重置
  260. useEffect(() => {
  261. // 当切换到标签页 2 (GoodPickExecutionRecord) 时,重置打印按钮状态
  262. if (tabIndex === 2) {
  263. setPrintButtonsEnabled(false);
  264. console.log("Reset print buttons for Pick Execution Record tab");
  265. }
  266. }, [tabIndex]);
  267. /*
  268. // ... existing code ...
  269. const handleAssignByLane = useCallback(async (
  270. storeId: string,
  271. truckDepartureTime: string,
  272. truckLanceCode: string
  273. ) => {
  274. if (!currentUserId) {
  275. console.error("Missing user id in session");
  276. return;
  277. }
  278. setIsAssigning(true);
  279. try {
  280. const res = await assignByLane(currentUserId, storeId, truckLanceCode, truckDepartureTime);
  281. if (res.code === "SUCCESS") {
  282. console.log("✅ Successfully assigned pick order from lane", truckLanceCode);
  283. window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
  284. loadSummaries(); // 刷新按钮状态
  285. } else if (res.code === "USER_BUSY") {
  286. Swal.fire({
  287. icon: "warning",
  288. title: t("Warning"),
  289. text: t("You already have a pick order in progess. Please complete it first before taking next pick order."),
  290. confirmButtonText: t("Confirm"),
  291. confirmButtonColor: "#8dba00"
  292. });
  293. window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
  294. } else if (res.code === "NO_ORDERS") {
  295. Swal.fire({
  296. icon: "info",
  297. title: t("Info"),
  298. text: t("No available pick order(s) for this lane."),
  299. confirmButtonText: t("Confirm"),
  300. confirmButtonColor: "#8dba00"
  301. });
  302. } else {
  303. console.log("ℹ️ Assignment result:", res.message);
  304. }
  305. } catch (error) {
  306. console.error("❌ Error assigning by lane:", error);
  307. Swal.fire({
  308. icon: "error",
  309. title: t("Error"),
  310. text: t("Error occurred during assignment."),
  311. confirmButtonText: t("Confirm"),
  312. confirmButtonColor: "#8dba00"
  313. });
  314. } finally {
  315. setIsAssigning(false);
  316. }
  317. }, [currentUserId, t, loadSummaries]);
  318. // ✅ Manual assignment handler - uses the action function
  319. */
  320. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  321. (_e, newValue) => {
  322. setTabIndex(newValue);
  323. },
  324. [],
  325. );
  326. const handleSwitchToDetailTab = useCallback(() => {
  327. setTabIndex(1);
  328. }, []);
  329. const handleSwtitchToRecordTab = useCallback(() =>{
  330. setTabIndex(2);
  331. }, []);
  332. const openCreateModal = useCallback(async () => {
  333. console.log("testing")
  334. const res = await fetchAllItemsInClient()
  335. console.log(res)
  336. setItems(res)
  337. setIsOpenCreateModal(true)
  338. }, [])
  339. const closeCreateModal = useCallback(() => {
  340. setIsOpenCreateModal(false)
  341. }, [])
  342. useEffect(() => {
  343. if (tabIndex === 3) {
  344. const loadItems = async () => {
  345. try {
  346. const itemsData = await fetchAllItemsInClient();
  347. console.log("PickOrderSearch loaded items:", itemsData.length);
  348. setItems(itemsData);
  349. } catch (error) {
  350. console.error("Error loading items in PickOrderSearch:", error);
  351. }
  352. };
  353. // 如果还没有数据,则加载
  354. if (items.length === 0) {
  355. loadItems();
  356. }
  357. }
  358. }, [tabIndex, items.length]);
  359. useEffect(() => {
  360. const handleCompletionStatusChange = (event: CustomEvent) => {
  361. const { allLotsCompleted } = event.detail;
  362. setPrintButtonsEnabled(allLotsCompleted);
  363. console.log("Print buttons enabled:", allLotsCompleted);
  364. };
  365. window.addEventListener('pickOrderCompletionStatus', handleCompletionStatusChange as EventListener);
  366. return () => {
  367. window.removeEventListener('pickOrderCompletionStatus', handleCompletionStatusChange as EventListener);
  368. };
  369. }, []);
  370. const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
  371. () => {
  372. const baseCriteria: Criterion<SearchParamNames>[] = [
  373. {
  374. label: tabIndex === 3 ? t("Item Code") : t("Code"),
  375. paramName: "code",
  376. type: "text"
  377. },
  378. {
  379. label: t("Type"),
  380. paramName: "type",
  381. type: "autocomplete",
  382. options: tabIndex === 3
  383. ?
  384. [
  385. { value: "Consumable", label: t("Consumable") },
  386. { value: "Material", label: t("Material") },
  387. { value: "Product", label: t("Product") }
  388. ]
  389. :
  390. sortBy(
  391. uniqBy(
  392. pickOrders.map((po) => ({
  393. value: po.type,
  394. label: t(upperCase(po.type)),
  395. })),
  396. "value",
  397. ),
  398. "label",
  399. ),
  400. },
  401. ];
  402. // Add Job Order search for Create Item tab (tabIndex === 3)
  403. if (tabIndex === 3) {
  404. baseCriteria.splice(1, 0, {
  405. label: t("Job Order"),
  406. paramName: "jobOrderCode" as any, // Type assertion for now
  407. type: "text",
  408. });
  409. baseCriteria.splice(2, 0, {
  410. label: t("Target Date"),
  411. paramName: "targetDate",
  412. type: "date",
  413. });
  414. } else {
  415. baseCriteria.splice(1, 0, {
  416. label: t("Target Date From"),
  417. label2: t("Target Date To"),
  418. paramName: "targetDate",
  419. type: "dateRange",
  420. });
  421. }
  422. // Add Items/Item Name criteria
  423. baseCriteria.push({
  424. label: tabIndex === 3 ? t("Item Name") : t("Items"),
  425. paramName: "items",
  426. type: tabIndex === 3 ? "text" : "autocomplete",
  427. options: tabIndex === 3
  428. ? []
  429. :
  430. uniqBy(
  431. flatten(
  432. sortBy(
  433. pickOrders.map((po) =>
  434. po.items
  435. ? po.items.map((item) => ({
  436. value: item.name,
  437. label: item.name,
  438. }))
  439. : [],
  440. ),
  441. "label",
  442. ),
  443. ),
  444. "value",
  445. ),
  446. });
  447. // Add Status criteria for non-Create Item tabs
  448. if (tabIndex !== 3) {
  449. baseCriteria.push({
  450. label: t("Status"),
  451. paramName: "status",
  452. type: "autocomplete",
  453. options: sortBy(
  454. uniqBy(
  455. pickOrders.map((po) => ({
  456. value: po.status,
  457. label: t(upperFirst(po.status)),
  458. })),
  459. "value",
  460. ),
  461. "label",
  462. ),
  463. });
  464. }
  465. return baseCriteria;
  466. },
  467. [pickOrders, t, tabIndex, items],
  468. );
  469. const fetchNewPagePickOrder = useCallback(
  470. async (
  471. pagingController: Record<string, number>,
  472. filterArgs: Record<string, number>,
  473. ) => {
  474. const params = {
  475. ...pagingController,
  476. ...filterArgs,
  477. };
  478. const res = await fetchPickOrderClient(params);
  479. if (res) {
  480. console.log(res);
  481. setFilteredPickOrders(res.records);
  482. setTotalCount(res.total);
  483. }
  484. },
  485. [],
  486. );
  487. const onReset = useCallback(() => {
  488. setFilteredPickOrders(pickOrders);
  489. }, [pickOrders]);
  490. useEffect(() => {
  491. if (!isOpenCreateModal) {
  492. setTabIndex(1)
  493. setTimeout(async () => {
  494. setTabIndex(0)
  495. }, 200)
  496. }
  497. }, [isOpenCreateModal])
  498. // 添加处理提料单创建成功的函数
  499. const handlePickOrderCreated = useCallback(() => {
  500. // 切换到 Assign & Release 标签页 (tabIndex = 1)
  501. setTabIndex(2);
  502. }, []);
  503. return (
  504. <Box sx={{
  505. // Full viewport height
  506. overflow: 'auto' // Single scrollbar for the whole page
  507. }}>
  508. {/* Header section */}
  509. <Box
  510. sx={{
  511. p: 1,
  512. borderBottom: '1px solid #e0e0e0',
  513. minHeight: 'auto',
  514. display: 'flex',
  515. alignItems: 'center',
  516. justifyContent: 'space-between', // 左标题,右控件
  517. gap: 2,
  518. flexWrap: 'wrap', // 如果屏幕窄就自动换行
  519. }}
  520. >
  521. {/* 左侧标题 */}
  522. <Typography
  523. variant="h5"
  524. sx={{
  525. lineHeight: 1.4,
  526. m: 0,
  527. fontWeight: 500,
  528. }}
  529. >
  530. {t("Finished Good Order")}
  531. </Typography>
  532. {/* 右侧:打印机 + 按钮 */}
  533. <Stack
  534. direction="row"
  535. spacing={2}
  536. sx={{
  537. alignItems: 'center',
  538. flexWrap: 'wrap', // 控件太多时换行,不会撑出横向滚动
  539. rowGap: 1,
  540. }}
  541. >
  542. <Typography variant="body2" sx={{ minWidth: 'fit-content', mr: 1.5 }}>
  543. {t("A4 Printer")}:
  544. </Typography>
  545. <Autocomplete
  546. options={printerCombo || []}
  547. getOptionLabel={(option) =>
  548. option.name || option.label || option.code || `Printer ${option.id}`
  549. }
  550. value={selectedPrinterForAllDraft}
  551. onChange={(_, newValue) => setSelectedPrinterForAllDraft(newValue)}
  552. sx={{ minWidth: 200 }}
  553. size="small"
  554. renderInput={(params) => (
  555. <TextField {...params} placeholder={t("A4 Printer")} />
  556. )}
  557. />
  558. <Typography variant="body2" sx={{ minWidth: 'fit-content', ml: 1 }}>
  559. {t("Label Printer")}:
  560. </Typography>
  561. <Autocomplete
  562. options={printerCombo || []}
  563. getOptionLabel={(option) =>
  564. option.name || option.label || option.code || `Printer ${option.id}`
  565. }
  566. value={selectedPrinterForDraft}
  567. onChange={(_, newValue) => setSelectedPrinterForDraft(newValue)}
  568. sx={{ minWidth: 200 }}
  569. size="small"
  570. renderInput={(params) => (
  571. <TextField {...params} placeholder={t("Label Printer")} />
  572. )}
  573. />
  574. <Button
  575. variant="contained"
  576. sx={{
  577. py: 0.5,
  578. px: 1.25,
  579. height: '40px',
  580. fontSize: '0.75rem',
  581. lineHeight: 1.2,
  582. display: 'flex',
  583. alignItems: 'center',
  584. justifyContent: 'center',
  585. '&.Mui-disabled': {
  586. height: '40px',
  587. },
  588. }}
  589. onClick={handleAllDraft}
  590. >
  591. {t("Print All Draft")} ({releasedOrderCount})
  592. </Button>
  593. <Button
  594. variant="contained"
  595. sx={{
  596. py: 0.5,
  597. px: 1.25,
  598. height: '40px',
  599. fontSize: '0.75rem',
  600. lineHeight: 1.2,
  601. display: 'flex',
  602. alignItems: 'center',
  603. justifyContent: 'center',
  604. '&.Mui-disabled': {
  605. height: '40px',
  606. },
  607. }}
  608. title={!printButtonsEnabled ? t("All lots must be completed before printing") : ""}
  609. onClick={handleDraft}
  610. >
  611. {t("Print Draft")}
  612. </Button>
  613. </Stack>
  614. </Box>
  615. {/* Tabs section - ✅ Move the click handler here */}
  616. <Box sx={{
  617. borderBottom: '1px solid #e0e0e0'
  618. }}>
  619. <Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable">
  620. <Tab label={t("Pick Order Detail")} iconPosition="end" />
  621. <Tab label={t("Finished Good Detail")} iconPosition="end" />
  622. <Tab label={t("Finished Good Record")} iconPosition="end" />
  623. <Tab label={t("Ticket Release Table")} iconPosition="end" />
  624. </Tabs>
  625. </Box>
  626. {/* Content section - NO overflow: 'auto' here */}
  627. <Box sx={{ p: 2 }}>
  628. {tabIndex === 0 && (
  629. <PickExecution
  630. filterArgs={filterArgs}
  631. onFgPickOrdersChange={setFgPickOrdersData}
  632. onSwitchToDetailTab={handleSwitchToDetailTab}
  633. />
  634. )}
  635. {tabIndex === 1 && (
  636. <PickExecutionDetail
  637. filterArgs={filterArgs}
  638. onSwitchToRecordTab={handleSwtitchToRecordTab}
  639. onRefreshReleasedOrderCount={fetchReleasedOrderCount}
  640. />
  641. ) }
  642. {tabIndex === 2 && <GoodPickExecutionRecord filterArgs={filterArgs} printerCombo={printerCombo} a4Printer={selectedPrinterForAllDraft} labelPrinter={selectedPrinterForDraft} />}
  643. {tabIndex === 3 && <FGPickOrderTicketReleaseTable/>}
  644. </Box>
  645. </Box>
  646. );
  647. };
  648. export default PickOrderSearch;