Browse Source

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx
master
CANCERYS\kw093 1 month ago
parent
commit
6967adf3ea
12 changed files with 242 additions and 99 deletions
  1. +1
    -1
      src/app/(main)/finishedGood/detail/page.tsx
  2. +1
    -1
      src/app/(main)/finishedGood/page.tsx
  3. +37
    -8
      src/app/api/do/actions.tsx
  4. +1
    -0
      src/app/api/pickOrder/actions.ts
  5. +72
    -21
      src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx
  6. +48
    -30
      src/components/FinishedGoodSearch/FinishedGoodFloorLanePanel.tsx
  7. +22
    -7
      src/components/FinishedGoodSearch/FinishedGoodSearch.tsx
  8. +4
    -0
      src/components/FinishedGoodSearch/GoodPickExecutionForm.tsx
  9. +13
    -26
      src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx
  10. +11
    -3
      src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx
  11. +3
    -2
      src/i18n/zh/pickOrder.json
  12. +29
    -0
      src/i18n/zh/ticketReleaseTable.json

+ 1
- 1
src/app/(main)/finishedGood/detail/page.tsx View File

@@ -18,7 +18,7 @@ const PickOrder: React.FC<Props> = async ({ searchParams }) => {

return (
<>
<I18nProvider namespaces={["pickOrder", "common"]}>
<I18nProvider namespaces={["pickOrder", "common", "ticketReleaseTable"]}>
<Suspense fallback={<FinishedGoodSearchWrapper.Loading />}>
<FinishedGoodSearchWrapper />
</Suspense>


+ 1
- 1
src/app/(main)/finishedGood/page.tsx View File

@@ -17,7 +17,7 @@ const PickOrder: React.FC = async () => {

return (
<>
<I18nProvider namespaces={["pickOrder", "common"]}>
<I18nProvider namespaces={["pickOrder", "common", "ticketReleaseTable"]}>
<Suspense fallback={<FinishedGoodSearch.Loading />}>
<FinishedGoodSearch />
</Suspense>


+ 37
- 8
src/app/api/do/actions.tsx View File

@@ -3,7 +3,7 @@ import { BASE_API_URL } from "@/config/api";
// import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
import { revalidateTag } from "next/cache";
import { cache } from "react";
import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
import { serverFetch, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
import { QcItemResult } from "../settings/qcItem";
import { RecordsRes } from "../utils";
import { DoResult } from ".";
@@ -129,11 +129,22 @@ export interface getTicketReleaseTable {
shopName: string | null;
requiredDeliveryDate: string | null;
handlerName: string | null;
numberOfFGItems: number;
}

export const fetchTicketReleaseTable = cache(async ()=> {
export const fetchTicketReleaseTable = cache(async (startDate?: string, endDate?: string) => {
const params = new URLSearchParams();
if (startDate) {
params.append('startDate', startDate);
}
if (endDate) {
params.append('endDate', endDate);
}
const url = `${BASE_API_URL}/doPickOrder/ticket-release-table${params.toString() ? `?${params.toString()}` : ''}`;
return await serverFetchJson<getTicketReleaseTable[]>(
`${BASE_API_URL}/doPickOrder/ticket-release-table`,
url,
{
method: "GET",
}
@@ -226,11 +237,29 @@ export async function printDN(request: PrintDeliveryNoteRequest){
params.append('numOfCarton', request.numOfCarton.toString());
params.append('isDraft', request.isDraft.toString());

const response = await serverFetchWithNoContent(`${BASE_API_URL}/do/print-DN?${params.toString()}`,{
method: "GET",
});
return { success: true, message: "Print job sent successfully (DN)" } as PrintDeliveryNoteResponse;
try {
const response = await serverFetch(`${BASE_API_URL}/do/print-DN?${params.toString()}`, {
method: "GET",
});

if (response.ok) {
return { success: true, message: "Print job sent successfully (DN)" } as PrintDeliveryNoteResponse;
}

const errorText = await response.text();
console.error("Print DN error:", errorText);
return {
success: false,
message: "No data found for this pick order."
} as PrintDeliveryNoteResponse;

} catch (error) {
console.error("Error in printDN:", error);
return {
success: false,
message: "No data found for this pick order."
} as PrintDeliveryNoteResponse;
}
}

export async function printDNLabels(request: PrintDNLabelsRequest){


+ 1
- 0
src/app/api/pickOrder/actions.ts View File

@@ -357,6 +357,7 @@ export interface CompletedDoPickOrderResponse {
storeId: string;
completedDate: string;
fgPickOrders: FGPickOrderResponse[];
deliveryNoteCode: number;
}

// 新增:搜索参数接口


+ 72
- 21
src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx View File

@@ -24,13 +24,15 @@ import {
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs';
import { arrayToDayjs } from '@/app/utils/formatUtil';
import { fetchTicketReleaseTable, getTicketReleaseTable } from '@/app/api/do/actions';
import { time } from 'console';

const FGPickOrderTicketReleaseTable: React.FC = () => {
const { t } = useTranslation("pickOrder");
const { t } = useTranslation("ticketReleaseTable");
const [selectedDate, setSelectedDate] = useState<string>("today");
const [selectedFloor, setSelectedFloor] = useState<string>("");
const [selectedStatus, setSelectedStatus] = useState<string>("released");

const [data, setData] = useState<getTicketReleaseTable[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [paginationController, setPaginationController] = useState({
@@ -62,16 +64,22 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
const formattedMinute = minute.toString().padStart(2, '0');
return `${formattedHour}:${formattedMinute}`;
};

const getDateLabel = (offset: number) => {
return dayjs().add(offset, 'day').format('YYYY-MM-DD');
};

const getDateRange = () => {
const today = dayjs().format('YYYY-MM-DD');
const dayAfterTomorrow = dayjs().add(2, 'day').format('YYYY-MM-DD');
return { startDate: today, endDate: dayAfterTomorrow };
};

useEffect(() => {
const loadData = async () => {
setLoading(true);
try {
const result = await fetchTicketReleaseTable();
const { startDate, endDate } = getDateRange();
const result = await fetchTicketReleaseTable(startDate, endDate);
setData(result);
} catch (error) {
console.error('Error fetching ticket release table:', error);
@@ -99,8 +107,14 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
}
}

// Filter by status if selected
if (selectedStatus && item.ticketStatus?.toLowerCase() !== selectedStatus.toLowerCase()) {
return false;
}


return true;
},[data, selectedDate, selectedFloor]);
},[data, selectedDate, selectedFloor, selectedStatus]);

const handlePageChange = useCallback((event: unknown, newPage: number) => {
setPaginationController(prev => ({
@@ -125,19 +139,18 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {

useEffect(() => {
setPaginationController(prev => ({ ...prev, pageNum: 0 }));
}, [selectedDate, selectedFloor]);
}, [selectedDate, selectedFloor, selectedStatus]);

return (
<Card sx={{ mb: 2 }}>
<CardContent>
{/* Title */}
<Typography variant="h5" sx={{ mb: 3, fontWeight: 600 }}>
Ticket Release Table
{t("Ticket Release Table")}
</Typography>

{/* Dropdown Menus */}
<Stack direction="row" spacing={2} sx={{ mb: 3 }}>
{/* Date Selection Dropdown */}
<FormControl sx={{ minWidth: 250 }} size="small">
<InputLabel id="date-select-label">{t("Select Date")}</InputLabel>
<Select
@@ -174,13 +187,33 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
onChange={(e) => setSelectedFloor(e.target.value)}
displayEmpty
>
<MenuItem value="">
<em>{t("All Floors")}</em>
</MenuItem>
<MenuItem value="">{t("All Floors")}</MenuItem>
<MenuItem value="2/F">2/F</MenuItem>
<MenuItem value="4/F">4/F</MenuItem>
</Select>
</FormControl>

<FormControl sx={{ minWidth: 150 }} size="small">
<InputLabel
id="status-select-label"
shrink={true}
>
{t("Status")}
</InputLabel>
<Select
labelId="status-select-label"
id="status-select"
value={selectedStatus}
label={t("Status")}
onChange={(e) => setSelectedStatus(e.target.value)}
displayEmpty
>
<MenuItem value="">{t("All Statuses")}</MenuItem>
<MenuItem value="pending">{t("pending")}</MenuItem>
<MenuItem value="released">{t("released")}</MenuItem>
<MenuItem value="completed">{t("completed")}</MenuItem>
</Select>
</FormControl>
</Stack>

<Box sx={{ mt: 2 }}>
@@ -202,13 +235,13 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
{t("Truck Information")}
</Typography>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
{t("Departure Time")} {t("Truck Lane Code")}
{t("Truck Lane Code")} - {t("Departure Time")}
</Typography>
</Box>
</TableCell>
{/*<TableCell>{t("Truck Departure Time")}</TableCell>
<TableCell>{t("Truck Lane Code")}</TableCell>*/}
<TableCell>{t("Shop Name")}</TableCell>
<TableCell sx={{ minWidth: 200, width: '20%' }}>{t("Shop Name")}</TableCell>
<TableCell>{t("Loading Sequence")}</TableCell>
{/*<TableCell>{t("Delivery Order Code(s)")}</TableCell>
<TableCell>{t("Pick Order Code(s)")}</TableCell>
@@ -230,7 +263,7 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
</Box>
</TableCell>
<TableCell>{t("Handler Name")}</TableCell>
<TableCell>{t("Number of FG Items")}</TableCell>
<TableCell sx={{ minWidth: 100, width: '8%', whiteSpace: 'nowrap' }}>{t("Number of FG Items (Order Item(s) Count)")}</TableCell>
</TableRow>
</TableHead>
<TableBody>
@@ -275,7 +308,7 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
</Box>
</TableCell>

<TableCell>{row.shopName || '-'}</TableCell>
<TableCell sx={{ minWidth: 200, width: '20%' }}>{row.shopName || '-'}</TableCell>
<TableCell>{row.loadingSequence || '-'}</TableCell>
{/*<TableCell>{row.deliveryOrderCode || '-'}</TableCell>
<TableCell>{row.pickOrderCode || '-'}</TableCell>
@@ -295,22 +328,40 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
<TableCell>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
<Typography variant="body2">
{row.ticketNo || '-'} ({row.ticketStatus || '-'})
{row.ticketNo || '-'} ({row.ticketStatus ? t(row.ticketStatus.toLowerCase()) : '-'})
</Typography>
<Typography variant="body2">
{row.ticketReleaseTime
? dayjs(row.ticketReleaseTime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm')
{t("Released Time")}: {row.ticketReleaseTime
? (() => {
if (Array.isArray(row.ticketReleaseTime)) {
return arrayToDayjs(row.ticketReleaseTime, true).format('HH:mm');
}
const parsedDate = dayjs(row.ticketReleaseTime, 'YYYYMMDDHHmmss');
if (!parsedDate.isValid()) {
return dayjs(row.ticketReleaseTime).format('HH:mm');
}
return parsedDate.format('HH:mm');
})()
: '-'}
</Typography>
<Typography variant="body2">
{row.ticketCompleteDateTime
? dayjs(row.ticketCompleteDateTime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm')
{t("Completed Time")}: {row.ticketCompleteDateTime
? (() => {
if (Array.isArray(row.ticketCompleteDateTime)) {
return arrayToDayjs(row.ticketCompleteDateTime, true).format('HH:mm');
}
const parsedDate = dayjs(row.ticketCompleteDateTime, 'YYYYMMDDHHmmss');
if (!parsedDate.isValid()) {
return dayjs(row.ticketCompleteDateTime).format('HH:mm');
}
return parsedDate.format('HH:mm');
})()
: '-'}
</Typography>
</Box>
</TableCell>
<TableCell>{row.handlerName || '-'}</TableCell>
<TableCell>-</TableCell>
<TableCell sx={{ minWidth: 100, width: '8%' }}>{row.numberOfFGItems ?? 0}</TableCell>
</TableRow>
);
})


+ 48
- 30
src/components/FinishedGoodSearch/FinishedGoodFloorLanePanel.tsx View File

@@ -140,36 +140,54 @@ const FinishedGoodFloorLanePanel: React.FC<Props> = ({ onPickOrderAssigned, onSw

return (
<Box sx={{ mb: 2 }}>
{/* Date Selector Dropdown */}
<Box sx={{ maxWidth: 300, mb: 2 }}>
<FormControl fullWidth size="small">
<InputLabel id="date-select-label">{t("Select Date")}</InputLabel>
<Select
labelId="date-select-label"
id="date-select"
value={selectedDate}
label={t("Select Date")}
onChange={(e) => { {
setSelectedDate(e.target.value);
loadSummaries();
}}}
>
{/* Date Selector Dropdown and Legend */}
<Stack direction="row" spacing={2} sx={{ mb: 2, alignItems: 'flex-start' }}>
<Box sx={{ maxWidth: 300 }}>
<FormControl fullWidth size="small">
<InputLabel id="date-select-label">{t("Select Date")}</InputLabel>
<Select
labelId="date-select-label"
id="date-select"
value={selectedDate}
label={t("Select Date")}
onChange={(e) => { {
setSelectedDate(e.target.value);
loadSummaries();
}}}
>

<MenuItem value="today">
{t("Today")} ({getDateLabel(0)})
</MenuItem>
<MenuItem value="tomorrow">
{t("Tomorrow")} ({getDateLabel(1)})
</MenuItem>
<MenuItem value="dayAfterTomorrow">
{t("Day After Tomorrow")} ({getDateLabel(2)})
</MenuItem>
</Select>
</FormControl>
</Box>

<Box
sx={{
p: 1,
backgroundColor: '#fafafa',
borderRadius: 1,
border: '1px solid #e0e0e0',
flex: 1,
maxWidth: 400
}}
>
<Typography variant="body2" sx={{ display: 'block', color: 'text.secondary', fontWeight: 600 }}>
{t("EDT - Lane Code (Unassigned/Total)")}
</Typography>
</Box>
</Stack>

<MenuItem value="today">
{t("Today")} ({getDateLabel(0)})
</MenuItem>
<MenuItem value="tomorrow">
{t("Tomorrow")} ({getDateLabel(1)})
</MenuItem>
<MenuItem value="dayAfterTomorrow">
{t("Day After Tomorrow")} ({getDateLabel(2)})
</MenuItem>
</Select>
</FormControl>
</Box>

{/* Grid containing both floors */}
<Grid container spacing={2}>
@@ -299,7 +317,7 @@ const FinishedGoodFloorLanePanel: React.FC<Props> = ({ onPickOrderAssigned, onSw
}}
>
{isLoadingSummary ? (
<Typography variant="caption">Loading...</Typography>
<Typography variant="caption">{t("Loading...")}</Typography>
) : !summary4F?.rows || summary4F.rows.length === 0 ? (
<Typography
variant="body2"


+ 22
- 7
src/components/FinishedGoodSearch/FinishedGoodSearch.tsx View File

@@ -145,6 +145,11 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
});
} else {
console.error("Print failed: ", response.message);
Swal.fire({
title: "",
text: t("Please take one pick order before printing the draft."),
icon: "info"
})
}
} catch(error){
console.error("error: ", error)
@@ -247,7 +252,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
const handleCompletionStatusChange = (event: CustomEvent) => {
const { allLotsCompleted, tabIndex: eventTabIndex } = event.detail;
// 修复:根据标签页和事件来源决定是否更新打印按钮状态
// 修复:根据标签页和事件来源决定是否更新打印按钮状态
if (eventTabIndex === undefined || eventTabIndex === tabIndex) {
setPrintButtonsEnabled(allLotsCompleted);
console.log(`Print buttons enabled for tab ${tabIndex}:`, allLotsCompleted);
@@ -259,9 +264,9 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
return () => {
window.removeEventListener('pickOrderCompletionStatus', handleCompletionStatusChange as EventListener);
};
}, [tabIndex]); // 添加 tabIndex 依赖
}, [tabIndex]); // 添加 tabIndex 依赖

// 新增:处理标签页切换时的打印按钮状态重置
// 新增:处理标签页切换时的打印按钮状态重置
useEffect(() => {
// 当切换到标签页 2 (GoodPickExecutionRecord) 时,重置打印按钮状态
if (tabIndex === 2) {
@@ -286,7 +291,7 @@ const handleAssignByLane = useCallback(async (
const res = await assignByLane(currentUserId, storeId, truckLanceCode, truckDepartureTime);
if (res.code === "SUCCESS") {
console.log(" Successfully assigned pick order from lane", truckLanceCode);
console.log(" Successfully assigned pick order from lane", truckLanceCode);
window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
loadSummaries(); // 刷新按钮状态
} else if (res.code === "USER_BUSY") {
@@ -322,7 +327,7 @@ const handleAssignByLane = useCallback(async (
setIsAssigning(false);
}
}, [currentUserId, t, loadSummaries]);
// Manual assignment handler - uses the action function
// Manual assignment handler - uses the action function
*/
const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
(_e, newValue) => {
@@ -334,6 +339,10 @@ const handleAssignByLane = useCallback(async (
const handleSwitchToDetailTab = useCallback(() => {
setTabIndex(1);
}, []);

const handleSwtitchToRecordTab = useCallback(() =>{
setTabIndex(2);
}, []);
const openCreateModal = useCallback(async () => {
console.log("testing")
@@ -611,7 +620,7 @@ const handleAssignByLane = useCallback(async (
</Grid>
</Box>

{/* Tabs section - Move the click handler here */}
{/* Tabs section - Move the click handler here */}
<Box sx={{
borderBottom: '1px solid #e0e0e0'
}}>
@@ -634,7 +643,13 @@ const handleAssignByLane = useCallback(async (
onSwitchToDetailTab={handleSwitchToDetailTab}
/>
)}
{tabIndex === 1 && <PickExecutionDetail filterArgs={filterArgs} />}
{tabIndex === 1 && (
<PickExecutionDetail
filterArgs={filterArgs}
onSwitchToRecordTab={handleSwtitchToRecordTab}
onRefreshReleasedOrderCount={fetchReleasedOrderCount}
/>
) }
{tabIndex === 2 && <GoodPickExecutionRecord filterArgs={filterArgs} />}
{tabIndex === 3 && <FGPickOrderTicketReleaseTable/>}
</Box>


+ 4
- 0
src/components/FinishedGoodSearch/GoodPickExecutionForm.tsx View File

@@ -190,7 +190,11 @@ const validateForm = (): boolean => {
}
// 2. 检查 actualPickQty 不能超过可用数量或需求数量
<<<<<<< Updated upstream
if (ap > Math.min( req)) {
=======
if (ap > Math.min(req)) {
>>>>>>> Stashed changes
newErrors.actualPickQty = t('Qty is not allowed to be greater than required/available qty');
}


+ 13
- 26
src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx View File

@@ -564,33 +564,20 @@ if (showDetailView && selectedDoPickOrder) {
<Typography variant="subtitle1">
<strong>{t("Completed Date")}:</strong> {dayjs(selectedDoPickOrder.completedDate).format(OUTPUT_DATE_FORMAT)}
</Typography>
{selectedDoPickOrder.pickOrderIds && selectedDoPickOrder.pickOrderIds.length > 1 && (
<Typography variant="subtitle1">
<strong>{t("Pick Order Code(s)")}:</strong>{" "}
{(typeof selectedDoPickOrder.pickOrderCodes === 'string'
? selectedDoPickOrder.pickOrderCodes.split(',').map(code => code.trim())
: Array.isArray(selectedDoPickOrder.pickOrderCodes)
? selectedDoPickOrder.pickOrderCodes
: []
).filter(Boolean).join(', ')}
</Typography>
)}
</Stack>
</Paper>

{/* 添加:多个 Pick Orders 信息(如果有) */}
{selectedDoPickOrder.pickOrderIds && selectedDoPickOrder.pickOrderIds.length > 0 && (
<Paper sx={{ mb: 2, p: 2, backgroundColor: '#f5f5f5' }}>
<Typography variant="subtitle2" sx={{ mb: 1, fontWeight: 'bold' }}>
{t("This ticket contains")} {selectedDoPickOrder.pickOrderIds.length} {t("pick orders")}:
</Typography>
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
{(typeof selectedDoPickOrder.pickOrderCodes === 'string'
? selectedDoPickOrder.pickOrderCodes.split(',').map(code => code.trim())
: Array.isArray(selectedDoPickOrder.pickOrderCodes)
? selectedDoPickOrder.pickOrderCodes
: []
).filter(Boolean).map((code, idx) => (
<Chip
key={idx}
label={code}
size="small"
variant="outlined"
/>
))}
</Box>
</Paper>
)}

{/* 数据检查 */}
{detailLotData.length === 0 ? (
<Box sx={{ p: 3, textAlign: 'center' }}>
@@ -710,11 +697,11 @@ if (showDetailView && selectedDoPickOrder) {
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Box>
<Typography variant="h6">
{doPickOrder.pickOrderCode}
{doPickOrder.deliveryNoteCode}
</Typography>

<Typography variant="body2" color="text.secondary">
{doPickOrder.shopName} - {doPickOrder.deliveryNo}
{doPickOrder.shopName}
</Typography>
<Typography variant="body2" color="text.secondary">
{t("Completed")}: {dayjs(doPickOrder.completedDate).format(OUTPUT_DATE_FORMAT)}


+ 11
- 3
src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx View File

@@ -68,6 +68,8 @@ import GoodPickExecutionForm from "./GoodPickExecutionForm";
import FGPickOrderCard from "./FGPickOrderCard";
interface Props {
filterArgs: Record<string, any>;
onSwitchToRecordTab?: () => void;
onRefreshReleasedOrderCount?: () => void;
}

// QR Code Modal Component (from LotTable)
@@ -324,7 +326,7 @@ const QrCodeModal: React.FC<{
);
};

const PickExecution: React.FC<Props> = ({ filterArgs }) => {
const PickExecution: React.FC<Props> = ({ filterArgs, onSwitchToRecordTab, onRefreshReleasedOrderCount }) => {
const { t } = useTranslation("pickOrder");
const router = useRouter();
const { data: session } = useSession() as { data: SessionWithTokens | null };
@@ -579,7 +581,7 @@ console.log("🔍 DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos);
pickOrderTargetDate: mergedPickOrder.targetDate,
pickOrderStatus: mergedPickOrder.status,
pickOrderId: line.pickOrderId || mergedPickOrder.pickOrderIds?.[0] || 0, // 使用第一个 pickOrderId
pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "",
pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "",
pickOrderLineId: line.id,
pickOrderLineRequiredQty: line.requiredQty,
pickOrderLineStatus: line.status,
@@ -1678,6 +1680,12 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe
setTimeout(() => {
setQrScanSuccess(false);
checkAndAutoAssignNext();
if (onSwitchToRecordTab) {
onSwitchToRecordTab();
}
if (onRefreshReleasedOrderCount) {
onRefreshReleasedOrderCount();
}
}, 2000);
}
@@ -1687,7 +1695,7 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe
} finally {
setIsSubmittingAll(false);
}
}, [combinedLotData, fetchAllCombinedLotData, checkAndAutoAssignNext, handlelotnull]);
}, [combinedLotData, fetchAllCombinedLotData, checkAndAutoAssignNext, handlelotnull, onSwitchToRecordTab, onRefreshReleasedOrderCount]);

// Calculate scanned items count
// Calculate scanned items count (should match handleSubmitAllScanned filter logic)


+ 3
- 2
src/i18n/zh/pickOrder.json View File

@@ -405,6 +405,7 @@
"Print DN & Label": "列印提料單和送貨單標籤",
"Print Label": "列印送貨單標籤",
"Ticket Release Table": "查看提貨情況",
"Please take one pick order before printing the draft.": "請先從下方選取提料單,再列印草稿。",
"No released pick order records found.": "目前沒有可用的提料單。"
"Please take one pick order before printing the draft.": "請先從「撳單/提料單詳情」頁面下方選取提料單,再列印草稿。",
"No released pick order records found.": "目前沒有可用的提料單。",
"EDT - Lane Code (Unassigned/Total)": "預計出發時間 - 貨車班次(未撳數/總單數)"
}

+ 29
- 0
src/i18n/zh/ticketReleaseTable.json View File

@@ -0,0 +1,29 @@
{
"Ticket Release Table": "查看提貨情況",
"Select Date": "請選擇日期",
"Today": "是日",
"Tomorrow": "翌日",
"Day After Tomorrow": "後日",
"Floor": "樓層",
"All Floors": "所有樓層",
"Store ID": "樓層",
"Required Delivery Date": "需求送貨日期",
"Truck Information": "貨車資訊",
"Departure Time": "出發時間",
"Truck Lane Code": "車綫編號",
"Shop Name": "店鋪名稱",
"Loading Sequence": "裝載順序",
"Ticket Information": "提票資訊",
"Ticket No.": "提票號碼",
"Status": "狀態",
"Released Time": "開始時間",
"Completed Time": "完成時間",
"Handler Name": "負責員工",
"Number of FG Items (Order Item(s) Count)": "訂單項目數量",
"No data available": "沒有資料",
"Rows per page": "每頁行數",
"pending": "待撳單",
"released": "提貨中",
"completed": "已完成",
"All Statuses": "所有提貨狀態"
}

Loading…
Cancel
Save