tommy 1 неделю назад
Родитель
Сommit
66f3589d34
61 измененных файлов: 585 добавлений и 140 удалений
  1. +7
    -4
      src/app/(main)/settings/qcItemAll/page.tsx
  2. +9
    -0
      src/components/Breadcrumb/Breadcrumb.tsx
  3. +3
    -3
      src/components/CreatePrinter/CreatePrinter.tsx
  4. +2
    -1
      src/components/CreateUser/CreateUser.tsx
  5. +2
    -2
      src/components/DoSearch/DoSearch.tsx
  6. +2
    -2
      src/components/DoSearchWorkbench/DoSearchWorkbench.tsx
  7. +3
    -3
      src/components/EditPrinter/EditPrinter.tsx
  8. +2
    -1
      src/components/EditUser/EditUser.tsx
  9. +3
    -3
      src/components/FinishedGoodSearch/AssignAndRelease.tsx
  10. +1
    -0
      src/components/FinishedGoodSearch/ConsolidatedPickOrders.tsx
  11. +2
    -2
      src/components/FinishedGoodSearch/FinishedGood.tsx
  12. +1
    -2
      src/components/FinishedGoodSearch/FinishedGoodSearch.tsx
  13. +2
    -2
      src/components/JoSave/InfoCard.tsx
  14. +2
    -2
      src/components/JoSearch/JoSearch.tsx
  15. +2
    -2
      src/components/JoWorkbench/JoWorkbenchSearch.tsx
  16. +2
    -2
      src/components/Jodetail/Jodetail.tsx
  17. +1
    -2
      src/components/Jodetail/JodetailSearch.tsx
  18. +1
    -0
      src/components/PickOrderSearch/ConsolidatedPickOrders.tsx
  19. +4
    -4
      src/components/PrinterSearch/PrinterSearch.tsx
  20. +2
    -2
      src/components/ProductionProcess/ProductionProcess.tsx
  21. +2
    -2
      src/components/QcCategorySave/QcCategoryDetails.tsx
  22. +31
    -36
      src/components/QcItemAll/Tab0ItemQcCategoryMapping.tsx
  23. +38
    -3
      src/components/QcItemAll/Tab1QcCategoryQcItemMapping.tsx
  24. +35
    -9
      src/components/QcItemAll/Tab2QcCategoryManagement.tsx
  25. +23
    -6
      src/components/QcItemAll/Tab3QcItemManagement.tsx
  26. +72
    -0
      src/components/QcItemAll/qcItemAllMessages.ts
  27. +2
    -2
      src/components/QcItemSave/QcItemDetails.tsx
  28. +1
    -1
      src/components/Shop/ScheduleTaskHistoryModal.tsx
  29. +3
    -3
      src/components/Warehouse/TabStockTakeSectionMapping.tsx
  30. +14
    -14
      src/config/reportConfig.ts
  31. +5
    -0
      src/i18n/en/common.json
  32. +5
    -0
      src/i18n/en/do.json
  33. +6
    -3
      src/i18n/en/finishedgoodmanagement.json
  34. +37
    -1
      src/i18n/en/importBom.json
  35. +4
    -0
      src/i18n/en/jo.json
  36. +47
    -1
      src/i18n/en/m18Sync.json
  37. +9
    -9
      src/i18n/en/pickOrder.json
  38. +3
    -0
      src/i18n/en/po.json
  39. +11
    -1
      src/i18n/en/printer.json
  40. +5
    -0
      src/i18n/en/productionProcess.json
  41. +4
    -0
      src/i18n/en/qcCategory.json
  42. +4
    -0
      src/i18n/en/qcItem.json
  43. +11
    -0
      src/i18n/en/qcItemAll.json
  44. +8
    -0
      src/i18n/en/shop.json
  45. +3
    -3
      src/i18n/en/ticketReleaseTable.json
  46. +2
    -0
      src/i18n/en/user.json
  47. +5
    -0
      src/i18n/zh/common.json
  48. +2
    -0
      src/i18n/zh/do.json
  49. +37
    -1
      src/i18n/zh/importBom.json
  50. +4
    -0
      src/i18n/zh/jo.json
  51. +47
    -1
      src/i18n/zh/m18Sync.json
  52. +3
    -0
      src/i18n/zh/po.json
  53. +11
    -1
      src/i18n/zh/printer.json
  54. +5
    -0
      src/i18n/zh/productionProcess.json
  55. +4
    -0
      src/i18n/zh/qcCategory.json
  56. +4
    -0
      src/i18n/zh/qcItem.json
  57. +12
    -1
      src/i18n/zh/qcItemAll.json
  58. +8
    -0
      src/i18n/zh/shop.json
  59. +2
    -2
      src/i18n/zh/stockTake.json
  60. +2
    -0
      src/i18n/zh/user.json
  61. +1
    -1
      src/i18n/zh/warehouse.json

