| @@ -15,7 +15,7 @@ import { | |||
| import { | |||
| arrayToDayjs, | |||
| } from "@/app/utils/formatUtil"; | |||
| import { Button, Grid, Stack, Tab, Tabs, TabsProps, Typography, Box } from "@mui/material"; | |||
| import { Button, Grid, Stack, Tab, Tabs, TabsProps, Typography, Box, TextField } from "@mui/material"; | |||
| import PickOrders from "./FinishedGood"; | |||
| import ConsolidatedPickOrders from "./ConsolidatedPickOrders"; | |||
| import PickExecution from "./GoodPickExecution"; | |||
| @@ -38,10 +38,13 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; | |||
| import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; | |||
| import { DatePicker } from '@mui/x-date-pickers/DatePicker'; | |||
| import dayjs, { Dayjs } from 'dayjs'; | |||
| import { PrinterCombo } from "@/app/api/settings/printer"; | |||
| import { Autocomplete } from "@mui/material"; | |||
| import FGPickOrderTicketReleaseTable from "./FGPickOrderTicketReleaseTable"; | |||
| interface Props { | |||
| pickOrders: PickOrderResult[]; | |||
| printerCombo: PrinterCombo[]; | |||
| } | |||
| type SearchQuery = Partial< | |||
| @@ -50,7 +53,7 @@ type SearchQuery = Partial< | |||
| type SearchParamNames = keyof SearchQuery; | |||
| const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => { | |||
| const PickOrderSearch: React.FC<Props> = ({ pickOrders, printerCombo }) => { | |||
| const { t } = useTranslation("pickOrder"); | |||
| const { data: session } = useSession() as { data: SessionWithTokens | null }; | |||
| const currentUserId = session?.id ? parseInt(session.id) : undefined; | |||
| @@ -67,6 +70,18 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => { | |||
| // const [summary2F, setSummary2F] = useState<StoreLaneSummary | null>(null); | |||
| // const [summary4F, setSummary4F] = useState<StoreLaneSummary | null>(null); | |||
| const [isLoadingSummary, setIsLoadingSummary] = useState(false); | |||
| const [selectedPrinterForAllDraft, setSelectedPrinterForAllDraft] = useState<PrinterCombo | null>( | |||
| printerCombo && printerCombo.length > 0 ? printerCombo[0] : null | |||
| ); | |||
| const [selectedPrinterForDraft, setSelectedPrinterForDraft] = useState<PrinterCombo | null>( | |||
| printerCombo && printerCombo.length > 0 ? printerCombo[0] : null | |||
| ); | |||
| const [selectedPrinterForRecord, setSelectedPrinterForRecord] = useState<PrinterCombo | null>( | |||
| printerCombo && printerCombo.length > 0 ? printerCombo[0] : null | |||
| ); | |||
| const [hideCompletedUntilNext, setHideCompletedUntilNext] = useState<boolean>( | |||
| typeof window !== 'undefined' && localStorage.getItem('hideCompletedUntilNext') === 'true' | |||
| ); | |||
| @@ -118,11 +133,20 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => { | |||
| }) | |||
| return; | |||
| } | |||
| if (!selectedPrinterForDraft) { | |||
| Swal.fire({ | |||
| position: "bottom-end", | |||
| icon: "warning", | |||
| text: t("Please select a printer first"), | |||
| showConfirmButton: false, | |||
| timer: 1500 | |||
| }); | |||
| return; | |||
| } | |||
| const currentFgOrder = fgPickOrdersData[0]; | |||
| const printRequest = { | |||
| printerId: 1, | |||
| printerId: selectedPrinterForDraft.id, | |||
| printQty: 1, | |||
| isDraft: true, | |||
| numOfCarton: 0, | |||
| @@ -154,13 +178,22 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => { | |||
| } catch(error){ | |||
| console.error("error: ", error) | |||
| } | |||
| },[t, fgPickOrdersData]); | |||
| },[t, fgPickOrdersData, selectedPrinterForDraft]); | |||
| const handleAllDraft = useCallback(async () =>{ | |||
| try { | |||
| const releasedOrders = await fetchReleasedDoPickOrders(); | |||
| console.log('fgPickOrdersData length:' + releasedOrders.length) | |||
| if (!selectedPrinterForAllDraft) { | |||
| Swal.fire({ | |||
| position: "bottom-end", | |||
| icon: "warning", | |||
| text: t("Please select a printer first"), | |||
| showConfirmButton: false, | |||
| timer: 1500 | |||
| }); | |||
| return; | |||
| } | |||
| if(releasedOrders.length === 0) { | |||
| console.log("No released do_pick_order records found"); | |||
| Swal.fire({ | |||
| @@ -203,7 +236,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => { | |||
| console.log(`Processing order - DoPickOrder ID: ${doPickOrderId}, Ticket No: ${order.ticketNo}`); | |||
| const printRequest = { | |||
| printerId: 1, | |||
| printerId: selectedPrinterForAllDraft.id, | |||
| printQty: 1, | |||
| isDraft: true, | |||
| numOfCarton: 0, | |||
| @@ -229,7 +262,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => { | |||
| console.error("Error in handleAllDraft:",error); | |||
| } | |||
| },[t, fgPickOrdersData]); | |||
| },[t, fgPickOrdersData, selectedPrinterForAllDraft]); | |||
| @@ -540,86 +573,118 @@ const handleAssignByLane = useCallback(async ( | |||
| {/* Header section */} | |||
| <Box sx={{ | |||
| p: 1, | |||
| borderBottom: '1px solid #e0e0e0', | |||
| minHeight: 'auto' // 确保最小高度自适应 | |||
| }}> | |||
| <Grid container alignItems="center" spacing={1}> | |||
| <Grid item xs={8}> | |||
| <Typography | |||
| variant="h5" | |||
| sx={{ | |||
| lineHeight: 1.4, // 调整行高 | |||
| m: 0, | |||
| fontWeight: 500 | |||
| }} | |||
| > | |||
| {t("Finished Good Order")} | |||
| </Typography> | |||
| </Grid> | |||
| <Grid item xs={4}> | |||
| <Box sx={{ | |||
| display: 'flex', | |||
| justifyContent: 'flex-end', | |||
| <Box | |||
| sx={{ | |||
| p: 1, | |||
| borderBottom: '1px solid #e0e0e0', | |||
| minHeight: 'auto', | |||
| display: 'flex', | |||
| alignItems: 'center', | |||
| justifyContent: 'space-between', // 左标题,右控件 | |||
| gap: 2, | |||
| flexWrap: 'wrap', // 如果屏幕窄就自动换行 | |||
| }} | |||
| > | |||
| {/* 左侧标题 */} | |||
| <Typography | |||
| variant="h5" | |||
| sx={{ | |||
| lineHeight: 1.4, | |||
| m: 0, | |||
| fontWeight: 500, | |||
| }} | |||
| > | |||
| {t("Finished Good Order")} | |||
| </Typography> | |||
| {/* 右侧:打印机 + 按钮 */} | |||
| <Stack | |||
| direction="row" | |||
| spacing={2} | |||
| sx={{ | |||
| alignItems: 'center', | |||
| flexWrap: 'wrap', // 控件太多时换行,不会撑出横向滚动 | |||
| rowGap: 1, | |||
| }} | |||
| > | |||
| <Typography variant="body2" sx={{ minWidth: 'fit-content', mr: 1.5 }}> | |||
| {t("A4 Printer")}: | |||
| </Typography> | |||
| <Autocomplete | |||
| options={printerCombo || []} | |||
| getOptionLabel={(option) => | |||
| option.name || option.label || option.code || `Printer ${option.id}` | |||
| } | |||
| value={selectedPrinterForAllDraft} | |||
| onChange={(_, newValue) => setSelectedPrinterForAllDraft(newValue)} | |||
| sx={{ minWidth: 200 }} | |||
| size="small" | |||
| renderInput={(params) => ( | |||
| <TextField {...params} placeholder={t("A4 Printer")} /> | |||
| )} | |||
| /> | |||
| <Typography variant="body2" sx={{ minWidth: 'fit-content', ml: 1 }}> | |||
| {t("Label Printer")}: | |||
| </Typography> | |||
| <Autocomplete | |||
| options={printerCombo || []} | |||
| getOptionLabel={(option) => | |||
| option.name || option.label || option.code || `Printer ${option.id}` | |||
| } | |||
| value={selectedPrinterForDraft} | |||
| onChange={(_, newValue) => setSelectedPrinterForDraft(newValue)} | |||
| sx={{ minWidth: 200 }} | |||
| size="small" | |||
| renderInput={(params) => ( | |||
| <TextField {...params} placeholder={t("Label Printer")} /> | |||
| )} | |||
| /> | |||
| <Button | |||
| variant="contained" | |||
| sx={{ | |||
| py: 0.5, | |||
| px: 1.25, | |||
| height: '40px', | |||
| fontSize: '0.75rem', | |||
| lineHeight: 1.2, | |||
| display: 'flex', | |||
| alignItems: 'center', | |||
| justifyContent: 'center', | |||
| '&.Mui-disabled': { | |||
| height: '40px', | |||
| }, | |||
| }} | |||
| onClick={handleAllDraft} | |||
| > | |||
| {t("Print All Draft")} ({releasedOrderCount}) | |||
| </Button> | |||
| <Button | |||
| variant="contained" | |||
| sx={{ | |||
| py: 0.5, | |||
| px: 1.25, | |||
| height: '40px', | |||
| fontSize: '0.75rem', | |||
| lineHeight: 1.2, | |||
| display: 'flex', | |||
| alignItems: 'center', | |||
| height: '100%' | |||
| }}> | |||
| <Stack | |||
| direction="row" | |||
| spacing={0.5} | |||
| sx={{ | |||
| alignItems: 'center', | |||
| height: '100%' | |||
| }} | |||
| > | |||
| <Button | |||
| variant="contained" | |||
| sx={{ | |||
| py: 0.5, // 增加垂直padding | |||
| px: 1.25, // 增加水平padding | |||
| height: '40px', // 增加按钮高度 | |||
| fontSize: '0.75rem', | |||
| lineHeight: 1.2, // 添加行高控制 | |||
| display: 'flex', | |||
| alignItems: 'center', | |||
| justifyContent: 'center', | |||
| '&.Mui-disabled': { | |||
| height: '40px' | |||
| } | |||
| }} | |||
| onClick={handleAllDraft} | |||
| > | |||
| {t("Print All Draft")} ({releasedOrderCount}) | |||
| </Button> | |||
| <Button | |||
| variant="contained" | |||
| sx={{ | |||
| py: 0.5, | |||
| px: 1.25, | |||
| height: '40px', | |||
| fontSize: '0.75rem', | |||
| lineHeight: 1.2, | |||
| display: 'flex', | |||
| alignItems: 'center', | |||
| justifyContent: 'center', | |||
| '&.Mui-disabled': { | |||
| height: '40px' | |||
| } | |||
| }} | |||
| title={!printButtonsEnabled ? t("All lots must be completed before printing") : ""} | |||
| onClick={handleDraft} | |||
| > | |||
| {t("Print Draft")} | |||
| </Button> | |||
| </Stack> | |||
| </Box> | |||
| </Grid> | |||
| </Grid> | |||
| justifyContent: 'center', | |||
| '&.Mui-disabled': { | |||
| height: '40px', | |||
| }, | |||
| }} | |||
| title={!printButtonsEnabled ? t("All lots must be completed before printing") : ""} | |||
| onClick={handleDraft} | |||
| > | |||
| {t("Print Draft")} | |||
| </Button> | |||
| </Stack> | |||
| </Box> | |||
| {/* Tabs section - ✅ Move the click handler here */} | |||
| <Box sx={{ | |||
| borderBottom: '1px solid #e0e0e0' | |||
| @@ -650,7 +715,7 @@ const handleAssignByLane = useCallback(async ( | |||
| onRefreshReleasedOrderCount={fetchReleasedOrderCount} | |||
| /> | |||
| ) } | |||
| {tabIndex === 2 && <GoodPickExecutionRecord filterArgs={filterArgs} />} | |||
| {tabIndex === 2 && <GoodPickExecutionRecord filterArgs={filterArgs} printerCombo={printerCombo} a4Printer={selectedPrinterForAllDraft} labelPrinter={selectedPrinterForDraft} />} | |||
| {tabIndex === 3 && <FGPickOrderTicketReleaseTable/>} | |||
| </Box> | |||
| </Box> | |||
| @@ -1,13 +1,13 @@ | |||
| import { fetchPickOrders } from "@/app/api/pickOrder"; | |||
| import GeneralLoading from "../General/GeneralLoading"; | |||
| import PickOrderSearch from "./FinishedGoodSearch"; | |||
| import{fetchPrinterCombo} from "@/app/api/settings/printer"; | |||
| interface SubComponents { | |||
| Loading: typeof GeneralLoading; | |||
| } | |||
| const FinishedGoodSearchWrapper: React.FC & SubComponents = async () => { | |||
| const [pickOrders] = await Promise.all([ | |||
| const [pickOrders, printerCombo] = await Promise.all([ | |||
| fetchPickOrders({ | |||
| code: undefined, | |||
| targetDateFrom: undefined, | |||
| @@ -16,9 +16,10 @@ const FinishedGoodSearchWrapper: React.FC & SubComponents = async () => { | |||
| status: undefined, | |||
| itemName: undefined, | |||
| }), | |||
| fetchPrinterCombo(), | |||
| ]); | |||
| return <PickOrderSearch pickOrders={pickOrders} />; | |||
| return <PickOrderSearch pickOrders={pickOrders} printerCombo={printerCombo} />; | |||
| }; | |||
| FinishedGoodSearchWrapper.Loading = GeneralLoading; | |||
| @@ -25,6 +25,8 @@ import { | |||
| AccordionSummary, | |||
| AccordionDetails, | |||
| } from "@mui/material"; | |||
| import { PrinterCombo } from "@/app/api/settings/printer"; | |||
| import { Autocomplete } from "@mui/material"; | |||
| import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; | |||
| import { useCallback, useEffect, useState, useRef, useMemo } from "react"; | |||
| import { useTranslation } from "react-i18next"; | |||
| @@ -69,6 +71,9 @@ import Swal from "sweetalert2"; | |||
| interface Props { | |||
| filterArgs: Record<string, any>; | |||
| printerCombo: PrinterCombo[]; | |||
| a4Printer: PrinterCombo | null; // A4 打印机(DN 用) | |||
| labelPrinter: PrinterCombo | null; | |||
| } | |||
| @@ -82,7 +87,7 @@ interface PickOrderData { | |||
| lots: any[]; | |||
| } | |||
| const GoodPickExecutionRecord: React.FC<Props> = ({ filterArgs }) => { | |||
| const GoodPickExecutionRecord: React.FC<Props> = ({ filterArgs, printerCombo, a4Printer, labelPrinter }) => { | |||
| const { t } = useTranslation("pickOrder"); | |||
| const router = useRouter(); | |||
| const { data: session } = useSession() as { data: SessionWithTokens | null }; | |||
| @@ -112,6 +117,16 @@ const GoodPickExecutionRecord: React.FC<Props> = ({ filterArgs }) => { | |||
| const errors = formProps.formState.errors; | |||
| const handleDN = useCallback(async (recordId: number) => { | |||
| if (!a4Printer) { | |||
| Swal.fire({ | |||
| position: "bottom-end", | |||
| icon: "warning", | |||
| text: t("Please select a printer first"), | |||
| showConfirmButton: false, | |||
| timer: 1500 | |||
| }); | |||
| return; | |||
| } | |||
| const askNumofCarton = await Swal.fire({ | |||
| title: t("Enter the number of cartons: "), | |||
| icon: "info", | |||
| @@ -143,7 +158,7 @@ const GoodPickExecutionRecord: React.FC<Props> = ({ filterArgs }) => { | |||
| const numOfCartons = askNumofCarton.value; | |||
| try{ | |||
| const printRequest = { | |||
| printerId: 1, | |||
| printerId: a4Printer.id, | |||
| printQty: 1, | |||
| isDraft: false, | |||
| numOfCarton: numOfCartons, | |||
| @@ -172,6 +187,26 @@ const GoodPickExecutionRecord: React.FC<Props> = ({ filterArgs }) => { | |||
| }, [t]); | |||
| const handleDNandLabel = useCallback(async (recordId: number) => { | |||
| if (!a4Printer || !labelPrinter) { | |||
| Swal.fire({ | |||
| position: "bottom-end", | |||
| icon: "warning", | |||
| text: t("Please select a printer first"), | |||
| showConfirmButton: false, | |||
| timer: 1500 | |||
| }); | |||
| return; | |||
| } | |||
| if (!labelPrinter) { | |||
| Swal.fire({ | |||
| position: "bottom-end", | |||
| icon: "warning", | |||
| text: t("Please select a label printer first"), | |||
| showConfirmButton: false, | |||
| timer: 1500 | |||
| }); | |||
| return; | |||
| } | |||
| const askNumofCarton = await Swal.fire({ | |||
| title: t("Enter the number of cartons: "), | |||
| icon: "info", | |||
| @@ -203,7 +238,7 @@ const GoodPickExecutionRecord: React.FC<Props> = ({ filterArgs }) => { | |||
| const numOfCartons = askNumofCarton.value; | |||
| try{ | |||
| const printDNRequest = { | |||
| printerId: 1, | |||
| printerId: a4Printer.id, | |||
| printQty: 1, | |||
| isDraft: false, | |||
| numOfCarton: numOfCartons, | |||
| @@ -211,7 +246,7 @@ const GoodPickExecutionRecord: React.FC<Props> = ({ filterArgs }) => { | |||
| }; | |||
| const printDNLabelsRequest = { | |||
| printerId: 1, | |||
| printerId: labelPrinter.id, | |||
| printQty: 1, | |||
| numOfCarton: numOfCartons, | |||
| doPickOrderId: recordId | |||
| @@ -280,7 +315,7 @@ const GoodPickExecutionRecord: React.FC<Props> = ({ filterArgs }) => { | |||
| const numOfCartons = askNumofCarton.value; | |||
| try{ | |||
| const printRequest = { | |||
| printerId: 1, | |||
| printerId: labelPrinter?.id ?? 0, | |||
| printQty: 1, | |||
| numOfCarton: numOfCartons, | |||
| doPickOrderId: recordId | |||
| @@ -568,7 +568,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||
| <Typography variant="h6" gutterBottom fontWeight="bold"> | |||
| {t("Production Process Steps")} | |||
| </Typography> | |||
| <ProcessSummaryHeader t={t} processData={processData} /> | |||
| <ProcessSummaryHeader processData={processData} /> | |||
| {!isExecutingLine ? ( | |||
| /* ========== 步骤列表视图 ========== */ | |||
| <TableContainer> | |||
| @@ -578,7 +578,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||
| <TableCell>{t("Seq")}</TableCell> | |||
| <TableCell>{t("Step Name")}</TableCell> | |||
| <TableCell>{t("Description")}</TableCell> | |||
| <TableCell>{t("Equipment Type/Code")}</TableCell> | |||
| <TableCell>{t("EquipmentType-EquipmentName-Code")}</TableCell> | |||
| <TableCell>{t("Operator")}</TableCell> | |||
| {/*} | |||
| <TableCell>{t("Processing Time (mins)")}</TableCell> | |||
| @@ -43,6 +43,7 @@ interface JobOrderLine { | |||
| uom: string; | |||
| shortUom: string; | |||
| availableStatus: string; | |||
| type: string; | |||
| } | |||
| interface ProductProcessJobOrderDetailProps { | |||
| @@ -105,6 +106,9 @@ const ProductionProcessJobOrderDetail: React.FC<ProductProcessJobOrderDetailProp | |||
| }, [fetchData]); | |||
| // PickTable 组件内容 | |||
| const getStockAvailable = (line: JobOrderLine) => { | |||
| if (line.type?.toLowerCase() === "consumables") { | |||
| return null; | |||
| } | |||
| const inventory = inventoryData.find(inv => | |||
| inv.itemCode === line.itemCode || inv.itemName === line.itemName | |||
| ); | |||
| @@ -115,12 +119,22 @@ const getStockAvailable = (line: JobOrderLine) => { | |||
| }; | |||
| const isStockSufficient = (line: JobOrderLine) => { | |||
| if (line.type?.toLowerCase() === "consumables") { | |||
| return false; | |||
| } | |||
| const stockAvailable = getStockAvailable(line); | |||
| if (stockAvailable === null) { | |||
| return false; | |||
| } | |||
| return stockAvailable >= line.reqQty; | |||
| }; | |||
| const stockCounts = useMemo(() => { | |||
| const total = jobOrderLines.length; | |||
| const sufficient = jobOrderLines.filter(isStockSufficient).length; | |||
| // 过滤掉 consumables 类型的 lines | |||
| const nonConsumablesLines = jobOrderLines.filter( | |||
| line => line.type?.toLowerCase() !== "consumables" | |||
| ); | |||
| const total = nonConsumablesLines.length; | |||
| const sufficient = nonConsumablesLines.filter(isStockSufficient).length; | |||
| return { | |||
| total, | |||
| sufficient, | |||
| @@ -131,7 +145,8 @@ const status = processData?.status?.toLowerCase?.() ?? ""; | |||
| const handleDeleteJobOrder = useCallback(async ( jobOrderId: number) => { | |||
| const response = await deleteJobOrder(jobOrderId) | |||
| if (response) { | |||
| setProcessData(response.entity); | |||
| //setProcessData(response.entity); | |||
| await fetchData(); | |||
| } | |||
| }, [jobOrderId]); | |||
| const handleRelease = useCallback(async ( jobOrderId: number) => { | |||
| @@ -139,7 +154,8 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { | |||
| console.log("Release clicked for jobOrderId:", jobOrderId); | |||
| const response = await releaseJo({ id: jobOrderId }) | |||
| if (response) { | |||
| setProcessData(response.entity); | |||
| //setProcessData(response.entity); | |||
| await fetchData(); | |||
| } | |||
| }, [jobOrderId]); | |||
| const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( | |||
| @@ -318,6 +334,10 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { | |||
| align: "right", | |||
| headerAlign: "right", | |||
| renderCell: (params: GridRenderCellParams<JobOrderLine>) => { | |||
| if (params.row.type?.toLowerCase() === "consumables") { | |||
| return t("N/A"); | |||
| } | |||
| return `${decimalFormatter.format(params.value)} (${params.row.shortUom})`; | |||
| }, | |||
| }, | |||
| @@ -328,9 +348,15 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { | |||
| align: "right", | |||
| headerAlign: "right", | |||
| type: "number", | |||
| renderCell: (params: GridRenderCellParams<JobOrderLine>) => { | |||
| // 如果是 consumables,显示 N/A | |||
| if (params.row.type?.toLowerCase() === "consumables") { | |||
| return t("N/A"); | |||
| } | |||
| const stockAvailable = getStockAvailable(params.row); | |||
| if (stockAvailable === null) { | |||
| return t("N/A"); | |||
| } | |||
| return `${decimalFormatter.format(stockAvailable)} (${params.row.shortUom})`; | |||
| }, | |||
| }, | |||
| @@ -360,6 +386,9 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { | |||
| headerAlign: "center", | |||
| type: "boolean", | |||
| renderCell: (params: GridRenderCellParams<JobOrderLine>) => { | |||
| if (params.row.type?.toLowerCase() === "consumables") { | |||
| return <Typography>{t("N/A")}</Typography>; | |||
| } | |||
| return isStockSufficient(params.row) | |||
| ? <CheckCircleOutlineOutlinedIcon fontSize={"large"} color="success" /> | |||
| : <DoDisturbAltRoundedIcon fontSize={"large"} color="error" />; | |||
| @@ -18,7 +18,7 @@ | |||
| "R&D": "研發", | |||
| "STF": "樣品", | |||
| "Other": "其他", | |||
| "Add some entries!": "添加條目", | |||
| "Add Record": "新增", | |||
| "Clean Record": "重置", | |||
| @@ -34,7 +34,7 @@ | |||
| "Items": "物料", | |||
| "Release": "放單", | |||
| "Demand Forecast Setting": "需求預測設定", | |||
| "Equipment Type/Code": "使用設備-編號", | |||
| "EquipmentType-EquipmentName-Code": "設備類型-設備名稱-編號", | |||
| "Equipment": "設備", | |||
| "Time Information(mins)": "時間信息(分鐘)", | |||
| "Processing Time": "生產時間", | |||
| @@ -390,7 +390,8 @@ | |||
| "Step Information": "步驟信息", | |||
| "Stop": "停止", | |||
| "Demand Forecast Setting": "需求預測設定", | |||
| "Equipment Type/Code": "使用設備-編號", | |||
| "EquipmentType-EquipmentName-Code": "設備類型-設備名稱-編號", | |||
| "Equipment": "設備", | |||
| "Time Information(mins)": "時間信息(分鐘)", | |||
| "Processing Time": "生產時間", | |||
| @@ -205,6 +205,8 @@ | |||
| "Accept Stock Out": "接受出庫", | |||
| "Pick Another Lot": "欠數,並重新選擇批號", | |||
| "Delivery Note Code": "送貨單編號", | |||
| "A4 Printer": "A4 打印機", | |||
| "Label Printer": "標籤打印機", | |||
| "Lot No": "批號", | |||
| "Expiry Date": "到期日", | |||
| "Location": "位置", | |||