diff --git a/src/app/(main)/settings/m18ImportTesting/page.tsx b/src/app/(main)/settings/m18ImportTesting/page.tsx index dc426cb..f234fe0 100644 --- a/src/app/(main)/settings/m18ImportTesting/page.tsx +++ b/src/app/(main)/settings/m18ImportTesting/page.tsx @@ -3,6 +3,7 @@ import { getServerI18n } from "@/i18n"; import { Stack } from "@mui/material"; import { Metadata } from "next"; import React, { Suspense } from "react"; +import { I18nProvider } from "@/i18n"; export const metadata: Metadata = { title: "Import Testing" @@ -21,7 +22,9 @@ const M18ImportTestingPage: React.FC = async () => { > }> - + + + ) diff --git a/src/app/api/dashboard/actions.ts b/src/app/api/dashboard/actions.ts new file mode 100644 index 0000000..d30135a --- /dev/null +++ b/src/app/api/dashboard/actions.ts @@ -0,0 +1,159 @@ +"use server"; +// import { BASE_API_URL } from "@/config/api"; +import { BASE_API_URL } from "../../../config/api"; +// import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; +import { revalidateTag } from "next/cache"; +import { cache } from "react"; +import { PoResult, StockInLine } from "."; +//import { serverFetchJson } from "@/app/utils/fetchUtil"; +import { serverFetchJson } from "../../utils/fetchUtil"; +import { QcItemResult } from "../settings/qcItem"; +import { RecordsRes } from "../utils"; +// import { BASE_API_URL } from "@/config/api"; + +export interface PostStockInLiineResponse { + id: number | null; + name: string; + code: string; + type?: string + message: string | null; + errorPosition: string | keyof T; + entity: T | T[] + // entity: StockInLine | StockInLine[] +} + +export interface StockInLineEntry { + id?: number + itemId: number + purchaseOrderId: number + purchaseOrderLineId: number + acceptedQty: number + status?: string + expiryDate?: string +} + +export interface PurchaseQcResult { + qcItemId: number; + failQty: number; +} +export interface StockInInput { + status: string + productLotNo?: string, + receiptDate: string + acceptedQty: number + acceptedWeight?: number + productionDate?: string + expiryDate: string +} +export interface PurchaseQCInput { + status: string + acceptedQty: number + sampleRate: number; + sampleWeight: number; + totalWeight: number; + qcResult: PurchaseQcResult[]; +} +export interface EscalationInput { + status: string + handler: string + acceptedQty: number // this is the qty to be escalated + // escalationQty: number +} +export interface PutawayInput { + status: string + acceptedQty: number + warehouseId: number + // handler: string + // stockInLine: StockInLineEntry[] +} + +export type ModalFormInput = Partial + +export const testFetch = cache(async (id: number) => { + return serverFetchJson(`${BASE_API_URL}/po/detail/${id}`, { + next: { tags: ["po"] }, + }); +}); + +export const fetchStockInLineInfo = cache(async (stockInLineId: number) => { + return serverFetchJson(`${BASE_API_URL}/stockInLine/${stockInLineId}`, { + next: { tags: ["stockInLine"] }, + }); +}); + +export const createStockInLine = async (data: StockInLineEntry) => { + const stockInLine = await serverFetchJson>(`${BASE_API_URL}/stockInLine/create`, { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); + // revalidateTag("po"); + return stockInLine +} + +export const updateStockInLine = async (data: StockInLineEntry & ModalFormInput) => { + const stockInLine = await serverFetchJson>(`${BASE_API_URL}/stockInLine/update`, { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }); + // revalidateTag("po"); + return stockInLine +} + +export const startPo = async (poId: number) => { + const po = await serverFetchJson>(`${BASE_API_URL}/po/start/${poId}`, { + method: "POST", + body: JSON.stringify({ poId }), + headers: { "Content-Type": "application/json" }, + }); + revalidateTag("po"); + return po +} + +export const checkPolAndCompletePo = async (poId: number) => { + const po = await serverFetchJson>(`${BASE_API_URL}/po/check/${poId}`, { + method: "POST", + body: JSON.stringify({ poId }), + headers: { "Content-Type": "application/json" }, + }); + revalidateTag("po"); + return po +} + +export const fetchPoInClient = cache(async (id: number) => { + return serverFetchJson(`${BASE_API_URL}/po/detail/${id}`, { + next: { tags: ["po"] }, + }); +}); + + export const fetchPoListClient = cache(async (queryParams?: Record) => { + if (queryParams) { + const queryString = new URLSearchParams(queryParams).toString(); + return serverFetchJson>(`${BASE_API_URL}/po/list?${queryString}`, { + method: 'GET', + next: { tags: ["po"] }, + }); + } else { + return serverFetchJson>(`${BASE_API_URL}/po/list`, { + method: 'GET', + next: { tags: ["po"] }, + }); + } + }); + + export const testing = cache(async (queryParams?: Record) => { + if (queryParams) { + const queryString = new URLSearchParams(queryParams).toString(); + return serverFetchJson>(`${BASE_API_URL}/po/testing?${queryString}`, { + method: 'GET', + next: { tags: ["po"] }, + }); + } else { + return serverFetchJson>(`${BASE_API_URL}/po/testing`, { + method: 'GET', + next: { tags: ["po"] }, + }); + } + }); + diff --git a/src/app/api/dashboard/index.ts b/src/app/api/dashboard/index.ts new file mode 100644 index 0000000..84ee091 --- /dev/null +++ b/src/app/api/dashboard/index.ts @@ -0,0 +1,81 @@ +import { cache } from "react"; +import "server-only"; +// import { serverFetchJson } from "@/app/utils/fetchUtil"; +// import { BASE_API_URL } from "@/config/api"; +import { serverFetchJson } from "../../utils/fetchUtil"; +import { BASE_API_URL } from "../../../config/api"; +import { Uom } from "../settings/uom"; +import { RecordsRes } from "../utils"; + +export interface PoResult { + id: number + code: string + orderDate: string + supplier: string + estimatedArrivalDate: string + completedDate: string + escalated: boolean + status: string + pol?: PurchaseOrderLine[] + } + +export interface PurchaseOrderLine { + id: number + purchaseOrderId: number + itemId: number + itemNo: string + itemName: string + qty: number + processed: number + uom: Uom + price: number + status: string + stockInLine: StockInLine[] +} + +export interface StockInLine { + id: number + stockInId: number + purchaseOrderId?: number + purchaseOrderLineId: number + itemId: number + itemNo: string + itemName: string + itemType: string + demandQty: number + acceptedQty: number + price: number + priceUnit: string + shelfLife?: number, + receiptDate?: string + productionDate?: string + expiryDate?: string + status: string + supplier: string + lotNo: string + poCode: string + uom: Uom + defaultWarehouseId: number // id for now +} + + + export const fetchPoList = cache(async (queryParams?: Record) => { + if (queryParams) { + const queryString = new URLSearchParams(queryParams).toString(); + return serverFetchJson>(`${BASE_API_URL}/po/list?${queryString}`, { + method: 'GET', + next: { tags: ["po"] }, + }); + } else { + return serverFetchJson>(`${BASE_API_URL}/po/list`, { + method: 'GET', + next: { tags: ["po"] }, + }); + } + }); + + export const fetchPoWithStockInLines = cache(async (id: number) => { + return serverFetchJson(`${BASE_API_URL}/po/detail/${id}`, { + next: { tags: ["po"] }, + }); + }); \ No newline at end of file diff --git a/src/components/DashboardPage/CollapsibleCard.tsx b/src/components/DashboardPage/CollapsibleCard.tsx new file mode 100644 index 0000000..4214ae4 --- /dev/null +++ b/src/components/DashboardPage/CollapsibleCard.tsx @@ -0,0 +1,32 @@ +import React, { useState } from "react"; +import { Card, CardHeader, CardContent, IconButton, Collapse } from "@mui/material"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; +import ExpandLessIcon from "@mui/icons-material/ExpandLess"; + +interface CollapsibleCardProps { + title: string; + children: React.ReactNode; + defaultOpen?: boolean; +} + +const CollapsibleCard: React.FC = ({ title, children, defaultOpen = true }) => { + const [open, setOpen] = useState(defaultOpen); + + return ( + + setOpen((v) => !v)}> + {open ? : } + + } + /> + + {children} + + + ); +}; + +export default CollapsibleCard; \ No newline at end of file diff --git a/src/components/DashboardPage/DashboardLineChart.tsx b/src/components/DashboardPage/DashboardLineChart.tsx deleted file mode 100644 index 425be25..0000000 --- a/src/components/DashboardPage/DashboardLineChart.tsx +++ /dev/null @@ -1,18 +0,0 @@ -"use client" -// npm install -interface Props { // params type - -} - -const DashboardLineChart: React.FC = ({ - // params - }) => { - - return ( - <> - line chart - - ) -} -export default DashboardLineChart - diff --git a/src/components/DashboardPage/DashboardPage.tsx b/src/components/DashboardPage/DashboardPage.tsx index dc50888..b2f06fd 100644 --- a/src/components/DashboardPage/DashboardPage.tsx +++ b/src/components/DashboardPage/DashboardPage.tsx @@ -6,9 +6,14 @@ import { TabsProps } from "@mui/material/Tabs"; import React, { useCallback, useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { Card, CardContent, CardHeader, Grid } from "@mui/material"; -import DashboardProgressChart from "../DashboardProgressChart/DashboardProgressChart"; -import DashboardLineChart from "../DashboardLineChart/DashboardLineChart"; - +import DashboardProgressChart from "./chart/DashboardProgressChart"; +import DashboardLineChart from "./chart/DashboardLineChart"; +import PendingInspectionChart from "./chart/PendingInspectionChart"; +import PendingStorageChart from "./chart/PendingStorageChart"; +import ApplicationCompletionChart from "./chart/ApplicationCompletionChart"; +import OrderCompletionChart from "./chart/OrderCompletionChart"; +import DashboardBox from "./DashboardBox"; +import CollapsibleCard from "./CollapsibleCard"; type Props = {}; const DashboardPage: React.FC = ({}) => { @@ -17,30 +22,58 @@ const DashboardPage: React.FC = ({}) => { return ( - <> - - - - - + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + - - + + - + + + + ); }; diff --git a/src/components/DashboardPage/DashboardProgressChart.tsx b/src/components/DashboardPage/DashboardProgressChart.tsx deleted file mode 100644 index f5ec1a1..0000000 --- a/src/components/DashboardPage/DashboardProgressChart.tsx +++ /dev/null @@ -1,18 +0,0 @@ -"use client" - -interface Props { // params type - -} - -const DashboardProgressChart: React.FC = ({ - // params - }) => { - - return ( - <> - progress chart - - ) -} -export default DashboardProgressChart - diff --git a/src/components/DashboardPage/Dashboardbox.tsx b/src/components/DashboardPage/Dashboardbox.tsx new file mode 100644 index 0000000..6db6682 --- /dev/null +++ b/src/components/DashboardPage/Dashboardbox.tsx @@ -0,0 +1,30 @@ +"use client" +import React from "react"; + +interface DashboardBoxProps { + title: string; + value: string | number; + unit: string; + time?: string; +} + +const DashboardBox: React.FC = ({ title, value, unit, time }) => { + return ( +
+
{title}
+
+ {value} {unit} +
+
{time || "NaN/NaN/NaN NaN:NaN:NaN"}
+
+ ); +}; + +export default DashboardBox; \ No newline at end of file diff --git a/src/components/DashboardPage/chart/ApplicationCompletionChart.tsx b/src/components/DashboardPage/chart/ApplicationCompletionChart.tsx new file mode 100644 index 0000000..9c025b3 --- /dev/null +++ b/src/components/DashboardPage/chart/ApplicationCompletionChart.tsx @@ -0,0 +1,126 @@ +"use client" +import React, { useState } from "react"; +import dynamic from "next/dynamic"; +const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); +import { useTranslation } from "react-i18next"; +const ApplicationCompletionChart: React.FC = () => { + const { t } = useTranslation(); + const [tab, setTab] = useState(t("Raw material")); + const percent = 0; + const options = { + chart: { type: "donut" as const }, + labels: [], + colors: ["#42A5F5", "#e0e0e0"], + dataLabels: { + enabled: true, + formatter: () => `${percent}%`, + style: { fontSize: "32px", fontWeight: 600, color: "#1976d2" } + }, + legend: { show: false }, + plotOptions: { + pie: { + donut: { + size: "70%", + labels: { + show: false + } + } + } + }, + stroke: { show: true, width: 2, colors: ['#fff'] } + }; + + return ( +
+
+ + {t("Application completion")} + +
+ + +
+
+
+ +
+
+
{t("Processed application")}: 0
+
{t("Pending application")}: 0
+
+
+ ); +}; + +export default ApplicationCompletionChart; \ No newline at end of file diff --git a/src/components/DashboardPage/chart/DashboardLineChart.tsx b/src/components/DashboardPage/chart/DashboardLineChart.tsx new file mode 100644 index 0000000..ab34d0f --- /dev/null +++ b/src/components/DashboardPage/chart/DashboardLineChart.tsx @@ -0,0 +1,74 @@ +"use client" +// npm install +import { Select, MenuItem, FormControl, InputLabel } from "@mui/material"; +import React,{useState} from "react"; +import dynamic from "next/dynamic"; +const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); +import { useTranslation } from "react-i18next"; +interface Props { // params type + +} + +const DashboardLineChart: React.FC = () => { + const { t } = useTranslation(); + const [warehouseType, setWarehouseType] = useState(t("Cold storage")); + const [timeRange, setTimeRange] = useState("6h"); + + const options = { + chart: { type: "line" as const }, + xaxis: { + categories: ["10:00", "11:00", "12:00", "13:00", "14:00", "15:00"] + }, + yaxis: { + title: { text: t("Temperature") } + }, + stroke: { curve: "smooth" as const } + }; + const series = [ + { + name: "溫度", + data: [] + } + ]; + + return ( +
+
+ {t("Warehouse temperature record")} + + {t("Warehouse type")} + + + + + +
+ +
+ ); + }; + +export default DashboardLineChart + diff --git a/src/components/DashboardPage/chart/DashboardProgressChart.tsx b/src/components/DashboardPage/chart/DashboardProgressChart.tsx new file mode 100644 index 0000000..7a71053 --- /dev/null +++ b/src/components/DashboardPage/chart/DashboardProgressChart.tsx @@ -0,0 +1,128 @@ +"use client" +import React, { useEffect, useState } from "react"; +import dynamic from "next/dynamic"; +import { PoResult } from "@/app/api/po"; +import { fetchPoListClient } from "@/app/api/po/actions"; +import { useTranslation } from "react-i18next"; + +interface Props { // params type + po: PoResult[]; +} + +const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); + +const DashboardProgressChart: React.FC = () => { + const { t } = useTranslation("dashboard"); + const [series, setSeries] = useState([]); + const [total, setTotal] = useState(0); + const [pending, setPending] = useState(0); + const [receiving, setReceiving] = useState(0); + + useEffect(() => { + const fetchData = async () => { + const res = await fetchPoListClient(); + const records = res?.records || []; + const pendingCount = records.filter((r: any) => r.status === "pending").length; + const receivingCount = records.filter((r: any) => r.status === "receiving").length; + const totalCount = records.length; + + setPending(pendingCount); + setReceiving(receivingCount); + setTotal(totalCount); + setSeries([pendingCount, receivingCount]); + }; + fetchData(); + }, []); + + const options = { + chart: { + type: "donut" as const, + }, + labels: [t("pending"), t("receiving")], + dataLabels: { + formatter: (val: number) => `${val.toFixed(1)}%`, + dropShadow: { + enabled: false, + }, + style: { + fontSize: '18px', + fontWeight: 'bold', + }, + }, + legend: { + position: "bottom" as const, + fontSize: '16px', + markers: { + width: 16, + height: 16, + radius: 8, + }, + }, + colors: ["#A3C9F9", "#8DD7A9"], + plotOptions: { + pie: { + donut: { + size: "70%", + labels: { + show: true, + name: { show: false }, + value: { + show: true, + fontSize: "32px", + fontWeight: 600, + color: "#333", + formatter: function (val: string) { + return `${val}%`; + } + }, + total: { + show: false + } + } + } + } + }, + stroke: { + show: true, + width: 2, + colors: ['#fff'] + }, + }; + + return ( +
+
{t("採購訂單概覽")}
+
+ {series.length > 0 ? ( + + ) : ( +
+ 載入中... +
+ )} +
+
+
{t("pending")}:{pending}
+
{t("receiving")}:{receiving}
+
{t("total")}:{total}
+
+
+ ); + }; + + +export default DashboardProgressChart \ No newline at end of file diff --git a/src/components/DashboardPage/chart/OrderCompletionChart.tsx b/src/components/DashboardPage/chart/OrderCompletionChart.tsx new file mode 100644 index 0000000..15e8467 --- /dev/null +++ b/src/components/DashboardPage/chart/OrderCompletionChart.tsx @@ -0,0 +1,119 @@ +"use client" +import React, { useState } from "react"; +import dynamic from "next/dynamic"; +const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); +import { useTranslation } from "react-i18next"; +const OrderCompletionChart: React.FC = () => { + const { t } = useTranslation(); + const [tab, setTab] = useState(t("Raw material")); + const percent = 0; + const options = { + chart: { type: "donut" as const }, + labels: [], + colors: ["#42A5F5", "#e0e0e0"], + dataLabels: { + enabled: true, + formatter: () => `${percent}%`, + style: { fontSize: "32px", fontWeight: 600, color: "#1976d2" } + }, + legend: { show: false }, + plotOptions: { + pie: { + donut: { + size: "70%", + labels: { + show: false + } + } + } + }, + stroke: { show: true, width: 2, colors: ['#fff'] } + }; + + return ( +
+
+ {t("Order completion")} +
+ + + +
+
+
+ +
+
+
{t("Extracted order")}: 0
+
{t("Pending order")}: 0
+
+
+ ); +}; + +export default OrderCompletionChart; \ No newline at end of file diff --git a/src/components/DashboardPage/chart/PendingInspectionChart.tsx b/src/components/DashboardPage/chart/PendingInspectionChart.tsx new file mode 100644 index 0000000..1dd3823 --- /dev/null +++ b/src/components/DashboardPage/chart/PendingInspectionChart.tsx @@ -0,0 +1,65 @@ +"use client" +import React from "react"; +import dynamic from "next/dynamic"; +const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); +import { useTranslation } from "react-i18next"; + +const PendingInspectionChart: React.FC = () => { + const { t } = useTranslation("dashboard"); + const percent = 6.25; + const options = { + chart: { type: "donut" as const }, + labels: [t("pending inspection material"), t("inspected material")], + colors: ["#2196f3", "#e0e0e0"], + dataLabels: { enabled: false }, + legend: { position: "bottom" as const }, + plotOptions: { + pie: { + donut: { + size: "70%", + labels: { + show: true, + name: { show: false }, + value: { + show: true, + fontSize: "32px", + fontWeight: 600, + color: "#1976d2", + formatter: () => `${percent}%` + }, + total: { show: false } + } + } + } + }, + stroke: { show: true, width: 2, colors: ['#fff'] } + }; + + return ( +
+
待品檢物料
+
+ +
+
+
{t("pending inspection material")}: 1
+
{t("total material")}: 16
+
{t("inspected material")}: 15
+
+
+ ); +}; + +export default PendingInspectionChart; \ No newline at end of file diff --git a/src/components/DashboardPage/chart/PendingStorageChart.tsx b/src/components/DashboardPage/chart/PendingStorageChart.tsx new file mode 100644 index 0000000..e8f6253 --- /dev/null +++ b/src/components/DashboardPage/chart/PendingStorageChart.tsx @@ -0,0 +1,65 @@ +"use client" +import React from "react"; +import dynamic from "next/dynamic"; +import { useTranslation } from "node_modules/react-i18next"; +const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); + +const PendingStorageChart: React.FC = () => { + const { t } = useTranslation(); + const percent = 93.75; + const options = { + chart: { type: "donut" as const }, + labels: [t("Pending storage"), t("Total storage")], + colors: ["#1976d2", "#e0e0e0"], + dataLabels: { enabled: false }, + legend: { position: "bottom" as const }, + plotOptions: { + pie: { + donut: { + size: "70%", + labels: { + show: true, + name: { show: false }, + value: { + show: true, + fontSize: "32px", + fontWeight: 600, + color: "#1976d2", + formatter: () => `${percent}%` + }, + total: { show: false } + } + } + } + }, + stroke: { show: true, width: 2, colors: ['#fff'] } + }; + + return ( +
+
{t("Pending storage")}
+
+ +
+
+
 
{t("Pending storage")}: 15 +
{t("Total storage")}: 16
+ +
+
+ ); +}; + +export default PendingStorageChart; \ No newline at end of file diff --git a/src/components/M18ImportTesting/M18ImportDo.tsx b/src/components/M18ImportTesting/M18ImportDo.tsx index d749c61..26423b3 100644 --- a/src/components/M18ImportTesting/M18ImportDo.tsx +++ b/src/components/M18ImportTesting/M18ImportDo.tsx @@ -16,7 +16,7 @@ interface Props { const M18ImportDo: React.FC = ({ }) => { - const { t } = useTranslation() + const { t } = useTranslation("m18ImportTesting") const [isLoading, setIsLoading] = useState(false) const { control, diff --git a/src/components/M18ImportTesting/M18ImportMasterData.tsx b/src/components/M18ImportTesting/M18ImportMasterData.tsx index 55c181f..774cf4b 100644 --- a/src/components/M18ImportTesting/M18ImportMasterData.tsx +++ b/src/components/M18ImportTesting/M18ImportMasterData.tsx @@ -15,8 +15,7 @@ interface Props { const M18ImportMasterData: React.FC = ({ }) => { - - const { t } = useTranslation() + const { t } = useTranslation("m18ImportTesting") const [isLoading, setIsLoading] = useState(false) const { control, diff --git a/src/components/M18ImportTesting/M18ImportPo.tsx b/src/components/M18ImportTesting/M18ImportPo.tsx index 5223300..5892d21 100644 --- a/src/components/M18ImportTesting/M18ImportPo.tsx +++ b/src/components/M18ImportTesting/M18ImportPo.tsx @@ -16,7 +16,7 @@ interface Props { const M18ImportPo: React.FC = ({ }) => { - const { t } = useTranslation("settings") + const { t } = useTranslation("m18ImportTesting") const [isLoading, setIsLoading] = useState(false) const { control, diff --git a/src/components/M18ImportTesting/M18ImportPq.tsx b/src/components/M18ImportTesting/M18ImportPq.tsx index 9a6dbce..9a11fc4 100644 --- a/src/components/M18ImportTesting/M18ImportPq.tsx +++ b/src/components/M18ImportTesting/M18ImportPq.tsx @@ -16,7 +16,7 @@ interface Props { const M18ImportPq: React.FC = ({ }) => { - const { t } = useTranslation() + const { t } = useTranslation("m18ImportTesting") const [isLoading, setIsLoading] = useState(false) const { control, diff --git a/src/components/M18ImportTesting/M18ImportTesting.tsx b/src/components/M18ImportTesting/M18ImportTesting.tsx index b7f060c..6e1120b 100644 --- a/src/components/M18ImportTesting/M18ImportTesting.tsx +++ b/src/components/M18ImportTesting/M18ImportTesting.tsx @@ -19,7 +19,7 @@ const M18ImportTesting: React.FC = ({ }) => { - const { t } = useTranslation() + const { t } = useTranslation("m18ImportTesting") const [isLoading, setIsLoading] = useState(false) const [loadingType, setLoadingType] = useState(null) const formProps = useForm() diff --git a/src/i18n/zh/dashboard.json b/src/i18n/zh/dashboard.json index 4f6e429..b678a19 100644 --- a/src/i18n/zh/dashboard.json +++ b/src/i18n/zh/dashboard.json @@ -1,4 +1,33 @@ { "Dashboard": "資訊展示面板", - "Order status": "訂單狀態" -} + "Order status": "訂單狀態", + "pending": "未收貨", + "receiving": "收貨中", + "total": "未完成總數", + "Warehouse temperature record": "倉庫溫度記錄", + "Warehouse type": "倉庫類型", + "Last 6 hours": "過去6小時", + "Last 24 hours": "過去24小時", + "Cold storage": "冷藏倉", + "Normal temperature storage": "常溫倉", + "Temperature status": "溫度狀態", + "Humidity status": "濕度狀態", + "Warehouse status": "倉庫狀態", + "Progress chart": "進度圖表", + "Order completion": "訂單完成度", + "Raw material": "原料", + "Consumable": "消耗品", + "Shipment": "出貨", + "Extracted order": "已提取提料單", + "Pending order": "待提取提料單", + "Temperature": "溫度", + "Humidity": "濕度", + "Pending storage": "待入倉物料", + "Total storage": "已入倉物料", + "Application completion": "提料申請完成度", + "Processed application": "已處理提料申請", + "Pending application": "待處理提料申請", + "pending inspection material": "待品檢物料", + "inspected material": "已品檢物料", + "total material": "物料總數" + } diff --git a/src/i18n/zh/m18ImportTesting.json b/src/i18n/zh/m18ImportTesting.json new file mode 100644 index 0000000..bc93308 --- /dev/null +++ b/src/i18n/zh/m18ImportTesting.json @@ -0,0 +1,16 @@ +{ + "Import Master Data": "匯入主資料", + "Modified Date From": "修改日期從", + "Modified Date From *": "修改日期從 *", + "Modified Date To": "修改日期到", + "Modified Date To *": "修改日期到 *", + "Import Purchase Order": "匯入採購單", + "Import Delivery Order": "匯入出貨單", + "Import Purchase Quotation": "匯入採購報價單", + "Import Po": "匯入採購單", + "Import Do": "匯入出貨單", + "Import Pq": "匯入採購報價單", + "Ready to import": "準備匯入", + "Status": "狀態" + +} \ No newline at end of file diff --git a/src/i18n/zh/mail.json b/src/i18n/zh/mail.json new file mode 100644 index 0000000..0402484 --- /dev/null +++ b/src/i18n/zh/mail.json @@ -0,0 +1,22 @@ +{ + "Mail": "郵件", + "Mail List": "郵件列表", + "Mail Name": "郵件名稱", + "Mail Description": "郵件描述", + "Mail Status": "郵件狀態", + "Mail Created At": "郵件創建時間", + "Mail Updated At": "郵件更新時間", + "Setting": "設定", + "Settings": "設定", + "Template": "模板", + "Code": "代碼", + "Description": "描述", + "Subject CHT": "主旨 (繁體中文)", + "Select Template (View By Code - Description)": "選擇模板 (代碼 - 描述)", + "MAIL.smtp.host": "SMTP 主機", + "MAIL.smtp.port": "SMTP 埠口", + "MAIL.smtp.username": "SMTP 使用者名稱", + "MAIL.smtp.password": "SMTP 密碼", + "MAIL.smtp.auth": "SMTP 認證", + "MAIL.smtp.ssl": "SMTP SSL" +} \ No newline at end of file diff --git a/src/i18n/zh/qcCategory.json b/src/i18n/zh/qcCategory.json new file mode 100644 index 0000000..fbd0481 --- /dev/null +++ b/src/i18n/zh/qcCategory.json @@ -0,0 +1,9 @@ +{ + "Qc Category": "QC 類別", + "Qc Category List": "QC 類別列表", + "Qc Category Name": "QC 類別名稱", + "Qc Category Description": "QC 類別描述", + "Qc Category Status": "QC 類別狀態", + "Qc Category Created At": "QC 類別創建時間", + "Qc Category Updated At": "QC 類別更新時間" +} \ No newline at end of file