+ 7
- 4
src/app/(main)/settings/qcItemAll/page.tsx Просмотреть файл

@@ -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 />}


+ 9
- 0
src/components/Breadcrumb/Breadcrumb.tsx Просмотреть файл

@@ -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",


+ 3
- 3
src/components/CreatePrinter/CreatePrinter.tsx Просмотреть файл

@@ -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")}


+ 2
- 1
src/components/CreateUser/CreateUser.tsx Просмотреть файл

@@ -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",
}); });
} }


+ 2
- 2
src/components/DoSearch/DoSearch.tsx Просмотреть файл

@@ -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);
}, },
}, },
], ],


+ 2
- 2
src/components/DoSearchWorkbench/DoSearchWorkbench.tsx Просмотреть файл

@@ -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);
}, },
}, },
], ],


+ 3
- 3
src/components/EditPrinter/EditPrinter.tsx Просмотреть файл

@@ -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")}


+ 2
- 1
src/components/EditUser/EditUser.tsx Просмотреть файл

@@ -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",
}); });
} }


+ 3
- 3
src/components/FinishedGoodSearch/AssignAndRelease.tsx Просмотреть файл

@@ -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>
)) ))


+ 1
- 0
src/components/FinishedGoodSearch/ConsolidatedPickOrders.tsx Просмотреть файл

@@ -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],


+ 2
- 2
src/components/FinishedGoodSearch/FinishedGood.tsx Просмотреть файл

@@ -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);
}, },
}, },
], ],


+ 1
- 2
src/components/FinishedGoodSearch/FinishedGoodSearch.tsx Просмотреть файл

@@ -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",
), ),


+ 2
- 2
src/components/JoSave/InfoCard.tsx Просмотреть файл

@@ -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}/>*/}


+ 2
- 2
src/components/JoSearch/JoSearch.tsx Просмотреть файл

@@ -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>
} }
}, },


+ 2
- 2
src/components/JoWorkbench/JoWorkbenchSearch.tsx Просмотреть файл

@@ -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>
} }
}, },


+ 2
- 2
src/components/Jodetail/Jodetail.tsx Просмотреть файл

@@ -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);
}, },
}, },
], ],


+ 1
- 2
src/components/Jodetail/JodetailSearch.tsx Просмотреть файл

@@ -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",
), ),


+ 1
- 0
src/components/PickOrderSearch/ConsolidatedPickOrders.tsx Просмотреть файл

@@ -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],


+ 4
- 4
src/components/PrinterSearch/PrinterSearch.tsx Просмотреть файл

@@ -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" },


+ 2
- 2
src/components/ProductionProcess/ProductionProcess.tsx Просмотреть файл

@@ -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"
/> />


+ 2
- 2
src/components/QcCategorySave/QcCategoryDetails.tsx Просмотреть файл

@@ -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,
})} })}
/> />


+ 31
- 36
src/components/QcItemAll/Tab0ItemQcCategoryMapping.tsx Просмотреть файл

@@ -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>


+ 38
- 3
src/components/QcItemAll/Tab1QcCategoryQcItemMapping.tsx Просмотреть файл

@@ -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


+ 35
- 9
src/components/QcItemAll/Tab2QcCategoryManagement.tsx Просмотреть файл

@@ -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"),


+ 23
- 6
src/components/QcItemAll/Tab3QcItemManagement.tsx Просмотреть файл

@@ -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]);


+ 72
- 0
src/components/QcItemAll/qcItemAllMessages.ts Просмотреть файл

@@ -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;
}

+ 2
- 2
src/components/QcItemSave/QcItemDetails.tsx Просмотреть файл

@@ -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,
})} })}
/> />


+ 1
- 1
src/components/Shop/ScheduleTaskHistoryModal.tsx Просмотреть файл

@@ -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" }}
/> />


+ 3
- 3
src/components/Warehouse/TabStockTakeSectionMapping.tsx Просмотреть файл

