| @@ -9,9 +9,12 @@ import Tab1QcCategoryQcItemMapping from "@/components/QcItemAll/Tab1QcCategoryQc | |||||
| import Tab2QcCategoryManagement from "@/components/QcItemAll/Tab2QcCategoryManagement"; | import Tab2QcCategoryManagement from "@/components/QcItemAll/Tab2QcCategoryManagement"; | ||||
| import Tab3QcItemManagement from "@/components/QcItemAll/Tab3QcItemManagement"; | import Tab3QcItemManagement from "@/components/QcItemAll/Tab3QcItemManagement"; | ||||
| export const metadata: Metadata = { | |||||
| title: "Qc Item All", | |||||
| }; | |||||
| export async function generateMetadata(): Promise<Metadata> { | |||||
| const { t } = await getServerI18n("qcItemAll"); | |||||
| return { | |||||
| title: t("Qc Item All"), | |||||
| }; | |||||
| } | |||||
| const qcItemAll: React.FC = async () => { | const qcItemAll: React.FC = async () => { | ||||
| const { t } = await getServerI18n("qcItemAll"); | const { t } = await getServerI18n("qcItemAll"); | ||||
| @@ -29,7 +32,7 @@ const qcItemAll: React.FC = async () => { | |||||
| {t("Qc Item All")} | {t("Qc Item All")} | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <Suspense fallback={<div>Loading...</div>}> | |||||
| <Suspense fallback={<div>{t("Loading...")}</div>}> | |||||
| <I18nProvider namespaces={["qcItemAll","navigation","common","qcCategory","qcItem"]}> | <I18nProvider namespaces={["qcItemAll","navigation","common","qcCategory","qcItem"]}> | ||||
| <QcItemAllTabs | <QcItemAllTabs | ||||
| tab0Content={<Tab0ItemQcCategoryMapping />} | tab0Content={<Tab0ItemQcCategoryMapping />} | ||||
| @@ -20,6 +20,15 @@ const pathToLabelKey: { [path: string]: string } = { | |||||
| "/projects/create": "nav.breadcrumb.projectsCreate", | "/projects/create": "nav.breadcrumb.projectsCreate", | ||||
| "/tasks": "nav.breadcrumb.tasks", | "/tasks": "nav.breadcrumb.tasks", | ||||
| "/tasks/create": "nav.breadcrumb.tasksCreate", | "/tasks/create": "nav.breadcrumb.tasksCreate", | ||||
| "/settings": "nav.settings", | |||||
| "/settings/user": "nav.settings.user", | |||||
| "/settings/clientMonitor": "nav.settings.clientMonitor", | |||||
| "/settings/items": "nav.settings.items", | |||||
| "/settings/warehouse": "nav.settings.warehouse", | |||||
| "/settings/qcCategory": "nav.settings.qcCategory", | |||||
| "/settings/bomWeighting": "nav.settings.bomWeighting", | |||||
| "/settings/importExcel": "nav.settings.importExcel", | |||||
| "/settings/importBom": "nav.settings.importBom", | |||||
| "/settings/qcItem": "nav.breadcrumb.qcItem", | "/settings/qcItem": "nav.breadcrumb.qcItem", | ||||
| "/settings/qcItemAll": "nav.breadcrumb.qcItemAll", | "/settings/qcItemAll": "nav.breadcrumb.qcItemAll", | ||||
| "/settings/qrCodeHandle": "nav.breadcrumb.qrCodeHandle", | "/settings/qrCodeHandle": "nav.breadcrumb.qrCodeHandle", | ||||
| @@ -21,7 +21,7 @@ import { useCallback, useEffect, useState } from "react"; | |||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| const CreatePrinter: React.FC = () => { | const CreatePrinter: React.FC = () => { | ||||
| const { t } = useTranslation("common"); | |||||
| const { t } = useTranslation(["printer", "common"]); | |||||
| const router = useRouter(); | const router = useRouter(); | ||||
| const [isSubmitting, setIsSubmitting] = useState(false); | const [isSubmitting, setIsSubmitting] = useState(false); | ||||
| const [descriptions, setDescriptions] = useState<string[]>([]); | const [descriptions, setDescriptions] = useState<string[]>([]); | ||||
| @@ -146,7 +146,7 @@ const CreatePrinter: React.FC = () => { | |||||
| <Grid item xs={12} md={6}> | <Grid item xs={12} md={6}> | ||||
| <TextField | <TextField | ||||
| fullWidth | fullWidth | ||||
| label="IP" | |||||
| label={t("IP")} | |||||
| value={formData.ip} | value={formData.ip} | ||||
| onChange={handleChange("ip")} | onChange={handleChange("ip")} | ||||
| variant="outlined" | variant="outlined" | ||||
| @@ -155,7 +155,7 @@ const CreatePrinter: React.FC = () => { | |||||
| <Grid item xs={12} md={6}> | <Grid item xs={12} md={6}> | ||||
| <TextField | <TextField | ||||
| fullWidth | fullWidth | ||||
| label="Port" | |||||
| label={t("Port")} | |||||
| type="number" | type="number" | ||||
| value={formData.port ?? ""} | value={formData.port ?? ""} | ||||
| onChange={handleChange("port")} | onChange={handleChange("port")} | ||||
| @@ -139,8 +139,9 @@ const CreateUser: React.FC<Props> = ({ rules, auths }) => { | |||||
| if (!regex_pw.test(pw)) { | if (!regex_pw.test(pw)) { | ||||
| haveError = true; | haveError = true; | ||||
| formProps.setError("password", { | formProps.setError("password", { | ||||
| message: | |||||
| message: t( | |||||
| "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", | "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", | ||||
| ), | |||||
| type: "required", | type: "required", | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -11,7 +11,7 @@ import { useRouter } from "next/navigation"; | |||||
| import React, { ForwardedRef, useCallback, useEffect, useMemo, useState } from "react"; | import React, { ForwardedRef, useCallback, useEffect, useMemo, useState } from "react"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { Criterion } from "../SearchBox"; | import { Criterion } from "../SearchBox"; | ||||
| import { isEmpty, sortBy, uniqBy, upperFirst } from "lodash"; | |||||
| import { isEmpty, sortBy, uniqBy } from "lodash"; | |||||
| import { arrayToDateString, arrayToDayjs } from "@/app/utils/formatUtil"; | import { arrayToDateString, arrayToDayjs } from "@/app/utils/formatUtil"; | ||||
| import SearchBox from "../SearchBox/SearchBox"; | import SearchBox from "../SearchBox/SearchBox"; | ||||
| import { EditNote } from "@mui/icons-material"; | import { EditNote } from "@mui/icons-material"; | ||||
| @@ -285,7 +285,7 @@ const DoSearch: React.FC<Props> = ({ filterArgs, searchQuery, onDeliveryOrderSea | |||||
| headerName: t("Status"), | headerName: t("Status"), | ||||
| flex: 1, | flex: 1, | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return t(upperFirst(params.row.status)); | |||||
| return t(params.row.status); | |||||
| }, | }, | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -11,7 +11,7 @@ import { useRouter } from "next/navigation"; | |||||
| import React, { ForwardedRef, useCallback, useEffect, useMemo, useState } from "react"; | import React, { ForwardedRef, useCallback, useEffect, useMemo, useState } from "react"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { Criterion } from "../SearchBox"; | import { Criterion } from "../SearchBox"; | ||||
| import { isEmpty, sortBy, uniqBy, upperFirst } from "lodash"; | |||||
| import { isEmpty, sortBy, uniqBy } from "lodash"; | |||||
| import { arrayToDateString, arrayToDayjs } from "@/app/utils/formatUtil"; | import { arrayToDateString, arrayToDayjs } from "@/app/utils/formatUtil"; | ||||
| import SearchBox from "../SearchBox/SearchBox"; | import SearchBox from "../SearchBox/SearchBox"; | ||||
| import { EditNote } from "@mui/icons-material"; | import { EditNote } from "@mui/icons-material"; | ||||
| @@ -272,7 +272,7 @@ const DoSearchWorkbench: React.FC<Props> = ({ | |||||
| headerName: t("Status"), | headerName: t("Status"), | ||||
| flex: 1, | flex: 1, | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return t(upperFirst(params.row.status)); | |||||
| return t(params.row.status); | |||||
| }, | }, | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -25,7 +25,7 @@ type Props = { | |||||
| }; | }; | ||||
| const EditPrinter: React.FC<Props> = ({ printer }) => { | const EditPrinter: React.FC<Props> = ({ printer }) => { | ||||
| const { t } = useTranslation("common"); | |||||
| const { t } = useTranslation(["printer", "common"]); | |||||
| const router = useRouter(); | const router = useRouter(); | ||||
| const [isSubmitting, setIsSubmitting] = useState(false); | const [isSubmitting, setIsSubmitting] = useState(false); | ||||
| const [formData, setFormData] = useState<PrinterInputs>({ | const [formData, setFormData] = useState<PrinterInputs>({ | ||||
| @@ -112,7 +112,7 @@ const EditPrinter: React.FC<Props> = ({ printer }) => { | |||||
| <Grid item xs={12} md={6}> | <Grid item xs={12} md={6}> | ||||
| <TextField | <TextField | ||||
| fullWidth | fullWidth | ||||
| label="IP" | |||||
| label={t("IP")} | |||||
| value={formData.ip} | value={formData.ip} | ||||
| onChange={handleChange("ip")} | onChange={handleChange("ip")} | ||||
| variant="outlined" | variant="outlined" | ||||
| @@ -121,7 +121,7 @@ const EditPrinter: React.FC<Props> = ({ printer }) => { | |||||
| <Grid item xs={12} md={6}> | <Grid item xs={12} md={6}> | ||||
| <TextField | <TextField | ||||
| fullWidth | fullWidth | ||||
| label="Port" | |||||
| label={t("Port")} | |||||
| type="number" | type="number" | ||||
| value={formData.port || ""} | value={formData.port || ""} | ||||
| onChange={handleChange("port")} | onChange={handleChange("port")} | ||||
| @@ -95,8 +95,9 @@ const EditUser: React.FC<Props> = ({ user, rules }) => { | |||||
| if (!regex_pw.test(pw)) { | if (!regex_pw.test(pw)) { | ||||
| haveError = true; | haveError = true; | ||||
| formProps.setError("password", { | formProps.setError("password", { | ||||
| message: | |||||
| message: t( | |||||
| "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", | "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", | ||||
| ), | |||||
| type: "required", | type: "required", | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -28,7 +28,7 @@ import { | |||||
| } from "@/app/api/pickOrder/actions"; | } from "@/app/api/pickOrder/actions"; | ||||
| import { fetchNameList, NameList ,fetchNewNameList, NewNameList} from "@/app/api/user/actions"; | import { fetchNameList, NameList ,fetchNewNameList, NewNameList} from "@/app/api/user/actions"; | ||||
| import { FormProvider, useForm } from "react-hook-form"; | import { FormProvider, useForm } from "react-hook-form"; | ||||
| import { isEmpty, sortBy, uniqBy, upperFirst, groupBy } from "lodash"; | |||||
| import { isEmpty, sortBy, uniqBy, groupBy } from "lodash"; | |||||
| import { OUTPUT_DATE_FORMAT, arrayToDayjs } from "@/app/utils/formatUtil"; | import { OUTPUT_DATE_FORMAT, arrayToDayjs } from "@/app/utils/formatUtil"; | ||||
| import useUploadContext from "../UploadProvider/useUploadContext"; | import useUploadContext from "../UploadProvider/useUploadContext"; | ||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
| @@ -237,7 +237,7 @@ console.log("First record targetDate formatted:", dayjs(res.records[0]?.targetDa | |||||
| uniqBy( | uniqBy( | ||||
| originalItemData.map((item) => ({ | originalItemData.map((item) => ({ | ||||
| value: item.status, | value: item.status, | ||||
| label: t(upperFirst(item.status)), | |||||
| label: t(item.status), | |||||
| })), | })), | ||||
| "value", | "value", | ||||
| ), | ), | ||||
| @@ -511,7 +511,7 @@ console.log("First record targetDate formatted:", dayjs(res.records[0]?.targetDa | |||||
| {/* Pick Order Status - 只在第一个项目显示 */} | {/* Pick Order Status - 只在第一个项目显示 */} | ||||
| <TableCell> | <TableCell> | ||||
| {index === 0 ? upperFirst(item.status) : null} | |||||
| {index === 0 ? t(item.status) : null} | |||||
| </TableCell> | </TableCell> | ||||
| </TableRow> | </TableRow> | ||||
| )) | )) | ||||
| @@ -134,6 +134,7 @@ const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | |||||
| { | { | ||||
| name: "status", | name: "status", | ||||
| label: t("status"), | label: t("status"), | ||||
| renderCell: (params: any) => t(params.status), | |||||
| }, | }, | ||||
| ], | ], | ||||
| [onDetailClick, t], | [onDetailClick, t], | ||||
| @@ -3,7 +3,7 @@ import SearchResults, { Column } from "../SearchResults/SearchResults"; | |||||
| import { PickOrderResult } from "@/app/api/pickOrder"; | import { PickOrderResult } from "@/app/api/pickOrder"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { useCallback, useEffect, useMemo, useState } from "react"; | import { useCallback, useEffect, useMemo, useState } from "react"; | ||||
| import { isEmpty, upperCase, upperFirst } from "lodash"; | |||||
| import { isEmpty, upperCase } from "lodash"; | |||||
| import { arrayToDateString, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | import { arrayToDateString, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | ||||
| import { | import { | ||||
| consolidatePickOrder, | consolidatePickOrder, | ||||
| @@ -127,7 +127,7 @@ const PickOrders: React.FC<Props> = ({ filteredPickOrders, filterArgs }) => { | |||||
| name: "status", | name: "status", | ||||
| label: t("Status"), | label: t("Status"), | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return upperFirst(params.status); | |||||
| return t(params.status); | |||||
| }, | }, | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -10,7 +10,6 @@ import { | |||||
| sortBy, | sortBy, | ||||
| uniqBy, | uniqBy, | ||||
| upperCase, | upperCase, | ||||
| upperFirst, | |||||
| } from "lodash"; | } from "lodash"; | ||||
| import { | import { | ||||
| arrayToDayjs, | arrayToDayjs, | ||||
| @@ -642,7 +641,7 @@ const handleAssignByLane = useCallback(async ( | |||||
| uniqBy( | uniqBy( | ||||
| pickOrders.map((po) => ({ | pickOrders.map((po) => ({ | ||||
| value: po.status, | value: po.status, | ||||
| label: t(upperFirst(po.status)), | |||||
| label: t(po.status), | |||||
| })), | })), | ||||
| "value", | "value", | ||||
| ), | ), | ||||
| @@ -1,7 +1,7 @@ | |||||
| import { JoDetail } from "@/app/api/jo"; | import { JoDetail } from "@/app/api/jo"; | ||||
| import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | ||||
| import { Box, Card, CardContent, Grid, Stack, TextField } from "@mui/material"; | import { Box, Card, CardContent, Grid, Stack, TextField } from "@mui/material"; | ||||
| import { upperFirst } from "lodash"; | |||||
| import { useFormContext } from "react-hook-form"; | import { useFormContext } from "react-hook-form"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { arrayToDateString } from "@/app/utils/formatUtil"; | import { arrayToDateString } from "@/app/utils/formatUtil"; | ||||
| @@ -30,7 +30,7 @@ const InfoCard: React.FC<Props> = ({ | |||||
| label={t("Status")} | label={t("Status")} | ||||
| fullWidth | fullWidth | ||||
| disabled={true} | disabled={true} | ||||
| value={`${t(upperFirst(watch("status")))}`} | |||||
| value={`${t(watch("status"))}`} | |||||
| /> | /> | ||||
| </Grid> | </Grid> | ||||
| <Grid item xs={6}/>*/} | <Grid item xs={6}/>*/} | ||||
| @@ -6,7 +6,7 @@ import { Criterion } from "../SearchBox"; | |||||
| import SearchResults, { Column, defaultPagingController } from "../SearchResults/SearchResults"; | import SearchResults, { Column, defaultPagingController } from "../SearchResults/SearchResults"; | ||||
| import { EditNote } from "@mui/icons-material"; | import { EditNote } from "@mui/icons-material"; | ||||
| import { arrayToDateString, arrayToDateTimeString, integerFormatter, dayjsToDateString } from "@/app/utils/formatUtil"; | import { arrayToDateString, arrayToDateTimeString, integerFormatter, dayjsToDateString } from "@/app/utils/formatUtil"; | ||||
| import { orderBy, uniqBy, upperFirst } from "lodash"; | |||||
| import { orderBy, uniqBy } from "lodash"; | |||||
| import SearchBox from "../SearchBox/SearchBox"; | import SearchBox from "../SearchBox/SearchBox"; | ||||
| import { useRouter } from "next/navigation"; | import { useRouter } from "next/navigation"; | ||||
| import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form"; | import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form"; | ||||
| @@ -478,7 +478,7 @@ const JoSearch: React.FC<Props> = ({ defaultInputs, bomCombo, printerCombo, jobT | |||||
| label: t("Status"), | label: t("Status"), | ||||
| renderCell: (row) => { | renderCell: (row) => { | ||||
| return <span style={{color: row.stockInLineStatus == "escalated" ? "red" : "inherit"}}> | return <span style={{color: row.stockInLineStatus == "escalated" ? "red" : "inherit"}}> | ||||
| {t(upperFirst(row.status))} | |||||
| {t(row.status)} | |||||
| </span> | </span> | ||||
| } | } | ||||
| }, | }, | ||||
| @@ -7,7 +7,7 @@ import { Criterion } from "../SearchBox"; | |||||
| import SearchResults, { Column, defaultPagingController } from "../SearchResults/SearchResults"; | import SearchResults, { Column, defaultPagingController } from "../SearchResults/SearchResults"; | ||||
| import { EditNote } from "@mui/icons-material"; | import { EditNote } from "@mui/icons-material"; | ||||
| import { arrayToDateString, arrayToDateTimeString, integerFormatter, dayjsToDateString } from "@/app/utils/formatUtil"; | import { arrayToDateString, arrayToDateTimeString, integerFormatter, dayjsToDateString } from "@/app/utils/formatUtil"; | ||||
| import { orderBy, uniqBy, upperFirst } from "lodash"; | |||||
| import { orderBy, uniqBy } from "lodash"; | |||||
| import SearchBox from "../SearchBox/SearchBox"; | import SearchBox from "../SearchBox/SearchBox"; | ||||
| import { useRouter } from "next/navigation"; | import { useRouter } from "next/navigation"; | ||||
| import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form"; | import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form"; | ||||
| @@ -479,7 +479,7 @@ const JoWorkbenchSearch: React.FC<Props> = ({ defaultInputs, bomCombo, printerCo | |||||
| label: t("Status"), | label: t("Status"), | ||||
| renderCell: (row) => { | renderCell: (row) => { | ||||
| return <span style={{color: row.stockInLineStatus == "escalated" ? "red" : "inherit"}}> | return <span style={{color: row.stockInLineStatus == "escalated" ? "red" : "inherit"}}> | ||||
| {t(upperFirst(row.status))} | |||||
| {t(row.status)} | |||||
| </span> | </span> | ||||
| } | } | ||||
| }, | }, | ||||
| @@ -3,7 +3,7 @@ import SearchResults, { Column } from "../SearchResults/SearchResults"; | |||||
| import { PickOrderResult } from "@/app/api/pickOrder"; | import { PickOrderResult } from "@/app/api/pickOrder"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { useCallback, useEffect, useMemo, useState } from "react"; | import { useCallback, useEffect, useMemo, useState } from "react"; | ||||
| import { isEmpty, upperCase, upperFirst } from "lodash"; | |||||
| import { isEmpty, upperCase } from "lodash"; | |||||
| import { arrayToDateString, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | import { arrayToDateString, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | ||||
| import { | import { | ||||
| consolidatePickOrder, | consolidatePickOrder, | ||||
| @@ -127,7 +127,7 @@ const Jodetail: React.FC<Props> = ({ filteredPickOrders, filterArgs }) => { | |||||
| name: "status", | name: "status", | ||||
| label: t("Status"), | label: t("Status"), | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return upperFirst(params.status); | |||||
| return t(params.status); | |||||
| }, | }, | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -10,7 +10,6 @@ import { | |||||
| sortBy, | sortBy, | ||||
| uniqBy, | uniqBy, | ||||
| upperCase, | upperCase, | ||||
| upperFirst, | |||||
| } from "lodash"; | } from "lodash"; | ||||
| import { | import { | ||||
| arrayToDayjs, | arrayToDayjs, | ||||
| @@ -351,7 +350,7 @@ const JodetailSearch: React.FC<Props> = ({ printerCombo }) => { | |||||
| uniqBy( | uniqBy( | ||||
| pickOrders.map((po) => ({ | pickOrders.map((po) => ({ | ||||
| value: po.status, | value: po.status, | ||||
| label: t(upperFirst(po.status)), | |||||
| label: t(po.status), | |||||
| })), | })), | ||||
| "value", | "value", | ||||
| ), | ), | ||||
| @@ -134,6 +134,7 @@ const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | |||||
| { | { | ||||
| name: "status", | name: "status", | ||||
| label: t("status"), | label: t("status"), | ||||
| renderCell: (params: any) => t(params.status), | |||||
| }, | }, | ||||
| ], | ], | ||||
| [onDetailClick, t], | [onDetailClick, t], | ||||
| @@ -20,7 +20,7 @@ type SearchQuery = Partial<Omit<PrinterResult, "id">>; | |||||
| type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
| const PrinterSearch: React.FC<Props> = ({ printers }) => { | const PrinterSearch: React.FC<Props> = ({ printers }) => { | ||||
| const { t } = useTranslation("common"); | |||||
| const { t } = useTranslation(["printer", "common"]); | |||||
| const [filteredPrinters, setFilteredPrinters] = useState(printers); | const [filteredPrinters, setFilteredPrinters] = useState(printers); | ||||
| const [pagingController, setPagingController] = useState({ | const [pagingController, setPagingController] = useState({ | ||||
| pageNum: 1, | pageNum: 1, | ||||
| @@ -42,7 +42,7 @@ const PrinterSearch: React.FC<Props> = ({ printers }) => { | |||||
| type: "text", | type: "text", | ||||
| }, | }, | ||||
| { | { | ||||
| label: "IP", | |||||
| label: t("IP"), | |||||
| paramName: "ip", | paramName: "ip", | ||||
| type: "text", | type: "text", | ||||
| }, | }, | ||||
| @@ -115,14 +115,14 @@ const PrinterSearch: React.FC<Props> = ({ printers }) => { | |||||
| }, | }, | ||||
| { | { | ||||
| name: "ip", | name: "ip", | ||||
| label: "IP", | |||||
| label: t("IP"), | |||||
| align: "left", | align: "left", | ||||
| headerAlign: "left", | headerAlign: "left", | ||||
| sx: { width: "15%", minWidth: "100px" }, | sx: { width: "15%", minWidth: "100px" }, | ||||
| }, | }, | ||||
| { | { | ||||
| name: "port", | name: "port", | ||||
| label: "Port", | |||||
| label: t("Port"), | |||||
| align: "left", | align: "left", | ||||
| headerAlign: "left", | headerAlign: "left", | ||||
| sx: { width: "10%", minWidth: "80px" }, | sx: { width: "10%", minWidth: "80px" }, | ||||
| @@ -45,7 +45,7 @@ const ProductionProcess: React.FC<ProductionProcessProps> = ({ processes }) => { | |||||
| const [isQCModalOpen, setIsQCModalOpen] = React.useState<boolean>(false); | const [isQCModalOpen, setIsQCModalOpen] = React.useState<boolean>(false); | ||||
| const { t } = useTranslation(); | |||||
| const { t } = useTranslation("productionProcess"); | |||||
| console.log("production process"); | console.log("production process"); | ||||
| @@ -122,7 +122,7 @@ const ProductionProcess: React.FC<ProductionProcessProps> = ({ processes }) => { | |||||
| <TableCell>{process.processName}</TableCell> | <TableCell>{process.processName}</TableCell> | ||||
| <TableCell> | <TableCell> | ||||
| <Chip | <Chip | ||||
| label={process.status} | |||||
| label={t(process.status)} | |||||
| color={getStatusColor(process.status)} | color={getStatusColor(process.status)} | ||||
| size="small" | size="small" | ||||
| /> | /> | ||||
| @@ -28,7 +28,7 @@ const QcCategoryDetails = () => { | |||||
| label={t("Code")} | label={t("Code")} | ||||
| fullWidth | fullWidth | ||||
| {...register("code", { | {...register("code", { | ||||
| required: "Code required!", | |||||
| required: t("Code required!"), | |||||
| maxLength: 30, | maxLength: 30, | ||||
| })} | })} | ||||
| /> | /> | ||||
| @@ -38,7 +38,7 @@ const QcCategoryDetails = () => { | |||||
| label={t("Name")} | label={t("Name")} | ||||
| fullWidth | fullWidth | ||||
| {...register("name", { | {...register("name", { | ||||
| required: "Name required!", | |||||
| required: t("Name required!"), | |||||
| maxLength: 30, | maxLength: 30, | ||||
| })} | })} | ||||
| /> | /> | ||||
| @@ -46,6 +46,10 @@ import { | |||||
| submitDialog, | submitDialog, | ||||
| successDialog, | successDialog, | ||||
| } from "../Swal/CustomAlerts"; | } from "../Swal/CustomAlerts"; | ||||
| import { | |||||
| formatQcTypeLabel, | |||||
| translateQcItemAllBackendMessage, | |||||
| } from "./qcItemAllMessages"; | |||||
| type SearchQuery = Partial<Omit<QcCategoryResult, "id">>; | type SearchQuery = Partial<Omit<QcCategoryResult, "id">>; | ||||
| type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
| @@ -181,17 +185,8 @@ const Tab0ItemQcCategoryMapping: React.FC = () => { | |||||
| } catch { | } catch { | ||||
| // 解析失敗就維持原本的 message | // 解析失敗就維持原本的 message | ||||
| } | } | ||||
| let displayMessage = message; | |||||
| if (displayMessage.includes("already has type") && displayMessage.includes("linked to QcCategory")) { | |||||
| const match = displayMessage.match(/type "([^"]+)" linked to QcCategory[:\s]+(.+?)(?:\.|One item)/); | |||||
| const type = match?.[1] ?? ""; | |||||
| const categoryName = match?.[2]?.trim() ?? ""; | |||||
| displayMessage = t("Item already has type \"{{type}}\" in QcCategory \"{{category}}\". One item can only have each type in one QcCategory.", { | |||||
| type, | |||||
| category: categoryName, | |||||
| }); | |||||
| } | |||||
| const displayMessage = translateQcItemAllBackendMessage(message, t); | |||||
| errorDialogWithContent(t("Submit Error"), displayMessage || t("Submit Error"), t); | errorDialogWithContent(t("Submit Error"), displayMessage || t("Submit Error"), t); | ||||
| } | } | ||||
| }, t); | }, t); | ||||
| @@ -218,17 +213,19 @@ const Tab0ItemQcCategoryMapping: React.FC = () => { | |||||
| ); | ); | ||||
| const typeOptions = ["IQC", "IPQC", "EPQC"]; | const typeOptions = ["IQC", "IPQC", "EPQC"]; | ||||
| function formatTypeDisplay(value: unknown): string { | |||||
| if (value == null) return "null"; | |||||
| if (typeof value === "string") return value; | |||||
| if (typeof value === "object" && value !== null && "type" in value) { | |||||
| const v = (value as { type?: unknown }).type; | |||||
| if (typeof v === "string") return v; | |||||
| if (v != null && typeof v === "object") return "null"; // 避免 [object Object] | |||||
| return "null"; | |||||
| } | |||||
| return "null"; | |||||
| } | |||||
| const formatTypeDisplay = useCallback( | |||||
| (value: unknown): string => { | |||||
| if (value == null) return " "; | |||||
| if (typeof value === "string") return formatQcTypeLabel(value, t); | |||||
| if (typeof value === "object" && value !== null && "type" in value) { | |||||
| const v = (value as { type?: unknown }).type; | |||||
| if (typeof v === "string") return formatQcTypeLabel(v, t); | |||||
| return " "; | |||||
| } | |||||
| return " "; | |||||
| }, | |||||
| [t], | |||||
| ); | |||||
| const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
| () => [ | () => [ | ||||
| { label: t("Code"), paramName: "code", type: "text" }, | { label: t("Code"), paramName: "code", type: "text" }, | ||||
| @@ -253,16 +250,7 @@ const Tab0ItemQcCategoryMapping: React.FC = () => { | |||||
| name: "type", | name: "type", | ||||
| label: t("Type"), | label: t("Type"), | ||||
| sx: columnWidthSx("10%"), | sx: columnWidthSx("10%"), | ||||
| renderCell: (row) => { | |||||
| const t = row.type; | |||||
| if (t == null) return " "; // 原来是 "null" | |||||
| if (typeof t === "string") return t; | |||||
| if (typeof t === "object" && t !== null && "type" in t) { | |||||
| const v = (t as { type?: unknown }).type; | |||||
| return typeof v === "string" ? v : " "; // 原来是 "null" | |||||
| } | |||||
| return " "; // 原来是 "null" | |||||
| }, | |||||
| renderCell: (row) => formatTypeDisplay(row.type), | |||||
| }, | }, | ||||
| { | { | ||||
| name: "id", | name: "id", | ||||
| @@ -273,7 +261,7 @@ const Tab0ItemQcCategoryMapping: React.FC = () => { | |||||
| sx: columnWidthSx("10%"), | sx: columnWidthSx("10%"), | ||||
| }, | }, | ||||
| ], | ], | ||||
| [t, handleViewMappings] | |||||
| [t, handleViewMappings, formatTypeDisplay] | |||||
| ); | ); | ||||
| if (loading) { | if (loading) { | ||||
| @@ -333,7 +321,9 @@ const Tab0ItemQcCategoryMapping: React.FC = () => { | |||||
| SelectProps={{ native: true }} | SelectProps={{ native: true }} | ||||
| > | > | ||||
| {typeOptions.map((opt) => ( | {typeOptions.map((opt) => ( | ||||
| <option key={opt} value={opt}>{opt}</option> | |||||
| <option key={opt} value={opt}> | |||||
| {formatQcTypeLabel(opt, t)} | |||||
| </option> | |||||
| ))} | ))} | ||||
| </TextField> | </TextField> | ||||
| <Button | <Button | ||||
| @@ -363,7 +353,12 @@ const Tab0ItemQcCategoryMapping: React.FC = () => { | |||||
| const mappingData = await getItemQcCategoryMappings(selectedCategory.id); | const mappingData = await getItemQcCategoryMappings(selectedCategory.id); | ||||
| setMappings(mappingData); | setMappings(mappingData); | ||||
| } catch (e) { | } catch (e) { | ||||
| errorDialogWithContent(t("Submit Error"), String(e), t); | |||||
| const raw = e instanceof Error ? e.message : String(e); | |||||
| errorDialogWithContent( | |||||
| t("Submit Error"), | |||||
| translateQcItemAllBackendMessage(raw, t), | |||||
| t, | |||||
| ); | |||||
| } finally { | } finally { | ||||
| setSavingCategoryType(false); | setSavingCategoryType(false); | ||||
| } | } | ||||
| @@ -459,7 +454,7 @@ const Tab0ItemQcCategoryMapping: React.FC = () => { | |||||
| > | > | ||||
| {typeOptions.map((type) => ( | {typeOptions.map((type) => ( | ||||
| <option key={type} value={type}> | <option key={type} value={type}> | ||||
| {type} | |||||
| {formatQcTypeLabel(type, t)} | |||||
| </option> | </option> | ||||
| ))} | ))} | ||||
| </TextField> | </TextField> | ||||
| @@ -42,6 +42,10 @@ import { | |||||
| submitDialog, | submitDialog, | ||||
| successDialog, | successDialog, | ||||
| } from "../Swal/CustomAlerts"; | } from "../Swal/CustomAlerts"; | ||||
| import { | |||||
| formatQcTypeLabel, | |||||
| translateQcItemAllBackendMessage, | |||||
| } from "./qcItemAllMessages"; | |||||
| type SearchQuery = Partial<Omit<QcCategoryResult, "id">>; | type SearchQuery = Partial<Omit<QcCategoryResult, "id">>; | ||||
| type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
| @@ -122,7 +126,12 @@ const Tab1QcCategoryQcItemMapping: React.FC = () => { | |||||
| await successDialog(t("Submit Success"), t); | await successDialog(t("Submit Success"), t); | ||||
| // Keep the view dialog open to show updated data | // Keep the view dialog open to show updated data | ||||
| } catch (error) { | } catch (error) { | ||||
| errorDialogWithContent(t("Submit Error"), String(error), t); | |||||
| const raw = error instanceof Error ? error.message : String(error); | |||||
| errorDialogWithContent( | |||||
| t("Submit Error"), | |||||
| translateQcItemAllBackendMessage(raw, t), | |||||
| t, | |||||
| ); | |||||
| } | } | ||||
| }, t); | }, t); | ||||
| }, [selectedCategory, selectedQcItem, order, t]); | }, [selectedCategory, selectedQcItem, order, t]); | ||||
| @@ -140,7 +149,12 @@ const Tab1QcCategoryQcItemMapping: React.FC = () => { | |||||
| setMappings(mappingData); | setMappings(mappingData); | ||||
| // No need to reload categories list - it doesn't change | // No need to reload categories list - it doesn't change | ||||
| } catch (error) { | } catch (error) { | ||||
| errorDialogWithContent(t("Delete Error"), String(error), t); | |||||
| const raw = error instanceof Error ? error.message : String(error); | |||||
| errorDialogWithContent( | |||||
| t("Delete Error"), | |||||
| translateQcItemAllBackendMessage(raw, t), | |||||
| t, | |||||
| ); | |||||
| } | } | ||||
| }, t); | }, t); | ||||
| }, | }, | ||||
| @@ -167,7 +181,13 @@ const Tab1QcCategoryQcItemMapping: React.FC = () => { | |||||
| () => [ | () => [ | ||||
| { name: "code", label: t("Qc Category Code"), sx: columnWidthSx("20%") }, | { name: "code", label: t("Qc Category Code"), sx: columnWidthSx("20%") }, | ||||
| { name: "name", label: t("Qc Category Name"), sx: columnWidthSx("40%") }, | { name: "name", label: t("Qc Category Name"), sx: columnWidthSx("40%") }, | ||||
| { name: "type", label: t("Type"), sx: columnWidthSx("10%") }, | |||||
| { | |||||
| name: "type", | |||||
| label: t("Type"), | |||||
| sx: columnWidthSx("10%"), | |||||
| renderCell: (row) => | |||||
| row.type ? formatQcTypeLabel(String(row.type), t) : " ", | |||||
| }, | |||||
| { | { | ||||
| name: "id", | name: "id", | ||||
| label: t("Actions"), | label: t("Actions"), | ||||
| @@ -180,6 +200,21 @@ const Tab1QcCategoryQcItemMapping: React.FC = () => { | |||||
| [t, handleViewMappings] | [t, handleViewMappings] | ||||
| ); | ); | ||||
| if (loading) { | |||||
| return ( | |||||
| <Box | |||||
| sx={{ | |||||
| display: "flex", | |||||
| justifyContent: "center", | |||||
| alignItems: "center", | |||||
| minHeight: "200px", | |||||
| }} | |||||
| > | |||||
| <CircularProgress /> | |||||
| </Box> | |||||
| ); | |||||
| } | |||||
| return ( | return ( | ||||
| <Box> | <Box> | ||||
| <SearchBox | <SearchBox | ||||
| @@ -24,6 +24,10 @@ import { Add } from "@mui/icons-material"; | |||||
| import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack } from "@mui/material"; | import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack } from "@mui/material"; | ||||
| import QcCategoryDetails from "../QcCategorySave/QcCategoryDetails"; | import QcCategoryDetails from "../QcCategorySave/QcCategoryDetails"; | ||||
| import { FormProvider, useForm } from "react-hook-form"; | import { FormProvider, useForm } from "react-hook-form"; | ||||
| import { | |||||
| formatQcTypeLabel, | |||||
| translateQcItemAllBackendMessage, | |||||
| } from "./qcItemAllMessages"; | |||||
| type SearchQuery = Partial<Omit<QcCategoryResult, "id">>; | type SearchQuery = Partial<Omit<QcCategoryResult, "id">>; | ||||
| type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
| @@ -95,9 +99,12 @@ const Tab2QcCategoryManagement: React.FC = () => { | |||||
| for (const [key, value] of Object.entries(response.errors)) { | for (const [key, value] of Object.entries(response.errors)) { | ||||
| formProps.setError(key as keyof SaveQcCategoryInputs, { | formProps.setError(key as keyof SaveQcCategoryInputs, { | ||||
| type: "custom", | type: "custom", | ||||
| message: value, | |||||
| message: translateQcItemAllBackendMessage(String(value), t), | |||||
| }); | }); | ||||
| errorContents = errorContents + t(value) + "<br>"; | |||||
| errorContents = | |||||
| errorContents + | |||||
| translateQcItemAllBackendMessage(String(value), t) + | |||||
| "<br>"; | |||||
| } | } | ||||
| errorDialogWithContent(t("Submit Error"), errorContents, t); | errorDialogWithContent(t("Submit Error"), errorContents, t); | ||||
| } else { | } else { | ||||
| @@ -106,7 +113,12 @@ const Tab2QcCategoryManagement: React.FC = () => { | |||||
| await loadCategories(); | await loadCategories(); | ||||
| } | } | ||||
| } catch (error) { | } catch (error) { | ||||
| errorDialogWithContent(t("Submit Error"), String(error), t); | |||||
| const raw = error instanceof Error ? error.message : String(error); | |||||
| errorDialogWithContent( | |||||
| t("Submit Error"), | |||||
| translateQcItemAllBackendMessage(raw, t), | |||||
| t, | |||||
| ); | |||||
| } | } | ||||
| }, t); | }, t); | ||||
| }, [formProps, t]); | }, [formProps, t]); | ||||
| @@ -118,8 +130,8 @@ const Tab2QcCategoryManagement: React.FC = () => { | |||||
| if (!canDelete) { | if (!canDelete) { | ||||
| errorDialogWithContent( | errorDialogWithContent( | ||||
| t("Cannot Delete"), | t("Cannot Delete"), | ||||
| t("Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.").replace("{itemCount}", "some").replace("{qcItemCount}", "some"), | |||||
| t | |||||
| t("Cannot delete QcCategory linked"), | |||||
| t, | |||||
| ); | ); | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -130,15 +142,23 @@ const Tab2QcCategoryManagement: React.FC = () => { | |||||
| if (!response.success || !response.canDelete) { | if (!response.success || !response.canDelete) { | ||||
| errorDialogWithContent( | errorDialogWithContent( | ||||
| t("Delete Error"), | t("Delete Error"), | ||||
| response.message || t("Cannot Delete"), | |||||
| t | |||||
| translateQcItemAllBackendMessage( | |||||
| response.message || t("Cannot Delete"), | |||||
| t, | |||||
| ), | |||||
| t, | |||||
| ); | ); | ||||
| } else { | } else { | ||||
| await successDialog(t("Delete Success"), t); | await successDialog(t("Delete Success"), t); | ||||
| await loadCategories(); | await loadCategories(); | ||||
| } | } | ||||
| } catch (error) { | } catch (error) { | ||||
| errorDialogWithContent(t("Delete Error"), String(error), t); | |||||
| const raw = error instanceof Error ? error.message : String(error); | |||||
| errorDialogWithContent( | |||||
| t("Delete Error"), | |||||
| translateQcItemAllBackendMessage(raw, t), | |||||
| t, | |||||
| ); | |||||
| } | } | ||||
| }, t); | }, t); | ||||
| }, [t]); | }, [t]); | ||||
| @@ -158,7 +178,13 @@ const Tab2QcCategoryManagement: React.FC = () => { | |||||
| }, | }, | ||||
| { name: "code", label: t("Code"), sx: columnWidthSx("15%") }, | { name: "code", label: t("Code"), sx: columnWidthSx("15%") }, | ||||
| { name: "name", label: t("Name"), sx: columnWidthSx("30%") }, | { name: "name", label: t("Name"), sx: columnWidthSx("30%") }, | ||||
| { name: "type", label: t("Type"), sx: columnWidthSx("10%") }, | |||||
| { | |||||
| name: "type", | |||||
| label: t("Type"), | |||||
| sx: columnWidthSx("10%"), | |||||
| renderCell: (row) => | |||||
| row.type ? formatQcTypeLabel(String(row.type), t) : " ", | |||||
| }, | |||||
| { | { | ||||
| name: "id", | name: "id", | ||||
| label: t("Delete"), | label: t("Delete"), | ||||
| @@ -24,6 +24,7 @@ import { Add } from "@mui/icons-material"; | |||||
| import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack } from "@mui/material"; | import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack } from "@mui/material"; | ||||
| import QcItemDetails from "../QcItemSave/QcItemDetails"; | import QcItemDetails from "../QcItemSave/QcItemDetails"; | ||||
| import { FormProvider, useForm } from "react-hook-form"; | import { FormProvider, useForm } from "react-hook-form"; | ||||
| import { translateQcItemAllBackendMessage } from "./qcItemAllMessages"; | |||||
| type SearchQuery = Partial<Omit<QcItemResult, "id">>; | type SearchQuery = Partial<Omit<QcItemResult, "id">>; | ||||
| type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
| @@ -95,9 +96,12 @@ const Tab3QcItemManagement: React.FC = () => { | |||||
| for (const [key, value] of Object.entries(response.errors)) { | for (const [key, value] of Object.entries(response.errors)) { | ||||
| formProps.setError(key as keyof SaveQcItemInputs, { | formProps.setError(key as keyof SaveQcItemInputs, { | ||||
| type: "custom", | type: "custom", | ||||
| message: value, | |||||
| message: translateQcItemAllBackendMessage(String(value), t), | |||||
| }); | }); | ||||
| errorContents = errorContents + t(value) + "<br>"; | |||||
| errorContents = | |||||
| errorContents + | |||||
| translateQcItemAllBackendMessage(String(value), t) + | |||||
| "<br>"; | |||||
| } | } | ||||
| errorDialogWithContent(t("Submit Error"), errorContents, t); | errorDialogWithContent(t("Submit Error"), errorContents, t); | ||||
| } else { | } else { | ||||
| @@ -106,7 +110,12 @@ const Tab3QcItemManagement: React.FC = () => { | |||||
| await loadItems(); | await loadItems(); | ||||
| } | } | ||||
| } catch (error) { | } catch (error) { | ||||
| errorDialogWithContent(t("Submit Error"), String(error), t); | |||||
| const raw = error instanceof Error ? error.message : String(error); | |||||
| errorDialogWithContent( | |||||
| t("Submit Error"), | |||||
| translateQcItemAllBackendMessage(raw, t), | |||||
| t, | |||||
| ); | |||||
| } | } | ||||
| }, t); | }, t); | ||||
| }, [formProps, t]); | }, [formProps, t]); | ||||
| @@ -130,15 +139,23 @@ const Tab3QcItemManagement: React.FC = () => { | |||||
| if (!response.success || !response.canDelete) { | if (!response.success || !response.canDelete) { | ||||
| errorDialogWithContent( | errorDialogWithContent( | ||||
| t("Delete Error"), | t("Delete Error"), | ||||
| response.message || t("Cannot Delete"), | |||||
| t | |||||
| translateQcItemAllBackendMessage( | |||||
| response.message || t("Cannot Delete"), | |||||
| t, | |||||
| ), | |||||
| t, | |||||
| ); | ); | ||||
| } else { | } else { | ||||
| await successDialog(t("Delete Success"), t); | await successDialog(t("Delete Success"), t); | ||||
| await loadItems(); | await loadItems(); | ||||
| } | } | ||||
| } catch (error) { | } catch (error) { | ||||
| errorDialogWithContent(t("Delete Error"), String(error), t); | |||||
| const raw = error instanceof Error ? error.message : String(error); | |||||
| errorDialogWithContent( | |||||
| t("Delete Error"), | |||||
| translateQcItemAllBackendMessage(raw, t), | |||||
| t, | |||||
| ); | |||||
| } | } | ||||
| }, t); | }, t); | ||||
| }, [t]); | }, [t]); | ||||
| @@ -0,0 +1,72 @@ | |||||
| import { TFunction } from "i18next"; | |||||
| export function translateQcItemAllBackendMessage( | |||||
| message: string, | |||||
| t: TFunction, | |||||
| ): string { | |||||
| const categoryDeleteMatch = message.match( | |||||
| /Cannot delete QcCategory\. It has (\d+) item\(s\) and (\d+) qc item\(s\) linked to it\./, | |||||
| ); | |||||
| if (categoryDeleteMatch) { | |||||
| return t( | |||||
| "Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.", | |||||
| ) | |||||
| .replace("{itemCount}", categoryDeleteMatch[1]) | |||||
| .replace("{qcItemCount}", categoryDeleteMatch[2]); | |||||
| } | |||||
| if ( | |||||
| message.includes("Cannot delete QcItem") && | |||||
| message.includes("QcCategories") | |||||
| ) { | |||||
| return t( | |||||
| "Cannot delete QcItem. It is linked to one or more QcCategories.", | |||||
| ); | |||||
| } | |||||
| if ( | |||||
| message.includes("already has type") && | |||||
| message.includes("linked to QcCategory") | |||||
| ) { | |||||
| const match = message.match( | |||||
| /type "([^"]+)" linked to QcCategory[:\s]+(.+?)(?:\.|One item)/, | |||||
| ); | |||||
| const type = match?.[1] ?? ""; | |||||
| const categoryName = match?.[2]?.trim() ?? ""; | |||||
| return t( | |||||
| 'Item already has type "{{type}}" in QcCategory "{{category}}". One item can only have each type in one QcCategory.', | |||||
| { type, category: categoryName }, | |||||
| ); | |||||
| } | |||||
| const zhCategoryTypeMatch = message.match( | |||||
| /物料 (.+?) 已經以 (.+?) 映射在模板 (.+?),不能再把模板 (.+?) 改為 (.+)/, | |||||
| ); | |||||
| if (zhCategoryTypeMatch) { | |||||
| return t( | |||||
| "Item {{itemCode}} is already mapped as {{type}} in category {{conflictCategory}}. Cannot set category {{currentCategory}} to {{newType}}.", | |||||
| { | |||||
| itemCode: zhCategoryTypeMatch[1], | |||||
| type: zhCategoryTypeMatch[2], | |||||
| conflictCategory: zhCategoryTypeMatch[3], | |||||
| currentCategory: zhCategoryTypeMatch[4], | |||||
| newType: zhCategoryTypeMatch[5], | |||||
| }, | |||||
| ); | |||||
| } | |||||
| const staticKeys = ["Code cannot be empty", "Name cannot be empty"]; | |||||
| if (staticKeys.includes(message)) { | |||||
| const translated = t(message); | |||||
| if (translated !== message) { | |||||
| return translated; | |||||
| } | |||||
| } | |||||
| return message; | |||||
| } | |||||
| export function formatQcTypeLabel(type: string, t: TFunction): string { | |||||
| const translated = t(`Type.${type}`, { defaultValue: type }); | |||||
| return translated; | |||||
| } | |||||
| @@ -28,7 +28,7 @@ const QcItemDetails = () => { | |||||
| label={t("Code")} | label={t("Code")} | ||||
| fullWidth | fullWidth | ||||
| {...register("code", { | {...register("code", { | ||||
| required: "Code required!", | |||||
| required: t("Code required!"), | |||||
| maxLength: 30, | maxLength: 30, | ||||
| })} | })} | ||||
| /> | /> | ||||
| @@ -38,7 +38,7 @@ const QcItemDetails = () => { | |||||
| label={t("Name")} | label={t("Name")} | ||||
| fullWidth | fullWidth | ||||
| {...register("name", { | {...register("name", { | ||||
| required: "Name required!", | |||||
| required: t("Name required!"), | |||||
| maxLength: 30, | maxLength: 30, | ||||
| })} | })} | ||||
| /> | /> | ||||
| @@ -819,7 +819,7 @@ const ScheduleTaskHistoryModal: React.FC<Props> = ({ | |||||
| </Typography> | </Typography> | ||||
| <Chip | <Chip | ||||
| size="small" | size="small" | ||||
| label={line.lineStatus} | |||||
| label={t(line.lineStatus)} | |||||
| color={lineChipColor} | color={lineChipColor} | ||||
| sx={{ height: 18, fontSize: "0.65rem" }} | sx={{ height: 18, fontSize: "0.65rem" }} | ||||
| /> | /> | ||||
| @@ -97,10 +97,10 @@ export default function TabStockTakeSectionMapping() { | |||||
| const criteria: Criterion<SearchKey>[] = useMemo( | const criteria: Criterion<SearchKey>[] = useMemo( | ||||
| () => [ | () => [ | ||||
| { type: "text", label: "Stock Take Section", paramName: "stockTakeSection", placeholder: "" }, | |||||
| { type: "text", label: "Stock Take Section Description", paramName: "stockTakeSectionDescription", placeholder: "" }, | |||||
| { type: "text", label: t("Stock Take Section"), paramName: "stockTakeSection", placeholder: "" }, | |||||
| { type: "text", label: t("Stock Take Section Description"), paramName: "stockTakeSectionDescription", placeholder: "" }, | |||||
| ], | ], | ||||
| [] | |||||
| [t] | |||||
| ); | ); | ||||
| const handleSearch = useCallback((inputs: Record<SearchKey | `${SearchKey}To`, string>) => { | const handleSearch = useCallback((inputs: Record<SearchKey | `${SearchKey}To`, string>) => { | ||||
| @@ -81,7 +81,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| { label: "入倉日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | { label: "入倉日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | ||||
| { label: "入倉日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | { label: "入倉日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -92,7 +92,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| { label: "出貨日期:由 Last Out Date Start", name: "lastOutDateStart", type: "date", required: false }, | { label: "出貨日期:由 Last Out Date Start", name: "lastOutDateStart", type: "date", required: false }, | ||||
| { label: "出貨日期:至 Last Out Date End", name: "lastOutDateEnd", type: "date", required: false }, | { label: "出貨日期:至 Last Out Date End", name: "lastOutDateEnd", type: "date", required: false }, | ||||
| { label: "年份 Year", name: "year", type: "text", required: false, placeholder: "e.g. 2026" }, | { label: "年份 Year", name: "year", type: "text", required: false, placeholder: "e.g. 2026" }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| /* | /* | ||||
| @@ -102,7 +102,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| fields: [ | fields: [ | ||||
| { label: "盤點日期:由 Stock Take Date Start", name: "stockTakeDateStart", type: "date", required: false }, | { label: "盤點日期:由 Stock Take Date Start", name: "stockTakeDateStart", type: "date", required: false }, | ||||
| { label: "盤點日期:至 Stock Take Date End", name: "stockTakeDateEnd", type: "date", required: false }, | { label: "盤點日期:至 Stock Take Date End", name: "stockTakeDateEnd", type: "date", required: false }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| */ | */ | ||||
| @@ -121,7 +121,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| dynamicOptionsEndpoint: `${NEXT_PUBLIC_API_URL}/report/stock-take-rounds`, | dynamicOptionsEndpoint: `${NEXT_PUBLIC_API_URL}/report/stock-take-rounds`, | ||||
| options: [] | options: [] | ||||
| }, | }, | ||||
| { label: "物料編號", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號", name: "itemCode", type: "text", required: false}, | |||||
| { | { | ||||
| label: "倉庫樓層", | label: "倉庫樓層", | ||||
| name: "store_id", | name: "store_id", | ||||
| @@ -154,7 +154,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| fields: [ | fields: [ | ||||
| { label: "庫存日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | { label: "庫存日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | ||||
| { label: "庫存日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | { label: "庫存日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| /* | /* | ||||
| @@ -172,7 +172,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| dynamicOptionsEndpoint: `${NEXT_PUBLIC_API_URL}/report/stock-take-rounds`, | dynamicOptionsEndpoint: `${NEXT_PUBLIC_API_URL}/report/stock-take-rounds`, | ||||
| options: [] | options: [] | ||||
| }, | }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| */ | */ | ||||
| @@ -183,7 +183,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| fields: [ | fields: [ | ||||
| { label: "庫存日期: Stock Date", name: "stockDate", type: "date", required: true }, | { label: "庫存日期: Stock Date", name: "stockDate", type: "date", required: true }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| @@ -195,7 +195,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| fields: [ | fields: [ | ||||
| { label: "收貨日期:由 Receipt Date Start", name: "receiptDateStart", type: "date", required: false }, | { label: "收貨日期:由 Receipt Date Start", name: "receiptDateStart", type: "date", required: false }, | ||||
| { label: "收貨日期:至 Receipt Date End", name: "receiptDateEnd", type: "date", required: false }, | { label: "收貨日期:至 Receipt Date End", name: "receiptDateEnd", type: "date", required: false }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false }, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false }, | |||||
| ], | ], | ||||
| }, | }, | ||||
| @@ -205,7 +205,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| fields: [ | fields: [ | ||||
| { label: "出貨日期:由 Last Out Date Start", name: "lastOutDateStart", type: "date", required: false }, | { label: "出貨日期:由 Last Out Date Start", name: "lastOutDateStart", type: "date", required: false }, | ||||
| { label: "出貨日期:至 Last Out Date End", name: "lastOutDateEnd", type: "date", required: false }, | { label: "出貨日期:至 Last Out Date End", name: "lastOutDateEnd", type: "date", required: false }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "提料人 Handler", name: "handler", type: "select", required: false, | { label: "提料人 Handler", name: "handler", type: "select", required: false, | ||||
| multiple: true, | multiple: true, | ||||
| dynamicOptions: true, | dynamicOptions: true, | ||||
| @@ -221,16 +221,16 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| { label: "QC 不合格日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | { label: "QC 不合格日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | ||||
| { label: "QC 不合格日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | { label: "QC 不合格日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| { id: "rep-013", | { id: "rep-013", | ||||
| title: "物料出倉追蹤報告", | |||||
| title: "貨品出倉追蹤報告", | |||||
| apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-material-stock-out-traceability`, | apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-material-stock-out-traceability`, | ||||
| fields: [ | fields: [ | ||||
| { label: "庫存日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | { label: "庫存日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, | ||||
| { label: "庫存日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | { label: "庫存日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, | |||||
| { label: "提料人 Handler", name: "handler", type: "select", required: false, | { label: "提料人 Handler", name: "handler", type: "select", required: false, | ||||
| multiple: true, | multiple: true, | ||||
| dynamicOptions: true, | dynamicOptions: true, | ||||
| @@ -256,7 +256,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| { label: "FG", value: "FG" }, | { label: "FG", value: "FG" }, | ||||
| { label: "CMB", value: "CMB" } | { label: "CMB", value: "CMB" } | ||||
| ] }, | ] }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "select", required: false, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "select", required: false, | |||||
| multiple: true, | multiple: true, | ||||
| allowInput: true, | allowInput: true, | ||||
| dynamicOptions: true, | dynamicOptions: true, | ||||
| @@ -282,7 +282,7 @@ export const REPORTS: ReportDefinition[] = [ | |||||
| { label: "WIP", value: "WIP" }, | { label: "WIP", value: "WIP" }, | ||||
| { label: "FG", value: "FG" }, | { label: "FG", value: "FG" }, | ||||
| ] }, | ] }, | ||||
| { label: "物料編號 Item Code", name: "itemCode", type: "select", required: false, | |||||
| { label: "貨品編號 Item Code", name: "itemCode", type: "select", required: false, | |||||
| multiple: true, | multiple: true, | ||||
| allowInput: true, | allowInput: true, | ||||
| dynamicOptions: true, | dynamicOptions: true, | ||||
| @@ -23,6 +23,7 @@ | |||||
| "Day Before Yesterday": "前天", | "Day Before Yesterday": "前天", | ||||
| "Delete": "刪除", | "Delete": "刪除", | ||||
| "Delete Failed": "刪除失敗", | "Delete Failed": "刪除失敗", | ||||
| "Do you want to delete?": "Do you want to delete?", | |||||
| "Density": "濃淡", | "Density": "濃淡", | ||||
| "Depth": "顔色深淺度 深1淺5", | "Depth": "顔色深淺度 深1淺5", | ||||
| "Description": "描述", | "Description": "描述", | ||||
| @@ -42,6 +43,7 @@ | |||||
| "Grade {{grade}}": "等級 {{grade}}", | "Grade {{grade}}": "等級 {{grade}}", | ||||
| "Invoice": "發票", | "Invoice": "發票", | ||||
| "Invoice Date": "發票日期", | "Invoice Date": "發票日期", | ||||
| "IP": "IP", | |||||
| "Item Code": "Item Code", | "Item Code": "Item Code", | ||||
| "Item Name": "Item Name", | "Item Name": "Item Name", | ||||
| "Loading": "載入中...", | "Loading": "載入中...", | ||||
| @@ -51,6 +53,7 @@ | |||||
| "MAT": "材料", | "MAT": "材料", | ||||
| "MI": "雜項", | "MI": "雜項", | ||||
| "Material Name": "材料清單", | "Material Name": "材料清單", | ||||
| "Name": "Name", | |||||
| "Min": "最小值", | "Min": "最小值", | ||||
| "NM": "雜項及非消耗品", | "NM": "雜項及非消耗品", | ||||
| "No": "否", | "No": "否", | ||||
| @@ -59,6 +62,7 @@ | |||||
| "No options": "沒有選項", | "No options": "沒有選項", | ||||
| "Order": "順序", | "Order": "順序", | ||||
| "Pending": "Pending", | "Pending": "Pending", | ||||
| "Port": "Port", | |||||
| "Please Select BOM": "請選擇 BOM", | "Please Select BOM": "請選擇 BOM", | ||||
| "Please try again later.": "請稍後重試。", | "Please try again later.": "請稍後重試。", | ||||
| "Project Code": "專案代碼", | "Project Code": "專案代碼", | ||||
| @@ -88,6 +92,7 @@ | |||||
| "Supporting Document": "證明文件", | "Supporting Document": "證明文件", | ||||
| "Task": "任務", | "Task": "任務", | ||||
| "Time Sequence": "時段", | "Time Sequence": "時段", | ||||
| "Type": "Type", | |||||
| "Today": "今天", | "Today": "今天", | ||||
| "Total weighting must equal 1": "權重總和必須等於 1", | "Total weighting must equal 1": "權重總和必須等於 1", | ||||
| "Unauthorized: Please log in again": "未經授權:請重新登入", | "Unauthorized: Please log in again": "未經授權:請重新登入", | ||||
| @@ -49,6 +49,11 @@ | |||||
| "Order Date From": "Order Date From", | "Order Date From": "Order Date From", | ||||
| "Order Date To": "Order Date To", | "Order Date To": "Order Date To", | ||||
| "Pending": "Pending", | "Pending": "Pending", | ||||
| "pending": "Pending", | |||||
| "picking": "Picking", | |||||
| "receiving": "Receiving", | |||||
| "released": "Released", | |||||
| "completed": "Completed", | |||||
| "Pick Order Assignment": "Pick Order Assignment", | "Pick Order Assignment": "Pick Order Assignment", | ||||
| "Please wait": "Please wait", | "Please wait": "Please wait", | ||||
| "Price": "Price", | "Price": "Price", | ||||
| @@ -17,8 +17,10 @@ | |||||
| "Order": "Order", | "Order": "Order", | ||||
| "Code": "Code", | "Code": "Code", | ||||
| "Name": "Name", | "Name": "Name", | ||||
| "Shipping Warehouse": "Shipping Warehouse", | |||||
| "Receiving Warehouse": "Receiving Warehouse", | |||||
| "Shipping Warehouse": "Default Stock Out Location", | |||||
| "Receiving Warehouse": "Default Stock In Location", | |||||
| "Stock In Location": "Stock In Location", | |||||
| "Stock Out Location": "Stock Out Location", | |||||
| "Actions": "Actions", | "Actions": "Actions", | ||||
| "Loading": "Loading...", | "Loading": "Loading...", | ||||
| "No data available": "No data available", | "No data available": "No data available", | ||||
| @@ -34,5 +36,6 @@ | |||||
| "Confirm": "Confirm", | "Confirm": "Confirm", | ||||
| "Move to order": "Move to order", | "Move to order": "Move to order", | ||||
| "Target order": "Target order", | "Target order": "Target order", | ||||
| "This will move the item to exact order": "This will move the item to the specified order and reorder the rest" | |||||
| "This will move the item to exact order": "This will move the item to the specified order and reorder the rest", | |||||
| "Click to set": "Click to set" | |||||
| } | } | ||||
| @@ -1,4 +1,6 @@ | |||||
| { | { | ||||
| "Code": "Code", | |||||
| "Name": "Name", | |||||
| "Create Material": "Create Material", | "Create Material": "Create Material", | ||||
| "Update Equipment Maintenance and Repair": "Update Equipment Maintenance and Repair", | "Update Equipment Maintenance and Repair": "Update Equipment Maintenance and Repair", | ||||
| "Correct BOM List (Can Import)": "Correct BOM List (Can Import)", | "Correct BOM List (Can Import)": "Correct BOM List (Can Import)", | ||||
| @@ -8,5 +10,39 @@ | |||||
| "Is Drink": "Is Drink", | "Is Drink": "Is Drink", | ||||
| "Drink": "Drink", | "Drink": "Drink", | ||||
| "Powder_Mixture": "Powder Mixture", | "Powder_Mixture": "Powder Mixture", | ||||
| "Base Score": "Base Score" | |||||
| "Base Score": "Base Score", | |||||
| "Basic Info": "Basic Info", | |||||
| "Edit": "Edit", | |||||
| "Save": "Save", | |||||
| "Cancel": "Cancel", | |||||
| "Loading...": "Loading...", | |||||
| "Saving...": "Saving...", | |||||
| "Output Quantity": "Output Quantity", | |||||
| "Output Quantity UOM": "Output Quantity UOM", | |||||
| "Type": "Type", | |||||
| "Allergic Substances": "Allergic Substances", | |||||
| "Depth": "Depth", | |||||
| "Float": "Float", | |||||
| "Density": "Density", | |||||
| "Time Sequence": "Time Sequence", | |||||
| "Complexity": "Complexity", | |||||
| "Scrap Rate": "Scrap Rate", | |||||
| "Item Code": "Item Code", | |||||
| "Item Name": "Item Name", | |||||
| "Base Qty": "Base Qty", | |||||
| "Base UOM": "Base UOM", | |||||
| "Stock Qty": "Stock Qty", | |||||
| "Stock UOM": "Stock UOM", | |||||
| "Sales Qty": "Sales Qty", | |||||
| "Sales UOM": "Sales UOM", | |||||
| "Process & Equipment": "Process & Equipment", | |||||
| "Process Code": "Process Code", | |||||
| "Process Description": "Process Description", | |||||
| "Process Name": "Process Name", | |||||
| "Duration (Minutes)": "Duration (Minutes)", | |||||
| "Prep Time (Minutes)": "Prep Time (Minutes)", | |||||
| "Post Prod Time (Minutes)": "Post Prod Time (Minutes)", | |||||
| "Add": "Add", | |||||
| "Sequence": "Sequence", | |||||
| "Actions": "Actions" | |||||
| } | } | ||||
| @@ -606,6 +606,10 @@ | |||||
| "packaging": "packaging", | "packaging": "packaging", | ||||
| "paused": "paused", | "paused": "paused", | ||||
| "pending": "pending", | "pending": "pending", | ||||
| "pendingQC": "Pending QC", | |||||
| "planning": "Planning", | |||||
| "processing": "Processing", | |||||
| "scanned": "Scanned", | |||||
| "printQty": "printQty", | "printQty": "printQty", | ||||
| "process epqc": "process epqc", | "process epqc": "process epqc", | ||||
| "process stockIn": "process stockIn", | "process stockIn": "process stockIn", | ||||
| @@ -1,3 +1,49 @@ | |||||
| { | { | ||||
| "title": "M18 Sync" | |||||
| "title": "M18 Sync", | |||||
| "pageTitle": "M18 Sync (by code)", | |||||
| "pageSubtitle": "ADMIN only. Sync Purchase Order, Delivery Order, or product/material from M18 using document or item code.", | |||||
| "tabPo": "1. Purchase Order", | |||||
| "tabDo": "2. Delivery Order", | |||||
| "tabDoExtra": "3. Delivery Order (Extra)", | |||||
| "tabProduct": "4. Product", | |||||
| "sectionPo": "M18 Purchase Order — sync by code", | |||||
| "sectionDo": "M18 Delivery Order — sync by code", | |||||
| "sectionDoExtra": "M18 Delivery Order — Extra (isExtra)", | |||||
| "sectionProduct": "M18 Product / Material — sync by code", | |||||
| "labelPoCode": "PO Code", | |||||
| "labelDoCode": "DO / Shop PO Code", | |||||
| "labelDoExtraCode": "DO / Shop PO Code (Extra)", | |||||
| "labelProductCode": "Item / Product Code", | |||||
| "labelSyncResult": "Sync Result", | |||||
| "btnSyncPo": "Sync PO from M18", | |||||
| "btnSyncDo": "Sync DO from M18", | |||||
| "btnSyncDoExtra": "Sync DO (Extra) from M18", | |||||
| "btnSyncProduct": "Sync product from M18", | |||||
| "syncing": "Syncing...", | |||||
| "placeholderPoCode": "e.g. PFP002PO26030341", | |||||
| "placeholderDoCode": "e.g. same document code as M18 shop PO", | |||||
| "placeholderDoExtraCode": "Enter multiple codes separated by comma or newline", | |||||
| "placeholderProductCode": "e.g. PP1175 (M18 item code)", | |||||
| "waiting": "Waiting for implementation...", | |||||
| "noResponse": "No response received", | |||||
| "alreadyExists": "{{docName}} already exists in system", | |||||
| "notFoundInM18": "{{docName}} not found in M18", | |||||
| "syncSuccess": "Synced successfully: {{total}} {{docName}}(s)", | |||||
| "syncFail": "Failed: unable to sync {{docName}}", | |||||
| "syncMixed": "Complete: success {{success}} / fail {{fail}} ({{docName}})", | |||||
| "syncedOk": "Synced successfully", | |||||
| "summarySuccess": "{{count}} delivery order(s) synced successfully", | |||||
| "summaryNotFound": "{{count}} order(s) not found in M18 ({{codes}})", | |||||
| "summaryExists": "{{count}} order(s) already exist in system ({{codes}})", | |||||
| "summaryFail": "{{count}} order(s) sync failed ({{codes}})", | |||||
| "alertEnterPoCode": "Please enter PO code.", | |||||
| "alertEnterDoCode": "Please enter DO / shop PO code.", | |||||
| "alertEnterDoExtraCode": "Please enter DO / shop PO code(s) (Extra).", | |||||
| "alertEnterAtLeastOne": "Please enter at least one code.", | |||||
| "alertEnterProductCode": "Please enter M18 item / product code.", | |||||
| "alertSyncFailed": "Sync failed: {{status}}", | |||||
| "errorPoSync": "M18 PO sync failed. Check console/network.", | |||||
| "errorDoSync": "M18 DO sync failed. Check console/network.", | |||||
| "errorDoExtraSync": "M18 DO (Extra) sync failed. Check console/network.", | |||||
| "errorProductSync": "M18 product sync failed. Check console/network." | |||||
| } | } | ||||
| @@ -94,15 +94,15 @@ | |||||
| "qty cannot be greater than remaining qty": "qty cannot be greater than remaining qty", | "qty cannot be greater than remaining qty": "qty cannot be greater than remaining qty", | ||||
| "Record pol": "Record pol", | "Record pol": "Record pol", | ||||
| "Add some entries!": "Add some entries!", | "Add some entries!": "Add some entries!", | ||||
| "draft": "draft", | |||||
| "pending": "pending", | |||||
| "determine1": "determine1", | |||||
| "determine2": "determine2", | |||||
| "determine3": "determine3", | |||||
| "receiving": "receiving", | |||||
| "received": "received", | |||||
| "completed": "completed", | |||||
| "rejected": "rejected", | |||||
| "draft": "Draft", | |||||
| "pending": "Pending", | |||||
| "determine1": "Escalation 1", | |||||
| "determine2": "Escalation 2", | |||||
| "determine3": "Escalation 3", | |||||
| "receiving": "Receiving", | |||||
| "received": "Awaiting Putaway", | |||||
| "completed": "Completed", | |||||
| "rejected": "Rejected", | |||||
| "success": "success", | "success": "success", | ||||
| "acceptedQty must not greater than": "acceptedQty must not greater than", | "acceptedQty must not greater than": "acceptedQty must not greater than", | ||||
| "minimal value is 1": "minimal value is 1", | "minimal value is 1": "minimal value is 1", | ||||
| @@ -5,8 +5,11 @@ | |||||
| "notEscalated": "notEscalated", | "notEscalated": "notEscalated", | ||||
| "All": "All", | "All": "All", | ||||
| "Pending": "Pending", | "Pending": "Pending", | ||||
| "pending": "Pending", | |||||
| "Receiving": "Receiving", | "Receiving": "Receiving", | ||||
| "receiving": "Receiving", | |||||
| "Completed": "Completed", | "Completed": "Completed", | ||||
| "completed": "Completed", | |||||
| "Purchase Order": "Purchase Order", | "Purchase Order": "Purchase Order", | ||||
| "Details": "Details", | "Details": "Details", | ||||
| "OrderDate": "OrderDate", | "OrderDate": "OrderDate", | ||||
| @@ -1,8 +1,18 @@ | |||||
| { | { | ||||
| "Brand": "Brand", | |||||
| "Create Printer": "Create Printer", | "Create Printer": "Create Printer", | ||||
| "Delete": "Delete", | |||||
| "Delete Failed": "Delete failed", | |||||
| "Delete Success": "Delete Success", | |||||
| "Description": "Description", | |||||
| "DPI": "DPI", | |||||
| "Edit": "Edit", | "Edit": "Edit", | ||||
| "IP": "IP", | |||||
| "Name": "Name", | |||||
| "PDF Preview": "PDF Preview", | "PDF Preview": "PDF Preview", | ||||
| "Port": "Port", | |||||
| "Print failed": "Print failed", | "Print failed": "Print failed", | ||||
| "Print job sent successfully": "Print job sent successfully", | "Print job sent successfully": "Print job sent successfully", | ||||
| "Printer": "Printer" | |||||
| "Printer": "Printer", | |||||
| "Type": "Type" | |||||
| } | } | ||||
| @@ -59,6 +59,11 @@ | |||||
| "Finished lines": "Finished lines", | "Finished lines": "Finished lines", | ||||
| "In Progress": "In Progress", | "In Progress": "In Progress", | ||||
| "In progress": "In progress", | "In progress": "In progress", | ||||
| "Not Started": "Not Started", | |||||
| "cancelled": "Cancelled", | |||||
| "in_progress": "In Progress", | |||||
| "pending": "Pending", | |||||
| "stopped": "Stopped", | |||||
| "Invalid Job Order Id": "Invalid Job Order Id", | "Invalid Job Order Id": "Invalid Job Order Id", | ||||
| "Invalid Stock In Line Id": "Invalid Stock In Line Id", | "Invalid Stock In Line Id": "Invalid Stock In Line Id", | ||||
| "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity", | "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity", | ||||
| @@ -1,4 +1,8 @@ | |||||
| { | { | ||||
| "Code cannot be empty": "Code cannot be empty", | |||||
| "Code required!": "Code is required", | |||||
| "Name cannot be empty": "Name cannot be empty", | |||||
| "Name required!": "Name is required", | |||||
| "Cancel": "Cancel", | "Cancel": "Cancel", | ||||
| "Code": "Code", | "Code": "Code", | ||||
| "Create Qc Category": "Create Qc Category", | "Create Qc Category": "Create Qc Category", | ||||
| @@ -1,4 +1,8 @@ | |||||
| { | { | ||||
| "Code cannot be empty": "Code cannot be empty", | |||||
| "Code required!": "Code is required", | |||||
| "Name cannot be empty": "Name cannot be empty", | |||||
| "Name required!": "Name is required", | |||||
| "Cancel": "Cancel", | "Cancel": "Cancel", | ||||
| "Code": "Code", | "Code": "Code", | ||||
| "Create Qc Item": "Create Qc Item", | "Create Qc Item": "Create Qc Item", | ||||
| @@ -1,4 +1,11 @@ | |||||
| { | { | ||||
| "Code cannot be empty": "Code cannot be empty", | |||||
| "Code required!": "Code is required", | |||||
| "Error": "Error", | |||||
| "Item {{itemCode}} is already mapped as {{type}} in category {{conflictCategory}}. Cannot set category {{currentCategory}} to {{newType}}.": "Item {{itemCode}} is already mapped as {{type}} in category {{conflictCategory}}. Cannot set category {{currentCategory}} to {{newType}}.", | |||||
| "Loading...": "Loading...", | |||||
| "Name cannot be empty": "Name cannot be empty", | |||||
| "Name required!": "Name is required", | |||||
| "Actions": "Actions", | "Actions": "Actions", | ||||
| "Add": "Add", | "Add": "Add", | ||||
| "Add Association": "Add Association", | "Add Association": "Add Association", | ||||
| @@ -7,6 +14,7 @@ | |||||
| "Association Details": "Association Details", | "Association Details": "Association Details", | ||||
| "Cancel": "Cancel", | "Cancel": "Cancel", | ||||
| "Cannot Delete": "Cannot Delete", | "Cannot Delete": "Cannot Delete", | ||||
| "Cannot delete QcCategory linked": "Cannot delete QcCategory. It still has linked items or QC items.", | |||||
| "Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.": "Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.", | "Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.": "Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.", | ||||
| "Cannot delete QcItem. It is linked to one or more QcCategories.": "Cannot delete QcItem. It is linked to one or more QcCategories.", | "Cannot delete QcItem. It is linked to one or more QcCategories.": "Cannot delete QcItem. It is linked to one or more QcCategories.", | ||||
| "Category": "Category", | "Category": "Category", | ||||
| @@ -62,5 +70,8 @@ | |||||
| "Submit Error": "Submit Error", | "Submit Error": "Submit Error", | ||||
| "Submit Success": "Submit Success", | "Submit Success": "Submit Success", | ||||
| "Type": "Type", | "Type": "Type", | ||||
| "Type.EPQC": "End-product QC (EPQC)", | |||||
| "Type.IPQC": "In-process QC (IPQC)", | |||||
| "Type.IQC": "Incoming QC (IQC)", | |||||
| "View": "View" | "View": "View" | ||||
| } | } | ||||
| @@ -329,6 +329,14 @@ | |||||
| "schedule_history_subtitle": "Monitor, run, or troubleshoot scheduled shop-lane changes", | "schedule_history_subtitle": "Monitor, run, or troubleshoot scheduled shop-lane changes", | ||||
| "schedule_history_success_lines": "{{count}} shop move(s) succeeded", | "schedule_history_success_lines": "{{count}} shop move(s) succeeded", | ||||
| "schedule_history_title": "Scheduled task status & history", | "schedule_history_title": "Scheduled task status & history", | ||||
| "PENDING": "Pending", | |||||
| "APPLYING": "Applying", | |||||
| "APPLIED": "Applied", | |||||
| "PARTIAL": "Partial", | |||||
| "FAILED": "Failed", | |||||
| "CANCELLED": "Cancelled", | |||||
| "IGNORED": "Ignored", | |||||
| "SKIPPED": "Skipped", | |||||
| "schedule_history_unknown_user": "System", | "schedule_history_unknown_user": "System", | ||||
| "schedule_history_view_lines": "View shop lines", | "schedule_history_view_lines": "View shop lines", | ||||
| "schedule_import_col_action": "Action", | "schedule_import_col_action": "Action", | ||||
| @@ -42,7 +42,7 @@ | |||||
| "Tomorrow": "Tomorrow", | "Tomorrow": "Tomorrow", | ||||
| "Truck Information": "Truck Information", | "Truck Information": "Truck Information", | ||||
| "Truck Lane Code": "Truck Lane Code", | "Truck Lane Code": "Truck Lane Code", | ||||
| "completed": "completed", | |||||
| "pending": "pending", | |||||
| "released": "released" | |||||
| "completed": "Completed", | |||||
| "pending": "Pending", | |||||
| "released": "Released" | |||||
| } | } | ||||
| @@ -41,6 +41,8 @@ | |||||
| "view user": "view user", | "view user": "view user", | ||||
| "An error has occurred. Please try again later.": "An error has occurred. Please try again later.", | "An error has occurred. Please try again later.": "An error has occurred. Please try again later.", | ||||
| "Please input correct password": "Please input correct password", | "Please input correct password": "Please input correct password", | ||||
| "The password requires 8-20 characters.": "The password requires 8-20 characters.", | |||||
| "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.": "The password must be 8-20 characters and include uppercase letters, lowercase letters, numbers, and symbols.", | |||||
| "Failed to search by name": "Failed to search by name", | "Failed to search by name": "Failed to search by name", | ||||
| "Failed to search by username": "Failed to search by username", | "Failed to search by username": "Failed to search by username", | ||||
| "Staff No is required": "Staff No is required", | "Staff No is required": "Staff No is required", | ||||
| @@ -23,6 +23,7 @@ | |||||
| "Day Before Yesterday": "前天", | "Day Before Yesterday": "前天", | ||||
| "Delete": "刪除", | "Delete": "刪除", | ||||
| "Delete Failed": "刪除失敗", | "Delete Failed": "刪除失敗", | ||||
| "Do you want to delete?": "您確定要刪除嗎?", | |||||
| "Density": "濃淡", | "Density": "濃淡", | ||||
| "Depth": "顔色深淺度 深1淺5", | "Depth": "顔色深淺度 深1淺5", | ||||
| "Description": "描述", | "Description": "描述", | ||||
| @@ -43,6 +44,7 @@ | |||||
| "Invalid Job Order Id": "無效工單編號", | "Invalid Job Order Id": "無效工單編號", | ||||
| "Invoice": "發票", | "Invoice": "發票", | ||||
| "Invoice Date": "發票日期", | "Invoice Date": "發票日期", | ||||
| "IP": "IP 地址", | |||||
| "Item Code": "物品編號", | "Item Code": "物品編號", | ||||
| "Item Name": "物品名稱", | "Item Name": "物品名稱", | ||||
| "Loading": "載入中...", | "Loading": "載入中...", | ||||
| @@ -53,6 +55,7 @@ | |||||
| "MI": "雜項", | "MI": "雜項", | ||||
| "Management Job Order": "管理工單", | "Management Job Order": "管理工單", | ||||
| "Material Name": "材料清單", | "Material Name": "材料清單", | ||||
| "Name": "名稱", | |||||
| "Min": "最小值", | "Min": "最小值", | ||||
| "NM": "雜項及非消耗品", | "NM": "雜項及非消耗品", | ||||
| "No": "否", | "No": "否", | ||||
| @@ -62,6 +65,7 @@ | |||||
| "No processes found for this job order": "找不到此工單的工序", | "No processes found for this job order": "找不到此工單的工序", | ||||
| "Order": "順序", | "Order": "順序", | ||||
| "Pending": "待處理", | "Pending": "待處理", | ||||
| "Port": "連接埠", | |||||
| "Please Select BOM": "請選擇 BOM", | "Please Select BOM": "請選擇 BOM", | ||||
| "Please try again later.": "請稍後重試。", | "Please try again later.": "請稍後重試。", | ||||
| "Project Code": "專案代碼", | "Project Code": "專案代碼", | ||||
| @@ -91,6 +95,7 @@ | |||||
| "Supporting Document": "證明文件", | "Supporting Document": "證明文件", | ||||
| "Task": "任務", | "Task": "任務", | ||||
| "Time Sequence": "時段", | "Time Sequence": "時段", | ||||
| "Type": "類型", | |||||
| "Today": "今天", | "Today": "今天", | ||||
| "Total weighting must equal 1": "權重總和必須等於 1", | "Total weighting must equal 1": "權重總和必須等於 1", | ||||
| "Unauthorized: Please log in again": "未經授權:請重新登入", | "Unauthorized: Please log in again": "未經授權:請重新登入", | ||||
| @@ -53,6 +53,8 @@ | |||||
| "Details": "詳情", | "Details": "詳情", | ||||
| "Pending": "待處理", | "Pending": "待處理", | ||||
| "pending": "待處理", | "pending": "待處理", | ||||
| "picking": "提料中", | |||||
| "released": "已放單", | |||||
| "Receiving": "接收中", | "Receiving": "接收中", | ||||
| "receiving": "接收中", | "receiving": "接收中", | ||||
| "Completed": "已完成", | "Completed": "已完成", | ||||
| @@ -1,4 +1,6 @@ | |||||
| { | { | ||||
| "Code": "物品編號", | |||||
| "Name": "物品名稱", | |||||
| "Create Material": "新增材料", | "Create Material": "新增材料", | ||||
| "Update Equipment Maintenance and Repair": "更新設備的維護和保養", | "Update Equipment Maintenance and Repair": "更新設備的維護和保養", | ||||
| "Correct BOM List (Can Import)": "正確 BOM 列表(可匯入)", | "Correct BOM List (Can Import)": "正確 BOM 列表(可匯入)", | ||||
| @@ -8,5 +10,39 @@ | |||||
| "Is Drink": "飲料", | "Is Drink": "飲料", | ||||
| "Drink": "飲料", | "Drink": "飲料", | ||||
| "Powder_Mixture": "箱料粉", | "Powder_Mixture": "箱料粉", | ||||
| "Base Score": "基礎得分" | |||||
| "Base Score": "基礎得分", | |||||
| "Basic Info": "基本資訊", | |||||
| "Edit": "編輯", | |||||
| "Save": "儲存", | |||||
| "Cancel": "取消", | |||||
| "Loading...": "載入中…", | |||||
| "Saving...": "儲存中…", | |||||
| "Output Quantity": "產出數量", | |||||
| "Output Quantity UOM": "產出單位", | |||||
| "Type": "類型", | |||||
| "Allergic Substances": "過敏原", | |||||
| "Depth": "色深", | |||||
| "Float": "浮沉", | |||||
| "Density": "濃淡", | |||||
| "Time Sequence": "時段", | |||||
| "Complexity": "複雜度", | |||||
| "Scrap Rate": "損耗率", | |||||
| "Item Code": "物品編號", | |||||
| "Item Name": "物品名稱", | |||||
| "Base Qty": "基本數量", | |||||
| "Base UOM": "基本單位", | |||||
| "Stock Qty": "庫存數量", | |||||
| "Stock UOM": "庫存單位", | |||||
| "Sales Qty": "銷售數量", | |||||
| "Sales UOM": "銷售單位", | |||||
| "Process & Equipment": "製程與設備", | |||||
| "Process Code": "工序代碼", | |||||
| "Process Description": "工序說明", | |||||
| "Process Name": "工序名稱", | |||||
| "Duration (Minutes)": "時間(分)", | |||||
| "Prep Time (Minutes)": "準備時間(分鐘)", | |||||
| "Post Prod Time (Minutes)": "收尾時間(分鐘)", | |||||
| "Add": "新增", | |||||
| "Sequence": "次序", | |||||
| "Actions": "操作" | |||||
| } | } | ||||
| @@ -606,6 +606,10 @@ | |||||
| "packaging": "提料中", | "packaging": "提料中", | ||||
| "paused": "已暫停", | "paused": "已暫停", | ||||
| "pending": "待處理", | "pending": "待處理", | ||||
| "pendingQC": "待品檢", | |||||
| "planning": "規劃中", | |||||
| "processing": "生產中", | |||||
| "scanned": "已掃描", | |||||
| "printQty": "打印數量", | "printQty": "打印數量", | ||||
| "process epqc": "進行成品檢驗", | "process epqc": "進行成品檢驗", | ||||
| "process stockIn": "進行收貨程序", | "process stockIn": "進行收貨程序", | ||||
| @@ -1,3 +1,49 @@ | |||||
| { | { | ||||
| "title": "M18 同步" | |||||
| "title": "M18 同步", | |||||
| "pageTitle": "M18 同步", | |||||
| "pageSubtitle": "僅限管理員。使用文件或貨品編號從 M18 同步採購單、送貨訂單或貨品/物料。", | |||||
| "tabPo": "1. 採購單", | |||||
| "tabDo": "2. 送貨訂單", | |||||
| "tabDoExtra": "3. 送貨訂單 (加單)", | |||||
| "tabProduct": "4. 貨品", | |||||
| "sectionPo": "M18 採購單 — sync by code", | |||||
| "sectionDo": "M18 送貨訂單 — sync by code", | |||||
| "sectionDoExtra": "M18 送貨訂單 — 加單", | |||||
| "sectionProduct": "M18 貨品 / 物料 — sync by code", | |||||
| "labelPoCode": "採購單編號", | |||||
| "labelDoCode": "送貨單 / 店鋪訂單編號", | |||||
| "labelDoExtraCode": "送貨單 / 店鋪訂單編號(加單)", | |||||
| "labelProductCode": "貨品 / 物料編號", | |||||
| "labelSyncResult": "同步結果", | |||||
| "btnSyncPo": "從 M18 同步採購單", | |||||
| "btnSyncDo": "從 M18 同步送貨訂單", | |||||
| "btnSyncDoExtra": "從 M18 同步送貨訂單(加單)", | |||||
| "btnSyncProduct": "從 M18 同步貨品", | |||||
| "syncing": "同步中…", | |||||
| "placeholderPoCode": "例:PFP002PO26030341", | |||||
| "placeholderDoCode": "例:與 M18 店鋪訂單相同的文件編號", | |||||
| "placeholderDoExtraCode": "可輸入多個 code,用逗號或換行分隔", | |||||
| "placeholderProductCode": "例:PP1175(M18 貨品編號)", | |||||
| "waiting": "等待實作…", | |||||
| "noResponse": "未收到回應", | |||||
| "alreadyExists": "{{docName}}已存在系統", | |||||
| "notFoundInM18": "在M18找不到{{docName}}", | |||||
| "syncSuccess": "成功同步:{{total}}張{{docName}}", | |||||
| "syncFail": "失敗:無法同步{{docName}}", | |||||
| "syncMixed": "完成:成功 {{success}}/失敗 {{fail}}({{docName}})", | |||||
| "syncedOk": "成功同步", | |||||
| "summarySuccess": "共{{count}}張送貨訂單成功", | |||||
| "summaryNotFound": "共{{count}}張在M18找不到訂單({{codes}})", | |||||
| "summaryExists": "共{{count}}張訂單已存在系統({{codes}})", | |||||
| "summaryFail": "共{{count}}張同步失敗({{codes}})", | |||||
| "alertEnterPoCode": "請輸入採購單編號。", | |||||
| "alertEnterDoCode": "請輸入送貨單/店鋪訂單編號。", | |||||
| "alertEnterDoExtraCode": "請輸入送貨單/店鋪訂單編號(加單)。", | |||||
| "alertEnterAtLeastOne": "請輸入至少一個編號。", | |||||
| "alertEnterProductCode": "請輸入 M18 貨品/物料編號。", | |||||
| "alertSyncFailed": "同步失敗:{{status}}", | |||||
| "errorPoSync": "M18 採購單同步失敗,請檢查 console/network。", | |||||
| "errorDoSync": "M18 送貨訂單同步失敗,請檢查 console/network。", | |||||
| "errorDoExtraSync": "M18 送貨訂單(加單)同步失敗,請檢查 console/network。", | |||||
| "errorProductSync": "M18 貨品同步失敗,請檢查 console/network。" | |||||
| } | } | ||||
| @@ -5,8 +5,11 @@ | |||||
| "notEscalated": "未升级", | "notEscalated": "未升级", | ||||
| "All": "全部", | "All": "全部", | ||||
| "Pending": "待处理", | "Pending": "待处理", | ||||
| "pending": "待處理", | |||||
| "Receiving": "接收中", | "Receiving": "接收中", | ||||
| "receiving": "接收中", | |||||
| "Completed": "已完成", | "Completed": "已完成", | ||||
| "completed": "已完成", | |||||
| "Purchase Order": "采购订单", | "Purchase Order": "采购订单", | ||||
| "Details": "详情", | "Details": "详情", | ||||
| "OrderDate": "订单日期", | "OrderDate": "订单日期", | ||||
| @@ -1,8 +1,18 @@ | |||||
| { | { | ||||
| "Brand": "品牌", | |||||
| "Create Printer": "新增列印機", | "Create Printer": "新增列印機", | ||||
| "Delete": "刪除", | |||||
| "Delete Failed": "刪除失敗", | |||||
| "Delete Success": "刪除成功", | |||||
| "Description": "描述", | |||||
| "DPI": "DPI", | |||||
| "Edit": "編輯", | "Edit": "編輯", | ||||
| "IP": "IP 地址", | |||||
| "Name": "名稱", | |||||
| "PDF Preview": "PDF 預覽", | "PDF Preview": "PDF 預覽", | ||||
| "Port": "連接埠", | |||||
| "Print failed": "列印失敗", | "Print failed": "列印失敗", | ||||
| "Print job sent successfully": "列印作業已成功送出", | "Print job sent successfully": "列印作業已成功送出", | ||||
| "Printer": "列印機" | |||||
| "Printer": "列印機", | |||||
| "Type": "類型" | |||||
| } | } | ||||
| @@ -59,6 +59,11 @@ | |||||
| "Finished lines": "已完成流程", | "Finished lines": "已完成流程", | ||||
| "In Progress": "進行中", | "In Progress": "進行中", | ||||
| "In progress": "進行中", | "In progress": "進行中", | ||||
| "Not Started": "未開始", | |||||
| "cancelled": "已取消", | |||||
| "in_progress": "進行中", | |||||
| "pending": "待處理", | |||||
| "stopped": "已停止", | |||||
| "Invalid Job Order Id": "無效工單編號", | "Invalid Job Order Id": "無效工單編號", | ||||
| "Invalid Stock In Line Id": "無效庫存行ID", | "Invalid Stock In Line Id": "無效庫存行ID", | ||||
| "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間次序 | 複雜度", | "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間次序 | 複雜度", | ||||
| @@ -1,4 +1,8 @@ | |||||
| { | { | ||||
| "Code cannot be empty": "編號不可為空", | |||||
| "Code required!": "請輸入編號", | |||||
| "Name cannot be empty": "名稱不可為空", | |||||
| "Name required!": "請輸入名稱", | |||||
| "Qc Category": "品檢模板", | "Qc Category": "品檢模板", | ||||
| "Qc Category List": "QC 類別列表", | "Qc Category List": "QC 類別列表", | ||||
| "Qc Category Name": "QC 類別名稱", | "Qc Category Name": "QC 類別名稱", | ||||
| @@ -1,4 +1,8 @@ | |||||
| { | { | ||||
| "Code cannot be empty": "編號不可為空", | |||||
| "Code required!": "請輸入編號", | |||||
| "Name cannot be empty": "名稱不可為空", | |||||
| "Name required!": "請輸入名稱", | |||||
| "Name": "名稱", | "Name": "名稱", | ||||
| "Code": "編號", | "Code": "編號", | ||||
| "Description": "描述", | "Description": "描述", | ||||
| @@ -1,4 +1,11 @@ | |||||
| { | { | ||||
| "Code cannot be empty": "編號不可為空", | |||||
| "Code required!": "請輸入編號", | |||||
| "Error": "錯誤", | |||||
| "Item {{itemCode}} is already mapped as {{type}} in category {{conflictCategory}}. Cannot set category {{currentCategory}} to {{newType}}.": "物料 {{itemCode}} 已以 {{type}} 映射於模板「{{conflictCategory}}」,無法將模板「{{currentCategory}}」改為 {{newType}}。", | |||||
| "Loading...": "載入中...", | |||||
| "Name cannot be empty": "名稱不可為空", | |||||
| "Name required!": "請輸入名稱", | |||||
| "Qc Item All": "QC 綜合管理", | "Qc Item All": "QC 綜合管理", | ||||
| "Item and Qc Category Mapping": "物品與品檢模板映射", | "Item and Qc Category Mapping": "物品與品檢模板映射", | ||||
| "Qc Category and Qc Item Mapping": "品檢模板與品檢項目映射", | "Qc Category and Qc Item Mapping": "品檢模板與品檢項目映射", | ||||
| @@ -20,6 +27,9 @@ | |||||
| "Name": "名稱", | "Name": "名稱", | ||||
| "Description": "描述", | "Description": "描述", | ||||
| "Type": "類型", | "Type": "類型", | ||||
| "Type.EPQC": "生產後品檢EPQC", | |||||
| "Type.IPQC": "製程品檢IPQC", | |||||
| "Type.IQC": "來貨品檢IQC", | |||||
| "Order": "順序", | "Order": "順序", | ||||
| "Item Count": "關聯物品數量", | "Item Count": "關聯物品數量", | ||||
| "Qc Item Count": "關聯品檢項目數量", | "Qc Item Count": "關聯品檢項目數量", | ||||
| @@ -44,7 +54,8 @@ | |||||
| "Submit Success": "提交成功", | "Submit Success": "提交成功", | ||||
| "Submit Error": "提交失敗", | "Submit Error": "提交失敗", | ||||
| "Cannot Delete": "無法刪除", | "Cannot Delete": "無法刪除", | ||||
| "Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.": "無法刪除品檢模板。它有 {itemCount} 個物品和 {qcItemCount} 個品檢項目與其關聯。", | |||||
| "Cannot delete QcCategory linked": "無法刪除品檢模板,仍有物品或品檢項目與其關聯。", | |||||
| "Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.": "無法刪除品檢模板,仍有 {itemCount} 個物品及 {qcItemCount} 個品檢項目與其關聯。", | |||||
| "Cannot delete QcItem. It is linked to one or more QcCategories.": "無法刪除品檢項目。它與一個或多個品檢模板關聯。", | "Cannot delete QcItem. It is linked to one or more QcCategories.": "無法刪除品檢項目。它與一個或多個品檢模板關聯。", | ||||
| "Select Item": "選擇物品", | "Select Item": "選擇物品", | ||||
| "Select Qc Category": "選擇品檢模板", | "Select Qc Category": "選擇品檢模板", | ||||
| @@ -359,6 +359,14 @@ | |||||
| "schedule_history_ignore": "忽略", | "schedule_history_ignore": "忽略", | ||||
| "schedule_history_status_ignored": "已忽略", | "schedule_history_status_ignored": "已忽略", | ||||
| "schedule_history_close": "關閉視窗", | "schedule_history_close": "關閉視窗", | ||||
| "PENDING": "待處理", | |||||
| "APPLYING": "執行中", | |||||
| "APPLIED": "已套用", | |||||
| "PARTIAL": "部分完成", | |||||
| "FAILED": "失敗", | |||||
| "CANCELLED": "已取消", | |||||
| "IGNORED": "已忽略", | |||||
| "SKIPPED": "已跳過", | |||||
| "schedule_log_failed_hint": "有 {{count}} 個預約任務執行失敗,請查看 Log", | "schedule_log_failed_hint": "有 {{count}} 個預約任務執行失敗,請查看 Log", | ||||
| "btn_scheduleHistory": "查看預約變更 Log", | "btn_scheduleHistory": "查看預約變更 Log", | ||||
| "id": "ID", | "id": "ID", | ||||
| @@ -1,7 +1,7 @@ | |||||
| { | { | ||||
| "View Details": "查看詳細", | "View Details": "查看詳細", | ||||
| "Back to List": "返回列表", | "Back to List": "返回列表", | ||||
| "Stock Take Section": "盤點區域", | |||||
| "Stock Take Section": "盤點區域類型", | |||||
| "Warehouse": "倉庫", | "Warehouse": "倉庫", | ||||
| "All": "全部", | "All": "全部", | ||||
| "Rows per page": "每頁行數", | "Rows per page": "每頁行數", | ||||
| @@ -21,7 +21,7 @@ | |||||
| "Cancel": "取消", | "Cancel": "取消", | ||||
| "Confirm": "確認", | "Confirm": "確認", | ||||
| "Type": "類型", | "Type": "類型", | ||||
| "Status": "來貨狀態", | |||||
| "Status": "盤點狀態", | |||||
| "Lot No": "批號", | "Lot No": "批號", | ||||
| "Location": "位置", | "Location": "位置", | ||||
| "Reason": "原因", | "Reason": "原因", | ||||
| @@ -41,6 +41,8 @@ | |||||
| "Testing": "測試", | "Testing": "測試", | ||||
| "An error has occurred. Please try again later.": "發生錯誤,請稍後再試。", | "An error has occurred. Please try again later.": "發生錯誤,請稍後再試。", | ||||
| "Please input correct password": "請輸入正確密碼", | "Please input correct password": "請輸入正確密碼", | ||||
| "The password requires 8-20 characters.": "密碼須為 8 至 20 個字元。", | |||||
| "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.": "密碼須為 8 至 20 個字元,且須同時包含大寫字母、小寫字母、數字及符號。", | |||||
| "Failed to search by name": "依名稱搜尋失敗", | "Failed to search by name": "依名稱搜尋失敗", | ||||
| "Failed to search by username": "依使用者名稱搜尋失敗", | "Failed to search by username": "依使用者名稱搜尋失敗", | ||||
| "Staff No is required": "員工編號必填", | "Staff No is required": "員工編號必填", | ||||
| @@ -32,7 +32,7 @@ | |||||
| "store_id": "樓層", | "store_id": "樓層", | ||||
| "area": "區域", | "area": "區域", | ||||
| "slot": "位置", | "slot": "位置", | ||||
| "order": "提料單次序", | |||||
| "order": "提料區域次序", | |||||
| "stockTakeSection": "盤點區域", | "stockTakeSection": "盤點區域", | ||||
| "Do you want to delete?": "您確定要刪除嗎?", | "Do you want to delete?": "您確定要刪除嗎?", | ||||
| "Cancel": "取消", | "Cancel": "取消", | ||||