Procházet zdrojové kódy

update translate, do finish jump page, fix jo expiry can not submit,

production
CANCERYS\kw093 před 2 dny
rodič
revize
6159a435b8
11 změnil soubory, kde provedl 159 přidání a 32 odebrání
  1. +7
    -1
      src/app/api/pickOrder/actions.ts
  2. +57
    -4
      src/components/DoWorkbench/DoWorkbenchTabs.tsx
  3. +24
    -4
      src/components/DoWorkbench/GoodPickExecutionWorkbenchRecord.tsx
  4. +34
    -4
      src/components/DoWorkbench/WorkbenchGoodPickExecutionDetail.tsx
  5. +3
    -3
      src/components/JoWorkbench/JoPickOrderList.tsx
  6. +25
    -12
      src/components/JoWorkbench/newJobPickExecution.tsx
  7. +1
    -1
      src/components/Jodetail/FinishedGoodSearchWrapper.tsx
  8. +1
    -1
      src/components/ProductionProcess/ProductionProcessDetail.tsx
  9. +4
    -2
      src/i18n/zh/common.json
  10. +2
    -0
      src/i18n/zh/jo.json
  11. +1
    -0
      src/i18n/zh/pickOrder.json

+ 7
- 1
src/app/api/pickOrder/actions.ts Zobrazit soubor

