| @@ -906,7 +906,7 @@ export const fetchAllJoborderProductProcessInfo = cache(async (type?: string | n | |||||
| ); | ); | ||||
| }); | }); | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 40 | v1.0.7 | 2026-08-06 */ | |||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 40 | v1.0.11 | 2026-10-29 */ | |||||
| export const fetchJoborderProductProcessesPage = cache(async (params: { | export const fetchJoborderProductProcessesPage = cache(async (params: { | ||||
| /** Job order / process date(YYYY-MM-DD) */ | /** Job order / process date(YYYY-MM-DD) */ | ||||
| date?: string | null; | date?: string | null; | ||||
| @@ -965,6 +965,8 @@ export interface TruckLaneRenameLogResponse { | |||||
| oldDepartureTime?: string | null; | oldDepartureTime?: string | null; | ||||
| newDepartureTime?: string | null; | newDepartureTime?: string | null; | ||||
| ticketCount: number; | ticketCount: number; | ||||
| /** `truck.id` of shops in the renamed lane, comma-separated. */ | |||||
| truckIds?: string | null; | |||||
| } | } | ||||
| export const previewTruckLaneRenameAction = async ( | export const previewTruckLaneRenameAction = async ( | ||||
| @@ -203,13 +203,13 @@ const TruckScheduleDashboard: React.FC = () => { | |||||
| return '-'; | return '-'; | ||||
| }; | }; | ||||
| // Compare a timestamp against the selected date (today/tomorrow/...) and return a short label. | |||||
| // Used to avoid confusion when picking crosses midnight. | |||||
| // Compare a timestamp against calendar today. Same-day picks show no chip; | |||||
| // only midnight-crossing (yesterday / tomorrow / N days) gets a label. | |||||
| // Does not filter rows — trucklane tickets for the selected delivery date still show. | |||||
| const relativeDayLabel = useCallback( | const relativeDayLabel = useCallback( | ||||
| (dateTimeData: string | number[] | null, dateOption: string): string | null => { | |||||
| (dateTimeData: string | number[] | null): string | null => { | |||||
| if (!dateTimeData) return null; | if (!dateTimeData) return null; | ||||
| const dateOffset = getDateOffset(dateOption); | |||||
| const baseDate = dayjs().startOf('day').add(dateOffset, 'day'); | |||||
| const baseDate = dayjs().startOf('day'); | |||||
| let dt: dayjs.Dayjs; | let dt: dayjs.Dayjs; | ||||
| if (Array.isArray(dateTimeData)) { | if (Array.isArray(dateTimeData)) { | ||||
| @@ -518,8 +518,8 @@ const TruckScheduleDashboard: React.FC = () => { | |||||
| filteredData.map((row, index) => { | filteredData.map((row, index) => { | ||||
| const timeRemaining = calculateTimeRemaining(row, selectedDate); | const timeRemaining = calculateTimeRemaining(row, selectedDate); | ||||
| const chipColor = getTimeChipColor(row, selectedDate); | const chipColor = getTimeChipColor(row, selectedDate); | ||||
| const startRel = relativeDayLabel(row.firstTicketStartTime, selectedDate); | |||||
| const endRel = relativeDayLabel(row.lastTicketEndTime, selectedDate); | |||||
| const startRel = relativeDayLabel(row.firstTicketStartTime); | |||||
| const endRel = relativeDayLabel(row.lastTicketEndTime); | |||||
| return ( | return ( | ||||
| <TableRow | <TableRow | ||||
| @@ -17,25 +17,42 @@ import CheckCircleIcon from "@mui/icons-material/CheckCircle"; | |||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { UpdateProductProcessLineQtyRequest } from "@/app/api/jo/actions"; | import { UpdateProductProcessLineQtyRequest } from "@/app/api/jo/actions"; | ||||
| type QtyInput = number | ""; | |||||
| export type ProductionOutputFormData = Omit< | |||||
| UpdateProductProcessLineQtyRequest, | |||||
| | "outputFromProcessQty" | |||||
| | "byproductQty" | |||||
| | "defectQty" | |||||
| | "defect2Qty" | |||||
| | "defect3Qty" | |||||
| | "scrapQty" | |||||
| > & { | |||||
| outputFromProcessQty: QtyInput; | |||||
| byproductQty: QtyInput; | |||||
| defectQty: QtyInput; | |||||
| defect2Qty: QtyInput; | |||||
| defect3Qty: QtyInput; | |||||
| scrapQty: QtyInput; | |||||
| }; | |||||
| const parseQtyInput = (raw: string): QtyInput => { | |||||
| if (raw === "") return ""; | |||||
| const n = parseInt(raw, 10); | |||||
| return Number.isNaN(n) ? "" : n; | |||||
| }; | |||||
| export const toSubmitQty = (v: QtyInput | null | undefined): number => | |||||
| v === "" || v == null || Number.isNaN(Number(v)) ? 0 : Number(v); | |||||
| interface ProductionOutputFormProps { | interface ProductionOutputFormProps { | ||||
| outputData: (UpdateProductProcessLineQtyRequest & { | |||||
| byproductName: string; | |||||
| byproductQty: number; | |||||
| byproductUom: string; | |||||
| }); | |||||
| setOutputData: React.Dispatch< | |||||
| React.SetStateAction< | |||||
| UpdateProductProcessLineQtyRequest & { | |||||
| byproductName: string; | |||||
| byproductQty: number; | |||||
| byproductUom: string; | |||||
| } | |||||
| > | |||||
| >; | |||||
| outputData: ProductionOutputFormData; | |||||
| setOutputData: React.Dispatch<React.SetStateAction<ProductionOutputFormData>>; | |||||
| onSubmit: () => Promise<void> | void; | onSubmit: () => Promise<void> | void; | ||||
| onCancel: () => void; | onCancel: () => void; | ||||
| } | } | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 59 | v1.0.1 | 2026-10-29 */ | |||||
| const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({ | const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({ | ||||
| outputData, | outputData, | ||||
| setOutputData, | setOutputData, | ||||
| @@ -68,7 +85,7 @@ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({ | |||||
| onChange={(e) => | onChange={(e) => | ||||
| setOutputData({ | setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| outputFromProcessQty: parseInt(e.target.value) || 0, | |||||
| outputFromProcessQty: parseQtyInput(e.target.value), | |||||
| }) | }) | ||||
| } | } | ||||
| /> | /> | ||||
| @@ -103,7 +120,7 @@ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({ | |||||
| onChange={(e) => | onChange={(e) => | ||||
| setOutputData({ | setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| byproductQty: parseInt(e.target.value) || 0, | |||||
| byproductQty: parseQtyInput(e.target.value), | |||||
| }) | }) | ||||
| } | } | ||||
| /> | /> | ||||
| @@ -138,7 +155,7 @@ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({ | |||||
| onChange={(e) => | onChange={(e) => | ||||
| setOutputData({ | setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| defectQty: parseInt(e.target.value) || 0, | |||||
| defectQty: parseQtyInput(e.target.value), | |||||
| }) | }) | ||||
| } | } | ||||
| /> | /> | ||||
| @@ -173,7 +190,7 @@ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({ | |||||
| onChange={(e) => | onChange={(e) => | ||||
| setOutputData({ | setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| scrapQty: parseInt(e.target.value) || 0, | |||||
| scrapQty: parseQtyInput(e.target.value), | |||||
| }) | }) | ||||
| } | } | ||||
| /> | /> | ||||
| @@ -207,4 +224,4 @@ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({ | |||||
| ); | ); | ||||
| }; | }; | ||||
| export default ProductionOutputForm; | |||||
| export default ProductionOutputForm; | |||||
| @@ -5,47 +5,47 @@ import { | |||||
| Button, | Button, | ||||
| Typography, | Typography, | ||||
| } from "@mui/material"; | } from "@mui/material"; | ||||
| import ArrowBackIcon from "@mui/icons-material/ArrowBack"; | |||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { | import { | ||||
| fetchProductProcessLineDetail, | fetchProductProcessLineDetail, | ||||
| updateProductProcessLineQty, | updateProductProcessLineQty, | ||||
| UpdateProductProcessLineQtyRequest, | |||||
| JobOrderProcessLineDetailResponse, | JobOrderProcessLineDetailResponse, | ||||
| } from "@/app/api/jo/actions"; | } from "@/app/api/jo/actions"; | ||||
| import ProductionOutputForm from "./ProductionOutputForm"; | |||||
| import ProductionOutputForm, { | |||||
| ProductionOutputFormData, | |||||
| toSubmitQty, | |||||
| } from "./ProductionOutputForm"; | |||||
| interface ProductionOutputFormPageProps { | interface ProductionOutputFormPageProps { | ||||
| lineId: number | null; | lineId: number | null; | ||||
| onBack: () => void; | onBack: () => void; | ||||
| } | } | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 59 | v1.0.1 | 2026-10-29 */ | |||||
| const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({ | const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({ | ||||
| lineId, | lineId, | ||||
| onBack, | onBack, | ||||
| }) => { | }) => { | ||||
| const { t } = useTranslation(); | |||||
| const { t } = useTranslation(["common", "jo", "productionProcess"]); | |||||
| const [lineDetail, setLineDetail] = useState<JobOrderProcessLineDetailResponse | null>(null); | const [lineDetail, setLineDetail] = useState<JobOrderProcessLineDetailResponse | null>(null); | ||||
| const [outputData, setOutputData] = useState<UpdateProductProcessLineQtyRequest & { | |||||
| byproductName: string; | |||||
| byproductQty: number; | |||||
| byproductUom: string; | |||||
| }>({ | |||||
| const [outputData, setOutputData] = useState<ProductionOutputFormData>({ | |||||
| productProcessLineId: lineId ?? 0, | productProcessLineId: lineId ?? 0, | ||||
| outputFromProcessQty: 0, | |||||
| outputFromProcessQty: "", | |||||
| outputFromProcessUom: "", | outputFromProcessUom: "", | ||||
| defectQty: 0, | |||||
| defectQty: "", | |||||
| defectUom: "", | defectUom: "", | ||||
| defect2Qty: 0, | |||||
| defect2Qty: "", | |||||
| defect2Uom: "", | defect2Uom: "", | ||||
| defect3Qty: 0, | |||||
| defect3Qty: "", | |||||
| defect3Uom: "", | defect3Uom: "", | ||||
| defectDescription: "", | defectDescription: "", | ||||
| defectDescription2: "", | defectDescription2: "", | ||||
| defectDescription3: "", | defectDescription3: "", | ||||
| scrapQty: 0, | |||||
| scrapQty: "", | |||||
| scrapUom: "", | scrapUom: "", | ||||
| byproductName: "", | byproductName: "", | ||||
| byproductQty: 0, | |||||
| byproductQty: "", | |||||
| byproductUom: "", | byproductUom: "", | ||||
| }); | }); | ||||
| @@ -60,14 +60,14 @@ const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({ | |||||
| setOutputData((prev) => ({ | setOutputData((prev) => ({ | ||||
| ...prev, | ...prev, | ||||
| productProcessLineId: detail.id, | productProcessLineId: detail.id, | ||||
| outputFromProcessQty: (detail as any).outputFromProcessQty || 0, | |||||
| outputFromProcessQty: (detail as any).outputFromProcessQty || "", | |||||
| outputFromProcessUom: (detail as any).outputFromProcessUom || "", | outputFromProcessUom: (detail as any).outputFromProcessUom || "", | ||||
| defectQty: detail.defectQty || 0, | |||||
| defectQty: detail.defectQty || "", | |||||
| defectUom: detail.defectUom || "", | defectUom: detail.defectUom || "", | ||||
| scrapQty: detail.scrapQty || 0, | |||||
| scrapQty: detail.scrapQty || "", | |||||
| scrapUom: detail.scrapUom || "", | scrapUom: detail.scrapUom || "", | ||||
| byproductName: detail.byproductName || "", | byproductName: detail.byproductName || "", | ||||
| byproductQty: detail.byproductQty || 0, | |||||
| byproductQty: detail.byproductQty || "", | |||||
| byproductUom: detail.byproductUom || "", | byproductUom: detail.byproductUom || "", | ||||
| })); | })); | ||||
| }) | }) | ||||
| @@ -84,6 +84,12 @@ const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({ | |||||
| await updateProductProcessLineQty({ | await updateProductProcessLineQty({ | ||||
| ...outputData, | ...outputData, | ||||
| productProcessLineId: lineDetail.id || 0, | productProcessLineId: lineDetail.id || 0, | ||||
| outputFromProcessQty: toSubmitQty(outputData.outputFromProcessQty), | |||||
| byproductQty: toSubmitQty(outputData.byproductQty), | |||||
| defectQty: toSubmitQty(outputData.defectQty), | |||||
| defect2Qty: toSubmitQty(outputData.defect2Qty), | |||||
| defect3Qty: toSubmitQty(outputData.defect3Qty), | |||||
| scrapQty: toSubmitQty(outputData.scrapQty), | |||||
| }); | }); | ||||
| console.log("Output data submitted successfully"); | console.log("Output data submitted successfully"); | ||||
| @@ -94,14 +100,14 @@ const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({ | |||||
| setOutputData((prev) => ({ | setOutputData((prev) => ({ | ||||
| ...prev, | ...prev, | ||||
| productProcessLineId: detail.id, | productProcessLineId: detail.id, | ||||
| outputFromProcessQty: (detail as any).outputFromProcessQty || 0, | |||||
| outputFromProcessQty: (detail as any).outputFromProcessQty || "", | |||||
| outputFromProcessUom: (detail as any).outputFromProcessUom || "", | outputFromProcessUom: (detail as any).outputFromProcessUom || "", | ||||
| defectQty: detail.defectQty || 0, | |||||
| defectQty: detail.defectQty || "", | |||||
| defectUom: detail.defectUom || "", | defectUom: detail.defectUom || "", | ||||
| scrapQty: detail.scrapQty || 0, | |||||
| scrapQty: detail.scrapQty || "", | |||||
| scrapUom: detail.scrapUom || "", | scrapUom: detail.scrapUom || "", | ||||
| byproductName: detail.byproductName || "", | byproductName: detail.byproductName || "", | ||||
| byproductQty: detail.byproductQty || 0, | |||||
| byproductQty: detail.byproductQty || "", | |||||
| byproductUom: detail.byproductUom || "", | byproductUom: detail.byproductUom || "", | ||||
| })); | })); | ||||
| @@ -116,8 +122,13 @@ const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({ | |||||
| return ( | return ( | ||||
| <Box> | <Box> | ||||
| <Box sx={{ mb: 2 }}> | <Box sx={{ mb: 2 }}> | ||||
| <Button variant="outlined" onClick={onBack}> | |||||
| {t("Back to List")} | |||||
| <Button | |||||
| variant="outlined" | |||||
| size="small" | |||||
| onClick={onBack} | |||||
| startIcon={<ArrowBackIcon />} | |||||
| > | |||||
| {t("Back to Process Steps")} | |||||
| </Button> | </Button> | ||||
| </Box> | </Box> | ||||
| @@ -64,13 +64,16 @@ interface ProductProcessDetailProps { | |||||
| jobOrderId: number; | jobOrderId: number; | ||||
| onBack: () => void; | onBack: () => void; | ||||
| fromJosave?: boolean; | fromJosave?: boolean; | ||||
| /** 進入步驟執行頁時通知父層(用來隱藏「返回列表」) */ | |||||
| onStepViewChange?: (inStepView: boolean) => void; | |||||
| } | } | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 50 | v1.0.1 | 2026-08-10 */ | |||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 50 | v1.0.2 | 2026-10-29 */ | |||||
| const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ | const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ | ||||
| jobOrderId, | jobOrderId, | ||||
| onBack, | onBack, | ||||
| fromJosave, | fromJosave, | ||||
| onStepViewChange, | |||||
| }) => { | }) => { | ||||
| // console.log(" ProductionProcessDetail RENDER", { jobOrderId, fromJosave }); | // console.log(" ProductionProcessDetail RENDER", { jobOrderId, fromJosave }); | ||||
| @@ -143,6 +146,12 @@ const fetchProcessDetailRef = useRef<() => Promise<void>>(); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| onBackRef.current = onBack; | onBackRef.current = onBack; | ||||
| }, [onBack]); | }, [onBack]); | ||||
| useEffect(() => { | |||||
| const inStepView = isExecutingLine && selectedLineId != null; | |||||
| onStepViewChange?.(inStepView); | |||||
| return () => onStepViewChange?.(false); | |||||
| }, [isExecutingLine, selectedLineId, onStepViewChange]); | |||||
| // 获取 process 和 lines 数据 | // 获取 process 和 lines 数据 | ||||
| const fetchProcessDetail = useCallback(async () => { | const fetchProcessDetail = useCallback(async () => { | ||||
| // console.log(" fetchProcessDetail CALLED", { jobOrderId, timestamp: new Date().toISOString() }); | // console.log(" fetchProcessDetail CALLED", { jobOrderId, timestamp: new Date().toISOString() }); | ||||
| @@ -54,7 +54,7 @@ interface ProductProcessJobOrderDetailProps { | |||||
| initialTabIndex?: number; | initialTabIndex?: number; | ||||
| } | } | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 40 | v1.0.7 | 2026-08-06 */ | |||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 40 | v1.0.11 | 2026-10-29 */ | |||||
| const ProductionProcessJobOrderDetail: React.FC<ProductProcessJobOrderDetailProps> = ({ | const ProductionProcessJobOrderDetail: React.FC<ProductProcessJobOrderDetailProps> = ({ | ||||
| jobOrderId, | jobOrderId, | ||||
| onBack, | onBack, | ||||
| @@ -68,6 +68,7 @@ const ProductionProcessJobOrderDetail: React.FC<ProductProcessJobOrderDetailProp | |||||
| const [inventoryData, setInventoryData] = useState<InventoryResult[]>([]); | const [inventoryData, setInventoryData] = useState<InventoryResult[]>([]); | ||||
| const [tabIndex, setTabIndex] = useState(initialTabIndex); | const [tabIndex, setTabIndex] = useState(initialTabIndex); | ||||
| const [selectedProcessId, setSelectedProcessId] = useState<number | null>(null); | const [selectedProcessId, setSelectedProcessId] = useState<number | null>(null); | ||||
| const [inStepView, setInStepView] = useState(false); | |||||
| const [operationPriority, setOperationPriority] = useState<number>(50); | const [operationPriority, setOperationPriority] = useState<number>(50); | ||||
| const [openOperationPriorityDialog, setOpenOperationPriorityDialog] = useState(false); | const [openOperationPriorityDialog, setOpenOperationPriorityDialog] = useState(false); | ||||
| const [openPlanStartDialog, setOpenPlanStartDialog] = useState(false); | const [openPlanStartDialog, setOpenPlanStartDialog] = useState(false); | ||||
| @@ -320,6 +321,9 @@ const handleRelease = useCallback(async (jobOrderId: number) => { | |||||
| const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( | const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( | ||||
| (_e, newValue) => { | (_e, newValue) => { | ||||
| setTabIndex(newValue); | setTabIndex(newValue); | ||||
| if (newValue !== 2) { | |||||
| setInStepView(false); | |||||
| } | |||||
| }, | }, | ||||
| [], | [], | ||||
| ); | ); | ||||
| @@ -796,12 +800,14 @@ const handleRelease = useCallback(async (jobOrderId: number) => { | |||||
| return ( | return ( | ||||
| <Box> | <Box> | ||||
| {/* 返回按钮 */} | |||||
| <Box sx={{ mb: 2 }}> | |||||
| <Button variant="outlined" onClick={onBack} startIcon={<ArrowBackIcon />}> | |||||
| {t("Back to List")} | |||||
| </Button> | |||||
| </Box> | |||||
| {/* 步驟執行頁不顯示「返回列表」,避免誤離開工單 */} | |||||
| {!inStepView && ( | |||||
| <Box sx={{ mb: 2 }}> | |||||
| <Button variant="outlined" onClick={onBack} startIcon={<ArrowBackIcon />}> | |||||
| {t("Back to List")} | |||||
| </Button> | |||||
| </Box> | |||||
| )} | |||||
| {/* 标签页 */} | {/* 标签页 */} | ||||
| <Box sx={{ borderBottom: '1px solid #e0e0e0' }}> | <Box sx={{ borderBottom: '1px solid #e0e0e0' }}> | ||||
| @@ -833,6 +839,7 @@ const handleRelease = useCallback(async (jobOrderId: number) => { | |||||
| }} | }} | ||||
| fromJosave={Boolean(fromJosave && !isPutAwayed)} | fromJosave={Boolean(fromJosave && !isPutAwayed)} | ||||
| onStepViewChange={setInStepView} | |||||
| /> | /> | ||||
| )} | )} | ||||
| {tabIndex === 3 && <ProductionProcessesLineRemarkTableContent />} | {tabIndex === 3 && <ProductionProcessesLineRemarkTableContent />} | ||||
| @@ -179,7 +179,7 @@ function isWaitingQcPutAway( | |||||
| return s !== "completed" && s !== "rejected"; | return s !== "completed" && s !== "rejected"; | ||||
| } | } | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 40 | v1.0.10 | 2026-10-15 */ | |||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 40 | v1.0.11 | 2026-10-29 */ | |||||
| const ProductProcessList: React.FC<ProductProcessListProps> = ({ | const ProductProcessList: React.FC<ProductProcessListProps> = ({ | ||||
| onSelectProcess, | onSelectProcess, | ||||
| printerCombo, | printerCombo, | ||||
| @@ -28,6 +28,7 @@ import CheckCircleIcon from "@mui/icons-material/CheckCircle"; | |||||
| import StopIcon from "@mui/icons-material/Stop"; | import StopIcon from "@mui/icons-material/Stop"; | ||||
| import PauseIcon from "@mui/icons-material/Pause"; | import PauseIcon from "@mui/icons-material/Pause"; | ||||
| import PlayArrowIcon from "@mui/icons-material/PlayArrow"; | import PlayArrowIcon from "@mui/icons-material/PlayArrow"; | ||||
| import ArrowBackIcon from "@mui/icons-material/ArrowBack"; | |||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { | import { | ||||
| JobOrderProcessLineDetailResponse, | JobOrderProcessLineDetailResponse, | ||||
| @@ -47,6 +48,35 @@ import { fetchNameList, NameList } from "@/app/api/user/actions"; | |||||
| import BagConsumptionForm from "./BagConsumptionForm"; // ✅ 添加导入 | import BagConsumptionForm from "./BagConsumptionForm"; // ✅ 添加导入 | ||||
| import OverallTimeRemainingCard from "./OverallTimeRemainingCard"; // ✅ 添加导入 | import OverallTimeRemainingCard from "./OverallTimeRemainingCard"; // ✅ 添加导入 | ||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
| type QtyInput = number | ""; | |||||
| type OutputFormState = Omit< | |||||
| UpdateProductProcessLineQtyRequest, | |||||
| | "outputFromProcessQty" | |||||
| | "byproductQty" | |||||
| | "defectQty" | |||||
| | "defect2Qty" | |||||
| | "defect3Qty" | |||||
| | "scrapQty" | |||||
| > & { | |||||
| outputFromProcessQty: QtyInput; | |||||
| byproductQty: QtyInput; | |||||
| defectQty: QtyInput; | |||||
| defect2Qty: QtyInput; | |||||
| defect3Qty: QtyInput; | |||||
| scrapQty: QtyInput; | |||||
| }; | |||||
| const parseQtyInput = (raw: string): QtyInput => { | |||||
| if (raw === "") return ""; | |||||
| const n = parseInt(raw, 10); | |||||
| return Number.isNaN(n) ? "" : n; | |||||
| }; | |||||
| const toSubmitQty = (v: QtyInput | null | undefined): number => | |||||
| v === "" || v == null || Number.isNaN(Number(v)) ? 0 : Number(v); | |||||
| interface ProductionProcessStepExecutionProps { | interface ProductionProcessStepExecutionProps { | ||||
| lineId: number | null; | lineId: number | null; | ||||
| onBack: () => void; | onBack: () => void; | ||||
| @@ -55,7 +85,7 @@ interface ProductionProcessStepExecutionProps { | |||||
| jobOrderId?: number; // ✅ 添加 | jobOrderId?: number; // ✅ 添加 | ||||
| } | } | ||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 59 | v1.0.0 | 2026-08-10 */ | |||||
| /** FP-MTMS Version Checklist | Functions Ref. No. 59 | v1.0.1 | 2026-10-29 */ | |||||
| const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionProps> = ({ | const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionProps> = ({ | ||||
| lineId, | lineId, | ||||
| onBack, | onBack, | ||||
| @@ -75,24 +105,20 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| lineStatusNorm === "autopass"; | lineStatusNorm === "autopass"; | ||||
| const isPassStatus = lineStatusNorm === "pass"; | const isPassStatus = lineStatusNorm === "pass"; | ||||
| const isAutoPassStatus = lineStatusNorm === "autopass"; | const isAutoPassStatus = lineStatusNorm === "autopass"; | ||||
| const [outputData, setOutputData] = useState<UpdateProductProcessLineQtyRequest & { | |||||
| byproductName: string; | |||||
| byproductQty: number; | |||||
| byproductUom: string; | |||||
| }>({ | |||||
| const [outputData, setOutputData] = useState<OutputFormState>({ | |||||
| productProcessLineId: lineId ?? 0, | productProcessLineId: lineId ?? 0, | ||||
| outputFromProcessQty: 0, | |||||
| outputFromProcessQty: "", | |||||
| outputFromProcessUom: "", | outputFromProcessUom: "", | ||||
| defectQty: 0, | |||||
| defectQty: "", | |||||
| defectUom: "", | defectUom: "", | ||||
| scrapQty: 0, | |||||
| scrapQty: "", | |||||
| scrapUom: "", | scrapUom: "", | ||||
| byproductName: "", | byproductName: "", | ||||
| byproductQty: 0, | |||||
| byproductQty: "", | |||||
| byproductUom: "", | byproductUom: "", | ||||
| defect2Qty: 0, | |||||
| defect2Qty: "", | |||||
| defect2Uom: "", | defect2Uom: "", | ||||
| defect3Qty: 0, | |||||
| defect3Qty: "", | |||||
| defect3Uom: "", | defect3Uom: "", | ||||
| defectDescription: "", | defectDescription: "", | ||||
| defectDescription2: "", | defectDescription2: "", | ||||
| @@ -153,14 +179,14 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| setOutputData(prev => ({ | setOutputData(prev => ({ | ||||
| ...prev, | ...prev, | ||||
| productProcessLineId: detail.id, | productProcessLineId: detail.id, | ||||
| outputFromProcessQty: (detail as any).outputFromProcessQty || 0, | |||||
| outputFromProcessQty: (detail as any).outputFromProcessQty || "", | |||||
| outputFromProcessUom: (detail as any).outputFromProcessUom || "", | outputFromProcessUom: (detail as any).outputFromProcessUom || "", | ||||
| defectQty: detail.defectQty || 0, | |||||
| defectQty: detail.defectQty || "", | |||||
| defectUom: detail.defectUom || "", | defectUom: detail.defectUom || "", | ||||
| scrapQty: detail.scrapQty || 0, | |||||
| scrapQty: detail.scrapQty || "", | |||||
| scrapUom: detail.scrapUom || "", | scrapUom: detail.scrapUom || "", | ||||
| byproductName: detail.byproductName || "", | byproductName: detail.byproductName || "", | ||||
| byproductQty: detail.byproductQty || 0, | |||||
| byproductQty: detail.byproductQty || "", | |||||
| byproductUom: detail.byproductUom || "" | byproductUom: detail.byproductUom || "" | ||||
| })); | })); | ||||
| }) | }) | ||||
| @@ -351,20 +377,20 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| await updateProductProcessLineQty({ | await updateProductProcessLineQty({ | ||||
| productProcessLineId: lineDetail?.id || 0 as number, | productProcessLineId: lineDetail?.id || 0 as number, | ||||
| byproductName: outputData.byproductName, | byproductName: outputData.byproductName, | ||||
| byproductQty: outputData.byproductQty, | |||||
| byproductQty: toSubmitQty(outputData.byproductQty), | |||||
| byproductUom: outputData.byproductUom, | byproductUom: outputData.byproductUom, | ||||
| outputFromProcessQty: outputData.outputFromProcessQty, | |||||
| outputFromProcessQty: toSubmitQty(outputData.outputFromProcessQty), | |||||
| outputFromProcessUom: outputData.outputFromProcessUom, | outputFromProcessUom: outputData.outputFromProcessUom, | ||||
| defectQty: outputData.defectQty, | |||||
| defectQty: toSubmitQty(outputData.defectQty), | |||||
| defectUom: outputData.defectUom, | defectUom: outputData.defectUom, | ||||
| defect2Qty: outputData.defect2Qty, | |||||
| defect2Qty: toSubmitQty(outputData.defect2Qty), | |||||
| defect2Uom: outputData.defect2Uom, | defect2Uom: outputData.defect2Uom, | ||||
| defect3Qty: outputData.defect3Qty, | |||||
| defect3Qty: toSubmitQty(outputData.defect3Qty), | |||||
| defect3Uom: outputData.defect3Uom, | defect3Uom: outputData.defect3Uom, | ||||
| defectDescription: outputData.defectDescription, | defectDescription: outputData.defectDescription, | ||||
| defectDescription2: outputData.defectDescription2, | defectDescription2: outputData.defectDescription2, | ||||
| defectDescription3: outputData.defectDescription3, | defectDescription3: outputData.defectDescription3, | ||||
| scrapQty: outputData.scrapQty, | |||||
| scrapQty: toSubmitQty(outputData.scrapQty), | |||||
| scrapUom: outputData.scrapUom, | scrapUom: outputData.scrapUom, | ||||
| }); | }); | ||||
| @@ -383,21 +409,21 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| setOutputData(prev => ({ | setOutputData(prev => ({ | ||||
| ...prev, | ...prev, | ||||
| productProcessLineId: detail.id, | productProcessLineId: detail.id, | ||||
| outputFromProcessQty: (detail as any).outputFromProcessQty || 0, | |||||
| outputFromProcessQty: (detail as any).outputFromProcessQty || "", | |||||
| outputFromProcessUom: (detail as any).outputFromProcessUom || "", | outputFromProcessUom: (detail as any).outputFromProcessUom || "", | ||||
| defectQty: detail.defectQty || 0, | |||||
| defectQty: detail.defectQty || "", | |||||
| defectUom: detail.defectUom || "", | defectUom: detail.defectUom || "", | ||||
| defectDescription: detail.defectDescription || "", | defectDescription: detail.defectDescription || "", | ||||
| defectDescription2: detail.defectDescription2 || "", | defectDescription2: detail.defectDescription2 || "", | ||||
| defectDescription3: detail.defectDescription3 || "", | defectDescription3: detail.defectDescription3 || "", | ||||
| defectQty2: detail.defectQty2 || 0, | |||||
| defectUom2: detail.defectUom2 || "", | |||||
| defectQty3: detail.defectQty3 || 0, | |||||
| defectUom3: detail.defectUom3 || "", | |||||
| scrapQty: detail.scrapQty || 0, | |||||
| defect2Qty: (detail as any).defect2Qty || "", | |||||
| defect2Uom: (detail as any).defect2Uom || "", | |||||
| defect3Qty: (detail as any).defect3Qty || "", | |||||
| defect3Uom: (detail as any).defect3Uom || "", | |||||
| scrapQty: detail.scrapQty || "", | |||||
| scrapUom: detail.scrapUom || "", | scrapUom: detail.scrapUom || "", | ||||
| byproductName: detail.byproductName || "", | byproductName: detail.byproductName || "", | ||||
| byproductQty: detail.byproductQty || 0, | |||||
| byproductQty: detail.byproductQty || "", | |||||
| byproductUom: detail.byproductUom || "" | byproductUom: detail.byproductUom || "" | ||||
| })); | })); | ||||
| }) | }) | ||||
| @@ -561,8 +587,13 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| return ( | return ( | ||||
| <Box> | <Box> | ||||
| <Box sx={{ mb: 2 }}> | <Box sx={{ mb: 2 }}> | ||||
| <Button variant="outlined" onClick={onBack}> | |||||
| {t("Back to List")} | |||||
| <Button | |||||
| variant="outlined" | |||||
| size="small" | |||||
| onClick={onBack} | |||||
| startIcon={<ArrowBackIcon />} | |||||
| > | |||||
| {t("Back to Process Steps")} | |||||
| </Button> | </Button> | ||||
| </Box> | </Box> | ||||
| {processData && ( | {processData && ( | ||||
| @@ -812,7 +843,7 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| value={outputData.outputFromProcessQty} | value={outputData.outputFromProcessQty} | ||||
| onChange={(e) => setOutputData({ | onChange={(e) => setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| outputFromProcessQty: parseInt(e.target.value) || 0 | |||||
| outputFromProcessQty: parseQtyInput(e.target.value) | |||||
| })} | })} | ||||
| /> | /> | ||||
| </TableCell> | </TableCell> | ||||
| @@ -854,7 +885,7 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| value={outputData.defectQty} | value={outputData.defectQty} | ||||
| onChange={(e) => setOutputData({ | onChange={(e) => setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| defectQty: parseInt(e.target.value) || 0 | |||||
| defectQty: parseQtyInput(e.target.value) | |||||
| })} | })} | ||||
| /> | /> | ||||
| </TableCell> | </TableCell> | ||||
| @@ -902,7 +933,7 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| value={outputData.defect2Qty} | value={outputData.defect2Qty} | ||||
| onChange={(e) => setOutputData({ | onChange={(e) => setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| defect2Qty: parseInt(e.target.value) || 0 | |||||
| defect2Qty: parseQtyInput(e.target.value) | |||||
| })} | })} | ||||
| /> | /> | ||||
| </TableCell> | </TableCell> | ||||
| @@ -950,7 +981,7 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| value={outputData.defect3Qty} | value={outputData.defect3Qty} | ||||
| onChange={(e) => setOutputData({ | onChange={(e) => setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| defect3Qty: parseInt(e.target.value) || 0 | |||||
| defect3Qty: parseQtyInput(e.target.value) | |||||
| })} | })} | ||||
| /> | /> | ||||
| </TableCell> | </TableCell> | ||||
| @@ -998,7 +1029,7 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| value={outputData.scrapQty} | value={outputData.scrapQty} | ||||
| onChange={(e) => setOutputData({ | onChange={(e) => setOutputData({ | ||||
| ...outputData, | ...outputData, | ||||
| scrapQty: parseInt(e.target.value) || 0 | |||||
| scrapQty: parseQtyInput(e.target.value) | |||||
| })} | })} | ||||
| /> | /> | ||||
| </TableCell> | </TableCell> | ||||
| @@ -32,6 +32,8 @@ | |||||
| "BOM Type": "BOM Type", | "BOM Type": "BOM Type", | ||||
| "Back": "Back", | "Back": "Back", | ||||
| "Back to List": "Back to List", | "Back to List": "Back to List", | ||||
| "Back to Process": "Back to Process Steps", | |||||
| "Back to Process Steps": "Back to Process Steps", | |||||
| "Bad Item Qty": "Bad Item Qty", | "Bad Item Qty": "Bad Item Qty", | ||||
| "Bad Package Qty": "Bad Package Qty", | "Bad Package Qty": "Bad Package Qty", | ||||
| "Bag": "Bag", | "Bag": "Bag", | ||||
| @@ -10,6 +10,8 @@ | |||||
| "Auto-refresh every 10 minutes": "Auto-refresh every 10 minutes", | "Auto-refresh every 10 minutes": "Auto-refresh every 10 minutes", | ||||
| "Back": "Back", | "Back": "Back", | ||||
| "Back to List": "Back to List", | "Back to List": "Back to List", | ||||
| "Back to Process": "Back to Process Steps", | |||||
| "Back to Process Steps": "Back to Process Steps", | |||||
| "Bag": "Bag", | "Bag": "Bag", | ||||
| "Bag Consumption": "Bag Consumption", | "Bag Consumption": "Bag Consumption", | ||||
| "Balance": "Balance", | "Balance": "Balance", | ||||
| @@ -106,7 +106,7 @@ | |||||
| "lane_noMatchFilter": "No lanes match (clear search or floor filter)", | "lane_noMatchFilter": "No lanes match (clear search or floor filter)", | ||||
| "floor_label": "Floor", | "floor_label": "Floor", | ||||
| "floor_all": "All", | "floor_all": "All", | ||||
| "filter_clear": "Clear", | |||||
| "filter_clear": "Clear all", | |||||
| "filter_apply": "OK", | "filter_apply": "OK", | ||||
| "btn_addLane": "Add lane", | "btn_addLane": "Add lane", | ||||
| "tools_title": "Tools", | "tools_title": "Tools", | ||||
| @@ -132,13 +132,12 @@ | |||||
| "confirm_restoreDiscardsEdits": "Scheduling a version restore will discard other unsaved board changes (drags, deletes, pending shops/lanes, logistics fields, etc.). Continue?", | "confirm_restoreDiscardsEdits": "Scheduling a version restore will discard other unsaved board changes (drags, deletes, pending shops/lanes, logistics fields, etc.). Continue?", | ||||
| "confirm_restoreSaveWillDropStaging": "Save will apply the snapshot restore first; other staged edits in this save will be skipped. Continue?", | "confirm_restoreSaveWillDropStaging": "Save will apply the snapshot restore first; other staged edits in this save will be skipped. Continue?", | ||||
| "confirm_schedule_removeShop": "Remove this shop from the lane? It will be scheduled for deletion when you submit.", | "confirm_schedule_removeShop": "Remove this shop from the lane? It will be scheduled for deletion when you submit.", | ||||
| "departureDialog_hint": "Name and departure apply to every master row on this lane. Press \"Save changes\" to write them. Completed delivery tickets keep the old name.", | |||||
| "departureDialog_hint": "Name and departure apply to every master row on this lane. Press \"Save changes\" to write them. Existing delivery tickets keep the old name; later releases use the new name.", | |||||
| "departureDialog_title": "Edit lane", | "departureDialog_title": "Edit lane", | ||||
| "departureDialog_nameLabel": "Lane name", | "departureDialog_nameLabel": "Lane name", | ||||
| "departureDialog_remarkReadonly": "Remark (not edited here)", | |||||
| "laneEditTooltip": "Edit lane name and departure time (written when you press Save changes)", | "laneEditTooltip": "Edit lane name and departure time (written when you press Save changes)", | ||||
| "confirm_weekdayToken": "The weekday token in the lane name will change or become unreadable. 4F assignment matches Mon–Sun inside the name. Apply anyway?", | "confirm_weekdayToken": "The weekday token in the lane name will change or become unreadable. 4F assignment matches Mon–Sun inside the name. Apply anyway?", | ||||
| "confirm_renameLane": "Rename \"{{from}}\" to \"{{to}}\".\n{{unfinished}} unfinished delivery ticket(s) will follow (handlers: {{handlers}}).\n{{completed}} completed ticket(s) keep the old name.\n{{schedules}} open schedule line(s) will change from/to.\nNothing is written until you press Save changes.", | |||||
| "confirm_renameLane": "Rename \"{{from}}\" to \"{{to}}\".\n{{unfinished}} unfinished delivery ticket(s) stay on the old name (handlers: {{handlers}}).\n{{completed}} completed ticket(s) stay on the old name.\nLater releases use the new name.\n{{schedules}} open schedule line(s) will change from/to.\nNothing is written until you press Save changes.", | |||||
| "confirm_restoreKeepsTickets": "Restore puts lane master data, and open schedules that point at the current name, back to this snapshot. Unfinished delivery tickets stay on the current name.", | "confirm_restoreKeepsTickets": "Restore puts lane master data, and open schedules that point at the current name, back to this snapshot. Unfinished delivery tickets stay on the current name.", | ||||
| "rename_noHandlers": "none", | "rename_noHandlers": "none", | ||||
| "rename_none": "none", | "rename_none": "none", | ||||
| @@ -152,7 +151,7 @@ | |||||
| "renameErr_LANE_NOT_FOUND": "No live lane rows were found, so nothing was written", | "renameErr_LANE_NOT_FOUND": "No live lane rows were found, so nothing was written", | ||||
| "renameErr_LANE_TIME_INVALID": "Departure time is not a valid time", | "renameErr_LANE_TIME_INVALID": "Departure time is not a valid time", | ||||
| "renameLog_title": "Lane renames", | "renameLog_title": "Lane renames", | ||||
| "renameLog_line": "{{when}} {{who}}: {{from}} → {{to}} ({{floor}}, tickets {{tickets}})", | |||||
| "renameLog_line": "{{when}} {{who}}: {{from}} → {{to}} ({{floor}})", | |||||
| "departureEditAria": "Edit departure time", | "departureEditAria": "Edit departure time", | ||||
| "departureTooltipEditSave": "Edit departure time (saved with \"Save changes\")", | "departureTooltipEditSave": "Edit departure time (saved with \"Save changes\")", | ||||
| "departureTooltipNeedShops": "Add shops before setting departure time", | "departureTooltipNeedShops": "Add shops before setting departure time", | ||||
| @@ -231,9 +230,14 @@ | |||||
| "err_save": "Save failed", | "err_save": "Save failed", | ||||
| "exportRoutes": "Export routes", | "exportRoutes": "Export routes", | ||||
| "filter_apply": "OK", | "filter_apply": "OK", | ||||
| "filter_clear": "Clear", | |||||
| "filter_clear": "Clear all", | |||||
| "floor_all": "All", | "floor_all": "All", | ||||
| "floor_label": "Floor", | "floor_label": "Floor", | ||||
| "lane_filter": "Filter", | |||||
| "laneFilter_special": "Lane code", | |||||
| "laneFilter_zone": "Zone", | |||||
| "laneFilter_weekday": "Weekday", | |||||
| "laneFilter_area": "Area", | |||||
| "id": "id", | "id": "id", | ||||
| "importRoutes": "Import routes", | "importRoutes": "Import routes", | ||||
| "import_staged_preview": "Import preview loaded: {{file}} ({{sheets}} sheet(s) / {{rows}} rows). Press \"Save changes\" to persist.", | "import_staged_preview": "Import preview loaded: {{file}} ({{sheets}} sheet(s) / {{rows}} rows). Press \"Save changes\" to persist.", | ||||
| @@ -34,6 +34,8 @@ | |||||
| "BOM Type": "BOM 類型", | "BOM Type": "BOM 類型", | ||||
| "Back": "返回", | "Back": "返回", | ||||
| "Back to List": "返回列表", | "Back to List": "返回列表", | ||||
| "Back to Process": "返回列表", | |||||
| "Back to Process Steps": "返回列表", | |||||
| "Bad Item Qty": "不良物品數量", | "Bad Item Qty": "不良物品數量", | ||||
| "Bad Package Qty": "不良包裝數量", | "Bad Package Qty": "不良包裝數量", | ||||
| "Bag": "包裝袋", | "Bag": "包裝袋", | ||||
| @@ -10,6 +10,8 @@ | |||||
| "Auto-refresh every 10 minutes": "每10分鐘自動刷新", | "Auto-refresh every 10 minutes": "每10分鐘自動刷新", | ||||
| "Back": "返回", | "Back": "返回", | ||||
| "Back to List": "返回列表", | "Back to List": "返回列表", | ||||
| "Back to Process": "返回列表", | |||||
| "Back to Process Steps": "返回列表", | |||||
| "Bag": "包裝袋", | "Bag": "包裝袋", | ||||
| "Bag Consumption": "包裝袋消耗", | "Bag Consumption": "包裝袋消耗", | ||||
| "Balance": "可用數量", | "Balance": "可用數量", | ||||
| @@ -106,7 +106,7 @@ | |||||
| "lane_noMatchFilter": "無符合條件的車線(清除搜索或樓層篩選)", | "lane_noMatchFilter": "無符合條件的車線(清除搜索或樓層篩選)", | ||||
| "floor_label": "樓層", | "floor_label": "樓層", | ||||
| "floor_all": "全部", | "floor_all": "全部", | ||||
| "filter_clear": "清除", | |||||
| "filter_clear": "清除全部", | |||||
| "filter_apply": "確定", | "filter_apply": "確定", | ||||
| "btn_addLane": "新增車線", | "btn_addLane": "新增車線", | ||||
| "tools_title": "操作工具", | "tools_title": "操作工具", | ||||
| @@ -106,7 +106,12 @@ | |||||
| "lane_selectAll": "全選", | "lane_selectAll": "全選", | ||||
| "floor_label": "樓層", | "floor_label": "樓層", | ||||
| "floor_all": "全部", | "floor_all": "全部", | ||||
| "filter_clear": "清除", | |||||
| "lane_filter": "篩選", | |||||
| "laneFilter_special": "車線", | |||||
| "laneFilter_zone": "區", | |||||
| "laneFilter_weekday": "星期", | |||||
| "laneFilter_area": "地區", | |||||
| "filter_clear": "清除全部", | |||||
| "filter_apply": "確定", | "filter_apply": "確定", | ||||
| "btn_addLane": "新增車線", | "btn_addLane": "新增車線", | ||||
| "tools_title": "操作工具", | "tools_title": "操作工具", | ||||
| @@ -202,11 +207,10 @@ | |||||
| "addShop_confirm": "確認", | "addShop_confirm": "確認", | ||||
| "departureDialog_title": "編輯車線", | "departureDialog_title": "編輯車線", | ||||
| "departureDialog_nameLabel": "車線名稱", | "departureDialog_nameLabel": "車線名稱", | ||||
| "departureDialog_remarkReadonly": "備註(這次不改)", | |||||
| "departureDialog_hint": "名稱與出車時間會套用到此車線全部主檔。按上方「儲存更改」才寫入。已完成的出倉票不會改名。", | |||||
| "departureDialog_hint": "名稱與出車時間會套用到此車線全部店鋪。\n 既有送貨訂單維持舊名稱;之後放單才用新名稱。\n 按上方「儲存更改」才寫入。", | |||||
| "laneEditTooltip": "編輯車線名稱與出車時間(按「儲存更改」才寫入)", | "laneEditTooltip": "編輯車線名稱與出車時間(按「儲存更改」才寫入)", | ||||
| "confirm_weekdayToken": "車線名稱裡的星期代碼會改變,或改完後無法辨認。4F 派車是用名稱裡的 Mon–Sun 對日子。仍要套用?", | "confirm_weekdayToken": "車線名稱裡的星期代碼會改變,或改完後無法辨認。4F 派車是用名稱裡的 Mon–Sun 對日子。仍要套用?", | ||||
| "confirm_renameLane": "把「{{from}}」改成「{{to}}」。\n未完成出倉票 {{unfinished}} 張會改成新名稱(負責人:{{handlers}})。\n已完成 {{completed}} 張維持舊名稱。\n未完成排程 {{schedules}} 筆的起迄名稱會改。\n按「儲存更改」後才寫入。", | |||||
| "confirm_renameLane": "把「{{from}}」改成「{{to}}」。\n未完成出倉票 {{unfinished}} 張維持舊名稱(負責人:{{handlers}})。\n已完成 {{completed}} 張維持舊名稱。\n之後放單才用新名稱。\n未完成排程 {{schedules}} 筆的起迄名稱會改。\n按「儲存更改」後才寫入。", | |||||
| "confirm_restoreKeepsTickets": "還原會把車線主檔,以及指向目前名稱的未完成排程,改回此版本的名稱。未完成的出倉票會留在現在的名稱,不會跟回去。", | "confirm_restoreKeepsTickets": "還原會把車線主檔,以及指向目前名稱的未完成排程,改回此版本的名稱。未完成的出倉票會留在現在的名稱,不會跟回去。", | ||||
| "rename_noHandlers": "無", | "rename_noHandlers": "無", | ||||
| "rename_none": "無", | "rename_none": "無", | ||||
| @@ -220,7 +224,7 @@ | |||||
| "renameErr_LANE_NOT_FOUND": "找不到這條車線的主檔,沒有寫入", | "renameErr_LANE_NOT_FOUND": "找不到這條車線的主檔,沒有寫入", | ||||
| "renameErr_LANE_TIME_INVALID": "出車時間格式不正確", | "renameErr_LANE_TIME_INVALID": "出車時間格式不正確", | ||||
| "renameLog_title": "車線改名紀錄", | "renameLog_title": "車線改名紀錄", | ||||
| "renameLog_line": "{{when}} {{who}}:{{from}} → {{to}}({{floor}},票 {{tickets}})", | |||||
| "renameLog_line": "{{when}} {{who}}:{{from}} → {{to}}({{floor}})", | |||||
| "seqDialog_title": "編輯裝車順序", | "seqDialog_title": "編輯裝車順序", | ||||
| "logistics_colLaneCount": "{{count}} 條車線", | "logistics_colLaneCount": "{{count}} 條車線", | ||||
| "tooltip_openLaneBoard": "在車線看板開此車線", | "tooltip_openLaneBoard": "在車線看板開此車線", | ||||