@@ -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>) => {


+ 14
- 14
src/config/reportConfig.ts Просмотреть файл

@@ -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,


+ 5
- 0
src/i18n/en/common.json Просмотреть файл

@@ -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": "未經授權:請重新登入",


+ 5
- 0
src/i18n/en/do.json Просмотреть файл

@@ -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",


+ 6
- 3
src/i18n/en/finishedgoodmanagement.json Просмотреть файл

@@ -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"
} }

+ 37
- 1
src/i18n/en/importBom.json Просмотреть файл

@@ -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"
} }

+ 4
- 0
src/i18n/en/jo.json Просмотреть файл

@@ -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",


+ 47
- 1
src/i18n/en/m18Sync.json Просмотреть файл

@@ -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."
} }

+ 9
- 9
src/i18n/en/pickOrder.json Просмотреть файл

@@ -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",


+ 3
- 0
src/i18n/en/po.json Просмотреть файл

@@ -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",


+ 11
- 1
src/i18n/en/printer.json Просмотреть файл

@@ -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"
} }

+ 5
- 0
src/i18n/en/productionProcess.json Просмотреть файл

@@ -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",


+ 4
- 0
src/i18n/en/qcCategory.json Просмотреть файл

@@ -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",


+ 4
- 0
src/i18n/en/qcItem.json Просмотреть файл

@@ -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",


+ 11
- 0
src/i18n/en/qcItemAll.json Просмотреть файл

@@ -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"
} }

+ 8
- 0
src/i18n/en/shop.json Просмотреть файл

@@ -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",


+ 3
- 3
src/i18n/en/ticketReleaseTable.json Просмотреть файл

@@ -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"
} }

+ 2
- 0
src/i18n/en/user.json Просмотреть файл

@@ -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",


+ 5
- 0
src/i18n/zh/common.json Просмотреть файл

@@ -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": "未經授權:請重新登入",


+ 2
- 0
src/i18n/zh/do.json Просмотреть файл

@@ -53,6 +53,8 @@
"Details": "詳情", "Details": "詳情",
"Pending": "待處理", "Pending": "待處理",
"pending": "待處理", "pending": "待處理",
"picking": "提料中",
"released": "已放單",
"Receiving": "接收中", "Receiving": "接收中",
"receiving": "接收中", "receiving": "接收中",
"Completed": "已完成", "Completed": "已完成",


+ 37
- 1
src/i18n/zh/importBom.json Просмотреть файл

@@ -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": "操作"
} }

+ 4
- 0
src/i18n/zh/jo.json Просмотреть файл

@@ -606,6 +606,10 @@
"packaging": "提料中", "packaging": "提料中",
"paused": "已暫停", "paused": "已暫停",
"pending": "待處理", "pending": "待處理",
"pendingQC": "待品檢",
"planning": "規劃中",
"processing": "生產中",
"scanned": "已掃描",
"printQty": "打印數量", "printQty": "打印數量",
"process epqc": "進行成品檢驗", "process epqc": "進行成品檢驗",
"process stockIn": "進行收貨程序", "process stockIn": "進行收貨程序",


+ 47
- 1
src/i18n/zh/m18Sync.json Просмотреть файл

@@ -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。"
} }

+ 3
- 0
src/i18n/zh/po.json Просмотреть файл

@@ -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": "订单日期",


+ 11
- 1
src/i18n/zh/printer.json Просмотреть файл

@@ -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": "類型"
} }

+ 5
- 0
src/i18n/zh/productionProcess.json Просмотреть файл

@@ -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": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間次序 | 複雜度",


+ 4
- 0
src/i18n/zh/qcCategory.json Просмотреть файл

@@ -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 類別名稱",


+ 4
- 0
src/i18n/zh/qcItem.json Просмотреть файл

@@ -1,4 +1,8 @@
{ {
"Code cannot be empty": "編號不可為空",
"Code required!": "請輸入編號",
"Name cannot be empty": "名稱不可為空",
"Name required!": "請輸入名稱",
"Name": "名稱", "Name": "名稱",
"Code": "編號", "Code": "編號",
"Description": "描述", "Description": "描述",


+ 12
- 1
src/i18n/zh/qcItemAll.json Просмотреть файл

@@ -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": "選擇品檢模板",


+ 8
- 0
src/i18n/zh/shop.json Просмотреть файл

@@ -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",


+ 2
- 2
src/i18n/zh/stockTake.json Просмотреть файл

@@ -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": "原因",


+ 2
- 0
src/i18n/zh/user.json Просмотреть файл

@@ -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": "員工編號必填",


+ 1
- 1
src/i18n/zh/warehouse.json Просмотреть файл

@@ -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": "取消",


Загрузка…
Отмена
Сохранить