@@ -381,6 +381,7 @@ export interface CompletedDoPickOrderSearchParams {
deliveryNoteCode?: string; deliveryNoteCode?: string;
/** 卡車/車道(後端 truckLanceCode 模糊匹配) */ /** 卡車/車道(後端 truckLanceCode 模糊匹配) */
truckLanceCode?: string; truckLanceCode?: string;
ticketNo?: string;
} }
export interface PickExecutionIssue { export interface PickExecutionIssue {
id: number; id: number;
@@ -713,6 +714,9 @@ export const fetchCompletedDoPickOrdersWorkbench = async (
if (searchParams?.truckLanceCode) { if (searchParams?.truckLanceCode) {
params.append("truckLanceCode", searchParams.truckLanceCode); params.append("truckLanceCode", searchParams.truckLanceCode);
} }
if (searchParams?.ticketNo) {
params.append("ticketNo", searchParams.ticketNo);
}


const queryString = params.toString(); const queryString = params.toString();
const url = `${BASE_API_URL}/pickOrder/completed-do-pick-orders-workbench/${userId}${ const url = `${BASE_API_URL}/pickOrder/completed-do-pick-orders-workbench/${userId}${
@@ -742,7 +746,9 @@ export const fetchCompletedDoPickOrdersWorkbenchAll = async (
if (searchParams?.truckLanceCode) { if (searchParams?.truckLanceCode) {
params.append("truckLanceCode", searchParams.truckLanceCode); params.append("truckLanceCode", searchParams.truckLanceCode);
} }

if (searchParams?.ticketNo) {
params.append("ticketNo", searchParams.ticketNo);
}
const queryString = params.toString(); const queryString = params.toString();
const url = `${BASE_API_URL}/pickOrder/completed-do-pick-orders-workbench-all${ const url = `${BASE_API_URL}/pickOrder/completed-do-pick-orders-workbench-all${
queryString ? `?${queryString}` : "" queryString ? `?${queryString}` : ""


+ 57
- 4
src/components/DoWorkbench/DoWorkbenchTabs.tsx Zobrazit soubor

@@ -1,7 +1,8 @@
"use client"; "use client";


import { Autocomplete, Box, Tab, Tabs, TextField, Typography } from "@mui/material";
import React from "react";
import { Autocomplete, Box, CircularProgress, Tab, Tabs, TextField, Typography } from "@mui/material";
import React, { Suspense } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import DoWorkbenchPickShell from "./DoWorkbenchPickShell"; import DoWorkbenchPickShell from "./DoWorkbenchPickShell";
import type { PrinterCombo } from "@/app/api/settings/printer"; import type { PrinterCombo } from "@/app/api/settings/printer";
import GoodPickExecutionWorkbenchRecord from "./GoodPickExecutionWorkbenchRecord"; import GoodPickExecutionWorkbenchRecord from "./GoodPickExecutionWorkbenchRecord";
@@ -14,6 +15,9 @@ import { fetchWorkbenchReleasedDoPickOrdersForSelectionToday } from "@/app/api/d
import { Button } from "@mui/material"; import { Button } from "@mui/material";
import FinishedGoodCartonDashboardTab from "../FinishedGoodSearch/FinishedGoodCartonDashboardTab"; import FinishedGoodCartonDashboardTab from "../FinishedGoodSearch/FinishedGoodCartonDashboardTab";
import TruckRoutingSummaryTabWorkbench from "./TruckRoutingSummaryTabWorkbench"; import TruckRoutingSummaryTabWorkbench from "./TruckRoutingSummaryTabWorkbench";

const ALLOWED_WORKBENCH_TABS = new Set([0, 1, 2, 3, 5, 6]);

type Props = { type Props = {
defaultTabIndex?: 0 | 1; defaultTabIndex?: 0 | 1;
printerCombo?: PrinterCombo[]; printerCombo?: PrinterCombo[];
@@ -25,7 +29,18 @@ function TabPanel(props: { value: number; index: number; children: React.ReactNo
return <Box sx={{ pt: 2 }}>{children}</Box>; return <Box sx={{ pt: 2 }}>{children}</Box>;
} }


const DoWorkbenchTabs: React.FC<Props> = ({ defaultTabIndex = 0, printerCombo = [] }) => {
const DoWorkbenchTabsInner: React.FC<Props> = ({ defaultTabIndex = 0, printerCombo = [] }) => {
const searchParams = useSearchParams();
const router = useRouter();
const pathname = usePathname();

const urlTabStr = searchParams.get("tab");
const urlTicketRaw = searchParams.get("ticketNo");
const urlTicketNo =
urlTicketRaw && urlTicketRaw.trim() !== ""
? decodeURIComponent(urlTicketRaw.trim())
: null;

const [tab, setTab] = React.useState<number>(defaultTabIndex); const [tab, setTab] = React.useState<number>(defaultTabIndex);
const [a4Printer, setA4Printer] = React.useState<PrinterCombo | null>(null); const [a4Printer, setA4Printer] = React.useState<PrinterCombo | null>(null);
const [labelPrinter, setLabelPrinter] = React.useState<PrinterCombo | null>(null); const [labelPrinter, setLabelPrinter] = React.useState<PrinterCombo | null>(null);
@@ -54,6 +69,28 @@ const DoWorkbenchTabs: React.FC<Props> = ({ defaultTabIndex = 0, printerCombo =
void fetchReleasedOrderCount(); void fetchReleasedOrderCount();
}, [fetchReleasedOrderCount]); }, [fetchReleasedOrderCount]);


React.useEffect(() => {
if (urlTabStr == null || urlTabStr === "") return;
const n = parseInt(urlTabStr, 10);
if (!Number.isNaN(n) && ALLOWED_WORKBENCH_TABS.has(n)) {
setTab(n);
}
}, [urlTabStr]);

const handleTabChange = React.useCallback(
(_: React.SyntheticEvent, newTab: number) => {
setTab(newTab);
const params = new URLSearchParams(searchParams.toString());
params.set("tab", String(newTab));
if (newTab !== 1) {
params.delete("ticketNo");
}
const qs = params.toString();
router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false });
},
[pathname, router, searchParams],
);

const handleAllDraft = React.useCallback(async () => { const handleAllDraft = React.useCallback(async () => {
try { try {
if (!a4Printer) { if (!a4Printer) {
@@ -186,7 +223,7 @@ const DoWorkbenchTabs: React.FC<Props> = ({ defaultTabIndex = 0, printerCombo =
{`${t("Print All Draft")} (${releasedOrderCount})`} {`${t("Print All Draft")} (${releasedOrderCount})`}
</Button> </Button>
</Stack> </Stack>
<Tabs value={tab} onChange={(_, v) => setTab(v)} sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs value={tab} onChange={handleTabChange} sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tab label={t("Pick Order Detail")} value={0} /> <Tab label={t("Pick Order Detail")} value={0} />
<Tab label={t("Finished Good Record")} value={1} /> <Tab label={t("Finished Good Record")} value={1} />
<Tab label={t("Finished Good Record (All)")} value={2} /> <Tab label={t("Finished Good Record (All)")} value={2} />
@@ -200,18 +237,22 @@ const DoWorkbenchTabs: React.FC<Props> = ({ defaultTabIndex = 0, printerCombo =
</TabPanel> </TabPanel>
<TabPanel value={tab} index={1}> <TabPanel value={tab} index={1}>
<GoodPickExecutionWorkbenchRecord <GoodPickExecutionWorkbenchRecord
key={`workbench-record-mine-${urlTicketNo ?? ""}`}
printerCombo={printerCombo} printerCombo={printerCombo}
listScope="mine" listScope="mine"
a4Printer={a4Printer} a4Printer={a4Printer}
labelPrinter={labelPrinter} labelPrinter={labelPrinter}
initialTicketNo={urlTicketNo}
/> />
</TabPanel> </TabPanel>
<TabPanel value={tab} index={2}> <TabPanel value={tab} index={2}>
<GoodPickExecutionWorkbenchRecord <GoodPickExecutionWorkbenchRecord
//key={`workbench-record-all-${urlTicketNo ?? ""}`}
printerCombo={printerCombo} printerCombo={printerCombo}
listScope="all" listScope="all"
a4Printer={a4Printer} a4Printer={a4Printer}
labelPrinter={labelPrinter} labelPrinter={labelPrinter}
//initialTicketNo={urlTicketNo}
/> />
</TabPanel> </TabPanel>
<TabPanel value={tab} index={3}> <TabPanel value={tab} index={3}>
@@ -228,5 +269,17 @@ const DoWorkbenchTabs: React.FC<Props> = ({ defaultTabIndex = 0, printerCombo =
); );
}; };


const DoWorkbenchTabs: React.FC<Props> = (props) => (
<Suspense
fallback={
<Box sx={{ display: "flex", justifyContent: "center", p: 4 }}>
<CircularProgress />
</Box>
}
>
<DoWorkbenchTabsInner {...props} />
</Suspense>
);

export default DoWorkbenchTabs; export default DoWorkbenchTabs;



+ 24
- 4
src/components/DoWorkbench/GoodPickExecutionWorkbenchRecord.tsx Zobrazit soubor

@@ -44,6 +44,7 @@ type Props = {
listScope?: "mine" | "all"; listScope?: "mine" | "all";
a4Printer: PrinterCombo | null; a4Printer: PrinterCombo | null;
labelPrinter: PrinterCombo | null; labelPrinter: PrinterCombo | null;
initialTicketNo?: string | null;
}; };


const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({ const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({
@@ -51,6 +52,7 @@ const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({
listScope = "mine", listScope = "mine",
a4Printer, a4Printer,
labelPrinter, labelPrinter,
initialTicketNo,
}) => { }) => {
const { t } = useTranslation("pickOrder"); const { t } = useTranslation("pickOrder");
const { data: session } = useSession() as { data: SessionWithTokens | null }; const { data: session } = useSession() as { data: SessionWithTokens | null };
@@ -70,6 +72,7 @@ const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({
shopName?: string; shopName?: string;
deliveryNoteCode?: string; deliveryNoteCode?: string;
truckLanceCode?: string; truckLanceCode?: string;
ticketNo?: string;
}) => { }) => {
setLoading(true); setLoading(true);
try { try {
@@ -89,8 +92,13 @@ const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({
}, [currentUserId, listScope]); }, [currentUserId, listScope]);


useEffect(() => { useEffect(() => {
void loadData({ targetDate: dayjs().format("YYYY-MM-DD") });
}, [loadData]);
const today = dayjs().format("YYYY-MM-DD");
const tn = initialTicketNo?.trim() || undefined;
void loadData({
targetDate: today,
...(tn ? { ticketNo: tn } : {}),
});
}, [loadData, initialTicketNo]);


const searchCriteria: Criterion<any>[] = useMemo( const searchCriteria: Criterion<any>[] = useMemo(
() => [ () => [
@@ -115,8 +123,16 @@ const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({
type: "date", type: "date",
defaultValue: dayjs().format("YYYY-MM-DD"), defaultValue: dayjs().format("YYYY-MM-DD"),
}, },
{
label: t("Ticket No"),
paramName: "ticketNo",
type: "text",
...(initialTicketNo?.trim()
? { preFilledValue: initialTicketNo.trim() }
: {}),
},
], ],
[t],
[t, initialTicketNo],
); );


const handleSearch = useCallback((query: Record<string, any>) => { const handleSearch = useCallback((query: Record<string, any>) => {
@@ -126,6 +142,7 @@ const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({
shopName: query.shopName || undefined, shopName: query.shopName || undefined,
deliveryNoteCode: query.deliveryNoteCode || undefined, deliveryNoteCode: query.deliveryNoteCode || undefined,
truckLanceCode: query.truckLanceCode || undefined, truckLanceCode: query.truckLanceCode || undefined,
ticketNo: query.ticketNo || undefined,
}); });
}, [loadData]); }, [loadData]);


@@ -582,10 +599,10 @@ const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({
<Box> <Box>
<Box sx={{ mb: 2 }}> <Box sx={{ mb: 2 }}>
<SearchBox <SearchBox
key={`workbench-search-${listScope}-${initialTicketNo ?? ""}`}
criteria={searchCriteria} criteria={searchCriteria}
onSearch={handleSearch} onSearch={handleSearch}
onReset={handleSearchReset} onReset={handleSearchReset}
// searchQuery={searchQuery}
/> />
</Box> </Box>
<Stack <Stack
@@ -617,6 +634,9 @@ const GoodPickExecutionWorkbenchRecord: React.FC<Props> = ({
<Stack direction="row" justifyContent="space-between" alignItems="center"> <Stack direction="row" justifyContent="space-between" alignItems="center">
<Box> <Box>
<Typography variant="h6">{row.deliveryNoteCode || "-"}</Typography> <Typography variant="h6">{row.deliveryNoteCode || "-"}</Typography>
<Typography variant="body2" color="text.secondary">
{row.ticketNo || "-"}
</Typography>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
{row.shopName} {row.shopName}
</Typography> </Typography>


+ 34
- 4
src/components/DoWorkbench/WorkbenchGoodPickExecutionDetail.tsx Zobrazit soubor

@@ -25,7 +25,7 @@ import TestQrCodeProvider from "@/components/QrCodeScannerProvider/TestQrCodePro
import { fetchLotDetail } from "@/app/api/inventory/actions"; import { fetchLotDetail } from "@/app/api/inventory/actions";
import React, { useCallback, useEffect, useState, useRef, useMemo, startTransition } from "react"; import React, { useCallback, useEffect, useState, useRef, useMemo, startTransition } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useRouter } from "next/navigation";
import { usePathname, useRouter } from "next/navigation";
import { import {
updateStockOutLineStatus, updateStockOutLineStatus,
createStockOutLine, createStockOutLine,
@@ -383,6 +383,7 @@ const WorkbenchGoodPickExecutionDetail: React.FC<Props> = ({
const workbenchMode = true; const workbenchMode = true;
const { t } = useTranslation("pickOrder"); const { t } = useTranslation("pickOrder");
const router = useRouter(); const router = useRouter();
const pathname = usePathname();
const { data: session } = useSession() as { data: SessionWithTokens | null }; const { data: session } = useSession() as { data: SessionWithTokens | null };
const [doPickOrderDetail, setDoPickOrderDetail] = useState<DoPickOrderDetail | null>(null); const [doPickOrderDetail, setDoPickOrderDetail] = useState<DoPickOrderDetail | null>(null);
const [selectedPickOrderId, setSelectedPickOrderId] = useState<number | null>(null); const [selectedPickOrderId, setSelectedPickOrderId] = useState<number | null>(null);
@@ -519,6 +520,10 @@ const [pickOrderSwitching, setPickOrderSwitching] = useState(false);
const autoAssignRef = useRef(false); const autoAssignRef = useRef(false);
/** 曾成功載入過 workbench 階層資料;避免「列表仍有單但階層暫空」時對外層重複觸發造成迴圈 */ /** 曾成功載入過 workbench 階層資料;避免「列表仍有單但階層暫空」時對外層重複觸發造成迴圈 */
const workbenchHierarchicalReadyRef = useRef(false); const workbenchHierarchicalReadyRef = useRef(false);
/** 最後一筆 workbench 票號(階層清空或完成後仍可用於導向完成紀錄) */
const lastWorkbenchTicketNoRef = useRef<string | null>(null);
/** 同一筆揀貨完成後只導向「完成紀錄」分頁一次 */
const workbenchFinishNavigateDoneRef = useRef(false);


const formProps = useForm(); const formProps = useForm();
const errors = formProps.formState.errors; const errors = formProps.formState.errors;
@@ -718,15 +723,31 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
// 检查数据结构 // 检查数据结构
if (!hierarchicalData?.fgInfo || !hierarchicalData.pickOrders?.length) { if (!hierarchicalData?.fgInfo || !hierarchicalData.pickOrders?.length) {
console.warn("⚠️ No FG info or pick orders found"); console.warn("⚠️ No FG info or pick orders found");
const hadWorkbenchData = workbenchHierarchicalReadyRef.current;
const ticketForRedirect =
String(hierarchicalData?.fgInfo?.ticketNo ?? "").trim() ||
lastWorkbenchTicketNoRef.current ||
"";
setCombinedLotData([]); setCombinedLotData([]);
setOriginalCombinedData([]); setOriginalCombinedData([]);
setAllLotsCompleted(false); setAllLotsCompleted(false);
setIssuePickedQtyBySolId({}); setIssuePickedQtyBySolId({});
setFgPickOrders([]); setFgPickOrders([]);
if (workbenchHierarchicalReadyRef.current) {
workbenchHierarchicalReadyRef.current = false;
workbenchHierarchicalReadyRef.current = false;
if (hadWorkbenchData) {
onWorkbenchHierarchyEmpty?.(); onWorkbenchHierarchyEmpty?.();
} }
if (
hadWorkbenchData &&
ticketForRedirect &&
!workbenchFinishNavigateDoneRef.current
) {
workbenchFinishNavigateDoneRef.current = true;
router.replace(
`${pathname}?tab=1&ticketNo=${encodeURIComponent(ticketForRedirect)}`,
{ scroll: false },
);
}
return; return;
} }
@@ -779,6 +800,9 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
setFgPickOrders([fgOrder]); setFgPickOrders([fgOrder]);
workbenchHierarchicalReadyRef.current = true; workbenchHierarchicalReadyRef.current = true;
lastWorkbenchTicketNoRef.current =
String(fgOrder.ticketNo ?? "").trim() || null;
workbenchFinishNavigateDoneRef.current = false;
console.log(" DEBUG fgOrder.lineCountsPerPickOrder:", fgOrder.lineCountsPerPickOrder); console.log(" DEBUG fgOrder.lineCountsPerPickOrder:", fgOrder.lineCountsPerPickOrder);
console.log(" DEBUG fgOrder.pickOrderCodes:", fgOrder.pickOrderCodes); console.log(" DEBUG fgOrder.pickOrderCodes:", fgOrder.pickOrderCodes);
console.log(" DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos); console.log(" DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos);
@@ -967,7 +991,13 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO
} finally { } finally {
setCombinedDataLoading(false); setCombinedDataLoading(false);
} }
}, [currentUserId, checkAllLotsCompleted, onWorkbenchHierarchyEmpty]); // 移除 selectedPickOrderId 依赖
}, [
currentUserId,
checkAllLotsCompleted,
onWorkbenchHierarchyEmpty,
router,
pathname,
]); // 移除 selectedPickOrderId 依赖


/** After workbench scan-pick (incl. split → new stock_out_line), reload hierarchical rows. */ /** After workbench scan-pick (incl. split → new stock_out_line), reload hierarchical rows. */
const refreshWorkbenchAfterScanPick = useCallback(async () => { const refreshWorkbenchAfterScanPick = useCallback(async () => {


+ 3
- 3
src/components/JoWorkbench/JoPickOrderList.tsx Zobrazit soubor

@@ -45,7 +45,7 @@ const JoPickOrderList: React.FC<Props> = () => {
paramName: "BOM Description", paramName: "BOM Description",
type: "select-labelled", type: "select-labelled",
options: [ options: [
{ label: t("All"), value: "All" },
//{ label: t("All"), value: "All" },
{ label: t("FG"), value: "FG" }, { label: t("FG"), value: "FG" },
{ label: t("WIP"), value: "WIP" }, { label: t("WIP"), value: "WIP" },
], ],
@@ -56,7 +56,7 @@ const JoPickOrderList: React.FC<Props> = () => {
paramName: "bomType", paramName: "bomType",
type: "select-labelled", type: "select-labelled",
options: [ options: [
{ label: t("All"), value: "All" },
//{ label: t("All"), value: "All" },
{ label: t("Drink"), value: "drink" }, { label: t("Drink"), value: "drink" },
{ label: t("Powder Mixture"), value: "Powder_Mixture" }, { label: t("Powder Mixture"), value: "Powder_Mixture" },
{ label: t("Other"), value: "other" }, { label: t("Other"), value: "other" },
@@ -67,7 +67,7 @@ const JoPickOrderList: React.FC<Props> = () => {
paramName: "floor", paramName: "floor",
type: "select-labelled", type: "select-labelled",
options: [ options: [
{ label: t("All"), value: "ALL" },
//{ label: t("All"), value: "ALL" },
{ label: "2F", value: "2F" }, { label: "2F", value: "2F" },
{ label: "3F", value: "3F" }, { label: "3F", value: "3F" },
{ label: "4F", value: "4F" }, { label: "4F", value: "4F" },


+ 25
- 12
src/components/JoWorkbench/newJobPickExecution.tsx Zobrazit soubor

@@ -3002,6 +3002,7 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
const canPostScanPick = const canPostScanPick =
// unavailable lot: Just Completed must always submit qty=0, even without lotNo // unavailable lot: Just Completed must always submit qty=0, even without lotNo
isUnavailableForJustComplete || isUnavailableForJustComplete ||
isLotAvailabilityExpired(canonicalLotForSol) ||
// noLot row: Just Completed always submit qty=0 // noLot row: Just Completed always submit qty=0
isNoLotForJustComplete || isNoLotForJustComplete ||
(canonicalLotForSol.lotNo && (canonicalLotForSol.lotNo &&
@@ -3014,6 +3015,8 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
if (canPostScanPick) { if (canPostScanPick) {
const qtyToSend = const qtyToSend =
isUnavailableForJustComplete isUnavailableForJustComplete
? 0
: isLotAvailabilityExpired(canonicalLotForSol)
? 0 ? 0
: isNoLotForJustComplete : isNoLotForJustComplete
? 0 ? 0
@@ -3060,7 +3063,7 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
); );
return; return;
} }
const justCompleteErr = tPick(
const justCompleteErr = t(
"Just Completed (workbench): requires valid quantity; expired rows must not use this button.", "Just Completed (workbench): requires valid quantity; expired rows must not use this button.",
); );
if (solId > 0) { if (solId > 0) {
@@ -3964,7 +3967,8 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
!Number.isNaN(Number(fromPickRow)) !Number.isNaN(Number(fromPickRow))
? Number(fromPickRow) ? Number(fromPickRow)
: lockedSubmitQtyDisplay; : lockedSubmitQtyDisplay;

const totalAvail = Number(lot.itemTotalAvailableQty ?? 0);
const isLastLotUnavailable = Number.isFinite(totalAvail) && totalAvail === 0;
return ( return (
<TableRow <TableRow
key={`${lot.pickOrderLineId}-${lot.lotId}`} key={`${lot.pickOrderLineId}-${lot.lotId}`}
@@ -3982,14 +3986,14 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>
{row.isGroupFirst ? (
<>
{lot.itemCode} <br />
{lot.itemName} <br />
{lot.uomDesc}
</>
) : ""}
</TableCell>
{row.isGroupFirst ? (
<>
{lot.itemCode} <br />
{lot.itemName} <br />
{lot.uomDesc}
</>
) : ""}
</TableCell>


<TableCell> <TableCell>
<Typography variant="body2"> <Typography variant="body2">
@@ -4043,7 +4047,16 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
{t( {t(
"is expired. Please check around have available QR code or not.", "is expired. Please check around have available QR code or not.",
)} )}
</Box> </Box>
{isLastLotUnavailable && (
<Box
component="span"
sx={{ fontSize: "0.85rem", lineHeight: 1.4 }}
>
{t("This is last lot, so no available lot.")}
</Box>
)}
</> </>
) : isInventoryLotLineUnavailable(lot) && ) : isInventoryLotLineUnavailable(lot) &&
!( !(
@@ -4093,7 +4106,7 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
openWorkbenchLotLabelModalForLot(lot) openWorkbenchLotLabelModalForLot(lot)
} }
disabled={ disabled={
lot.lotAvailability === "expired" ||
(Number(lot.stockOutLineId) > 0 && (Number(lot.stockOutLineId) > 0 &&
actionBusyBySolId[ actionBusyBySolId[
Number(lot.stockOutLineId) Number(lot.stockOutLineId)
@@ -4457,7 +4470,7 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
"partially_completed" || "partially_completed" ||
lot.stockOutLineStatus === lot.stockOutLineStatus ===
"partially_complete" || "partially_complete" ||
isUnavailableLot ||
// isUnavailableLot ||
(Number(lot.stockOutLineId) > 0 && (Number(lot.stockOutLineId) > 0 &&
issuePickedQtyBySolId[ issuePickedQtyBySolId[
Number(lot.stockOutLineId) Number(lot.stockOutLineId)


+ 1
- 1
src/components/Jodetail/FinishedGoodSearchWrapper.tsx Zobrazit soubor

@@ -23,7 +23,7 @@ const JodetailSearchWrapper: React.FC & SubComponents = async () => {
*/ */
fetchPrinterCombo(), fetchPrinterCombo(),
]); ]);
console.log("%c printerCombo:", "color:green", printerCombo);
//console.log("%c printerCombo:", "color:green", printerCombo);


return <JodetailSearch printerCombo={printerCombo} />; return <JodetailSearch printerCombo={printerCombo} />;
}; };


+ 1
- 1
src/components/ProductionProcess/ProductionProcessDetail.tsx Zobrazit soubor

@@ -770,7 +770,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => {
) : isPaused ? ( ) : isPaused ? (
<Chip label={t("Paused")} color="warning" size="small" /> <Chip label={t("Paused")} color="warning" size="small" />
) : isPass ? ( ) : isPass ? (
<Chip label={t("Pass")} color="success" size="small" />
<Chip label={t("Just Pass")} color="success" size="small" />
) : ( ) : (
<Chip label={t("Unknown")} color="error" size="small" /> <Chip label={t("Unknown")} color="error" size="small" />
) )


+ 4
- 2
src/i18n/zh/common.json Zobrazit soubor

@@ -284,8 +284,9 @@
"Finished Good Management": "成品出倉管理", "Finished Good Management": "成品出倉管理",
"提料順序": "提料順序", "提料順序": "提料順序",
"Filter": "過濾", "Filter": "過濾",
"Item Code": "材料編號",
"Item Name": "材料名稱",
"Item Code": "物料編號",
"Item Name": "物料名稱",
"Just Completed (workbench): requires valid quantity; expired rows must not use this button.": "工單對料:需要有效數量;過期項目不能使用此按鈕。",
"Search & Jump": "搜尋並跳轉", "Search & Jump": "搜尋並跳轉",
"Enter to jump to item": "按 Enter 直接跳到品項位置", "Enter to jump to item": "按 Enter 直接跳到品項位置",
"Jump": "跳轉", "Jump": "跳轉",
@@ -533,6 +534,7 @@
"Edit departure time": "編輯出發時間", "Edit departure time": "編輯出發時間",
"Failed to load truck lane detail": "載入車線詳情失敗", "Failed to load truck lane detail": "載入車線詳情失敗",
"Shop Detail": "店鋪詳情", "Shop Detail": "店鋪詳情",
"Just Pass": "已完成",
"Truck Lane Detail": "車線詳情", "Truck Lane Detail": "車線詳情",
"Filter by Status": "按狀態篩選", "Filter by Status": "按狀態篩選",
"All": "全部", "All": "全部",


+ 2
- 0
src/i18n/zh/jo.json Zobrazit soubor

@@ -151,6 +151,8 @@
"Issue": "問題", "Issue": "問題",
"Location": "位置", "Location": "位置",
"Scan Result": "掃碼結果", "Scan Result": "掃碼結果",
"Just Completed (workbench): requires valid quantity; expired rows must not use this button.": "工單對料:需要有效數量;過期項目不能使用此按鈕。",
"This is last lot, so no available lot.": "這是最後一個批次,所以沒有可用批次。",
"Expiry Date": "有效期", "Expiry Date": "有效期",
"Target Date": "需求日期", "Target Date": "需求日期",
"Lot Required Pick Qty": "批號需求數", "Lot Required Pick Qty": "批號需求數",


+ 1
- 0
src/i18n/zh/pickOrder.json Zobrazit soubor

@@ -501,6 +501,7 @@
"label Printer" : "標籤打印機", "label Printer" : "標籤打印機",
"A4 Printer" : "A4 打印機", "A4 Printer" : "A4 打印機",
"Loading Sequence": "裝載序", "Loading Sequence": "裝載序",
"Ticket No": "提票號碼",
"The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated.": "掃描的庫存批行為「不可用」,無法換批或綁定;揀貨行未更新。", "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated.": "掃描的庫存批行為「不可用」,無法換批或綁定;揀貨行未更新。",
"is unavable. Please check around have available QR code or not.": "此批號不可用,請檢查周圍是否有可用的 QR 碼。", "is unavable. Please check around have available QR code or not.": "此批號不可用,請檢查周圍是否有可用的 QR 碼。",
"Lot switch failed; pick line was not marked as checked.": "換批失敗;揀貨行未標為已核對。", "Lot switch failed; pick line was not marked as checked.": "換批失敗;揀貨行未標為已核對。",


Načítá se…
Zrušit
Uložit