diff --git a/scripts/update-chart-i18n.js b/scripts/update-chart-i18n.js
new file mode 100644
index 0000000..05fa7c0
--- /dev/null
+++ b/scripts/update-chart-i18n.js
@@ -0,0 +1,267 @@
+const fs = require('fs');
+const path = require('path');
+
+const en = {
+ "pageTitle_delivery": "Delivery & Dispatch",
+ "pageTitle_jobOrder": "Job Orders",
+ "pageTitle_forecast": "Forecast & Planning",
+ "pageTitle_warehouse": "Inventory & Warehouse",
+ "pageTitle_equipmentBoard": "Equipment Usage Board",
+ "pageTitle_processBoard": "Process Real-time Board",
+ "pageTitle_jobOrderBoard": "Job Order Real-time Board",
+ "pageTitle_purchase": "Purchase",
+
+ "all": "All",
+ "noData": "No data",
+ "exportExcel": "Export Excel",
+ "show": "Show",
+ "laneX": "Lane X",
+ "today": "Today",
+ "yesterday": "Yesterday",
+ "selectDate": "Select Date",
+ "refresh": "Refresh",
+ "otherBoards": "Other Boards",
+ "autoRefresh": "Auto Refresh",
+ "on": "On",
+ "off": "Off",
+ "intervalSeconds": "Interval (sec)",
+ "minutes": "minutes",
+ "minutesWithVal": "{{val}} min",
+ "minuteAbbr": "min",
+
+ "delivery_staffPerfDateError": "Staff performance start date cannot be later than end date",
+ "delivery_ordersByDate": "Delivery Orders by Date",
+ "delivery_ordersByDate_export": "Delivery_Orders_By_Date",
+ "delivery_orderCount": "Order Count",
+ "delivery_topItemsByCount": "Top Items by Delivery Count",
+ "delivery_item": "Item",
+ "delivery_itemPlaceholder": "Leave empty for all",
+ "delivery_staffPerformanceTitle": "Staff Delivery Performance (Daily Pick Count & Duration)",
+ "delivery_startDate": "Start Date",
+ "delivery_endDate": "End Date",
+ "delivery_store": "Store",
+ "delivery_staff": "Staff",
+ "delivery_staffPlaceholder": "Leave empty for all",
+ "delivery_staffPerfCaption": "Per-person pick count & total duration for period",
+ "delivery_colStaff": "Staff",
+ "delivery_colPickCount": "Pick Count",
+ "delivery_colTotalMin": "Total Min",
+ "delivery_colAvgMin": "Avg Min/Order",
+ "delivery_dailyByStaff": "Daily by Staff",
+ "delivery_noDataDesc": "No delivery data available for the selected period.",
+
+ "jo_byStatus": "Job Orders by Status",
+ "jo_byStatus_export": "Job_Orders_By_Status",
+ "jo_datePlanStart": "Date (Plan Start)",
+ "jo_createdVsCompleted": "Job Orders Created vs Completed by Date",
+ "jo_createdVsCompleted_export": "Job_Orders_Created_vs_Completed",
+ "jo_detailSection": "Job Order Material / Process / Equipment",
+ "jo_materialPendingPicked": "Material Pending / Picked (by Plan Date)",
+ "jo_materialPendingPicked_export": "Material_Pending_vs_Picked",
+ "jo_processPendingCompleted": "Process Pending / Completed (by Plan Date)",
+ "jo_processPendingCompleted_export": "Process_Pending_vs_Completed",
+ "jo_equipmentWorkingWorked": "Equipment In Use / Used (by Job Order)",
+ "jo_equipmentWorkingWorked_export": "Equipment_In_Use_vs_Used",
+
+ "board_jobOrderLive": "Job Order Live Board",
+ "board_equipmentUsage": "Equipment Usage Board",
+ "board_processLive": "Process Live Board",
+ "board_jobOrderChart": "Job Order Chart",
+
+ "forecast_plannedOutputByDate": "Planned Daily Output by Item (Forecast)",
+ "forecast_plannedOutputByDate_export": "Planned_Daily_Output_By_Item",
+ "forecast_itemCode": "Item Code",
+ "forecast_noScheduleData": "No scheduling data for this date range.",
+ "forecast_productionSchedule": "Production Schedule by Date (Estimated Output)",
+ "forecast_productionSchedule_export": "Production_Schedule_By_Date",
+
+ "warehouse_stockTxnByDate": "Stock Transactions by Date (In / Out / Total)",
+ "warehouse_stockTxnByDate_export": "Stock_Transactions_By_Date",
+ "warehouse_stockInOutByDate": "Stock In vs Out by Date",
+ "warehouse_stockInOutByDate_export": "Stock_In_vs_Out",
+ "warehouse_balanceTrend": "Stock Balance Trend",
+ "warehouse_balanceTrend_export": "Stock_Balance_Trend",
+ "warehouse_consumptionTrend": "Monthly Consumption Trend (Outbound)",
+ "warehouse_consumptionTrend_export": "Monthly_Consumption_Trend",
+ "warehouse_qty": "Qty",
+ "warehouse_optional": "Optional",
+ "warehouse_sumAll": "Sum all if empty",
+ "warehouse_addItem": "Add item to split",
+ "warehouse_exportFail": "Master export failed",
+
+ "equipment_status": "Status",
+ "equipment_equipment": "Equipment",
+ "equipment_jobOrder": "Job Order",
+ "equipment_process": "Process",
+ "equipment_planStart": "Plan Start",
+ "equipment_startTime": "Start Time",
+ "equipment_endTime": "End Time",
+ "equipment_operator": "Operator",
+ "equipment_boardTitle": "Equipment Usage Board",
+ "equipment_infoDescription1": "Shows equipment status in real-time: working, idle, or under maintenance.",
+ "equipment_infoDescription2": "Each equipment card displays the current job order and process.",
+ "equipment_infoDescription3": "Equipment with unclosed hours or missing time entries will be flagged.",
+ "equipment_searchAndList": "Search & List",
+ "equipment_notToday": "Not Today",
+ "equipment_unclosedHours": "Equipment hours not closed",
+ "equipment_missingHours": "Missing equipment hours",
+ "equipment_completed": "Completed",
+
+ "process_notStarted": "Not Started",
+ "process_inProgress": "In Progress",
+ "process_completed": "Completed",
+ "process_nonToday": "Not Today",
+
+ "dateRange_lastDays": "Last {{d}} days",
+
+ "series_inbound": "Inbound",
+ "series_outbound": "Outbound",
+ "series_total": "Total",
+ "series_balance": "Balance",
+ "series_consumption": "Consumption",
+ "series_created": "Created",
+ "series_completed": "Completed",
+ "series_month": "Month",
+
+ "requestFailed": "Request failed"
+};
+
+const zh = {
+ "pageTitle_delivery": "發貨與配送",
+ "pageTitle_jobOrder": "工單",
+ "pageTitle_forecast": "預測與計劃",
+ "pageTitle_warehouse": "庫存與倉儲",
+ "pageTitle_equipmentBoard": "設備使用看板",
+ "pageTitle_processBoard": "工序即時看板",
+ "pageTitle_jobOrderBoard": "工單即時看板",
+ "pageTitle_purchase": "採購",
+
+ "all": "全部",
+ "noData": "無數據",
+ "exportExcel": "匯出 Excel",
+ "show": "顯示",
+ "laneX": "車線-X",
+ "today": "今日",
+ "yesterday": "昨日",
+ "selectDate": "選擇日期",
+ "refresh": "重新整理",
+ "otherBoards": "其他看板",
+ "autoRefresh": "自動重新整理",
+ "on": "開啟",
+ "off": "關閉",
+ "intervalSeconds": "間隔(秒)",
+ "minutes": "分鐘",
+ "minutesWithVal": "{{val}} 分鐘",
+ "minuteAbbr": "分",
+
+ "delivery_staffPerfDateError": "員工發貨績效的起始日期不能晚於結束日期",
+ "delivery_ordersByDate": "按日期發貨單數量",
+ "delivery_ordersByDate_export": "發貨單數量_按日期",
+ "delivery_orderCount": "單數",
+ "delivery_topItemsByCount": "發貨數量排行(按物料)",
+ "delivery_item": "物料",
+ "delivery_itemPlaceholder": "不選則全部",
+ "delivery_staffPerformanceTitle": "員工發貨績效(每日揀貨數量與耗時)",
+ "delivery_startDate": "開始日期",
+ "delivery_endDate": "結束日期",
+ "delivery_store": "倉別",
+ "delivery_staff": "員工",
+ "delivery_staffPlaceholder": "不選則全部",
+ "delivery_staffPerfCaption": "週期內每人揀單數及總耗時(首揀至完成)",
+ "delivery_colStaff": "員工",
+ "delivery_colPickCount": "揀單數",
+ "delivery_colTotalMin": "總分鐘",
+ "delivery_colAvgMin": "平均分鐘/單",
+ "delivery_dailyByStaff": "每日按員工單數",
+ "delivery_noDataDesc": "所選期間內暫無發貨記錄,請調整日期範圍後再試。",
+
+ "jo_byStatus": "工單按狀態",
+ "jo_byStatus_export": "工單_按狀態",
+ "jo_datePlanStart": "日期(計劃開始)",
+ "jo_createdVsCompleted": "工單創建與完成按日期",
+ "jo_createdVsCompleted_export": "工單_創建與完成_按日期",
+ "jo_detailSection": "工單物料/工序/設備",
+ "jo_materialPendingPicked": "物料待領/已揀(按工單計劃日)",
+ "jo_materialPendingPicked_export": "物料_待領_已揀",
+ "jo_processPendingCompleted": "工序待完成/已完成(按工單計劃日)",
+ "jo_processPendingCompleted_export": "工序_待完成_已完成",
+ "jo_equipmentWorkingWorked": "設備使用中/已使用(按工單)",
+ "jo_equipmentWorkingWorked_export": "設備_使用中_已使用",
+
+ "board_jobOrderLive": "工單即時看板",
+ "board_equipmentUsage": "設備使用看板",
+ "board_processLive": "工序即時看板",
+ "board_jobOrderChart": "工單圖表",
+
+ "forecast_plannedOutputByDate": "按物料計劃日產量(預測)",
+ "forecast_plannedOutputByDate_export": "計劃日產量_按物料",
+ "forecast_itemCode": "物料編碼",
+ "forecast_noScheduleData": "此日期範圍內尚無排程資料。",
+ "forecast_productionSchedule": "按日期生產排程(預估產量)",
+ "forecast_productionSchedule_export": "生產排程_按日期",
+
+ "warehouse_stockTxnByDate": "按日期庫存流水(入/出/合計)",
+ "warehouse_stockTxnByDate_export": "庫存流水_按日期",
+ "warehouse_stockInOutByDate": "按日期入庫與出庫",
+ "warehouse_stockInOutByDate_export": "入庫_出庫_按日期",
+ "warehouse_balanceTrend": "庫存餘額趨勢",
+ "warehouse_balanceTrend_export": "庫存餘額趨勢",
+ "warehouse_consumptionTrend": "按月考勤消耗趨勢(出庫量)",
+ "warehouse_consumptionTrend_export": "月考勤消耗趨勢",
+ "warehouse_qty": "數量",
+ "warehouse_optional": "可選",
+ "warehouse_sumAll": "不選則全部合計",
+ "warehouse_addItem": "新增物料以分項顯示",
+ "warehouse_exportFail": "總表匯出失敗",
+
+ "equipment_status": "狀態",
+ "equipment_equipment": "設備",
+ "equipment_jobOrder": "工單",
+ "equipment_process": "工序",
+ "equipment_planStart": "工單計劃開始",
+ "equipment_startTime": "開工時間",
+ "equipment_endTime": "完工時間",
+ "equipment_operator": "操作員",
+ "equipment_boardTitle": "設備使用看板",
+ "equipment_infoDescription1": "即時顯示設備狀態:使用中、閒置或維護中。",
+ "equipment_infoDescription2": "每張設備卡片顯示當前工單和工序。",
+ "equipment_infoDescription3": "設備工時未結案或未填寫將被標記。",
+ "equipment_searchAndList": "查詢與列表",
+ "equipment_notToday": "非今日",
+ "equipment_unclosedHours": "設備工時未結案",
+ "equipment_missingHours": "未填設備工時",
+ "equipment_completed": "已完工",
+
+ "process_notStarted": "未開工",
+ "process_inProgress": "進行中",
+ "process_completed": "已完工",
+ "process_nonToday": "非今日",
+
+ "dateRange_lastDays": "最近 {{d}} 天",
+
+ "series_inbound": "入庫",
+ "series_outbound": "出庫",
+ "series_total": "合計",
+ "series_balance": "餘額",
+ "series_consumption": "消耗",
+ "series_created": "新建",
+ "series_completed": "完成",
+ "series_month": "月份",
+
+ "requestFailed": "請求失敗"
+};
+
+const i18nDir = path.join(__dirname, '..', 'src', 'i18n');
+const enPath = path.join(i18nDir, 'en', 'chart.json');
+const zhPath = path.join(i18nDir, 'zh', 'chart.json');
+
+// Sort keys alphabetically
+const sortKeys = (obj) => {
+ const sorted = {};
+ Object.keys(obj).sort().forEach(k => { sorted[k] = obj[k]; });
+ return sorted;
+};
+
+fs.writeFileSync(enPath, JSON.stringify(sortKeys(en), null, 2) + '\n');
+fs.writeFileSync(zhPath, JSON.stringify(sortKeys(zh), null, 2) + '\n');
+console.log('Updated chart.json with', Object.keys(en).length, 'keys for each language');
diff --git a/src/app/(main)/bag/page.tsx b/src/app/(main)/bag/page.tsx
index 8e859ef..5e8939f 100644
--- a/src/app/(main)/bag/page.tsx
+++ b/src/app/(main)/bag/page.tsx
@@ -9,7 +9,7 @@ export const metadata: Metadata = {
}
const bagPage: React.FC = async () => {
- const { t } = await getServerI18n("jo");
+ const { t } = await getServerI18n("bagUsage");
return (
<>
@@ -23,7 +23,7 @@ const bagPage: React.FC = async () => {
{t("Bag Usage")}
-
+
}>
diff --git a/src/app/(main)/bagPrint/page.tsx b/src/app/(main)/bagPrint/page.tsx
index e935cee..0afeae7 100644
--- a/src/app/(main)/bagPrint/page.tsx
+++ b/src/app/(main)/bagPrint/page.tsx
@@ -1,23 +1,21 @@
+import { I18nProvider } from "@/i18n";
+import { Metadata } from "next";
import BagPrintSearch from "@/components/BagPrint/BagPrintSearch";
import { Stack, Typography } from "@mui/material";
-import { Metadata } from "next";
-import React from "react";
export const metadata: Metadata = {
title: "打袋機",
};
-const BagPrintPage: React.FC = () => {
+export default async function BagPrintPage() {
return (
- <>
+
打袋機
- >
+
);
-};
-
-export default BagPrintPage;
+}
diff --git a/src/app/(main)/chart/layout.tsx b/src/app/(main)/chart/layout.tsx
index 0c4a8ef..b2c183b 100644
--- a/src/app/(main)/chart/layout.tsx
+++ b/src/app/(main)/chart/layout.tsx
@@ -1,24 +1,13 @@
-import { Metadata } from "next";
-import { getServerSession } from "next-auth";
-import { redirect } from "next/navigation";
-import { authOptions } from "@/config/authConfig";
-import { AUTH } from "@/authorities";
+import { I18nProvider } from "@/i18n";
-export const metadata: Metadata = {
- title: "圖表報告",
-};
-
-export default async function ChartLayout({
+export default function ChartLayout({
children,
}: {
children: React.ReactNode;
}) {
- const session = await getServerSession(authOptions);
- const abilities = session?.user?.abilities ?? [];
- const canViewCharts =
- abilities.includes(AUTH.TESTING) || abilities.includes(AUTH.ADMIN);
- if (!canViewCharts) {
- redirect("/dashboard");
- }
- return <>{children}>;
+ return (
+
+ {children}
+
+ );
}
diff --git a/src/app/(main)/dashboard/page.tsx b/src/app/(main)/dashboard/page.tsx
index d965477..796234b 100644
--- a/src/app/(main)/dashboard/page.tsx
+++ b/src/app/(main)/dashboard/page.tsx
@@ -18,7 +18,7 @@ const Dashboard: React.FC = async ({ searchParams }) => {
fetchEscalationLogsByUser()
return (
-
+
}>
diff --git a/src/app/(main)/do copy 2/edit/page.tsx b/src/app/(main)/do copy 2/edit/page.tsx
index a3200a5..b114acc 100644
--- a/src/app/(main)/do copy 2/edit/page.tsx
+++ b/src/app/(main)/do copy 2/edit/page.tsx
@@ -24,7 +24,7 @@ const DoEdit: React.FC = async ({ searchParams }) => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/do copy 2/page.tsx b/src/app/(main)/do copy 2/page.tsx
index 5489385..235f4e0 100644
--- a/src/app/(main)/do copy 2/page.tsx
+++ b/src/app/(main)/do copy 2/page.tsx
@@ -23,7 +23,7 @@ const Page: React.FC = async () => {
/doworkbench
-
+
}>
diff --git a/src/app/(main)/do copy/edit/page.tsx b/src/app/(main)/do copy/edit/page.tsx
index a3200a5..b114acc 100644
--- a/src/app/(main)/do copy/edit/page.tsx
+++ b/src/app/(main)/do copy/edit/page.tsx
@@ -24,7 +24,7 @@ const DoEdit: React.FC = async ({ searchParams }) => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/do copy/page.tsx b/src/app/(main)/do copy/page.tsx
index e1ef75d..f2004ba 100644
--- a/src/app/(main)/do copy/page.tsx
+++ b/src/app/(main)/do copy/page.tsx
@@ -17,7 +17,7 @@ const DeliveryOrder: React.FC = async () => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/do/edit/page.tsx b/src/app/(main)/do/edit/page.tsx
index a3200a5..b114acc 100644
--- a/src/app/(main)/do/edit/page.tsx
+++ b/src/app/(main)/do/edit/page.tsx
@@ -24,7 +24,7 @@ const DoEdit: React.FC = async ({ searchParams }) => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/do/page.tsx b/src/app/(main)/do/page.tsx
index e1ef75d..f2004ba 100644
--- a/src/app/(main)/do/page.tsx
+++ b/src/app/(main)/do/page.tsx
@@ -17,7 +17,7 @@ const DeliveryOrder: React.FC = async () => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/doworkbench/edit/page.tsx b/src/app/(main)/doworkbench/edit/page.tsx
index 308d185..3ac873e 100644
--- a/src/app/(main)/doworkbench/edit/page.tsx
+++ b/src/app/(main)/doworkbench/edit/page.tsx
@@ -15,7 +15,7 @@ export const metadata: Metadata = {
type Props = SearchParams;
const Page: React.FC = async ({ searchParams }) => {
- const { t } = await getServerI18n("do");
+ const { t } = await getServerI18n("doWorkbench");
const id = searchParams["id"];
if (!id || isArray(id) || !isFinite(parseInt(id))) {
@@ -34,7 +34,7 @@ const Page: React.FC = async ({ searchParams }) => {
{t("DO Workbench Search", { defaultValue: "DO Workbench Search" })}
-
+
}>
diff --git a/src/app/(main)/doworkbench/page.tsx b/src/app/(main)/doworkbench/page.tsx
index 6322a89..381f79f 100644
--- a/src/app/(main)/doworkbench/page.tsx
+++ b/src/app/(main)/doworkbench/page.tsx
@@ -9,13 +9,13 @@ export const metadata: Metadata = {
};
const DoWorkbenchPage: React.FC = async () => {
- const { t } = await getServerI18n("do");
+ const { t } = await getServerI18n("doWorkbench");
const printerCombo = await fetchPrinterCombo();
return (
<>
-
+
>
diff --git a/src/app/(main)/doworkbenchsearch/page.tsx b/src/app/(main)/doworkbenchsearch/page.tsx
index 602cc26..ee44fcf 100644
--- a/src/app/(main)/doworkbenchsearch/page.tsx
+++ b/src/app/(main)/doworkbenchsearch/page.tsx
@@ -19,7 +19,7 @@ const DoWorkbenchSearchPage: React.FC = async () => {
title={t("DO Workbench Search", { defaultValue: "DO Workbench Search" })}
className="mb-4"
/>
-
+
}>
diff --git a/src/app/(main)/finishedGood/detail/page.tsx b/src/app/(main)/finishedGood/detail/page.tsx
index a456798..ec11371 100644
--- a/src/app/(main)/finishedGood/detail/page.tsx
+++ b/src/app/(main)/finishedGood/detail/page.tsx
@@ -12,13 +12,13 @@ export const metadata: Metadata = {
type Props = {} & SearchParams;
const PickOrder: React.FC = async ({ searchParams }) => {
- const { t } = await getServerI18n("pickOrder");
+ const { t } = await getServerI18n("finishedGood");
return (
<>
-
+
}>
diff --git a/src/app/(main)/finishedGood/management/page.tsx b/src/app/(main)/finishedGood/management/page.tsx
index 1594c8f..e754248 100644
--- a/src/app/(main)/finishedGood/management/page.tsx
+++ b/src/app/(main)/finishedGood/management/page.tsx
@@ -18,7 +18,7 @@ const Page = async () => {
redirect("/dashboard");
}
return (
-
+
}>
diff --git a/src/app/(main)/finishedGood/page.tsx b/src/app/(main)/finishedGood/page.tsx
index 44ca00b..eb0cbd9 100644
--- a/src/app/(main)/finishedGood/page.tsx
+++ b/src/app/(main)/finishedGood/page.tsx
@@ -11,13 +11,13 @@ export const metadata: Metadata = {
};
const PickOrder: React.FC = async () => {
- const { t } = await getServerI18n("pickOrder");
+ const { t } = await getServerI18n("finishedGood");
//PreloadPickOrder();
return (
<>
-
+
}>
diff --git a/src/app/(main)/inventory/page.tsx b/src/app/(main)/inventory/page.tsx
index 3b202f0..651aed9 100644
--- a/src/app/(main)/inventory/page.tsx
+++ b/src/app/(main)/inventory/page.tsx
@@ -14,7 +14,7 @@ export const metadata: Metadata = {
};
const Inventory: React.FC = async () => {
- const { t } = await getServerI18n("inventory", "common");
+ const { t } = await getServerI18n("inventory");
preloadInventory();
@@ -30,7 +30,7 @@ const Inventory: React.FC = async () => {
{t("Inventory")}
-
+
}>
diff --git a/src/app/(main)/jo/edit/page.tsx b/src/app/(main)/jo/edit/page.tsx
index 4a6b8ed..3c9f0c4 100644
--- a/src/app/(main)/jo/edit/page.tsx
+++ b/src/app/(main)/jo/edit/page.tsx
@@ -39,7 +39,7 @@ const JoEdit: React.FC = async ({ searchParams }) => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/jo/page.tsx b/src/app/(main)/jo/page.tsx
index 7cd53e4..295b60b 100644
--- a/src/app/(main)/jo/page.tsx
+++ b/src/app/(main)/jo/page.tsx
@@ -32,7 +32,7 @@ const Jo: React.FC = async () => {
return (
<>
-
+
}>
{
return (
<>
-
+
}>
diff --git a/src/app/(main)/jodetail/edit/page.tsx b/src/app/(main)/jodetail/edit/page.tsx
index 43a8027..82c1fe4 100644
--- a/src/app/(main)/jodetail/edit/page.tsx
+++ b/src/app/(main)/jodetail/edit/page.tsx
@@ -38,7 +38,7 @@ const JodetailEdit: React.FC = async ({ searchParams }) => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/jodetail/page.tsx b/src/app/(main)/jodetail/page.tsx
index 7769148..cc6af2a 100644
--- a/src/app/(main)/jodetail/page.tsx
+++ b/src/app/(main)/jodetail/page.tsx
@@ -18,7 +18,7 @@ const Jodetail: React.FC = async () => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/laserPrint/page.tsx b/src/app/(main)/laserPrint/page.tsx
index 081900e..aa01a1d 100644
--- a/src/app/(main)/laserPrint/page.tsx
+++ b/src/app/(main)/laserPrint/page.tsx
@@ -1,23 +1,21 @@
+import { I18nProvider } from "@/i18n";
+import { Metadata } from "next";
import LaserPrintSearch from "@/components/LaserPrint/LaserPrintSearch";
import { Stack, Typography } from "@mui/material";
-import { Metadata } from "next";
-import React from "react";
export const metadata: Metadata = {
title: "檸檬機(激光機)",
};
-const LaserPrintPage: React.FC = () => {
+export default async function LaserPrintPage() {
return (
- <>
+
檸檬機(激光機)
- >
+
);
-};
-
-export default LaserPrintPage;
+}
diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx
index cc020d8..3f2ddad 100644
--- a/src/app/(main)/layout.tsx
+++ b/src/app/(main)/layout.tsx
@@ -45,7 +45,7 @@ export default async function MainLayout({
/>
}
mainContent={
-
+
{children}
}
diff --git a/src/app/(main)/m18Syn/layout.tsx b/src/app/(main)/m18Syn/layout.tsx
index ad756a7..ecbed38 100644
--- a/src/app/(main)/m18Syn/layout.tsx
+++ b/src/app/(main)/m18Syn/layout.tsx
@@ -1,22 +1,13 @@
-import { Metadata } from "next";
-import { getServerSession } from "next-auth";
-import { redirect } from "next/navigation";
-import { authOptions } from "@/config/authConfig";
-import { AUTH } from "@/authorities";
+import { I18nProvider } from "@/i18n";
-export const metadata: Metadata = {
- title: "M18 Sync",
-};
-
-export default async function M18SynLayout({
+export default function M18SyncLayout({
children,
}: {
children: React.ReactNode;
}) {
- const session = await getServerSession(authOptions);
- const abilities = session?.user?.abilities ?? [];
- if (!abilities.includes(AUTH.ADMIN)) {
- redirect("/dashboard");
- }
- return <>{children}>;
+ return (
+
+ {children}
+
+ );
}
diff --git a/src/app/(main)/pickOrder/detail/page.tsx b/src/app/(main)/pickOrder/detail/page.tsx
index d40809a..7f69b70 100644
--- a/src/app/(main)/pickOrder/detail/page.tsx
+++ b/src/app/(main)/pickOrder/detail/page.tsx
@@ -18,7 +18,7 @@ const PickOrder: React.FC = async ({ searchParams }) => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/pickOrder/page.tsx b/src/app/(main)/pickOrder/page.tsx
index 31219a2..6f367f9 100644
--- a/src/app/(main)/pickOrder/page.tsx
+++ b/src/app/(main)/pickOrder/page.tsx
@@ -17,7 +17,7 @@ const PickOrder: React.FC = async () => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/po/edit/page.tsx b/src/app/(main)/po/edit/page.tsx
index d2fcbfd..e7f0667 100644
--- a/src/app/(main)/po/edit/page.tsx
+++ b/src/app/(main)/po/edit/page.tsx
@@ -31,7 +31,7 @@ const PoEdit: React.FC = async ({ searchParams }) => {
return (
<>
{/* {t("Create Material")} */}
-
+
}>
diff --git a/src/app/(main)/po/page.tsx b/src/app/(main)/po/page.tsx
index 96263ab..e2fbdba 100644
--- a/src/app/(main)/po/page.tsx
+++ b/src/app/(main)/po/page.tsx
@@ -17,7 +17,7 @@ const PurchaseOrder: React.FC = async () => {
// preloadClaims();
return (
<>
-
+
-
+
diff --git a/src/app/(main)/production/page.tsx b/src/app/(main)/production/page.tsx
index d8253ac..5708110 100644
--- a/src/app/(main)/production/page.tsx
+++ b/src/app/(main)/production/page.tsx
@@ -15,7 +15,7 @@ export const metadata: Metadata = {
};
const production: React.FC = async () => {
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("production", "common");
const printerCombo = await fetchPrinterCombo();
return (
<>
@@ -38,7 +38,7 @@ const production: React.FC = async () => {
{t("Create Process")}
*/}
-
+
{/* Use new component */}
>
diff --git a/src/app/(main)/productionProcess/page.tsx b/src/app/(main)/productionProcess/page.tsx
index 9d1ee22..94dbf7f 100644
--- a/src/app/(main)/productionProcess/page.tsx
+++ b/src/app/(main)/productionProcess/page.tsx
@@ -13,7 +13,7 @@ export const metadata: Metadata = {
};
const productionProcess: React.FC = async () => {
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("productionProcess", "navigation", "common");
const printerCombo = await fetchPrinterCombo();
return (
<>
@@ -36,7 +36,7 @@ const productionProcess: React.FC = async () => {
{t("Create Process")}
*/}
-
+
}>
diff --git a/src/app/(main)/projects/create/page.tsx b/src/app/(main)/projects/create/page.tsx
index 3af4630..9ceee68 100644
--- a/src/app/(main)/projects/create/page.tsx
+++ b/src/app/(main)/projects/create/page.tsx
@@ -11,12 +11,12 @@ export const metadata: Metadata = {
};
const Projects: React.FC = async () => {
- const { t } = await getServerI18n("projects");
+ const { t } = await getServerI18n("project");
return (
<>
{t("Create Project")}
-
+
>
diff --git a/src/app/(main)/projects/page.tsx b/src/app/(main)/projects/page.tsx
index a117fa2..0b9121a 100644
--- a/src/app/(main)/projects/page.tsx
+++ b/src/app/(main)/projects/page.tsx
@@ -20,7 +20,7 @@ export const metadata: Metadata = {
};
const Projects: React.FC = async () => {
- const { t } = await getServerI18n("projects");
+ const { t } = await getServerI18n("project");
preloadProjects();
return (
@@ -43,7 +43,7 @@ const Projects: React.FC = async () => {
{t("Create Project")}
-
+
}>
diff --git a/src/app/(main)/ps/layout.tsx b/src/app/(main)/ps/layout.tsx
new file mode 100644
index 0000000..a68270b
--- /dev/null
+++ b/src/app/(main)/ps/layout.tsx
@@ -0,0 +1,13 @@
+import { I18nProvider } from "@/i18n";
+
+export default function PsLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/app/(main)/ps/page.tsx b/src/app/(main)/ps/page.tsx
index a8f872d..fb4b5b0 100644
--- a/src/app/(main)/ps/page.tsx
+++ b/src/app/(main)/ps/page.tsx
@@ -619,7 +619,7 @@ export default function ProductionSchedulePage() {
return (
*/}
-
+
}>
diff --git a/src/app/(main)/scheduling/rough/page.tsx b/src/app/(main)/scheduling/rough/page.tsx
index cc4e9f8..23dfbf0 100644
--- a/src/app/(main)/scheduling/rough/page.tsx
+++ b/src/app/(main)/scheduling/rough/page.tsx
@@ -47,7 +47,7 @@ const roughScheduling: React.FC = async () => {
{t("Test Rough Scheduling")}
*/}
-
+
}>
diff --git a/src/app/(main)/settings/bomWeighting/page.tsx b/src/app/(main)/settings/bomWeighting/page.tsx
index 551dcd2..3aa3d39 100644
--- a/src/app/(main)/settings/bomWeighting/page.tsx
+++ b/src/app/(main)/settings/bomWeighting/page.tsx
@@ -9,13 +9,13 @@ export const metadata: Metadata = {
};
const BomWeightingScorePage: React.FC = async () => {
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("bomWeighting");
const bomWeightingScores = await fetchBomWeightingScores();
return (
<>
-
+
>
diff --git a/src/app/(main)/settings/clientMonitor/page.tsx b/src/app/(main)/settings/clientMonitor/page.tsx
index d7db777..66c082c 100644
--- a/src/app/(main)/settings/clientMonitor/page.tsx
+++ b/src/app/(main)/settings/clientMonitor/page.tsx
@@ -1,3 +1,4 @@
+import { I18nProvider } from "@/i18n";
import ClientMonitorPage from "@/components/ClientMonitor/ClientMonitorPage";
import { isMonitoringEnabled } from "@/config/monitoring";
import { Metadata } from "next";
@@ -11,5 +12,9 @@ export default function ClientMonitorRoutePage() {
if (!isMonitoringEnabled) {
redirect("/settings/user");
}
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/app/(main)/settings/deliveryOrderFloor/page.tsx b/src/app/(main)/settings/deliveryOrderFloor/page.tsx
index bcbbb91..88701b1 100644
--- a/src/app/(main)/settings/deliveryOrderFloor/page.tsx
+++ b/src/app/(main)/settings/deliveryOrderFloor/page.tsx
@@ -8,10 +8,10 @@ export const metadata: Metadata = {
};
export default async function DeliveryOrderFloorPage() {
- const { t } = await getServerI18n("deliveryOrderFloor", "common");
+ const { t } = await getServerI18n("deliveryOrderFloor");
return (
-
+
{t("title")}
diff --git a/src/app/(main)/settings/equipment/EquipmentTabs.tsx b/src/app/(main)/settings/equipment/EquipmentTabs.tsx
index d4e6a5b..519d9d0 100644
--- a/src/app/(main)/settings/equipment/EquipmentTabs.tsx
+++ b/src/app/(main)/settings/equipment/EquipmentTabs.tsx
@@ -13,7 +13,7 @@ type EquipmentTabsProps = {
const EquipmentTabs: React.FC = ({ onTabChange }) => {
const router = useRouter();
const searchParams = useSearchParams();
- const { t } = useTranslation("common");
+ const { t } = useTranslation(["equipment", "common"]);
const tabFromUrl = searchParams.get("tab");
const initialTabIndex = tabFromUrl ? parseInt(tabFromUrl, 10) : 0;
diff --git a/src/app/(main)/settings/equipment/MaintenanceEdit/page.tsx b/src/app/(main)/settings/equipment/MaintenanceEdit/page.tsx
index 65c233f..128811e 100644
--- a/src/app/(main)/settings/equipment/MaintenanceEdit/page.tsx
+++ b/src/app/(main)/settings/equipment/MaintenanceEdit/page.tsx
@@ -9,8 +9,8 @@ import UpdateMaintenanceForm from "@/components/UpdateMaintenance/UpdateMaintena
type Props = {} & SearchParams;
const MaintenanceEditPage: React.FC = async ({ searchParams }) => {
- const type = "common";
- const { t } = await getServerI18n(type);
+ const type = "equipment";
+ const { t } = await getServerI18n(type, "navigation", "common");
const id = isString(searchParams["id"])
? parseInt(searchParams["id"])
: undefined;
@@ -20,7 +20,7 @@ const MaintenanceEditPage: React.FC = async ({ searchParams }) => {
return (
<>
{t("Update Equipment Maintenance and Repair")}
-
+
>
diff --git a/src/app/(main)/settings/equipment/create/page.tsx b/src/app/(main)/settings/equipment/create/page.tsx
index ae48446..47c7979 100644
--- a/src/app/(main)/settings/equipment/create/page.tsx
+++ b/src/app/(main)/settings/equipment/create/page.tsx
@@ -9,11 +9,11 @@ type Props = {} & SearchParams;
const materialSetting: React.FC = async ({ searchParams }) => {
// const type = TypeEnum.PRODUCT;
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("equipment", "navigation", "common");
return (
<>
{/* {t("Create Material")} */}
-
+
>
diff --git a/src/app/(main)/settings/equipment/edit/page.tsx b/src/app/(main)/settings/equipment/edit/page.tsx
index 41e401c..39bb0bc 100644
--- a/src/app/(main)/settings/equipment/edit/page.tsx
+++ b/src/app/(main)/settings/equipment/edit/page.tsx
@@ -9,8 +9,8 @@ import { notFound } from "next/navigation";
type Props = {} & SearchParams;
const productSetting: React.FC = async ({ searchParams }) => {
- const type = "common";
- const { t } = await getServerI18n(type);
+ const type = "equipment";
+ const { t } = await getServerI18n(type, "navigation", "common");
const id = isString(searchParams["id"])
? parseInt(searchParams["id"])
: undefined;
@@ -20,7 +20,7 @@ const productSetting: React.FC = async ({ searchParams }) => {
return (
<>
{/* {t("Create Material")} */}
-
+
>
diff --git a/src/app/(main)/settings/equipment/page.tsx b/src/app/(main)/settings/equipment/page.tsx
index 3ef292d..29511f2 100644
--- a/src/app/(main)/settings/equipment/page.tsx
+++ b/src/app/(main)/settings/equipment/page.tsx
@@ -19,8 +19,8 @@ export const metadata: Metadata = {
};
const productSetting: React.FC = async () => {
- const type = "common";
- const { t } = await getServerI18n(type);
+ const type = "equipment";
+ const { t } = await getServerI18n(type, "navigation", "common");
return (
<>
@@ -35,7 +35,7 @@ const productSetting: React.FC = async () => {
}>
-
+
diff --git a/src/app/(main)/settings/equipmentType/create/page.tsx b/src/app/(main)/settings/equipmentType/create/page.tsx
index e996ab1..2f16ee6 100644
--- a/src/app/(main)/settings/equipmentType/create/page.tsx
+++ b/src/app/(main)/settings/equipmentType/create/page.tsx
@@ -9,11 +9,11 @@ type Props = {} & SearchParams;
const materialSetting: React.FC = async ({ searchParams }) => {
// const type = TypeEnum.PRODUCT;
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("equipment", "navigation", "common");
return (
<>
{/* {t("Create Material")} */}
-
+
>
diff --git a/src/app/(main)/settings/equipmentType/edit/page.tsx b/src/app/(main)/settings/equipmentType/edit/page.tsx
index b9dbc90..22c1af6 100644
--- a/src/app/(main)/settings/equipmentType/edit/page.tsx
+++ b/src/app/(main)/settings/equipmentType/edit/page.tsx
@@ -9,8 +9,8 @@ import { notFound } from "next/navigation";
type Props = {} & SearchParams;
const productSetting: React.FC = async ({ searchParams }) => {
- const type = "common";
- const { t } = await getServerI18n(type);
+ const type = "equipment";
+ const { t } = await getServerI18n(type, "navigation", "common");
const id = isString(searchParams["id"])
? parseInt(searchParams["id"])
: undefined;
@@ -20,7 +20,7 @@ const productSetting: React.FC = async ({ searchParams }) => {
return (
<>
{/* {t("Create Material")} */}
-
+
>
diff --git a/src/app/(main)/settings/equipmentType/page.tsx b/src/app/(main)/settings/equipmentType/page.tsx
index 63803dc..c5b18f3 100644
--- a/src/app/(main)/settings/equipmentType/page.tsx
+++ b/src/app/(main)/settings/equipmentType/page.tsx
@@ -15,8 +15,8 @@ export const metadata: Metadata = {
};
const productSetting: React.FC = async () => {
- const type = "common";
- const { t } = await getServerI18n(type);
+ const type = "equipment";
+ const { t } = await getServerI18n(type, "navigation", "common");
const equipmentTypes = await fetchAllEquipmentTypes();
// preloadClaims();
@@ -41,7 +41,7 @@ const productSetting: React.FC = async () => {
*/}
}>
-
+
diff --git a/src/app/(main)/settings/importBom/MaintenanceEdit/page.tsx b/src/app/(main)/settings/importBom/MaintenanceEdit/page.tsx
index 65c233f..d44533a 100644
--- a/src/app/(main)/settings/importBom/MaintenanceEdit/page.tsx
+++ b/src/app/(main)/settings/importBom/MaintenanceEdit/page.tsx
@@ -9,8 +9,8 @@ import UpdateMaintenanceForm from "@/components/UpdateMaintenance/UpdateMaintena
type Props = {} & SearchParams;
const MaintenanceEditPage: React.FC = async ({ searchParams }) => {
- const type = "common";
- const { t } = await getServerI18n(type);
+ const type = "importBom";
+ const { t } = await getServerI18n(type, "navigation", "common");
const id = isString(searchParams["id"])
? parseInt(searchParams["id"])
: undefined;
@@ -20,10 +20,10 @@ const MaintenanceEditPage: React.FC = async ({ searchParams }) => {
return (
<>
{t("Update Equipment Maintenance and Repair")}
-
+
>
);
};
-export default MaintenanceEditPage;
\ No newline at end of file
+export default MaintenanceEditPage;
diff --git a/src/app/(main)/settings/importBom/create/page.tsx b/src/app/(main)/settings/importBom/create/page.tsx
index ae48446..01a439d 100644
--- a/src/app/(main)/settings/importBom/create/page.tsx
+++ b/src/app/(main)/settings/importBom/create/page.tsx
@@ -13,7 +13,7 @@ const materialSetting: React.FC = async ({ searchParams }) => {
return (
<>
{/* {t("Create Material")} */}
-
+
>
diff --git a/src/app/(main)/settings/importBom/edit/page.tsx b/src/app/(main)/settings/importBom/edit/page.tsx
index 41e401c..1bd7012 100644
--- a/src/app/(main)/settings/importBom/edit/page.tsx
+++ b/src/app/(main)/settings/importBom/edit/page.tsx
@@ -1,16 +1,14 @@
import { SearchParams } from "@/app/utils/fetchUtil";
-import { TypeEnum } from "@/app/utils/typeEnum";
import CreateEquipmentType from "@/components/CreateEquipment";
import { I18nProvider, getServerI18n } from "@/i18n";
-import { Typography } from "@mui/material";
import isString from "lodash/isString";
import { notFound } from "next/navigation";
type Props = {} & SearchParams;
const productSetting: React.FC = async ({ searchParams }) => {
- const type = "common";
- const { t } = await getServerI18n(type);
+ const type = "importBom";
+ await getServerI18n(type, "navigation", "common");
const id = isString(searchParams["id"])
? parseInt(searchParams["id"])
: undefined;
@@ -19,8 +17,7 @@ const productSetting: React.FC = async ({ searchParams }) => {
}
return (
<>
- {/* {t("Create Material")} */}
-
+
>
diff --git a/src/app/(main)/settings/importBom/page.tsx b/src/app/(main)/settings/importBom/page.tsx
index 7285cd7..26f4b21 100644
--- a/src/app/(main)/settings/importBom/page.tsx
+++ b/src/app/(main)/settings/importBom/page.tsx
@@ -21,7 +21,7 @@ export default async function ImportBomPage() {
Import BOM
-
+
>
diff --git a/src/app/(main)/settings/importExcel/page.tsx b/src/app/(main)/settings/importExcel/page.tsx
index e83b3b6..010c672 100644
--- a/src/app/(main)/settings/importExcel/page.tsx
+++ b/src/app/(main)/settings/importExcel/page.tsx
@@ -1,34 +1,34 @@
-import { Metadata } from "next";
-import { getServerI18n } from "@/i18n";
+import { I18nProvider, getServerI18n } from "@/i18n";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
+import { Metadata } from "next";
import { Suspense } from "react";
import ExcelFileImport from "@/components/ExcelFileImport";
export const metadata: Metadata = {
- title: "Excel File Import",
+ title: "Excel File Import",
};
const ImportExcel: React.FC = async () => {
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("importExcel", "navigation", "common");
- return (
- <>
-
-
- {t("Excel File Import")}
-
-
-
-
-
- >
- )
+ return (
+
+
+
+ {t("title")}
+
+
+
+
+
+
+ );
};
export default ImportExcel;
diff --git a/src/app/(main)/settings/itemPrice/page.tsx b/src/app/(main)/settings/itemPrice/page.tsx
index d6d3cbc..9b386b3 100644
--- a/src/app/(main)/settings/itemPrice/page.tsx
+++ b/src/app/(main)/settings/itemPrice/page.tsx
@@ -9,13 +9,13 @@ export const metadata: Metadata = {
};
const ItemPriceSetting: React.FC = async () => {
- const { t } = await getServerI18n("inventory", "common");
+ const { t } = await getServerI18n("itemPrice", "importExcel");
return (
<>
-
+
-
+
}>
diff --git a/src/app/(main)/settings/items/create/page.tsx b/src/app/(main)/settings/items/create/page.tsx
index 5b1e314..463db53 100644
--- a/src/app/(main)/settings/items/create/page.tsx
+++ b/src/app/(main)/settings/items/create/page.tsx
@@ -13,7 +13,7 @@ const materialSetting: React.FC = async ({ searchParams }) => {
return (
<>
{/* {t("Create Material")} */}
-
+
>
diff --git a/src/app/(main)/settings/items/edit/page.tsx b/src/app/(main)/settings/items/edit/page.tsx
index ee32d7f..c1bdbfb 100644
--- a/src/app/(main)/settings/items/edit/page.tsx
+++ b/src/app/(main)/settings/items/edit/page.tsx
@@ -24,7 +24,7 @@ const productSetting: React.FC = async ({ searchParams }) => {
return (
<>
{/* {t("Create Material")} */}
-
+
>
diff --git a/src/app/(main)/settings/items/page.tsx b/src/app/(main)/settings/items/page.tsx
index 97ea0a8..79ea2b6 100644
--- a/src/app/(main)/settings/items/page.tsx
+++ b/src/app/(main)/settings/items/page.tsx
@@ -16,7 +16,7 @@ export const metadata: Metadata = {
const productSetting: React.FC = async () => {
const project = TypeEnum.PRODUCT;
- const { t } = await getServerI18n("project");
+ const { t } = await getServerI18n("items");
// preloadClaims();
return (
@@ -40,7 +40,7 @@ const productSetting: React.FC = async () => {
*/}
-
+
}>
diff --git a/src/app/(main)/settings/m18ImportTesting/page.tsx b/src/app/(main)/settings/m18ImportTesting/page.tsx
index 3aa4a35..e376c29 100644
--- a/src/app/(main)/settings/m18ImportTesting/page.tsx
+++ b/src/app/(main)/settings/m18ImportTesting/page.tsx
@@ -21,7 +21,7 @@ const M18ImportTestingPage: React.FC = async () => {
rowGap={2}
>
}>
-
+
diff --git a/src/app/(main)/settings/mail/page.tsx b/src/app/(main)/settings/mail/page.tsx
index 6bbb298..1dd8b96 100644
--- a/src/app/(main)/settings/mail/page.tsx
+++ b/src/app/(main)/settings/mail/page.tsx
@@ -29,7 +29,7 @@ const Customer: React.FC = async () => {
{t("Mail")}
-
+
}>
diff --git a/src/app/(main)/settings/masterDataIssues/page.tsx b/src/app/(main)/settings/masterDataIssues/page.tsx
index ebd698f..7b4f680 100644
--- a/src/app/(main)/settings/masterDataIssues/page.tsx
+++ b/src/app/(main)/settings/masterDataIssues/page.tsx
@@ -13,7 +13,7 @@ const MasterDataIssuesPage: React.FC = async () => {
return (
<>
-
+
>
diff --git a/src/app/(main)/settings/printer/create/page.tsx b/src/app/(main)/settings/printer/create/page.tsx
index 8a5e509..ba8ef78 100644
--- a/src/app/(main)/settings/printer/create/page.tsx
+++ b/src/app/(main)/settings/printer/create/page.tsx
@@ -4,12 +4,12 @@ import { Suspense } from "react";
import CreatePrinter from "@/components/CreatePrinter";
const CreatePrinterPage: React.FC = async () => {
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("printer");
return (
<>
{t("Create Printer") || "新增列印機"}
-
+
}>
diff --git a/src/app/(main)/settings/printer/edit/page.tsx b/src/app/(main)/settings/printer/edit/page.tsx
index c2c02c9..f4cdc0c 100644
--- a/src/app/(main)/settings/printer/edit/page.tsx
+++ b/src/app/(main)/settings/printer/edit/page.tsx
@@ -10,7 +10,7 @@ import { fetchPrinterDetails } from "@/app/api/settings/printer/actions";
type Props = {} & SearchParams;
const EditPrinterPage: React.FC = async ({ searchParams }) => {
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("printer");
const id = isString(searchParams["id"])
? parseInt(searchParams["id"])
: undefined;
@@ -26,7 +26,7 @@ const EditPrinterPage: React.FC = async ({ searchParams }) => {
return (
<>
{t("Edit")} {t("Printer")}
-
+
Loading... }>
diff --git a/src/app/(main)/settings/printer/page.tsx b/src/app/(main)/settings/printer/page.tsx
index ee662a2..ee7b9ee 100644
--- a/src/app/(main)/settings/printer/page.tsx
+++ b/src/app/(main)/settings/printer/page.tsx
@@ -13,7 +13,7 @@ export const metadata: Metadata = {
};
const Printer: React.FC = async () => {
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("printer");
return (
<>
@@ -35,7 +35,7 @@ const Printer: React.FC = async () => {
{t("Create Printer") || "新增列印機"}
-
+
}>
diff --git a/src/app/(main)/settings/qcCategory/edit/page.tsx b/src/app/(main)/settings/qcCategory/edit/page.tsx
index cadcd7a..3bf58e4 100644
--- a/src/app/(main)/settings/qcCategory/edit/page.tsx
+++ b/src/app/(main)/settings/qcCategory/edit/page.tsx
@@ -43,7 +43,7 @@ const qcCategory: React.FC = async ({ searchParams }) => {
{t("Edit Qc Category")}
-
+
>
diff --git a/src/app/(main)/settings/qcCategory/page.tsx b/src/app/(main)/settings/qcCategory/page.tsx
index 63f57ee..e27d2cd 100644
--- a/src/app/(main)/settings/qcCategory/page.tsx
+++ b/src/app/(main)/settings/qcCategory/page.tsx
@@ -36,9 +36,11 @@ const qcCategory: React.FC = async () => {
{t("Create Qc Category")}
- }>
-
-
+
+ }>
+
+
+
>
);
};
diff --git a/src/app/(main)/settings/qcItem copy/create/page.tsx b/src/app/(main)/settings/qcItem copy/create/page.tsx
index 1cb5c8a..b1a1bc0 100644
--- a/src/app/(main)/settings/qcItem copy/create/page.tsx
+++ b/src/app/(main)/settings/qcItem copy/create/page.tsx
@@ -16,7 +16,7 @@ const qcItem: React.FC = async () => {
{t("Create Qc Item")}
-
+
>
diff --git a/src/app/(main)/settings/qcItem copy/edit/page.tsx b/src/app/(main)/settings/qcItem copy/edit/page.tsx
index 0e433fb..2529168 100644
--- a/src/app/(main)/settings/qcItem copy/edit/page.tsx
+++ b/src/app/(main)/settings/qcItem copy/edit/page.tsx
@@ -43,7 +43,7 @@ const qcItem: React.FC = async ({ searchParams }) => {
{t("Edit Qc Item")}
-
+
>
diff --git a/src/app/(main)/settings/qcItem copy/page.tsx b/src/app/(main)/settings/qcItem copy/page.tsx
index f1b4e71..bc078ef 100644
--- a/src/app/(main)/settings/qcItem copy/page.tsx
+++ b/src/app/(main)/settings/qcItem copy/page.tsx
@@ -37,7 +37,7 @@ const qcItem: React.FC = async () => {
}>
-
+
diff --git a/src/app/(main)/settings/qcItem/create/page.tsx b/src/app/(main)/settings/qcItem/create/page.tsx
index 1cb5c8a..b1a1bc0 100644
--- a/src/app/(main)/settings/qcItem/create/page.tsx
+++ b/src/app/(main)/settings/qcItem/create/page.tsx
@@ -16,7 +16,7 @@ const qcItem: React.FC = async () => {
{t("Create Qc Item")}
-
+
>
diff --git a/src/app/(main)/settings/qcItem/edit/page.tsx b/src/app/(main)/settings/qcItem/edit/page.tsx
index 0e433fb..2529168 100644
--- a/src/app/(main)/settings/qcItem/edit/page.tsx
+++ b/src/app/(main)/settings/qcItem/edit/page.tsx
@@ -43,7 +43,7 @@ const qcItem: React.FC = async ({ searchParams }) => {
{t("Edit Qc Item")}
-
+
>
diff --git a/src/app/(main)/settings/qcItem/page.tsx b/src/app/(main)/settings/qcItem/page.tsx
index f1b4e71..bc078ef 100644
--- a/src/app/(main)/settings/qcItem/page.tsx
+++ b/src/app/(main)/settings/qcItem/page.tsx
@@ -37,7 +37,7 @@ const qcItem: React.FC = async () => {
}>
-
+
diff --git a/src/app/(main)/settings/qcItemAll/page.tsx b/src/app/(main)/settings/qcItemAll/page.tsx
index cb257ac..78cc17c 100644
--- a/src/app/(main)/settings/qcItemAll/page.tsx
+++ b/src/app/(main)/settings/qcItemAll/page.tsx
@@ -30,7 +30,7 @@ const qcItemAll: React.FC = async () => {
Loading...}>
-
+
}
tab1Content={}
diff --git a/src/app/(main)/settings/qrCodeHandle/page.tsx b/src/app/(main)/settings/qrCodeHandle/page.tsx
index d363561..07bfea2 100644
--- a/src/app/(main)/settings/qrCodeHandle/page.tsx
+++ b/src/app/(main)/settings/qrCodeHandle/page.tsx
@@ -12,7 +12,7 @@ import Box from "@mui/material/Box";
export const metadata: Metadata = { title: "QR Code Handle" };
const QrCodeHandlePage: React.FC = async () => {
- const { t } = await getServerI18n("common");
+ const { t } = await getServerI18n("qrCodeHandle");
return (
@@ -20,25 +20,25 @@ const QrCodeHandlePage: React.FC = async () => {
{t("QR Code Handle")}
-
+
}>
-
+
}
equipmentTabContent={
}>
-
+
}
warehouseTabContent={
}>
-
+
diff --git a/src/app/(main)/settings/rss/page.tsx b/src/app/(main)/settings/rss/page.tsx
index 3c9e853..388d579 100644
--- a/src/app/(main)/settings/rss/page.tsx
+++ b/src/app/(main)/settings/rss/page.tsx
@@ -18,8 +18,7 @@ export const metadata: Metadata = {
const roughScheduleSetting: React.FC = async () => {
//const project = TypeEnum.PRODUCT
- const project = "common"
- const { t } = await getServerI18n(project);
+ const { t } = await getServerI18n("demandForecast", "navigation", "common");
// preloadClaims();
return (
@@ -43,7 +42,7 @@ const roughScheduleSetting: React.FC = async () => {
*/}
}>
-
+
diff --git a/src/app/(main)/settings/shop/board/page.tsx b/src/app/(main)/settings/shop/board/page.tsx
index bee001e..2e47690 100644
--- a/src/app/(main)/settings/shop/board/page.tsx
+++ b/src/app/(main)/settings/shop/board/page.tsx
@@ -5,7 +5,7 @@ import GeneralLoading from "@/components/General/GeneralLoading";
import RouteBoard from "@/components/Shop/RouteBoard";
export default async function ShopRouteBoardPage() {
- await getServerI18n("shop", "common", "routeboard");
+ await getServerI18n("shop", "navigation");
return (
-
+
}>
diff --git a/src/app/(main)/settings/shop/detail/page.tsx b/src/app/(main)/settings/shop/detail/page.tsx
index 02c2334..7a22513 100644
--- a/src/app/(main)/settings/shop/detail/page.tsx
+++ b/src/app/(main)/settings/shop/detail/page.tsx
@@ -4,9 +4,9 @@ import { I18nProvider, getServerI18n } from "@/i18n";
import GeneralLoading from "@/components/General/GeneralLoading";
export default async function ShopDetailPage() {
- const { t } = await getServerI18n("shop", "common");
+ await getServerI18n("shop");
return (
-
+
}>
diff --git a/src/app/(main)/settings/shop/page.tsx b/src/app/(main)/settings/shop/page.tsx
index c4e8175..50901ac 100644
--- a/src/app/(main)/settings/shop/page.tsx
+++ b/src/app/(main)/settings/shop/page.tsx
@@ -8,9 +8,9 @@ import { notFound } from "next/navigation";
export default async function ShopPage() {
- const { t } = await getServerI18n("shop", "common");
+ await getServerI18n("shop");
return (
-
+
}>
diff --git a/src/app/(main)/settings/shop/truckdetail/page.tsx b/src/app/(main)/settings/shop/truckdetail/page.tsx
index 8c50c6d..a955368 100644
--- a/src/app/(main)/settings/shop/truckdetail/page.tsx
+++ b/src/app/(main)/settings/shop/truckdetail/page.tsx
@@ -4,9 +4,9 @@ import { I18nProvider, getServerI18n } from "@/i18n";
import GeneralLoading from "@/components/General/GeneralLoading";
export default async function TruckLaneDetailPage() {
- const { t } = await getServerI18n("shop", "common");
+ await getServerI18n("shop");
return (
-
+
}>
diff --git a/src/app/(main)/settings/user/create/page.tsx b/src/app/(main)/settings/user/create/page.tsx
index 88694b8..33351fd 100644
--- a/src/app/(main)/settings/user/create/page.tsx
+++ b/src/app/(main)/settings/user/create/page.tsx
@@ -17,7 +17,7 @@ const CreateStaffPage: React.FC = async () => {
return (
<>
{t("Create User")}
-
+
}>
diff --git a/src/app/(main)/settings/user/edit/page.tsx b/src/app/(main)/settings/user/edit/page.tsx
index e489f72..ba08277 100644
--- a/src/app/(main)/settings/user/edit/page.tsx
+++ b/src/app/(main)/settings/user/edit/page.tsx
@@ -18,7 +18,7 @@ const User: React.FC = async ({ searchParams }) => {
return (
<>
{t("Edit User")}
-
+
}>
diff --git a/src/app/(main)/settings/user/page.tsx b/src/app/(main)/settings/user/page.tsx
index 6876046..ccf7712 100644
--- a/src/app/(main)/settings/user/page.tsx
+++ b/src/app/(main)/settings/user/page.tsx
@@ -47,7 +47,7 @@ const User: React.FC = async () => {
{t("Create User")}
-
+
>
diff --git a/src/app/(main)/settings/warehouse/create/page.tsx b/src/app/(main)/settings/warehouse/create/page.tsx
index 0ee2965..913c3b6 100644
--- a/src/app/(main)/settings/warehouse/create/page.tsx
+++ b/src/app/(main)/settings/warehouse/create/page.tsx
@@ -9,7 +9,7 @@ const CreateWarehousePage: React.FC = async () => {
return (
<>
{t("Create Warehouse")}
-
+
}>
diff --git a/src/app/(main)/settings/warehouse/page.tsx b/src/app/(main)/settings/warehouse/page.tsx
index 5a57332..a842eb3 100644
--- a/src/app/(main)/settings/warehouse/page.tsx
+++ b/src/app/(main)/settings/warehouse/page.tsx
@@ -31,7 +31,7 @@ const Warehouse: React.FC = async () => {
{t("Create Warehouse")}
-
+
}
diff --git a/src/app/(main)/stockIssue/page.tsx b/src/app/(main)/stockIssue/page.tsx
index 11b49be..1881417 100644
--- a/src/app/(main)/stockIssue/page.tsx
+++ b/src/app/(main)/stockIssue/page.tsx
@@ -11,7 +11,7 @@ export const metadata: Metadata = {
const SearchView: React.FC = async () => {
return (
<>
-
+
}>
diff --git a/src/app/(main)/stockOutIssueRecord/detail/page.tsx b/src/app/(main)/stockOutIssueRecord/detail/page.tsx
index ce6ed51..4c21581 100644
--- a/src/app/(main)/stockOutIssueRecord/detail/page.tsx
+++ b/src/app/(main)/stockOutIssueRecord/detail/page.tsx
@@ -1,24 +1,18 @@
-
import { SearchParams } from "@/app/utils/fetchUtil";
import PickOrderDetail from "@/components/PickOrderDetail";
-import { getServerI18n, I18nProvider } from "@/i18n";
-import { Stack, Typography } from "@mui/material";
+import { I18nProvider } from "@/i18n";
import { Metadata } from "next";
import { Suspense } from "react";
export const metadata: Metadata = {
- title: "Consolidated Pick Order Flow",
+ title: "Stock Out Issue Record Detail",
};
type Props = {} & SearchParams;
-const PickOrder: React.FC = async ({ searchParams }) => {
- const { t } = await getServerI18n("pickOrder");
-
-
-
+const StockOutIssueRecordDetail: React.FC = async ({ searchParams }) => {
return (
<>
-
+
}>
@@ -27,4 +21,4 @@ const PickOrder: React.FC = async ({ searchParams }) => {
);
};
-export default PickOrder;
+export default StockOutIssueRecordDetail;
diff --git a/src/app/(main)/stockOutIssueRecord/page.tsx b/src/app/(main)/stockOutIssueRecord/page.tsx
index 70e91dd..36d5aa3 100644
--- a/src/app/(main)/stockOutIssueRecord/page.tsx
+++ b/src/app/(main)/stockOutIssueRecord/page.tsx
@@ -1,23 +1,16 @@
-import { PreloadPickOrder } from "@/app/api/pickOrder";
import PickOrderSearch from "@/components/PickOrderSearch";
-import { getServerI18n } from "@/i18n";
import { I18nProvider } from "@/i18n";
-import { Stack, Typography } from "@mui/material";
import { Metadata } from "next";
import { Suspense } from "react";
export const metadata: Metadata = {
- title: "Pick Order",
+ title: "Stock Out Issue Record",
};
-const PickOrder: React.FC = async () => {
- const { t } = await getServerI18n("pickOrder");
-
- // PreloadPickOrder();
-
+const StockOutIssueRecord: React.FC = async () => {
return (
<>
-
+
}>
@@ -26,4 +19,4 @@ const PickOrder: React.FC = async () => {
);
};
-export default PickOrder;
+export default StockOutIssueRecord;
diff --git a/src/app/(main)/stockRecord/page.tsx b/src/app/(main)/stockRecord/page.tsx
index d144167..3749834 100644
--- a/src/app/(main)/stockRecord/page.tsx
+++ b/src/app/(main)/stockRecord/page.tsx
@@ -9,11 +9,11 @@ export const metadata: Metadata = {
};
const SearchView: React.FC = async () => {
- const { t } = await getServerI18n("inventory");
+ const { t } = await getServerI18n("stockRecord");
return (
<>
-
+
}>
diff --git a/src/app/(main)/stocktakemanagement/page.tsx b/src/app/(main)/stocktakemanagement/page.tsx
index 1ed3fae..917a737 100644
--- a/src/app/(main)/stocktakemanagement/page.tsx
+++ b/src/app/(main)/stocktakemanagement/page.tsx
@@ -8,9 +8,9 @@ import { notFound } from "next/navigation";
export default async function InventoryManagementPage() {
- const { t } = await getServerI18n("inventory");
+ const { t } = await getServerI18n("stockTake");
return (
-
+
}>
diff --git a/src/app/(main)/tasks/create/page.tsx b/src/app/(main)/tasks/create/page.tsx
index 656139f..c14b50d 100644
--- a/src/app/(main)/tasks/create/page.tsx
+++ b/src/app/(main)/tasks/create/page.tsx
@@ -1,6 +1,6 @@
import { preloadAllTasks } from "@/app/api/tasks";
import CreateTaskTemplate from "@/components/CreateTaskTemplate";
-import { getServerI18n } from "@/i18n";
+import { getServerI18n, I18nProvider } from "@/i18n";
import Typography from "@mui/material/Typography";
import { Metadata } from "next";
@@ -14,8 +14,10 @@ const Projects: React.FC = async () => {
return (
<>
- {t("Create Task Template")}
-
+
+ {t("Create Task Template")}
+
+
>
);
};
diff --git a/src/app/(main)/tasks/page.tsx b/src/app/(main)/tasks/page.tsx
index b9e9bf8..12c8bc2 100644
--- a/src/app/(main)/tasks/page.tsx
+++ b/src/app/(main)/tasks/page.tsx
@@ -7,6 +7,7 @@ import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { Metadata } from "next";
import Link from "next/link";
+import { I18nProvider } from "@/i18n";
import { Suspense } from "react";
export const metadata: Metadata = {
@@ -14,7 +15,7 @@ export const metadata: Metadata = {
};
const TaskTemplates: React.FC = async () => {
- const { t } = await getServerI18n("projects");
+ const { t } = await getServerI18n("project");
preloadTaskTemplates();
return (
@@ -37,9 +38,11 @@ const TaskTemplates: React.FC = async () => {
{t("Create Template")}
- }>
-
-
+
+ }>
+
+
+
>
);
};
diff --git a/src/app/api/shop/actions.ts b/src/app/api/shop/actions.ts
index a60950b..6339c99 100644
--- a/src/app/api/shop/actions.ts
+++ b/src/app/api/shop/actions.ts
@@ -492,6 +492,7 @@ export interface TruckLaneVersionResponse {
truckLanceCode: string;
note: string | null;
created: string | null;
+ createdBy?: string | null;
/** truck_lane_version.modifiedBy(BaseEntity) */
modifiedBy?: string | null;
}
@@ -602,4 +603,309 @@ export const updateTruckLaneVersionNoteAction = async (
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
});
+};
+
+// ---- Truck lane schedule (server-side apply) ----
+
+export type TruckLaneScheduleLineAction =
+ | "MOVE"
+ | "CREATE"
+ | "DELETE"
+ | "ENSURE_LANE";
+
+export type TruckLaneMoveTargetRequest = {
+ truckRowId: number;
+ toTruckLanceCode: string;
+ toRemark?: string | null;
+ toStoreId: string;
+ toLoadingSequence: number;
+ toDistrictReference?: string | null;
+};
+
+export type TruckLaneScheduleLineRequest = {
+ action: TruckLaneScheduleLineAction;
+ truckRowId?: number | null;
+ toTruckLanceCode: string;
+ toRemark?: string | null;
+ toStoreId: string;
+ toLoadingSequence?: number | null;
+ toDistrictReference?: string | null;
+ shopId?: number | null;
+ shopCode?: string | null;
+ shopName?: string | null;
+ departureTime?: string | null;
+ logisticId?: number | null;
+};
+
+export type CreateTruckLaneScheduleRequest = {
+ executeAt: string;
+ note?: string | null;
+ lines?: TruckLaneScheduleLineRequest[] | null;
+ moves?: TruckLaneMoveTargetRequest[] | null;
+};
+
+export type TruckLaneScheduleLineResponse = {
+ id: number;
+ action: TruckLaneScheduleLineAction;
+ truckRowId: number | null;
+ shopCode: string | null;
+ shopName: string | null;
+ fromTruckLanceCode: string | null;
+ fromRemark: string | null;
+ fromStoreId: string | null;
+ fromLoadingSequence?: number | null;
+ fromDistrictReference?: string | null;
+ fromDepartureTime?: string | null;
+ toTruckLanceCode: string;
+ toRemark: string | null;
+ toStoreId: string;
+ toDistrictReference?: string | null;
+ toLoadingSequence?: number | null;
+ departureTime?: string | null;
+ lineStatus: string;
+ errorMessage: string | null;
+ appliedAt: string | null;
+};
+
+export type RouteExcelSchedulePlanPreviewRow = {
+ action: TruckLaneScheduleLineAction;
+ truckRowId: number | null;
+ shopCode: string | null;
+ shopName: string | null;
+ toTruckLanceCode: string;
+ toRemark: string | null;
+ toStoreId: string;
+ toLoadingSequence: number | null;
+};
+
+export type RouteExcelSchedulePlanError = {
+ shopCode: string;
+ shopName: string;
+ message: string;
+};
+
+export type RouteExcelSchedulePlanCounts = {
+ moves: number;
+ creates: number;
+ deletes: number;
+ ensureLanes: number;
+};
+
+export type RouteExcelSchedulePlanResponse = {
+ sheetCount: number;
+ rowCount: number;
+ lines: TruckLaneScheduleLineRequest[];
+ previews: RouteExcelSchedulePlanPreviewRow[];
+ errors: RouteExcelSchedulePlanError[];
+ counts: RouteExcelSchedulePlanCounts;
+};
+
+export type TruckLaneScheduleResponse = {
+ id: number;
+ executeAt: string;
+ status: string;
+ source: string;
+ note: string | null;
+ appliedAt: string | null;
+ errorMessage: string | null;
+ snapshotVersionId: number | null;
+ preApplySnapshotVersionId?: number | null;
+ created: string | null;
+ createdBy?: string | null;
+ modifiedBy: string | null;
+ lines?: TruckLaneScheduleLineResponse[] | null;
+ lineCounts?: {
+ total: number;
+ applied: number;
+ failed: number;
+ pending: number;
+ } | null;
+};
+
+export type PendingTruckRowIdsResponse = {
+ truckRowIds: number[];
+};
+
+export type TruckLaneScheduleExcelPreviewRow = {
+ rowIndex: number;
+ shopCode: string;
+ toTruckLanceCode: string;
+ toRemark: string | null;
+ toStoreId: string;
+ executeAt: string | null;
+ truckRowId: number | null;
+};
+
+export type TruckLaneScheduleExcelRowError = {
+ rowIndex: number;
+ message: string;
+};
+
+export type ParseTruckLaneScheduleExcelResponse = {
+ rowCount: number;
+ validCount: number;
+ errorCount: number;
+ rows: TruckLaneScheduleExcelPreviewRow[];
+ errors: TruckLaneScheduleExcelRowError[];
+};
+
+export const createTruckLaneScheduleAction = async (
+ data: CreateTruckLaneScheduleRequest,
+): Promise => {
+ const endpoint = `${BASE_API_URL}/truckLaneSchedule`;
+ return serverFetchJson(endpoint, {
+ method: "POST",
+ body: JSON.stringify(data),
+ headers: { "Content-Type": "application/json" },
+ });
+};
+
+export const planTruckLaneScheduleFromRouteExcelAction = async (
+ formData: FormData,
+): Promise => {
+ const response = await serverFetch(
+ `${BASE_API_URL}/truckLaneSchedule/planFromRouteExcel`,
+ {
+ method: "POST",
+ body: formData,
+ },
+ );
+ if (!response.ok) {
+ const text = await response.text().catch(() => "");
+ throw new ServerFetchError(
+ `Plan import failed: ${response.status} ${text}`.trim(),
+ response,
+ );
+ }
+ return (await response.json()) as RouteExcelSchedulePlanResponse;
+};
+
+export const listTruckLaneSchedulesAction = async (
+ status?: string[],
+ limit: number = 200,
+): Promise => {
+ const params = new URLSearchParams();
+ for (const s of status ?? []) {
+ params.append("status", s);
+ }
+ params.set("limit", String(limit));
+ const qs = params.toString();
+ const base = `${BASE_API_URL}/truckLaneSchedule`;
+ return serverFetchJson(
+ `${base}${qs ? `?${qs}` : ""}`,
+ {
+ method: "GET",
+ headers: { "Content-Type": "application/json" },
+ },
+ );
+};
+
+export const getTruckLaneScheduleAction = async (
+ id: number,
+): Promise => {
+ const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}`;
+ return serverFetchJson(endpoint, {
+ method: "GET",
+ headers: { "Content-Type": "application/json" },
+ });
+};
+
+export const pendingTruckLaneScheduleShopIdsAction =
+ async (): Promise => {
+ const endpoint = `${BASE_API_URL}/truckLaneSchedule/pendingShopIds`;
+ return serverFetchJson(endpoint, {
+ method: "GET",
+ headers: { "Content-Type": "application/json" },
+ });
+ };
+
+export const cancelTruckLaneScheduleAction = async (
+ id: number,
+): Promise => {
+ const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/cancel`;
+ return serverFetchJson(endpoint, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ });
+};
+
+export const applyNowTruckLaneScheduleAction = async (
+ id: number,
+): Promise => {
+ const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/applyNow`;
+ return serverFetchJson(endpoint, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ });
+};
+
+export type RetryFailedTruckLaneScheduleRequest = {
+ executeAt?: string | null;
+};
+
+export const retryFailedTruckLaneScheduleAction = async (
+ id: number,
+ body?: RetryFailedTruckLaneScheduleRequest,
+): Promise => {
+ const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/retry-failed`;
+ return serverFetchJson(endpoint, {
+ method: "POST",
+ body: JSON.stringify(body ?? {}),
+ headers: { "Content-Type": "application/json" },
+ });
+};
+
+export const ignoreTruckLaneScheduleAction = async (
+ id: number,
+): Promise => {
+ const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/ignore`;
+ return serverFetchJson(endpoint, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ });
+};
+
+export const parseTruckLaneScheduleExcelAction = async (
+ formData: FormData,
+ defaultExecuteAt?: string | null,
+): Promise => {
+ const qs =
+ defaultExecuteAt != null && defaultExecuteAt !== ""
+ ? `?defaultExecuteAt=${encodeURIComponent(defaultExecuteAt)}`
+ : "";
+ const response = await serverFetch(
+ `${BASE_API_URL}/truckLaneSchedule/parseExcel${qs}`,
+ { method: "POST", body: formData },
+ );
+ if (!response.ok) {
+ const text = await response.text().catch(() => "");
+ throw new ServerFetchError(
+ `Parse schedule Excel failed: ${response.status} ${text}`.trim(),
+ response,
+ );
+ }
+ return (await response.json()) as ParseTruckLaneScheduleExcelResponse;
+};
+
+export const importTruckLaneScheduleExcelAction = async (
+ formData: FormData,
+ defaultExecuteAt?: string | null,
+ note?: string | null,
+): Promise => {
+ const params = new URLSearchParams();
+ if (defaultExecuteAt) params.set("defaultExecuteAt", defaultExecuteAt);
+ if (note) params.set("note", note);
+ const qs = params.toString() ? `?${params.toString()}` : "";
+ const response = await serverFetch(
+ `${BASE_API_URL}/truckLaneSchedule/importExcel${qs}`,
+ { method: "POST", body: formData },
+ );
+ if (!response.ok) {
+ const text = await response.text().catch(() => "");
+ throw new ServerFetchError(
+ `Import schedule Excel failed: ${response.status} ${text}`.trim(),
+ response,
+ );
+ }
+ return (await response.json()) as TruckLaneScheduleResponse[];
};
\ No newline at end of file
diff --git a/src/app/api/shop/client.ts b/src/app/api/shop/client.ts
index d86dcf0..d7b710f 100644
--- a/src/app/api/shop/client.ts
+++ b/src/app/api/shop/client.ts
@@ -30,7 +30,29 @@ import {
diffTruckLaneVersionsAction,
restoreTruckLaneVersionAction,
updateTruckLaneVersionNoteAction,
+ createTruckLaneScheduleAction,
+ planTruckLaneScheduleFromRouteExcelAction,
+ listTruckLaneSchedulesAction,
+ getTruckLaneScheduleAction,
+ pendingTruckLaneScheduleShopIdsAction,
+ cancelTruckLaneScheduleAction,
+ applyNowTruckLaneScheduleAction,
+ retryFailedTruckLaneScheduleAction,
+ ignoreTruckLaneScheduleAction,
+ type RetryFailedTruckLaneScheduleRequest,
+ parseTruckLaneScheduleExcelAction,
+ importTruckLaneScheduleExcelAction,
type CreateTruckLaneSnapshotRequest,
+ type CreateTruckLaneScheduleRequest,
+ type TruckLaneScheduleResponse,
+ type TruckLaneScheduleLineRequest,
+ type RouteExcelSchedulePlanPreviewRow,
+ type RouteExcelSchedulePlanError,
+ type RouteExcelSchedulePlanResponse,
+ type RouteExcelSchedulePlanCounts,
+ type TruckLaneMoveTargetRequest,
+ type PendingTruckRowIdsResponse,
+ type ParseTruckLaneScheduleExcelResponse,
type UpdateTruckLaneVersionNoteRequest,
type TruckLaneVersionResponse,
type TruckLaneVersionLineResponse,
@@ -184,4 +206,92 @@ export const updateTruckLaneVersionNoteClient = async (
return await updateTruckLaneVersionNoteAction(versionId, data);
};
+export const planTruckLaneScheduleFromRouteExcelClient = async (
+ formData: FormData,
+): Promise => {
+ return await planTruckLaneScheduleFromRouteExcelAction(formData);
+};
+
+export const createTruckLaneScheduleClient = async (
+ data: CreateTruckLaneScheduleRequest,
+): Promise => {
+ return await createTruckLaneScheduleAction(data);
+};
+
+export const listTruckLaneSchedulesClient = async (
+ status?: string[],
+ limit: number = 200,
+): Promise => {
+ return await listTruckLaneSchedulesAction(status, limit);
+};
+
+export const getTruckLaneScheduleClient = async (
+ id: number,
+): Promise => {
+ return await getTruckLaneScheduleAction(id);
+};
+
+export const pendingTruckLaneScheduleShopIdsClient =
+ async (): Promise => {
+ return await pendingTruckLaneScheduleShopIdsAction();
+ };
+
+export const cancelTruckLaneScheduleClient = async (
+ id: number,
+): Promise => {
+ return await cancelTruckLaneScheduleAction(id);
+};
+
+export const applyNowTruckLaneScheduleClient = async (
+ id: number,
+): Promise => {
+ return await applyNowTruckLaneScheduleAction(id);
+};
+
+export const retryFailedTruckLaneScheduleClient = async (
+ id: number,
+ body?: RetryFailedTruckLaneScheduleRequest,
+): Promise => {
+ return await retryFailedTruckLaneScheduleAction(id, body);
+};
+
+export const ignoreTruckLaneScheduleClient = async (
+ id: number,
+): Promise => {
+ return await ignoreTruckLaneScheduleAction(id);
+};
+
+export const parseTruckLaneScheduleExcelClient = async (
+ formData: FormData,
+ defaultExecuteAt?: string | null,
+): Promise => {
+ return await parseTruckLaneScheduleExcelAction(formData, defaultExecuteAt);
+};
+
+export const importTruckLaneScheduleExcelClient = async (
+ formData: FormData,
+ defaultExecuteAt?: string | null,
+ note?: string | null,
+): Promise => {
+ return await importTruckLaneScheduleExcelAction(
+ formData,
+ defaultExecuteAt,
+ note,
+ );
+};
+
+export type {
+ TruckLaneScheduleResponse,
+ TruckLaneScheduleLineResponse,
+ TruckLaneMoveTargetRequest,
+ TruckLaneScheduleLineRequest,
+ CreateTruckLaneScheduleRequest,
+ PendingTruckRowIdsResponse,
+ ParseTruckLaneScheduleExcelResponse,
+ RouteExcelSchedulePlanResponse,
+ RouteExcelSchedulePlanPreviewRow,
+ RouteExcelSchedulePlanError,
+ RouteExcelSchedulePlanCounts,
+} from "./actions";
+
export default fetchAllShopsClient;
diff --git a/src/components/AppBar/AppBar.tsx b/src/components/AppBar/AppBar.tsx
index cb70811..8fa9d95 100644
--- a/src/components/AppBar/AppBar.tsx
+++ b/src/components/AppBar/AppBar.tsx
@@ -16,7 +16,7 @@ export interface AppBarProps {
const AppBar: React.FC = ({ avatarImageSrc, profileName }) => {
return (
-
+
diff --git a/src/components/AppBar/Profile.tsx b/src/components/AppBar/Profile.tsx
index dc6ed1d..7146f81 100644
--- a/src/components/AppBar/Profile.tsx
+++ b/src/components/AppBar/Profile.tsx
@@ -29,7 +29,7 @@ const Profile: React.FC = ({ avatarImageSrc, profileName }) => {
return (
<>
-
+
),
+ sx: {
+ alignItems: "center",
+ },
+ }}
+ sx={{
+ "& .MuiInputBase-root": {
+ alignItems: "center",
+ },
+ "& .MuiInputBase-input": {
+ textAlign: "left",
+ py: 0.75,
+ },
+ "& .MuiInputBase-input::placeholder": {
+ opacity: 1,
+ color: "text.disabled",
+ textAlign: "left",
+ },
}}
/>
+
+ ) : (
+
+ {districtSections.map(({ district, shops, isPendingEmpty }) => (
+ {
+ e.preventDefault();
+ onDragOverColumn(e);
+ }}
+ onDrop={(e) => onDropDistrict(e, district)}
+ >
+ onRemoveEmptyDistrict(district)
+ : undefined
+ }
+ />
+
+ {shops.map((shop) => (
+
+ ))}
+
+
+ ))}
+ }
+ onClick={onAddDistrict}
+ sx={{ alignSelf: "flex-start" }}
+ >
+ {addDistrictLabel}
+
+
+ )}
+
+
+ );
+});
+
+const ScheduleDragWorkspacePane: React.FC = ({
+ lanes,
+ leftLaneId,
+ rightLaneId,
+ plannedLanes,
+ pendingEmptyDistrictsByLane,
+ onLeftLaneChange,
+ onRightLaneChange,
+ onMoveShop,
+ onRevertShop,
+ onSetLoadingSequence,
+ onAddEmptyDistrict,
+ onRemoveEmptyDistrict,
+ onDeleteShop,
+}) => {
+ const { t } = useTranslation("shop");
+ const draggedRef = useRef<{ shopId: number; fromLaneId: string } | null>(
+ null,
+ );
+ const [isOverColumnId, setIsOverColumnId] = useState(null);
+ const [hoveredShopId, setHoveredShopId] = useState(null);
+ const [hoveredPosition, setHoveredPosition] = useState<"before" | "after">(
+ "after",
+ );
+ const [seqEditTarget, setSeqEditTarget] = useState(
+ null,
+ );
+ const [districtAddLaneId, setDistrictAddLaneId] = useState(
+ null,
+ );
+ const [districtAddDraft, setDistrictAddDraft] = useState("");
+ const [districtAddError, setDistrictAddError] = useState(
+ null,
+ );
+
+ const leftLane = plannedLanes.find((l) => l.id === leftLaneId);
+ const rightLane = plannedLanes.find((l) => l.id === rightLaneId);
+
+ const clearDrag = useCallback(() => {
+ draggedRef.current = null;
+ setIsOverColumnId(null);
+ setHoveredShopId(null);
+ }, []);
+
+ const handleDragStart = (shopId: number, fromLaneId: string) => {
+ draggedRef.current = { shopId, fromLaneId };
+ };
+
+ const handleDragOverShop = (e: React.DragEvent, shopId: number) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
+ const offset = e.clientY - rect.top;
+ setHoveredShopId(shopId);
+ setHoveredPosition(offset < rect.height / 2 ? "before" : "after");
+ };
+
+ const handleDropOnShop = (
+ e: React.DragEvent,
+ targetLaneId: string,
+ targetShopId: number,
+ ) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const dragged = draggedRef.current;
+ if (!dragged) return;
+ const lane = plannedLanes.find((l) => l.id === targetLaneId);
+ const flat = lane?.shops ?? [];
+ let beforeShopId: number | null;
+ if (hoveredShopId === targetShopId && hoveredPosition === "before") {
+ beforeShopId = targetShopId;
+ } else if (hoveredShopId === targetShopId && hoveredPosition === "after") {
+ const idx = flat.findIndex((s) => s.truckRowId === targetShopId);
+ beforeShopId =
+ idx >= 0 && idx < flat.length - 1
+ ? (flat[idx + 1]?.truckRowId ?? null)
+ : null;
+ } else {
+ beforeShopId = targetShopId;
+ }
+ onMoveShop(
+ dragged.shopId,
+ dragged.fromLaneId,
+ targetLaneId,
+ beforeShopId,
+ );
+ clearDrag();
+ };
+
+ const handleDropOnColumn = (e: React.DragEvent, targetLaneId: string) => {
+ e.preventDefault();
+ const dragged = draggedRef.current;
+ if (!dragged) return;
+ const beforeShopId = getBeforeShopIdByPointer(targetLaneId, e.clientY);
+ onMoveShop(
+ dragged.shopId,
+ dragged.fromLaneId,
+ targetLaneId,
+ beforeShopId,
+ );
+ clearDrag();
+ };
+
+ const handleDropOnDistrict = useCallback(
+ (e: React.DragEvent, targetLaneId: string, district: string) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const dragged = draggedRef.current;
+ if (!dragged) return;
+ onMoveShop(
+ dragged.shopId,
+ dragged.fromLaneId,
+ targetLaneId,
+ null,
+ district,
+ );
+ clearDrag();
+ },
+ [onMoveShop, clearDrag],
+ );
+
+ const renderLaneSelectors = (
+
+
+
+ {t("schedule_lane_left")}
+
+ ) =>
+ onLeftLaneChange(e.target.value)
+ }
+ sx={nativeSelectSx}
+ >
+ {lanes.map((l) => (
+
+ ))}
+
+
+
+
+ {t("schedule_lane_right")}
+
+ ) =>
+ onRightLaneChange(e.target.value)
+ }
+ sx={nativeSelectSx}
+ >
+ {lanes.map((l) => (
+
+ ))}
+
+
+
+ );
+
+ const seqLabel = (seq: number) =>
+ t("schedule_drag_seq", { seq: String(seq) });
+
+ const handleStartSeqEdit = useCallback(
+ (laneId: string, shopId: number, current: number) => {
+ setSeqEditTarget({
+ laneId,
+ shopId,
+ draft: String(current),
+ });
+ },
+ [],
+ );
+
+ const handleCommitSeqEdit = useCallback(() => {
+ setSeqEditTarget((prev) => {
+ if (!prev) return null;
+ const n = Number(prev.draft);
+ const seq = Number.isFinite(n) ? Math.max(0, Math.trunc(n)) : 0;
+ onSetLoadingSequence(prev.laneId, prev.shopId, seq);
+ return null;
+ });
+ }, [onSetLoadingSequence]);
+
+ const handleCancelSeqEdit = useCallback(() => {
+ setSeqEditTarget(null);
+ }, []);
+
+ const openDistrictAdd = useCallback((laneId: string) => {
+ setDistrictAddLaneId(laneId);
+ setDistrictAddDraft("");
+ setDistrictAddError(null);
+ }, []);
+
+ const closeDistrictAdd = useCallback(() => {
+ setDistrictAddLaneId(null);
+ setDistrictAddDraft("");
+ setDistrictAddError(null);
+ }, []);
+
+ const applyDistrictAdd = useCallback(() => {
+ if (!districtAddLaneId) return;
+ const lane = plannedLanes.find((l) => l.id === districtAddLaneId);
+ if (!lane) {
+ closeDistrictAdd();
+ return;
+ }
+ const trimmed = districtAddDraft.trim();
+ if (!trimmed) {
+ setDistrictAddError(t("district_err_name"));
+ return;
+ }
+ if (trimmed === "未分類") {
+ setDistrictAddError(t("district_err_reserved"));
+ return;
+ }
+ const pendingExtra = pendingEmptyDistrictsByLane[districtAddLaneId] ?? [];
+ if (districtDisplayExistsInShops(lane.shops, pendingExtra, trimmed)) {
+ setDistrictAddError(t("district_err_exists"));
+ return;
+ }
+ onAddEmptyDistrict(districtAddLaneId, trimmed);
+ closeDistrictAdd();
+ }, [
+ closeDistrictAdd,
+ districtAddDraft,
+ districtAddLaneId,
+ onAddEmptyDistrict,
+ pendingEmptyDistrictsByLane,
+ plannedLanes,
+ t,
+ ]);
+
+ if (!leftLane || !rightLane) {
+ return (
+
+ {renderLaneSelectors}
+
+ {t("schedule_no_shops")}
+
+
+ );
+ }
+
+ const columnProps = (lane: PlannedLane) => ({
+ lane,
+ pendingEmptyDistricts: pendingEmptyDistrictsByLane[lane.id] ?? [],
+ isOver: isOverColumnId === lane.id,
+ onDragOverColumn: (e: React.DragEvent) => {
+ e.preventDefault();
+ setIsOverColumnId(lane.id);
+ },
+ onDragLeaveColumn: () => setIsOverColumnId(null),
+ onDropColumn: (e: React.DragEvent) => handleDropOnColumn(e, lane.id),
+ onDropDistrict: (e: React.DragEvent, district: string) =>
+ handleDropOnDistrict(e, lane.id, district),
+ onDragStartShop: (shopId: number) => handleDragStart(shopId, lane.id),
+ onDragOverShop: handleDragOverShop,
+ onDropShop: (e: React.DragEvent, shopId: number) =>
+ handleDropOnShop(e, lane.id, shopId),
+ onRevertShop: (shopId: number) => onRevertShop(shopId, lane.id),
+ onDeleteShop,
+ removeFromLaneTooltip: t("tooltip_removeFromLane"),
+ onAddDistrict: () => openDistrictAdd(lane.id),
+ onRemoveEmptyDistrict: (district: string) =>
+ onRemoveEmptyDistrict(lane.id, district),
+ hoveredShopId,
+ hoveredPosition,
+ movedBadgeLabel: t("schedule_moved_badge"),
+ seqLabel,
+ seqEditAriaLabel: t("schedule_seq_edit_btn"),
+ removeEmptyDistrictAriaLabel: t("aria_removeEmptyDistrict"),
+ onStartSeqEdit: handleStartSeqEdit,
+ dropHint: t("schedule_drop_hint"),
+ addDistrictLabel: t("btn_addDistrict"),
+ });
+
+ return (
+ <>
+
+ {renderLaneSelectors}
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default memo(ScheduleDragWorkspacePane);
diff --git a/src/components/Shop/ScheduleReviewQueue.tsx b/src/components/Shop/ScheduleReviewQueue.tsx
new file mode 100644
index 0000000..5174c03
--- /dev/null
+++ b/src/components/Shop/ScheduleReviewQueue.tsx
@@ -0,0 +1,349 @@
+"use client";
+
+import React, { memo } from "react";
+import {
+ Box,
+ Button,
+ Chip,
+ Paper,
+ Stack,
+ Typography,
+} from "@mui/material";
+import { alpha } from "@mui/material/styles";
+import { ArrowRight, Clock, HelpCircle, Trash2, Undo2 } from "lucide-react";
+import { useTranslation } from "react-i18next";
+import type {
+ ScheduleModification,
+ ScheduledDeleteSnapshot,
+} from "@/components/Shop/scheduleDragWorkspace";
+
+type Props = {
+ modifications: ScheduleModification[];
+ pendingDeletes: ScheduledDeleteSnapshot[];
+ onRevert: (shopId: number, currentLaneId: string) => void;
+ onRevertDelete: (truckRowId: number) => void;
+ errorTruckRowIds?: Set;
+ validationErrorsByTruckRowId?: Map;
+};
+
+const ScheduleReviewQueue: React.FC = ({
+ modifications,
+ pendingDeletes,
+ onRevert,
+ onRevertDelete,
+ errorTruckRowIds = new Set(),
+ validationErrorsByTruckRowId = new Map(),
+}) => {
+ const { t } = useTranslation("shop");
+ const totalCount = modifications.length + pendingDeletes.length;
+ const isEmpty = totalCount === 0;
+
+ return (
+
+
+
+
+
+ {t("schedule_review_queue")}
+
+
+
+
+
+
+ {isEmpty ? (
+
+
+
+ {t("schedule_review_empty")}
+
+
+ {t("schedule_review_empty_hint")}
+
+
+ ) : (
+
+ {pendingDeletes.map((del) => (
+
+
+
+
+
+
+ {del.shopCode}
+
+
+
+ {del.displayName}
+
+
+ onRevertDelete(del.truckRowId)}
+ startIcon={}
+ sx={{
+ minWidth: 0,
+ px: 1,
+ py: 0.25,
+ fontSize: "0.65rem",
+ fontWeight: 700,
+ textTransform: "none",
+ flexShrink: 0,
+ }}
+ >
+ {t("schedule_review_revert")}
+
+
+
+
+
+
+ {t("schedule_review_delete_action")}
+
+
+ {del.fromLaneLabel}
+
+
+ {del.location && (
+
+ {del.location}
+
+ )}
+
+
+ ))}
+
+ {modifications.map((mod) => {
+ const hasError = errorTruckRowIds.has(mod.truckRowId);
+ const errorMessage = validationErrorsByTruckRowId.get(mod.truckRowId);
+ return (
+
+
+
+
+ {mod.shopCode}
+
+
+ {mod.displayName}
+
+
+ onRevert(mod.truckRowId, mod.toLaneId)}
+ startIcon={}
+ sx={{
+ minWidth: 0,
+ px: 1,
+ py: 0.25,
+ fontSize: "0.65rem",
+ fontWeight: 700,
+ textTransform: "none",
+ flexShrink: 0,
+ }}
+ >
+ {t("schedule_review_revert")}
+
+
+
+
+ {hasError && errorMessage && (
+
+ {errorMessage}
+
+ )}
+ {mod.isLaneChanged && (
+
+
+ {t("schedule_review_lane_change")}
+
+
+ {mod.fromLaneLabel}
+
+
+
+ {mod.toLaneLabel}
+
+
+ )}
+ {mod.isDistrictChanged && (
+
+
+ {t("schedule_review_district_change")}
+
+
+ {mod.oldDistrictLabel}
+
+
+
+ {mod.newDistrictLabel}
+
+
+ )}
+
+
+ {t("schedule_review_seq")}
+
+ {mod.isSeqChanged ? (
+ <>
+
+ {mod.oldLoadingSequence}
+
+
+
+ {mod.newLoadingSequence}
+
+ >
+ ) : (
+
+ {mod.newLoadingSequence}
+
+ )}
+
+
+
+ );
+ })}
+
+ )}
+
+
+ );
+};
+
+export default memo(ScheduleReviewQueue);
diff --git a/src/components/Shop/ScheduleTaskHistoryModal.tsx b/src/components/Shop/ScheduleTaskHistoryModal.tsx
new file mode 100644
index 0000000..2c5da4a
--- /dev/null
+++ b/src/components/Shop/ScheduleTaskHistoryModal.tsx
@@ -0,0 +1,995 @@
+"use client";
+
+import React, { memo, useCallback, useEffect, useMemo, useState } from "react";
+import {
+ Alert,
+ Box,
+ Button,
+ Chip,
+ CircularProgress,
+ Collapse,
+ Dialog,
+ DialogActions,
+ DialogContent,
+ DialogTitle,
+ IconButton,
+ Stack,
+ Typography,
+} from "@mui/material";
+import {
+ AlertCircle,
+ AlertTriangle,
+ Ban,
+ Calendar,
+ Check,
+ CheckCircle2,
+ ChevronDown,
+ ChevronUp,
+ ClipboardList,
+ Clock,
+ FileText,
+ EyeOff,
+ Play,
+ RotateCcw,
+ X,
+} from "lucide-react";
+import { useTranslation } from "react-i18next";
+import {
+ applyNowTruckLaneScheduleClient,
+ cancelTruckLaneScheduleClient,
+ createTruckLaneScheduleClient,
+ getTruckLaneScheduleClient,
+ ignoreTruckLaneScheduleClient,
+ listTruckLaneSchedulesClient,
+ retryFailedTruckLaneScheduleClient,
+ type TruckLaneScheduleLineResponse,
+ type TruckLaneScheduleResponse,
+} from "@/app/api/shop/client";
+import type { ScheduleLaneOption } from "@/components/Shop/ScheduleChangeModal";
+import { extractApiErrorMessage } from "@/components/Shop/scheduleClientHelpers";
+import { resolveRescheduleExecuteAt, formatScheduleDisplayDateTime } from "@/components/Shop/scheduleExecuteAt";
+import {
+ buildScheduleLineDescription,
+} from "@/components/Shop/scheduleLineDisplay";
+
+type UiFilter = "all" | "pending" | "success" | "failed";
+
+type UiTaskStatus = "pending" | "success" | "failed" | "cancelled" | "ignored";
+
+function uiStatusFromLineCounts(
+ counts: NonNullable,
+): UiTaskStatus | null {
+ const { total, applied, failed, pending } = counts;
+ if (failed > 0) return "failed";
+ if (pending === 0 && applied > 0) return "success";
+ if (pending === 0 && failed > 0 && applied === 0) return "failed";
+ if (applied > 0 || failed > 0) return failed > 0 ? "failed" : "success";
+ if (total > 0 && pending === total) return "pending";
+ return null;
+}
+
+function uiStatusFromLines(
+ lines: TruckLaneScheduleLineResponse[],
+): UiTaskStatus | null {
+ if (lines.length === 0) return null;
+ const failed = lines.filter((l) => l.lineStatus === "FAILED").length;
+ const applied = lines.filter((l) => l.lineStatus === "APPLIED").length;
+ const pending = lines.filter((l) => l.lineStatus === "PENDING").length;
+ if (failed > 0) return "failed";
+ if (pending === 0 && applied > 0) return "success";
+ if (pending > 0 && (applied > 0 || failed > 0)) {
+ return failed > 0 ? "failed" : "pending";
+ }
+ if (pending === lines.length) return "pending";
+ return null;
+}
+
+/** Prefer line outcomes over header status when they disagree (e.g. PARTIAL still stored as PENDING). */
+function resolveUiStatus(
+ task: TruckLaneScheduleResponse,
+ detail?: TruckLaneScheduleResponse | null,
+): UiTaskStatus {
+ const st = String(task.status ?? "").toUpperCase();
+ if (st === "CANCELLED") return "cancelled";
+ if (st === "IGNORED") return "ignored";
+
+ const fromDetailLines = detail?.lines?.length
+ ? uiStatusFromLines(detail.lines)
+ : null;
+ if (fromDetailLines) return fromDetailLines;
+
+ if (task.lineCounts) {
+ const fromCounts = uiStatusFromLineCounts(task.lineCounts);
+ if (fromCounts) return fromCounts;
+ }
+
+ if (st === "APPLIED") return "success";
+ if (st === "FAILED") return "failed";
+ if (st === "PARTIAL") {
+ return (task.lineCounts?.failed ?? 0) > 0 ? "failed" : "success";
+ }
+ if (st === "PENDING" || st === "APPLYING") return "pending";
+ return "pending";
+}
+
+function canManagePendingSchedule(
+ task: TruckLaneScheduleResponse,
+ detail?: TruckLaneScheduleResponse | null,
+): boolean {
+ const st = String(task.status ?? "").toUpperCase();
+ if (st !== "PENDING" && st !== "APPLYING") return false;
+ const lines = detail?.lines ?? [];
+ if (lines.length > 0) {
+ return lines.every((l) => l.lineStatus === "PENDING");
+ }
+ const c = task.lineCounts;
+ if (!c) return true;
+ return c.pending > 0 && c.applied === 0 && c.failed === 0;
+}
+
+function splitExecuteAt(executeAt: string): { date: string; time: string } {
+ const raw = executeAt.trim();
+ if (!raw) return { date: "-", time: "-" };
+ const tIdx = raw.indexOf("T");
+ if (tIdx < 0) return { date: raw, time: "" };
+ return {
+ date: raw.slice(0, tIdx),
+ time: raw.slice(tIdx + 1, tIdx + 6),
+ };
+}
+
+type Props = {
+ open: boolean;
+ onClose: () => void;
+ lanes: ScheduleLaneOption[];
+ onAfterChange?: () => void | Promise;
+};
+
+const ScheduleTaskHistoryModal: React.FC = ({
+ open,
+ onClose,
+ lanes,
+ onAfterChange,
+}) => {
+ const { t } = useTranslation("shop");
+ const [filter, setFilter] = useState("all");
+ const [loading, setLoading] = useState(false);
+ const [tasks, setTasks] = useState([]);
+ const [expandedId, setExpandedId] = useState(null);
+ const [detailById, setDetailById] = useState<
+ Record
+ >({});
+ const [detailLoadingId, setDetailLoadingId] = useState(null);
+ const [actionId, setActionId] = useState(null);
+ const [actionError, setActionError] = useState(null);
+ const [actionNotice, setActionNotice] = useState(null);
+
+ const laneById = useMemo(
+ () => new Map(lanes.map((l) => [l.id, l])),
+ [lanes],
+ );
+
+ const loadTasks = useCallback(async () => {
+ setLoading(true);
+ try {
+ const list = await listTruckLaneSchedulesClient(
+ ["PENDING", "APPLYING", "APPLIED", "PARTIAL", "FAILED", "CANCELLED", "IGNORED"],
+ 200,
+ );
+ const sorted = [...list].sort((a, b) =>
+ String(b.created ?? b.executeAt).localeCompare(
+ String(a.created ?? a.executeAt),
+ ),
+ );
+ setTasks(sorted);
+
+ // Warm detail cache so badges match expanded view (and line-level errors are available).
+ const warmTargets = sorted
+ .filter((task) => {
+ const st = String(task.status ?? "").toUpperCase();
+ if (st === "CANCELLED" || st === "APPLIED" || st === "IGNORED") return false;
+ if (task.lineCounts) return false;
+ return true;
+ })
+ .slice(0, 30);
+ if (warmTargets.length > 0) {
+ const warmed = await Promise.all(
+ warmTargets.map((task) =>
+ getTruckLaneScheduleClient(task.id).catch(() => null),
+ ),
+ );
+ const next: Record = {};
+ for (const d of warmed) {
+ if (d?.id) next[d.id] = d;
+ }
+ if (Object.keys(next).length > 0) {
+ setDetailById((prev) => ({ ...prev, ...next }));
+ }
+ }
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ if (!open) return;
+ setFilter("all");
+ setExpandedId(null);
+ setDetailById({});
+ setActionError(null);
+ setActionNotice(null);
+ void loadTasks();
+ }, [open, loadTasks]);
+
+ const counts = useMemo(() => {
+ let pending = 0;
+ let success = 0;
+ let failed = 0;
+ for (const task of tasks) {
+ const ui = resolveUiStatus(task, detailById[task.id]);
+ if (ui === "pending") pending++;
+ else if (ui === "success") success++;
+ else if (ui === "failed") failed++;
+ }
+ return { pending, success, failed, all: tasks.length };
+ }, [tasks, detailById]);
+
+ const filteredTasks = useMemo(() => {
+ return tasks.filter((task) => {
+ const detail = detailById[task.id];
+ const ui = resolveUiStatus(task, detail);
+ if (filter === "all") return ui !== "cancelled";
+ if (filter === "pending") return ui === "pending";
+ if (filter === "success") return ui === "success";
+ return ui === "failed";
+ });
+ }, [tasks, filter, detailById]);
+
+ const ensureDetail = async (id: number) => {
+ if (detailById[id]) return detailById[id];
+ setDetailLoadingId(id);
+ try {
+ const detail = await getTruckLaneScheduleClient(id);
+ setDetailById((prev) => ({ ...prev, [id]: detail }));
+ return detail;
+ } finally {
+ setDetailLoadingId(null);
+ }
+ };
+
+ const toggleExpand = async (id: number) => {
+ if (expandedId === id) {
+ setExpandedId(null);
+ return;
+ }
+ setExpandedId(id);
+ await ensureDetail(id);
+ };
+
+ const handleCancel = async (id: number) => {
+ setActionId(id);
+ setActionError(null);
+ try {
+ await cancelTruckLaneScheduleClient(id);
+ await onAfterChange?.();
+ await loadTasks();
+ } catch (err: unknown) {
+ setActionError(extractApiErrorMessage(err) ?? t("schedule_err_generic"));
+ } finally {
+ setActionId(null);
+ }
+ };
+
+ const handleApplyNow = async (id: number) => {
+ setActionId(id);
+ setActionError(null);
+ try {
+ await applyNowTruckLaneScheduleClient(id);
+ await onAfterChange?.();
+ await loadTasks();
+ } catch (err: unknown) {
+ setActionError(extractApiErrorMessage(err) ?? t("schedule_err_generic"));
+ } finally {
+ setActionId(null);
+ }
+ };
+
+ const handleReschedule = async (task: TruckLaneScheduleResponse) => {
+ if (String(task.status ?? "").toUpperCase() === "PARTIAL") {
+ setActionError(t("schedule_retry_rejects_partial"));
+ return;
+ }
+ setActionId(task.id);
+ setActionError(null);
+ setActionNotice(null);
+ try {
+ const { executeAt, adjusted } = resolveRescheduleExecuteAt(task.executeAt);
+ try {
+ await retryFailedTruckLaneScheduleClient(task.id, { executeAt });
+ } catch (retryErr: unknown) {
+ let detail = detailById[task.id];
+ if (!detail?.lines?.length) {
+ detail = (await ensureDetail(task.id)) ?? undefined;
+ }
+ const retryLines = (detail?.lines ?? []).filter(
+ (l) => l.lineStatus === "FAILED" || l.lineStatus === "PENDING",
+ );
+ if (retryLines.length === 0) throw retryErr;
+ const lines = retryLines.map((l) => ({
+ action: l.action,
+ truckRowId: l.truckRowId,
+ toTruckLanceCode: l.toTruckLanceCode,
+ toRemark: l.toRemark,
+ toStoreId: l.toStoreId,
+ toLoadingSequence: l.toLoadingSequence ?? 0,
+ toDistrictReference: l.toDistrictReference ?? null,
+ shopCode: l.shopCode,
+ shopName: l.shopName,
+ departureTime: l.departureTime,
+ }));
+ await createTruckLaneScheduleClient({ executeAt, lines });
+ }
+ if (adjusted) {
+ setActionNotice(
+ t("schedule_reschedule_time_adjusted", { at: executeAt }),
+ );
+ }
+ await onAfterChange?.();
+ await loadTasks();
+ } catch (err: unknown) {
+ setActionError(extractApiErrorMessage(err) ?? t("schedule_err_generic"));
+ } finally {
+ setActionId(null);
+ }
+ };
+
+ const handleIgnore = async (id: number) => {
+ setActionId(id);
+ setActionError(null);
+ try {
+ await ignoreTruckLaneScheduleClient(id);
+ await onAfterChange?.();
+ await loadTasks();
+ } catch (err: unknown) {
+ setActionError(extractApiErrorMessage(err) ?? t("schedule_err_generic"));
+ } finally {
+ setActionId(null);
+ }
+ };
+
+ const resolveActionLabel = useCallback(
+ (action: string) => {
+ switch (action) {
+ case "MOVE":
+ return t("schedule_action_move");
+ case "CREATE":
+ return t("schedule_action_create");
+ case "DELETE":
+ return t("schedule_action_delete");
+ case "ENSURE_LANE":
+ return t("schedule_action_ensure_lane");
+ default:
+ return action;
+ }
+ },
+ [t],
+ );
+
+ const resolveActionChipColor = useCallback(
+ (
+ action: string,
+ ): "default" | "primary" | "success" | "warning" | "info" | "error" => {
+ switch (action) {
+ case "MOVE":
+ return "primary";
+ case "CREATE":
+ return "success";
+ case "DELETE":
+ return "warning";
+ case "ENSURE_LANE":
+ return "info";
+ default:
+ return "default";
+ }
+ },
+ [],
+ );
+
+ const statusBadge = (
+ task: TruckLaneScheduleResponse,
+ ui: UiTaskStatus,
+ ) => {
+ if (ui === "pending") {
+ return (
+ }
+ label={t("schedule_history_status_pending")}
+ sx={{
+ fontWeight: 700,
+ bgcolor: "warning.50",
+ color: "warning.dark",
+ border: 1,
+ borderColor: "warning.200",
+ "@keyframes schedulePulse": {
+ "0%, 100%": { opacity: 1 },
+ "50%": { opacity: 0.65 },
+ },
+ animation: "schedulePulse 2s ease-in-out infinite",
+ }}
+ />
+ );
+ }
+ if (ui === "success") {
+ return (
+ }
+ label={t("schedule_history_status_success")}
+ sx={{
+ fontWeight: 700,
+ bgcolor: "success.50",
+ color: "success.dark",
+ border: 1,
+ borderColor: "success.200",
+ }}
+ />
+ );
+ }
+ if (ui === "ignored") {
+ return (
+ }
+ label={t("schedule_history_status_ignored")}
+ sx={{
+ fontWeight: 700,
+ bgcolor: "grey.100",
+ color: "text.secondary",
+ border: 1,
+ borderColor: "grey.300",
+ }}
+ />
+ );
+ }
+ return (
+ }
+ label={t("schedule_history_status_failed")}
+ sx={{
+ fontWeight: 700,
+ bgcolor: "error.50",
+ color: "error.dark",
+ border: 1,
+ borderColor: "error.200",
+ }}
+ />
+ );
+ };
+
+ const filterBtn = (
+ key: UiFilter,
+ label: string,
+ count: number,
+ selectedBg?: string,
+ selectedColor?: string,
+ ) => (
+ setFilter(key)}
+ sx={{
+ textTransform: "none",
+ fontWeight: 700,
+ minWidth: 0,
+ px: 1.75,
+ py: 0.75,
+ borderRadius: 1.5,
+ boxShadow: filter === key ? 1 : 0,
+ ...(filter === key && selectedBg
+ ? { bgcolor: selectedBg, color: selectedColor ?? "white", "&:hover": { bgcolor: selectedBg } }
+ : { color: "text.secondary" }),
+ }}
+ >
+ {label} ({count})
+
+ );
+
+ return (
+
+ );
+};
+
+export default memo(ScheduleTaskHistoryModal);
diff --git a/src/components/Shop/Shop.tsx b/src/components/Shop/Shop.tsx
index 8f7a2e8..a78aac8 100644
--- a/src/components/Shop/Shop.tsx
+++ b/src/components/Shop/Shop.tsx
@@ -41,7 +41,7 @@ type SearchQuery = {
type SearchParamNames = keyof SearchQuery;
const Shop: React.FC = () => {
- const { t } = useTranslation("common");
+ const { t } = useTranslation("shop");
const router = useRouter();
const searchParams = useSearchParams();
const [activeTab, setActiveTab] = useState(0);
@@ -315,9 +315,9 @@ const Shop: React.FC = () => {
borderBottom: '1px solid #e0e0e0'
}}>
- 店鋪路線管理
+ {t("ShopAndTruck")}
router.push("/settings/shop/board")}>
- MTMS 車線看板
+ {t("Route Board")}
diff --git a/src/components/Shop/ShopDetail.tsx b/src/components/Shop/ShopDetail.tsx
index f475193..135902d 100644
--- a/src/components/Shop/ShopDetail.tsx
+++ b/src/components/Shop/ShopDetail.tsx
@@ -100,7 +100,7 @@ const departureTimeToStringForSave = (timeValue: Truck["departureTime"]): string
};
const ShopDetail: React.FC = () => {
- const { t } = useTranslation("common");
+ const { t } = useTranslation("shop");
const router = useRouter();
const searchParams = useSearchParams();
const shopId = searchParams.get("id");
diff --git a/src/components/Shop/TruckLane.tsx b/src/components/Shop/TruckLane.tsx
index 146318f..f6c99d6 100644
--- a/src/components/Shop/TruckLane.tsx
+++ b/src/components/Shop/TruckLane.tsx
@@ -5,14 +5,6 @@ import {
Card,
CardContent,
Typography,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TablePagination,
- TableRow,
- Paper,
Button,
CircularProgress,
Alert,
@@ -30,14 +22,20 @@ import {
} from "@mui/material";
import AddIcon from "@mui/icons-material/Add";
import SaveIcon from "@mui/icons-material/Save";
-import { useState, useMemo } from "react";
+import { useState, useMemo, useCallback } from "react";
import { useRouter } from "next/navigation";
import { useTranslation } from "react-i18next";
import { findAllUniqueTruckLaneCombinationsClient, createTruckWithoutShopClient } from "@/app/api/shop/client";
import type { Truck } from "@/app/api/shop/actions";
import SearchBox, { Criterion } from "../SearchBox";
+import SearchResults, {
+ Column,
+ defaultPagingController,
+} from "../SearchResults/SearchResults";
import { formatDepartureTime, normalizeStoreId } from "@/app/utils/formatUtil";
+type TruckRow = Omit & { id: string | number };
+
type SearchQuery = {
truckLanceCode: string;
departureTime: string;
@@ -47,14 +45,13 @@ type SearchQuery = {
type SearchParamNames = keyof SearchQuery;
const TruckLane: React.FC = () => {
- const { t } = useTranslation("common");
+ const { t } = useTranslation("shop");
const router = useRouter();
const [truckData, setTruckData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [filters, setFilters] = useState>({});
- const [page, setPage] = useState(0);
- const [rowsPerPage, setRowsPerPage] = useState(10);
+ const [pagingController, setPagingController] = useState(defaultPagingController);
const [addDialogOpen, setAddDialogOpen] = useState(false);
const [newTruck, setNewTruck] = useState({
truckLanceCode: "",
@@ -93,11 +90,80 @@ const TruckLane: React.FC = () => {
});
}, [truckData, filters]);
- // Paginated rows
- const paginatedRows = useMemo(() => {
- const startIndex = page * rowsPerPage;
- return filteredRows.slice(startIndex, startIndex + rowsPerPage);
- }, [filteredRows, page, rowsPerPage]);
+ const tableRows = useMemo(
+ () =>
+ filteredRows.map((truck) => ({
+ ...truck,
+ id: truck.id ?? (String(truck.truckLanceCode ?? "").trim() || `truck-${truck.truckLanceCode}`),
+ })),
+ [filteredRows],
+ );
+
+ const handleViewDetail = useCallback(
+ (truck: TruckRow) => {
+ const truckLanceCode = String(truck.truckLanceCode || "").trim();
+ if (truckLanceCode) {
+ const url = new URL(`/settings/shop/truckdetail`, window.location.origin);
+ url.searchParams.set("truckLanceCode", truckLanceCode);
+ router.push(url.pathname + url.search);
+ }
+ },
+ [router],
+ );
+
+ const columns = useMemo[]>(
+ () => [
+ {
+ name: "truckLanceCode",
+ label: t("TruckLance Code"),
+ sx: { width: "250px", minWidth: "250px", maxWidth: "250px" },
+ renderCell: (item) => String(item.truckLanceCode ?? "-"),
+ },
+ {
+ name: "departureTime",
+ label: t("Departure Time"),
+ sx: { width: "200px", minWidth: "200px", maxWidth: "200px" },
+ renderCell: (item) =>
+ formatDepartureTime(
+ Array.isArray(item.departureTime)
+ ? item.departureTime
+ : item.departureTime
+ ? String(item.departureTime)
+ : null,
+ ),
+ },
+ {
+ name: "storeId",
+ label: t("Store ID"),
+ sx: { width: "150px", minWidth: "150px", maxWidth: "150px" },
+ renderCell: (item) =>
+ normalizeStoreId(
+ item.storeId
+ ? typeof item.storeId === "string" || item.storeId instanceof String
+ ? String(item.storeId)
+ : String(item.storeId)
+ : null,
+ ),
+ },
+ {
+ name: "id",
+ label: t("Actions"),
+ align: "right",
+ headerAlign: "right",
+ sx: { width: "150px", minWidth: "150px", maxWidth: "150px" },
+ renderCell: (item) => (
+ handleViewDetail(item)}
+ >
+ {t("View Detail")}
+
+ ),
+ },
+ ],
+ [handleViewDetail, t],
+ );
const handleSearch = async (inputs: Record) => {
setLoading(true);
@@ -113,7 +179,7 @@ const TruckLane: React.FC = () => {
});
setTruckData(Array.from(uniqueCodes.values()));
setFilters(inputs);
- setPage(0);
+ setPagingController(defaultPagingController);
} catch (err: any) {
console.error("Failed to load truck lanes:", err);
setError(err?.message ?? String(err) ?? t("Failed to load truck lanes"));
@@ -122,26 +188,6 @@ const TruckLane: React.FC = () => {
}
};
- const handlePageChange = (event: unknown, newPage: number) => {
- setPage(newPage);
- };
-
- const handleRowsPerPageChange = (event: React.ChangeEvent) => {
- setRowsPerPage(parseInt(event.target.value, 10));
- setPage(0); // Reset to first page when changing rows per page
- };
-
- const handleViewDetail = (truck: Truck) => {
- // Navigate to truck lane detail page using truckLanceCode
- const truckLanceCode = String(truck.truckLanceCode || "").trim();
- if (truckLanceCode) {
- // Use router.push with proper URL encoding
- const url = new URL(`/settings/shop/truckdetail`, window.location.origin);
- url.searchParams.set("truckLanceCode", truckLanceCode);
- router.push(url.pathname + url.search);
- }
- };
-
const handleOpenAddDialog = () => {
setNewTruck({
truckLanceCode: "",
@@ -270,77 +316,12 @@ const TruckLane: React.FC = () => {
) : (
-
-
-
-
-
- {t("TruckLance Code")}
-
-
- {t("Departure Time")}
-
-
- {t("Store ID")}
-
-
- {t("Actions")}
-
-
-
-
- {paginatedRows.length === 0 ? (
-
-
-
- {t("No Truck Lane data available")}
-
-
-
- ) : (
- paginatedRows.map((truck) => (
-
-
- {String(truck.truckLanceCode ?? "-")}
-
-
- {formatDepartureTime(
- Array.isArray(truck.departureTime)
- ? truck.departureTime
- : (truck.departureTime ? String(truck.departureTime) : null)
- )}
-
-
- {normalizeStoreId(
- truck.storeId ? (typeof truck.storeId === 'string' || truck.storeId instanceof String
- ? String(truck.storeId)
- : String(truck.storeId)) : null
- )}
-
-
- handleViewDetail(truck)}
- >
- {t("View Detail")}
-
-
-
- ))
- )}
-
-
-
-
)}
diff --git a/src/components/Shop/TruckLaneDetail.tsx b/src/components/Shop/TruckLaneDetail.tsx
index 5874f2a..9f617eb 100644
--- a/src/components/Shop/TruckLaneDetail.tsx
+++ b/src/components/Shop/TruckLaneDetail.tsx
@@ -71,7 +71,7 @@ const truckDepartureTimeToInputValue = (timeValue: Truck["departureTime"]): stri
};
const TruckLaneDetail: React.FC = () => {
- const { t } = useTranslation("common");
+ const { t } = useTranslation("shop");
const router = useRouter();
const searchParams = useSearchParams();
const truckLanceCodeParam = searchParams.get("truckLanceCode");
diff --git a/src/components/Shop/routeBoardDisplayOrder.ts b/src/components/Shop/routeBoardDisplayOrder.ts
new file mode 100644
index 0000000..891f6d2
--- /dev/null
+++ b/src/components/Shop/routeBoardDisplayOrder.ts
@@ -0,0 +1,158 @@
+import { normalizeStoreId } from "@/app/utils/formatUtil";
+
+/** Shared display-order helpers for RouteBoard and schedule drag workspace. */
+
+export type DisplayOrderShop = {
+ id: number;
+ districtReferenceRaw?: string | null;
+ loadingSequence?: number | null;
+};
+
+export function toDistrictDisplayName(
+ district: string | null | undefined,
+): string {
+ const value = String(district ?? "").trim();
+ return value === "" ? "未分類" : value;
+}
+
+export function toDistrictRawValue(
+ district: string | null | undefined,
+): string | null {
+ const value = String(district ?? "").trim();
+ return value === "" || value === "未分類" ? null : value;
+}
+
+/** Shop card subtitle on RouteBoard (branch · code · store; district is in section header). */
+export function formatShopCardSubtitle(shop: {
+ branchName?: string | null;
+ shopCode: string;
+ storeId?: string | null;
+}): string {
+ const parts: string[] = [];
+ const branch = String(shop.branchName ?? "").trim();
+ if (branch !== "") parts.push(branch);
+ parts.push(String(shop.shopCode || "").trim() || "-");
+ const store = normalizeStoreId(shop.storeId);
+ if (store !== "" && store !== "-") parts.push(store);
+ return parts.join(" · ");
+}
+
+/** Subtitle for schedule review queue; always reflects current districtReferenceRaw. */
+export function formatPlannedShopLocation(shop: {
+ districtReferenceRaw: string | null;
+ shopCode: string;
+ storeId?: string | null;
+}): string {
+ const district = toDistrictDisplayName(shop.districtReferenceRaw);
+ const parts = [district, String(shop.shopCode || "").trim() || "-"];
+ const store = normalizeStoreId(shop.storeId);
+ if (store !== "" && store !== "-") parts.push(store);
+ return parts.join(" · ");
+}
+
+export function dedupeDistrictPendingOrder(items: string[]): string[] {
+ const seen = new Set();
+ const out: string[] = [];
+ for (const x of items) {
+ if (seen.has(x)) continue;
+ seen.add(x);
+ out.push(x);
+ }
+ return out;
+}
+
+export function districtDisplayExistsInShops(
+ shops: T[],
+ pendingExtra: string[] | undefined,
+ display: string,
+): boolean {
+ const set = new Set(groupByDistrict(shops).map((g) => g.district));
+ for (const d of pendingExtra ?? []) set.add(d);
+ return set.has(display);
+}
+
+export function buildLaneDistrictSections(
+ shops: T[],
+ pendingExtraDistrictDisplays: string[] | undefined,
+): Array<{ district: string; shops: T[]; isPendingEmpty: boolean }> {
+ const grouped = groupByDistrict(shops);
+ const keysFromShops = new Set(grouped.map((g) => g.district));
+ const extras = (pendingExtraDistrictDisplays ?? []).filter(
+ (d) => !keysFromShops.has(d),
+ );
+ const merged = [
+ ...grouped.map((g) => ({
+ district: g.district,
+ shops: g.shops,
+ isPendingEmpty: false,
+ })),
+ ...extras.map((district) => ({
+ district,
+ shops: [] as T[],
+ isPendingEmpty: true,
+ })),
+ ];
+ merged.sort((a, b) => {
+ if (a.district === "未分類") return -1;
+ if (b.district === "未分類") return 1;
+ return a.district.localeCompare(b.district, "zh-Hant");
+ });
+ return merged;
+}
+
+export function groupByDistrict(
+ shops: T[],
+): Array<{ district: string; shops: T[] }> {
+ const map = new Map();
+ for (const s of shops) {
+ const key = toDistrictDisplayName(s.districtReferenceRaw);
+ const arr = map.get(key) ?? [];
+ arr.push(s);
+ map.set(key, arr);
+ }
+ return Array.from(map.entries())
+ .sort(([a], [b]) => {
+ if (a === "未分類") return -1;
+ if (b === "未分類") return 1;
+ return a.localeCompare(b, "zh-Hant");
+ })
+ .map(([district, list]) => ({
+ district,
+ shops: list
+ .slice()
+ .sort(
+ (x, y) => (x.loadingSequence ?? 0) - (y.loadingSequence ?? 0),
+ ),
+ }));
+}
+
+export function flattenDisplayOrder(
+ shops: T[],
+): T[] {
+ return groupByDistrict(shops).flatMap((g) => g.shops);
+}
+
+export function computeMovedLoadingSequence(
+ inserted: T[],
+ movedId: number,
+ preferPrevious = false,
+): number {
+ const idx = inserted.findIndex((s) => s.id === movedId);
+ if (idx < 0) return 0;
+ if (preferPrevious) {
+ const prev = inserted[idx - 1];
+ if (prev && typeof prev.loadingSequence === "number")
+ return prev.loadingSequence;
+ }
+ const next = inserted[idx + 1];
+ if (next && typeof next.loadingSequence === "number")
+ return next.loadingSequence;
+ const prev = inserted[idx - 1];
+ if (prev && typeof prev.loadingSequence === "number")
+ return prev.loadingSequence;
+ const max = inserted.reduce(
+ (m, s) => Math.max(m, Number(s.loadingSequence ?? 0) || 0),
+ 0,
+ );
+ return max;
+}
diff --git a/src/components/Shop/routeBoardVersionLog.ts b/src/components/Shop/routeBoardVersionLog.ts
index 05efb07..8482ad8 100644
--- a/src/components/Shop/routeBoardVersionLog.ts
+++ b/src/components/Shop/routeBoardVersionLog.ts
@@ -27,18 +27,45 @@ function pickField(
return changes.find((c) => c.field === field);
}
-export const VERSION_LOG_LOADING_SEQUENCE_LABEL = "裝載順序";
+function isBlankDiffValue(raw: string | null | undefined): boolean {
+ return raw == null || String(raw).trim() === "";
+}
+
+/** 新版本已無此列:車線/店碼等由有值變空(勿用 line 上的 ctx fallback 當 to 車線) */
+function isRowRemovedInDiff(ch: DiffFieldChange[]): boolean {
+ const lane = pickField(ch, "truckLanceCode");
+ const code = pickField(ch, "shopCode");
+ if (!lane && !code) return false;
+ const laneOk =
+ !lane || (!isBlankDiffValue(lane.from) && isBlankDiffValue(lane.to));
+ const codeOk =
+ !code || (!isBlankDiffValue(code.from) && isBlankDiffValue(code.to));
+ return laneOk && codeOk;
+}
+
+function isRowInsertedInDiff(ch: DiffFieldChange[]): boolean {
+ const lane = pickField(ch, "truckLanceCode");
+ const code = pickField(ch, "shopCode");
+ if (!lane && !code) return false;
+ const laneOk =
+ !lane || (isBlankDiffValue(lane.from) && !isBlankDiffValue(lane.to));
+ const codeOk =
+ !code || (isBlankDiffValue(code.from) && !isBlankDiffValue(code.to));
+ return laneOk && codeOk;
+}
+
+export const VERSION_LOG_LOADING_SEQUENCE_LABEL = "versionLogField_loadingSequence";
const VERSION_LOG_FIELD_LABEL: Record = {
- departureTime: "發車時段",
+ departureTime: "versionLogField_departureTime",
loadingSequence: VERSION_LOG_LOADING_SEQUENCE_LABEL,
- branchName: "分店名稱",
- districtReference: "區域",
- shopCode: "店鋪代碼",
- storeId: "樓層/店別",
- remark: "備註",
- truckLanceCode: "車線代碼",
- logisticId: "物流公司",
+ branchName: "versionLogField_branchName",
+ districtReference: "versionLogField_districtReference",
+ shopCode: "versionLogField_shopCode",
+ storeId: "versionLogField_storeId",
+ remark: "versionLogField_remark",
+ truckLanceCode: "versionLogField_truckLanceCode",
+ logisticId: "versionLogField_logisticId",
};
/** 版本 LOG 用:時段顯示為 HH:mm,避免 ISO / 帶秒過長 */
@@ -118,6 +145,13 @@ export function formatLaneLabel(
return `${c} · ${r}`;
}
+export function resolveVersionActor(version: {
+ modifiedBy?: string | null;
+ createdBy?: string | null;
+}): string {
+ return String(version.modifiedBy ?? version.createdBy ?? "").trim();
+}
+
export function splitVersionCreated(created: string | null | undefined): {
date: string;
time: string;
@@ -164,15 +198,17 @@ export function diffLineToShopRow(
const fromLane = formatLaneLabel(tc?.from ?? ctxCode, rem?.from ?? ctxRem);
const toLane = formatLaneLabel(tc?.to ?? ctxCode, rem?.to ?? ctxRem);
- const fromEmpty = fromLane === "—";
- const toEmpty = toLane === "—";
+ const toLaneStrict = formatLaneLabel(tc?.to, rem?.to);
let type: VersionLogShopRow["type"];
- if (fromEmpty && !toEmpty) type = "added";
- else if (!fromEmpty && toEmpty) type = "deleted";
+ if (isRowInsertedInDiff(ch)) type = "added";
+ else if (isRowRemovedInDiff(ch)) type = "deleted";
else if (fromLane !== toLane) type = "moved";
else type = "edited";
+ const fromEmpty = fromLane === "—";
+ const toEmpty = type === "deleted" ? true : toLaneStrict === "—";
+
return {
type,
shopName,
@@ -638,7 +674,7 @@ export function buildStagedBoardLogEntries(input: {
}
/**
- * 異動列標題:優先用 shop 主檔名稱,其次快照 branchName(與代碼不同時),最後才代碼。
+ * 異動列標題:優先用 shop 主檔名稱,其次版本 branchName(與代碼不同時),最後才代碼。
*/
export function resolveVersionLogShopHeadline(
row: VersionLogShopRow,
@@ -659,7 +695,7 @@ export function resolveVersionLogShopHeadline(
const bits: string[] = [];
if (!snapIsEmpty && !snapIsJustCode && snap !== master)
- bits.push(`快照分店:${snap}`);
+ bits.push(`分店:${snap}`);
const detail = bits.length > 0 ? bits.join(" · ") : undefined;
return { headline, detail };
diff --git a/src/components/Shop/scheduleApiAdapter.ts b/src/components/Shop/scheduleApiAdapter.ts
new file mode 100644
index 0000000..01a69e9
--- /dev/null
+++ b/src/components/Shop/scheduleApiAdapter.ts
@@ -0,0 +1,215 @@
+import type {
+ CreateTruckLaneScheduleRequest,
+ TruckLaneMoveTargetRequest,
+ TruckLaneScheduleLineRequest,
+} from "@/app/api/shop/actions";
+import { movesToScheduleLines } from "@/components/Shop/scheduleLineAdapter";
+import { normalizeStoreId } from "@/app/utils/formatUtil";
+import type {
+ ScheduleLaneOption,
+ ScheduleMoveSelection,
+} from "@/components/Shop/ScheduleChangeModal";
+import type {
+ ScheduleModification,
+ ScheduleDragWorkspaceState,
+ ScheduledDeleteSnapshot,
+} from "@/components/Shop/scheduleDragWorkspace";
+
+export function buildScheduleMoveFromSelection(
+ truckRowId: number,
+ selection: ScheduleMoveSelection,
+ lane: ScheduleLaneOption,
+ toDistrictReference?: string | null,
+): TruckLaneMoveTargetRequest {
+ return {
+ truckRowId,
+ toTruckLanceCode: lane.truckLanceCode,
+ toRemark:
+ lane.remark != null && String(lane.remark).trim() !== ""
+ ? String(lane.remark).trim()
+ : null,
+ toStoreId: normalizeStoreId(lane.storeId),
+ toLoadingSequence: selection.toLoadingSequence,
+ toDistrictReference: toDistrictReference ?? null,
+ };
+}
+
+export function buildDeleteScheduleLine(
+ truckRowId: number,
+ lane: ScheduleLaneOption,
+ shopCode: string,
+ shopName: string,
+): TruckLaneScheduleLineRequest {
+ return {
+ action: "DELETE",
+ truckRowId,
+ toTruckLanceCode: lane.truckLanceCode,
+ toRemark:
+ lane.remark != null && String(lane.remark).trim() !== ""
+ ? String(lane.remark).trim()
+ : null,
+ toStoreId: normalizeStoreId(lane.storeId),
+ shopCode,
+ shopName,
+ };
+}
+
+function districtByTruckRowIdFromPlanned(
+ plannedLanes?: ScheduleDragWorkspaceState,
+): Map {
+ const map = new Map();
+ if (!plannedLanes) return map;
+ for (const lane of plannedLanes) {
+ for (const shop of lane.shops) {
+ map.set(shop.truckRowId, shop.districtReferenceRaw);
+ }
+ }
+ return map;
+}
+
+export function buildScheduleMovesFromMappings(
+ mappings: Record,
+ lanes: ScheduleLaneOption[],
+ plannedLanes?: ScheduleDragWorkspaceState,
+): TruckLaneMoveTargetRequest[] {
+ const laneById = new Map(lanes.map((l) => [l.id, l]));
+ const districtByTruckRowId = districtByTruckRowIdFromPlanned(plannedLanes);
+ const out: TruckLaneMoveTargetRequest[] = [];
+ for (const [id, sel] of Object.entries(mappings)) {
+ const truckRowId = Number(id);
+ const lane = laneById.get(sel.laneId);
+ if (!lane || !Number.isFinite(truckRowId)) continue;
+ const seq = sel.toLoadingSequence;
+ if (!Number.isFinite(seq) || seq < 0) continue;
+ out.push(
+ buildScheduleMoveFromSelection(
+ truckRowId,
+ sel,
+ lane,
+ districtByTruckRowId.get(truckRowId),
+ ),
+ );
+ }
+ return out;
+}
+
+export function buildScheduleLinesFromPlan(input: {
+ modifications: ScheduleModification[];
+ pendingDeletes: ScheduledDeleteSnapshot[];
+ lanes: ScheduleLaneOption[];
+ plannedLanes?: ScheduleDragWorkspaceState;
+}): TruckLaneScheduleLineRequest[] {
+ const laneById = new Map(input.lanes.map((l) => [l.id, l]));
+ const deleteIds = new Set(input.pendingDeletes.map((d) => d.truckRowId));
+ const mappings = Object.fromEntries(
+ input.modifications
+ .filter((m) => !deleteIds.has(m.truckRowId))
+ .map((m) => [
+ m.truckRowId,
+ { laneId: m.toLaneId, toLoadingSequence: m.newLoadingSequence },
+ ]),
+ );
+ const moveLines = movesToScheduleLines(
+ buildScheduleMovesFromMappings(
+ mappings,
+ input.lanes,
+ input.plannedLanes,
+ ),
+ );
+ const deleteLines = input.pendingDeletes
+ .map((d) => {
+ const lane = laneById.get(d.fromLaneId);
+ if (!lane) return null;
+ return buildDeleteScheduleLine(
+ d.truckRowId,
+ lane,
+ d.shopCode,
+ d.displayName,
+ );
+ })
+ .filter((line): line is TruckLaneScheduleLineRequest => line != null);
+ return [...moveLines, ...deleteLines];
+}
+
+export function buildScheduleMovesFromModifications(
+ modifications: ScheduleModification[],
+ lanes: ScheduleLaneOption[],
+ plannedLanes?: ScheduleDragWorkspaceState,
+ pendingDeletes: ScheduledDeleteSnapshot[] = [],
+): TruckLaneMoveTargetRequest[] {
+ const deleteIds = new Set(pendingDeletes.map((d) => d.truckRowId));
+ const mappings = Object.fromEntries(
+ modifications
+ .filter((m) => !deleteIds.has(m.truckRowId))
+ .map((m) => [
+ m.truckRowId,
+ { laneId: m.toLaneId, toLoadingSequence: m.newLoadingSequence },
+ ]),
+ );
+ return buildScheduleMovesFromMappings(mappings, lanes, plannedLanes);
+}
+
+export function buildCreateScheduleRequest(input: {
+ executeAt: string;
+ note?: string | null;
+ mappings: Record;
+ lanes: ScheduleLaneOption[];
+ plannedLanes?: ScheduleDragWorkspaceState;
+ pendingDeletes?: ScheduledDeleteSnapshot[];
+ modifications?: ScheduleModification[];
+}): CreateTruckLaneScheduleRequest {
+ if (input.modifications != null) {
+ return {
+ executeAt: input.executeAt,
+ note: input.note ?? null,
+ lines: buildScheduleLinesFromPlan({
+ modifications: input.modifications,
+ pendingDeletes: input.pendingDeletes ?? [],
+ lanes: input.lanes,
+ plannedLanes: input.plannedLanes,
+ }),
+ };
+ }
+ const moves = buildScheduleMovesFromMappings(
+ input.mappings,
+ input.lanes,
+ input.plannedLanes,
+ );
+ const deleteLines = (input.pendingDeletes ?? [])
+ .map((d) => {
+ const lane = input.lanes.find((l) => l.id === d.fromLaneId);
+ if (!lane) return null;
+ return buildDeleteScheduleLine(
+ d.truckRowId,
+ lane,
+ d.shopCode,
+ d.displayName,
+ );
+ })
+ .filter((line): line is TruckLaneScheduleLineRequest => line != null);
+ return {
+ executeAt: input.executeAt,
+ note: input.note ?? null,
+ lines: [...movesToScheduleLines(moves), ...deleteLines],
+ };
+}
+
+export function buildCreateScheduleRequestFromModifications(input: {
+ executeAt: string;
+ note?: string | null;
+ modifications: ScheduleModification[];
+ lanes: ScheduleLaneOption[];
+ plannedLanes?: ScheduleDragWorkspaceState;
+ pendingDeletes?: ScheduledDeleteSnapshot[];
+}): CreateTruckLaneScheduleRequest {
+ return {
+ executeAt: input.executeAt,
+ note: input.note ?? null,
+ lines: buildScheduleLinesFromPlan({
+ modifications: input.modifications,
+ pendingDeletes: input.pendingDeletes ?? [],
+ lanes: input.lanes,
+ plannedLanes: input.plannedLanes,
+ }),
+ };
+}
diff --git a/src/components/Shop/scheduleClientHelpers.ts b/src/components/Shop/scheduleClientHelpers.ts
new file mode 100644
index 0000000..8fd1321
--- /dev/null
+++ b/src/components/Shop/scheduleClientHelpers.ts
@@ -0,0 +1,57 @@
+import type { TruckLaneScheduleResponse } from "@/app/api/shop/actions";
+
+const DEFAULT_LIST_LIMIT = 200;
+
+export function buildTruckLaneScheduleListQuery(
+ status?: string[],
+ limit: number = DEFAULT_LIST_LIMIT,
+): string {
+ const params = new URLSearchParams();
+ for (const s of status ?? []) {
+ params.append("status", s);
+ }
+ params.set("limit", String(limit));
+ const qs = params.toString();
+ return qs ? `?${qs}` : "";
+}
+
+export function collectFailedTruckRowIdsFromSchedules(
+ schedules: TruckLaneScheduleResponse[],
+ lineDetails: Array,
+): Set {
+ const out = new Set();
+ for (const detail of lineDetails) {
+ for (const line of detail?.lines ?? []) {
+ if (line.lineStatus === "FAILED" && line.truckRowId != null && line.truckRowId > 0) {
+ out.add(line.truckRowId);
+ }
+ }
+ }
+ for (const schedule of schedules) {
+ if (
+ schedule.status === "FAILED" &&
+ (schedule.lineCounts?.failed ?? 0) > 0 &&
+ !lineDetails.some((d) => d?.id === schedule.id)
+ ) {
+ // header-only failure without warmed lines — no shop ids available
+ }
+ }
+ return out;
+}
+
+export function filterFailedSchedules(
+ schedules: TruckLaneScheduleResponse[],
+): TruckLaneScheduleResponse[] {
+ return schedules.filter(
+ (s) =>
+ s.status !== "IGNORED" &&
+ (s.status === "FAILED" ||
+ (s.status === "PARTIAL" && (s.lineCounts?.failed ?? 0) > 0)),
+ );
+}
+
+export function extractApiErrorMessage(err: unknown): string | null {
+ if (err instanceof Error && err.message.trim()) return err.message.trim();
+ if (typeof err === "string" && err.trim()) return err.trim();
+ return null;
+}
diff --git a/src/components/Shop/scheduleDragWorkspace.ts b/src/components/Shop/scheduleDragWorkspace.ts
new file mode 100644
index 0000000..1f09a59
--- /dev/null
+++ b/src/components/Shop/scheduleDragWorkspace.ts
@@ -0,0 +1,381 @@
+import type {
+ ScheduleLaneOption,
+ ScheduleMoveSelection,
+ ScheduleShopRow,
+} from "@/components/Shop/ScheduleChangeModal";
+import {
+ computeMovedLoadingSequence,
+ flattenDisplayOrder,
+ formatPlannedShopLocation,
+ toDistrictDisplayName,
+ toDistrictRawValue,
+} from "@/components/Shop/routeBoardDisplayOrder";
+
+export type PlannedShop = {
+ id: number;
+ truckRowId: number;
+ shopCode: string;
+ displayName: string;
+ branchName: string;
+ storeId: string;
+ districtReferenceRaw: string | null;
+ loadingSequence: number;
+ originalLaneId: string;
+ originalLoadingSequence: number;
+ originalDistrictReferenceRaw: string | null;
+};
+
+export type PlannedLane = {
+ id: string;
+ label: string;
+ truckLanceCode: string;
+ remark?: string | null;
+ storeId: string;
+ shops: PlannedShop[];
+};
+
+export type ScheduleDragWorkspaceState = PlannedLane[];
+
+export type ScheduleModification = {
+ truckRowId: number;
+ shopCode: string;
+ displayName: string;
+ location: string;
+ fromLaneId: string;
+ fromLaneLabel: string;
+ toLaneId: string;
+ toLaneLabel: string;
+ oldLoadingSequence: number;
+ newLoadingSequence: number;
+ isLaneChanged: boolean;
+ isSeqChanged: boolean;
+ isDistrictChanged: boolean;
+ oldDistrictLabel: string;
+ newDistrictLabel: string;
+};
+
+export type ScheduledDeleteSnapshot = {
+ truckRowId: number;
+ shopCode: string;
+ displayName: string;
+ location: string;
+ fromLaneId: string;
+ fromLaneLabel: string;
+ shop: PlannedShop;
+};
+
+type MoveShopArgs = {
+ shopId: number;
+ fromLaneId: string;
+ toLaneId: string;
+ beforeShopId?: number | null;
+ targetDistrict?: string | null;
+};
+
+function laneHasShopCode(lane: PlannedLane, shopCode: string, excludeId: number): boolean {
+ return lane.shops.some(
+ (s) => s.truckRowId !== excludeId && s.shopCode === shopCode,
+ );
+}
+
+export function initPlannedLanes(
+ lanes: ScheduleLaneOption[],
+ shops: ScheduleShopRow[],
+): ScheduleDragWorkspaceState {
+ const shopRowById = new Map(shops.map((s) => [s.truckRowId, s]));
+
+ return lanes.map((lane) => {
+ const plannedShops: PlannedShop[] = lane.shops
+ .map((snap) => {
+ const row = shopRowById.get(snap.truckRowId);
+ if (!row) return null;
+ const seq = snap.loadingSequence ?? 0;
+ return {
+ id: row.truckRowId,
+ truckRowId: row.truckRowId,
+ shopCode: row.shopCode,
+ displayName: row.displayName,
+ branchName: row.branchName,
+ storeId: row.storeId,
+ districtReferenceRaw: row.districtReferenceRaw,
+ loadingSequence: seq,
+ originalLaneId: row.currentLaneId,
+ originalLoadingSequence: seq,
+ originalDistrictReferenceRaw: row.districtReferenceRaw,
+ } satisfies PlannedShop;
+ })
+ .filter((s): s is PlannedShop => s != null);
+
+ return {
+ id: lane.id,
+ label: lane.label,
+ truckLanceCode: lane.truckLanceCode,
+ remark: lane.remark,
+ storeId: lane.storeId,
+ shops: plannedShops,
+ };
+ });
+}
+
+export function moveShop(
+ state: ScheduleDragWorkspaceState,
+ args: MoveShopArgs,
+): ScheduleDragWorkspaceState {
+ const { shopId, fromLaneId, toLaneId, beforeShopId = null, targetDistrict } =
+ args;
+
+ if (beforeShopId != null && beforeShopId === shopId) {
+ return state;
+ }
+
+ const next = state.map((lane) => ({ ...lane, shops: lane.shops.slice() }));
+ const from = next.find((l) => l.id === fromLaneId);
+ const to = next.find((l) => l.id === toLaneId);
+ if (!from || !to) return state;
+
+ const shop = from.shops.find((s) => s.truckRowId === shopId);
+ if (!shop) return state;
+
+ if (from.id !== to.id && laneHasShopCode(to, shop.shopCode, shop.truckRowId)) {
+ return state;
+ }
+
+ const fromFlat = flattenDisplayOrder(
+ from.shops.filter((s) => s.truckRowId !== shopId),
+ );
+ const toFlatRaw = flattenDisplayOrder(to.shops);
+ const toFlat =
+ from.id === to.id
+ ? toFlatRaw.filter((s) => s.truckRowId !== shopId)
+ : toFlatRaw.slice();
+
+ const beforeShop =
+ beforeShopId != null
+ ? toFlat.find((s) => s.truckRowId === beforeShopId)
+ : null;
+ const isCrossLane = from.id !== to.id;
+ const targetDistrictRaw =
+ targetDistrict !== undefined
+ ? toDistrictRawValue(targetDistrict)
+ : isCrossLane
+ ? shop.districtReferenceRaw
+ : beforeShop
+ ? toDistrictRawValue(beforeShop.districtReferenceRaw)
+ : shop.districtReferenceRaw;
+
+ const moved: PlannedShop = {
+ ...shop,
+ districtReferenceRaw: targetDistrictRaw,
+ };
+
+ const insertIdx =
+ beforeShopId != null
+ ? toFlat.findIndex((s) => s.truckRowId === beforeShopId)
+ : targetDistrict !== undefined
+ ? (() => {
+ const targetDisplay = toDistrictDisplayName(targetDistrictRaw);
+ for (let i = toFlat.length - 1; i >= 0; i -= 1) {
+ if (
+ toDistrictDisplayName(toFlat[i].districtReferenceRaw) ===
+ targetDisplay
+ ) {
+ return i + 1;
+ }
+ }
+ return -1;
+ })()
+ : -1;
+
+ const inserted =
+ insertIdx >= 0
+ ? [...toFlat.slice(0, insertIdx), moved, ...toFlat.slice(insertIdx)]
+ : [...toFlat, moved];
+
+ const newSeq = computeMovedLoadingSequence(
+ inserted,
+ moved.truckRowId,
+ targetDistrict !== undefined && beforeShopId == null,
+ );
+
+ from.shops = fromFlat;
+ to.shops = inserted.map((s) =>
+ s.truckRowId === moved.truckRowId ? { ...s, loadingSequence: newSeq } : s,
+ );
+
+ return next;
+}
+
+export function setShopLoadingSequence(
+ state: ScheduleDragWorkspaceState,
+ laneId: string,
+ shopId: number,
+ loadingSequence: number,
+): ScheduleDragWorkspaceState {
+ const seq = Math.max(0, Math.trunc(loadingSequence));
+ const lane = state.find((l) => l.id === laneId);
+ const shop = lane?.shops.find((s) => s.truckRowId === shopId);
+ if (!shop || shop.loadingSequence === seq) return state;
+
+ return state.map((l) =>
+ l.id !== laneId
+ ? l
+ : {
+ ...l,
+ shops: l.shops.map((s) =>
+ s.truckRowId === shopId ? { ...s, loadingSequence: seq } : s,
+ ),
+ },
+ );
+}
+
+export function revertShop(
+ state: ScheduleDragWorkspaceState,
+ shopId: number,
+ currentLaneId: string,
+): ScheduleDragWorkspaceState {
+ const currentLane = state.find((l) => l.id === currentLaneId);
+ const shop = currentLane?.shops.find((s) => s.truckRowId === shopId);
+ if (!shop) return state;
+
+ let next = moveShop(state, {
+ shopId,
+ fromLaneId: currentLaneId,
+ toLaneId: shop.originalLaneId,
+ beforeShopId: null,
+ });
+
+ next = next.map((lane) => {
+ if (lane.id !== shop.originalLaneId) return lane;
+ return {
+ ...lane,
+ shops: lane.shops.map((s) =>
+ s.truckRowId === shopId
+ ? {
+ ...s,
+ loadingSequence: shop.originalLoadingSequence,
+ districtReferenceRaw: shop.originalDistrictReferenceRaw,
+ }
+ : s,
+ ),
+ };
+ });
+
+ return next;
+}
+
+export function findShopLaneId(
+ state: ScheduleDragWorkspaceState,
+ shopId: number,
+): string | null {
+ for (const lane of state) {
+ if (lane.shops.some((s) => s.truckRowId === shopId)) return lane.id;
+ }
+ return null;
+}
+
+export function removeShopFromPlan(
+ state: ScheduleDragWorkspaceState,
+ truckRowId: number,
+): {
+ next: ScheduleDragWorkspaceState;
+ removed: PlannedShop | null;
+ laneId: string | null;
+} {
+ for (const lane of state) {
+ const shop = lane.shops.find((s) => s.truckRowId === truckRowId);
+ if (!shop) continue;
+ return {
+ next: state.map((l) =>
+ l.id === lane.id
+ ? { ...l, shops: l.shops.filter((s) => s.truckRowId !== truckRowId) }
+ : l,
+ ),
+ removed: shop,
+ laneId: lane.id,
+ };
+ }
+ return { next: state, removed: null, laneId: null };
+}
+
+export function restoreDeletedShop(
+ state: ScheduleDragWorkspaceState,
+ snapshot: ScheduledDeleteSnapshot,
+): ScheduleDragWorkspaceState {
+ const lane = state.find((l) => l.id === snapshot.fromLaneId);
+ if (!lane) return state;
+ if (lane.shops.some((s) => s.truckRowId === snapshot.truckRowId)) return state;
+
+ const shop: PlannedShop = {
+ ...snapshot.shop,
+ loadingSequence: snapshot.shop.originalLoadingSequence,
+ districtReferenceRaw: snapshot.shop.originalDistrictReferenceRaw,
+ };
+
+ return state.map((l) =>
+ l.id === snapshot.fromLaneId ? { ...l, shops: [...l.shops, shop] } : l,
+ );
+}
+
+export function listModifications(
+ state: ScheduleDragWorkspaceState,
+): ScheduleModification[] {
+ const laneById = new Map(state.map((l) => [l.id, l]));
+ const out: ScheduleModification[] = [];
+
+ for (const lane of state) {
+ for (const shop of lane.shops) {
+ const isLaneChanged = shop.originalLaneId !== lane.id;
+ const isSeqChanged = shop.originalLoadingSequence !== shop.loadingSequence;
+ const isDistrictChanged =
+ (shop.originalDistrictReferenceRaw ?? "") !==
+ (shop.districtReferenceRaw ?? "");
+ if (!isLaneChanged && !isSeqChanged && !isDistrictChanged) continue;
+
+ const fromLane = laneById.get(shop.originalLaneId);
+ out.push({
+ truckRowId: shop.truckRowId,
+ shopCode: shop.shopCode,
+ displayName: shop.displayName,
+ location: formatPlannedShopLocation(shop),
+ fromLaneId: shop.originalLaneId,
+ fromLaneLabel: fromLane?.label ?? shop.originalLaneId,
+ toLaneId: lane.id,
+ toLaneLabel: lane.label,
+ oldLoadingSequence: shop.originalLoadingSequence,
+ newLoadingSequence: shop.loadingSequence,
+ isLaneChanged,
+ isSeqChanged,
+ isDistrictChanged,
+ oldDistrictLabel: toDistrictDisplayName(shop.originalDistrictReferenceRaw),
+ newDistrictLabel: toDistrictDisplayName(shop.districtReferenceRaw),
+ });
+ }
+ }
+
+ return out.sort((a, b) => a.shopCode.localeCompare(b.shopCode, "zh-Hant"));
+}
+
+export function toScheduleMappings(
+ modifications: ScheduleModification[],
+ excludeTruckRowIds: Set = new Set(),
+): Record {
+ const out: Record = {};
+ for (const mod of modifications) {
+ if (excludeTruckRowIds.has(mod.truckRowId)) continue;
+ out[mod.truckRowId] = {
+ laneId: mod.toLaneId,
+ toLoadingSequence: mod.newLoadingSequence,
+ };
+ }
+ return out;
+}
+
+export function defaultFocusedLaneIds(
+ lanes: ScheduleLaneOption[],
+): { leftLaneId: string; rightLaneId: string } {
+ const ids = lanes.map((l) => l.id);
+ return {
+ leftLaneId: ids[0] ?? "",
+ rightLaneId: ids[1] ?? ids[0] ?? "",
+ };
+}
diff --git a/src/components/Shop/scheduleExecuteAt.ts b/src/components/Shop/scheduleExecuteAt.ts
new file mode 100644
index 0000000..e2eae36
--- /dev/null
+++ b/src/components/Shop/scheduleExecuteAt.ts
@@ -0,0 +1,81 @@
+/** Backend allows executeAt down to now - 2 minutes. */
+export const SCHEDULE_EXECUTE_AT_GRACE_MS = 2 * 60 * 1000;
+
+/** Default offset when rescheduling a past executeAt. */
+export const RESCHEDULE_DEFAULT_OFFSET_MS = 5 * 60 * 1000;
+
+export function parseExecuteAtIso(iso: string): Date | null {
+ const raw = iso.trim();
+ if (!raw) return null;
+ const normalized = raw.includes("T") ? raw : raw.replace(" ", "T");
+ const d = new Date(normalized);
+ return Number.isFinite(d.getTime()) ? d : null;
+}
+
+export function formatExecuteAtIso(date: Date): string {
+ const y = date.getFullYear();
+ const mo = String(date.getMonth() + 1).padStart(2, "0");
+ const d = String(date.getDate()).padStart(2, "0");
+ const h = String(date.getHours()).padStart(2, "0");
+ const mi = String(date.getMinutes()).padStart(2, "0");
+ const s = String(date.getSeconds()).padStart(2, "0");
+ return `${y}-${mo}-${d}T${h}:${mi}:${s}`;
+}
+
+/** Display API timestamps as `yyyy-MM-dd HH:mm:ss` (no `T`). */
+export function formatScheduleDisplayDateTime(iso: string): string {
+ const raw = iso.trim();
+ if (!raw) return raw;
+ const tIdx = raw.indexOf("T");
+ if (tIdx < 0) return raw;
+ const time = raw
+ .slice(tIdx + 1)
+ .replace(/\.\d+.*$/, "")
+ .replace(/Z$/i, "")
+ .replace(/[+-]\d{2}:\d{2}$/, "");
+ return `${raw.slice(0, tIdx)} ${time}`;
+}
+
+export function isExecuteAtTooEarly(
+ executeAtIso: string,
+ now: Date = new Date(),
+): boolean {
+ const parsed = parseExecuteAtIso(executeAtIso);
+ if (!parsed) return true;
+ const min = new Date(now.getTime() - SCHEDULE_EXECUTE_AT_GRACE_MS);
+ return parsed.getTime() < min.getTime();
+}
+
+export function buildExecuteAtIso(
+ date: string,
+ time: string,
+): string | null {
+ const d = date.trim();
+ const t = time.trim();
+ if (!d || !t) return null;
+ return `${d}T${t.length === 5 ? `${t}:00` : t}`;
+}
+
+export type RescheduleExecuteAtResult = {
+ executeAt: string;
+ adjusted: boolean;
+};
+
+/**
+ * Keeps original executeAt if still valid; otherwise shifts to now + offset.
+ */
+export function resolveRescheduleExecuteAt(
+ originalIso: string,
+ now: Date = new Date(),
+ offsetMs: number = RESCHEDULE_DEFAULT_OFFSET_MS,
+): RescheduleExecuteAtResult {
+ if (!isExecuteAtTooEarly(originalIso, now)) {
+ return { executeAt: originalIso.trim(), adjusted: false };
+ }
+ const next = new Date(now.getTime() + offsetMs);
+ return { executeAt: formatExecuteAtIso(next), adjusted: true };
+}
+
+export function defaultRetryExecuteAt(now: Date = new Date()): string {
+ return formatExecuteAtIso(new Date(now.getTime() + 60 * 1000));
+}
diff --git a/src/components/Shop/scheduleLineAdapter.ts b/src/components/Shop/scheduleLineAdapter.ts
new file mode 100644
index 0000000..38ced03
--- /dev/null
+++ b/src/components/Shop/scheduleLineAdapter.ts
@@ -0,0 +1,24 @@
+import type {
+ TruckLaneMoveTargetRequest,
+ TruckLaneScheduleLineRequest,
+} from "@/app/api/shop/actions";
+
+export function moveToScheduleLine(
+ move: TruckLaneMoveTargetRequest,
+): TruckLaneScheduleLineRequest {
+ return {
+ action: "MOVE",
+ truckRowId: move.truckRowId,
+ toTruckLanceCode: move.toTruckLanceCode,
+ toRemark: move.toRemark ?? null,
+ toStoreId: move.toStoreId,
+ toLoadingSequence: move.toLoadingSequence,
+ toDistrictReference: move.toDistrictReference ?? null,
+ };
+}
+
+export function movesToScheduleLines(
+ moves: TruckLaneMoveTargetRequest[],
+): TruckLaneScheduleLineRequest[] {
+ return moves.map(moveToScheduleLine);
+}
diff --git a/src/components/Shop/scheduleLineDisplay.ts b/src/components/Shop/scheduleLineDisplay.ts
new file mode 100644
index 0000000..6504aa9
--- /dev/null
+++ b/src/components/Shop/scheduleLineDisplay.ts
@@ -0,0 +1,145 @@
+import type { TruckLaneScheduleLineResponse } from "@/app/api/shop/actions";
+import type { ScheduleLaneOption } from "@/components/Shop/ScheduleChangeModal";
+import { toDistrictDisplayName } from "@/components/Shop/routeBoardDisplayOrder";
+import { formatScheduleTargetLaneLabel } from "@/components/Shop/scheduleRouteExcelToMoves";
+
+export function resolveScheduleLaneLabel(
+ line: TruckLaneScheduleLineResponse,
+ kind: "from" | "to",
+ laneById?: Map,
+): string {
+ const code =
+ kind === "from" ? line.fromTruckLanceCode : line.toTruckLanceCode;
+ const remark = kind === "from" ? line.fromRemark : line.toRemark;
+ const storeId = kind === "from" ? line.fromStoreId : line.toStoreId;
+ if (!code?.trim()) return "—";
+ if (laneById) {
+ const match = Array.from(laneById.values()).find(
+ (l) =>
+ l.truckLanceCode === code &&
+ (l.remark ?? "") === (remark ?? "") &&
+ l.storeId === storeId,
+ );
+ if (match) return match.label;
+ }
+ return formatScheduleTargetLaneLabel(code, remark);
+}
+
+export function isSameScheduleLaneBucket(
+ line: TruckLaneScheduleLineResponse,
+): boolean {
+ const norm = (v?: string | null) => (v ?? "").trim();
+ return (
+ norm(line.fromTruckLanceCode) === norm(line.toTruckLanceCode) &&
+ norm(line.fromRemark) === norm(line.toRemark) &&
+ norm(line.fromStoreId) === norm(line.toStoreId)
+ );
+}
+
+function normDistrict(v?: string | null): string {
+ return toDistrictDisplayName(v ?? null) || "—";
+}
+
+function formatTimeLabel(v?: string | null): string | null {
+ const raw = v?.trim();
+ if (!raw) return null;
+ const tIdx = raw.indexOf("T");
+ if (tIdx >= 0) return raw.slice(tIdx + 1, tIdx + 6);
+ return raw.length >= 5 ? raw.slice(0, 5) : raw;
+}
+
+function formatSeqValue(from?: number | null, to?: number | null): string | null {
+ if (from != null && to != null && from !== to) return `${from} → ${to}`;
+ if (to != null) return String(to);
+ if (from != null) return String(from);
+ return null;
+}
+
+export type ScheduleLineDescription = {
+ headline: string;
+ details: string[];
+};
+
+type TranslateFn = (key: string, opts?: Record) => string;
+
+export function buildScheduleLineDescription(
+ line: TruckLaneScheduleLineResponse,
+ laneById: Map | undefined,
+ t: TranslateFn,
+): ScheduleLineDescription {
+ const toLane = resolveScheduleLaneLabel(line, "to", laneById);
+ const fromLane = resolveScheduleLaneLabel(line, "from", laneById);
+ const details: string[] = [];
+
+ const pushSeq = () => {
+ const seq = formatSeqValue(line.fromLoadingSequence, line.toLoadingSequence);
+ if (seq) details.push(t("schedule_line_seq", { value: seq }));
+ };
+
+ const pushDistrict = () => {
+ const fromDist = normDistrict(line.fromDistrictReference);
+ const toDist = normDistrict(line.toDistrictReference);
+ if (fromDist !== toDist) {
+ details.push(
+ t("schedule_line_district_change", { from: fromDist, to: toDist }),
+ );
+ } else if (line.action === "CREATE" && toDist !== "—") {
+ details.push(t("schedule_line_district_target", { district: toDist }));
+ }
+ };
+
+ const pushDeparture = () => {
+ const fromDep = formatTimeLabel(line.fromDepartureTime);
+ const toDep = formatTimeLabel(line.departureTime);
+ if (fromDep && toDep && fromDep !== toDep) {
+ details.push(
+ t("schedule_line_departure_change", { from: fromDep, to: toDep }),
+ );
+ } else if (toDep && line.action === "CREATE") {
+ details.push(t("schedule_line_departure_target", { time: toDep }));
+ }
+ };
+
+ switch (line.action) {
+ case "DELETE":
+ return {
+ headline: t("schedule_line_remove_from", {
+ lane: fromLane !== "—" ? fromLane : toLane,
+ }),
+ details,
+ };
+ case "ENSURE_LANE":
+ pushDeparture();
+ return {
+ headline: t("schedule_line_ensure_lane", { lane: toLane }),
+ details,
+ };
+ case "CREATE":
+ pushSeq();
+ pushDistrict();
+ pushDeparture();
+ return {
+ headline: t("schedule_line_add_to", { lane: toLane }),
+ details,
+ };
+ case "MOVE":
+ default: {
+ if (isSameScheduleLaneBucket(line)) {
+ pushSeq();
+ pushDistrict();
+ pushDeparture();
+ return {
+ headline: t("schedule_line_on_lane", { lane: toLane }),
+ details,
+ };
+ }
+ pushSeq();
+ pushDistrict();
+ pushDeparture();
+ return {
+ headline: t("schedule_line_lane_change", { from: fromLane, to: toLane }),
+ details,
+ };
+ }
+ }
+}
diff --git a/src/components/Shop/scheduleLineValidation.ts b/src/components/Shop/scheduleLineValidation.ts
new file mode 100644
index 0000000..17ab799
--- /dev/null
+++ b/src/components/Shop/scheduleLineValidation.ts
@@ -0,0 +1,230 @@
+import type {
+ TruckLaneScheduleLineAction,
+ TruckLaneScheduleLineRequest,
+} from "@/app/api/shop/actions";
+import type { ScheduleLaneOption } from "@/components/Shop/ScheduleChangeModal";
+import type { ScheduleDragWorkspaceState } from "@/components/Shop/scheduleDragWorkspace";
+import { isExecuteAtTooEarly } from "@/components/Shop/scheduleExecuteAt";
+
+export type ScheduleLineValidationError = {
+ truckRowId: number;
+ messageKey: string;
+ messageParams?: Record;
+};
+
+export type ValidateScheduleLinesInput = {
+ lines: TruckLaneScheduleLineRequest[];
+ lanes: ScheduleLaneOption[];
+ plannedLanes?: ScheduleDragWorkspaceState;
+ pendingTruckRowIds: Set;
+ executeAt: string;
+ shopCodeByTruckRowId?: Map;
+};
+
+export type ValidateScheduleLinesResult =
+ | { ok: true }
+ | { ok: false; errors: ScheduleLineValidationError[] };
+
+function laneBucketKey(lane: ScheduleLaneOption): string {
+ return `${lane.truckLanceCode}|${lane.storeId}|${lane.remark ?? ""}`;
+}
+
+function lineTargetBucketKey(line: TruckLaneScheduleLineRequest): string {
+ return `${line.toTruckLanceCode.trim()}|${line.toStoreId.trim()}|${(line.toRemark ?? "").trim()}`;
+}
+
+function findLaneForLine(
+ line: TruckLaneScheduleLineRequest,
+ lanes: ScheduleLaneOption[],
+): ScheduleLaneOption | undefined {
+ const code = line.toTruckLanceCode.trim();
+ const storeId = line.toStoreId.trim();
+ const remark = (line.toRemark ?? "").trim();
+ return lanes.find(
+ (l) =>
+ l.truckLanceCode.trim() === code &&
+ l.storeId.trim() === storeId &&
+ (l.remark ?? "").trim() === remark,
+ );
+}
+
+function effectiveShopsOnLane(
+ lane: ScheduleLaneOption,
+ plannedLanes?: ScheduleDragWorkspaceState,
+): ScheduleLaneOption["shops"] {
+ const planned = plannedLanes?.find((l) => l.id === lane.id);
+ if (planned) {
+ return planned.shops.map((s) => ({
+ truckRowId: s.truckRowId,
+ districtReferenceRaw: s.districtReferenceRaw,
+ loadingSequence: s.loadingSequence,
+ }));
+ }
+ return lane.shops;
+}
+
+export function validateScheduleLines(
+ input: ValidateScheduleLinesInput,
+): ValidateScheduleLinesResult {
+ const errors: ScheduleLineValidationError[] = [];
+ const {
+ lines,
+ lanes,
+ plannedLanes,
+ pendingTruckRowIds,
+ executeAt,
+ shopCodeByTruckRowId = new Map(),
+ } = input;
+
+ if (lines.length === 0) {
+ errors.push({
+ truckRowId: 0,
+ messageKey: "schedule_err_no_moves",
+ });
+ }
+
+ if (isExecuteAtTooEarly(executeAt)) {
+ errors.push({
+ truckRowId: 0,
+ messageKey: "schedule_err_execute_at_past",
+ });
+ }
+
+ const ensuredLaneKeys = new Set(
+ lines
+ .filter((l) => l.action === "ENSURE_LANE")
+ .map((l) => lineTargetBucketKey(l)),
+ );
+
+ const shopCodesInTargetBucket = new Map>();
+
+ for (const line of lines) {
+ const action = line.action as TruckLaneScheduleLineAction;
+ const truckRowId = line.truckRowId ?? 0;
+
+ if (
+ (action === "MOVE" || action === "DELETE") &&
+ truckRowId > 0 &&
+ pendingTruckRowIds.has(truckRowId)
+ ) {
+ errors.push({
+ truckRowId,
+ messageKey: "schedule_err_open_pending",
+ messageParams: { id: truckRowId },
+ });
+ }
+
+ if (action === "ENSURE_LANE" || action === "DELETE") {
+ continue;
+ }
+
+ const lane = findLaneForLine(line, lanes);
+ const targetKey = lineTargetBucketKey(line);
+ const laneEnsured = ensuredLaneKeys.has(targetKey);
+
+ if (!lane && !laneEnsured) {
+ errors.push({
+ truckRowId,
+ messageKey: "schedule_err_target_lane_missing",
+ messageParams: { lane: line.toTruckLanceCode },
+ });
+ continue;
+ }
+
+ if (lane) {
+ const persistedShops = effectiveShopsOnLane(lane, plannedLanes).filter(
+ (s) => s.truckRowId > 0,
+ );
+ if (persistedShops.length === 0 && !laneEnsured && action !== "CREATE") {
+ errors.push({
+ truckRowId,
+ messageKey: "schedule_err_target_lane_empty",
+ messageParams: { lane: lane.label },
+ });
+ continue;
+ }
+ }
+
+ if (action === "MOVE" && truckRowId > 0) {
+ const shopCode = shopCodeByTruckRowId.get(truckRowId)?.trim();
+ if (shopCode && lane) {
+ const bucket = laneBucketKey(lane);
+ const laneShops = effectiveShopsOnLane(lane, plannedLanes);
+ const duplicateOnLane = laneShops.some((s) => {
+ if (s.truckRowId === truckRowId) return false;
+ const otherCode = shopCodeByTruckRowId.get(s.truckRowId)?.trim();
+ return otherCode === shopCode;
+ });
+ const seen = shopCodesInTargetBucket.get(bucket) ?? new Set();
+ const duplicateInBatch = seen.has(shopCode);
+
+ if (duplicateOnLane || duplicateInBatch) {
+ errors.push({
+ truckRowId,
+ messageKey: "schedule_err_duplicate_shop",
+ messageParams: { shop: shopCode },
+ });
+ } else {
+ seen.add(shopCode);
+ shopCodesInTargetBucket.set(bucket, seen);
+ }
+ }
+ }
+
+ if (action === "CREATE") {
+ const shopCode = line.shopCode?.trim();
+ const bucketKey = targetKey;
+ if (shopCode) {
+ const laneForCreate = lane ?? findLaneForLine(line, lanes);
+ if (laneForCreate) {
+ const bucket = laneBucketKey(laneForCreate);
+ const laneShops = effectiveShopsOnLane(laneForCreate, plannedLanes);
+ const duplicateOnLane = laneShops.some((s) => {
+ const otherCode = shopCodeByTruckRowId.get(s.truckRowId)?.trim();
+ return otherCode === shopCode;
+ });
+ const seen = shopCodesInTargetBucket.get(bucket) ?? new Set();
+ if (duplicateOnLane || seen.has(shopCode)) {
+ errors.push({
+ truckRowId: 0,
+ messageKey: "schedule_err_duplicate_shop",
+ messageParams: { shop: shopCode },
+ });
+ } else {
+ seen.add(shopCode);
+ shopCodesInTargetBucket.set(bucket, seen);
+ }
+ } else {
+ const seen = shopCodesInTargetBucket.get(bucketKey) ?? new Set();
+ if (seen.has(shopCode)) {
+ errors.push({
+ truckRowId: 0,
+ messageKey: "schedule_err_duplicate_shop",
+ messageParams: { shop: shopCode },
+ });
+ } else {
+ seen.add(shopCode);
+ shopCodesInTargetBucket.set(bucketKey, seen);
+ }
+ }
+ }
+ }
+ }
+
+ if (errors.length > 0) {
+ return { ok: false, errors };
+ }
+ return { ok: true };
+}
+
+export function formatScheduleLineValidationErrors(
+ t: (key: string, params?: Record) => string,
+ errors: ScheduleLineValidationError[],
+): string {
+ return errors
+ .map((e) => {
+ const params = e.messageParams ?? {};
+ return t(e.messageKey, params);
+ })
+ .join("\n");
+}
diff --git a/src/components/Shop/scheduleMoveValidation.ts b/src/components/Shop/scheduleMoveValidation.ts
new file mode 100644
index 0000000..26aa485
--- /dev/null
+++ b/src/components/Shop/scheduleMoveValidation.ts
@@ -0,0 +1,131 @@
+import type { TruckLaneMoveTargetRequest } from "@/app/api/shop/actions";
+import type { ScheduleLaneOption } from "@/components/Shop/ScheduleChangeModal";
+import { isExecuteAtTooEarly } from "@/components/Shop/scheduleExecuteAt";
+
+export type ScheduleMoveValidationError = {
+ truckRowId: number;
+ messageKey: string;
+ messageParams?: Record;
+};
+
+export type ValidateScheduleMovesInput = {
+ moves: TruckLaneMoveTargetRequest[];
+ lanes: ScheduleLaneOption[];
+ /** truck row ids with an open pending schedule on the server */
+ pendingTruckRowIds: Set;
+ executeAt: string;
+ /** shopCode by truckRowId for duplicate detection */
+ shopCodeByTruckRowId?: Map;
+};
+
+export type ValidateScheduleMovesResult =
+ | { ok: true }
+ | { ok: false; errors: ScheduleMoveValidationError[] };
+
+function laneBucketKey(lane: ScheduleLaneOption): string {
+ return `${lane.truckLanceCode}|${lane.storeId}|${lane.remark ?? ""}`;
+}
+
+function findLaneForMove(
+ move: TruckLaneMoveTargetRequest,
+ lanes: ScheduleLaneOption[],
+): ScheduleLaneOption | undefined {
+ const code = move.toTruckLanceCode.trim();
+ const storeId = move.toStoreId.trim();
+ const remark = (move.toRemark ?? "").trim();
+ return lanes.find(
+ (l) =>
+ l.truckLanceCode.trim() === code &&
+ l.storeId.trim() === storeId &&
+ (l.remark ?? "").trim() === remark,
+ );
+}
+
+export function validateScheduleMoves(
+ input: ValidateScheduleMovesInput,
+): ValidateScheduleMovesResult {
+ const errors: ScheduleMoveValidationError[] = [];
+ const {
+ moves,
+ lanes,
+ pendingTruckRowIds,
+ executeAt,
+ shopCodeByTruckRowId = new Map(),
+ } = input;
+
+ if (moves.length === 0) {
+ errors.push({
+ truckRowId: 0,
+ messageKey: "schedule_err_no_moves",
+ });
+ }
+
+ if (isExecuteAtTooEarly(executeAt)) {
+ errors.push({
+ truckRowId: 0,
+ messageKey: "schedule_err_execute_at_past",
+ });
+ }
+
+ const shopCodesInTargetBucket = new Map>();
+
+ for (const move of moves) {
+ const truckRowId = move.truckRowId;
+
+ if (pendingTruckRowIds.has(truckRowId)) {
+ errors.push({
+ truckRowId,
+ messageKey: "schedule_err_open_pending",
+ messageParams: { id: truckRowId },
+ });
+ }
+
+ const lane = findLaneForMove(move, lanes);
+ if (!lane) {
+ errors.push({
+ truckRowId,
+ messageKey: "schedule_err_target_lane_missing",
+ messageParams: { lane: move.toTruckLanceCode },
+ });
+ continue;
+ }
+
+ const persistedShops = lane.shops.filter((s) => s.truckRowId > 0);
+ if (persistedShops.length === 0) {
+ errors.push({
+ truckRowId,
+ messageKey: "schedule_err_target_lane_empty",
+ messageParams: { lane: lane.label },
+ });
+ continue;
+ }
+
+ const shopCode = shopCodeByTruckRowId.get(truckRowId)?.trim();
+ if (shopCode) {
+ const bucket = laneBucketKey(lane);
+ const duplicateOnLane = lane.shops.some((s) => {
+ if (s.truckRowId === truckRowId) return false;
+ const otherCode = shopCodeByTruckRowId.get(s.truckRowId)?.trim();
+ return otherCode === shopCode;
+ });
+ const seen = shopCodesInTargetBucket.get(bucket) ?? new Set();
+ const duplicateInBatch = seen.has(shopCode);
+
+ if (duplicateOnLane || duplicateInBatch) {
+ errors.push({
+ truckRowId,
+ messageKey: "schedule_err_duplicate_shop",
+ messageParams: { shop: shopCode },
+ });
+ } else {
+ seen.add(shopCode);
+ shopCodesInTargetBucket.set(bucket, seen);
+ }
+ }
+ }
+
+ if (errors.length > 0) {
+ return { ok: false, errors };
+ }
+ return { ok: true };
+}
diff --git a/src/components/Shop/scheduleRouteExcelToMoves.ts b/src/components/Shop/scheduleRouteExcelToMoves.ts
new file mode 100644
index 0000000..fdb689e
--- /dev/null
+++ b/src/components/Shop/scheduleRouteExcelToMoves.ts
@@ -0,0 +1,99 @@
+import type { RouteLaneImportPreviewRow } from "@/app/api/shop/client";
+import type { TruckLaneMoveTargetRequest } from "@/app/api/shop/actions";
+import { normalizeStoreId } from "@/app/utils/formatUtil";
+
+export type ScheduleRouteExcelRowError = {
+ shopCode: string;
+ shopName: string;
+ message: string;
+};
+
+export type ScheduleRouteExcelMovePreview = {
+ truckRowId: number;
+ shopCode: string;
+ shopName: string;
+ toTruckLanceCode: string;
+ toRemark: string | null;
+ toStoreId: string;
+ toLoadingSequence: number;
+};
+
+export type ScheduleRouteExcelToMovesResult = {
+ moves: TruckLaneMoveTargetRequest[];
+ previews: ScheduleRouteExcelMovePreview[];
+ rowErrors: ScheduleRouteExcelRowError[];
+};
+
+export function formatScheduleTargetLaneLabel(
+ truckLanceCode: string,
+ remark: string | null | undefined,
+): string {
+ const code = String(truckLanceCode || "").trim();
+ const rem = remark != null && String(remark).trim() !== "" ? String(remark).trim() : "";
+ return rem ? `${code} (${rem})` : code;
+}
+
+/**
+ * Converts RouteBoard MTMS Excel parse rows into truck-lane schedule moves.
+ * Rows without an existing truck board row are reported as errors.
+ */
+export function scheduleRouteExcelToMoves(
+ rows: RouteLaneImportPreviewRow[],
+): ScheduleRouteExcelToMovesResult {
+ const moves: TruckLaneMoveTargetRequest[] = [];
+ const previews: ScheduleRouteExcelMovePreview[] = [];
+ const rowErrors: ScheduleRouteExcelRowError[] = [];
+
+ for (const row of rows) {
+ const shopCode = String(row.shopCode || "").trim() || "-";
+ const shopName = String(row.shopName || "").trim() || "-";
+ const truckRowId = row.truckRowId;
+
+ if (truckRowId == null || !Number.isFinite(truckRowId) || truckRowId <= 0) {
+ rowErrors.push({
+ shopCode,
+ shopName,
+ message: "no_truck_row",
+ });
+ continue;
+ }
+
+ const toTruckLanceCode = String(row.truckLanceCode || "").trim();
+ if (!toTruckLanceCode) {
+ rowErrors.push({
+ shopCode,
+ shopName,
+ message: "no_target_lane",
+ });
+ continue;
+ }
+
+ const toRemark =
+ row.remark != null && String(row.remark).trim() !== ""
+ ? String(row.remark).trim()
+ : null;
+ const toStoreId = normalizeStoreId(row.storeId);
+ const seq = Math.max(0, Number(row.loadingSequence ?? 0) || 0);
+
+ const move: TruckLaneMoveTargetRequest = {
+ truckRowId,
+ toTruckLanceCode,
+ toRemark,
+ toStoreId,
+ toLoadingSequence: seq,
+ toDistrictReference: row.districtReference ?? null,
+ };
+ moves.push(move);
+ previews.push({
+ truckRowId,
+ shopCode,
+ shopName,
+ toTruckLanceCode,
+ toRemark,
+ toStoreId,
+ toLoadingSequence: seq,
+ });
+ }
+
+ return { moves, previews, rowErrors };
+}
diff --git a/src/components/Shop/scheduleUiHelpers.ts b/src/components/Shop/scheduleUiHelpers.ts
new file mode 100644
index 0000000..9753a2b
--- /dev/null
+++ b/src/components/Shop/scheduleUiHelpers.ts
@@ -0,0 +1,21 @@
+import type { TFunction } from "i18next";
+
+export type ScheduleValidationError = {
+ truckRowId: number;
+ messageKey: string;
+ messageParams?: Record;
+};
+
+export function formatScheduleValidationError(
+ t: TFunction<"shop">,
+ error: ScheduleValidationError,
+): string {
+ return t(error.messageKey, (error.messageParams ?? {}) as Record);
+}
+
+export function formatScheduleValidationErrors(
+ t: TFunction<"shop">,
+ errors: ScheduleValidationError[],
+): string {
+ return errors.map((e) => formatScheduleValidationError(t, e)).join("\n");
+}
diff --git a/src/components/Shop/truckLaneMovePlanner.ts b/src/components/Shop/truckLaneMovePlanner.ts
new file mode 100644
index 0000000..fac137c
--- /dev/null
+++ b/src/components/Shop/truckLaneMovePlanner.ts
@@ -0,0 +1,173 @@
+/**
+ * TruckLaneMovePlanner — single seam for planning schedule moves from the board UI.
+ */
+import type {
+ CreateTruckLaneScheduleRequest,
+ TruckLaneMoveTargetRequest,
+} from "@/app/api/shop/actions";
+import type {
+ ScheduleChangePayload,
+ ScheduleLaneOption,
+ ScheduleShopRow,
+} from "@/components/Shop/ScheduleChangeModal";
+import {
+ buildCreateScheduleRequest,
+ buildCreateScheduleRequestFromModifications,
+ buildScheduleLinesFromPlan,
+} from "@/components/Shop/scheduleApiAdapter";
+import {
+ initPlannedLanes,
+ listModifications,
+ moveShop,
+ revertShop,
+ type ScheduleDragWorkspaceState,
+ type ScheduleModification,
+ type ScheduledDeleteSnapshot,
+} from "@/components/Shop/scheduleDragWorkspace";
+import { buildExecuteAtIso } from "@/components/Shop/scheduleExecuteAt";
+import {
+ validateScheduleLines,
+ type ScheduleLineValidationError,
+} from "@/components/Shop/scheduleLineValidation";
+
+export type PlanScheduleSubmitInput = {
+ lanes: ScheduleLaneOption[];
+ shops: ScheduleShopRow[];
+ plannedLanes: ScheduleDragWorkspaceState;
+ pendingDeletes: ScheduledDeleteSnapshot[];
+ date: string;
+ time: string;
+ pendingTruckRowIds: Set;
+ note?: string | null;
+};
+
+export type PlanScheduleSubmitResult =
+ | {
+ ok: true;
+ request: CreateTruckLaneScheduleRequest;
+ modifications: ScheduleModification[];
+ }
+ | { ok: false; errors: ScheduleLineValidationError[] };
+
+export function initPlannerState(
+ lanes: ScheduleLaneOption[],
+ shops: ScheduleShopRow[],
+): ScheduleDragWorkspaceState {
+ return initPlannedLanes(lanes, shops);
+}
+
+export function planMove(
+ state: ScheduleDragWorkspaceState,
+ args: Parameters[1],
+): ScheduleDragWorkspaceState {
+ return moveShop(state, args);
+}
+
+export function planRevert(
+ state: ScheduleDragWorkspaceState,
+ shopId: number,
+ currentLaneId: string,
+): ScheduleDragWorkspaceState {
+ return revertShop(state, shopId, currentLaneId);
+}
+
+export function listPlannedModifications(
+ state: ScheduleDragWorkspaceState,
+): ScheduleModification[] {
+ return listModifications(state);
+}
+
+export function buildShopCodeByTruckRowId(
+ shops: ScheduleShopRow[],
+): Map {
+ return new Map(shops.map((s) => [s.truckRowId, s.shopCode]));
+}
+
+export function validatePlannedSubmit(
+ input: PlanScheduleSubmitInput,
+): PlanScheduleSubmitResult {
+ const executeAt = buildExecuteAtIso(input.date, input.time);
+ if (!executeAt) {
+ return {
+ ok: false,
+ errors: [{ truckRowId: 0, messageKey: "schedule_err_execute_at_past" }],
+ };
+ }
+ const modifications = listModifications(input.plannedLanes);
+ const lines = buildScheduleLinesFromPlan({
+ modifications,
+ pendingDeletes: input.pendingDeletes,
+ lanes: input.lanes,
+ plannedLanes: input.plannedLanes,
+ });
+ const validation = validateScheduleLines({
+ lines,
+ lanes: input.lanes,
+ plannedLanes: input.plannedLanes,
+ pendingTruckRowIds: input.pendingTruckRowIds,
+ executeAt,
+ shopCodeByTruckRowId: buildShopCodeByTruckRowId(input.shops),
+ });
+ if (!validation.ok) {
+ return validation;
+ }
+ return {
+ ok: true,
+ modifications,
+ request: buildCreateScheduleRequestFromModifications({
+ executeAt,
+ note: input.note,
+ modifications,
+ lanes: input.lanes,
+ plannedLanes: input.plannedLanes,
+ pendingDeletes: input.pendingDeletes,
+ }),
+ };
+}
+
+export function validatePayloadSubmit(input: {
+ payload: ScheduleChangePayload;
+ lanes: ScheduleLaneOption[];
+ shops: ScheduleShopRow[];
+ pendingTruckRowIds: Set;
+}): { ok: true } | { ok: false; errors: ScheduleLineValidationError[] } {
+ const executeAt = buildExecuteAtIso(input.payload.date, input.payload.time);
+ if (!executeAt) {
+ return {
+ ok: false,
+ errors: [{ truckRowId: 0, messageKey: "schedule_err_execute_at_past" }],
+ };
+ }
+ const lines = buildScheduleLinesFromPlan({
+ modifications: listModifications(input.payload.plannedLanes),
+ pendingDeletes: input.payload.pendingDeletes,
+ lanes: input.lanes,
+ plannedLanes: input.payload.plannedLanes,
+ });
+ return validateScheduleLines({
+ lines,
+ lanes: input.lanes,
+ plannedLanes: input.payload.plannedLanes,
+ pendingTruckRowIds: input.pendingTruckRowIds,
+ executeAt,
+ shopCodeByTruckRowId: buildShopCodeByTruckRowId(input.shops),
+ });
+}
+
+export function buildRequestFromPayload(
+ payload: ScheduleChangePayload,
+ lanes: ScheduleLaneOption[],
+): CreateTruckLaneScheduleRequest | null {
+ const executeAt = buildExecuteAtIso(payload.date, payload.time);
+ if (!executeAt) return null;
+ return buildCreateScheduleRequest({
+ executeAt,
+ mappings: payload.mappings,
+ lanes,
+ plannedLanes: payload.plannedLanes,
+ pendingDeletes: payload.pendingDeletes,
+ modifications: listModifications(payload.plannedLanes),
+ });
+}
+
+export type { TruckLaneMoveTargetRequest, ScheduleModification };
diff --git a/src/components/Shop/useRouteBoardScheduleIndicators.ts b/src/components/Shop/useRouteBoardScheduleIndicators.ts
new file mode 100644
index 0000000..dd6e606
--- /dev/null
+++ b/src/components/Shop/useRouteBoardScheduleIndicators.ts
@@ -0,0 +1,82 @@
+import { useCallback, useEffect, useRef, useState } from "react";
+import {
+ getTruckLaneScheduleClient,
+ listTruckLaneSchedulesClient,
+ pendingTruckLaneScheduleShopIdsClient,
+} from "@/app/api/shop/client";
+import {
+ collectFailedTruckRowIdsFromSchedules,
+ filterFailedSchedules,
+} from "@/components/Shop/scheduleClientHelpers";
+
+export function useRouteBoardScheduleIndicators(options?: {
+ pollMs?: number;
+ applyingPollMs?: number;
+ paused?: boolean;
+}) {
+ const pollMs = options?.pollMs ?? 60_000;
+ const applyingPollMs = options?.applyingPollMs ?? 5_000;
+ const paused = options?.paused ?? false;
+ const [hasApplyingSchedule, setHasApplyingSchedule] = useState(false);
+
+ const [pendingScheduleShopIds, setPendingScheduleShopIds] = useState<
+ Set
+ >(new Set());
+ const [failedScheduleShopIds, setFailedScheduleShopIds] = useState<
+ Set
+ >(new Set());
+ const [failedScheduleCount, setFailedScheduleCount] = useState(0);
+
+ const refreshScheduleIndicators = useCallback(async () => {
+ try {
+ const [pendingIds, scheduleList] = await Promise.all([
+ pendingTruckLaneScheduleShopIdsClient(),
+ listTruckLaneSchedulesClient(
+ ["PENDING", "APPLYING", "FAILED", "PARTIAL"],
+ 200,
+ ),
+ ]);
+ setPendingScheduleShopIds(new Set(pendingIds.truckRowIds ?? []));
+
+ const failedSchedules = filterFailedSchedules(scheduleList);
+ setFailedScheduleCount(failedSchedules.length);
+ const needsLineWarm = failedSchedules.filter(
+ (s) => !s.lineCounts || (s.lineCounts.failed ?? 0) > 0,
+ );
+ const details = await Promise.all(
+ needsLineWarm.map((s) =>
+ getTruckLaneScheduleClient(s.id).catch(() => null),
+ ),
+ );
+ setFailedScheduleShopIds(
+ collectFailedTruckRowIdsFromSchedules(failedSchedules, details),
+ );
+ setHasApplyingSchedule(
+ scheduleList.some((s) => String(s.status).toUpperCase() === "APPLYING"),
+ );
+ } catch (e) {
+ console.warn("refreshScheduleIndicators failed", e);
+ }
+ }, []);
+
+ const pausedRef = useRef(paused);
+ pausedRef.current = paused;
+
+ useEffect(() => {
+ if (paused) return;
+ void refreshScheduleIndicators();
+ const intervalMs = hasApplyingSchedule ? applyingPollMs : pollMs;
+ const timer = window.setInterval(() => {
+ if (pausedRef.current) return;
+ void refreshScheduleIndicators();
+ }, intervalMs);
+ return () => window.clearInterval(timer);
+ }, [paused, pollMs, applyingPollMs, hasApplyingSchedule, refreshScheduleIndicators]);
+
+ return {
+ pendingScheduleShopIds,
+ failedScheduleShopIds,
+ failedScheduleCount,
+ refreshScheduleIndicators,
+ };
+}
diff --git a/src/components/StockIssue/BadItemHandleForm.tsx b/src/components/StockIssue/BadItemHandleForm.tsx
index 4346528..4d16685 100644
--- a/src/components/StockIssue/BadItemHandleForm.tsx
+++ b/src/components/StockIssue/BadItemHandleForm.tsx
@@ -62,7 +62,7 @@ const normalizeStatus = (status: string | undefined | null): string => {
};
const BadItemHandleForm: React.FC = () => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockIssue", "common"]);
const { data: session } = useSession() as { data: SessionWithTokens | null };
const currentUserId = session?.id ? parseInt(session.id) : undefined;
diff --git a/src/components/StockIssue/BadItemHandleModal.tsx b/src/components/StockIssue/BadItemHandleModal.tsx
index 0744e36..b3ee2b5 100644
--- a/src/components/StockIssue/BadItemHandleModal.tsx
+++ b/src/components/StockIssue/BadItemHandleModal.tsx
@@ -36,7 +36,7 @@ const BadItemHandleModal: React.FC = ({
currentUserId,
onSuccess,
}) => {
- const { t } = useTranslation("inventory");
+ const { t } = useTranslation("stockIssue");
const inFlightRef = useRef(false);
const [qty, setQty] = useState("");
const [remarks, setRemarks] = useState("");
diff --git a/src/components/StockIssue/ExpiryHandleTab.tsx b/src/components/StockIssue/ExpiryHandleTab.tsx
index f4e7670..a582c4e 100644
--- a/src/components/StockIssue/ExpiryHandleTab.tsx
+++ b/src/components/StockIssue/ExpiryHandleTab.tsx
@@ -27,7 +27,7 @@ type SearchParamNames = keyof SearchQuery;
const ExpiryHandleTab: React.FC = () => {
const BATCH_CHUNK_SIZE = 20;
- const { t } = useTranslation("inventory");
+ const { t } = useTranslation("stockIssue");
const { data: session } = useSession() as { data: SessionWithTokens | null };
const currentUserId = session?.id ? parseInt(session.id) : undefined;
diff --git a/src/components/StockIssue/SearchPage.tsx b/src/components/StockIssue/SearchPage.tsx
index 8567eac..50e571c 100644
--- a/src/components/StockIssue/SearchPage.tsx
+++ b/src/components/StockIssue/SearchPage.tsx
@@ -10,7 +10,7 @@ import ExpiryHandleTab from "./ExpiryHandleTab";
type TabValue = "badHandle" | "badRecord" | "expiryHandle" | "expiryRecord";
const SearchPage: React.FC = () => {
- const { t } = useTranslation("inventory");
+ const { t } = useTranslation("stockIssue");
const [tab, setTab] = useState("badHandle");
const handleTabChange = useCallback((_: React.SyntheticEvent, value: string) => {
diff --git a/src/components/StockIssue/StockIssueInventoryTable.tsx b/src/components/StockIssue/StockIssueInventoryTable.tsx
index f3bc023..4112536 100644
--- a/src/components/StockIssue/StockIssueInventoryTable.tsx
+++ b/src/components/StockIssue/StockIssueInventoryTable.tsx
@@ -24,7 +24,7 @@ const StockIssueInventoryTable: React.FC = ({
totalCount,
onRowClick,
}) => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockIssue", "common"]);
const columns = useMemo[]>(
() => [
diff --git a/src/components/StockIssue/StockIssueLotLineTable.tsx b/src/components/StockIssue/StockIssueLotLineTable.tsx
index 7433523..a195c38 100644
--- a/src/components/StockIssue/StockIssueLotLineTable.tsx
+++ b/src/components/StockIssue/StockIssueLotLineTable.tsx
@@ -50,7 +50,7 @@ const StockIssueLotLineTable: React.FC = ({
onBadItemHandleSuccess,
onLotLinesChanged,
}) => {
- const { t } = useTranslation("inventory");
+ const { t } = useTranslation(["stockIssue", "common"]);
const [modalOpen, setModalOpen] = useState(false);
const [selectedLotLine, setSelectedLotLine] =
useState(null);
@@ -202,7 +202,7 @@ const StockIssueLotLineTable: React.FC = ({
{inventory
- ? `${t("Item selected")}: ${inventory.itemCode} | ${inventory.itemName} (${t(inventory.itemType)})`
+ ? `${t("Item selected")}: ${inventory.itemCode} | ${inventory.itemName} (${t(inventory.itemType, { ns: "common", defaultValue: inventory.itemType })})`
: t("No items are selected yet.")}
diff --git a/src/components/StockIssue/StockIssueRecordTab.tsx b/src/components/StockIssue/StockIssueRecordTab.tsx
index 31332a9..145441a 100644
--- a/src/components/StockIssue/StockIssueRecordTab.tsx
+++ b/src/components/StockIssue/StockIssueRecordTab.tsx
@@ -30,7 +30,7 @@ interface Props {
}
const StockIssueRecordTab: React.FC = ({ kind }) => {
- const { t } = useTranslation("inventory");
+ const { t } = useTranslation("stockIssue");
const [items, setItems] = useState([]);
const [totalCount, setTotalCount] = useState(0);
const [paging, setPaging] = useState({ pageNum: 1, pageSize: 10 });
diff --git a/src/components/StockIssue/StockIssueSearchPanel.tsx b/src/components/StockIssue/StockIssueSearchPanel.tsx
index a7355f8..c0a2998 100644
--- a/src/components/StockIssue/StockIssueSearchPanel.tsx
+++ b/src/components/StockIssue/StockIssueSearchPanel.tsx
@@ -53,7 +53,7 @@ function StockIssueSearchPanel({
extraActions,
disabled = false,
}: Props) {
- const { t } = useTranslation("inventory");
+ const { t } = useTranslation("stockIssue");
const { t: tCommon } = useTranslation("common"); // All
const emptyValues = useMemo(() => {
diff --git a/src/components/StockRecord/SearchPage.tsx b/src/components/StockRecord/SearchPage.tsx
index 975c1b4..dc1161c 100644
--- a/src/components/StockRecord/SearchPage.tsx
+++ b/src/components/StockRecord/SearchPage.tsx
@@ -30,7 +30,7 @@ interface ExtendedStockTransaction extends StockTransactionResponse {
}
const SearchPage: React.FC = ({ dataList: initialDataList }) => {
- const { t } = useTranslation("inventory");
+ const { t } = useTranslation(["stockRecord", "common"]);
// 添加数据状态
const [dataList, setDataList] = useState(initialDataList);
diff --git a/src/components/StockTakeManagement/ApproverAllCardList.tsx b/src/components/StockTakeManagement/ApproverAllCardList.tsx
index ac8ca62..29ab422 100644
--- a/src/components/StockTakeManagement/ApproverAllCardList.tsx
+++ b/src/components/StockTakeManagement/ApproverAllCardList.tsx
@@ -30,7 +30,7 @@ interface ApproverAllCardListProps {
const ApproverAllCardList: React.FC = ({
onCardClick,
}) => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const [loading, setLoading] = useState(false);
const [sessions, setSessions] = useState([]);
const [page, setPage] = useState(0);
diff --git a/src/components/StockTakeManagement/ApproverCardList.tsx b/src/components/StockTakeManagement/ApproverCardList.tsx
index 44db58a..6b562d9 100644
--- a/src/components/StockTakeManagement/ApproverCardList.tsx
+++ b/src/components/StockTakeManagement/ApproverCardList.tsx
@@ -31,7 +31,7 @@ interface ApproverCardListProps {
}
const ApproverCardList: React.FC = ({ onCardClick }) => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const [loading, setLoading] = useState(false);
const [stockTakeSessions, setStockTakeSessions] = useState([]);
diff --git a/src/components/StockTakeManagement/ApproverStockTake.tsx b/src/components/StockTakeManagement/ApproverStockTake.tsx
index 700fd13..e2bdbb1 100644
--- a/src/components/StockTakeManagement/ApproverStockTake.tsx
+++ b/src/components/StockTakeManagement/ApproverStockTake.tsx
@@ -51,7 +51,7 @@ const ApproverStockTake: React.FC = ({
onBack,
onSnackbar,
}) => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const { data: session } = useSession() as { data: SessionWithTokens | null };
const [inventoryLotDetails, setInventoryLotDetails] = useState([]);
diff --git a/src/components/StockTakeManagement/ApproverStockTakeAll.tsx b/src/components/StockTakeManagement/ApproverStockTakeAll.tsx
index 8bcf5d8..91f5748 100644
--- a/src/components/StockTakeManagement/ApproverStockTakeAll.tsx
+++ b/src/components/StockTakeManagement/ApproverStockTakeAll.tsx
@@ -225,7 +225,7 @@ const ApproverStockTakeAll: React.FC = ({
onBack,
onSnackbar,
}) => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const { data: session } = useSession() as { data: SessionWithTokens | null };
const [inventoryLotDetails, setInventoryLotDetails] = useState([]);
diff --git a/src/components/StockTakeManagement/InventoryAdjustmentsTab.tsx b/src/components/StockTakeManagement/InventoryAdjustmentsTab.tsx
index 42ae4cb..44631f8 100644
--- a/src/components/StockTakeManagement/InventoryAdjustmentsTab.tsx
+++ b/src/components/StockTakeManagement/InventoryAdjustmentsTab.tsx
@@ -114,7 +114,7 @@ const fakeAdjustments: InventoryAdjustment[] = [
];
const InventoryAdjustmentsTab: React.FC = () => {
- const { t } = useTranslation(["inventory"]);
+ const { t } = useTranslation(["stockTake"]);
// States
const [adjustments] = useState(fakeAdjustments);
diff --git a/src/components/StockTakeManagement/PickExecutionIssuesTab.tsx b/src/components/StockTakeManagement/PickExecutionIssuesTab.tsx
index d98efba..c0b92cf 100644
--- a/src/components/StockTakeManagement/PickExecutionIssuesTab.tsx
+++ b/src/components/StockTakeManagement/PickExecutionIssuesTab.tsx
@@ -47,7 +47,7 @@ type SearchQuery = {
type SearchParamNames = keyof SearchQuery;
const PickExecutionIssuesTab: React.FC = () => {
- const { t } = useTranslation(["inventory", "pickOrder"]);
+ const { t } = useTranslation(["stockTake", "pickOrder"]);
// States
const [issues, setIssues] = useState([]);
@@ -81,14 +81,21 @@ const PickExecutionIssuesTab: React.FC = () => {
{
label: t("Type"),
paramName: "type",
- type: "select",
- options: ["all", "jo", "do", "material"],
+ type: "select-labelled",
+ options: [
+ { value: "jo", label: t("jo") },
+ { value: "do", label: t("do") },
+ { value: "material", label: t("material") },
+ ],
},
{
label: t("Status"),
paramName: "status",
- type: "select",
- options: ["all", "pending", "resolved"],
+ type: "select-labelled",
+ options: [
+ { value: "pending", label: t("pending") },
+ { value: "resolved", label: t("resolved") },
+ ],
},
],
[t],
@@ -107,7 +114,7 @@ const PickExecutionIssuesTab: React.FC = () => {
// Build API parameters with proper type casting
let apiParams: FetchPickExecutionIssuesParams | undefined = undefined;
- if (query.type && query.type !== "all") {
+ if (query.type && query.type !== "All") {
// Type assertion to ensure the string is one of the valid types
const validType = query.type as "jo" | "do" | "material";
apiParams = { type: validType };
@@ -143,7 +150,7 @@ const PickExecutionIssuesTab: React.FC = () => {
);
}
- if (query.status && query.status !== "all") {
+ if (query.status && query.status !== "All") {
filteredResult = filteredResult.filter(issue => {
if (query.status === "pending") {
return issue.handleStatus.toLowerCase() === "pending";
diff --git a/src/components/StockTakeManagement/PickerCardList.tsx b/src/components/StockTakeManagement/PickerCardList.tsx
index 6068e82..55b4933 100644
--- a/src/components/StockTakeManagement/PickerCardList.tsx
+++ b/src/components/StockTakeManagement/PickerCardList.tsx
@@ -126,7 +126,7 @@ const PickerCardList: React.FC = ({
onSearchFiltersChange,
onAppliedFiltersChange,
}) => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const router = useRouter();
dayjs.extend(duration);
diff --git a/src/components/StockTakeManagement/PickerReStockTake.tsx b/src/components/StockTakeManagement/PickerReStockTake.tsx
index 199b593..1c8ebd3 100644
--- a/src/components/StockTakeManagement/PickerReStockTake.tsx
+++ b/src/components/StockTakeManagement/PickerReStockTake.tsx
@@ -51,7 +51,7 @@ const PickerReStockTake: React.FC = ({
onBack,
onSnackbar,
}) => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const { data: session } = useSession() as { data: SessionWithTokens | null };
const [inventoryLotDetails, setInventoryLotDetails] = useState([]);
diff --git a/src/components/StockTakeManagement/PickerStockTake.tsx b/src/components/StockTakeManagement/PickerStockTake.tsx
index 76ca5d7..220c7b3 100644
--- a/src/components/StockTakeManagement/PickerStockTake.tsx
+++ b/src/components/StockTakeManagement/PickerStockTake.tsx
@@ -56,7 +56,7 @@ const PickerStockTake: React.FC = ({
onBack,
onSnackbar,
}) => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const { data: session } = useSession() as { data: SessionWithTokens | null };
const [inventoryLotDetails, setInventoryLotDetails] = useState([]);
diff --git a/src/components/StockTakeManagement/StockTakeManagement.tsx b/src/components/StockTakeManagement/StockTakeManagement.tsx
index 9f9a543..c877ed2 100644
--- a/src/components/StockTakeManagement/StockTakeManagement.tsx
+++ b/src/components/StockTakeManagement/StockTakeManagement.tsx
@@ -30,7 +30,7 @@ function TabPanel(props: TabPanelProps) {
}
const StockTakeManagement: React.FC = () => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const [currentTab, setCurrentTab] = useState(0);
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
diff --git a/src/components/StockTakeManagement/StockTakeTab.tsx b/src/components/StockTakeManagement/StockTakeTab.tsx
index c4ddfd7..ad4af35 100644
--- a/src/components/StockTakeManagement/StockTakeTab.tsx
+++ b/src/components/StockTakeManagement/StockTakeTab.tsx
@@ -20,7 +20,7 @@ const DEFAULT_PICKER_CARD_LIST_FILTERS: PickerCardListFilters = {
};
const StockTakeTab: React.FC = () => {
- const { t } = useTranslation(["inventory", "common"]);
+ const { t } = useTranslation(["stockTake", "common"]);
const [tabValue, setTabValue] = useState(0);
const [selectedSession, setSelectedSession] = useState(null);
const [viewMode, setViewMode] = useState<"details" | "reStockTake">("details");
diff --git a/src/components/UpdateMaintenance/UpdateMaintenanceForm.tsx b/src/components/UpdateMaintenance/UpdateMaintenanceForm.tsx
index 1d319f2..61a6256 100644
--- a/src/components/UpdateMaintenance/UpdateMaintenanceForm.tsx
+++ b/src/components/UpdateMaintenance/UpdateMaintenanceForm.tsx
@@ -34,7 +34,7 @@ type EquipmentDetailData = {
};
const UpdateMaintenanceForm: React.FC = ({ id }) => {
- const { t } = useTranslation("common");
+ const { t } = useTranslation(["equipment", "common"]);
const router = useRouter();
const [loading, setLoading] = useState(false);
const [fetching, setFetching] = useState(true);
diff --git a/src/components/qrCodeHandles/qrCodeHandleTabs.tsx b/src/components/qrCodeHandles/qrCodeHandleTabs.tsx
index 08eb2a0..3d08d48 100644
--- a/src/components/qrCodeHandles/qrCodeHandleTabs.tsx
+++ b/src/components/qrCodeHandles/qrCodeHandleTabs.tsx
@@ -38,7 +38,7 @@ const QrCodeHandleTabs: React.FC = ({
equipmentTabContent,
warehouseTabContent,
}) => {
- const { t } = useTranslation("common");
+ const { t: tQrCodeHandle } = useTranslation("qrCodeHandle");
const { t: tUser } = useTranslation("user");
const { t: tWarehouse } = useTranslation("warehouse");
const searchParams = useSearchParams();
@@ -80,7 +80,7 @@ const QrCodeHandleTabs: React.FC = ({
-
+
diff --git a/src/i18n/I18nClientProvider.tsx b/src/i18n/I18nClientProvider.tsx
index e28d972..6614e9f 100644
--- a/src/i18n/I18nClientProvider.tsx
+++ b/src/i18n/I18nClientProvider.tsx
@@ -25,7 +25,10 @@ const I18nProvider: React.FC = ({
resources: {
[language]: resources,
},
+ lng: language,
fallbackLng: language,
+ defaultNS: namespaces[0],
+ fallbackNS: namespaces,
interpolation: {
escapeValue: false,
},
diff --git a/src/i18n/en/bagPrint.json b/src/i18n/en/bagPrint.json
new file mode 100644
index 0000000..2baf2eb
--- /dev/null
+++ b/src/i18n/en/bagPrint.json
@@ -0,0 +1,3 @@
+{
+ "title": "Bag Printer"
+}
diff --git a/src/i18n/en/bagUsage.json b/src/i18n/en/bagUsage.json
new file mode 100644
index 0000000..0d498ea
--- /dev/null
+++ b/src/i18n/en/bagUsage.json
@@ -0,0 +1,12 @@
+{
+ "Actions": "Actions",
+ "Back": "Back",
+ "Bag": "Bag",
+ "Bag Usage": "Bag Usage",
+ "Balance": "Balance",
+ "Consumed Qty": "Consumed Qty",
+ "Date": "Date",
+ "Job Order Code": "Job Order Code",
+ "Lot No": "Lot No",
+ "Scrap Qty": "Scrap Qty"
+}
diff --git a/src/i18n/en/bomWeighting.json b/src/i18n/en/bomWeighting.json
new file mode 100644
index 0000000..1f8a21a
--- /dev/null
+++ b/src/i18n/en/bomWeighting.json
@@ -0,0 +1,12 @@
+{
+ "BOM Weighting Score List": "BOM Weighting Score List",
+ "Material Weighting": "Material Weighting",
+ "Material Score": "Material Score",
+ "Weighting": "Weighting",
+ "Base Score": "Base Score",
+ "Edit BOM Weighting Score": "Edit BOM Weighting Score",
+ "Scoring Item": "Scoring Item",
+ "Range": "Range",
+ "Item Code": "Item Code",
+ "Item Name": "Item Name"
+}
diff --git a/src/i18n/en/chart.json b/src/i18n/en/chart.json
new file mode 100644
index 0000000..0eb11e4
--- /dev/null
+++ b/src/i18n/en/chart.json
@@ -0,0 +1,113 @@
+{
+ "all": "All",
+ "autoRefresh": "Auto Refresh",
+ "board_equipmentUsage": "Equipment Usage Board",
+ "board_jobOrderChart": "Job Order Chart",
+ "board_jobOrderLive": "Job Order Live Board",
+ "board_processLive": "Process Live Board",
+ "dateRange_lastDays": "Last {{d}} days",
+ "delivery_colAvgMin": "Avg Min/Order",
+ "delivery_colPickCount": "Pick Count",
+ "delivery_colStaff": "Staff",
+ "delivery_colTotalMin": "Total Min",
+ "delivery_dailyByStaff": "Daily by Staff",
+ "delivery_endDate": "End Date",
+ "delivery_item": "Item",
+ "delivery_itemPlaceholder": "Leave empty for all",
+ "delivery_noDataDesc": "No delivery data available for the selected period.",
+ "delivery_orderCount": "Order Count",
+ "delivery_ordersByDate": "Delivery Orders by Date",
+ "delivery_ordersByDate_export": "Delivery_Orders_By_Date",
+ "delivery_staff": "Staff",
+ "delivery_staffPerfCaption": "Per-person pick count & total duration for period",
+ "delivery_staffPerfDateError": "Staff performance start date cannot be later than end date",
+ "delivery_staffPerformanceTitle": "Staff Delivery Performance (Daily Pick Count & Duration)",
+ "delivery_staffPlaceholder": "Leave empty for all",
+ "delivery_startDate": "Start Date",
+ "delivery_store": "Store",
+ "delivery_topItemsByCount": "Top Items by Delivery Count",
+ "equipment_boardTitle": "Equipment Usage Board",
+ "equipment_completed": "Completed",
+ "equipment_endTime": "End Time",
+ "equipment_equipment": "Equipment",
+ "equipment_infoDescription1": "Shows equipment status in real-time: working, idle, or under maintenance.",
+ "equipment_infoDescription2": "Each equipment card displays the current job order and process.",
+ "equipment_infoDescription3": "Equipment with unclosed hours or missing time entries will be flagged.",
+ "equipment_jobOrder": "Job Order",
+ "equipment_missingHours": "Missing equipment hours",
+ "equipment_notToday": "Not Today",
+ "equipment_operator": "Operator",
+ "equipment_planStart": "Plan Start",
+ "equipment_process": "Process",
+ "equipment_searchAndList": "Search & List",
+ "equipment_startTime": "Start Time",
+ "equipment_status": "Status",
+ "equipment_unclosedHours": "Equipment hours not closed",
+ "exportExcel": "Export Excel",
+ "forecast_itemCode": "Item Code",
+ "forecast_noScheduleData": "No scheduling data for this date range.",
+ "forecast_plannedOutputByDate": "Planned Daily Output by Item (Forecast)",
+ "forecast_plannedOutputByDate_export": "Planned_Daily_Output_By_Item",
+ "forecast_productionSchedule": "Production Schedule by Date (Estimated Output)",
+ "forecast_productionSchedule_export": "Production_Schedule_By_Date",
+ "intervalSeconds": "Interval (sec)",
+ "jo_byStatus": "Job Orders by Status",
+ "jo_byStatus_export": "Job_Orders_By_Status",
+ "jo_createdVsCompleted": "Job Orders Created vs Completed by Date",
+ "jo_createdVsCompleted_export": "Job_Orders_Created_vs_Completed",
+ "jo_datePlanStart": "Date (Plan Start)",
+ "jo_detailSection": "Job Order Material / Process / Equipment",
+ "jo_equipmentWorkingWorked": "Equipment In Use / Used (by Job Order)",
+ "jo_equipmentWorkingWorked_export": "Equipment_In_Use_vs_Used",
+ "jo_materialPendingPicked": "Material Pending / Picked (by Plan Date)",
+ "jo_materialPendingPicked_export": "Material_Pending_vs_Picked",
+ "jo_processPendingCompleted": "Process Pending / Completed (by Plan Date)",
+ "jo_processPendingCompleted_export": "Process_Pending_vs_Completed",
+ "laneX": "Lane X",
+ "minuteAbbr": "min",
+ "minutes": "minutes",
+ "minutesWithVal": "{{val}} min",
+ "noData": "No data",
+ "off": "Off",
+ "on": "On",
+ "otherBoards": "Other Boards",
+ "pageTitle_delivery": "Delivery & Dispatch",
+ "pageTitle_equipmentBoard": "Equipment Usage Board",
+ "pageTitle_forecast": "Forecast & Planning",
+ "pageTitle_jobOrder": "Job Orders",
+ "pageTitle_jobOrderBoard": "Job Order Real-time Board",
+ "pageTitle_processBoard": "Process Real-time Board",
+ "pageTitle_purchase": "Purchase",
+ "pageTitle_warehouse": "Inventory & Warehouse",
+ "process_completed": "Completed",
+ "process_inProgress": "In Progress",
+ "process_nonToday": "Not Today",
+ "process_notStarted": "Not Started",
+ "refresh": "Refresh",
+ "requestFailed": "Request failed",
+ "selectDate": "Select Date",
+ "series_balance": "Balance",
+ "series_completed": "Completed",
+ "series_consumption": "Consumption",
+ "series_created": "Created",
+ "series_inbound": "Inbound",
+ "series_month": "Month",
+ "series_outbound": "Outbound",
+ "series_total": "Total",
+ "show": "Show",
+ "today": "Today",
+ "warehouse_addItem": "Add item to split",
+ "warehouse_balanceTrend": "Stock Balance Trend",
+ "warehouse_balanceTrend_export": "Stock_Balance_Trend",
+ "warehouse_consumptionTrend": "Monthly Consumption Trend (Outbound)",
+ "warehouse_consumptionTrend_export": "Monthly_Consumption_Trend",
+ "warehouse_exportFail": "Master export failed",
+ "warehouse_optional": "Optional",
+ "warehouse_qty": "Qty",
+ "warehouse_stockInOutByDate": "Stock In vs Out by Date",
+ "warehouse_stockInOutByDate_export": "Stock_In_vs_Out",
+ "warehouse_stockTxnByDate": "Stock Transactions by Date (In / Out / Total)",
+ "warehouse_stockTxnByDate_export": "Stock_Transactions_By_Date",
+ "warehouse_sumAll": "Sum all if empty",
+ "yesterday": "Yesterday"
+}
diff --git a/src/i18n/en/clientMonitor.json b/src/i18n/en/clientMonitor.json
new file mode 100644
index 0000000..4292a20
--- /dev/null
+++ b/src/i18n/en/clientMonitor.json
@@ -0,0 +1,3 @@
+{
+ "title": "Device Connection Monitor"
+}
diff --git a/src/i18n/en/common.json b/src/i18n/en/common.json
index 5e04af1..3c050f7 100644
--- a/src/i18n/en/common.json
+++ b/src/i18n/en/common.json
@@ -1,74 +1,125 @@
{
- "Grade {{grade}}": "Grade {{grade}}",
- "General Data": "General Data",
- "Repair and Maintenance": "Repair and Maintenance",
- "Repair and Maintenance Status": "Repair and Maintenance Status",
- "Latest Repair and Maintenance Date": "Latest Repair and Maintenance Date",
- "Last Repair and Maintenance Date": "Last Repair and Maintenance Date",
- "Repair and Maintenance Remarks": "Repair and Maintenance Remarks",
- "Update Equipment Maintenance and Repair": "Update Equipment Maintenance and Repair",
- "Equipment Information": "Equipment Information",
- "Loading": "Loading...",
- "Equipment not found": "Equipment not found",
- "Error saving data": "Error saving data",
- "Cancel": "Cancel",
- "Do you want to delete?": "Do you want to delete?",
- "Save": "Save",
- "Yes": "Yes",
- "No": "No",
- "Equipment Name": "Equipment Name",
- "Equipment Code": "Equipment Code",
- "ShopAndTruck": "Shop & route management",
- "DO floor (supplier)": "DO floor (supplier)",
- "Route Board": "Route board",
- "TruckLance Code is required": "TruckLance Code is required",
- "Truck shop details updated successfully": "Truck shop details updated successfully",
- "Failed to save truck shop details": "Failed to save truck shop details",
- "Truck lane information is required": "Truck lane information is required",
- "Shop added to truck lane successfully": "Shop added to truck lane successfully",
- "Failed to create shop in truck lane": "Failed to create shop in truck lane",
- "Add Shop": "Add Shop",
- "Shop Name": "Shop Name",
- "Shop Branch": "Shop Branch",
- "Shop Code": "Shop Code",
- "Search or select shop name": "Search or select shop name",
- "Search or select shop code": "Search or select shop code",
- "Search or select remark": "Search or select remark",
- "Edit shop details": "Edit shop details",
- "Add Shop to Truck Lane": "Add Shop to Truck Lane",
- "Truck lane code already exists. Please use a different code.": "Truck lane code already exists. Please use a different code.",
- "No Purchase Order After 2026-01-01": "No Purchase Order After 2026-01-01",
- "No Import Record": "No Import Record",
- "Download Template": "Download Template",
- "Upload": "Upload",
- "Downloading...": "Downloading...",
- "Uploading...": "Uploading...",
- "Upload successful": "Upload successful",
- "Upload failed": "Upload failed",
- "Download failed": "Download failed",
- "Upload completed with count": "{{count}} item(s) updated.",
- "Upload row errors": "The following rows had issues:",
- "item(s) updated": "item(s) updated.",
- "Average unit price": "Average unit price",
- "Latest market unit price": "Latest market unit price",
- "Invalid departure time": "Invalid departure time",
- "No trucks found for this truck lane": "No trucks found for this truck lane",
- "Departure time updated for all shops on this truck lane": "Departure time updated for all shops on this truck lane",
- "Applies to all shops using this truck lane": "Applies to all shops using this truck lane",
- "Please fill in the following required fields:": "Please fill in the following required fields:",
- "Departure Time": "Departure Time",
- "Submitting...": "Submitting...",
- "Failed to save truck data": "Failed to save truck data",
- "Edit departure time": "Edit departure time",
- "Cancel editing": "Cancel editing",
- "Select a shop first": "Select a shop first",
- "Search or select branch": "Search or select branch",
- "Mass Edit": "Mass Edit",
- "Save All": "Save All",
- "All shops updated successfully": "All shops updated successfully",
- "PO Workbench": "PO Workbench",
- "masterDataIssue_nav": "Master Data Issues",
- "masterDataIssue_pageTitle": "Master Data Issues",
- "masterDataIssue_viewDetail": "View detail",
- "masterDataIssue_group_count": "{{groups}} rows · {{issues}} issues"
-}
\ No newline at end of file
+ "Actions": "操作",
+ "Add Document": "新增文件",
+ "All": "全部",
+ "Allergic Substances": "過敏原",
+ "An error has occurred. Please try again later.": "An error has occurred. Please try again later.",
+ "Are you sure you want to delete this item?": "您確定要刪除此項目嗎?",
+ "Back": "返回",
+ "Basic Info": "基本資訊",
+ "Bom Required Qty": "BOM Required Qty",
+ "Bom UOM": "BOM UOM",
+ "Brand": "品牌",
+ "CMB": "消耗品",
+ "CO": "消耗品",
+ "Cancel": "取消",
+ "Column Name": "欄位名稱",
+ "Coming soon": "即將推出",
+ "Complexity": "複雜度",
+ "Confirm": "確認",
+ "Confirm Delete": "確認刪除",
+ "Cost (HKD)": "費用 (HKD)",
+ "Current total": "目前總和",
+ "Day Before Yesterday": "前天",
+ "Delete": "刪除",
+ "Delete Failed": "刪除失敗",
+ "Density": "濃淡",
+ "Depth": "顔色深淺度 深1淺5",
+ "Description": "描述",
+ "Details": "詳情",
+ "Duration (Minutes)": "時間(分)",
+ "Edit": "編輯",
+ "Enter any additional observations or notes...": "輸入其他觀察或備註...",
+ "Enter or select remark": "輸入或選擇備註",
+ "Error saving data": "Error saving data",
+ "Failed to fetch data": "無法取得資料",
+ "Filter": "過濾",
+ "Finished Good Detail": "成品出倉詳情",
+ "Finished Good Management": "成品出倉管理",
+ "Finished Good Order": "成品出倉",
+ "Float": "浮沉",
+ "General Data": "基本資料",
+ "Grade {{grade}}": "等級 {{grade}}",
+ "Invoice": "發票",
+ "Invoice Date": "發票日期",
+ "Item Code": "Item Code",
+ "Item Name": "Item Name",
+ "Loading": "載入中...",
+ "Loading order summary": "正在載入訂單摘要",
+ "Location": "位置",
+ "MA": "材料",
+ "MAT": "材料",
+ "MI": "雜項",
+ "Material Name": "材料清單",
+ "Min": "最小值",
+ "NM": "雜項及非消耗品",
+ "No": "否",
+ "No Lot": "沒有批號",
+ "No data available": "沒有資料",
+ "No options": "沒有選項",
+ "Order": "順序",
+ "Pending": "Pending",
+ "Please Select BOM": "請選擇 BOM",
+ "Please try again later.": "請稍後重試。",
+ "Project Code": "專案代碼",
+ "Project Code and Name": "專案代碼與名稱",
+ "QC Template not found": "找不到 QC 範本",
+ "Qty": "數量",
+ "RM": "原料",
+ "Range": "範圍",
+ "Refresh": "重新載入",
+ "Remarks": "備註",
+ "Remove Document": "移除文件",
+ "Report": "報告",
+ "Reset": "重置",
+ "Row per page": "每頁行數",
+ "Rows per page": "每頁行數",
+ "Sales Qty": "銷售數量",
+ "Sales UOM": "銷售單位",
+ "Save": "儲存",
+ "Saving": "儲存中",
+ "Search": "搜索",
+ "Search Criteria": "搜索條件",
+ "Select Date": "選擇日期",
+ "Session expired or unauthorized.": "工作階段已過期或未經授權。",
+ "Sign out": "Sign out",
+ "Status": "狀態",
+ "Stock Qty": "庫存數量",
+ "Supporting Document": "證明文件",
+ "Task": "任務",
+ "Time Sequence": "時段",
+ "Today": "今天",
+ "Total weighting must equal 1": "權重總和必須等於 1",
+ "Unauthorized: Please log in again": "未經授權:請重新登入",
+ "Uom": "單位",
+ "Update Failed": "更新失敗",
+ "Update Success": "更新成功",
+ "Weighting must be a number": "權重必須為數字",
+ "Yes": "是",
+ "Yesterday": "昨天",
+ "all": "全部",
+ "bomWeighting": "BOM Weighting Score",
+ "cmb": "消耗品",
+ "collapsible table": "可折疊表格",
+ "consumable": "消耗品",
+ "consumables": "消耗品",
+ "create": "新增",
+ "edit": "編輯",
+ "expand row": "展開行",
+ "group mode": "群組模式",
+ "item": "貨品",
+ "items": "物品",
+ "mat": "原料",
+ "menu": "選單",
+ "nm": "雜項及非消耗品",
+ "non-consumables": "非消耗品",
+ "other": "其他",
+ "profile": "個人資料",
+ "revert": "還原",
+ "settings": "設定",
+ "stockRecord": "盤點記錄",
+ "stocktakemanagement": "盤點管理",
+ "testing sections tabs": "測試區域分頁",
+ "warehouse": "倉庫",
+ "材料": "材料"
+}
diff --git a/src/i18n/en/dashboard.json b/src/i18n/en/dashboard.json
index c45c20f..fc5c351 100644
--- a/src/i18n/en/dashboard.json
+++ b/src/i18n/en/dashboard.json
@@ -1,129 +1,137 @@
{
- "Dashboard": "Dashboard",
- "Order status": "Order status",
- "pending": "pending",
- "receiving": "receiving",
- "total": "total",
- "Warehouse temperature record": "Warehouse temperature record",
- "Warehouse type": "Warehouse type",
- "Last 6 hours": "Last 6 hours",
"Add some entries!": "Add some entries!",
- "Last 24 hours": "Last 24 hours",
+ "All": "All",
+ "All Stores": "All Stores",
+ "Allow to select Date to view history.": "Allow to select Date to view history.",
+ "Application completion": "Application completion",
+ "Auto-refresh every 1 minute": "Auto-refresh every 1 minute",
+ "Auto-refresh every 10 minutes": "Auto-refresh every 10 minutes",
+ "Auto-refresh every 15 minutes": "Auto-refresh every 15 minutes",
+ "Auto-refresh every 5 minutes": "Auto-refresh every 5 minutes",
+ "Based on Expected Delivery Date": "Based on Expected Delivery Date",
"Cold storage": "Cold storage",
- "Normal temperature storage": "Normal temperature storage",
- "Temperature status": "Temperature status",
+ "Column 1": "Column 1",
+ "Column 2": "Column 2",
+ "Column 3": "Column 3",
+ "Completed QC Total": "Completed QC Total",
+ "Consumable": "Consumable",
+ "Count any item with IQC defect in any IQC criteria": "Count any item with IQC defect in any IQC criteria",
+ "DN Date": "DN Date",
+ "Dashboard": "Dashboard",
+ "dashboard": "Dashboard",
+ "dashboard tabs": "Dashboard tabs",
+ "Date": "Date",
+ "Day After Tomorrow": "Day After Tomorrow",
+ "Escalation Level": "Escalation Level",
+ "Escalation List": "Escalation List",
+ "Exit Screen": "Exit Screen",
+ "Expected No. of Delivery": "Expected No. of Delivery",
+ "Extracted order": "Extracted order",
+ "Filter": "Filter",
+ "First Ticket Start": "First Ticket Start",
+ "Goods Receipt Status": "Goods Receipt Status",
+ "Goods Receipt Status New": "Goods Receipt Status",
+ "Humidity": "Humidity",
"Humidity status": "Humidity status",
- "Warehouse status": "Warehouse status",
- "Progress chart": "Progress chart",
- "Purchase Order Code": "Purchase Order Code",
"Item Name": "Item Name",
- "Escalation Level": "Escalation Level",
- "Reason": "Reason",
- "escalated date": "escalated date",
+ "Last 24 hours": "Last 24 hours",
+ "Last 6 hours": "Last 6 hours",
+ "Last Ticket End": "Last Ticket End",
+ "Last updated": "Last updated",
+ "My Escalation List": "My Escalation List",
+ "No": "No",
+ "No data available": "No data available",
+ "No truck schedules available": "No truck schedules available",
+ "Overview": "Overview",
+ "No truck schedules available for today": "No truck schedules available for today",
+ "No. of Items Completed Put Away at Store": "No. of Items Completed Put Away at Store",
+ "No. of Items Inspected": "No. of Items Inspected",
+ "No. of Items with IQC Issue": "No. of Items with IQC Issue",
+ "No. of Orders Received at Dock": "No. of Orders Received at Dock",
+ "No. of Shops": "No. of Shops",
+ "Normal temperature storage": "Normal temperature storage",
+ "Now": "Now",
"Order completion": "Order completion",
- "Store Management": "Store Management",
- "Consumable": "Consumable",
- "Shipment": "Shipment",
- "Extracted order": "Extracted order",
+ "Order status": "Order status",
+ "Pending application": "Pending application",
"Pending order": "Pending order",
- "Temperature": "Temperature",
- "Humidity": "Humidity",
"Pending storage": "Pending storage",
- "Total storage": "Total storage",
- "Application completion": "Application completion",
- "Processed application": "Processed application",
- "Pending application": "Pending application",
- "pending inspection material": "pending inspection material",
- "rejected": "rejected",
- "accepted": "accepted",
- "escalated": "escalated",
- "inspected material": "inspected material",
- "total material": "total material",
- "stock in escalation list": "stock in escalation list",
- "Responsible for handling colleagues": "Responsible for handling colleagues",
- "Completed QC Total": "Completed QC Total",
- "QC Fail Count": "QC Fail Count",
- "DN Date": "DN Date",
- "Received Qty": "Received Qty",
+ "Pick Time (min)": "Pick Time (min)",
"Po Code": "Po Code",
- "My Escalation List": "My Escalation List",
- "Escalation List": "Escalation List",
+ "Po Code/Jo Code": "Po Code/Jo Code",
+ "Processed application": "Processed application",
+ "Progress chart": "Progress chart",
+ "Purchase Order Code": "Purchase Order Code",
"Purchase UoM": "Purchase UoM",
"QC Completed Count": "QC Completed Count",
+ "QC Fail Count": "QC Fail Count",
"QC Fail-Total Count": "QC Fail-Total Count",
- "escalationStatus": "escalationStatus",
- "escalated datetime": "escalated datetime",
- "escalateFrom": "escalateFrom",
- "No": "No",
+ "Reason": "Reason",
+ "Received Qty": "Received Qty",
"Responsible Escalation List": "Responsible Escalation List",
- "show completed logs": "show completed logs",
+ "Responsible for handling colleagues": "Responsible for handling colleagues",
+ "Restore Screen": "Restore Screen",
"Rows per page": "Rows per page",
- "Truck Schedule Dashboard": "Truck Schedule Dashboard",
+ "Screen cleared": "Screen cleared",
+ "Select Date": "Select Date",
+ "Shipment": "Shipment",
+ "Show Purchase Order Codes": "Show Purchase Order Codes",
+ "Show Supplier Code": "Show Supplier Code",
+ "Show Supplier Name": "Show Supplier Name",
+ "Statistics": "Statistics",
+ "Status": "Status",
"Store ID": "Store ID",
- "All Stores": "All Stores",
- "Auto-refresh every 5 minutes": "Auto-refresh every 5 minutes",
- "Last updated": "Last updated",
- "Truck Schedule": "Truck Schedule",
- "Time Remaining": "Time Remaining",
- "No. of Shops": "No. of Shops",
- "Total Items": "Total Items",
- "Tickets Released": "Tickets Released",
- "First Ticket Start": "First Ticket Start",
+ "Store Management": "Store Management",
+ "Supplier": "Supplier",
+ "Supplier Code": "Supplier Code",
+ "Supplier Name": "Supplier Name",
+ "Temperature": "Temperature",
+ "Temperature status": "Temperature status",
"Tickets Completed": "Tickets Completed",
- "Last Ticket End": "Last Ticket End",
- "Pick Time (min)": "Pick Time (min)",
- "No truck schedules available for today": "No truck schedules available for today",
- "No truck schedules available": "No truck schedules available",
- "Select Date": "Select Date",
+ "Tickets Released": "Tickets Released",
+ "Time": "Time",
+ "Time Remaining": "Time Remaining",
+ "Two column navigable table": "Two column navigable table",
"Today": "Today",
"Tomorrow": "Tomorrow",
- "Day After Tomorrow": "Day After Tomorrow",
- "Goods Receipt Status": "Goods Receipt Status",
- "Date": "Date",
- "Time": "Time",
- "Allow to select Date to view history.": "Allow to select Date to view history.",
- "Auto-refresh every 15 minutes": "Auto-refresh every 15 minutes",
- "Exit Screen": "Exit Screen",
- "Restore Screen": "Restore Screen",
- "Screen cleared": "Screen cleared",
- "Supplier": "Supplier",
- "Expected No. of Delivery": "Expected No. of Delivery",
- "No. of Orders Received at Dock": "No. of Orders Received at Dock",
- "No. of Items Inspected": "No. of Items Inspected",
- "No. of Items with IQC Issue": "No. of Items with IQC Issue",
- "No. of Items Completed Put Away at Store": "No. of Items Completed Put Away at Store",
- "Show Supplier Name": "Show Supplier Name",
- "Based on Expected Delivery Date": "Based on Expected Delivery Date",
- "Upon entry of DN and Lot No. for all items of the order": "Upon entry of DN and Lot No. for all items of the order",
+ "Total Items": "Total Items",
+ "Total storage": "Total storage",
+ "Truck Schedule": "Truck Schedule",
+ "Truck Schedule Dashboard": "Truck Schedule Dashboard",
"Upon any IQC decision received": "Upon any IQC decision received",
- "Count any item with IQC defect in any IQC criteria": "Count any item with IQC defect in any IQC criteria",
"Upon completion of put away for an material in order. Count no. of items being put away": "Upon completion of put away for an material in order. Count no. of items being put away",
- "Filter": "Filter",
- "All": "All",
- "Column 1": "Column 1",
- "Column 2": "Column 2",
- "Column 3": "Column 3",
- "No data available": "No data available",
- "Supplier Code": "Supplier Code",
- "Supplier Name": "Supplier Name",
- "Purchase Order Code": "Purchase Order Code",
- "Statistics": "Statistics",
- "Show Supplier Code": "Show Supplier Code",
- "Show Purchase Order Codes": "Show Purchase Order Codes",
- "x/y orders received": "x/y orders received",
- "Goods Receipt Status New": "Goods Receipt Status",
+ "Upon entry of DN and Lot No. for all items of the order": "Upon entry of DN and Lot No. for all items of the order",
"Usage statistics": "Usage statistics",
"Usage stats description": "Report management and truck routing summary: page views, downloads, and direct prints.",
- "Usage stats report section": "Report management (報告管理)",
- "Usage stats truck routing section": "Truck routing summary (送貨路線摘要)",
- "Usage stats user": "User",
- "Usage stats page views": "Page views",
"Usage stats downloads": "Downloads",
+ "Usage stats end date": "End date",
+ "Usage stats invalid date range": "Start date must be earlier than or equal to end date.",
+ "Usage stats load error": "Could not load usage statistics.",
+ "Usage stats page views": "Page views",
"Usage stats prints": "Direct prints",
"Usage stats refresh": "Refresh",
- "Usage stats load error": "Could not load usage statistics.",
- "Usage stats start date": "Start date",
- "Usage stats end date": "End date",
+ "Usage stats report section": "Usage stats report section",
"Usage stats search": "Search",
- "Usage stats invalid date range": "Start date must be earlier than or equal to end date."
+ "Usage stats start date": "Start date",
+ "Usage stats truck routing section": "Usage stats truck routing section",
+ "Usage stats user": "User",
+ "Warehouse status": "Warehouse status",
+ "Warehouse temperature record": "Warehouse temperature record",
+ "Warehouse type": "Warehouse type",
+ "accepted": "accepted",
+ "escalateFrom": "escalateFrom",
+ "escalated": "escalated",
+ "escalated date": "escalated date",
+ "escalated datetime": "escalated datetime",
+ "escalationStatus": "escalationStatus",
+ "inspected material": "inspected material",
+ "pending": "pending",
+ "pending inspection material": "pending inspection material",
+ "receiving": "receiving",
+ "rejected": "rejected",
+ "show completed logs": "show completed logs",
+ "stock in escalation list": "stock in escalation list",
+ "total": "total",
+ "total material": "total material",
+ "x/y orders received": "x/y orders received"
}
diff --git a/src/i18n/en/deliveryOrderFloor.json b/src/i18n/en/deliveryOrderFloor.json
index addd841..3fd6f02 100644
--- a/src/i18n/en/deliveryOrderFloor.json
+++ b/src/i18n/en/deliveryOrderFloor.json
@@ -1,6 +1,6 @@
{
"title": "Delivery order / workbench floor (supplier codes)",
- "Intro": "Comma-separated supplier codes in system settings. Use edit to change; DO behavior depends on backend reading these keys.",
+ "Intro": "Manage supplier codes assigned to each floor. Use the edit button to add or remove suppliers from a floor.",
"2F supplier": "2F supplier",
"4F supplier": "4F supplier",
"Edit 2F": "Edit 2F",
@@ -29,5 +29,6 @@
"Comma separated hint": "Separate codes with commas, no spaces",
"Save": "Save",
"Saved": "Saved",
- "Cancel": "Cancel"
+ "Cancel": "Cancel",
+ "DO floor (supplier)": "DO floor (supplier)"
}
diff --git a/src/i18n/en/demandForecast.json b/src/i18n/en/demandForecast.json
new file mode 100644
index 0000000..988fe7b
--- /dev/null
+++ b/src/i18n/en/demandForecast.json
@@ -0,0 +1,12 @@
+{
+ "Demand Forecast Setting": "Demand Forecast Setting",
+ "Exclude Date": "Exclude Date",
+ "Finished Goods Name": "Finished Goods Name",
+ "Mon": "Mon",
+ "Tue": "Tue",
+ "Wed": "Wed",
+ "Thu": "Thu",
+ "Fri": "Fri",
+ "Sat": "Sat",
+ "Sun": "Sun"
+}
diff --git a/src/i18n/en/detailScheduling.json b/src/i18n/en/detailScheduling.json
new file mode 100644
index 0000000..6abb2ab
--- /dev/null
+++ b/src/i18n/en/detailScheduling.json
@@ -0,0 +1,21 @@
+{
+ "Client Name": "Client Name",
+ "Demand Forecast Period": "Demand Forecast Period",
+ "Detail Scheduling": "Detail Scheduling",
+ "Details": "Details",
+ "Product": "Product",
+ "Product Count": "Product Count",
+ "Product Count(s)": "Product Count(s)",
+ "Project Category": "Project Category",
+ "Project Code": "Project Code",
+ "Project Name": "Project Name",
+ "Project Status": "Project Status",
+ "Project Type": "Project Type",
+ "Reset": "Reset",
+ "Schedule Period": "Schedule Period",
+ "Scheduled At": "Scheduled At",
+ "Search": "Search",
+ "Search Criteria": "Search Criteria",
+ "Search by Project Code or Project Name or Client Name or Project Category or Project Type or Project Status or Project Start Date or Project End Date": "Search by Project Code or Project Name or Client Name or Project Category or Project Type or Project Status or Project Start Date or Project End Date",
+ "types": "types"
+}
diff --git a/src/i18n/en/do.json b/src/i18n/en/do.json
new file mode 100644
index 0000000..12467ab
--- /dev/null
+++ b/src/i18n/en/do.json
@@ -0,0 +1,91 @@
+{
+ "Action": "Action",
+ "An error has occurred. Please try again later.": "An error has occurred. Please try again later.",
+ "Assign 2/F": "Assign 2/F",
+ "Assign 4/F": "Assign 4/F",
+ "Available Orders": "Available Orders",
+ "Available Trucks": "Available Trucks",
+ "Back": "Back",
+ "Batch Release": "Batch Release",
+ "Batch release completed successfully.": "Batch release completed successfully.",
+ "Cancel": "Cancel",
+ "Code": "Code",
+ "Completed": "Completed",
+ "Confirm": "Confirm",
+ "Confirm Assignment": "Confirm Assignment",
+ "Create": "Create",
+ "DO Workbench": "DO Workbench",
+ "DO released successfully! Pick orders created.": "DO released successfully! Pick orders created.",
+ "Delete": "Delete",
+ "Delivery Order": "Delivery Order",
+ "Delivery Order Code": "Delivery Order Code",
+ "Delivery Order Date": "Delivery Order Date",
+ "Delivery Order No.": "Delivery Order No.",
+ "Delivery Order Status": "Delivery Order Status",
+ "Details": "Details",
+ "Do Workbench": "Do Workbench",
+ "Edit": "Edit",
+ "Edit Delivery Order Detail": "Edit Delivery Order Detail",
+ "Estimated Arrival": "Estimated Arrival",
+ "Estimated Arrival Date": "Estimated Arrival Date",
+ "Estimated Arrival From": "Estimated Arrival From",
+ "Estimated Arrival To": "Estimated Arrival To",
+ "Etra": "Etra",
+ "Expiry Date": "Expiry Date",
+ "Failed to assign pick orders. Please try again later.": "Failed to assign pick orders. Please try again later.",
+ "Failed to release pick orders. Please try again later.": "Failed to release pick orders. Please try again later.",
+ "Fetching all matching records...": "Fetching all matching records...",
+ "Floor": "Floor",
+ "Item Name": "Item Name",
+ "Item No.": "Item No.",
+ "Just Complete": "Just Complete",
+ "Just Completed": "Just Completed",
+ "Lane Code": "Lane Code",
+ "Loading...": "Loading...",
+ "Location": "Location",
+ "Lot No.": "Lot No.",
+ "No trucks available": "No trucks available",
+ "Order Date": "Order Date",
+ "Order Date From": "Order Date From",
+ "Order Date To": "Order Date To",
+ "Pending": "Pending",
+ "Pick Order Assignment": "Pick Order Assignment",
+ "Please wait": "Please wait",
+ "Price": "Price",
+ "Problem DO(s): ": "Problem DO(s): ",
+ "Progress": "Progress",
+ "Quantity": "Quantity",
+ "Receiving": "Receiving",
+ "Release": "Release",
+ "Release 2/F": "Release 2/F",
+ "Release 4/F": "Release 4/F",
+ "Releasing": "Releasing",
+ "Remark": "Remark",
+ "Required Date": "Required Date",
+ "Select Remark": "Select Remark",
+ "Selected Item(s): ": "Selected Item(s): ",
+ "Selected Shop(s): ": "Selected Shop(s): ",
+ "Shop Code": "Shop Code",
+ "Shop Name": "Shop Name",
+ "Status": "Status",
+ "Stock Available": "Stock Available",
+ "Stock Status": "Stock Status",
+ "Delivery": "Delivery",
+ "Store": "Store",
+ "Submit Miss Item": "Submit Miss Item",
+ "Submit Qty": "Submit Qty",
+ "Submit Quantity": "Submit Quantity",
+ "Supplier Code": "Supplier Code",
+ "Supplier Name": "Supplier Name",
+ "Truck Availability Warning": "Truck Availability Warning",
+ "Truck Lance Code": "Truck Lance Code",
+ "Truck X": "Truck X",
+ "Truck lane search requires date message": "Truck lane search requires date message",
+ "Truck lane search requires date title": "Truck lane search requires date title",
+ "Warning: Some delivery orders do not have matching trucks for the target date.": "Warning: Some delivery orders do not have matching trucks for the target date.",
+ "Workbench Batch Release": "Workbench Batch Release",
+ "code": "code",
+ "do workbench": "do workbench",
+ "row selected": "row selected",
+ "uom": "uom"
+}
diff --git a/src/i18n/en/doWorkbench.json b/src/i18n/en/doWorkbench.json
new file mode 100644
index 0000000..321a91a
--- /dev/null
+++ b/src/i18n/en/doWorkbench.json
@@ -0,0 +1,49 @@
+{
+ "Actions": "Actions",
+ "All Pick Order Lots": "All Pick Order Lots",
+ "Auto-refresh every 5 minutes": "Auto-refresh every 5 minutes",
+ "Back to List": "Back to List",
+ "Cancel": "Cancel",
+ "Completed": "Completed",
+ "Confirm": "Confirm",
+ "DO Workbench": "DO Workbench",
+ "Delivery Order": "Delivery Order",
+ "Departure Time": "Departure Time",
+ "Edit": "Edit",
+ "Edit Delivery Order Detail": "Edit Delivery Order Detail",
+ "Floor": "Floor",
+ "Handler": "Handler",
+ "Issue": "Issue",
+ "Item Code": "Item Code",
+ "Item Name": "Item Name",
+ "Last updated": "Last updated",
+ "Loading Sequence": "Loading Sequence",
+ "Location": "Location",
+ "Lot No": "Lot No",
+ "Lot Required Pick Qty": "Lot Required Pick Qty",
+ "No data available": "No data available",
+ "Now": "Now",
+ "Pick Order": "Pick Order",
+ "Pick Order Code": "Pick Order Code",
+ "Required Qty": "Required Qty",
+ "Rows per page": "Rows per page",
+ "Scan Result": "Scan Result",
+ "Search date": "Search date",
+ "Select Date": "Select Date",
+ "Shop": "Shop",
+ "Shop Name": "Shop Name",
+ "Start QR Scan": "Start QR Scan",
+ "Status": "Status",
+ "Stop QR Scan": "Stop QR Scan",
+ "Store ID": "Store ID",
+ "Submitting...": "Submitting...",
+ "Target Date": "Target Date",
+ "This lot is rejected, please scan another lot.": "This lot is rejected, please scan another lot.",
+ "Today": "Today",
+ "Truck Information": "Truck Information",
+ "View Details": "View Details",
+ "DO Workbench Search": "DO Workbench Search",
+ "completed": "completed",
+ "items": "items",
+ "pending": "pending"
+}
diff --git a/src/i18n/en/equipment.json b/src/i18n/en/equipment.json
new file mode 100644
index 0000000..fee9996
--- /dev/null
+++ b/src/i18n/en/equipment.json
@@ -0,0 +1,21 @@
+{
+ "Create Material": "Create Material",
+ "Equipment": "Equipment",
+ "Equipment Type": "Equipment Type",
+ "Update Equipment Maintenance and Repair": "Update Equipment Maintenance and Repair",
+ "Create Equipment": "Create Equipment",
+ "Edit Equipment": "Edit Equipment",
+ "Create Equipment Type": "Create Equipment Type",
+ "Edit Equipment Type": "Edit Equipment Type",
+ "Equipment Information": "Equipment Information",
+ "Equipment Name": "Equipment Name",
+ "Equipment Code": "Equipment Code",
+ "Equipment Details": "Equipment Details",
+ "Equipment Type Details": "Equipment Type Details",
+ "Equipment not found": "Equipment not found",
+ "Last Repair and Maintenance Date": "Last Repair and Maintenance Date",
+ "Latest Repair and Maintenance Date": "Latest Repair and Maintenance Date",
+ "Repair and Maintenance": "Repair and Maintenance",
+ "Repair and Maintenance Remarks": "Repair and Maintenance Remarks",
+ "Repair and Maintenance Status": "Repair and Maintenance Status"
+}
diff --git a/src/i18n/en/finishedGood.json b/src/i18n/en/finishedGood.json
new file mode 100644
index 0000000..6792d27
--- /dev/null
+++ b/src/i18n/en/finishedGood.json
@@ -0,0 +1,4 @@
+{
+ "Finished Good Order": "Finished Good Order",
+ "Finished Good Detail": "Finished Good Detail"
+}
diff --git a/src/i18n/en/finishedgoodmanagement.json b/src/i18n/en/finishedgoodmanagement.json
new file mode 100644
index 0000000..9d77f11
--- /dev/null
+++ b/src/i18n/en/finishedgoodmanagement.json
@@ -0,0 +1,38 @@
+{
+ "Finished Good Management": "Finished Good Management",
+ "提料順序": "Pick Order Sequence",
+ "Item Code": "Item Code",
+ "Item Name": "Item Name",
+ "Search & Jump": "Search & Jump",
+ "Jump": "Jump",
+ "Move Up": "Move Up",
+ "Move Down": "Move Down",
+ "Move Top": "Move to Top",
+ "Move Bottom": "Move to Bottom",
+ "Add Item": "Add Item",
+ "Saving": "Saving",
+ "Save": "Save",
+ "Refresh": "Reload",
+ "Unsaved changes": "Unsaved changes",
+ "Order": "Order",
+ "Code": "Code",
+ "Name": "Name",
+ "Shipping Warehouse": "Shipping Warehouse",
+ "Receiving Warehouse": "Receiving Warehouse",
+ "Actions": "Actions",
+ "Loading": "Loading...",
+ "No data available": "No data available",
+ "Insert": "Insert",
+ "Search": "Search",
+ "Insert at": "Insert at",
+ "Insert position must be >= 1": "Insert position must be >= 1",
+ "Order number": "Order number",
+ "In front of": "In front of",
+ "Behind": "Behind",
+ "Only show FG items without order": "Enter a keyword to search (only items without sequence)",
+ "Cancel": "Cancel",
+ "Confirm": "Confirm",
+ "Move to order": "Move to 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"
+}
diff --git a/src/i18n/en/home.json b/src/i18n/en/home.json
new file mode 100644
index 0000000..5f5738d
--- /dev/null
+++ b/src/i18n/en/home.json
@@ -0,0 +1,4 @@
+{
+ "Add some entries!": "Add some entries!",
+ "Demand Qty": "Demand Qty"
+}
diff --git a/src/i18n/en/importBom.json b/src/i18n/en/importBom.json
new file mode 100644
index 0000000..a570fc4
--- /dev/null
+++ b/src/i18n/en/importBom.json
@@ -0,0 +1,12 @@
+{
+ "Create Material": "Create Material",
+ "Update Equipment Maintenance and Repair": "Update Equipment Maintenance and Repair",
+ "Correct BOM List (Can Import)": "Correct BOM List (Can Import)",
+ "Issue BOM List": "Issue BOM List",
+ "Loading BOM Detail...": "Loading BOM Detail...",
+ "Bom Material": "Bom Material",
+ "Is Drink": "Is Drink",
+ "Drink": "Drink",
+ "Powder_Mixture": "Powder Mixture",
+ "Base Score": "Base Score"
+}
diff --git a/src/i18n/en/importExcel.json b/src/i18n/en/importExcel.json
new file mode 100644
index 0000000..14388f3
--- /dev/null
+++ b/src/i18n/en/importExcel.json
@@ -0,0 +1,15 @@
+{
+ "title": "Excel File Import",
+ "Download Template": "Download Template",
+ "Download failed": "Download failed",
+ "Downloading...": "Downloading...",
+ "File Name": "File Name",
+ "No Import Record": "No Import Record",
+ "Upload": "Upload",
+ "Upload completed with count": "{{count}} item(s) updated",
+ "Upload failed": "Upload failed",
+ "Upload row errors": "Upload row errors",
+ "Upload successful": "Upload successful",
+ "Uploading...": "Uploading...",
+ "item(s) updated": "item(s) updated"
+}
diff --git a/src/i18n/en/inventory.json b/src/i18n/en/inventory.json
index 81e3feb..1bb7e57 100644
--- a/src/i18n/en/inventory.json
+++ b/src/i18n/en/inventory.json
@@ -1,56 +1,206 @@
{
- "Stock transfer successful": "Stock transfer completed",
- "Stock transfer merged ambiguous": "Merged into the earliest available batch (multiple available lines for the same lot).",
- "Stock transfer merged existing lot": "Stock transfer completed (merged into existing lot).",
- "Stock transfer created new lot": "Stock transfer completed (created new lot line).",
- "Average unit price": "Average unit price",
- "Latest market unit price": "Latest market unit price",
+ "-{{Variance}}≤Variance Percentage ≤{{Variance}} will be filtered out": "-{{Variance}}≤Variance Percentage ≤{{Variance}} will be filtered out",
+ "AVAILABLE": "AVAILABLE",
+ "Action": "Action",
+ "Add": "Add",
+ "Add entry": "Add entry",
"Add entry for items without inventory": "Add entry for items without inventory",
- "Enter item code or name to search": "Enter item code or name to search",
+ "Adjusted Qty": "Adjusted Qty",
+ "Approve": "Approve",
+ "Approver All": "Approver All",
+ "Approver search empty hint": "Set search criteria and click Search",
+ "ApproverAll": "ApproverAll",
+ "Available": "Available",
+ "Available Qty": "Available Qty",
+ "Available Qty Per Smallest Unit": "Available Qty Per Smallest Unit",
+ "Average unit price": "Average unit price",
+ "Back": "Back",
+ "Bad Item Handle": "Bad Item Handle",
+ "Bad Item Qty": "Bad Item Qty",
+ "Bad Item Records": "Bad Item Records",
+ "Balance Qty": "Balance Qty",
+ "Base UoM": "Base UoM",
+ "Batch Save Completed": "Batch Save Completed",
+ "Batch Save Inputted": "Batch Save Inputted",
+ "Batch Submit All": "Batch Submit All",
+ "Batch approver save completed: {{success}} success, {{skipped}} skipped, {{errors}} errors": "Batch approver save completed: {{success}} success, {{skipped}} skipped, {{errors}} errors",
+ "Body is unavailable": "Body is unavailable",
+ "Bom Req. Qty": "Bom Req. Qty",
+ "CMB": "Consumables",
+ "CO": "Consumables",
+ "Clear selection": "Clear selection",
+ "Code": "Code",
+ "Collapse floor sections": "Collapse sections for this floor",
+ "Confirm Adjustment": "Confirm Adjustment",
+ "Confirm create stock take for all sections?": "Confirm create stock take for all sections?",
+ "Confirm remove": "Confirm remove",
+ "Counted Qty": "Counted Qty",
+ "Create Stock Take for All Sections": "Create Stock Take for All Sections",
"Current Stock": "Current Stock",
+ "Delivery Order": "Delivery Order",
+ "Difference": "Difference",
+ "Download QR Code": "Download QR Code",
+ "Edit mode": "Edit mode",
+ "End Date": "End Date",
+ "Enter item code or name to search": "Enter item code or name to search",
+ "Expand floor sections": "Expand sections for this floor",
+ "Expiry Date": "Expiry Date",
+ "Expiry End Date": "Expiry End Date",
+ "Expiry Item Handle": "Expiry Item Handle",
+ "Expiry Item Qty": "Expiry Item Qty",
+ "Expiry Item Records": "Expiry Item Records",
+ "Expiry Qty": "Expiry Qty",
+ "Expiry Start Date": "Expiry Start Date",
+ "FG": "Finished good",
+ "Failed to transfer stock": "Failed to transfer stock",
+ "Failed to transfer stock. Please try again.": "Failed to transfer stock. Please try again.",
+ "Filtered out": "Filtered out",
+ "First Qty": "First Qty",
+ "Handled Date": "Handled Date",
+ "Handler": "Handler",
+ "Hide Search Filters": "Hide Search Filters",
+ "In Qty": "In Qty",
+ "Input": "Input",
+ "Invalid QTY": "Invalid quantity",
+ "Inventory": "Inventory",
+ "Inventory Exception Management": "Inventory Exception Management",
+ "Item Name": "Item Name",
+ "Item selected": "Item selected",
+ "Item-lotNo": "Item-lotNo",
+ "Job Order": "Job Order",
+ "Latest market unit price": "Latest market unit price",
+ "Loading": "Loading",
+ "Lot No": "Lot No",
+ "MA": "Material",
+ "MI": "Miscellaneous",
+ "Material": "Material",
+ "NM": "Miscellaneous / non-consumables",
+ "Name": "Name",
+ "No Data": "No Data",
+ "No changes to submit": "No changes to submit",
+ "No issues found": "No issues found",
+ "No items are selected yet.": "No items are selected yet.",
+ "No lot no entered, will be generated by system.": "No lot no entered, will be generated by system.",
+ "No record found": "No record found",
+ "Opening Inventory": "Opening Inventory",
+ "Optional - system will generate": "Optional - system will generate",
+ "Original Qty": "Original Qty",
+ "Out Qty": "Out Qty",
+ "Perform Stock Take": "Perform Stock Take",
+ "Pick Order, Issue No, Item, Lot...": "Pick Order, Issue No, Item, Lot...",
+ "Please enter QTY and Bad QTY": "Please enter QTY and Bad QTY",
+ "Please scan...": "Please scan...",
"Please set at least one search criterion": "Please set at least one search criterion",
- "Approver search empty hint": "Set search criteria and click Search",
- "Saved successfully": "Saved successfully",
- "Save failed": "Save failed",
+ "Print": "Print",
+ "Print QR Code": "Print QR Code",
+ "Print Qty": "Print Qty",
+ "Print failed": "Print failed",
+ "Print sent": "Print sent",
+ "Printer": "Printer",
+ "Qty": "Qty",
+ "Qty To Be Transferred": "Qty To Be Transferred",
+ "Quantity exceeds available quantity": "Quantity exceeds available quantity",
+ "RM": "Raw material",
+ "Reason for adjustment": "Reason for adjustment",
+ "Reason for removal": "Reason for removal",
+ "Refresh": "Refresh",
+ "Remaining Qty": "Remaining Qty",
+ "Remarks": "Remarks",
"Remove": "Remove",
- "Create Stock Take (Select Sections)": "Create stock take (select sections)",
- "Select stock take sections to create hint": "Choose warehouse stock take sections to start a new round (selected sections share one new round id in this batch).",
- "Stock take round name": "Stock take round name",
- "Stock take round name placeholder": "Optional, e.g. May full-site stock take",
- "Select sections placeholder": "Select one or more",
+ "Resolved": "Resolved",
+ "Review Variance": "Review Variance",
+ "Rows per page": "Rows per page",
+ "SFG": "Semi-finished good",
+ "Sales UoM": "Sales UoM",
+ "Save failed": "Save failed",
+ "Saved successfully": "Saved successfully",
+ "Search lot by QR code": "Search lot by QR code",
+ "Search to load lot lines": "Search to load lot lines",
+ "Second Qty": "Second Qty",
+ "Select": "Select",
+ "Select Section": "Select Section",
+ "Select Stock Take Section": "Select Stock Take Section",
"Select all sections": "Select all sections",
- "Clear selection": "Clear selection",
+ "Select sections placeholder": "Select one or more",
+ "Select stock take sections to create hint": "Choose warehouse stock take sections to start a new round (selected sections share one new round id in this batch).",
"Selected section count": "Selected: {{count}} section(s)",
- "Floor unassigned": "Unassigned floor",
- "No stock take sections from warehouse": "No stock take sections returned from warehouse.",
- "Expand floor sections": "Expand sections for this floor",
- "Collapse floor sections": "Collapse sections for this floor",
- "Select all on this floor": "Select all on this floor ({{floor}})",
- "Deselect all on this floor": "Deselect all on this floor ({{floor}})",
- "Creation date": "Creation date",
- "Floor area selection header": "{{floor}} area selection ({{count}} areas)",
- "Search section code or name": "Search code or name (e.g. ST-042 or drinks)",
- "Select all sections all floors": "Select all areas (all floors)",
- "Clear selection all floors": "Clear selection (all floors)",
- "Total selected sections label": "Total selected:",
- "sections unit": "area(s)",
- "No sections match search": "No areas match your search",
- "Variance filter inclusive only": "Show only rows within variance range",
+ "Show Search Filters": "Show Search Filters",
+ "Something went wrong fetching data in server.": "Something went wrong fetching data in server.",
+ "Start Date": "Start Date",
+ "Start Location": "Start Location",
+ "Start New Stock Take": "Start New Stock Take",
+ "Start Time": "Start Time",
+ "Stock Adjustment": "Stock Adjustment",
+ "Stock Record": "Stock Record",
+ "Stock Take Variance": "Stock Take Variance",
+ "Stock Transfer": "Stock Transfer",
+ "Stock UoM": "Stock UoM",
+ "Stock take adjustment confirmed! (Demo only)": "Stock take adjustment confirmed! (Demo only)",
+ "Stock take adjustment has been confirmed successfully!": "Stock take adjustment has been confirmed successfully!",
+ "Stock take qty exceeds maximum": "Stock take quantity cannot exceed 999,999,999,999",
+ "Stock transfer created new lot": "Stock transfer completed (created new lot line).",
+ "Stock transfer merged ambiguous": "Merged into the earliest available batch (multiple available lines for the same lot).",
+ "Stock transfer merged existing lot": "Stock transfer completed (merged into existing lot).",
+ "Stock transfer successful": "Stock transfer completed",
+ "Stop QR Scan": "Stop QR Scan",
+ "Submit": "Submit",
+ "Submit completed: {{success}} success, {{errors}} errors": "Submit completed: {{success}} success, {{errors}} errors",
+ "System Qty": "System Qty",
+ "Target Location": "Target Location",
+ "Total Approved": "Total Approved",
+ "Total Issues": "Total Issues",
+ "Total Item Number": "Total Item Number",
+ "Total Stock Takes": "Total Stock Takes",
+ "Total need stock take": "Total need stock take",
+ "Type": "Type",
+ "UNAVAILABLE": "UNAVAILABLE",
"Variance filter strict bounds": "Exclude boundaries (use > <)",
- "Variance filter exclusive range hint": "Show rows with -{{value}}% {{op}} variance % {{op}} {{value}}% (outside range, server-filtered)",
- "Variance filter inclusive range hint": "Show rows with -{{value}}% {{op}} variance % {{op}} {{value}}% (within range)",
- "Confirm batch save approver": "Confirm batch save",
- "Batch save confirm message": "Batch save {{count}} stock take record(s) in the current list. Continue?",
- "Stock take sections in current list": "{{count}} stock take section(s) in current list",
- "Confirm create stock take": "Confirm create stock take",
- "Not filled": "(not filled)",
- "Warehouse missing stock take section warn title": "Warehouses without stock take section",
- "Warehouse missing stock take section tooltip has": "{{count}} warehouse location(s) missing stock take section — click to view",
- "Warehouse missing stock take section tooltip none": "All warehouses have a stock take section",
- "Warehouse missing stock take section drawer hint": "These locations have no stock take section (ST-xxx) and cannot be included in stock take. Fix in warehouse settings.",
- "Warehouse missing stock take section go settings": "Go to warehouse settings",
- "Warehouse missing stock take section showing": "Showing {{shown}} of {{count}}",
- "Warehouse missing stock take section empty": "No warehouses missing stock take section",
- "Invalid QTY": "Invalid quantity",
- "Stock take qty exceeds maximum": "Stock take quantity cannot exceed 999,999,999,999"
-}
\ No newline at end of file
+ "View": "View",
+ "WIP": "Work in progress",
+ "Waiting for Approver": "Waiting for Approver",
+ "Warehouse": "Warehouse",
+ "adj": "adj",
+ "approver": "approver",
+ "approving": "approving",
+ "available": "available",
+ "bad": "bad",
+ "cmb": "Consumables",
+ "complete": "complete",
+ "completed": "completed",
+ "completed by": "completed by",
+ "completed date": "completed date",
+ "completed remarks": "completed remarks",
+ "completed status": "completed status",
+ "consumable": "Consumable",
+ "consumables": "Consumables",
+ "dnNo": "dnNo",
+ "expiry": "expiry",
+ "fg": "Finished good",
+ "item": "Item",
+ "mat": "Raw material",
+ "miss": "miss",
+ "nm": "Miscellaneous / non-consumables",
+ "non-consumables": "Non-consumables",
+ "nor": "nor",
+ "not available": "not available",
+ "not match": "not match",
+ "not pass": "not pass",
+ "notMatch": "notMatch",
+ "notmatch": "notmatch",
+ "open": "open",
+ "pass": "pass",
+ "pending": "pending",
+ "productLotNo": "productLotNo",
+ "rejected": "rejected",
+ "save": "save",
+ "section": "section",
+ "sfg": "Semi-finished good",
+ "stockTaking": "stockTaking",
+ "tke": "tke",
+ "to": "to",
+ "trf": "trf",
+ "unavailable": "unavailable",
+ "variance": "variance",
+ "wip": "Work in progress",
+ "材料": "Material"
+}
diff --git a/src/i18n/en/itemPrice.json b/src/i18n/en/itemPrice.json
new file mode 100644
index 0000000..d036b8f
--- /dev/null
+++ b/src/i18n/en/itemPrice.json
@@ -0,0 +1,30 @@
+{
+ "Price Inquiry": "Price Inquiry",
+ "No Purchase Order After 2026-01-01": "No Purchase Order After 2026-01-01",
+ "Code": "Code",
+ "Name": "Name",
+ "Searching": "Searching",
+ "No item selected": "No item selected",
+ "Average unit price": "Average unit price",
+ "Latest market unit price": "Latest market unit price",
+ "No Import Record": "No Import Record",
+ "Download Template": "Download Template",
+ "Downloading...": "Downloading...",
+ "Upload": "Upload",
+ "Uploading...": "Uploading...",
+ "Download failed": "Download failed",
+ "Upload failed": "Upload failed",
+ "Upload successful": "Upload successful",
+ "item(s) updated": "item(s) updated",
+ "Upload row errors": "Upload row errors",
+ "FG": "Finished good",
+ "RM": "Raw material",
+ "SFG": "Semi-finished good",
+ "WIP": "Work in progress",
+ "CMB": "Consumables",
+ "NM": "Miscellaneous / non-consumables",
+ "MA": "Material",
+ "MI": "Miscellaneous",
+ "CO": "Consumables",
+ "MAT": "Material"
+}
diff --git a/src/i18n/en/items.json b/src/i18n/en/items.json
index 1acc8c5..859f7ef 100644
--- a/src/i18n/en/items.json
+++ b/src/i18n/en/items.json
@@ -1,22 +1,70 @@
{
- "LocationCode": "Location Code",
- "DefaultLocationCode": "Default Location Code",
- "Special Type": "Special Type",
- "None": "None",
- "isEgg": "Egg",
- "isFee": "Fee",
- "isBag": "Bag",
+ "Actions": "Actions",
"Back": "Back",
- "Status": "Status",
+ "Cancel": "Cancel",
+ "Code": "Code",
+ "Code or name": "Code or name",
"Complete": "Complete",
- "Missing Data": "Missing Data",
+ "Confirm": "Confirm",
+ "Create Material": "Create Material",
+ "DefaultLocationCode": "Default Location Code",
+ "Demand Forecast Period": "Demand Forecast Period",
+ "Details": "Details",
+ "EPQC": "EPQC",
+ "Edit Product / Material": "Edit Product / Material",
+ "Finished Goods Name": "Finished Goods Name",
+ "IPQC": "IPQC",
+ "Item": "Item",
"Loading QC items...": "Loading QC items...",
- "Select a QC template to view items": "Select a QC template to view items",
+ "LocationCode": "Location Code",
+ "Missing Data": "Missing Data",
+ "Name": "Name",
"No QC items in this template": "No QC items in this template",
+ "None": "None",
+ "Product": "Product",
+ "Product / Material": "Product / Material",
+ "Product / Material Details": "Product / Material Details",
+ "Product Count": "Product Count",
+ "Product Count(s)": "Product Count(s)",
+ "Product Details": "Product Details",
"QC Checklist": "QC Checklist",
"QC Type": "QC Type",
- "IPQC": "IPQC",
- "EPQC": "EPQC",
- "Item": "Item",
- "Code or name": "Code or name"
-}
\ No newline at end of file
+ "Qc Category": "Qc Category",
+ "Qc items": "Qc items",
+ "Release": "Release",
+ "Reset": "Reset",
+ "Save": "Save",
+ "Schedule Period": "Schedule Period",
+ "Scheduled At": "Scheduled At",
+ "Search": "Search",
+ "Select a QC template to view items": "Select a QC template to view items",
+ "Special Type": "Special Type",
+ "Status": "Status",
+ "Type": "Type",
+ "fg": "FG",
+ "wip": "WIP",
+ "mat": "MAT",
+ "cmb": "CMB",
+ "nm": "NM",
+ "code": "code",
+ "countryOfOrigin": "countryOfOrigin",
+ "description": "description",
+ "instruction": "instruction",
+ "isBag": "Bag",
+ "isEgg": "Egg",
+ "isFee": "Fee",
+ "lowerLimit": "lowerLimit",
+ "maxQty": "maxQty",
+ "name": "name",
+ "no rows": "no rows",
+ "remarks": "remarks",
+ "shelfLife": "shelfLife",
+ "upperLimit": "upperLimit",
+ "Item Code": "Item Code",
+ "Item Name": "Item Name",
+ "Sales Qty": "Sales Qty",
+ "Sales UOM": "Sales UOM",
+ "Stock Qty": "Stock Qty",
+ "Uom": "Uom",
+ "Cost (HKD)": "Cost (HKD)"
+}
diff --git a/src/i18n/en/jo.json b/src/i18n/en/jo.json
new file mode 100644
index 0000000..0d94138
--- /dev/null
+++ b/src/i18n/en/jo.json
@@ -0,0 +1,645 @@
+{
+ "2/F plastic box carton Qty": "2/F plastic box carton Qty",
+ "2/F plastic box carton qty count": "2/F plastic box carton qty count",
+ "3/F plastic box carton Qty": "3/F plastic box carton Qty",
+ "3/F plastic box carton qty count": "3/F plastic box carton qty count",
+ "4/F plastic box carton Qty": "4/F plastic box carton Qty",
+ "4/F plastic box carton qty count": "4/F plastic box carton qty count",
+ "Action": "Action",
+ "Actions": "Actions",
+ "Actual Pick Qty": "Actual Pick Qty",
+ "Add Bag": "Add Bag",
+ "Add Record": "Add Record",
+ "Add Selected Items to Created Items": "Add Selected Items to Created Items",
+ "Add some entries!": "Add some entries!",
+ "All": "All",
+ "All Pick Order Lots": "All Pick Order Lots",
+ "All floors": "All floors",
+ "All pick orders created successfully": "All pick orders created successfully",
+ "Are you sure you want to delete this procoess?": "Are you sure you want to delete this procoess?",
+ "Assignment failed: ": "Assignment failed: ",
+ "Assignment successful": "Assignment successful",
+ "Assume End Time": "Assume End Time",
+ "At least one issue must be reported": "At least one issue must be reported",
+ "Auto-refresh every 1 minute": "Auto-refresh every 1 minute",
+ "Auto-refresh every 10 minutes": "Auto-refresh every 10 minutes",
+ "Auto-refresh every 15 minutes": "Auto-refresh every 15 minutes",
+ "Auto-refresh every 5 minutes": "Auto-refresh every 5 minutes",
+ "Available Qty": "Available Qty",
+ "Available in warehouse": "Available in warehouse",
+ "BOM Description": "BOM Description",
+ "BOM Status": "BOM Status",
+ "BOM Type": "BOM Type",
+ "Back": "Back",
+ "Back to List": "Back to List",
+ "Bad Item Qty": "Bad Item Qty",
+ "Bad Package Qty": "Bad Package Qty",
+ "Bag": "Bag",
+ "Bag Code": "Bag Code",
+ "Bag Consumption": "Bag Consumption",
+ "Bag Consumption Records": "Bag Consumption Records",
+ "Bag List": "Bag List",
+ "Bag Lot Lines": "Bag Lot Lines",
+ "Bag Name": "Bag Name",
+ "Bag Usage": "Bag Usage",
+ "Balance": "Balance",
+ "Balance Qty": "Balance Qty",
+ "Base Qty": "Base Qty",
+ "Base UOM": "Base UOM",
+ "Batch Count": "Batch Count",
+ "BoM Material": "BoM Material",
+ "Bom": "Bom",
+ "Bom Req. Qty": "Bom Req. Qty",
+ "Bom Uom": "Bom Uom",
+ "By-product": "By-product",
+ "COMPLETED": "COMPLETED",
+ "Cancel": "Cancel",
+ "Cancel Job Order": "Cancel Job Order",
+ "Cancel job order confirm message": "Cancel job order confirm message",
+ "Changeover Time": "Changeover Time",
+ "Changeover Time (mins)": "Changeover Time (mins)",
+ "Changeover Time (mins)": "Changeover Time (mins)",
+ "Clean Record": "Clean Record",
+ "Code": "Code",
+ "Code / Lot No": "Code / Lot No",
+ "Complete Job Order Record": "Complete Job Order Record",
+ "Complete Step": "Complete Step",
+ "Completed": "Completed",
+ "Completed Step": "Completed Step",
+ "Confirm": "Confirm",
+ "Confirm All": "Confirm All",
+ "Confirm Lot Substitution": "Confirm Lot Substitution",
+ "Confirm cancel job order": "Confirm cancel job order",
+ "Confirm delete job order": "Confirm delete job order",
+ "Consolidate": "Consolidate",
+ "Consolidated Code": "Consolidated Code",
+ "Consumable": "Consumable",
+ "Consumed Qty": "Consumed Qty",
+ "Continue": "Continue",
+ "Count of Job Orders": "Count of Job Orders",
+ "Create": "Create",
+ "Create Job Order": "Create Job Order",
+ "Create New Group": "Create New Group",
+ "Create Pick Order": "Create Pick Order",
+ "Create Project": "Create Project",
+ "Create Task Template": "Create Task Template",
+ "Created Items": "Created Items",
+ "Current Stock": "Current Stock",
+ "Customer": "Customer",
+ "Date": "Date",
+ "Default Warehouse": "Default Warehouse",
+ "Defect": "Defect",
+ "Delete Job Order": "Delete Job Order",
+ "Delete job order confirm message": "Delete job order confirm message",
+ "Deliver Order": "Deliver Order",
+ "Delivery Code": "Delivery Code",
+ "Delivery Date": "Delivery Date",
+ "Delivery Note Code": "Delivery Note Code",
+ "Delivery Order": "Delivery Order",
+ "Demand Forecast": "Demand Forecast",
+ "Demand Forecast Setting": "Demand Forecast Setting",
+ "Departure Time": "Departure Time",
+ "Describe the issue with bad items": "Describe the issue with bad items",
+ "Description": "Description",
+ "Detail Scheduling": "Detail Scheduling",
+ "Details": "Details",
+ "Do you want to start job order": "Do you want to start job order",
+ "Download Excel": "Download Excel",
+ "Drink": "Drink",
+ "Duration hours": "Duration hours",
+ "Duration minutes": "Duration minutes",
+ "Duration seconds": "Duration seconds",
+ "Edit": "Edit",
+ "Edit Equipment": "Edit Equipment",
+ "Edit Equipment Type": "Edit Equipment Type",
+ "Edit Job Order": "Edit Job Order",
+ "Edit Job Order Detail": "Edit Job Order Detail",
+ "End Product": "End Product",
+ "End Qty": "End Qty",
+ "Enter all floors plastic box carton qty": "Enter all floors plastic box carton qty",
+ "Enter bad item quantity (required if no missing items)": "Enter bad item quantity (required if no missing items)",
+ "Enter missing quantity (required if no bad items)": "Enter missing quantity (required if no bad items)",
+ "Enter plastic box carton qty": "Enter plastic box carton qty",
+ "Enter print quantity": "Enter print quantity",
+ "Enter the number of cartons": "Enter the number of cartons",
+ "Enter the number of cartons: ": "Enter the number of cartons: ",
+ "Equipment": "Equipment",
+ "Equipment Code": "Equipment Code",
+ "Equipment Details": "Equipment Details",
+ "Equipment Name and Code": "Equipment Name and Code",
+ "Equipment Type Details": "Equipment Type Details",
+ "EquipmentType-EquipmentName-Code": "EquipmentType-EquipmentName-Code",
+ "Escalation History": "Escalation History",
+ "Escalation Info": "Escalation Info",
+ "Escalation Result": "Escalation Result",
+ "Estimated Production Date": "Estimated Production Date",
+ "Exclude Date": "Exclude Date",
+ "Executing": "Executing",
+ "Expected Lot:": "Expected Lot:",
+ "Expiry Date": "Expiry Date",
+ "Exporting...": "Exporting...",
+ "FG": "FG",
+ "FG & Material Demand Forecast Detail": "FG & Material Demand Forecast Detail",
+ "FG / WIP Item": "FG / WIP Item",
+ "FG Production Schedule": "FG Production Schedule",
+ "Failed to create group": "Failed to create group",
+ "Failed to load plastic box carton qty dashboard": "Failed to load plastic box carton qty dashboard",
+ "Failed to submit scan data. Please try again.": "Failed to submit scan data. Please try again.",
+ "Finish": "Finish",
+ "Finished Good Order": "Finished Good Order",
+ "Finished Goods Name": "Finished Goods Name",
+ "Finished Job Order Record": "Finished Job Order Record",
+ "Finished lines": "Finished lines",
+ "First created group": "First created group",
+ "Floor": "Floor",
+ "Group": "Group",
+ "Handled By": "Handled By",
+ "Handler": "Handler",
+ "Idle": "Idle",
+ "If you confirm, the system will:": "If you confirm, the system will:",
+ "Import Testing": "Import Testing",
+ "In Progress": "In Progress",
+ "In progress": "In progress",
+ "In_Progress": "In_Progress",
+ "Index": "Index",
+ "Input Equipment is not match with process": "Input Equipment is not match with process",
+ "Insufficient available quantity on lot (may have been picked by another user)": "Insufficient available quantity on lot (may have been picked by another user)",
+ "Invalid Stock In Line Id": "Invalid Stock In Line Id",
+ "Invalid date format": "Invalid date format",
+ "Inventory": "Inventory",
+ "Is Dark": "Is Dark",
+ "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity",
+ "Is Dense": "Is Dense",
+ "Is Float": "Is Float",
+ "Issue": "Issue",
+ "Issue Remark": "Issue Remark",
+ "Item": "Item",
+ "Item Code": "Item Code",
+ "Item Name": "Item Name",
+ "Item already exists in created items": "Item already exists in created items",
+ "Items": "Items",
+ "Jo Pick Order Detail": "Jo Pick Order Detail",
+ "Job Order": "Job Order",
+ "Job Order Code": "Job Order Code",
+ "Job Order Info": "Job Order Info",
+ "Job Order Item Name": "Job Order Item Name",
+ "Job Order Match": "Job Order Match",
+ "Job Order No.": "Job Order No.",
+ "Job Order Pick Execution": "Job Order Pick Execution",
+ "Job Order Pick Order Details": "Job Order Pick Order Details",
+ "Job Order Pickexcution": "Job Order Pickexcution",
+ "Job Order Qty": "Job Order Qty",
+ "Job Order Type": "Job Order Type",
+ "Job Order not found or has no items": "Job Order not found or has no items",
+ "Job Process Status Dashboard": "Job Process Status Dashboard",
+ "Job Type": "Job Type",
+ "Job dashboard PP status: cancelled": "Job dashboard PP status: cancelled",
+ "Job dashboard PP status: completed": "Job dashboard PP status: completed",
+ "Job dashboard PP status: in_progress": "Job dashboard PP status: in_progress",
+ "Job dashboard PP status: pending": "Job dashboard PP status: pending",
+ "Job dashboard PP status: stopped": "Job dashboard PP status: stopped",
+ "Job process detail mode label": "Job process detail mode label",
+ "Job process detail: equipment": "Job process detail: equipment",
+ "Job process detail: handler": "Job process detail: handler",
+ "Job process detail: process name": "Job process detail: process name",
+ "Job process detail: time": "Job process detail: time",
+ "Just Complete": "Just Complete",
+ "Just Completed (workbench): requires valid quantity; expired rows must not use this button.": "Just Completed (workbench): requires valid quantity; expired rows must not use this button.",
+ "Last 7 days": "Last 7 days",
+ "Last updated": "Last updated",
+ "Latest created group": "Latest created group",
+ "Lines with insufficient stock: ": "Lines with insufficient stock: ",
+ "Lines with sufficient stock: ": "Lines with sufficient stock: ",
+ "Loading...": "Loading...",
+ "Location": "Location",
+ "Lot Actual Pick Qty": "Lot Actual Pick Qty",
+ "Lot Availability": "Lot Availability",
+ "Lot Details": "Lot Details",
+ "Lot No": "Lot No",
+ "Lot No.": "Lot No.",
+ "Lot Number Mismatch": "Lot Number Mismatch",
+ "Lot Required Pick Qty": "Lot Required Pick Qty",
+ "Lot has been rejected and marked as unavailable.": "Lot has been rejected and marked as unavailable.",
+ "LotNo": "LotNo",
+ "Mail": "Mail",
+ "Management Job Order": "Management Job Order",
+ "Manual Input": "Manual Input",
+ "Matching Stock": "Matching Stock",
+ "Material": "Material",
+ "Material Code": "Material Code",
+ "Material Pick Status": "Material Pick Status",
+ "Max": "Max",
+ "Missing item Qty": "Missing item Qty",
+ "Missing items": "Missing items",
+ "Multiplier": "Multiplier",
+ "N/A": "N/A",
+ "Name": "Name",
+ "Next": "Next",
+ "Next page": "Next page",
+ "No": "No",
+ "No Group": "No Group",
+ "No Item": "No Item",
+ "No Qc": "No Qc",
+ "No Uom": "No Uom",
+ "No Warehouse": "No Warehouse",
+ "No chart data": "No chart data",
+ "No completed Job Order pick orders with matching found": "No completed Job Order pick orders with matching found",
+ "No created items": "No created items",
+ "No data available": "No data available",
+ "No data found": "No data found",
+ "No lot details available": "No lot details available",
+ "No results found": "No results found",
+ "No. of Items to be Picked": "No. of Items to be Picked",
+ "No. of Items with Issue During Pick": "No. of Items with Issue During Pick",
+ "None": "None",
+ "Note:": "Note:",
+ "Now": "Now",
+ "Number must be at least 1": "Number must be at least 1",
+ "Number of cartons": "Number of cartons",
+ "Open 挑號 QR 碼 on a pick line first, then scan {2fic} to use manual lot substitution.": "Open 挑號 QR 碼 on a pick line first, then scan {2fic} to use manual lot substitution.",
+ "Operator": "Operator",
+ "Operator KPI": "Operator KPI",
+ "Operator KPI Dashboard": "Operator KPI Dashboard",
+ "Operator Name & No.": "Operator Name & No.",
+ "Order Complete": "Order Complete",
+ "Order Quantity": "Order Quantity",
+ "Other": "Other",
+ "Output Qty": "Output Qty",
+ "Output from Process": "Output from Process",
+ "Over Time": "Over Time",
+ "Overall Time Remaining": "Overall Time Remaining",
+ "Overview": "Overview",
+ "Packaging": "Packaging",
+ "Partial quantity submitted. Please submit more or complete the order.": "Partial quantity submitted. Please submit more or complete the order.",
+ "Pass": "Pass",
+ "Passed Step": "Passed Step",
+ "Pause": "Pause",
+ "Pause Reason": "Pause Reason",
+ "Paused": "Paused",
+ "Pending": "Pending",
+ "Pending for pick": "Pending for pick",
+ "Pick End Time": "Pick End Time",
+ "Pick Execution Issue Form": "Pick Execution Issue Form",
+ "Pick Order": "Pick Order",
+ "Pick Order Code": "Pick Order Code",
+ "Pick Order Conso Code": "Pick Order Conso Code",
+ "Pick Order Detail": "Pick Order Detail",
+ "Pick Order Id": "Pick Order Id",
+ "Pick Order No.- Job Order No.- Item": "Pick Order No.- Job Order No.- Item",
+ "Pick Order Status": "Pick Order Status",
+ "Pick Order Target Date": "Pick Order Target Date",
+ "Pick Start Time": "Pick Start Time",
+ "Pick Time Taken (minutes)": "Pick Time Taken (minutes)",
+ "Pick order completed successfully!": "Pick order completed successfully!",
+ "Picked Qty": "Picked Qty",
+ "Plan Start": "Plan Start",
+ "Plan Start From": "Plan Start From",
+ "Plan Start To": "Plan Start To",
+ "Planning": "Planning",
+ "Plastic box carton Qty": "Plastic box carton Qty",
+ "Plastic box carton qty dashboard": "Plastic box carton qty dashboard",
+ "Plastic box carton qty multi period report": "Plastic box carton qty multi period report",
+ "Plastic box carton qty report last 7 days": "Plastic box carton qty report last 7 days",
+ "Plastic box carton qty report this month": "Plastic box carton qty report this month",
+ "Plastic box carton qty report this year": "Plastic box carton qty report this year",
+ "Plastic box carton qty usage": "Plastic box carton qty usage",
+ "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.",
+ "Please enter at least code or name": "Please enter at least code or name",
+ "Please enter quantity for all selected items": "Please enter quantity for all selected items",
+ "Please finish QR code scan and pick order.": "Please finish QR code scan and pick order.",
+ "Please make sure all required items are picked": "Please make sure all required items are picked",
+ "Please make sure the qty is enough": "Please make sure the qty is enough",
+ "Please scan equipment code": "Please scan equipment code",
+ "Please scan equipment code (optional if not required)": "Please scan equipment code (optional if not required)",
+ "Please scan operator code": "Please scan operator code",
+ "Please scan operator code first": "Please scan operator code first",
+ "Please scan staff no": "Please scan staff no",
+ "Please scan the item qr code": "Please scan the item qr code",
+ "Please scan warehouse qr code.": "Please scan warehouse qr code.",
+ "Please select": "Please select",
+ "Please select a printer": "Please select a printer",
+ "Please select a printer first": "Please select a printer first",
+ "Please select at least one item to submit": "Please select at least one item to submit",
+ "Please select group and enter quantity for all selected items": "Please select group and enter quantity for all selected items",
+ "Please select group for all selected items": "Please select group for all selected items",
+ "Please select item": "Please select item",
+ "Please select product type": "Please select product type",
+ "Please select target date": "Please select target date",
+ "Please select type": "Please select type",
+ "Please submit the pick order.": "Please submit the pick order.",
+ "Po Code": "Po Code",
+ "Powder Mixture": "Powder Mixture",
+ "Powder_Mixture": "Powder_Mixture",
+ "Previous page": "Previous page",
+ "Print Pick Record": "Print Pick Record",
+ "Print Quantity": "Print Quantity",
+ "Printed Successfully.": "Printed Successfully.",
+ "Printer": "Printer",
+ "Process": "Process",
+ "Process page summary": "Process page summary",
+ "Processing": "Processing",
+ "Processing QR code...": "Processing QR code...",
+ "Processing Status": "Processing Status",
+ "Processing Time": "Processing Time",
+ "Processing Time (mins)": "Processing Time (mins)",
+ "Processing...": "Processing...",
+ "Product": "Product",
+ "Product Type": "Product Type",
+ "Product process status": "Product process status",
+ "Production": "Production",
+ "Production Date": "Production Date",
+ "Production Equipment Status Dashboard": "Production Equipment Status Dashboard",
+ "Production Output Data": "Production Output Data",
+ "Production Output Data Entry": "Production Output Data Entry",
+ "Production Priority": "Production Priority",
+ "Production Priority required!": "Production Priority required!",
+ "Production Process": "Production Process",
+ "Production Process Information": "Production Process Information",
+ "Production Process Line Remark": "Production Process Line Remark",
+ "Production Process Steps": "Production Process Steps",
+ "Production Time Remaining": "Production Time Remaining",
+ "Production date": "Production date",
+ "Progress": "Progress",
+ "Project": "Project",
+ "Projects": "Projects",
+ "Purchase Order": "Purchase Order",
+ "Put Away": "Put Away",
+ "Put Away Scan": "Put Away Scan",
+ "Put Awayed": "Put Awayed",
+ "Putaway Detail": "Putaway Detail",
+ "QC Category": "QC Category",
+ "QC Check Item": "QC Check Item",
+ "QC Check Template": "QC Check Template",
+ "QC Info": "QC Info",
+ "QR Code Handle": "QR Code Handle",
+ "QR Code Scan for Lot": "QR Code Scan for Lot",
+ "QR Scan Result:": "QR Scan Result:",
+ "QR code does not match any item in current orders.": "QR code does not match any item in current orders.",
+ "QR code verified.": "QR code verified.",
+ "Qc Item": "Qc Item",
+ "Qty": "Qty",
+ "Qty Already Picked": "Qty Already Picked",
+ "Qty cannot be negative": "Qty cannot be negative",
+ "Qty is not allowed to be greater than required qty": "Qty is not allowed to be greater than required qty",
+ "Qty is required": "Qty is required",
+ "Qty must be a whole number": "Qty must be a whole number",
+ "Qty will submit": "Qty will submit",
+ "Quality Check": "Quality Check",
+ "Quantity": "Quantity",
+ "R&D": "R&D",
+ "RELEASED": "RELEASED",
+ "Reason": "Reason",
+ "Received Qty": "Received Qty",
+ "Reject": "Reject",
+ "Release": "Release",
+ "Released": "Released",
+ "Released By": "Released By",
+ "Remaining Available Qty": "Remaining Available Qty",
+ "Remaining Time (min)": "Remaining Time (min)",
+ "Remark": "Remark",
+ "Remember plan start as default": "Remember plan start as default",
+ "Repair": "Repair",
+ "Req. Qty": "Req. Qty",
+ "Required Qty": "Required Qty",
+ "Reset": "Reset",
+ "Route": "Route",
+ "Router": "Router",
+ "Row per page": "Row per page",
+ "Rows per page": "Rows per page",
+ "SEQ": "SEQ",
+ "STF": "STF",
+ "Save": "Save",
+ "Scan Operator & Equipment": "Scan Operator & Equipment",
+ "Scan Result": "Scan Result",
+ "Scan Status": "Scan Status",
+ "Scanned": "Scanned",
+ "Scanned Lot:": "Scanned Lot:",
+ "Scanning...": "Scanning...",
+ "Scrap": "Scrap",
+ "Scrap Qty": "Scrap Qty",
+ "Search": "Search",
+ "Search Criteria": "Search Criteria",
+ "Search Items": "Search Items",
+ "Search Job Order/ Create Job Order": "Search Job Order/ Create Job Order",
+ "Search Results": "Search Results",
+ "Second Scan Completed": "Second Scan Completed",
+ "Second Scan Pending": "Second Scan Pending",
+ "Second Scan Status": "Second Scan Status",
+ "Select Another Bag Lot": "Select Another Bag Lot",
+ "Select Bag": "Select Bag",
+ "Select Date": "Select Date",
+ "Select Printer": "Select Printer",
+ "Select Unit": "Select Unit",
+ "Select a printer": "Select a printer",
+ "Select warehouse": "Select warehouse",
+ "Selected": "Selected",
+ "Selected items will join above created group": "Selected items will join above created group",
+ "Seq": "Seq",
+ "Seq No": "Seq No",
+ "Seq No Remark": "Seq No Remark",
+ "Seq:": "Seq:",
+ "Sequence": "Sequence",
+ "Setup Time": "Setup Time",
+ "Setup Time (mins)": "Setup Time (mins)",
+ "Shop Address": "Shop Address",
+ "Shop ID": "Shop ID",
+ "Shop Name": "Shop Name",
+ "Shop PO Code": "Shop PO Code",
+ "Sign out": "Sign out",
+ "Skip": "Skip",
+ "Staff No": "Staff No",
+ "Staff No Required": "Staff No Required",
+ "Staff No:": "Staff No:",
+ "Start": "Start",
+ "Start Job Order": "Start Job Order",
+ "Start QR Scan": "Start QR Scan",
+ "Start Qty": "Start Qty",
+ "Start Scan": "Start Scan",
+ "Start Time": "Start Time",
+ "Status": "Status",
+ "Step": "Step",
+ "Step Information": "Step Information",
+ "Step Name": "Step Name",
+ "Still need to pick": "Still need to pick",
+ "Stock Available": "Stock Available",
+ "Stock Req. Qty": "Stock Req. Qty",
+ "Stock Status": "Stock Status",
+ "Stock UOM": "Stock UOM",
+ "Stock Unit": "Stock Unit",
+ "Stop": "Stop",
+ "Stop QR Scan": "Stop QR Scan",
+ "Stop Scan": "Stop Scan",
+ "Store ID": "Store ID",
+ "Storing": "Storing",
+ "Submit": "Submit",
+ "Submit & Start": "Submit & Start",
+ "Submit All Scanned": "Submit All Scanned",
+ "Submit Bag Consumption": "Submit Bag Consumption",
+ "Submit Required Pick Qty": "Submit Required Pick Qty",
+ "Submitting...": "Submitting...",
+ "Summary": "Summary",
+ "Supplier": "Supplier",
+ "Target Date": "Target Date",
+ "Target Date From": "Target Date From",
+ "Target Date To": "Target Date To",
+ "Target Production Date": "Target Production Date",
+ "Task Template": "Task Template",
+ "The input is not the same as the expected lot number.": "The input is not the same as the expected lot number.",
+ "The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?": "The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?",
+ "This form is for reporting issues only. You must report either missing items or bad items.": "This form is for reporting issues only. You must report either missing items or bad items.",
+ "This is last lot, so no available lot.": "This is last lot, so no available lot.",
+ "This lot is rejected, please scan another lot.": "This lot is rejected, please scan another lot.",
+ "This month": "This month",
+ "This order is insufficient, please pick another lot.": "This order is insufficient, please pick another lot.",
+ "This year": "This year",
+ "Ticket No.": "Ticket No.",
+ "Time": "Time",
+ "Time Information(mins)": "Time Information(mins)",
+ "Time Remaining": "Time Remaining",
+ "Time used": "Time used",
+ "Timer Paused": "Timer Paused",
+ "Today": "Today",
+ "Total": "Total",
+ "Total (Verified + Bad + Missing) must equal Required quantity": "Total (Verified + Bad + Missing) must equal Required quantity",
+ "Total Processing Time": "Total Processing Time",
+ "Total Steps": "Total Steps",
+ "Total lines: ": "Total lines: ",
+ "Total pick orders": "Total pick orders",
+ "Total plastic box carton qty": "Total plastic box carton qty",
+ "Total processes": "Total processes",
+ "Truck No.": "Truck No.",
+ "Two Days Ago": "Two Days Ago",
+ "Type": "Type",
+ "Unable to get user ID": "Unable to get user ID",
+ "Unassigned Job Orders": "Unassigned Job Orders",
+ "Unit": "Unit",
+ "Unknown": "Unknown",
+ "Unknown error": "Unknown error",
+ "Unknown error: ": "Unknown error: ",
+ "UoM": "UoM",
+ "Update Estimated Production Date": "Update Estimated Production Date",
+ "Update Job Order": "Update Job Order",
+ "Update Production Priority": "Update Production Priority",
+ "Update Time Information": "Update Time Information",
+ "Update your suggested lot to the this scanned lot": "Update your suggested lot to the this scanned lot",
+ "User not found with staffNo:": "User not found with staffNo:",
+ "Validation failed. Please check operator and equipment.": "Validation failed. Please check operator and equipment.",
+ "Verified Qty": "Verified Qty",
+ "Verified quantity cannot exceed received quantity": "Verified quantity cannot exceed received quantity",
+ "Verified successfully!": "Verified successfully!",
+ "View": "View",
+ "View Details": "View Details",
+ "View item In-out And inventory Ledger": "View item In-out And inventory Ledger",
+ "WIP": "WIP",
+ "Wait Time [minutes]": "Wait Time [minutes]",
+ "Warehouse": "Warehouse",
+ "Yesterday": "Yesterday",
+ "You need to enter a number": "You need to enter a number",
+ "acceptQty": "acceptQty",
+ "acceptQty must not greater than": "acceptQty must not greater than",
+ "acceptedQty": "acceptedQty",
+ "acceptedQty must not greater than": "acceptedQty must not greater than",
+ "acceptedWeight": "acceptedWeight",
+ "bind": "bind",
+ "bomWarn_close": "bomWarn_close",
+ "bomWarn_copyAll": "bomWarn_copyAll",
+ "bomWarn_empty": "bomWarn_empty",
+ "bomWarn_issue_MISSING_BOM_CODE": "bomWarn_issue_MISSING_BOM_CODE",
+ "bomWarn_issue_MISSING_BOM_NAME": "bomWarn_issue_MISSING_BOM_NAME",
+ "bomWarn_issue_MISSING_ITEM": "bomWarn_issue_MISSING_ITEM",
+ "bomWarn_issue_MISSING_SALES_UOM": "bomWarn_issue_MISSING_SALES_UOM",
+ "bomWarn_issue_MISSING_STOCK_UOM": "bomWarn_issue_MISSING_STOCK_UOM",
+ "bomWarn_issue_MISSING_STOCK_UOM_CONVERSION": "bomWarn_issue_MISSING_STOCK_UOM_CONVERSION",
+ "bomWarn_issue_MISSING_UOM_CONVERSION": "bomWarn_issue_MISSING_UOM_CONVERSION",
+ "bomWarn_loadFailed": "bomWarn_loadFailed",
+ "bomWarn_refresh": "bomWarn_refresh",
+ "bomWarn_refreshing": "bomWarn_refreshing",
+ "bomWarn_rowBomId": "bomWarn_rowBomId",
+ "bomWarn_rowItemId": "bomWarn_rowItemId",
+ "bomWarn_title": "bomWarn_title",
+ "bomWarn_tooltipHas": "bomWarn_tooltipHas",
+ "bomWarn_tooltipNone": "bomWarn_tooltipNone",
+ "cancel": "cancel",
+ "cancelled": "cancelled",
+ "complete jo": "complete jo",
+ "completed": "completed",
+ "completed Job Order pick orders with Matching": "completed Job Order pick orders with Matching",
+ "completed Job Order pick orders with matching": "completed Job Order pick orders with matching",
+ "consumables": "consumables",
+ "create": "create",
+ "edit": "edit",
+ "enter a qty": "enter a qty",
+ "equipmentType": "equipmentType",
+ "escalation": "escalation",
+ "escalation processing": "escalation processing",
+ "expiryDate": "expiryDate",
+ "failedQty": "failedQty",
+ "fg": "fg",
+ "finishedGood": "finishedGood",
+ "handler": "handler",
+ "hr": "hr",
+ "hrs": "hrs",
+ "id": "id",
+ "inProgress": "inProgress",
+ "in_progress": "in_progress",
+ "is expired. Please check around have available QR code or not.": "is expired. Please check around have available QR code or not.",
+ "is unavable. Please check around have available QR code or not.": "is unavable. Please check around have available QR code or not.",
+ "issue": "issue",
+ "issue remark": "issue remark",
+ "item": "item",
+ "itemName": "itemName",
+ "itemNo": "itemNo",
+ "items": "items",
+ "items completed": "items completed",
+ "jodetail": "jodetail",
+ "mat": "mat",
+ "min": "min",
+ "minimal value is 1": "minimal value is 1",
+ "mins": "mins",
+ "minutes": "minutes",
+ "non-consumables": "non-consumables",
+ "not default warehosue": "not default warehosue",
+ "packaging": "packaging",
+ "paused": "paused",
+ "pending": "pending",
+ "printQty": "printQty",
+ "process epqc": "process epqc",
+ "process stockIn": "process stockIn",
+ "productionDate": "productionDate",
+ "qcCategory": "qcCategory",
+ "qcItem": "qcItem",
+ "qcResult": "qcResult",
+ "qty": "qty",
+ "qty is not allowed to be greater than picked qty": "qty is not allowed to be greater than picked qty",
+ "qty is not allowed to be greater than remaining available qty": "qty is not allowed to be greater than remaining available qty",
+ "qty is not allowed to be greater than required qty": "qty is not allowed to be greater than required qty",
+ "qty is required": "qty is required",
+ "receivedQty": "receivedQty",
+ "release jo": "release jo",
+ "remarks": "remarks",
+ "reset": "reset",
+ "scan picked material": "scan picked material",
+ "scheduling": "scheduling",
+ "second Scan Status": "second Scan Status",
+ "select qc": "select qc",
+ "seq": "seq",
+ "settings": "settings",
+ "sfg": "sfg",
+ "stock in information": "stock in information",
+ "stopped": "stopped",
+ "storing": "storing",
+ "submit": "submit",
+ "submitting": "submitting",
+ "success": "success",
+ "supervisor": "supervisor",
+ "targetDate": "targetDate",
+ "type": "type",
+ "uom": "uom",
+ "update production priority": "update production priority",
+ "update qc info": "update qc info",
+ "update success": "update success",
+ "value must be a number": "value must be a number",
+ "view putaway": "view putaway",
+ "view stockin": "view stockin",
+ "warehouse": "warehouse"
+}
diff --git a/src/i18n/en/laserPrint.json b/src/i18n/en/laserPrint.json
new file mode 100644
index 0000000..5cf6a96
--- /dev/null
+++ b/src/i18n/en/laserPrint.json
@@ -0,0 +1,3 @@
+{
+ "title": "Laser Printer"
+}
diff --git a/src/i18n/en/login.json b/src/i18n/en/login.json
index 9e26dfe..4b0d314 100644
--- a/src/i18n/en/login.json
+++ b/src/i18n/en/login.json
@@ -1 +1,11 @@
-{}
\ No newline at end of file
+{
+ "Invalid username or password.": "Invalid username or password.",
+ "Login": "Login",
+ "Password": "Password",
+ "Please enter a password": "Please enter a password",
+ "Please enter a username": "Please enter a username",
+ "Sign In": "Sign In",
+ "Something went wrong. Please try again later.": "Something went wrong. Please try again later.",
+ "Username": "Username",
+ "toggle password visibility": "Toggle password visibility"
+}
diff --git a/src/i18n/en/m18ImportTesting.json b/src/i18n/en/m18ImportTesting.json
new file mode 100644
index 0000000..1df1011
--- /dev/null
+++ b/src/i18n/en/m18ImportTesting.json
@@ -0,0 +1,16 @@
+{
+ "testing sections tabs": "testing sections tabs",
+ "Import Delivery Order": "Import Delivery Order",
+ "Import Do": "Import Do",
+ "Import Master Data": "Import Master Data",
+ "Import Po": "Import Po",
+ "Import Pq": "Import Pq",
+ "Import Purchase Order": "Import Purchase Order",
+ "Import Purchase Quotation": "Import Purchase Quotation",
+ "Modified Date From": "Modified Date From",
+ "Modified Date From *": "Modified Date From *",
+ "Modified Date To": "Modified Date To",
+ "Modified Date To *": "Modified Date To *",
+ "Ready to import": "Ready to import",
+ "Status": "Status"
+}
diff --git a/src/i18n/en/m18Sync.json b/src/i18n/en/m18Sync.json
new file mode 100644
index 0000000..f718dcb
--- /dev/null
+++ b/src/i18n/en/m18Sync.json
@@ -0,0 +1,3 @@
+{
+ "title": "M18 Sync"
+}
diff --git a/src/i18n/en/mail.json b/src/i18n/en/mail.json
new file mode 100644
index 0000000..ffcf818
--- /dev/null
+++ b/src/i18n/en/mail.json
@@ -0,0 +1,25 @@
+{
+ "Code": "Code",
+ "Description": "Description",
+ "MAIL.smtp.auth": "MAIL.smtp.auth",
+ "MAIL.smtp.host": "MAIL.smtp.host",
+ "MAIL.smtp.password": "MAIL.smtp.password",
+ "MAIL.smtp.port": "MAIL.smtp.port",
+ "MAIL.smtp.ssl": "MAIL.smtp.ssl",
+ "MAIL.smtp.username": "MAIL.smtp.username",
+ "Mail": "Mail",
+ "Mail Created At": "Mail Created At",
+ "Mail Description": "Mail Description",
+ "Mail List": "Mail List",
+ "Mail Name": "Mail Name",
+ "Mail Status": "Mail Status",
+ "Mail Updated At": "Mail Updated At",
+ "Save Fail": "Save Fail",
+ "Save Success": "Save Success",
+ "Select Template (View By Code - Description)": "Select Template (View By Code - Description)",
+ "Setting": "Setting",
+ "Settings": "Settings",
+ "Subject CHT": "Subject CHT",
+ "Template": "Template",
+ "send to everyone": "send to everyone"
+}
diff --git a/src/i18n/en/masterDataIssue.json b/src/i18n/en/masterDataIssue.json
new file mode 100644
index 0000000..54374a1
--- /dev/null
+++ b/src/i18n/en/masterDataIssue.json
@@ -0,0 +1,101 @@
+{
+ "Current Stock": "Current Stock",
+ "masterDataIssue": "masterDataIssue",
+ "masterDataIssue_BOM_MATERIAL_BASE_UOM_MISMATCH": "masterDataIssue_BOM_MATERIAL_BASE_UOM_MISMATCH",
+ "masterDataIssue_BOM_MATERIAL_MISSING_ITEM": "masterDataIssue_BOM_MATERIAL_MISSING_ITEM",
+ "masterDataIssue_BOM_MATERIAL_SALES_UOM_MISMATCH": "masterDataIssue_BOM_MATERIAL_SALES_UOM_MISMATCH",
+ "masterDataIssue_BOM_MATERIAL_STOCK_UOM_MISMATCH": "masterDataIssue_BOM_MATERIAL_STOCK_UOM_MISMATCH",
+ "masterDataIssue_BOM_MATERIAL_UOM_FK_INVALID": "masterDataIssue_BOM_MATERIAL_UOM_FK_INVALID",
+ "masterDataIssue_BOM_OUTPUT_UOM_MISMATCH_SALES": "masterDataIssue_BOM_OUTPUT_UOM_MISMATCH_SALES",
+ "masterDataIssue_BOM_OUTPUT_UOM_TEXT_DRIFT": "masterDataIssue_BOM_OUTPUT_UOM_TEXT_DRIFT",
+ "masterDataIssue_DELETED_BASE_UOM": "masterDataIssue_DELETED_BASE_UOM",
+ "masterDataIssue_DELETED_PURCHASE_UOM": "masterDataIssue_DELETED_PURCHASE_UOM",
+ "masterDataIssue_DELETED_SALES_UOM": "masterDataIssue_DELETED_SALES_UOM",
+ "masterDataIssue_DELETED_STOCK_UOM": "masterDataIssue_DELETED_STOCK_UOM",
+ "masterDataIssue_MISSING_BASE_UOM": "masterDataIssue_MISSING_BASE_UOM",
+ "masterDataIssue_MISSING_BASE_UOM_CONVERSION": "masterDataIssue_MISSING_BASE_UOM_CONVERSION",
+ "masterDataIssue_MISSING_BOM_CODE": "masterDataIssue_MISSING_BOM_CODE",
+ "masterDataIssue_MISSING_BOM_NAME": "masterDataIssue_MISSING_BOM_NAME",
+ "masterDataIssue_MISSING_ITEM": "masterDataIssue_MISSING_ITEM",
+ "masterDataIssue_MISSING_PICKING_UOM": "masterDataIssue_MISSING_PICKING_UOM",
+ "masterDataIssue_MISSING_PICKING_UOM_CONVERSION": "masterDataIssue_MISSING_PICKING_UOM_CONVERSION",
+ "masterDataIssue_MISSING_PURCHASE_UOM": "masterDataIssue_MISSING_PURCHASE_UOM",
+ "masterDataIssue_MISSING_PURCHASE_UOM_CONVERSION": "masterDataIssue_MISSING_PURCHASE_UOM_CONVERSION",
+ "masterDataIssue_MISSING_SALES_UOM": "masterDataIssue_MISSING_SALES_UOM",
+ "masterDataIssue_MISSING_SALES_UOM_CONVERSION": "masterDataIssue_MISSING_SALES_UOM_CONVERSION",
+ "masterDataIssue_MISSING_STOCK_UOM": "masterDataIssue_MISSING_STOCK_UOM",
+ "masterDataIssue_MISSING_STOCK_UOM_CONVERSION": "masterDataIssue_MISSING_STOCK_UOM_CONVERSION",
+ "masterDataIssue_MISSING_UOM_CONVERSION": "masterDataIssue_MISSING_UOM_CONVERSION",
+ "masterDataIssue_MULTIPLE_BASE_UOM": "masterDataIssue_MULTIPLE_BASE_UOM",
+ "masterDataIssue_MULTIPLE_PICKING_UOM": "masterDataIssue_MULTIPLE_PICKING_UOM",
+ "masterDataIssue_MULTIPLE_PURCHASE_UOM": "masterDataIssue_MULTIPLE_PURCHASE_UOM",
+ "masterDataIssue_MULTIPLE_SALES_UOM": "masterDataIssue_MULTIPLE_SALES_UOM",
+ "masterDataIssue_MULTIPLE_STOCK_UOM": "masterDataIssue_MULTIPLE_STOCK_UOM",
+ "masterDataIssue_bomMore": "masterDataIssue_bomMore",
+ "masterDataIssue_close": "masterDataIssue_close",
+ "masterDataIssue_col_actions": "masterDataIssue_col_actions",
+ "masterDataIssue_col_actual": "masterDataIssue_col_actual",
+ "masterDataIssue_col_bom": "BOM",
+ "masterDataIssue_col_bom_uom": "BOM UOM",
+ "masterDataIssue_col_expected": "masterDataIssue_col_expected",
+ "masterDataIssue_col_issue": "masterDataIssue_col_issue",
+ "masterDataIssue_col_item": "masterDataIssue_col_item",
+ "masterDataIssue_col_item_uom": "M18 UOM",
+ "masterDataIssue_col_problem": "masterDataIssue_col_problem",
+ "masterDataIssue_col_scope": "masterDataIssue_col_scope",
+ "masterDataIssue_col_subject": "masterDataIssue_col_subject",
+ "masterDataIssue_col_summary": "masterDataIssue_col_summary",
+ "masterDataIssue_copy": "masterDataIssue_copy",
+ "masterDataIssue_count": "masterDataIssue_count",
+ "masterDataIssue_detail_subtitle": "masterDataIssue_detail_subtitle",
+ "masterDataIssue_detail_uomBase": "masterDataIssue_detail_uomBase",
+ "masterDataIssue_detail_uomBoth": "masterDataIssue_detail_uomBoth",
+ "masterDataIssue_detail_uomSales": "masterDataIssue_detail_uomSales",
+ "masterDataIssue_detail_uomStock": "masterDataIssue_detail_uomStock",
+ "masterDataIssue_detail_usedInBom": "masterDataIssue_detail_usedInBom",
+ "masterDataIssue_empty": "masterDataIssue_empty",
+ "masterDataIssue_fgItem": "masterDataIssue_fgItem",
+ "masterDataIssue_filter_all": "masterDataIssue_filter_all",
+ "masterDataIssue_filter_type": "masterDataIssue_filter_type",
+ "masterDataIssue_group_count": "masterDataIssue_group_count",
+ "masterDataIssue_issueCount": "masterDataIssue_issueCount",
+ "masterDataIssue_line_generic": "masterDataIssue_line_generic",
+ "masterDataIssue_line_itemGeneric": "masterDataIssue_line_itemGeneric",
+ "masterDataIssue_line_itemMissing": "masterDataIssue_line_itemMissing",
+ "masterDataIssue_line_missingUnits": "masterDataIssue_line_missingUnits",
+ "masterDataIssue_line_outputText": "masterDataIssue_line_outputText",
+ "masterDataIssue_line_outputUom": "masterDataIssue_line_outputUom",
+ "masterDataIssue_line_pairBase": "masterDataIssue_line_pairBase",
+ "masterDataIssue_line_pairBoth": "masterDataIssue_line_pairBoth",
+ "masterDataIssue_line_pairSales": "masterDataIssue_line_pairSales",
+ "masterDataIssue_line_pairStock": "masterDataIssue_line_pairStock",
+ "masterDataIssue_line_problemOnly": "{{bom}}:{{problem}}",
+ "masterDataIssue_line_uomBoth": "masterDataIssue_line_uomBoth",
+ "masterDataIssue_line_uomSales": "masterDataIssue_line_uomSales",
+ "masterDataIssue_line_uomStock": "masterDataIssue_line_uomStock",
+ "masterDataIssue_loadFailed": "masterDataIssue_loadFailed",
+ "masterDataIssue_material": "masterDataIssue_material",
+ "masterDataIssue_materialUsedInBom": "masterDataIssue_materialUsedInBom",
+ "masterDataIssue_modifiedAt": "masterDataIssue_modifiedAt",
+ "masterDataIssue_nav": "masterDataIssue_nav",
+ "masterDataIssue_pageTitle": "masterDataIssue_pageTitle",
+ "masterDataIssue_refresh": "masterDataIssue_refresh",
+ "masterDataIssue_refreshing": "masterDataIssue_refreshing",
+ "masterDataIssue_scope_BOM": "masterDataIssue_scope_BOM",
+ "masterDataIssue_scope_BOM_MATERIAL": "masterDataIssue_scope_BOM_MATERIAL",
+ "masterDataIssue_scope_ITEM": "masterDataIssue_scope_ITEM",
+ "masterDataIssue_search": "masterDataIssue_search",
+ "masterDataIssue_tab_bom": "BOM",
+ "masterDataIssue_tab_item": "masterDataIssue_tab_item",
+ "masterDataIssue_unit_active": "masterDataIssue_unit_active",
+ "masterDataIssue_unit_base": "masterDataIssue_unit_base",
+ "masterDataIssue_unit_inactive": "masterDataIssue_unit_inactive",
+ "masterDataIssue_unit_missing": "masterDataIssue_unit_missing",
+ "masterDataIssue_unit_output": "masterDataIssue_unit_output",
+ "masterDataIssue_unit_picking": "masterDataIssue_unit_picking",
+ "masterDataIssue_unit_purchase": "masterDataIssue_unit_purchase",
+ "masterDataIssue_unit_sales": "masterDataIssue_unit_sales",
+ "masterDataIssue_unit_stock": "masterDataIssue_unit_stock",
+ "masterDataIssue_usedInBom": "masterDataIssue_usedInBom",
+ "masterDataIssue_viewDetail": "masterDataIssue_viewDetail"
+}
diff --git a/src/i18n/en/material.json b/src/i18n/en/material.json
new file mode 100644
index 0000000..f10f621
--- /dev/null
+++ b/src/i18n/en/material.json
@@ -0,0 +1,4 @@
+{
+ "Material": "Material",
+ "Create Claim": "Create Claim"
+}
diff --git a/src/i18n/en/navigation.json b/src/i18n/en/navigation.json
new file mode 100644
index 0000000..8b6cbe0
--- /dev/null
+++ b/src/i18n/en/navigation.json
@@ -0,0 +1,99 @@
+{
+ "menu": "menu",
+ "nav.dashboard": "Dashboard",
+ "nav.storeManagement": "Store Management",
+ "nav.store.purchaseOrder": "Purchase Order",
+ "nav.store.pickOrder": "Pick Order",
+ "nav.store.inventoryLedger": "View item In-out And inventory Ledger",
+ "nav.store.stockTake": "Stock Take Management",
+ "nav.store.stockIssue": "Stock Issue",
+ "nav.store.putAwayScan": "Put Away Scan",
+ "nav.store.finishedGoodManagement": "Finished Good Management",
+ "nav.store.stockRecord": "Stock Record",
+ "nav.store.doWorkbench": "DO Workbench",
+ "nav.deliveryOrder": "Delivery Order",
+ "nav.scheduling": "Scheduling",
+ "nav.jobOrderManagement": "Management Job Order",
+ "nav.jobOrder.searchCreate": "Search Job Order/ Create Job Order",
+ "nav.jobOrder.pickExecution": "Job Order Pick Execution",
+ "nav.jobOrder.productionProcess": "Job Order Production Process",
+ "nav.jobOrder.bagUsage": "Bag Usage",
+ "nav.bagPrint": "Bag Printer",
+ "nav.laserPrint": "Laser Printer",
+ "nav.report": "Report Management",
+ "nav.m18Sync": "M18 Sync",
+ "nav.chartReports": "Chart Reports",
+ "nav.chart.purchase": "Purchase",
+ "nav.chart.jobOrder": "Job Order",
+ "nav.chart.jobOrderBoard": "Job Order Live Board",
+ "nav.chart.delivery": "Delivery & Distribution",
+ "nav.chart.warehouse": "Inventory & Warehouse",
+ "nav.chart.forecast": "Forecast & Planning",
+ "nav.settings": "Settings",
+ "nav.settings.user": "User",
+ "nav.settings.clientMonitor": "Device Connection Monitor",
+ "nav.settings.items": "Items",
+ "nav.settings.equipment": "Equipment",
+ "nav.settings.warehouse": "Warehouse",
+ "nav.settings.printer": "Printer",
+ "nav.settings.priceInquiry": "Price Inquiry",
+ "nav.settings.qcItem": "QC Check Item",
+ "nav.settings.qcCategory": "QC Category",
+ "nav.settings.qcItemAll": "QC Item All",
+ "nav.settings.shopAndTruck": "Shop And Truck",
+ "nav.settings.deliveryOrderFloor": "DO floor (supplier)",
+ "nav.settings.demandForecast": "Demand Forecast Setting",
+ "nav.settings.bomWeighting": "BOM Weighting Score List",
+ "nav.settings.masterDataIssues": "BOM / Item UOM Issues",
+ "nav.settings.qrCodeHandle": "QR Code Handle",
+ "nav.settings.importTesting": "Import Testing",
+ "nav.settings.importExcel": "Import Excel",
+ "nav.settings.importBom": "Import BOM",
+ "nav.breadcrumb.home": "Overview",
+ "nav.breadcrumb.chart": "Chart Reports",
+ "nav.breadcrumb.chartWarehouse": "Inventory & Warehouse",
+ "nav.breadcrumb.chartPurchase": "Purchase",
+ "nav.breadcrumb.chartDelivery": "Delivery & Distribution",
+ "nav.breadcrumb.chartJobOrder": "Job Order",
+ "nav.breadcrumb.chartJobOrderBoard": "Job Order Live Board",
+ "nav.breadcrumb.chartForecast": "Forecast & Planning",
+ "nav.breadcrumb.projects": "Projects",
+ "nav.breadcrumb.projectsCreate": "Create Project",
+ "nav.breadcrumb.tasks": "Task Template",
+ "nav.breadcrumb.tasksCreate": "Create Task Template",
+ "nav.breadcrumb.qcItem": "QC Item",
+ "nav.breadcrumb.qcItemAll": "QC Item All",
+ "nav.breadcrumb.qrCodeHandle": "QR Code Handle",
+ "nav.breadcrumb.demandForecast": "Demand Forecast Setting",
+ "nav.breadcrumb.deliveryOrderFloor": "Delivery Order Floor",
+ "nav.breadcrumb.masterDataIssues": "BOM / Item UOM Issues",
+ "nav.breadcrumb.equipment": "Equipment",
+ "nav.breadcrumb.equipmentMaintenanceEdit": "Maintenance Edit",
+ "nav.breadcrumb.shop": "Shop And Truck",
+ "nav.breadcrumb.routeBoard": "Route Board",
+ "nav.breadcrumb.shopDetail": "Shop Detail",
+ "nav.breadcrumb.truckLaneDetail": "Truck Lane Detail",
+ "nav.breadcrumb.printer": "Printer",
+ "nav.breadcrumb.schedulingRough": "Demand Forecast",
+ "nav.breadcrumb.schedulingRoughEdit": "FG & Material Demand Forecast Detail",
+ "nav.breadcrumb.schedulingDetailed": "Detail Scheduling",
+ "nav.breadcrumb.schedulingDetailedEdit": "FG Production Schedule",
+ "nav.breadcrumb.inventory": "Inventory",
+ "nav.breadcrumb.importTesting": "Import Testing",
+ "nav.breadcrumb.doWorkbenchSearch": "DO Workbench Search",
+ "nav.breadcrumb.doWorkbenchPick": "DO Workbench Pick",
+ "nav.breadcrumb.doWorkbenchEdit": "DO Workbench Detail",
+ "nav.breadcrumb.poEdit": "Edit",
+ "nav.breadcrumb.poWorkbench": "PO Workbench",
+ "nav.breadcrumb.joEdit": "Edit Job Order",
+ "nav.breadcrumb.joTesting": "Job Order Testing",
+ "nav.breadcrumb.joWorkbench": "Job Order Workbench",
+ "nav.breadcrumb.report": "Report",
+ "nav.breadcrumb.m18Sync": "M18 Sync",
+ "nav.breadcrumb.bagPrint": "Bag Printer",
+ "nav.breadcrumb.laserPrint": "Laser Printer",
+ "nav.breadcrumb.priceInquiry": "Price Inquiry",
+ "nav.breadcrumb.finishedGood": "Finished Good Order",
+ "nav.breadcrumb.finishedGoodManagement": "Finished Good Management",
+ "nav.productionServer": "Production Server"
+}
diff --git a/src/i18n/en/pickOrder.json b/src/i18n/en/pickOrder.json
new file mode 100644
index 0000000..4e6026c
--- /dev/null
+++ b/src/i18n/en/pickOrder.json
@@ -0,0 +1,521 @@
+{
+ "Purchase Order": "Purchase Order",
+ "Code": "Code",
+ "Pick Order Code": "Pick Order Code",
+ "Item Code": "Item Code",
+ "OrderDate": "OrderDate",
+ "Details": "Details",
+ "Supplier": "Supplier",
+ "Status": "Status",
+ "N/A": "N/A",
+ "Release Pick Orders": "Release Pick Orders",
+ "released": "released",
+ "Loading...": "Loading...",
+ "Suggestion success": "Suggestion success",
+ "Scan pick success": "Scan pick success",
+ "Remark": "Remark",
+ "Available Qty": "Available Qty",
+ "Picked Qty": "Picked Qty",
+ "Escalated": "Escalated",
+ "NotEscalated": "NotEscalated",
+ "Assigned To": "Assigned To",
+ "Progress": "Progress",
+ "Select Remark": "Select Remark",
+ "Just Complete": "Just Complete",
+ "Skip": "Skip",
+ "if need just edit number, please scan the lot again": "if need just edit number, please scan the lot again",
+ "Total qty (actual pick + miss + bad) cannot exceed available qty: {available}": "Total qty (actual pick + miss + bad) cannot exceed available qty: {available}",
+ "Confirm Assignment": "Confirm Assignment",
+ "Required Date": "Required Date",
+ "Store": "Store",
+ "Available Orders": "Available Orders",
+ "This lot is rejected, please scan another lot.": "This lot is rejected, please scan another lot.",
+ "Lane Code": "Lane Code",
+ "Fetching all matching records...": "Fetching all matching records...",
+ "Edit": "Edit",
+ "Submit Qty": "Submit Qty",
+ "Just Completed": "Just Completed",
+ "Just Completed (workbench): requires a valid lot number and quantity; expired rows must not use this button.": "Just Completed (workbench): requires a valid lot number and quantity; expired rows must not use this button.",
+ "Do you want to start?": "Do you want to start?",
+ "Start": "Start",
+ "Pick Order Code(s)": "Pick Order Code(s)",
+ "Delivery Order Code(s)": "Delivery Order Code(s)",
+ "Start Success": "Start Success",
+ "Qty will submit": "Qty will submit",
+ "Truck Lance Code": "Truck Lance Code",
+ "Pick Order Codes": "Pick Order Codes",
+ "Pick Order Lines": "Pick Order Lines",
+ "Delivery Order Codes": "Delivery Order Codes",
+ "Delivery Order Lines": "Delivery Order Lines",
+ "Lines Per Pick Order": "Lines Per Pick Order",
+ "Pick Orders Details": "Pick Orders Details",
+ "Lines": "Lines",
+ "Before Today": "Before Today",
+ "Truck X": "Truck X",
+ "Finsihed good items": "Finsihed good items",
+ "kinds": "kinds",
+ "Completed Date": "Completed Date",
+ "Completed Time": "Completed Time",
+ "Delivery Order": "Delivery Order",
+ "items": "items",
+ "Select Pick Order:": "Select Pick Order:",
+ "No Stock Available": "No Stock Available",
+ "is expired. Please check around have available QR code or not.": "is expired. Please check around have available QR code or not.",
+ "Start Fail": "Start Fail",
+ "Start PO": "Start PO",
+ "Do you want to complete?": "Do you want to complete?",
+ "Complete": "Complete",
+ "Complete Success": "Complete Success",
+ "Complete Fail": "Complete Fail",
+ "Complete Pick Order": "Complete Pick Order",
+ "General": "General",
+ "Bind Storage": "Bind Storage",
+ "itemNo": "itemNo",
+ "itemName": "itemName",
+ "qty": "qty",
+ "Require Qty": "Require Qty",
+ "uom": "uom",
+ "total weight": "total weight",
+ "weight unit": "weight unit",
+ "price": "price",
+ "processed": "processed",
+ "expiryDate": "expiryDate",
+ "acceptedQty": "acceptedQty",
+ "weight": "weight",
+ "start": "start",
+ "qc": "qc",
+ "escalation": "escalation",
+ "stock in": "stock in",
+ "putaway": "putaway",
+ "delete": "delete",
+ "qty cannot be greater than remaining qty": "qty cannot be greater than remaining qty",
+ "Record pol": "Record pol",
+ "Add some entries!": "Add some entries!",
+ "draft": "draft",
+ "pending": "pending",
+ "determine1": "determine1",
+ "determine2": "determine2",
+ "determine3": "determine3",
+ "receiving": "receiving",
+ "received": "received",
+ "completed": "completed",
+ "rejected": "rejected",
+ "success": "success",
+ "acceptedQty must not greater than": "acceptedQty must not greater than",
+ "minimal value is 1": "minimal value is 1",
+ "value must be a number": "value must be a number",
+ "qc Check": "qc Check",
+ "Please select QC": "Please select QC",
+ "failQty": "failQty",
+ "select qc": "select qc",
+ "enter a failQty": "enter a failQty",
+ "qty too big": "qty too big",
+ "sampleRate": "sampleRate",
+ "sampleWeight": "sampleWeight",
+ "totalWeight": "totalWeight",
+ "Escalation": "Escalation",
+ "to be processed": "to be processed",
+ "Stock In Detail": "Stock In Detail",
+ "productLotNo": "productLotNo",
+ "receiptDate": "receiptDate",
+ "acceptedWeight": "acceptedWeight",
+ "productionDate": "productionDate",
+ "reportQty": "reportQty",
+ "Default Warehouse": "Default Warehouse",
+ "Select warehouse": "Select warehouse",
+ "Putaway Detail": "Putaway Detail",
+ "LotNo": "LotNo",
+ "Po Code": "Po Code",
+ "No Warehouse": "No Warehouse",
+ "Please scan warehouse qr code.": "Please scan warehouse qr code.",
+ "Reject": "Reject",
+ "submit": "submit",
+ "print": "print",
+ "bind": "bind",
+ "Total must equal Required Qty. Missing: {diff}": "Total must equal Required Qty. Missing: {diff}",
+ "Total must equal Required Qty. Exceeds by: {diff}": "Total must equal Required Qty. Exceeds by: {diff}",
+ "Batch": "Batch",
+ "Single": "Single",
+ "Release Type": "Release Type",
+ "isExtra order": "isExtra order",
+ "Etra": "Etra",
+ "Exit Etra view": "Exit Etra view",
+ "Etra Pick Order Detail": "Etra Pick Order Detail",
+ "Etra incomplete badge tooltip": "Etra incomplete badge tooltip",
+ "Etra incomplete badge tooltip none": "Etra incomplete badge tooltip none",
+ "Back to normal assign tab": "Back to normal assign tab",
+ "Enter isExtra workbench view?": "Enter isExtra workbench view?",
+ "Etra view groups all add-on tickets by shop and lane for the selected date.": "Etra view groups all add-on tickets by shop and lane for the selected date.",
+ "Etra Ticket Notice": "Etra Ticket Notice",
+ "Pick Order": "Pick Order",
+ "Type": "Type",
+ "Product Type": "Product Type",
+ "Reset": "Reset",
+ "Search": "Search",
+ "Pick Orders": "Pick Orders",
+ "Consolidated Pick Orders": "Consolidated Pick Orders",
+ "Pick Order No.": "Pick Order No.",
+ "Pick Order Date": "Pick Order Date",
+ "Pick Order Status": "Pick Order Status",
+ "Pick Order Type": "Pick Order Type",
+ "Consolidated Code": "Consolidated Code",
+ "type": "type",
+ "Items": "Items",
+ "Target Date": "Target Date",
+ "Released By": "Released By",
+ "Target Date From": "Target Date From",
+ "Target Date To": "Target Date To",
+ "Consolidate": "Consolidate",
+ "Stock Unit": "Stock Unit",
+ "create": "create",
+ "detail": "detail",
+ "Pick Order Detail": "Pick Order Detail",
+ "item": "item",
+ "Unit": "Unit",
+ "reset": "reset",
+ "targetDate": "targetDate",
+ "remove": "remove",
+ "release": "release",
+ "location": "location",
+ "suggestedLotNo": "suggestedLotNo",
+ "lotNo": "lotNo",
+ "item name": "item name",
+ "Item Name": "Item Name",
+ "approval": "approval",
+ "lot change": "lot change",
+ "checkout": "checkout",
+ "Search Items": "Search Items",
+ "Search Results": "Search Results",
+ "Second Search Results": "Second Search Results",
+ "Second Search Items": "Second Search Items",
+ "Second Search": "Second Search",
+ "Item": "Item",
+ "Order Quantity": "Order Quantity",
+ "Current Stock": "Current Stock",
+ "Selected": "Selected",
+ "Select Items": "Select Items",
+ "Assign": "Assign",
+ "Release": "Release",
+ "Pick Execution": "Pick Execution",
+ "Create Pick Order": "Create Pick Order",
+ "Consumable": "Consumable",
+ "Material": "Material",
+ "Job Order": "Job Order",
+ "End Product": "End Product",
+ "Lot Expiry Date": "Lot Expiry Date",
+ "Lot Location": "Lot Location",
+ "Available Lot": "Available Lot",
+ "Lot Required Pick Qty": "Lot Required Pick Qty",
+ "Lot Actual Pick Qty": "Lot Actual Pick Qty",
+ "Lot#": "Lot#",
+ "Submit": "Submit",
+ "Created Items": "Created Items",
+ "Create New Group": "Create New Group",
+ "Group": "Group",
+ "Qty Already Picked": "Qty Already Picked",
+ "Select Job Order Items": "Select Job Order Items",
+ "failedQty": "failedQty",
+ "remarks": "remarks",
+ "Qc items": "Qc items",
+ "qcItem": "qcItem",
+ "QC Info": "QC Info",
+ "qcResult": "qcResult",
+ "acceptQty": "acceptQty",
+ "Escalation History": "Escalation History",
+ "Group Code": "Group Code",
+ "Job Order Code": "Job Order Code",
+ "QC Check": "QC Check",
+ "QR Code Scan": "QR Code Scan",
+ "Pick Order Details": "Pick Order Details",
+ "Partial quantity submitted. Please submit more or complete the order.": "Partial quantity submitted. Please submit more or complete the order.",
+ "Pick order completed successfully!": "Pick order completed successfully!",
+ "Lot has been rejected and marked as unavailable.": "Lot has been rejected and marked as unavailable.",
+ "This order is insufficient, please pick another lot.": "This order is insufficient, please pick another lot.",
+ "Please finish QR code scan, QC check and pick order.": "Please finish QR code scan, QC check and pick order.",
+ "No data available": "No data available",
+ "Please submit the pick order.": "Please submit the pick order.",
+ "Item lot to be Pick:": "Item lot to be Pick:",
+ "Report and Pick another lot": "Report and Pick another lot",
+ "Accept Stock Out": "Accept Stock Out",
+ "Pick Another Lot": "Pick Another Lot",
+ "Delivery Note Code": "Delivery Note Code",
+ "A4 Printer": "A4 Printer",
+ "Label Printer": "Label Printer",
+ "Please select a printer first": "Please select a printer first",
+ "Please select a label printer first": "Please select a label printer first",
+ "Lot No": "Lot No",
+ "Expiry Date": "Expiry Date",
+ "Location": "Location",
+ "All Pick Order Lots": "All Pick Order Lots",
+ "Completed": "Completed",
+ "Finished Good Order": "Finished Good Order",
+ "Assign and Release": "Assign and Release",
+ "Original Available Qty": "Original Available Qty",
+ "Remaining Available Qty": "Remaining Available Qty",
+ "Please submit pick order.": "Please submit pick order.",
+ "Please finish QR code scan and pick order.": "Please finish QR code scan and pick order.",
+ "Please finish QR code scanand pick order.": "Please finish QR code scanand pick order.",
+ "First created group": "First created group",
+ "Latest created group": "Latest created group",
+ "Manual Input": "Manual Input",
+ "QR Code Scan for Lot": "QR Code Scan for Lot",
+ "Processing QR code...": "Processing QR code...",
+ "The input is not the same as the expected lot number.": "The input is not the same as the expected lot number.",
+ "Verified successfully!": "Verified successfully!",
+ "Cancel": "Cancel",
+ "storing": "storing",
+ "pick successful": "pick successful",
+ "Insufficient available quantity on lot (may have been picked by another user)": "Insufficient available quantity on lot (may have been picked by another user)",
+ "Scan": "Scan",
+ "Before today": "Before today",
+ "Scanned": "Scanned",
+ "Loading data...": "Loading data...",
+ "No available stock for this item": "No available stock for this item",
+ "No lot details available for this item": "No lot details available for this item",
+ "Current stock is insufficient or unavailable": "Current stock is insufficient or unavailable",
+ "Please check inventory status": "Please check inventory status",
+ "Rows per page": "Rows per page",
+ "QR Scan Result:": "QR Scan Result:",
+ "Action": "Action",
+ "Please finish pick order.": "Please finish pick order.",
+ "Lot": "Lot",
+ "Assign Pick Orders": "Assign Pick Orders",
+ "Selected Pick Orders": "Selected Pick Orders",
+ "Please assgin/release the pickorders to picker": "Please assgin/release the pickorders to picker",
+ "Assign To": "Assign To",
+ "No Group": "No Group",
+ "Selected items will join above created group": "Selected items will join above created group",
+ "Issue": "Issue",
+ "Pick Execution Issue Form": "Pick Execution Issue Form",
+ "Lot line is unavailable": "Lot line is unavailable",
+ "This form is for reporting issues only. You must report either missing items or bad items.": "This form is for reporting issues only. You must report either missing items or bad items.",
+ "Bad item Qty": "Bad item Qty",
+ "Missing item Qty": "Missing item Qty",
+ "Missing Item Qty": "Missing Item Qty",
+ "Bad Item Qty": "Bad Item Qty",
+ "Bad Package Qty": "Bad Package Qty",
+ "Lot line is not available (status=UNAVAILABLE)": "Lot line is not available (status=UNAVAILABLE)",
+ "Actual Pick Qty": "Actual Pick Qty",
+ "Required Qty": "Required Qty",
+ "Issue Remark": "Issue Remark",
+ "Handler": "Handler",
+ "Qty is required": "Qty is required",
+ "Qty is not allowed to be greater than remaining available qty": "Qty is not allowed to be greater than remaining available qty",
+ "Qty is not allowed to be greater than required qty": "Qty is not allowed to be greater than required qty",
+ "At least one issue must be reported": "At least one issue must be reported",
+ "issueRemark": "issueRemark",
+ "handler": "handler",
+ "Max": "Max",
+ "Route": "Route",
+ "Index": "Index",
+ "No FG pick orders found": "No FG pick orders found",
+ "Finish Scan?": "Finish Scan?",
+ "Delivery Code": "Delivery Code",
+ "Shop PO Code": "Shop PO Code",
+ "Shop ID": "Shop ID",
+ "Truck No.": "Truck No.",
+ "Departure Time": "Departure Time",
+ "Shop Name": "Shop Name",
+ "Shop Address": "Shop Address",
+ "Delivery Date": "Delivery Date",
+ "Pick Execution 2/F": "Pick Execution 2/F",
+ "Pick Execution 4/F": "Pick Execution 4/F",
+ "Pick Execution Detail": "Pick Execution Detail",
+ "Submit Required Pick Qty": "Submit Required Pick Qty",
+ "Scan Result": "Scan Result",
+ "Ticket No.": "Ticket No.",
+ "Start QR Scan": "Start QR Scan",
+ "Stop QR Scan": "Stop QR Scan",
+ "Scanning...": "Scanning...",
+ "Print DN/Label": "Print DN/Label",
+ "Store ID": "Store ID",
+ "QR code does not match any item in current orders.": "QR code does not match any item in current orders.",
+ "Lot Number Mismatch": "Lot Number Mismatch",
+ "The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?": "The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?",
+ "The scanned item matches the expected item, but the lot number is different. Scan again to confirm: scan the expected lot QR to keep the suggested lot, or scan the other lot QR again to switch.": "The scanned item matches the expected item, but the lot number is different. Scan again to confirm: scan the expected lot QR to keep the suggested lot, or scan the other lot QR again to switch.",
+ "Expected Lot:": "Expected Lot:",
+ "Scanned Lot:": "Scanned Lot:",
+ "Confirm": "Confirm",
+ "Update your suggested lot to the this scanned lot": "Update your suggested lot to the this scanned lot",
+ "Print Draft": "Print Draft",
+ "Print Pick Order and DN Label": "Print Pick Order and DN Label",
+ "Print Pick Order": "Print Pick Order",
+ "Print DN Label": "Print DN Label",
+ "Print All Draft": "Print All Draft",
+ "If you confirm, the system will:": "If you confirm, the system will:",
+ "After you scan to choose, the system will update the pick line to the lot you confirmed.": "After you scan to choose, the system will update the pick line to the lot you confirmed.",
+ "Or use the Confirm button below if you cannot scan again (same as scanning the other lot again).": "Or use the Confirm button below if you cannot scan again (same as scanning the other lot again).",
+ "Lot switch failed": "Lot switch failed",
+ "The system could not switch to the scanned lot. Review the lots below, then tap Confirm to retry.": "The system could not switch to the scanned lot. Review the lots below, then tap Confirm to retry.",
+ "You can also scan again: expected lot QR keeps the suggested line; scanned lot QR retries the switch.": "You can also scan again: expected lot QR keeps the suggested line; scanned lot QR retries the switch.",
+ "QR code verified.": "QR code verified.",
+ "Order Finished": "Order Finished",
+ "Submitted Status": "Submitted Status",
+ "Pick Execution Record": "Pick Execution Record",
+ "Delivery No.": "Delivery No.",
+ "Total": "Total",
+ "Completed DO pick orders: ": "Completed DO pick orders: ",
+ "No completed DO pick orders found": "No completed DO pick orders found",
+ "Enter the number of cartons: ": "Enter the number of cartons: ",
+ "Number of cartons": "Number of cartons",
+ "Select an action for the assigned pick orders.": "Select an action for the assigned pick orders.",
+ "Detail": "Detail",
+ "consoCode": "consoCode",
+ "status": "status",
+ "Items Included": "Items Included",
+ "Pick Order Included": "Pick Order Included",
+ "No created items": "No created items",
+ "Please select item": "Please select item",
+ "enter a qty": "enter a qty",
+ "update qc info": "update qc info",
+ "All lots must be completed before printing": "All lots must be completed before printing",
+ "Assigning pick order...": "Assigning pick order...",
+ "Enter the number of cartons:": "Enter the number of cartons:",
+ "Finished Good Detail": "Finished Good Detail",
+ "Finished Good Record": "Finished Good Record",
+ "Finished Good Record (All)": "Finished Good Record (All)",
+ "All dates": "All dates",
+ "Search date": "Search date",
+ "Hide Completed: OFF": "Hide Completed: OFF",
+ "Hide Completed: ON": "Hide Completed: ON",
+ "Number must be at least 1": "Number must be at least 1",
+ "Printed Successfully.": "Printed Successfully.",
+ "Product": "Product",
+ "You need to enter a number": "You need to enter a number",
+ "Available in warehouse": "Available in warehouse",
+ "Describe the issue with bad items": "Describe the issue with bad items",
+ "Enter pick qty or issue qty": "Enter pick qty or issue qty",
+ "Invalid qty": "Invalid qty",
+ "Note:": "Note:",
+ "Qty is not allowed to be greater than required/available qty": "Qty is not allowed to be greater than required/available qty",
+ "Still need to pick": "Still need to pick",
+ "Total exceeds required qty": "Total exceeds required qty",
+ "submitting": "submitting",
+ "Back to List": "Back to List",
+ "Delivery No": "Delivery No",
+ "FG orders": "FG orders",
+ "View Details": "View Details",
+ "No Item": "No Item",
+ "None": "None",
+ "Add Selected Items to Created Items": "Add Selected Items to Created Items",
+ "All pick orders created successfully": "All pick orders created successfully",
+ "Failed to create group": "Failed to create group",
+ "Invalid date format": "Invalid date format",
+ "Item already exists in created items": "Item already exists in created items",
+ "Job Order not found or has no items": "Job Order not found or has no items",
+ "No results found": "No results found",
+ "Please enter at least code or name": "Please enter at least code or name",
+ "Please enter quantity for all selected items": "Please enter quantity for all selected items",
+ "Please select at least one item to submit": "Please select at least one item to submit",
+ "Please select group and enter quantity for all selected items": "Please select group and enter quantity for all selected items",
+ "Please select group for all selected items": "Please select group for all selected items",
+ "Please select product type": "Please select product type",
+ "Please select target date": "Please select target date",
+ "Please select type": "Please select type",
+ "Search Criteria": "Search Criteria",
+ "Processing...": "Processing...",
+ "Failed items must have failed quantity": "Failed items must have failed quantity",
+ "QC items without result": "QC items without result",
+ "confirm putaway": "confirm putaway",
+ "email supplier": "email supplier",
+ "qc processing": "qc processing",
+ "submitStockIn": "submitStockIn",
+ "not default warehosue": "not default warehosue",
+ "printQty": "printQty",
+ "Shop": "Shop",
+ "warehouse": "warehouse",
+ "Add Record": "Add Record",
+ "Clean Record": "Clean Record",
+ "Select": "Select",
+ "Close": "Close",
+ "Truck": "Truck",
+ "Date": "Date",
+ "Delivery Order Code": "Delivery Order Code",
+ "Escalation Info": "Escalation Info",
+ "Escalation Result": "Escalation Result",
+ "acceptQty must not greater than": "acceptQty must not greater than",
+ "supervisor": "supervisor",
+ "No Qc": "No Qc",
+ "receivedQty": "receivedQty",
+ "stock in information": "stock in information",
+ "No Uom": "No Uom",
+ "Input quantity cannot exceed": "Input quantity cannot exceed",
+ "Quantity cannot be negative": "Quantity cannot be negative",
+ "Enter bad item quantity (required if no missing items)": "Enter bad item quantity (required if no missing items)",
+ "Enter missing quantity (required if no bad items)": "Enter missing quantity (required if no bad items)",
+ "Submit All Scanned": "Submit All Scanned",
+ "Submitting...": "Submitting...",
+ "COMPLETED": "COMPLETED",
+ "Confirm print: (": "Confirm print: (",
+ "piece(s))": "piece(s))",
+ "Printing...": "Printing...",
+ "Please wait...": "Please wait...",
+ "No available pick order(s) for this floor.": "No available pick order(s) for this floor.",
+ "You already have a pick order in progess. Please complete it first before taking next pick order.": "You already have a pick order in progess. Please complete it first before taking next pick order.",
+ "Error occurred during assignment.": "Error occurred during assignment.",
+ "Info": "Info",
+ "Warning": "Warning",
+ "Error": "Error",
+ "Batch Print": "Batch Print",
+ "No entries available": "No entries available",
+ "Today": "Today",
+ "Tomorrow": "Tomorrow",
+ "packaging": "packaging",
+ "This lot is not available, please scan another lot.": "This lot is not available, please scan another lot.",
+ "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.",
+ "Lot is expired (expiry={{expiry}})": "Lot is expired (expiry={{expiry}})",
+ "Day After Tomorrow": "Day After Tomorrow",
+ "Select Date": "Select Date",
+ "Suggest Lot No.": "Suggest Lot No.",
+ "Search by Shop": "Search by Shop",
+ "Search by Truck": "Search by Truck",
+ "Print DN & Label": "Print DN & Label",
+ "Print Label": "Print Label",
+ "Reprint Label(s)": "Reprint Label(s)",
+ "Reprint DN Label": "Reprint DN Label",
+ "From carton": "From carton",
+ "To carton": "To carton",
+ "Total cartons on shipment": "Total cartons on shipment",
+ "From carton must be at least 1": "From carton must be at least 1",
+ "To carton must be greater than or equal to from carton": "To carton must be greater than or equal to from carton",
+ "Total cartons on shipment must be at least 1": "Total cartons on shipment must be at least 1",
+ "To carton cannot be greater than total cartons on shipment": "To carton cannot be greater than total cartons on shipment",
+ "Not Yet Finished Released Do Pick Orders": "Not Yet Finished Released Do Pick Orders",
+ "Not yet finished released do pick orders": "Not yet finished released do pick orders",
+ "Released orders not yet completed - click lane to select and assign": "Released orders not yet completed - click lane to select and assign",
+ "Ticket Release Table": "Ticket Release Table",
+ "Please take one pick order before printing the draft.": "Please take one pick order before printing the draft.",
+ "No released pick order records found.": "No released pick order records found.",
+ "EDT - Lane Code (Unassigned/Total)": "EDT - Lane Code (Unassigned/Total)",
+ "Floor ticket": "Floor ticket",
+ "2F ticket": "2F ticket",
+ "4F ticket": "4F ticket",
+ "4F lane panel legend": "4F lane panel legend",
+ "Loading sequence n": "Loading sequence n",
+ "lot QR code": "lot QR code",
+ "label Printer": "label Printer",
+ "Loading Sequence": "Loading Sequence",
+ "Ticket No": "Ticket No",
+ "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated.": "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated.",
+ "is unavable. Please check around have available QR code or not.": "is unavable. Please check around have available QR code or not.",
+ "Lot switch failed; pick line was not marked as checked.": "Lot switch failed; pick line was not marked as checked.",
+ "Lot confirmation failed. Please try again.": "Lot confirmation failed. Please try again.",
+ "Powder Mixture": "Powder Mixture",
+ "This lot is not yet putaway": "This lot is not yet putaway",
+ "Cannot resolve new inventory lot line": "Cannot resolve new inventory lot line",
+ "Pick order line item is null": "Pick order line item is null",
+ "New lot line item does not match pick order line item": "New lot line item does not match pick order line item",
+ "Pick order line {{id}} not found": "Pick order line {{id}} not found",
+ "SuggestedPickLot not found for pickOrderLineId {{polId}}": "SuggestedPickLot not found for pickOrderLineId {{polId}}",
+ "SuggestedPickLot qty is invalid: {{qty}}": "SuggestedPickLot qty is invalid: {{qty}}",
+ "Reject switch lot: available {{available}} less than required {{required}}": "Reject switch lot: available {{available}} less than required {{required}}",
+ "Reject switch lot: picked {{picked}} already greater or equal required {{required}}": "Reject switch lot: picked {{picked}} already greater or equal required {{required}}",
+ "Lot status is unavailable. Cannot switch or bind; pick line was not updated.": "Lot status is unavailable. Cannot switch or bind; pick line was not updated.",
+ "No lot rows. Select a line in the table above.": "No lot rows. Select a line in the table above.",
+ "No stock out line for this lot": "No stock out line for this lot",
+ "No data available for this pick order.": "No data available for this pick order.",
+ "Report missing or bad items": "Report missing or bad items",
+ "passed": "Passed",
+ "failed": "Failed",
+ "confirm_accept_with_fail": "There are failed QC items. Confirm to accept stock out?"
+}
diff --git a/src/i18n/en/po.json b/src/i18n/en/po.json
new file mode 100644
index 0000000..abb99cf
--- /dev/null
+++ b/src/i18n/en/po.json
@@ -0,0 +1,16 @@
+{
+ "code": "code",
+ "status": "status",
+ "escalated": "escalated",
+ "notEscalated": "notEscalated",
+ "All": "All",
+ "Pending": "Pending",
+ "Receiving": "Receiving",
+ "Completed": "Completed",
+ "Purchase Order": "Purchase Order",
+ "Details": "Details",
+ "OrderDate": "OrderDate",
+ "Supplier": "Supplier",
+ "Escalated": "Escalated",
+ "NotEscalated": "NotEscalated"
+}
diff --git a/src/i18n/en/poWorkbench.json b/src/i18n/en/poWorkbench.json
index d054a2f..5612607 100644
--- a/src/i18n/en/poWorkbench.json
+++ b/src/i18n/en/poWorkbench.json
@@ -1,4 +1,5 @@
{
+ "PO Workbench": "PO Workbench",
"searchCriteria": {
"poPlaceholder": "Scan PO QR code or enter PO number",
"ariaPoSearch": "PO number search",
diff --git a/src/i18n/en/printer.json b/src/i18n/en/printer.json
new file mode 100644
index 0000000..0dd667f
--- /dev/null
+++ b/src/i18n/en/printer.json
@@ -0,0 +1,8 @@
+{
+ "Create Printer": "Create Printer",
+ "Edit": "Edit",
+ "PDF Preview": "PDF Preview",
+ "Print failed": "Print failed",
+ "Print job sent successfully": "Print job sent successfully",
+ "Printer": "Printer"
+}
diff --git a/src/i18n/en/production.json b/src/i18n/en/production.json
new file mode 100644
index 0000000..1dc2b2b
--- /dev/null
+++ b/src/i18n/en/production.json
@@ -0,0 +1,3 @@
+{
+ "Production Process": "Production Process"
+}
diff --git a/src/i18n/en/productionProcess.json b/src/i18n/en/productionProcess.json
new file mode 100644
index 0000000..3e68fe4
--- /dev/null
+++ b/src/i18n/en/productionProcess.json
@@ -0,0 +1,221 @@
+{
+ "Action": "Action",
+ "All": "All",
+ "An error has occurred. Please try again later.": "An error has occurred. Please try again later.",
+ "Are you sure you want to delete this process?": "Are you sure you want to delete this process?",
+ "Assignment successful": "Assignment successful",
+ "Assume End Time": "Assume End Time",
+ "Assume Time Need": "Assume Time Need",
+ "Auto-refresh every 1 minute": "Auto-refresh every 1 minute",
+ "Auto-refresh every 10 minutes": "Auto-refresh every 10 minutes",
+ "Back": "Back",
+ "Back to List": "Back to List",
+ "Bag": "Bag",
+ "Bag Consumption": "Bag Consumption",
+ "Balance": "Balance",
+ "Base Qty": "Base Qty",
+ "Base UOM": "Base UOM",
+ "Batch Count": "Batch Count",
+ "BoM Material": "BoM Material",
+ "Bom Req. Qty": "Bom Req. Qty",
+ "Bom Uom": "Bom Uom",
+ "By-product": "By-product",
+ "Cancel": "Cancel",
+ "Cancel Job Order": "Cancel Job Order",
+ "Cancel job order confirm message": "Cancel job order confirm message",
+ "Changeover Time": "Changeover Time",
+ "Changeover Time (mins)": "Changeover Time (mins)",
+ "Code": "Code",
+ "Complete Step": "Complete Step",
+ "Completed": "Completed",
+ "Completed Step": "Completed Step",
+ "Confirm": "Confirm",
+ "Confirm cancel job order": "Confirm cancel job order",
+ "Confirm delete job order": "Confirm delete job order",
+ "Confirm to Pass this Process?": "Confirm to Pass this Process?",
+ "Confirm to update this Job Order?": "Confirm to update this Job Order?",
+ "Consumed Qty": "Consumed Qty",
+ "Continue": "Continue",
+ "Count of Job Orders": "Count of Job Orders",
+ "Date": "Date",
+ "Defect": "Defect",
+ "Delete job order confirm message": "Delete job order confirm message",
+ "Description": "Description",
+ "Duration hours": "{{count}} hour(s)",
+ "Duration minutes": "{{count}} minute(s)",
+ "Duration seconds": "{{count}} second(s)",
+ "End Time": "End Time",
+ "Enter any additional production notes...": "Enter any additional production notes...",
+ "Equipment": "Equipment",
+ "Equipment Code": "Equipment Code",
+ "Equipment Name and Code": "Equipment Name and Code",
+ "Equipment Type": "Equipment Type",
+ "EquipmentType-EquipmentName-Code": "EquipmentType-EquipmentName-Code",
+ "Estimated Completion Time": "Estimated Completion Time",
+ "Executing": "Executing",
+ "FG / WIP Item": "FG / WIP Item",
+ "Filtered": "Filtered",
+ "Finished Time": "Finished Time",
+ "Finished lines": "Finished lines",
+ "In Progress": "In Progress",
+ "In progress": "In progress",
+ "Invalid Job Order Id": "Invalid Job Order 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",
+ "Item": "Item",
+ "Item Code": "Item Code",
+ "Item Name": "Item Name",
+ "Job Details": "Job Details",
+ "Job Order": "Job Order",
+ "Job Order Code": "Job Order Code",
+ "Job Order Info": "Job Order Info",
+ "Job Order No.": "Job Order No.",
+ "Job Order and Product": "Job Order and Product",
+ "Job Order Production Process": "Job Order Production Process",
+ "Job Process Status Dashboard": "Job Process Status Dashboard",
+ "Job Type": "Job Type",
+ "Job process detail mode label": "Job process detail mode label",
+ "Job process detail: equipment": "Equipment",
+ "Job process detail: handler": "Handler",
+ "Job process detail: process name": "Process Name",
+ "Job process detail: time": "Time",
+ "Just Pass": "Just Pass",
+ "Last updated": "Last updated",
+ "Lines with insufficient stock: ": "Lines with insufficient stock: ",
+ "Lines with sufficient stock: ": "Lines with sufficient stock: ",
+ "Lot No": "Lot No",
+ "Matching Stock": "Matching Stock",
+ "Material Code": "Material Code",
+ "N/A": "N/A",
+ "Name": "Name",
+ "Next page": "Next page",
+ "No data available": "No data available",
+ "No data found": "No data found",
+ "No.": "No.",
+ "Now": "Now",
+ "Operator": "Operator",
+ "Operator KPI Dashboard": "Operator KPI Dashboard",
+ "Operator Name & No.": "Operator Name & No.",
+ "Order Complete": "Order Complete",
+ "Output from Process": "Output from Process",
+ "Output Quantity": "Output Quantity",
+ "Over Time": "Over Time",
+ "Overall Time Remaining": "Overall Time Remaining",
+ "Passed Step": "Passed Step",
+ "Pause": "Pause",
+ "Pause Reason": "Pause Reason",
+ "Paused": "Paused",
+ "Pending": "Pending",
+ "Plan start (from)": "Plan start (from)",
+ "Plan start (to)": "Plan start (to)",
+ "Please scan equipment code": "Please scan equipment code",
+ "Please scan operator code first": "Please scan operator code first",
+ "Please scan staff no": "Please scan staff no",
+ "Post Prod Time (Minutes)": "Post Prod Time (Minutes)",
+ "Prep Time (Minutes)": "Prep Time (Minutes)",
+ "Previous page": "Previous page",
+ "Printer": "Printer",
+ "Process": "Process",
+ "Process & Equipment": "Process & Equipment",
+ "Process Description": "Process Description",
+ "Process Name": "Process Name",
+ "Process Start Time": "Process Start Time",
+ "Process Type": "Process Type",
+ "Process page summary": "Process {{from}}–{{to}} / {{total}} total",
+ "Processing Time": "Processing Time",
+ "Processing Time (mins)": "Processing Time (mins)",
+ "Product process status": "Product process status",
+ "Production Date": "Production Date",
+ "Production Equipment Status Dashboard": "Production Equipment Status Dashboard",
+ "Production Output Data": "Production Output Data",
+ "Production Output Data Entry": "Production Output Data Entry",
+ "Production Priority": "Production Priority",
+ "Production Process": "Production Process",
+ "Production Process Line Remark": "Production Process Line Remark",
+ "Production Process Steps": "Production Process Steps",
+ "Production Time Remaining": "Production Time Remaining",
+ "Production date": "Production date",
+ "Put Awayed Job Orders": "Put Awayed Job Orders",
+ "Qty": "Qty",
+ "Quality Check": "Quality Check",
+ "Quantity": "Quantity",
+ "Reason": "Reason",
+ "Release": "Release",
+ "Remaining Time": "Remaining Time",
+ "Remaining Time (min)": "Remaining Time (min)",
+ "Remark": "Remark",
+ "Req. Qty": "Req. Qty",
+ "Required Qty": "Required Qty",
+ "Required Time": "Required Time",
+ "SEQ": "SEQ",
+ "Save": "Save",
+ "Scan Operator & Equipment": "Scan Operator & Equipment",
+ "Scrap": "Scrap",
+ "Scrap Qty": "Scrap Qty",
+ "Search date": "Search date",
+ "Searched Item": "Searched Item",
+ "Select Another Bag Lot": "Select Another Bag Lot",
+ "Select Bag": "Select Bag",
+ "Select Date": "Select Date",
+ "Select Printer": "Select Printer",
+ "Select Unit": "Select Unit",
+ "Seq": "Seq",
+ "Seq No": "Seq No",
+ "Setup Time": "Setup Time",
+ "Setup Time (mins)": "Setup Time (mins)",
+ "Staff No": "Staff No",
+ "Start": "Start",
+ "Start QR Scan": "Start QR Scan",
+ "Start Time": "Start Time",
+ "Status": "Status",
+ "Step": "Step",
+ "Step Information": "Step Information",
+ "Step Name": "Step Name",
+ "Step Start Time": "Step Start Time",
+ "Stock Available": "Stock Available",
+ "Stock Req. Qty": "Stock Req. Qty",
+ "Stock Status": "Stock Status",
+ "Stock UOM": "Stock UOM",
+ "Stop QR Scan": "Stop QR Scan",
+ "Submit & Start": "Submit & Start",
+ "Submit Bag Consumption": "Submit Bag Consumption",
+ "Submitting...": "Submitting...",
+ "Target Production Date": "Target Production Date",
+ "Time Information(mins)": "Time Information (mins)",
+ "Time Remaining": "Time Remaining",
+ "Timer Paused": "Timer Paused",
+ "Total Processing Time": "Total Processing Time",
+ "Total Time": "Total Time",
+ "Total finished QC job orders": "Total finished QC job orders",
+ "Total job orders": "Total job orders",
+ "Total lines: ": "Total lines: ",
+ "Type": "Type",
+ "Unable to get user ID": "Unable to get user ID",
+ "Unit": "Unit",
+ "Unknown": "Unknown",
+ "Update Job Order": "Update Job Order",
+ "Update Production Priority": "Update Production Priority",
+ "Update Target Production Date": "Update Target Production Date",
+ "Update Required Quantity": "Update Required Quantity",
+ "Update Time Information": "Update Time Information",
+ "View": "View",
+ "View Details": "View Details",
+ "Wait Time": "Wait Time",
+ "Waiting QC Put Away Job Orders": "Waiting QC Put Away Job Orders",
+ "all": "All",
+ "drink": "Drink",
+ "id": "ID",
+ "mins": "mins",
+ "minutes": "minutes",
+ "FG": "FG",
+ "No processes found for this job order": "No processes found for this job order",
+ "SFG": "SFG",
+ "WIP": "WIP",
+ "fg": "fg",
+ "other": "Other",
+ "processing": "Processing",
+ "productionProcess": "Production Process",
+ "sfg": "sfg",
+ "view stockin": "View Stock In",
+ "wip": "wip"
+}
diff --git a/src/i18n/en/project.json b/src/i18n/en/project.json
index 45de18e..47f8b14 100644
--- a/src/i18n/en/project.json
+++ b/src/i18n/en/project.json
@@ -1,6 +1,16 @@
{
-
- "FG & Material Demand Forecast Detail": "FG & Material Demand Forecast Detail",
- "Release": "Release",
- "Actions": "Actions"
-}
\ No newline at end of file
+ "Actions": "Actions",
+ "Create Project": "Create Project",
+ "Details": "Details",
+ "FG & Material Demand Forecast Detail": "FG & Material Demand Forecast Detail",
+ "Product": "Product",
+ "Projects": "Projects",
+ "Project Code": "Project Code",
+ "Project Code and Name": "Project Code and Name",
+ "Release": "Release",
+ "View BoM": "View BoM",
+ "code": "code",
+ "Task": "Task",
+ "description": "description",
+ "details": "details"
+}
diff --git a/src/i18n/en/purchaseOrder.json b/src/i18n/en/purchaseOrder.json
index 9e26dfe..96f848a 100644
--- a/src/i18n/en/purchaseOrder.json
+++ b/src/i18n/en/purchaseOrder.json
@@ -1 +1,185 @@
-{}
\ No newline at end of file
+{
+ "Purchase Order": "Purchase Order",
+ "Purchase Receipt": "Purchase Receipt",
+ "Code": "Code",
+ "row per page": "Rows per page",
+ "Rows per page": "Rows per page",
+ "OrderDate": "Order Date",
+ "Order Date": "Order Date",
+ "Order Date To": "Order Date To",
+ "ETA": "ETA",
+ "ETA To": "ETA To",
+ "Details": "Details",
+ "Supplier": "Supplier",
+ "Status": "Receipt Status",
+ "escalateFrom": "Escalation Source",
+ "Escalated": "Escalated",
+ "NotEscalated": "Not Escalated",
+ "Do you want to start?": "Do you want to start?",
+ "Start": "Start",
+ "Start Success": "Start Success",
+ "Start Fail": "Start Fail",
+ "Start PO": "Start PO",
+ "Do you want to complete?": "Do you want to complete?",
+ "Cancel": "Cancel",
+ "Complete": "Complete",
+ "Complete Success": "Complete Success",
+ "Complete Fail": "Complete Fail",
+ "Complete PO": "Complete PO",
+ "General": "General",
+ "Bind Storage": "Bind Storage",
+ "PO No.": "PO No.",
+ "itemNo": "Item No.",
+ "itemName": "Item Name",
+ "Item Detail": "Item Detail",
+ "Item Code": "Item Code",
+ "Item Name": "Item Name",
+ "Item Qty": "Item Qty",
+ "Item": "Item",
+ "Item Accepted Qty": "Item Accepted Qty",
+ "Item Purchase UoM": "Item Purchase UoM",
+ "qty": "Order Qty",
+ "uom": "Purchase UoM",
+ "Stock UoM": "Stock UoM",
+ "Stock In Qty": "Stock In Qty",
+ "total weight": "Total Weight",
+ "weight unit": "Weight Unit",
+ "price": "Order Value",
+ "processedQty": "Put Away Qty",
+ "expiryDate": "Expiry Date",
+ "acceptedQty": "Accepted Qty (This Batch)",
+ "acceptedPutawayQty": "Put Away Qty (This Batch)",
+ "putawayQty": "Put Away Qty",
+ "Confirm submit": "Confirm Submit",
+ "This batch quantity exceeds order quantity. Do you still want to submit?": "This batch quantity exceeds order quantity. Do you still want to submit?",
+ "acceptQty": "Accept Qty",
+ "printQty": "Print Qty",
+ "qcResult": "QC Result",
+ "weight": "Weight",
+ "start": "Start",
+ "qc": "Quality Control",
+ "escalation": "Escalation",
+ "stock in": "Stock In",
+ "putaway": "Put Away",
+ "delete": "Delete",
+ "Accept quantity must be greater than 0": "Accept quantity must be greater than 0",
+ "QC items without result": "QC items without result",
+ "Failed items must have failed quantity": "Failed items must have failed quantity",
+ "qty cannot be greater than remaining qty": "Qty cannot be greater than remaining qty",
+ "acceptQty must not greater than": "Accept qty must not be greater than",
+ "Record pol": "Record PO",
+ "Add some entries!": "Add some entries!",
+ "draft": "Draft",
+ "pending": "Pending",
+ "determine1": "Escalation 1",
+ "determine2": "Escalation 2",
+ "determine3": "Escalation 3",
+ "receiving": "Receiving",
+ "received": "Awaiting Put Away",
+ "completed": "Put Away Completed",
+ "partially_completed": "Partially Put Away",
+ "rejected": "Rejected",
+ "escalated": "Escalated",
+ "status": "Status",
+ "acceptedQty must not greater than": "Accepted qty must not be greater than",
+ "minimal value is 1": "Minimum value is 1",
+ "value must be a number": "Value must be a number",
+ "qc Check": "QC Check",
+ "Please select QC": "Please select QC",
+ "failQty": "Fail Qty",
+ "select qc": "Select QC",
+ "enter a failQty": "Enter fail qty",
+ "qty too big": "Qty too big",
+ "sampleRate": "Sample Rate",
+ "sampleWeight": "Sample Weight",
+ "totalWeight": "Total Weight",
+ "Escalation": "Escalation",
+ "to be processed": "To Be Processed",
+ "supervisor": "Supervisor",
+ "Stock In Detail": "Stock In Detail",
+ "productLotNo": "Delivery Lot No.",
+ "receiptDate": "Receipt Date",
+ "acceptedWeight": "Accepted Weight",
+ "productionDate": "Production Date",
+ "reportQty": "Report Qty",
+ "Default Warehouse": "Suggested Warehouse",
+ "Select warehouse": "Select Warehouse",
+ "Putaway Detail": "Put Away Detail",
+ "Delivery Detail": "Delivery Detail",
+ "stockLotNo": "Stock Lot No.",
+ "Po Code": "PO No.",
+ "No Warehouse": "No Warehouse",
+ "Please scan warehouse qr code.": "Please scan warehouse QR code.",
+ "receivedQty": "Received Qty",
+ "dnQty": "Delivery Qty (This Batch)",
+ "Accept submit": "Accept Delivery",
+ "qc processing": "Delivery & QC Processing",
+ "putaway processing": "Delivery & Put Away Processing",
+ "view stockin": "View Stock In Detail",
+ "view putaway": "View Put Away Detail",
+ "putawayBtn": "Put Away",
+ "dnNo": "Delivery Note No.",
+ "dnDate": "Delivery Note Date",
+ "submitStockIn": "Update Delivery Info",
+ "QC Info": "QC Info",
+ "Escalation History": "Escalation History",
+ "Escalation Info": "Escalation Info",
+ "Escalation Result": "Escalation Result",
+ "update qc info": "Update QC Info",
+ "email supplier": "Email Supplier",
+ "confirm putaway": "Confirm & Complete Put Away",
+ "confirm qc result": "Confirm QC Result",
+ "warehouse": "Warehouse",
+ "qcItem": "QC Item",
+ "passed": "Passed",
+ "failed": "Failed",
+ "failedQty": "Failed Qty",
+ "remarks": "Remarks",
+ "Reject": "Reject",
+ "submit": "Submit",
+ "printQrCode": "Print QR Code",
+ "print": "Print",
+ "bind": "Bind",
+ "Search": "Search",
+ "Found": "Found",
+ "escalation processing": "Escalation Processing",
+ "Printer": "Printer",
+ "Printing": "Printing",
+ "rejectQty": "Reject Qty",
+ "QC decision is required": "QC decision is required",
+ "Select All": "Select All",
+ "View Selected": "View Selected",
+ "No Option": "No Option",
+ "receivedTotal": "Total Received",
+ "QC Record": "QC Record",
+ "value must be integer": "Value must be an integer",
+ "dn and qc info": "Delivery & QC Detail",
+ "Qc Decision": "QC Decision",
+ "Print Qty": "Print Qty",
+ "putawayDatetime": "Put Away Time",
+ "putawayUser": "Put Away User",
+ "joCode": "Job Order No.",
+ "salesUnit": "Sales Unit",
+ "download Qr Code": "Download QR Code",
+ "downloading": "Downloading",
+ "&": "&",
+ "Calculate Expiry Date": "Calculate Expiry Date",
+ "shelfLife": "Shelf Life",
+ "Fill in Expiry Date": "Fill in production date and shelf life to calculate expiry date",
+ "Expiry Date cannot be earlier than Production Date": "Expiry date cannot be earlier than production date",
+ "Production Date must be earlier than Expiry Date": "Production date must be earlier than expiry date",
+ "confirm expiry date": "Confirm Expiry Date",
+ "Invalid Date": "Invalid Date",
+ "Missing QC Template, please contact administrator": "Missing QC template, please contact administrator",
+ "submitting": "Submitting...",
+ "Submit": "Submit",
+ "Total must equal Required Qty. Missing": "Total must equal required qty. Missing: {{diff}}",
+ "Total must equal Required Qty. Exceeds by": "Total must equal required qty. Exceeds by: {{diff}}",
+ "Add Record": "Add Record",
+ "Clean Record": "Reset",
+ "Create Material": "Create Material",
+ "Will start binding procedure after scanning item qr code.": "Will start binding procedure after scanning item qr code.",
+ "Quantity": "Quantity",
+ "Enter quantity": "Enter quantity",
+ "Enter your remark": "Enter your remark"
+}
diff --git a/src/i18n/en/putAway.json b/src/i18n/en/putAway.json
new file mode 100644
index 0000000..806ee3c
--- /dev/null
+++ b/src/i18n/en/putAway.json
@@ -0,0 +1,26 @@
+{
+ "Pending scan": "Pending scan",
+ "Please scan warehouse qr code": "Please scan warehouse qr code",
+ "PoCode/JoCode": "PoCode/JoCode",
+ "Put Away": "Put Away",
+ "Put Away Scan": "Put Away Scan",
+ "Rescan": "Rescan",
+ "Scanning": "Scanning",
+ "acceptedQty": "acceptedQty",
+ "confirm putaway": "confirm putaway",
+ "itemCode": "itemCode",
+ "itemName": "itemName",
+ "lotNo": "lotNo",
+ "minimal value is 1": "minimal value is 1",
+ "poCode": "poCode",
+ "putAwayHistory": "putAwayHistory",
+ "putQty": "putQty",
+ "putQty must not greater than": "putQty must not greater than",
+ "putawayQty": "putawayQty",
+ "scan loading": "scan loading",
+ "scan warehouse": "scan warehouse",
+ "uom": "uom",
+ "value must be a number": "value must be a number",
+ "value must be integer": "value must be integer",
+ "warehouse": "warehouse"
+}
diff --git a/src/i18n/en/qcCategory.json b/src/i18n/en/qcCategory.json
new file mode 100644
index 0000000..b25c2c6
--- /dev/null
+++ b/src/i18n/en/qcCategory.json
@@ -0,0 +1,21 @@
+{
+ "Cancel": "Cancel",
+ "Code": "Code",
+ "Create Qc Category": "Create Qc Category",
+ "Delete": "Delete",
+ "Description": "Description",
+ "Details": "Details",
+ "Edit Qc Category": "Edit Qc Category",
+ "Edit Qc Item": "Edit Qc Item",
+ "Name": "Name",
+ "Qc Category": "Qc Category",
+ "Qc Category Created At": "Qc Category Created At",
+ "Qc Category Description": "Qc Category Description",
+ "Qc Category List": "Qc Category List",
+ "Qc Category Name": "Qc Category Name",
+ "Qc Category Status": "Qc Category Status",
+ "Qc Category Updated At": "Qc Category Updated At",
+ "Qc Item": "Qc Item",
+ "Qc Item Details": "Qc Item Details",
+ "Submit": "Submit"
+}
diff --git a/src/i18n/en/qcItem.json b/src/i18n/en/qcItem.json
new file mode 100644
index 0000000..c85af2d
--- /dev/null
+++ b/src/i18n/en/qcItem.json
@@ -0,0 +1,13 @@
+{
+ "Cancel": "Cancel",
+ "Code": "Code",
+ "Create Qc Item": "Create Qc Item",
+ "Delete": "Delete",
+ "Description": "Description",
+ "Details": "Details",
+ "Edit Qc Item": "Edit Qc Item",
+ "Name": "Name",
+ "Qc Item": "Qc Item",
+ "Qc Item Details": "Qc Item Details",
+ "Submit": "Submit"
+}
diff --git a/src/i18n/en/qcItemAll.json b/src/i18n/en/qcItemAll.json
index f587f48..3cc2e26 100644
--- a/src/i18n/en/qcItemAll.json
+++ b/src/i18n/en/qcItemAll.json
@@ -1,58 +1,66 @@
{
- "Qc Item All": "QC Management",
- "Item and Qc Category Mapping": "Item and Qc Category Mapping",
- "Qc Category and Qc Item Mapping": "Qc Category and Qc Item Mapping",
- "Qc Category Management": "Qc Category Management",
- "Qc Item Management": "Qc Item Management",
- "Qc Category": "Qc Category",
- "Qc Item": "Qc Item",
- "Item": "Item",
- "Code": "Code",
- "Name": "Name",
- "Description": "Description",
- "Type": "Type",
- "Order": "Order",
- "Item Count": "Item Count",
- "Qc Item Count": "Qc Item Count",
- "Qc Category Count": "Qc Category Count",
"Actions": "Actions",
- "View": "View",
- "Edit": "Edit",
- "Delete": "Delete",
"Add": "Add",
- "Add Mapping": "Add Mapping",
"Add Association": "Add Association",
- "Save": "Save",
+ "Add Mapping": "Add Mapping",
+ "Are you sure you want to delete this item?": "Are you sure you want to delete this item?",
+ "Association Details": "Association Details",
"Cancel": "Cancel",
- "Submit": "Submit",
- "Details": "Details",
- "Create Qc Category": "Create Qc Category",
- "Edit Qc Category": "Edit Qc Category",
- "Create Qc Item": "Create Qc Item",
- "Edit Qc Item": "Edit Qc Item",
- "Delete Success": "Delete Success",
- "Delete Error": "Delete Error",
- "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.": "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.",
- "Select Item": "Select Item",
- "Select Qc Category": "Select Qc Category",
- "Select Qc Item": "Select Qc Item",
- "Select Type": "Select Type",
+ "Category": "Category",
+ "Category Type": "Category Type",
+ "Code": "Code",
+ "Confirm": "Confirm",
+ "Confirm Delete": "Confirm Delete",
+ "Create Qc Category": "Create Qc Category",
+ "Create Qc Item": "Create Qc Item",
+ "Delete": "Delete",
+ "Delete Error": "Delete Error",
+ "Delete Success": "Delete Success",
+ "Description": "Description",
+ "Details": "Details",
+ "Do you want to delete?": "Do you want to delete?",
+ "Do you want to submit?": "Do you want to submit?",
+ "Edit": "Edit",
+ "Edit Qc Category": "Edit Qc Category",
+ "Edit Qc Item": "Edit Qc Item",
+ "Enter item code to validate": "Enter item code to validate",
+ "Error validating item code": "Error validating item code",
+ "Item": "Item",
"Item Code": "Item Code",
+ "Item Count": "Item Count",
"Item Name": "Item Name",
+ "Item already has type \"{{type}}\" in QcCategory \"{{category}}\". One item can only have each type in one QcCategory.": "Item already has type \"{{type}}\" in QcCategory \"{{category}}\". One item can only have each type in one QcCategory.",
+ "Item and Qc Category Mapping": "Item and Qc Category Mapping",
+ "Item code not found": "Item code not found",
+ "Mapping Details": "Mapping Details",
+ "Name": "Name",
+ "No associations found": "No associations found",
+ "No data available": "No data available",
+ "No mappings found": "No mappings found",
+ "Order": "Order",
+ "Qc Category": "Qc Category",
"Qc Category Code": "Qc Category Code",
+ "Qc Category Count": "Qc Category Count",
+ "Qc Category Management": "Qc Category Management",
"Qc Category Name": "Qc Category Name",
+ "Qc Category and Qc Item Mapping": "Qc Category and Qc Item Mapping",
+ "Qc Item": "Qc Item",
+ "Qc Item All": "QC Management",
"Qc Item Code": "Qc Item Code",
+ "Qc Item Count": "Qc Item Count",
+ "Qc Item Management": "Qc Item Management",
"Qc Item Name": "Qc Item Name",
- "Mapping Details": "Mapping Details",
- "Association Details": "Association Details",
- "No mappings found": "No mappings found",
- "No associations found": "No associations found",
- "No data available": "No data available",
- "Confirm Delete": "Confirm Delete",
- "Are you sure you want to delete this item?": "Are you sure you want to delete this item?"
+ "Save": "Save",
+ "Select Item": "Select Item",
+ "Select Qc Category": "Select Qc Category",
+ "Select Qc Item": "Select Qc Item",
+ "Select Type": "Select Type",
+ "Submit": "Submit",
+ "Submit Error": "Submit Error",
+ "Submit Success": "Submit Success",
+ "Type": "Type",
+ "View": "View"
}
-
diff --git a/src/i18n/en/qrCodeHandle.json b/src/i18n/en/qrCodeHandle.json
new file mode 100644
index 0000000..b5c8133
--- /dev/null
+++ b/src/i18n/en/qrCodeHandle.json
@@ -0,0 +1,5 @@
+{
+ "PDF Preview": "PDF Preview",
+ "QR Code Handle": "QR Code Handle",
+ "Equipment": "Equipment"
+}
diff --git a/src/i18n/en/report.json b/src/i18n/en/report.json
new file mode 100644
index 0000000..c13c611
--- /dev/null
+++ b/src/i18n/en/report.json
@@ -0,0 +1,13 @@
+{
+ "Report": "Report",
+ "title": "Report Management",
+ "selectReport": "Select Report",
+ "reportList": "Report List",
+ "selectReportHelper": "Select a report",
+ "searchCriteria": "Search Criteria",
+ "downloadPdf": "Download Report (PDF)",
+ "downloadExcel": "Download Report (Excel)",
+ "generatingPdf": "Generating PDF...",
+ "generatingExcel": "Generating Excel...",
+ "generatingReport": "Generating report..."
+}
diff --git a/src/i18n/en/schedule.json b/src/i18n/en/schedule.json
index 75a38bf..6d1ae64 100644
--- a/src/i18n/en/schedule.json
+++ b/src/i18n/en/schedule.json
@@ -1,10 +1,121 @@
{
- "Total Demand Qty": "Total Demand Qty",
- "Demand Qty (Day1)": "Demand Qty (Day1)",
- "Demand Qty (Day2)": "Demand Qty (Day2)",
- "Demand Qty (Day3)": "Demand Qty (Day3)",
- "Demand Qty (Day4)": "Demand Qty (Day4)",
- "Demand Qty (Day5)": "Demand Qty (Day5)",
- "Demand Qty (Day6)": "Demand Qty (Day6)",
- "Demand Qty (Day7)": "Demand Qty (Day7)"
-}
\ No newline at end of file
+ " (Selected)": " (Selected)",
+ "Actions": "Actions",
+ "Add": "Add",
+ "Available Qty": "Available Qty",
+ "Avg Qty Last Month": "Avg Qty Last Month",
+ "Back": "Back",
+ "Batch Need": "Batch Need",
+ "CODE": "CODE",
+ "Cancel": "Cancel",
+ "Close": "Close",
+ "Code": "Code",
+ "Confirm": "Confirm",
+ "Date": "Date",
+ "Days Left": "Days Left",
+ "Delete": "Delete",
+ "Demand Forecast": "Demand Forecast",
+ "Demand Forecast Detail": "Demand Forecast Detail",
+ "Demand Forecast Period": "Demand Forecast Period",
+ "Demand Qty": "Demand Qty",
+ "Demand Qty (7 Days)": "Demand Qty (7 Days)",
+ "Demand Qty (Day1)": "Demand Qty (Day1)",
+ "Demand Qty (Day2)": "Demand Qty (Day2)",
+ "Demand Qty (Day3)": "Demand Qty (Day3)",
+ "Demand Qty (Day4)": "Demand Qty (Day4)",
+ "Demand Qty (Day5)": "Demand Qty (Day5)",
+ "Demand Qty (Day6)": "Demand Qty (Day6)",
+ "Demand Qty (Day7)": "Demand Qty (Day7)",
+ "Detail Scheduling": "Detail Scheduling",
+ "Detailed Schedule": "Detailed Schedule",
+ "Detailed": "Detailed",
+ "Details": "Details",
+ "Edit": "Edit",
+ "Estimated Production Time": "Estimated Production Time",
+ "Export Schedule": "Export Schedule",
+ "FG & Material Demand Forecast": "FG & Material Demand Forecast",
+ "FG & Material Demand Forecast Detail": "FG & Material Demand Forecast Detail",
+ "FG Demand Date": "FG Demand Date",
+ "FG Demand List (7 Days)": "FG Demand List (7 Days)",
+ "FG Demand Qty": "FG Demand Qty",
+ "FG Production Schedule": "FG Production Schedule",
+ "Fri": "Fri",
+ "Job Date": "Job Date",
+ "Job Name": "Job Name",
+ "Job No.": "Job No.",
+ "Job Priority": "Job Priority",
+ "Job Qty": "Job Qty",
+ "Job Status": "Job Status",
+ "Job Type": "Job Type",
+ "Last Month Average Sales": "Last Month Average Sales",
+ "Last Month Average Stock": "Last Month Average Stock",
+ "Material Demand Date": "Material Demand Date",
+ "Material Demand List": "Material Demand List",
+ "Material Demand List (7 Days)": "Material Demand List (7 Days)",
+ "Mon": "Mon",
+ "Name": "Name",
+ "Output Qty": "Output Qty",
+ "Overall": "Overall",
+ "Product Count": "Product Count",
+ "Product Count(s)": "Product Count(s)",
+ "Production Date": "Production Date",
+ "Production Priority": "Production Priority",
+ "Release": "Release",
+ "Reset": "Reset",
+ "Safety Stock": "Safety Stock",
+ "Sales Qty": "Sales Qty",
+ "Sales UOM": "Sales UOM",
+ "Sat": "Sat",
+ "Save": "Save",
+ "Schedule": "Schedule",
+ "Schedule At": "Schedule At",
+ "Schedule Detail": "Schedule Detail",
+ "Schedule Period": "Schedule Period",
+ "Schedule Period To": "Schedule Period To",
+ "Scheduled At": "Scheduled At",
+ "Search": "Search",
+ "Selected": "Selected",
+ "Status": "Status",
+ "Stock Qty": "Stock Qty",
+ "Sun": "Sun",
+ "Test Detailed Schedule": "Test Detailed Schedule",
+ "Test Rough Schedule": "Test Rough Schedule",
+ "Thu": "Thu",
+ "Total Demand Qty": "Total Demand Qty",
+ "Total Estimated Demand Qty": "Total Estimated Demand Qty",
+ "Total FG Item": "Total FG Item",
+ "Total Job Order": "Total Job Order",
+ "Total Job Orders": "Total Job Orders",
+ "Total Production Qty": "Total Production Qty",
+ "Tue": "Tue",
+ "Type": "Type",
+ "Unselected": "Unselected",
+ "UoM": "UoM",
+ "View BoM": "View BoM",
+ "View By FG": "View By FG",
+ "View By Material": "View By Material",
+ "Wed": "Wed",
+ "code": "code",
+ "consumables": "consumables",
+ "detailed": "detailed",
+ "fg": "fg",
+ "item": "item",
+ "Item Name": "Item Name",
+ "Priority": "Priority",
+ "Mat Code": "Mat Code",
+ "Mat Name": "Mat Name",
+ "Required Qty": "Required Qty",
+ "Total Qty Need": "Total Qty Need",
+ "Purchased Qty": "Purchased Qty",
+ "On Hand Qty": "On Hand Qty",
+ "Unavailable Qty": "Unavailable Qty",
+ "Related Item Code": "Related Item Code",
+ "Related Item Name": "Related Item Name",
+ "Material Summary": "Material Summary",
+ "mat": "mat",
+ "name": "name",
+ "non-consumables": "non-consumables",
+ "sfg": "sfg",
+ "type": "type",
+ "Generate Job Order": "Generate Job Order"
+}
diff --git a/src/i18n/en/scheduling.json b/src/i18n/en/scheduling.json
new file mode 100644
index 0000000..3531f16
--- /dev/null
+++ b/src/i18n/en/scheduling.json
@@ -0,0 +1,5 @@
+{
+ "title": "Scheduling",
+ "Scheduling": "Scheduling",
+ "ps": "Scheduling"
+}
diff --git a/src/i18n/en/settings.json b/src/i18n/en/settings.json
new file mode 100644
index 0000000..427d1c8
--- /dev/null
+++ b/src/i18n/en/settings.json
@@ -0,0 +1,14 @@
+{
+ "settings": "settings",
+ "Demand Forecast Setting": "Demand Forecast Setting",
+ "Import Master Data": "Import Master Data",
+ "Import Po": "Import Po",
+ "QC Check Template": "QC Check Template",
+ "QC Check Template Created At": "QC Check Template Created At",
+ "QC Check Template Description": "QC Check Template Description",
+ "QC Check Template Details": "QC Check Template Details",
+ "QC Check Template Name": "QC Check Template Name",
+ "QC Check Template Status": "QC Check Template Status",
+ "QC Check Template Updated At": "QC Check Template Updated At",
+ "Ready to import": "Ready to import"
+}
diff --git a/src/i18n/en/shop.json b/src/i18n/en/shop.json
new file mode 100644
index 0000000..6b864aa
--- /dev/null
+++ b/src/i18n/en/shop.json
@@ -0,0 +1,471 @@
+{
+ "Actions": "Actions",
+ "Add New Truck Lane": "Add New Truck Lane",
+ "Add Shop": "Add Shop",
+ "Add Shop to Truck Lane": "Add Shop to Truck Lane",
+ "Add Truck Lane": "Add Truck Lane",
+ "Addr1": "Addr1",
+ "Addr2": "Addr2",
+ "Addr3": "Addr3",
+ "All": "All",
+ "All shops updated successfully": "All shops updated successfully",
+ "Back": "Back",
+ "Back to Truck Lane List": "Back to Truck Lane List",
+ "Cancel": "Cancel",
+ "Cancel editing": "Cancel editing",
+ "Changed": "Changed",
+ "Code": "Code",
+ "Complete": "Complete",
+ "Contact Email": "Contact Email",
+ "Contact Name": "Contact Name",
+ "Contact No": "Contact No",
+ "Current version": "Current version",
+ "Delete truck lane": "Delete truck lane",
+ "Departure": "Departure",
+ "Departure Time": "Departure Time",
+ "Departure time updated for all shops on this truck lane": "Departure time updated for all shops on this truck lane",
+ "District Reference": "District Reference",
+ "Driver": "Driver",
+ "Edit departure time": "Edit departure time",
+ "Edit shop details": "Edit shop details",
+ "Failed to create shop in truck lane": "Failed to create shop in truck lane",
+ "Failed to create truck": "Failed to create truck",
+ "Failed to delete truck lane": "Failed to delete truck lane",
+ "Failed to load shop details": "Failed to load shop details",
+ "Failed to load shops": "Failed to load shops",
+ "Failed to load truck lane detail": "Failed to load truck lane detail",
+ "Failed to load truck lanes": "Failed to load truck lanes",
+ "Failed to save": "Failed to save",
+ "Failed to save truck data": "Failed to save truck data",
+ "Failed to save truck shop details": "Failed to save truck shop details",
+ "Filter by Status": "Filter by Status",
+ "Invalid Shop ID": "Invalid Shop ID",
+ "Invalid departure time": "Invalid departure time",
+ "Invalid shop data": "Invalid shop data",
+ "Loading Sequence": "Loading Sequence",
+ "Logistic": "Logistic",
+ "Mass Edit": "Mass Edit",
+ "Missing Data": "Missing Data",
+ "Name": "Name",
+ "No Truck Lane data available": "No Truck Lane data available",
+ "No Truck data available": "No Truck data available",
+ "No TruckLance": "No TruckLance",
+ "No changes": "No changes",
+ "No shops found using this truck lane": "No shops found using this truck lane",
+ "No truck lane data available": "No truck lane data available",
+ "No trucks found for this truck lane": "No trucks found for this truck lane",
+ "Not editable for this Store ID": "Not editable for this Store ID",
+ "Plate": "Plate",
+ "Please fill in the following required fields:": "Please fill in the following required fields:",
+ "Please log in to view shop details": "Please log in to view shop details",
+ "Remark": "Remark",
+ "Save": "Save",
+ "Save All": "Save All",
+ "Save changes": "Save changes",
+ "Saved": "Saved",
+ "Search or select remark": "Search or select remark",
+ "Search or select shop name": "Search or select shop name",
+ "Shop": "Shop",
+ "Shop Branch": "Shop Branch",
+ "Shop Code": "Shop Code",
+ "Shop ID is required": "Shop ID is required",
+ "Shop Information": "Shop Information",
+ "Shop Name": "Shop Name",
+ "Shop added to truck lane successfully": "Shop added to truck lane successfully",
+ "Shop not found": "Shop not found",
+ "ShopAndTruck": "Lane & shop management",
+ "Shops": "Shops",
+ "Shops Using This Truck Lane": "Shops Using This Truck Lane",
+ "Store ID": "Store ID",
+ "Submitting...": "Submitting…",
+ "Truck Information": "Truck Information",
+ "Truck Lane": "Truck Lane",
+ "Truck Lane Detail": "Truck Lane Detail",
+ "Truck lane code already exists. Please use a different code.": "Truck lane code already exists. Please use a different code.",
+ "Truck lane deleted successfully": "Truck lane deleted successfully",
+ "Truck lane information is required": "Truck lane information is required",
+ "Truck lane not found": "Truck lane not found",
+ "Truck shop details updated successfully": "Truck shop details updated successfully",
+ "TruckLance Code": "TruckLance Code",
+ "TruckLance Code is required": "TruckLance Code is required",
+ "TruckLance Status": "TruckLance Status",
+ "View Detail": "View Detail",
+ "addRoute_confirm": "Confirm add lane",
+ "addRoute_dialogTitle": "Add delivery lane",
+ "addRoute_hint": "After confirm, the lane is staged on the board; press \"Save changes\" in the header to create it on the server (no dummy shop rows).",
+ "addRoute_submitting": "Adding…",
+ "addShop_confirm": "Confirm",
+ "addShop_dialogTitle": "Add shop to lane",
+ "addShop_listHint": "Shop codes already on this lane are hidden from the list. After adding, reorder by drag; like other edits, press \"Save changes\" to persist to truck rows.",
+ "api_fail_addShop": "Failed to add shop",
+ "api_fail_createLane": "Failed to create lane",
+ "api_fail_deleteShop": "Failed to delete shop",
+ "api_fail_updateLane": "Failed to update lane",
+ "api_fail_updateLogistics": "Failed to update logistics",
+ "aria_deleteLogistics": "Delete logistics company",
+ "aria_editDistrict": "Edit district",
+ "aria_editLogistics": "Edit logistics company",
+ "aria_editSeq": "Edit load sequence",
+ "aria_openLaneBoard": "Open lane on route board",
+ "aria_pickLane": "Pick lane",
+ "aria_removeEmptyDistrict": "Remove empty district block",
+ "aria_searchLanes": "Search lanes",
+ "btn_addDistrict": "Add district",
+ "btn_addLane": "Add lane",
+ "btn_addLogistics": "Add logistics",
+ "btn_addShopToLane": "Add shop",
+ "btn_apply": "Apply",
+ "btn_cancelBack": "Cancel and go back",
+ "btn_loading": "Loading…",
+ "btn_openVersionLog": "Version log",
+ "btn_refresh": "Refresh",
+ "btn_scheduleChange": "Schedule changes",
+ "btn_scheduleHistory": "Schedule change log",
+ "cancel": "Cancel",
+ "code": "code",
+ "confirm_addShopConflict": "Detected {{count}} potential conflict(s) with other lanes (Rules 1/2; see bell). It will be added to the board first; press \"Save changes\" to persist. Continue?",
+ "confirm_clearLane": "Clear all {{count}} shop(s) from lane \"{{laneLabel}}\"? (Press \"Save changes\" to delete on server)",
+ "confirm_deleteLogistic": "Delete logistics company \"{{name}}\"? Press \"Save changes\" to persist.",
+ "confirm_departureConflict": "After changing departure time, {{count}} potential conflict(s) detected (Rules 1/2; see bell). Apply anyway?",
+ "confirm_discardDraftShop": "Discard unsaved \"new shop\" draft?",
+ "confirm_importDiscardEdits": "Import will replace unsaved board edits. Continue?",
+ "confirm_removeShop": "Remove this shop from the lane? (Press \"Save changes\" to persist)",
+ "confirm_restoreDiscardsEdits": "Scheduling a version restore will discard other unsaved board changes (drags, deletes, pending shops/lanes, logistics fields, etc.). Continue?",
+ "confirm_restoreSaveWillDropStaging": "Save will apply the snapshot restore first; other staged edits in this save will be skipped. Continue?",
+ "confirm_schedule_removeShop": "Remove this shop from the lane? It will be scheduled for deletion when you submit.",
+ "departureDialog_hint": "Applies to all shop rows on this lane; press \"Save changes\" above to persist.",
+ "departureDialog_title": "Edit departure time",
+ "departureEditAria": "Edit departure time",
+ "departureTooltipEditSave": "Edit departure time (saved with \"Save changes\")",
+ "departureTooltipNeedShops": "Add shops before setting departure time",
+ "dialog_addLogisticsTitle": "Add logistics",
+ "dialog_close": "Close",
+ "dialog_editLogisticsTitle": "Edit logistics master",
+ "diffField_logisticsCompany": "Logistics company",
+ "diffLogistic_unassigned": "Unassigned",
+ "diff_addedToLane": "Added to lane {{lane}}",
+ "diff_clickLeft": "Select a version on the left to view changes",
+ "diff_editedCaption": "Field edits (sequence / branch name / time window, etc.)",
+ "diff_export_blockedError": "Cannot export while the board has unsaved changes (Excel is persisted snapshots only).",
+ "diff_export_blockedTooltip": "Export compares two persisted snapshots only. Save or discard board changes first, then export.",
+ "diff_export_reportBtn": "Export version lane report",
+ "diff_loadFail": "Failed to load version diff",
+ "diff_loadingEllipsis": "…",
+ "diff_logisticMaster_added": "Added",
+ "diff_logisticMaster_edited": "Edited",
+ "diff_logisticMaster_section": "Logistics company changes",
+ "diff_markedCount": "{{count}} change(s)",
+ "diff_moveFrom": "From {{lane}}",
+ "diff_moveTo": "Move to {{lane}}",
+ "diff_noDiffFromPrev": "No differences vs previous version",
+ "diff_noOlderCompare": "No older version to compare (pick a newer version)",
+ "diff_noShopDiffHasBoardStaged": "No shop-row changes vs the previous snapshot. Below are unsaved board edits (including new logistics company records).",
+ "diff_oldestSnapshot": "Oldest snapshot—no older version to diff against.",
+ "diff_onLane": "Lane {{lane}}",
+ "diff_removedFromLane": "Removed from {{lane}}",
+ "diff_restoreAlreadyPending": "This version is already scheduled; press \"Save changes\" to apply.",
+ "diff_restoreFail": "Restore failed",
+ "diff_restoreScheduled": "Restore to version #{{versionId}} is scheduled; press \"Save changes\" to persist.",
+ "diff_restoreToHead": "Schedule restore to latest snapshot (requires Save)",
+ "diff_restoreToSelected": "Schedule restore to this version (requires Save)",
+ "diff_shopList_title": "Shop change list",
+ "diff_staged_boardPendingLine": "{{count}} unsaved / scheduled board item(s) — see the list below.",
+ "diff_staged_deleteLogisticMaster": "Delete logistics company (not saved): {{name}}",
+ "diff_staged_deleteUnknown": "Delete truck id={{id}} (unsaved; save or cancel to refresh details)",
+ "diff_staged_editLogisticMaster": "Edit logistics company (unsaved): {{fromName}} ({{fromPlate}}) → {{name}} ({{plate}})",
+ "diff_staged_emptyDistricts": "Empty-district blocks (unsaved): {{lane}} — {{names}}",
+ "diff_staged_importPending": "Import Excel (unsaved): {{file}} — {{sheets}} sheet(s), {{rows}} row(s) (persisted on \"Save changes\")",
+ "diff_staged_laneLogistic": "Lane logistics (unsaved): {{lane}} → {{company}}",
+ "diff_staged_newLane": "New lane (unsaved): {{lane}}",
+ "diff_staged_pendingLogisticMaster": "New logistics company (not saved yet): {{name}} (plate {{plate}}); will be created on \"Save changes\" together with route edits",
+ "diff_staged_restoreScheduled": "Restore to version #{{versionId}} is scheduled (calls restore only after \"Save changes\").",
+ "diff_staged_section_subtitle": "These match what will hit the DB after \"Save changes\"; listed separately from the version diff above (Excel is server snapshots only).",
+ "diff_staged_section_title": "Board: unsaved / scheduled (not persisted yet)",
+ "diff_staged_shopDistrictHint": " · District: {{from}}→{{to}}",
+ "diff_staged_shopDistrictOnly": "{{name}} ({{code}}) — lane {{lane}}: district {{from}}→{{to}} (unsaved; persisted on \"Save changes\")",
+ "diff_staged_shopPendingOnLane": "{{name}} ({{code}}) — lane {{lane}}: unsaved edits (drag / departure / load order; persisted on \"Save changes\"){{districtPart}}",
+ "diff_staged_tag_scheduled": "Scheduled",
+ "diff_staged_tag_unsaved": "Unsaved",
+ "diff_summary_added": "Added",
+ "diff_summary_deleted": "Deleted",
+ "diff_summary_fieldChange": "Field changes",
+ "diff_summary_moved": "Moved",
+ "diff_summary_title": "Summary",
+ "district_dialog_add": "Add district",
+ "district_dialog_edit": "Edit district",
+ "district_err_exists": "This district already exists",
+ "district_err_name": "Enter a district name",
+ "district_err_reserved": "\"Unclassified\" is built-in; do not add it again",
+ "district_help_mapped": "Display name is written via toDistrictRawValue to each shop's districtReference; API runs on \"Save changes\"",
+ "district_help_null": "Unclassified maps to districtReference = null on server",
+ "district_name_label": "District display name",
+ "district_name_ph": "Blank means \"Unclassified\"",
+ "drag_blockDraftShop": "Unsaved \"new shop\" rows must be saved with \"Save changes\" or removed from the card before dragging.",
+ "drawerClose": "Close",
+ "emDash": "—",
+ "empty_lane_noShops": "No assigned shops",
+ "err_dragDuplicateShop": "Target lane already has this shop (same shop / same shop code)",
+ "err_export": "Export failed",
+ "err_exportNeedSelection": "Select at least one lane on the left to export",
+ "err_import": "Import failed",
+ "err_importEmpty": "No valid lane rows found in the import file",
+ "err_invalidMasterId": "Invalid master record id",
+ "err_loadLanes": "Failed to load lanes",
+ "err_logisticDeleteHasLanes": "This company still has {{count}} lane(s). Reassign or remove them first.",
+ "err_noLanes": "No lane data",
+ "err_save": "Save failed",
+ "exportRoutes": "Export routes",
+ "filter_apply": "OK",
+ "filter_clear": "Clear",
+ "floor_all": "All",
+ "floor_label": "Floor",
+ "id": "id",
+ "importRoutes": "Import routes",
+ "import_staged_preview": "Import preview loaded: {{file}} ({{sheets}} sheet(s) / {{rows}} rows). Press \"Save changes\" to persist.",
+ "lane_companyChip": "{{count}} lane(s)",
+ "lane_searchPh": "Search…",
+ "lane_selectAll": "Select all",
+ "lane_selectTitle": "Lanes",
+ "lane_selectedCount": "{{count}} selected",
+ "lane_selectedNone": "No lanes selected",
+ "lane_shopCountInline": "{{count}} shop(s)",
+ "logistic_btn_apply": "Apply",
+ "logistic_btn_save": "Save",
+ "logistic_btn_saveDb": "Save to database",
+ "logistic_companyName": "Company name",
+ "logistic_driver": "Driver name",
+ "logistic_needMasterTpl": "\"{{name}}\" has no logistics master id—create it with \"Add logistics\" first.",
+ "logistic_phone": "Phone",
+ "logistic_plate": "Plate",
+ "logistics_colLaneCount": "{{count}} lane(s)",
+ "logistics_colShopCount": "{{count}} shop(s)",
+ "logistics_dirtyColumnBadge": "Unsaved logistics changes",
+ "logistics_dirtyLaneBadge": "Unsaved logistics on lane",
+ "logistics_overviewTitle": "Logistics overview",
+ "logistics_sidebarEmpty": "No lanes (refresh or relax filters)",
+ "mtmsRouteWarn_conflict4f": "4F: same shop on different lanes · weekday {{weekday}}",
+ "mtmsRouteWarn_conflictDep": "Non-4F: same shop on different lanes · departure {{time}}",
+ "mtmsRouteWarn_copyAll": "Copy all",
+ "mtmsRouteWarn_empty": "No data conflicts.",
+ "mtmsRouteWarn_parseHint": "{{count}} 4F lane(s): weekday could not be determined (excluded from alerts)",
+ "mtmsRouteWarn_postAddConflict": "After adding the shop, data conflicts with other lane(s). Open the bell for details.",
+ "mtmsRouteWarn_refresh": "Reload data",
+ "mtmsRouteWarn_refreshing": "Loading…",
+ "mtmsRouteWarn_shop": "Shop",
+ "mtmsRouteWarn_title": "Route data alerts",
+ "mtmsRouteWarn_tooltipHas": "{{count}} potential conflict(s)",
+ "mtmsRouteWarn_tooltipNone": "No alerts",
+ "nav_unsavedLeave": "You have unsaved changes. Leave this page?",
+ "new arrangement": "new arrangement",
+ "pageTitle": "MTMS route & shop board",
+ "quickIndex": "Quick index",
+ "quickPick_noKeyword": "No lanes match the keyword",
+ "quickPick_noLanes": "No lanes (relax floor filter or refresh)",
+ "restore_applied": "Snapshot restore applied; board reloaded.",
+ "restore_appliedDroppedStaging": "Snapshot restore applied; other staged edits in this save were skipped (edit again if needed).",
+ "routeReport": "Route report",
+ "route_err_code": "Enter a lane code",
+ "route_err_create": "Failed to add lane",
+ "route_err_departure": "Select or enter departure time",
+ "route_err_duplicate": "This lane (including remark group) already exists",
+ "route_logisticUnspecified": "(Unassigned — assign later in Logistics)",
+ "route_new_code_label": "Lane code",
+ "route_new_logistic_label": "Logistics company",
+ "route_new_remark_label": "Lane remark (4F)",
+ "route_new_store_label": "Floor",
+ "route_new_time_label": "Departure time",
+ "saveChanges": "Save changes",
+ "saveDisabledTooltip": "Make changes (drag, departure time, load order, logistics, etc.) before saving",
+ "save_clearedEmptyDistricts": "Only empty district blocks (no shops); cleared staging",
+ "schedule_action_create": "Add shop",
+ "schedule_action_delete": "Delete",
+ "schedule_action_ensure_lane": "New lane",
+ "schedule_action_move": "Move",
+ "schedule_applied_snackbar": "{{count}} scheduled change(s) applied on the board — press Save changes to persist.",
+ "schedule_bulk_seq": "Uniform seq",
+ "schedule_bulk_target": "Bulk target:",
+ "schedule_col_current_lane": "Current lane",
+ "schedule_col_select": "Select",
+ "schedule_col_shop": "Shop",
+ "schedule_col_target_district": "District",
+ "schedule_col_target_lane": "Target lane",
+ "schedule_col_target_seq": "Seq",
+ "schedule_confirm_btn": "Confirm scheduled changes",
+ "schedule_district_original": "Keep shop's original district",
+ "schedule_drag_seq": "Seq: {{seq}}",
+ "schedule_drop_hint": "Drag shop cards into this lane",
+ "schedule_err_conflict": "Some shops could not move (duplicate on target lane or draft row).",
+ "schedule_err_duplicate_shop": "Shop {{shop}} already exists on the target lane.",
+ "schedule_err_execute_at_past": "Scheduled run time is in the past. Choose a future date and time.",
+ "schedule_err_generic": "Schedule request failed. Please try again.",
+ "schedule_err_no_moves": "No shop moves to schedule.",
+ "schedule_err_open_pending": "Shop row #{{id}} already has a pending schedule.",
+ "schedule_err_target_lane_empty": "Target lane {{lane}} has no shops — add a shop to the lane first.",
+ "schedule_err_target_lane_missing": "Target lane {{lane}} was not found on the board.",
+ "schedule_exec_date": "Execution date",
+ "schedule_exec_time": "Execution time",
+ "schedule_history_applied_at": "Completed at {{at}}",
+ "schedule_history_apply_now": "Run now",
+ "schedule_history_archived": "Executed",
+ "schedule_history_cancel": "Cancel schedule",
+ "schedule_history_close": "Close",
+ "schedule_history_created": "Created {{at}} ({{by}})",
+ "schedule_history_empty": "No tasks match this filter",
+ "schedule_history_failed_lines": "{{count}} shop move(s) failed",
+ "schedule_history_filter_all": "All tasks",
+ "schedule_history_filter_failed": "Failed",
+ "schedule_history_filter_pending": "Pending",
+ "schedule_history_filter_success": "Succeeded",
+ "schedule_history_ignore": "Ignore",
+ "schedule_history_line_counts": "{{total}} line(s) · {{applied}} applied · {{failed}} failed · {{pending}} pending",
+ "schedule_history_line_placement": "Target district {{district}} · seq {{seq}}",
+ "schedule_history_needs_attention": "Needs attention",
+ "schedule_history_no_lines": "No line details",
+ "schedule_history_reschedule": "Reschedule",
+ "schedule_history_status_failed": "Failed",
+ "schedule_history_status_ignored": "Ignored",
+ "schedule_history_status_pending": "Scheduled",
+ "schedule_history_status_success": "Succeeded",
+ "schedule_history_subtitle": "Monitor, run, or troubleshoot scheduled shop-lane changes",
+ "schedule_history_success_lines": "{{count}} shop move(s) succeeded",
+ "schedule_history_title": "Scheduled task status & history",
+ "schedule_history_unknown_user": "System",
+ "schedule_history_view_lines": "View shop lines",
+ "schedule_import_col_action": "Action",
+ "schedule_import_col_lane": "Target lane",
+ "schedule_import_col_name": "Shop name",
+ "schedule_import_col_seq": "Seq",
+ "schedule_import_col_shop": "Shop code",
+ "schedule_import_confirm_btn": "Confirm import schedules",
+ "schedule_import_err_invalid_departure": "Shop {{shop}} has invalid departure time",
+ "schedule_import_err_no_target_lane": "Shop {{shop}} is missing a target lane",
+ "schedule_import_err_no_truck_row": "Shop {{shop}} has no board row — import or add on the board first",
+ "schedule_import_err_placeholder_row": "Shop {{shop}} is on a placeholder row",
+ "schedule_import_err_truck_not_found": "Shop {{shop}} board row not found",
+ "schedule_import_hint": "Use the same route Excel as board \"Import routes\"",
+ "schedule_import_need_datetime": "Set execution date and time first",
+ "schedule_import_no_valid_moves": "No schedulable changes in file (no moves, creates, deletes, or new lanes detected)",
+ "schedule_import_parse_summary": "Parsed: {{valid}} valid, {{errors}} error(s)",
+ "schedule_import_pick": "Choose file",
+ "schedule_import_plan_summary": "Loaded {{file}}: {{sheets}} sheet(s) / {{rows}} row(s) · move {{moves}} · add {{creates}} · delete {{deletes}} · new lane {{ensureLanes}} · {{errors}} skipped",
+ "schedule_import_preview_summary": "Loaded {{file}}: {{sheets}} sheet(s) / {{rows}} row(s) · {{valid}} scheduled · {{errors}} skipped",
+ "schedule_import_row_error": "{{shop}} ({{name}}): {{reason}}",
+ "schedule_import_skipped_title": "{{count}} row(s) skipped",
+ "schedule_import_title": "Import lane layout (same as board)",
+ "schedule_lane_left": "Left lane",
+ "schedule_lane_right": "Right lane",
+ "schedule_line_add_to": "Add to {{lane}}",
+ "schedule_line_departure_change": "Departure {{from}} → {{to}}",
+ "schedule_line_departure_target": "Departure {{time}}",
+ "schedule_line_district_change": "District {{from}} → {{to}}",
+ "schedule_line_district_target": "District {{district}}",
+ "schedule_line_ensure_lane": "Create lane {{lane}}",
+ "schedule_line_lane_change": "{{from}} → {{to}}",
+ "schedule_line_on_lane": "Lane {{lane}}",
+ "schedule_line_remove_from": "Remove from {{lane}}",
+ "schedule_line_seq": "Seq {{value}}",
+ "schedule_log_failed_hint": "{{count}} scheduled task(s) failed — view log",
+ "schedule_modal_subtitle": "Set when schedule changes should take effect",
+ "schedule_modal_title": "Schedule changes",
+ "schedule_moved_badge": "Moved in",
+ "schedule_no_shops": "No shops match your search",
+ "schedule_pick_lane": "Select lane...",
+ "schedule_planned_label": "Planned run",
+ "schedule_registered_snackbar": "{{count}} scheduled change(s) registered; the server will apply them at the planned time.",
+ "schedule_reschedule_time_adjusted": "Run time was in the past and was adjusted to {{at}}.",
+ "schedule_retry_rejects_partial": "PARTIAL schedules cannot be retried. Restore the board and create a new schedule.",
+ "schedule_review_count": "{{count}} change(s)",
+ "schedule_review_delete_action": "Remove from:",
+ "schedule_review_district_change": "District:",
+ "schedule_review_empty": "No pending changes",
+ "schedule_review_empty_hint": "Drag shops to adjust lane or loading sequence, or use the delete button to remove shops",
+ "schedule_review_lane_change": "Lane:",
+ "schedule_review_queue": "Change preview queue",
+ "schedule_review_revert": "Revert",
+ "schedule_review_seq": "Sequence:",
+ "schedule_search_ph": "Search shop name / code...",
+ "schedule_seq_dialog_hint": "The change is added to the preview queue and applied when you confirm the schedule.",
+ "schedule_seq_edit_btn": "Edit load sequence",
+ "schedule_seq_hint": "Default: max sequence in target lane for same district + 1",
+ "schedule_shop_badge": "Scheduled change",
+ "schedule_shop_locked": "Schedule is applying; this shop cannot be edited manually",
+ "schedule_step_method": "2. Open lanes to schedule and review planned changes",
+ "schedule_step_time": "1. Set execution time",
+ "schedule_summary_changes": "{{count}} change(s) (lane moves and sequence updates) will be scheduled",
+ "schedule_summary_counts": "{{selected}} shop(s) selected, {{ready}} with a target lane.",
+ "schedule_summary_pending": "Target lanes still incomplete",
+ "schedule_summary_ready": "All settings are ready",
+ "schedule_tab_import": "Import route Excel",
+ "schedule_tab_manual": "Drag scheduling",
+ "schedule_target_unset": "Not set",
+ "seqDialog_hint": "Press \"Save changes\" to persist to truck rows.",
+ "seqDialog_title": "Edit load sequence",
+ "seq_edit_departureLabel": "Departure time",
+ "seq_edit_seqLabel": "Load sequence (Seq)",
+ "shop_autocomplete_label": "Select shop",
+ "shop_autocomplete_loading": "Shop master not loaded",
+ "shop_autocomplete_noOptions": "All shops already on this lane or no options",
+ "shop_autocomplete_ph": "Filter by name or code",
+ "shop_searchPh": "Search shop name / code / district…",
+ "tabBoard": "Route board",
+ "tabLogistics": "Logistics",
+ "tools_title": "Tools",
+ "tooltip_clearLaneShops": "Clear all shops on this lane (press \"Save changes\" to persist)",
+ "tooltip_deleteLogistics": "Delete logistics company (persists after Save changes)",
+ "tooltip_editDistrict": "Edit district name (press \"Save changes\" to persist)",
+ "tooltip_editLogisticsDb": "Edit logistics company (persists after Save changes)",
+ "tooltip_editSeq": "Edit load sequence (press \"Save changes\" to persist)",
+ "tooltip_openLaneBoard": "Open this lane on the route board",
+ "tooltip_pickLane": "Pick lane (add to selection and scroll into view)",
+ "tooltip_removeEmptyDistrict": "Remove this staged empty block (deletable before save)",
+ "tooltip_removeFromLane": "Remove from this lane",
+ "val_logisticsDuplicateName": "A logistics master or staged add with this name already exists",
+ "val_logisticsRequired": "Enter logistics company, plate, and driver name",
+ "val_phoneInvalid": "Enter a valid phone number (digits)",
+ "versionLogDialogTitle": "Version change log",
+ "versionNote_saveFail": "Failed to save note",
+ "version_date_label": "Date",
+ "version_empty_filtered": "No versions match filters",
+ "version_empty_list": "No versions yet (use \"Save version log\")",
+ "version_note_placeholder": "Note (saved on blur)",
+ "version_note_saving": "Saving…",
+ "version_search_label": "Search",
+ "version_search_placeholder": "Version id / note / editor",
+ "version_ui_editedBy": "By: {{name}}",
+ "version_ui_filterAria": "Filter version list",
+ "version_ui_historyTitle": "Version history",
+ "version_ui_id": "Version #{{id}}",
+ "version_ui_listAria": "Version history list",
+ "version_ui_none": "No snapshot yet",
+ "version_ui_snapshotBadge": "Current snapshot",
+ "warnClipboardDep": "Dep",
+ "warnClipboardStore": "Store",
+ "warnClipboardWeekday": "Weekday",
+ "warnCollapse": "Collapse",
+ "warnExpand": "Expand",
+ "Applies to all shops using this truck lane": "Applies to all shops using this truck lane",
+ "Edit loading sequence": "Edit loading sequence",
+ "Edit shop truck lane": "Edit shop truck lane",
+ "Edit truck lane": "Edit truck lane",
+ "Invalid truck data": "Invalid truck data",
+ "Loading sequence updated successfully": "Loading sequence updated successfully",
+ "Failed to load shop detail": "Failed to load shop detail",
+ "Failed to save loading sequence": "Failed to save loading sequence",
+ "Route Board": "Route Board",
+ "Select a shop first": "Select a shop first",
+ "Select items without order to append to bottom": "Select items without order to append to bottom",
+ "Shop Detail": "Shop Detail",
+ "Truck ID is required": "Truck ID is required",
+ "Are you sure you want to delete this truck lane?": "Are you sure you want to delete this truck lane?",
+ "Search or select branch": "Search or select branch",
+ "Search or select shop code": "Search or select shop code",
+ "versionLogField_departureTime": "Departure time",
+ "versionLogField_loadingSequence": "Load sequence",
+ "versionLogField_branchName": "Branch name",
+ "versionLogField_districtReference": "District",
+ "versionLogField_shopCode": "Shop code",
+ "versionLogField_storeId": "Floor / Store",
+ "versionLogField_remark": "Remark",
+ "versionLogField_truckLanceCode": "Lane code",
+ "versionLogField_logisticId": "Logistics"
+}
diff --git a/src/i18n/en/stockIssue.json b/src/i18n/en/stockIssue.json
new file mode 100644
index 0000000..5e6583f
--- /dev/null
+++ b/src/i18n/en/stockIssue.json
@@ -0,0 +1,78 @@
+{
+ "Action": "Action",
+ "Available Qty": "Available Qty",
+ "Bad Item": "Bad Item",
+ "Bad Item Handle": "Bad Item Handle",
+ "Bad Item Qty": "Bad Item Qty",
+ "Bad Item Records": "Bad Item Records",
+ "Batch Disposed All": "Batch Disposed All",
+ "Book Qty": "Book Qty",
+ "Cancel": "Cancel",
+ "Code": "Code",
+ "Defective Qty": "Defective Qty",
+ "Disposed": "Disposed",
+ "Disposing...": "Disposing...",
+ "DO Order Code": "DO Order Code",
+ "End Date": "End Date",
+ "Expiry Date": "Expiry Date",
+ "Expiry End Date": "Expiry End Date",
+ "Expiry Item": "Expiry Item",
+ "Expiry Item Handle": "Expiry Item Handle",
+ "Expiry Item Qty": "Expiry Item Qty",
+ "Expiry Item Records": "Expiry Item Records",
+ "Expiry Start Date": "Expiry Start Date",
+ "Failed to load expiry items": "Failed to load expiry items",
+ "Failed to submit": "Failed to submit",
+ "Failed to submit expiry item": "Failed to submit expiry item",
+ "Handled Date": "Handled Date",
+ "Handler": "Handler",
+ "Issue Qty": "Issue Qty",
+ "Item": "Item",
+ "Item Code": "Item Code",
+ "Item not found": "Item not found",
+ "Item selected": "Item selected",
+ "JO Order Code": "JO Order Code",
+ "Loading": "Loading",
+ "Location": "Location",
+ "Looked": "Looked",
+ "Lot No": "Lot No",
+ "Lot No.": "Lot No.",
+ "Miss Item": "Miss Item",
+ "Miss Qty": "Miss Qty",
+ "Name": "Name",
+ "No changes to submit": "No changes to submit",
+ "No items are selected yet.": "No items are selected yet.",
+ "No record found": "No record found",
+ "Picker Name": "Picker Name",
+ "Pick Order Code": "Pick Order Code",
+ "Please enter a valid quantity": "Please enter a valid quantity",
+ "Please set at least one search criterion": "Please set at least one search criterion",
+ "Processing...": "Processing...",
+ "Quantity exceeds available quantity": "Quantity exceeds available quantity",
+ "Remain available Quantity": "Remain available Quantity",
+ "Remaining Qty": "Remaining Qty",
+ "Remark": "Remark",
+ "Remarks": "Remarks",
+ "Reset": "Reset",
+ "Rows per page": "Rows per page",
+ "Saved successfully": "Saved successfully",
+ "Search": "Search",
+ "Search Criteria": "Search Criteria",
+ "Search to load lot lines": "Search to load lot lines",
+ "Start Date": "Start Date",
+ "Status": "Status",
+ "Stock UoM": "Stock UoM",
+ "Submit": "Submit",
+ "Submit Bad Item": "Submit Bad Item",
+ "Submit Miss Item": "Submit Miss Item",
+ "Submit Quantity": "Submit Quantity",
+ "Submitting...": "Submitting...",
+ "Type": "Type",
+ "Unknown error": "Unknown error",
+ "UoM": "UoM",
+ "User ID is required": "User ID is required",
+ "Warehouse": "Warehouse",
+ "available": "Available",
+ "unavailable": "Unavailable",
+ "Stock Issue": "Stock Issue"
+}
diff --git a/src/i18n/en/stockRecord.json b/src/i18n/en/stockRecord.json
new file mode 100644
index 0000000..5b0ca0d
--- /dev/null
+++ b/src/i18n/en/stockRecord.json
@@ -0,0 +1,32 @@
+{
+ "title": "Stock Record",
+ "tke": "tke",
+ "adj": "adj",
+ "nor": "nor",
+ "trf": "trf",
+ "open": "open",
+ "miss": "miss",
+ "bad": "bad",
+ "Start Date": "Start Date",
+ "End Date": "End Date",
+ "Date": "Date",
+ "Item-lotNo": "Item-lotNo",
+ "UOM": "UOM",
+ "In Qty": "In Qty",
+ "Out Qty": "Out Qty",
+ "Balance Qty": "Balance Qty",
+ "Loading...": "Loading...",
+ "Type": "Type",
+ "Status": "Status",
+ "pending": "Pending",
+ "completed": "Completed",
+ "partially_completed": "Partially completed",
+ "receiving": "Receiving",
+ "rejected": "Rejected",
+ "checked": "Checked",
+ "determine1": "Determine 1",
+ "lot-change": "Lot change approval",
+ "qc1": "QC 1",
+ "qc2": "QC 2",
+ "qc3": "QC 3"
+}
diff --git a/src/i18n/en/stockTake.json b/src/i18n/en/stockTake.json
new file mode 100644
index 0000000..faaef94
--- /dev/null
+++ b/src/i18n/en/stockTake.json
@@ -0,0 +1,179 @@
+{
+ "Action": "Action",
+ "Actual Qty": "Actual Qty",
+ "Adjusted By": "Adjusted By",
+ "Adjustment": "Adjustment",
+ "Adjustment No": "Adjustment No",
+ "Adjustment No, Item, Lot...": "Adjustment No, Item, Lot...",
+ "After Qty": "After Qty",
+ "All": "All",
+ "Approved": "Approved",
+ "Approver": "Approver",
+ "Approver Approved": "Approver Approved",
+ "Approver Input": "Approver Input",
+ "Approver Pending": "Approver Pending",
+ "Approver Time": "Approver Time",
+ "Approver input empty; save skipped, row remains pending": "Approver input empty; save skipped, row remains pending",
+ "Approver stock take record saved successfully": "Approver stock take record saved successfully",
+ "Area": "Area",
+ "Available QTY cannot be negative": "Available QTY cannot be negative",
+ "Back to List": "Back to List",
+ "Bad Qty": "Bad Qty",
+ "Batch Save All": "Batch Save All",
+ "Batch approver save completed: {{success}} success, {{errors}} errors": "Batch approver save completed: {{success}} success, {{errors}} errors",
+ "Batch save completed: {{success}} success, {{errors}} errors": "Batch save completed: {{success}} success, {{errors}} errors",
+ "Batch save confirm message": "Batch save {{count}} stock take record(s) in the current list. Continue?",
+ "Before Qty": "Before Qty",
+ "Book Qty": "Book Qty",
+ "Cancel": "Cancel",
+ "Category": "Category",
+ "Clear selection all floors": "Clear selection (all floors)",
+ "Close": "Close",
+ "Confirm": "Confirm",
+ "Confirm batch save approver": "Confirm batch save",
+ "Confirm create stock take": "Confirm create stock take",
+ "Control Time": "Control Time",
+ "Create Stock Take (Select Sections)": "Create stock take (select sections)",
+ "Created": "Created",
+ "Creation date": "Creation date",
+ "Damage": "Damage",
+ "Date": "Date",
+ "Deselect all on this floor": "Deselect all on this floor ({{floor}})",
+ "Detail": "Detail",
+ "Difference": "Difference",
+ "Errors": "Errors",
+ "Failed to batch save approver stock take records": "Failed to batch save approver stock take records",
+ "Failed to batch save stock take records": "Failed to batch save stock take records",
+ "Failed to save approver stock take record": "Failed to save approver stock take record",
+ "Failed to save stock take record": "Failed to save stock take record",
+ "Failed to update stock take record status": "Failed to update stock take record status",
+ "First": "First",
+ "First QTY is not available": "First count quantity is not available",
+ "Floor area selection header": "{{floor}} area selection ({{count}} areas)",
+ "Floor unassigned": "Unassigned floor",
+ "Handle Remark": "Handle Remark",
+ "Invalid QTY": "Invalid quantity",
+ "Inventory Adjustments": "Inventory Adjustments",
+ "Inventory Difference": "Inventory Difference",
+ "Issue Detail": "Issue Detail",
+ "Issue No": "Issue No",
+ "Issue Remark": "Issue Remark",
+ "Item": "Item",
+ "Item Code": "Item Code",
+ "Item-lotNo-ExpiryDate": "Item-lotNo-ExpiryDate",
+ "Last Stock Take Date": "Last Stock Take Date",
+ "Location": "Location",
+ "Lot No": "Lot No",
+ "Manual": "Manual",
+ "Mark as Resolved": "Mark as Resolved",
+ "Miss Qty": "Miss Qty",
+ "No adjustments found": "No adjustments found",
+ "No data": "No data",
+ "No rows loaded; set search criteria and search first": "No rows loaded; set search criteria and search first",
+ "No sections match search": "No areas match your search",
+ "No stock take sections from warehouse": "No stock take sections returned from warehouse.",
+ "No valid input to submit": "No valid input to submit",
+ "No valid records to batch save": "No valid records to batch save",
+ "Not Match": "Not Match",
+ "Not filled": "(not filled)",
+ "Only Variance": "Only Variance",
+ "Pass": "Pass",
+ "Pending": "Pending",
+ "Pick Execution Issues": "Pick Execution Issues",
+ "Pick Order": "Pick Order",
+ "Pick Order Code": "Pick Order Code",
+ "Picker": "Picker",
+ "Plan Start Date": "Plan Start Date",
+ "Please enter Approver Bad QTY": "Please enter approver bad quantity",
+ "Please enter Approver QTY": "Please enter approver count quantity",
+ "Please enter QTY": "Please enter quantity",
+ "Please enter Second QTY": "Please enter second count quantity",
+ "ReStockTake": "ReStockTake",
+ "Reason": "Reason",
+ "Record Status": "Record Status",
+ "Rejected": "Rejected",
+ "Remark": "Remark",
+ "Required Qty": "Required Qty",
+ "Reset": "Reset",
+ "Return": "Return",
+ "Rows per page": "Rows per page",
+ "Save": "Save",
+ "Search": "Search",
+ "Search Criteria": "Search Criteria",
+ "Search section code or name": "Search code or name (e.g. ST-042 or drinks)",
+ "Second": "Second",
+ "Second QTY is not available": "Second count quantity is not available",
+ "Section": "Section",
+ "Select all on this floor": "Select all on this floor ({{floor}})",
+ "Select all sections all floors": "Select all areas (all floors)",
+ "Selected Qty": "Selected Qty",
+ "Shortcut Input": "Shortcut input",
+ "Shown": "Shown",
+ "Skipped": "Skipped",
+ "Start Stock Take Date": "Start Stock Take Date",
+ "Status": "Status",
+ "Stock Take": "Stock Take",
+ "Stock Take Management": "Stock Take Management",
+ "Stock Take Qty": "Stock Take Qty",
+ "Stock Take Qty Data and Variance Analysis": "Stock Take Qty Data and Variance Analysis",
+ "Stock Take Qty(include Bad Qty)= Available Qty": "Stock Take Qty(include Bad Qty)= Available Qty",
+ "Stock Take Round": "Stock Take Round",
+ "Stock Take Section": "Stock Take Section",
+ "Stock Take Section (can use , to search multiple sections)": "Stock Take Section (can use , to search multiple sections)",
+ "Stock Taker": "Stock Taker",
+ "Stock take qty exceeds maximum": "Stock take quantity cannot exceed 999,999,999,999",
+ "Stock take record ID is required": "Stock take record ID is required",
+ "Stock take record saved successfully": "Stock take record saved successfully",
+ "Stock take record status updated to not match": "Stock take record status updated to not match",
+ "Stock take round name": "Stock take round name",
+ "Stock take round name placeholder": "Optional, e.g. May full-site stock take",
+ "Stock take sections in current list": "{{count}} stock take section(s) in current list",
+ "Store ID": "Store ID",
+ "Submit All Inputted": "Submit All Inputted",
+ "Total": "Total",
+ "Total Adjustments": "Total Adjustments",
+ "Total Item Kind Number": "Total Item Kind Number",
+ "Total Items": "Total Items",
+ "Total Lots": "Total Lots",
+ "Total Sections": "Total Sections",
+ "Total selected sections label": "Total selected:",
+ "Type": "Type",
+ "UOM": "UOM",
+ "Variance": "Variance",
+ "Variance %": "Variance %",
+ "Variance filter exclusive range hint": "Show rows with -{{value}}% {{op}} variance % {{op}} {{value}}% (outside range, server-filtered)",
+ "Variance filter inclusive only": "Show only rows within variance range",
+ "Variance filter inclusive range hint": "Show rows with -{{value}}% {{op}} variance % {{op}} {{value}}% (within range)",
+ "View Details": "View Details",
+ "View ReStockTake": "View ReStockTake",
+ "Warehouse": "Warehouse",
+ "Warehouse Location": "Warehouse Location",
+ "Warehouse missing stock take section drawer hint": "These locations have no stock take section (ST-xxx) and cannot be included in stock take. Fix in warehouse settings.",
+ "Warehouse missing stock take section empty": "No warehouses missing stock take section",
+ "Warehouse missing stock take section go settings": "Go to warehouse settings",
+ "Warehouse missing stock take section showing": "Showing {{shown}} of {{count}}",
+ "Warehouse missing stock take section tooltip has": "{{count}} warehouse location(s) missing stock take section — click to view",
+ "Warehouse missing stock take section tooltip none": "All warehouses have a stock take section",
+ "Warehouse missing stock take section warn title": "Warehouses without stock take section",
+ "approving": "Approving",
+ "book qty": "book qty",
+ "completed": "Completed",
+ "do": "Delivery order",
+ "end time": "end time",
+ "jo": "Job order",
+ "lot_issue": "Lot issue",
+ "material": "Material",
+ "notMatch": "Re-count required",
+ "notmatch": "Re-count required",
+ "pass": "Counted",
+ "pending": "Pending",
+ "quality_issue": "Quality issue",
+ "quantity_mismatch": "Quantity mismatch",
+ "resolved": "Resolved",
+ "sections unit": "area(s)",
+ "selected stock take qty": "selected stock take qty",
+ "start time": "start time",
+ "stockTaking": "Stock taking",
+ "stock_take": "Stock take",
+ "variance Percentage": "variance Percentage"
+}
diff --git a/src/i18n/en/ticketReleaseTable.json b/src/i18n/en/ticketReleaseTable.json
new file mode 100644
index 0000000..a4935c1
--- /dev/null
+++ b/src/i18n/en/ticketReleaseTable.json
@@ -0,0 +1,48 @@
+{
+ "Actions": "Actions",
+ "All Floors": "All Floors",
+ "All Statuses": "All Statuses",
+ "Auto-refresh every 1 minute": "Auto-refresh every 1 minute",
+ "Auto-refresh every 10 minutes": "Auto-refresh every 10 minutes",
+ "Auto-refresh every 15 minutes": "Auto-refresh every 15 minutes",
+ "Auto-refresh every 5 minutes": "Auto-refresh every 5 minutes",
+ "Cancel": "Cancel",
+ "Completed Time": "Completed Time",
+ "Confirm": "Confirm",
+ "Confirm force complete": "Confirm force complete",
+ "Confirm revert assignment": "Confirm revert assignment",
+ "Day After Tomorrow": "Day After Tomorrow",
+ "Departure Time": "Departure Time",
+ "Floor": "Floor",
+ "Force complete DO": "Force complete DO",
+ "Force complete hint": "Force complete hint",
+ "Handler Name": "Handler Name",
+ "Last updated": "Last updated",
+ "Loading Sequence": "Loading Sequence",
+ "Manager only hint": "Manager only hint",
+ "No data available": "No data available",
+ "Now": "Now",
+ "Number of FG Items (Order Item(s) Count)": "Number of FG Items (Order Item(s) Count)",
+ "Operation succeeded": "Operation succeeded",
+ "Released Time": "Released Time",
+ "Reload data": "Reload data",
+ "Required Delivery Date": "Required Delivery Date",
+ "Revert assignment": "Revert assignment",
+ "Revert assignment hint": "Revert assignment hint",
+ "Rows per page": "Rows per page",
+ "Select Date": "Select Date",
+ "Shop Name": "Shop Name",
+ "Status": "Status",
+ "Store ID": "Store ID",
+ "Target Date": "Target Date",
+ "Ticket Information": "Ticket Information",
+ "Ticket No.": "Ticket No.",
+ "Ticket Release Table": "Ticket Release Table",
+ "Today": "Today",
+ "Tomorrow": "Tomorrow",
+ "Truck Information": "Truck Information",
+ "Truck Lane Code": "Truck Lane Code",
+ "completed": "completed",
+ "pending": "pending",
+ "released": "released"
+}
diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json
new file mode 100644
index 0000000..59f2a71
--- /dev/null
+++ b/src/i18n/en/translation.json
@@ -0,0 +1,4 @@
+{
+ "Actions": "Actions",
+ "Release": "Release"
+}
diff --git a/src/i18n/en/user.json b/src/i18n/en/user.json
index 8afc58a..f9cf3b3 100644
--- a/src/i18n/en/user.json
+++ b/src/i18n/en/user.json
@@ -1,26 +1,48 @@
{
- "Create User": "新增用戶",
- "User Detail": "用戶詳細資料",
- "User Authority": "用戶權限",
- "Authority Pool": "權限池",
- "Allocated Authority": "已分配權限",
- "username": "用戶名稱",
- "password": "密碼",
- "Confirm Password": "確認密碼",
- "Reset": "重置",
- "Cancel": "取消",
- "Confirm": "確認",
- "name": "姓名",
- "User ID": "用戶ID",
- "User Name": "用戶名稱",
- "User Group": "用戶群組",
- "Authority": "權限",
- "Delete Success": "Delete Success",
- "Do you want to delete?": "Do you want to delete?",
- "Maintain User": "Maintain User",
- "Maintain group": "Maintain group",
- "view user": "view user",
- "view group": "view group",
- "Approval": "Approval",
- "Testing": "Testing"
-}
\ No newline at end of file
+ "profile": "profile",
+ "Add": "Add",
+ "Allocated Authority": "Allocated Authority",
+ "Approval": "Approval",
+ "Authority": "Authority",
+ "Authority Pool": "Authority Pool",
+ "Cancel": "Cancel",
+ "Confirm": "Confirm",
+ "Confirm Password": "Confirm Password",
+ "Create User": "Create User",
+ "Delete": "Delete",
+ "Delete Success": "Delete Success",
+ "Do you want to delete?": "Do you want to delete?",
+ "Edit": "Edit",
+ "Edit User": "Edit User",
+ "Failed to fetch staff list": "Failed to fetch staff list",
+ "Maintain User": "Maintain User",
+ "Maintain group": "Maintain group",
+ "Remove": "Remove",
+ "Reset": "Reset",
+ "Rows per page": "Rows per page",
+ "Search by Authority or description or position.": "Search by Authority or description or position.",
+ "Testing": "Testing",
+ "User": "User",
+ "User Authority": "User Authority",
+ "User Detail": "User Detail",
+ "User Group": "User Group",
+ "User ID": "User ID",
+ "User Name": "User Name",
+ "Username": "Username",
+ "authority": "authority",
+ "description": "description",
+ "name": "name",
+ "password": "password",
+ "qrcode": "qrcode",
+ "staffNo": "staffNo",
+ "user": "user",
+ "username": "username",
+ "view group": "view group",
+ "view user": "view user",
+ "An error has occurred. Please try again later.": "An error has occurred. Please try again later.",
+ "Please input correct password": "Please input correct password",
+ "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",
+ "User Not Found": "User Not Found"
+}
diff --git a/src/i18n/en/warehouse.json b/src/i18n/en/warehouse.json
index 45bb138..1aef422 100644
--- a/src/i18n/en/warehouse.json
+++ b/src/i18n/en/warehouse.json
@@ -1,27 +1,44 @@
{
- "Create Warehouse": "Create Warehouse",
- "Edit Warehouse": "Edit Warehouse",
- "Warehouse Detail": "Warehouse Detail",
- "code": "Code",
- "name": "Name",
- "description": "Description",
- "Edit": "Edit",
- "Delete": "Delete",
- "Delete Success": "Delete Success",
- "Warehouse": "Warehouse",
- "warehouse": "warehouse",
- "Rows per page": "Rows per page",
- "capacity": "Capacity",
- "store_id": "Store ID",
- "area": "Area",
- "slot": "Slot",
- "order": "Order",
- "stockTakeSection": "Stock Take Section",
- "Do you want to delete?": "Do you want to delete?",
- "Cancel": "Cancel",
- "Reset": "Reset",
- "Confirm": "Confirm",
- "is required": "is required",
- "Search Criteria": "Search Criteria",
- "Search": "Search"
+ "Actions": "Actions",
+ "Add": "Add",
+ "Add Success": "Add Success",
+ "Add Warehouse": "Add Warehouse",
+ "Cancel": "Cancel",
+ "Confirm": "Confirm",
+ "Create Warehouse": "Create Warehouse",
+ "Delete": "Delete",
+ "Delete Success": "Delete Success",
+ "Do you want to delete?": "Do you want to delete?",
+ "Edit": "Edit",
+ "Edit Warehouse": "Edit Warehouse",
+ "Mapping Details": "Mapping Details",
+ "No warehouses": "No warehouses",
+ "Remove": "Remove",
+ "Reset": "Reset",
+ "Rows per page": "Rows per page",
+ "Save": "Save",
+ "Saved": "Saved",
+ "Saved Successfully": "Saved Successfully",
+ "Search": "Search",
+ "Search Criteria": "Search Criteria",
+ "Stock Take Section": "Stock Take Section",
+ "Stock Take Section & Warehouse Mapping": "Stock Take Section & Warehouse Mapping",
+ "Stock Take Section Description": "Stock Take Section Description",
+ "Store ID": "Store ID",
+ "Warehouse": "Warehouse",
+ "Warehouse Detail": "Warehouse Detail",
+ "Warehouse List": "Warehouse List",
+ "Warehouses in this section": "Warehouses in this section",
+ "area": "Area",
+ "capacity": "Capacity",
+ "code": "Code",
+ "description": "Description",
+ "is required": "is required",
+ "name": "Name",
+ "order": "Order",
+ "slot": "Slot",
+ "stockTakeSection": "Stock Take Section",
+ "stockTakeSectionDescription": "stockTakeSectionDescription",
+ "store_id": "Store ID",
+ "warehouse": "warehouse"
}
diff --git a/src/i18n/zh/bagPrint.json b/src/i18n/zh/bagPrint.json
new file mode 100644
index 0000000..b3e7187
--- /dev/null
+++ b/src/i18n/zh/bagPrint.json
@@ -0,0 +1,3 @@
+{
+ "title": "打袋機"
+}
diff --git a/src/i18n/zh/bagUsage.json b/src/i18n/zh/bagUsage.json
new file mode 100644
index 0000000..23439cd
--- /dev/null
+++ b/src/i18n/zh/bagUsage.json
@@ -0,0 +1,12 @@
+{
+ "Bag": "包裝袋",
+ "Bag Usage": "包裝袋使用記錄",
+ "Balance": "可用數量",
+ "Actions": "操作",
+ "Lot No": "批號",
+ "Consumed Qty": "消耗數量",
+ "Scrap Qty": "損耗數量",
+ "Job Order Code": "工單編號",
+ "Date": "日期",
+ "Back": "返回"
+}
diff --git a/src/i18n/zh/bomWeighting.json b/src/i18n/zh/bomWeighting.json
new file mode 100644
index 0000000..a8f7277
--- /dev/null
+++ b/src/i18n/zh/bomWeighting.json
@@ -0,0 +1,12 @@
+{
+ "BOM Weighting Score List": "BOM 權重得分",
+ "Material Weighting": "BOM 加權",
+ "Material Score": "BOM得分",
+ "Weighting": "權重",
+ "Base Score": "基礎得分",
+ "Edit BOM Weighting Score": "編輯 BOM 權重得分",
+ "Scoring Item": "評分項目",
+ "Range": "範圍",
+ "Item Code": "物品編號",
+ "Item Name": "物品名稱"
+}
diff --git a/src/i18n/zh/chart.json b/src/i18n/zh/chart.json
new file mode 100644
index 0000000..d0fc2dd
--- /dev/null
+++ b/src/i18n/zh/chart.json
@@ -0,0 +1,113 @@
+{
+ "all": "全部",
+ "autoRefresh": "自動重新整理",
+ "board_equipmentUsage": "設備使用看板",
+ "board_jobOrderChart": "工單圖表",
+ "board_jobOrderLive": "工單即時看板",
+ "board_processLive": "工序即時看板",
+ "dateRange_lastDays": "最近 {{d}} 天",
+ "delivery_colAvgMin": "平均分鐘/單",
+ "delivery_colPickCount": "揀單數",
+ "delivery_colStaff": "員工",
+ "delivery_colTotalMin": "總分鐘",
+ "delivery_dailyByStaff": "每日按員工單數",
+ "delivery_endDate": "結束日期",
+ "delivery_item": "物品",
+ "delivery_itemPlaceholder": "不選則全部",
+ "delivery_noDataDesc": "所選期間內暫無發貨記錄,請調整日期範圍後再試。",
+ "delivery_orderCount": "單數",
+ "delivery_ordersByDate": "按日期發貨單數量",
+ "delivery_ordersByDate_export": "發貨單數量_按日期",
+ "delivery_staff": "員工",
+ "delivery_staffPerfCaption": "週期內每人揀單數及總耗時(首揀至完成)",
+ "delivery_staffPerfDateError": "員工發貨績效的起始日期不能晚於結束日期",
+ "delivery_staffPerformanceTitle": "員工發貨績效(每日揀貨數量與耗時)",
+ "delivery_staffPlaceholder": "不選則全部",
+ "delivery_startDate": "開始日期",
+ "delivery_store": "倉別",
+ "delivery_topItemsByCount": "發貨數量排行(按物品)",
+ "equipment_boardTitle": "設備使用看板",
+ "equipment_completed": "已完工",
+ "equipment_endTime": "完工時間",
+ "equipment_equipment": "設備",
+ "equipment_infoDescription1": "即時顯示設備狀態:使用中、閒置或維護中。",
+ "equipment_infoDescription2": "每張設備卡片顯示當前工單和工序。",
+ "equipment_infoDescription3": "設備工時未結案或未填寫將被標記。",
+ "equipment_jobOrder": "工單",
+ "equipment_missingHours": "未填設備工時",
+ "equipment_notToday": "非今日",
+ "equipment_operator": "操作員",
+ "equipment_planStart": "工單計劃開始",
+ "equipment_process": "工序",
+ "equipment_searchAndList": "查詢與列表",
+ "equipment_startTime": "開工時間",
+ "equipment_status": "狀態",
+ "equipment_unclosedHours": "設備工時未結案",
+ "exportExcel": "匯出 Excel",
+ "forecast_itemCode": "物品編碼",
+ "forecast_noScheduleData": "此日期範圍內尚無排程資料。",
+ "forecast_plannedOutputByDate": "按物品計劃日產量(預測)",
+ "forecast_plannedOutputByDate_export": "計劃日產量_按物品",
+ "forecast_productionSchedule": "按日期生產排程(預估產量)",
+ "forecast_productionSchedule_export": "生產排程_按日期",
+ "intervalSeconds": "間隔(秒)",
+ "jo_byStatus": "工單按狀態",
+ "jo_byStatus_export": "工單_按狀態",
+ "jo_createdVsCompleted": "工單創建與完成按日期",
+ "jo_createdVsCompleted_export": "工單_創建與完成_按日期",
+ "jo_datePlanStart": "日期(計劃開始)",
+ "jo_detailSection": "工單物料/工序/設備",
+ "jo_equipmentWorkingWorked": "設備使用中/已使用(按工單)",
+ "jo_equipmentWorkingWorked_export": "設備_使用中_已使用",
+ "jo_materialPendingPicked": "物料待領/已揀(按工單計劃日)",
+ "jo_materialPendingPicked_export": "物料_待領_已揀",
+ "jo_processPendingCompleted": "工序待完成/已完成(按工單計劃日)",
+ "jo_processPendingCompleted_export": "工序_待完成_已完成",
+ "laneX": "車線-X",
+ "minuteAbbr": "分",
+ "minutes": "分鐘",
+ "minutesWithVal": "{{val}} 分鐘",
+ "noData": "無數據",
+ "off": "關閉",
+ "on": "開啟",
+ "otherBoards": "其他看板",
+ "pageTitle_delivery": "發貨與配送",
+ "pageTitle_equipmentBoard": "設備使用看板",
+ "pageTitle_forecast": "預測與計劃",
+ "pageTitle_jobOrder": "工單",
+ "pageTitle_jobOrderBoard": "工單即時看板",
+ "pageTitle_processBoard": "工序即時看板",
+ "pageTitle_purchase": "採購",
+ "pageTitle_warehouse": "庫存與倉儲",
+ "process_completed": "已完工",
+ "process_inProgress": "進行中",
+ "process_nonToday": "非今日",
+ "process_notStarted": "未開工",
+ "refresh": "重新整理",
+ "requestFailed": "請求失敗",
+ "selectDate": "選擇日期",
+ "series_balance": "餘額",
+ "series_completed": "完成",
+ "series_consumption": "消耗",
+ "series_created": "新建",
+ "series_inbound": "入庫",
+ "series_month": "月份",
+ "series_outbound": "出庫",
+ "series_total": "合計",
+ "show": "顯示",
+ "today": "今日",
+ "warehouse_addItem": "新增物品以分項顯示",
+ "warehouse_balanceTrend": "庫存餘額趨勢",
+ "warehouse_balanceTrend_export": "庫存餘額趨勢",
+ "warehouse_consumptionTrend": "按月考勤消耗趨勢(出庫量)",
+ "warehouse_consumptionTrend_export": "月考勤消耗趨勢",
+ "warehouse_exportFail": "總表匯出失敗",
+ "warehouse_optional": "可選",
+ "warehouse_qty": "數量",
+ "warehouse_stockInOutByDate": "按日期入庫與出庫",
+ "warehouse_stockInOutByDate_export": "入庫_出庫_按日期",
+ "warehouse_stockTxnByDate": "按日期庫存流水(入/出/合計)",
+ "warehouse_stockTxnByDate_export": "庫存流水_按日期",
+ "warehouse_sumAll": "不選則全部合計",
+ "yesterday": "昨日"
+}
diff --git a/src/i18n/zh/clientMonitor.json b/src/i18n/zh/clientMonitor.json
new file mode 100644
index 0000000..33efc5e
--- /dev/null
+++ b/src/i18n/zh/clientMonitor.json
@@ -0,0 +1,3 @@
+{
+ "title": "裝置連線監控"
+}
diff --git a/src/i18n/zh/common.json b/src/i18n/zh/common.json
index 28a3cf0..39ecc24 100644
--- a/src/i18n/zh/common.json
+++ b/src/i18n/zh/common.json
@@ -1,677 +1,126 @@
{
- "dashboard": "資訊展示面板",
- "Edit": "編輯",
- "Job Order Production Process": "工單生產流程",
- "productionProcess": "生產流程",
- "Search Criteria": "搜索條件",
- "Stock Record": "庫存記錄",
- "No options": "沒有選項",
- "Drink": "飲料",
- "packaging": "提料中",
- "Issue BOM List": "問題 BOM 列表",
- "File Name": "檔案名稱",
- "Please Select BOM": "請選擇 BOM",
- "Plan Start": "預計生產日期",
- "Floor": "樓層",
- "Job Order Type": "工單類型",
-
- "BOM Type": "BOM 類型",
- "No Lot": "沒有批號",
- "Select All": "全選",
- "Do Workbench": "新版成品出倉",
- "DO Workbench": "新版成品出倉",
- "storing": "待品檢入倉",
- "Submit Qty": "提交數量",
- "Waiting QC Put Away Job Orders": "待QC上架工單",
- "Put Awayed Job Orders": "已上架工單",
- "Loading BOM Detail...": "正在載入 BOM 明細…",
- "Output Quantity": "使用數量",
- "Process & Equipment": "製程與設備",
- "Sequence": "順序",
- "Process Name": "製程名稱",
- "Plan start (from)": "開始日期(從)",
- "Plan start (to)": "開始日期(至)",
- "Process Description": "說明",
- "Search date": "搜索日期",
- "Confirm to Pass this Process?": "確認要通過此工序嗎?",
- "Equipment Name": "設備",
- "Confirm to update this Job Order?": "確認要完成此工單嗎?",
- "Cancel Job Order": "取消工單",
- "Confirm delete job order": "確認刪除工單",
- "Delete job order confirm message": "確定要刪除此工單嗎?此操作無法復原。",
- "Confirm cancel job order": "確認取消工單",
- "Cancel job order confirm message": "確定要取消此工單嗎?工單將從列表中隱藏。",
- "all": "全部",
- "Bom Uom": "BOM 單位",
- "Searched Item": "已搜索物料",
- "drink": "飲料",
- "other": "其他",
- "Total job orders": "總工單數量",
- "Filtered": "已過濾",
- "Duration (Minutes)": "時間(分)",
- "Prep Time (Minutes)": "準備時間",
- "Post Prod Time (Minutes)": "收尾時間",
-
- "Correct BOM List (Can Import)": "正確 BOM 列表(可匯入)",
- "Select Another Bag Lot": "選擇另一個包裝袋",
- "Finished QC Job Orders": "完成QC工單",
- "Stock Issue": "出倉問題",
- "Step Start Time": "步驟開始時間",
- "Overall Time Remaining": "總剩餘時間",
-
- "Reset": "重置",
- "Complexity": "複雜度",
- "Uom": "單位",
- "Time Sequence": "時段",
- "Density": "濃淡",
- "Float": "浮沉",
- "Allergic Substances": "過敏原",
- "Basic Info": "基本資訊",
- "Base Qty": "基本數量",
- "Stock Qty": "庫存數量",
- "Sales Qty": "銷售數量",
- "Sales UOM": "銷售單位",
- "Bom Material" : "BOM 材料",
- "Stock Take Section": "盤點區域",
- "Stock Take Section Description": "盤點區域描述",
- "Lot No": "批號",
- "Depth": "顔色深淺度 深1淺5",
- "Search": "搜索",
- "This lot is rejected, please scan another lot.": "此批次發現問題,請掃描另一個批號。",
- "Process Start Time": "工序開始時間",
- "Stock Req. Qty": "需求數",
- "Actual Time Start": "實際開始時間",
- "Actual Time End": "實際完成時間",
- "Actual Time Used": "實際使用時間",
- "Staff No Required": "員工編號必填",
- "Stock Take Section (can use , to search multiple sections)": "盤點區域(可使用逗號搜索多個區域)",
- "User Not Found": "用戶不存在",
- "Time Remaining": "剩餘時間",
- "Select Printer": "選擇打印機",
- "Changeover Time (mins)": "生產後轉換時間(分鐘)",
- "Finished Time": "完成時間",
- "Passed Step": "通過步驟",
- "Assume End Time": "預計完成時間",
- "Printer": "打印機",
- "Finished Qc Job Order List": "完成QC工單列表",
- "Total finished Qc Job Order": "總完成QC工單數量",
- "Timer Paused": "計時器已暫停",
- "User not found with staffNo:": "用戶不存在",
- "Total finished QC job orders": "總完成QC工單數量",
- "Over Time": "超時",
- "Code": "編號",
- "Job Order No.": "工單編號",
- "FG / WIP Item": "成品/半成品",
- "Production Time Remaining": "生產剩餘時間",
- "Process": "工序",
- "Start": "開始",
-"Finish": "完成",
-"Wait Time [minutes]": "等待時間(分鐘)",
- "Staff No": "員工編號",
- "code": "編號",
- "Name": "名稱",
- "Assignment successful": "分配成功",
-
- "Unable to get user ID": "無法獲取用戶ID",
- "Unknown error: ": "未知錯誤: ",
- "Please try again later.": "請稍後重試。",
- "Type": "類型",
- "Update Job Order": "完成工單",
- "No": "沒有",
- "Assignment failed: ": "分配失敗: ",
- "Unknown error": "未知錯誤",
- "Job Process Status Dashboard": "儀表板 - 工單狀態",
- "Time used": "耗時",
- "In progress": "進行中",
- "Previous page": "上一頁",
- "Next page": "下一頁",
- "Process page summary": "工序 {{from}}–{{to}} / 共 {{total}} 道",
- "Duration hours": "{{count}} 小時",
- "Duration minutes": "{{count}} 分鐘",
- "Duration seconds": "{{count}} 秒",
- "Job process detail: time": "時間",
- "Job process detail: process name": "工序",
- "Job process detail: equipment": "設備",
- "Job process detail: handler": "員工",
- "Job process detail mode label": "工序格顯示",
- "Product process status": "生產流程狀態",
- "Job dashboard PP status: pending": "工序待處理",
- "Job dashboard PP status: in_progress": "工序進行中",
- "Job dashboard PP status: stopped": "工序暫停",
- "Job dashboard PP status: completed": "工序完成",
- "Job dashboard PP status: cancelled": "工序已取消",
- "stopped": "已停止",
- "cancelled": "已取消",
-
-
- "Total Time": "總時間",
- "Remaining Time": "剩餘時間",
- "Wait Time": "等待時間",
- "Wait Time [minutes]": "等待時間(分鐘)",
- "End Time": "完成時間",
- "WIP": "半成品",
- "R&D": "研發",
- "STF": "樣品",
- "Other": "其他",
- "Add some entries!": "添加條目",
- "Add Record": "新增",
- "Clean Record": "重置",
- "Dashboard": "資訊展示面板",
- "Stock Take Management": "盤點管理",
-
- "Store Management": "倉庫管理",
- "Delivery": "送貨訂單",
- "Scheduling": "排程",
- "Settings": "設定",
- "User": "用戶",
- "user": "用戶",
- "User Group": "用戶群組",
- "Items": "物品",
- "BOM Weighting Score List": "物料清單權重得分",
- "Material Weighting": "物料清單加權",
- "Material Score": "物料清單得分",
- "Coming soon": "即將推出",
- "Base Score": "基礎得分",
- "Column Name": "欄位名稱",
- "Range": "範圍",
- "Weighting": "權重",
- "Total weighting must equal 1": "權重總和必須等於 1",
- "Current total": "目前總和",
- "Weighting must be a number": "權重必須為數字",
- "Edit": "編輯",
- "Edit BOM Weighting Score": "編輯物料清單",
- "Save": "儲存",
- "Saving": "儲存中",
- "Cancel": "取消",
- "Update Success": "更新成功",
- "Update Failed": "更新失敗",
- "Remarks": "備註",
- "Release": "放單",
- "Demand Forecast Setting": "需求預測設定",
- "EquipmentType-EquipmentName-Code": "設備類型-設備名稱-編號",
- "Equipment": "設備",
- "Time Information(mins)": "時間信息(分鐘)",
- "Processing Time": "生產時間",
- "Setup Time": "生產前預備時間",
- "Changeover Time": "生產後轉換時間",
- "Warehouse": "倉庫",
- "processing": "生產中",
- "warehouse": "倉庫",
- "Supplier": "供應商",
- "Purchase Order": "採購單",
- "PO Workbench": "採購單工作台",
- "Demand Forecast": "需求預測",
- "Pick Order": "提料單",
- "Deliver Order": "送貨訂單",
- "Project": "專案",
- "Product": "產品",
-
- "mat": "原料",
- "consumables": "消耗品",
- "non-consumables": "非消耗品",
- "fg": "成品",
- "sfg": "半成品",
- "item": "貨品",
- "FG": "成品",
- "Qty": "數量",
- "FG & Material Demand Forecast Detail": "成品及材料需求預測詳情",
- "View item In-out And inventory Ledger": "查看物料出入庫及庫存日誌",
- "Delivery Order": "送貨訂單",
- "Detail Scheduling": "詳細排程",
- "Customer": "客戶",
- "qcItem": "品檢項目",
-
- "Today": "今天",
- "Yesterday": "昨天",
- "Two Days Ago": "前天",
- "Input Equipment is not match with process": "輸入的設備與流程不匹配",
- "Staff No is required": "員工編號必填",
-
- "Day Before Yesterday": "前天",
- "Select Date": "選擇日期",
- "Production Date": "生產日期",
- "QC Check Item": "QC 品檢項目",
- "QC Category": "QC 品檢模板",
- "QC Item All": "QC 綜合管理",
- "qcItemAll": "QC 綜合管理",
- "qcCategory": "品檢模板",
- "QC Check Template": "QC 檢查模板",
- "Mail": "郵件",
- "Import Testing": "匯入測試",
- "FG":"成品",
- "Qty":"數量",
- "FG & Material Demand Forecast Detail":"成品及材料需求預測詳情",
- "View item In-out And inventory Ledger":"查看物料出入庫及庫存日誌",
- "Delivery Order":"送貨訂單",
- "Detail Scheduling":"詳細排程",
- "Customer":"客戶",
- "qcItem":"品檢項目",
- "Item":"物料",
- "Production Date":"生產日期",
- "QC Check Item":"QC 品檢項目",
- "QC Category":"QC 品檢模板",
- "QC Item All":"QC 綜合管理",
- "qcCategory":"品檢模板",
- "QC Check Template":"QC檢查模板",
- "QR Code Handle":"二維碼列印及下載",
- "Mail":"郵件",
- "Import Testing":"匯入測試",
- "Overview": "總覽",
- "Projects": "專案",
- "Create Project": "新增專案",
- "Task Template": "任務範本",
- "Create Task Template": "新增任務範本",
- "Qc Item": "QC 項目",
- "FG Production Schedule": "FG 生產排程",
- "Inventory": "庫存",
- "scheduling": "排程",
- "settings": "設定",
- "items": "物品",
- "edit":"編輯",
- "bag": "包裝袋",
- "Bag Usage": "包裝袋使用記錄",
- "Edit Equipment Type":"設備類型詳情",
- "Edit Equipment":"設備詳情",
- "equipmentType":"設備種類",
- "Description":"描述",
- "edit": "編輯",
- "Edit Equipment Type": "設備類型詳情",
- "Edit Equipment": "設備詳情",
- "equipmentType": "設備類型",
- "Description": "描述",
- "Details": "詳情",
- "Equipment Type Details":"設備類型詳情",
- "Equipment Type":"設備類型",
- "Save":"儲存",
- "Cancel":"取消",
- "Equipment Details":"設備詳情",
- "Exclude Date":"排除日期",
- "Finished Goods Name":"成品名稱",
- "Equipment Type Details": "設備類型詳情",
- "Save": "儲存",
- "Cancel": "取消",
- "Equipment Details": "設備詳情",
- "Exclude Date": "排除日期",
- "Finished Goods Name": "成品名稱",
- "create": "新增",
- "hr": "小時",
- "hrs": "小時",
- "min": "分鐘",
- "mins": "分鐘",
- "Job Order": "工單",
- "Edit Job Order": "工單詳情",
- "Production": "生產流程",
- "Put Away": "上架",
- "Put Away Scan": "上架掃碼",
- "Management Job Order": "管理工單",
- "Search Job Order/ Create Job Order": "搜索工單/ 建立工單",
- "Finished Good Order": "成品出倉",
- "Finished Good Management": "成品出倉管理",
- "提料順序": "提料順序",
- "Filter": "過濾",
- "Item Code": "物料編號",
- "Item Name": "物料名稱",
- "Just Completed (workbench): requires valid quantity; expired rows must not use this button.": "工單對料:需要有效數量;過期項目不能使用此按鈕。",
- "Search & Jump": "搜索並跳轉",
- "Enter to jump to item": "按 Enter 直接跳到品項位置",
- "Jump": "跳轉",
- "Move Up": "上移",
- "Move Down": "下移",
- "Move Top": "置頂",
- "Move Bottom": "置底",
- "Add Item": "加入品項",
- "Refresh": "重新載入",
- "Unsaved changes": "有未儲存的變更",
- "Select items without order to append to bottom": "只會顯示尚未設定順序的品項,確認後會加到清單底部",
- "Only show FG items without order": "請先輸入關鍵字再搜索(只會查詢未設定順序的品項)",
- "Insert position must be >= 1": "插入位置必須大於或等於 1",
- "Insert at": "插入位置",
- "Order number": "順序號碼",
- "Order": "順序",
- "Location": "位置",
- "finishedGood": "成品",
- "Router": "執貨路線",
- "Job Order Pickexcution": "工單提料",
- "No data available": "沒有資料",
- "Job Type": "工單類型",
- "Start Scan": "開始掃碼",
- "Stop Scan": "停止掃碼",
- "Scan Result": "掃碼結果",
- "Expiry Date": "有效期",
- "Pick Order Code": "提料單編號",
- "Target Date": "需求日期",
- "Lot Required Pick Qty": "批號需求數量",
- "Are you sure you want to delete this process?": "您確定要刪除此工序嗎?",
- "Job Order Match": "工單對料",
- "All Pick Order Lots": "所有提料單批號",
- "Row per page": "每頁行數",
- "Select Unit": "選擇單位",
- "No data available": "沒有資料",
- "Bom Req. Qty": "BOM",
- "Material Name": "材料清單",
- "Material Code": "材料清單",
- "Bom UOM": "使用單位",
- "Base UOM": "基本單位",
- "Stock UOM": "庫存單位",
- "jodetail": "工單細節",
- "Sign out": "登出",
- "By-product": "副產品",
- "Complete Step": "完成步驟",
- "Defect": "不良品",
- "Output from Process": "工序產出",
- "Quantity": "數量",
- "Scrap": "損耗",
- "Unit": "單位",
- "Back to List": "返回列表",
- "Production Output Data Entry": "生產輸出數據輸入",
- "Step": "步驟",
- "Quality Check": "品質檢查",
- "Action": "操作",
- "Changeover Time (mins)": "生產後轉換時間(分鐘)",
- "Completed": "完成",
- "completed": "完成",
- "Date": "日期",
- "Failed to submit scan data. Please try again.": "掃碼數據提交失敗. 請重試.",
- "In Progress": "進行中",
- "Is Dark": " 顔色深淺度",
- "Is Dense": "濃淡",
- "Is Float": "浮沉",
- "Job Order Code": "工單編號",
-
- "Output Qty": "輸出數量",
- "Pending": "待處理",
- "pending": "待處理",
- "Please scan equipment code (optional if not required)": "請掃描設備編號(可選)",
- "Please scan operator code": "請掃描操作員編號",
- "Please scan operator code first": "請先掃描操作員編號",
- "Processing Time (mins)": "步驟時間(分鐘)",
- "Production Process Information": "生產流程信息",
- "Production Process Steps": "生產流程步驟",
- "Scan Operator & Equipment": "掃描操作員和設備",
- "Setup Time (mins)": "生產前預備時間(分鐘)",
- "Start": "開始",
- "Start QR Scan": "開始掃碼",
- "Status": "狀態",
- "in_progress": "進行中",
- "In_Progress": "進行中",
- "inProgress": "進行中",
- "Step Name": "名稱",
- "Stop QR Scan": "停止掃碼",
- "Submit & Start": "提交並開始",
- "Total Steps": "總步驟數",
- "Unknown": "",
- "Validation failed. Please check operator and equipment.": "驗證失敗. 請檢查操作員和設備.",
- "View": "查看",
- "Back": "返回",
- "BoM Material": "材料清單",
- "N/A": "不適用",
- "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間次序 | 複雜度",
- "Please scan equipment code": "請掃描設備編號",
- "Equipment Code": "設備編號",
- "Seq": "步驟",
- "SEQ": "步驟",
- "Job Order Info": "工單信息",
- "Matching Stock": "工單對料",
- "No data found": "沒有找到資料",
- "Production Priority": "生產優先序",
- "Production Process": "工藝流程",
- "Production Process Line Remark": "工藝明細",
- "Remark": "明細",
- "Req. Qty": "需求數量",
- "Seq No": "加入步驟",
- "Total pick orders": "總提料單數量",
- "Seq No Remark": "序號明細",
- "Stock Available": "庫存數",
- "Confirm": "確認",
- "Do you want to delete?": "您確定要刪除嗎?",
- "Stock Status": "庫存狀態",
- "Target Production Date": "目標生產日期",
- "id": "ID",
- "Finished lines": "已完成流程",
- "Please scan staff no": "請掃描員工編號",
- "Paused": "已暫停",
- "paused": "已暫停",
- "Pause Reason": "暫停原因",
- "Reason": "原因",
- "Invalid Stock In Line Id": "無效庫存行ID",
- "Production date": "生產日期",
- "update production priority": "更新生產優先序",
- "Assume Time Need": "預計所需時間",
- "Required Qty": "需求數",
- "Bom Required Qty": "Bom 使用份量",
- "Total processes": "總流程數",
- "View Details": "查看詳情",
- "view stockin": "品檢",
- "minutes": "分鐘",
- "Start Time": "開始時間",
- "Consumed Qty": "消耗數量",
- "Scrap Qty": "損耗數量",
- "Add Bag": "新增包裝袋",
- "Submit Bag Consumption": "提交包裝袋消耗",
- "Bag Consumption": "包裝袋消耗",
- "Bag": "包裝袋",
- "Select Bag": "選擇包裝袋",
- "No completed Job Order pick orders with matching found": "沒有相關記錄",
- "Handler": "提料員",
- "Completed Step": "完成步驟",
- "Continue": "繼續",
- "Executing": "執行中",
- "Order Complete": "訂單完成",
- "Pause": "暫停",
- "Production Output Data": "生產輸出數據",
- "Step Information": "步驟信息",
- "Stop": "停止",
- "Putaway Detail": "上架詳情",
- "Lines with sufficient stock: ": "可提料項目數量: ",
- "Lines with insufficient stock: ": "未能提料項目數量: ",
- "Total lines: ": "總數量:",
- "Balance": "可用數量",
- "Selected Qty": "選擇數量",
- "Submitting...": "提交中...",
- "Batch Count": "批數",
- "Shop": "店鋪",
- "ShopAndTruck": "店鋪路線管理",
- "DO floor (supplier)": "送貨單樓層(供應商)",
- "Route Board": "車線看板",
- "Shop Information": "店鋪資訊",
- "Shop Name": "店鋪名稱",
- "Shop Branch": "店鋪分店",
- "Select a shop first": "請先選擇店鋪",
- "Search or select branch": "搜索或選擇分店",
- "Mass Edit": "批量編輯",
- "Save All": "全部儲存",
- "All shops updated successfully": "所有店鋪已成功更新",
- "Shop Code": "店鋪編號",
- "Truck Lane": "車線",
- "Truck Lane Detail": "車線詳情",
- "TruckLance Code": "車線編號",
- "TruckLance Status": "車線狀態",
- "Departure Time": "出發時間",
- "Loading Sequence": "裝載順序",
- "District Reference": "區域參考",
- "Store ID": "樓層",
- "Remark": "備註",
- "Powder_Mixture": "箱料粉",
- "Powder Mixture": "箱料粉",
- "Not Match": "數值不符",
- "Pass": "已盤點",
- "pass": "已盤點",
- "Actions": "操作",
- "Insert": "插入",
- "Move to order": "移動到指定順序",
- "Target order": "目標順序",
- "In front of": "前面",
- "Behind": "後面",
- "This will move the item to exact order": "確認後會把此品項移到指定順序位置,並自動重排其餘順序",
- "View Detail": "查看詳情",
- "Back": "返回",
- "Back to Truck Lane List": "返回車線列表",
- "Back to List": "返回列表",
- "Add Truck Lane": "新增車線",
- "Add New Truck Lane": "新增車線",
- "Truck Information": "車線資訊",
- "No Truck data available": "沒有卡車資料",
- "No shops found using this truck lane": "沒有找到使用此車線的店鋪",
- "Shops Using This Truck Lane": "使用此車線的店鋪",
- "Complete": "完成",
- "Missing Data": "缺少資料",
- "No TruckLance": "無車線",
- "Edit shop truck lane": "編輯店鋪車線",
- "Delete truck lane": "刪除車線",
- "Edit loading sequence": "編輯裝載順序",
- "Save changes": "儲存變更",
- "Cancel editing": "取消編輯",
- "Edit truck lane": "編輯車線",
- "Truck ID is required": "需要卡車ID",
- "Truck lane not found": "找不到車線",
- "No truck lane data available": "沒有車線資料",
- "Failed to load truck lanes": "載入車線失敗",
- "Failed to load shops": "載入店鋪失敗",
- "Loading sequence updated successfully": "裝載順序更新成功",
- "Failed to save loading sequence": "儲存裝載順序失敗",
- "Truck lane deleted successfully": "車線刪除成功",
- "Failed to delete truck lane": "刪除車線失敗",
- "Are you sure you want to delete this truck lane?": "您確定要刪除此車線嗎?",
- "Invalid shop data": "無效的店鋪資料",
- "Contact No": "聯絡電話",
- "Contact Email": "聯絡郵箱",
- "Contact Name": "聯絡人",
- "Addr1": "地址1",
- "Addr2": "地址2",
- "Addr3": "地址",
- "Shop not found": "找不到店鋪",
- "Shop ID is required": "需要店鋪ID",
- "Invalid Shop ID": "無效的店鋪ID",
- "Failed to load shop detail": "載入店鋪詳情失敗",
- "Failed to load shop details": "載入店鋪詳情失敗",
- "Failed to save truck data": "儲存卡車資料失敗",
- "Failed to delete truck lane": "刪除車線失敗",
- "Failed to create truck": "建立卡車失敗",
- "Please fill in the following required fields:": "請填寫以下必填欄位:",
- "TruckLance Code": "車線編號",
- "Enter or select remark": "輸入或選擇備註",
- "Not editable for this Store ID": "此樓層不可編輯",
- "No Truck Lane data available": "沒有車線資料",
- "Please log in to view shop details": "請登入以查看店鋪詳情",
- "Invalid truck data": "無效的卡車資料",
- "Invalid departure time": "無效的出發時間",
- "No trucks found for this truck lane": "此車線沒有可更新的資料",
- "Departure time updated for all shops on this truck lane": "已將出發時間更新至此車線下的所有店鋪",
- "Applies to all shops using this truck lane": "將套用至所有使用此車線的店鋪",
- "Edit departure time": "編輯出發時間",
- "Failed to load truck lane detail": "載入車線詳情失敗",
- "Shop Detail": "店鋪詳情",
- "Just Pass": "已完成",
- "Truck Lane Detail": "車線詳情",
- "Filter by Status": "按狀態篩選",
- "All": "全部",
- "General Data": "基本資料",
- "Repair and Maintenance": "維護和保養",
- "Repair and Maintenance Status": "維護和保養狀態",
- "Latest Repair and Maintenance Date": "最新維護和保養日期",
- "Last Repair and Maintenance Date": "上次維護和保養日期",
- "Repair and Maintenance Remarks": "維護和保養備註",
- "Rows per page": "每頁行數",
- "Equipment Name": "設備名稱",
- "Equipment Code": "設備編號",
- "Yes": "是",
- "No": "否",
- "No.": "編號",
- "Operator Name & No.": "操作員名稱及編號",
- "Count of Job Orders": "已處理工單",
- "Total Processing Time": "總工時",
- "Material Pick Status": "物料提料狀態",
- "Operator KPI Dashboard": "儀表板 - 操作員KPI概覽",
- "Operator": "員工資訊",
- "Equipment Name and Code": "設備名稱及編號",
- "Remaining Time (min)": "剩餘時間(分鐘)",
- "Production Equipment Status Dashboard": "儀表板 - 生產設備最新狀態",
- "Idle": "閒置",
- "Process": "工序",
- "Job Details": "工單編號及生產產品",
- "Required Time": "所需時間",
- "Estimated Completion Time": "預計完成時間",
- "Job Order and Product": "工單及貨品",
- "Update Equipment Maintenance and Repair": "更新設備的維護和保養",
- "Equipment Information": "設備資訊",
- "Loading": "載入中...",
- "Equipment not found": "找不到設備",
- "Error saving data": "保存數據時出錯",
- "TruckLance Code is required": "需要車線編號",
- "Truck shop details updated successfully": "卡車店鋪詳情更新成功",
- "Failed to save truck shop details": "儲存卡車店鋪詳情失敗",
- "Truck lane information is required": "需要車線資訊",
- "Shop added to truck lane successfully": "店鋪已成功新增至車線",
- "Failed to create shop in truck lane": "新增店鋪至車線失敗",
- "Add Shop": "新增店鋪",
- "Search or select shop name": "搜索或選擇店鋪名稱",
- "stocktakemanagement": "盤點管理",
- "stockRecord": "盤點記錄",
- "Search or select shop code": "搜索或選擇店鋪編號",
- "Search or select remark": "搜索或選擇備註",
- "Edit shop details": "編輯店鋪詳情",
- "Add Shop to Truck Lane": "新增店鋪至車線",
- "Truck lane code already exists. Please use a different code.": "車線編號已存在,請使用其他編號。",
- "MaintenanceEdit": "編輯維護和保養",
- "ps": "排程",
- "Printer": "列印機",
- "Delete": "刪除",
- "Delete Success": "刪除成功",
- "Delete Failed": "刪除失敗",
- "Create Printer": "新增列印機",
- "Report": "報告",
- "Issue": "問題",
- "Note:": "注意:",
- "Required Qty": "需求數量",
- "Verified Qty": "確認數量",
- "Max": "最大值",
- "Min": "最小值",
- "Max": "最大值",
- "This form is for reporting issues only. You must report either missing items or bad items.": "此表單僅用於報告問題。您必須報告缺少的物品或不良物品。",
- "Pick Execution Issue Form": "提料問題表單",
- "Missing items": "缺少物品",
- "Total (Verified + Bad + Missing) must equal Required quantity": "總數必須等於需求數量",
- "Missing item Qty": "缺少物品數量",
- "seq": "序號",
- "Job Order Pick Execution": "工單提料",
- "Bad Item Qty": "不良物品數量",
- "Issue Remark": "問題備註",
- "At least one issue must be reported": "至少需要報告一個問題",
- "Qty is required": "數量是必填項",
- "Verified quantity cannot exceed received quantity": "確認數量不能超過接收數量",
- "Handled By": "處理者",
- "submit": "提交",
- "Received Qty": "接收數量",
- "bomWeighting": "物料清單權重得分",
- "Now": "現時",
- "Last updated": "最後更新",
- "Auto-refresh every 5 minutes": "每5分鐘自動刷新",
- "Auto-refresh every 10 minutes": "每10分鐘自動刷新",
- "Auto-refresh every 15 minutes": "每15分鐘自動刷新",
- "Auto-refresh every 1 minute": "每1分鐘自動刷新",
- "Brand": "品牌",
- "Price Inquiry": "價格查詢",
- "No Purchase Order After 2026-01-01": "在2026-01-01後沒有採購記錄",
- "No Import Record": "沒有導入記錄",
-
- "wip": "半成品",
- "cmb": "消耗品",
- "nm": "雜項及非消耗品",
- "MAT": "材料",
- "CMB": "消耗品",
- "NM": "雜項及非消耗品",
- "Download Template": "下載範本",
- "Upload": "上傳",
- "Downloading...": "正在下載...",
- "Uploading...": "正在上傳...",
- "Upload successful": "上傳成功",
- "Upload failed": "上傳失敗",
- "Download failed": "下載失敗",
- "Upload completed with count": "已更新 {{count}} 個項目。",
- "Upload row errors": "以下行有問題:",
- "item(s) updated": "個項目已更新。",
- "Average unit price": "平均單位價格",
- "Latest market unit price": "最新市場價格",
- "Current Stock": "現有庫存",
- "masterDataIssue_nav": "BOM/貨品單位問題"
-}
\ No newline at end of file
+ "Actions": "操作",
+ "Add Document": "新增文件",
+ "All": "全部",
+ "Allergic Substances": "過敏原",
+ "An error has occurred. Please try again later.": "發生錯誤,請稍後再試。",
+ "Are you sure you want to delete this item?": "您確定要刪除此項目嗎?",
+ "Back": "返回",
+ "Basic Info": "基本資訊",
+ "Bom Required Qty": "BOM 使用份量",
+ "Bom UOM": "BOM 單位",
+ "Brand": "品牌",
+ "CMB": "消耗品",
+ "CO": "消耗品",
+ "Cancel": "取消",
+ "Column Name": "欄位名稱",
+ "Coming soon": "即將推出",
+ "Complexity": "複雜度",
+ "Confirm": "確認",
+ "Confirm Delete": "確認刪除",
+ "Cost (HKD)": "費用 (HKD)",
+ "Current total": "目前總和",
+ "Day Before Yesterday": "前天",
+ "Delete": "刪除",
+ "Delete Failed": "刪除失敗",
+ "Density": "濃淡",
+ "Depth": "顔色深淺度 深1淺5",
+ "Description": "描述",
+ "Details": "詳情",
+ "Duration (Minutes)": "時間(分)",
+ "Edit": "編輯",
+ "Enter any additional observations or notes...": "輸入其他觀察或備註...",
+ "Enter or select remark": "輸入或選擇備註",
+ "Error saving data": "保存數據時出錯",
+ "Failed to fetch data": "無法取得資料",
+ "Filter": "過濾",
+ "Finished Good Detail": "成品出倉詳情",
+ "Finished Good Management": "成品出倉管理",
+ "Finished Good Order": "成品出倉",
+ "Float": "浮沉",
+ "General Data": "基本資料",
+ "Grade {{grade}}": "等級 {{grade}}",
+ "Invalid Job Order Id": "無效工單編號",
+ "Invoice": "發票",
+ "Invoice Date": "發票日期",
+ "Item Code": "物品編號",
+ "Item Name": "物品名稱",
+ "Loading": "載入中...",
+ "Loading order summary": "正在載入訂單摘要",
+ "Location": "位置",
+ "MA": "材料",
+ "MAT": "材料",
+ "MI": "雜項",
+ "Management Job Order": "管理工單",
+ "Material Name": "材料清單",
+ "Min": "最小值",
+ "NM": "雜項及非消耗品",
+ "No": "否",
+ "No Lot": "沒有批號",
+ "No data available": "沒有資料",
+ "No options": "沒有選項",
+ "No processes found for this job order": "找不到此工單的工序",
+ "Order": "順序",
+ "Pending": "待處理",
+ "Please Select BOM": "請選擇 BOM",
+ "Please try again later.": "請稍後重試。",
+ "Project Code": "專案代碼",
+ "Project Code and Name": "專案代碼與名稱",
+ "QC Template not found": "找不到 QC 範本",
+ "Qty": "數量",
+ "RM": "原料",
+ "Range": "範圍",
+ "Refresh": "重新載入",
+ "Remarks": "備註",
+ "Remove Document": "移除文件",
+ "Report": "報告",
+ "Reset": "重置",
+ "Row per page": "每頁行數",
+ "Rows per page": "每頁行數",
+ "Sales Qty": "銷售數量",
+ "Sales UOM": "銷售單位",
+ "Save": "儲存",
+ "Saving": "儲存中",
+ "Search": "搜索",
+ "Search Criteria": "搜索條件",
+ "Select Date": "選擇日期",
+ "Session expired or unauthorized.": "工作階段已過期或未經授權。",
+ "Sign out": "登出",
+ "Status": "狀態",
+ "Stock Qty": "庫存數量",
+ "Supporting Document": "證明文件",
+ "Task": "任務",
+ "Time Sequence": "時段",
+ "Today": "今天",
+ "Total weighting must equal 1": "權重總和必須等於 1",
+ "Unauthorized: Please log in again": "未經授權:請重新登入",
+ "Uom": "單位",
+ "Update Failed": "更新失敗",
+ "Update Success": "更新成功",
+ "Weighting must be a number": "權重必須為數字",
+ "Yes": "是",
+ "Yesterday": "昨天",
+ "all": "全部",
+ "bomWeighting": "BOM 權重得分",
+ "cmb": "消耗品",
+ "collapsible table": "可折疊表格",
+ "consumable": "消耗品",
+ "consumables": "消耗品",
+ "create": "新增",
+ "edit": "編輯",
+ "expand row": "展開行",
+ "group mode": "群組模式",
+ "item": "貨品",
+ "items": "物品",
+ "mat": "原料",
+ "menu": "選單",
+ "nm": "雜項及非消耗品",
+ "non-consumables": "非消耗品",
+ "other": "其他",
+ "profile": "個人資料",
+ "revert": "還原",
+ "settings": "設定",
+ "testing sections tabs": "測試區域分頁",
+ "warehouse": "倉庫",
+ "材料": "材料"
+}
diff --git a/src/i18n/zh/dashboard.json b/src/i18n/zh/dashboard.json
index a937856..017ab5c 100644
--- a/src/i18n/zh/dashboard.json
+++ b/src/i18n/zh/dashboard.json
@@ -1,5 +1,7 @@
{
"Dashboard": "資訊展示面板",
+ "dashboard": "資訊展示面板",
+ "dashboard tabs": "儀表板分頁",
"Order status": "訂單狀態",
"pending": "待處理",
"receiving": "收貨中",
@@ -16,7 +18,7 @@
"Warehouse status": "倉庫狀態",
"Progress chart": "進度圖表",
"Po Code/Jo Code": "採購編號/工單編號",
- "Purchase Order Code": "採購單號",
+ "Purchase Order Code": "採購訂單編號",
"Item Name": "貨品名稱",
"Escalation Level": "上報等級",
"Reason": "上報原因",
@@ -59,7 +61,7 @@
"Responsible Escalation List": "負責的上報列表",
"show completed logs": "顯示已完成上報",
"Rows per page": "每頁行數",
- "Truck Schedule Dashboard": "車線調度儀表板",
+ "Truck Schedule Dashboard": "車線儀表板",
"Store ID": "樓層",
"All Stores": "所有樓層",
"Auto-refresh every 5 minutes": "每5分鐘自動刷新",
@@ -105,20 +107,18 @@
"Column 2": "欄位2",
"Column 3": "欄位3",
"No data available": "暫無資料",
+ "Overview": "總覽",
"Supplier Code": "供應商編號",
"Supplier Name": "供應商名稱",
- "Purchase Order Code": "採購訂單編號",
"Statistics": "統計",
"Show Supplier Code": "顯示供應商編號",
"Show Purchase Order Codes": "顯示採購訂單編號",
"x/y orders received": "x/y張單已處理",
"Goods Receipt Status New": "採購單接收狀態",
"Status": "狀態",
- "Now": "現時",
- "Last updated": "最後更新",
- "Auto-refresh every 5 minutes": "每5分鐘自動刷新",
+ "Two column navigable table": "雙欄導航表格",
+ "Now": "現時",
"Auto-refresh every 10 minutes": "每10分鐘自動刷新",
- "Auto-refresh every 15 minutes": "每15分鐘自動刷新",
"Auto-refresh every 1 minute": "每1分鐘自動刷新",
"Usage statistics": "報告管理與送貨路線摘要使用統計",
"Usage stats description": "報告管理與送貨路線摘要:進入頁面次數、下載與直接列印次數。",
diff --git a/src/i18n/zh/deliveryOrderFloor.json b/src/i18n/zh/deliveryOrderFloor.json
index 6718d20..6cabec6 100644
--- a/src/i18n/zh/deliveryOrderFloor.json
+++ b/src/i18n/zh/deliveryOrderFloor.json
@@ -1,6 +1,6 @@
{
"title": "送貨單樓層設定(供應商代碼)",
- "Intro": "以下為系統設定中的供應商代碼(逗號分隔)。點編輯可修改;是否影響 DO 行為取決於後端是否讀取對應 settings。",
+ "Intro": "管理各樓層的供應商代碼。點擊編輯按鈕可新增或移除供應商。",
"2F supplier": "2F 供應商",
"4F supplier": "4F 供應商",
"Edit 2F": "編輯 2F",
@@ -29,5 +29,6 @@
"Comma separated hint": "多個代碼請以英文逗號分隔,勿加空白",
"Save": "儲存",
"Saved": "已儲存",
- "Cancel": "取消"
+ "Cancel": "取消",
+ "DO floor (supplier)": "送貨單樓層(供應商)"
}
diff --git a/src/i18n/zh/demandForecast.json b/src/i18n/zh/demandForecast.json
new file mode 100644
index 0000000..feb7352
--- /dev/null
+++ b/src/i18n/zh/demandForecast.json
@@ -0,0 +1,12 @@
+{
+ "Demand Forecast Setting": "需求預測設定",
+ "Finished Goods Name": "成品名稱",
+ "Exclude Date": "排除日期",
+ "Mon": "週一",
+ "Tue": "週二",
+ "Wed": "週三",
+ "Thu": "週四",
+ "Fri": "週五",
+ "Sat": "週六",
+ "Sun": "週日"
+}
diff --git a/src/i18n/zh/detailScheduling.json b/src/i18n/zh/detailScheduling.json
index c0bb011..8666fa5 100644
--- a/src/i18n/zh/detailScheduling.json
+++ b/src/i18n/zh/detailScheduling.json
@@ -1,21 +1,21 @@
{
- "Detail Scheduling": "詳細排程",
- "Search Criteria": "搜索條件",
- "Search": "搜索",
- "Reset": "重置",
- "Search by Project Code or Project Name or Client Name or Project Category or Project Type or Project Status or Project Start Date or Project End Date": "搜索專案編號、專案名稱、客戶名稱、專案類別、專案類型、專案狀態、專案開始日期、專案結束日期",
- "Project Code": "專案編號",
- "Project Name": "專案名稱",
- "Client Name": "客戶名稱",
- "Project Category": "專案類別",
- "Project Type": "專案類型",
- "Project Status": "專案狀態",
- "Demand Forecast Period": "需求預測期",
- "Scheduled At": "預定時間",
- "Product Count(s)": "產品數量",
- "Product Count": "產品數量",
- "Schedule Period": "排程期間",
- "Product": "產品",
- "Details": "詳情",
- "types": "類型"
-}
\ No newline at end of file
+ "Detail Scheduling": "詳細排程",
+ "Search Criteria": "搜索條件",
+ "Search": "搜索",
+ "Reset": "重置",
+ "Search by Project Code or Project Name or Client Name or Project Category or Project Type or Project Status or Project Start Date or Project End Date": "搜索專案編號、專案名稱、客戶名稱、專案類別、專案類型、專案狀態、專案開始日期、專案結束日期",
+ "Project Code": "專案編號",
+ "Project Name": "專案名稱",
+ "Client Name": "客戶名稱",
+ "Project Category": "專案類別",
+ "Project Type": "專案類型",
+ "Project Status": "專案狀態",
+ "Demand Forecast Period": "需求預測期",
+ "Scheduled At": "預定時間",
+ "Product Count(s)": "產品數量",
+ "Product Count": "產品數量",
+ "Schedule Period": "排程期間",
+ "Product": "產品",
+ "Details": "詳情",
+ "types": "類型"
+}
diff --git a/src/i18n/zh/do.json b/src/i18n/zh/do.json
index 5ab7452..a22423c 100644
--- a/src/i18n/zh/do.json
+++ b/src/i18n/zh/do.json
@@ -1,97 +1,98 @@
{
- "Delivery Order": "送貨訂單",
- "Shop Name": "店鋪名稱",
- "Delivery Order No.": "送貨訂單編號",
- "Delivery Order Date": "送貨訂單日期",
- "Delivery Order Status": "送貨訂單狀態",
- "Order Date": "訂單日期",
- "Estimated Arrival": "預計送貨日期",
- "Estimated Arrival From": "預計送貨日期",
- "Estimated Arrival To": "預計送貨日期至",
- "Status": "來貨狀態",
- "Etra": "加單",
- "Loading": "正在加載...",
- "No delivery orders selected for batch release. Uncheck orders you want to exclude, or search again to reset selection.": "沒有選擇送貨訂單進行批量放單。取消勾選您想排除的訂單,或重新搜索以重置選擇。",
- "No Records": "沒有找到記錄",
- "OK": "確認",
- "Truck X": "車線-X",
- "DO Workbench": "新版成品出倉",
- "Order Date From": "訂單日期",
- "Workbench Batch Release": "批量放單",
- "do workbench": "新版成品出倉",
- "Do Workbench": "新版成品出倉",
- "Delivery Order Code": "送貨訂單編號",
- "Floor": "樓層",
- "Truck lane search requires date title": "需選擇預計送貨日期",
- "Truck lane search requires date message": "已填寫車線號碼時,請一併選擇預計送貨日期後再搜索。",
- "Truck Lance Code": "車線號碼",
- "Select Remark": "選擇備註",
- "Confirm Assignment": "確認分配",
- "Submit Qty": "提交數量",
- "Required Date": "所需日期",
- "Submit Miss Item": "提交缺貨品",
- "Submit Quantity": "提交數量",
- "Store": "位置",
- "Lane Code": "車線號碼",
- "Available Orders": "可用訂單",
- "Just Complete": "已完成",
- "Order Date To": "訂單日期至",
- "Warning: Some delivery orders do not have matching trucks for the target date.": "警告:部分送貨訂單於目標日期沒有可匹配的車線。",
- "Truck Availability Warning": "車線可用性警告",
- "Problem DO(s): ": "問題送貨訂單",
- "Fetching all matching records...": "正在獲取所有匹配的記錄...",
- "Progress": "進度",
- "Loading...": "正在加載...",
- "Available Trucks": "可用車線",
- "No trucks available": "沒有車線可用",
- "Remark": "備註",
- "Just Completed": "已完成",
- "Code": "門店訂單編號",
- "code": "門店訂單編號",
- "Create": "新增",
- "Supplier Name": "供應商名稱",
- "Details": "詳情",
- "Pending": "待處理",
- "pending": "待處理",
- "Receiving": "接收中",
- "receiving": "接收中",
- "Completed": "已完成",
- "completed": "已完成",
- "Please wait": "請稍候",
- "Selected Shop(s): ": "已選擇店舖數量: ",
- "Selected Item(s): ": "總貨品數量: ",
- "Confirm": "確認",
- "Cancel": "取消",
- "Releasing": "處理中",
- "Shop Code": "店鋪編號",
- "Supplier Code": "供應商編號",
- "Estimated Arrival Date": "預計送貨日期",
- "Item No.": "商品編號",
- "Item Name": "商品名稱",
- "Quantity": "數量",
- "uom": "單位",
- "Lot No.": "批號",
- "Expiry Date": "有效期",
- "Location": "庫位",
- "Price": "價格",
- "Action": "操作",
- "Edit": "編輯",
- "Delete": "刪除",
- "Release": "放單",
- "Back": "返回",
- "Batch Release": "批量放單",
- "Batch release completed successfully.": "已完成批量放單",
- "Edit Delivery Order Detail": "編輯送貨訂單詳情",
- "DO released successfully! Pick orders created.": "送貨訂單放單成功!提料單已建立。",
- "Stock Available": "庫存可用",
- "row selected": "行已選擇",
- "An error has occurred. Please try again later.": "發生錯誤,請稍後再試。",
- "Assign 2/F": "分配2/F",
- "Assign 4/F": "分配4/F",
- "Failed to assign pick orders. Please try again later.": "分配提料單失敗,請稍後再試。",
- "Failed to release pick orders. Please try again later.": "放單提料單失敗,請稍後再試。",
- "Pick Order Assignment": "提料單分配",
- "Release 2/F": "放單2/F",
- "Release 4/F": "放單4/F",
- "Stock Status": "庫存狀態"
-}
\ No newline at end of file
+ "Delivery Order": "送貨訂單",
+ "Shop Name": "店鋪名稱",
+ "Delivery Order No.": "送貨訂單編號",
+ "Delivery Order Date": "送貨訂單日期",
+ "Delivery Order Status": "送貨訂單狀態",
+ "Order Date": "訂單日期",
+ "Estimated Arrival": "預計送貨日期",
+ "Estimated Arrival From": "預計送貨日期",
+ "Estimated Arrival To": "預計送貨日期至",
+ "Status": "來貨狀態",
+ "Etra": "加單",
+ "Loading": "正在加載...",
+ "No delivery orders selected for batch release. Uncheck orders you want to exclude, or search again to reset selection.": "沒有選擇送貨訂單進行批量放單。取消勾選您想排除的訂單,或重新搜索以重置選擇。",
+ "No Records": "沒有找到記錄",
+ "OK": "確認",
+ "Truck X": "車線-X",
+ "DO Workbench": "新版成品出倉",
+ "Order Date From": "訂單日期",
+ "Workbench Batch Release": "批量放單",
+ "do workbench": "新版成品出倉",
+ "Do Workbench": "新版成品出倉",
+ "Delivery Order Code": "送貨訂單編號",
+ "Floor": "樓層",
+ "Truck lane search requires date title": "需選擇預計送貨日期",
+ "Truck lane search requires date message": "已填寫車線號碼時,請一併選擇預計送貨日期後再搜索。",
+ "Truck Lance Code": "車線號碼",
+ "Select Remark": "選擇備註",
+ "Confirm Assignment": "確認分配",
+ "Submit Qty": "提交數量",
+ "Required Date": "所需日期",
+ "Submit Miss Item": "提交缺貨品",
+ "Submit Quantity": "提交數量",
+ "Store": "位置",
+ "Lane Code": "車線號碼",
+ "Available Orders": "可用訂單",
+ "Just Complete": "已完成",
+ "Order Date To": "訂單日期至",
+ "Warning: Some delivery orders do not have matching trucks for the target date.": "警告:部分送貨訂單於目標日期沒有可匹配的車線。",
+ "Truck Availability Warning": "車線可用性警告",
+ "Problem DO(s): ": "問題送貨訂單",
+ "Fetching all matching records...": "正在獲取所有匹配的記錄...",
+ "Progress": "進度",
+ "Loading...": "正在加載...",
+ "Available Trucks": "可用車線",
+ "No trucks available": "沒有車線可用",
+ "Remark": "備註",
+ "Just Completed": "已完成",
+ "Code": "門店訂單編號",
+ "code": "門店訂單編號",
+ "Create": "新增",
+ "Supplier Name": "供應商名稱",
+ "Details": "詳情",
+ "Pending": "待處理",
+ "pending": "待處理",
+ "Receiving": "接收中",
+ "receiving": "接收中",
+ "Completed": "已完成",
+ "completed": "已完成",
+ "Please wait": "請稍候",
+ "Selected Shop(s): ": "已選擇店舖數量: ",
+ "Selected Item(s): ": "總貨品數量: ",
+ "Confirm": "確認",
+ "Cancel": "取消",
+ "Releasing": "處理中",
+ "Shop Code": "店鋪編號",
+ "Supplier Code": "供應商編號",
+ "Estimated Arrival Date": "預計送貨日期",
+ "Item No.": "商品編號",
+ "Item Name": "商品名稱",
+ "Quantity": "數量",
+ "uom": "單位",
+ "Lot No.": "批號",
+ "Expiry Date": "有效期",
+ "Location": "庫位",
+ "Price": "價格",
+ "Action": "操作",
+ "Edit": "編輯",
+ "Delete": "刪除",
+ "Release": "放單",
+ "Back": "返回",
+ "Batch Release": "批量放單",
+ "Batch release completed successfully.": "已完成批量放單",
+ "Edit Delivery Order Detail": "編輯送貨訂單詳情",
+ "DO released successfully! Pick orders created.": "送貨訂單放單成功!提料單已建立。",
+ "Stock Available": "庫存可用",
+ "row selected": "行已選擇",
+ "An error has occurred. Please try again later.": "發生錯誤,請稍後再試。",
+ "Assign 2/F": "分配2/F",
+ "Assign 4/F": "分配4/F",
+ "Failed to assign pick orders. Please try again later.": "分配提料單失敗,請稍後再試。",
+ "Failed to release pick orders. Please try again later.": "放單提料單失敗,請稍後再試。",
+ "Pick Order Assignment": "提料單分配",
+ "Release 2/F": "放單2/F",
+ "Release 4/F": "放單4/F",
+ "Stock Status": "庫存狀態",
+ "Delivery": "送貨訂單"
+}
diff --git a/src/i18n/zh/doWorkbench.json b/src/i18n/zh/doWorkbench.json
new file mode 100644
index 0000000..d918e48
--- /dev/null
+++ b/src/i18n/zh/doWorkbench.json
@@ -0,0 +1,49 @@
+{
+ "DO Workbench": "新版成品出倉",
+ "Confirm": "確認",
+ "Cancel": "取消",
+ "Shop Name": "店鋪名稱",
+ "Target Date": "需求日期",
+ "Back to List": "返回列表",
+ "Store ID": "樓層",
+ "Handler": "提料員",
+ "Pick Order": "提料單",
+ "items": "物品",
+ "Delivery Order": "送貨訂單",
+ "Edit Delivery Order Detail": "編輯送貨訂單詳情",
+ "DO Workbench Search": "DO Workbench 搜索",
+ "Item Code": "物品編號",
+ "Item Name": "物品名稱",
+ "Lot No": "批號",
+ "Location": "位置",
+ "Required Qty": "需求數量",
+ "Status": "狀態",
+ "Search date": "搜索日期",
+ "completed": "完成",
+ "Completed": "完成",
+ "View Details": "查看詳情",
+ "Loading Sequence": "裝載順序",
+ "Departure Time": "出發時間",
+ "Select Date": "選擇日期",
+ "Today": "今天",
+ "Shop": "店鋪",
+ "Pick Order Code": "提料單編號",
+ "All Pick Order Lots": "所有提料單批號",
+ "Stop QR Scan": "停止掃碼",
+ "Start QR Scan": "開始掃碼",
+ "Submitting...": "提交中...",
+ "Lot Required Pick Qty": "批號需求數量",
+ "Scan Result": "掃碼結果",
+ "No data available": "沒有資料",
+ "This lot is rejected, please scan another lot.": "此批次發現問題,請掃描另一個批號。",
+ "Issue": "問題",
+ "Edit": "編輯",
+ "Rows per page": "每頁行數",
+ "Floor": "樓層",
+ "pending": "待處理",
+ "Now": "現時",
+ "Auto-refresh every 5 minutes": "每5分鐘自動刷新",
+ "Last updated": "最後更新",
+ "Truck Information": "車線資訊",
+ "Actions": "操作"
+}
diff --git a/src/i18n/zh/equipment.json b/src/i18n/zh/equipment.json
new file mode 100644
index 0000000..f3953f6
--- /dev/null
+++ b/src/i18n/zh/equipment.json
@@ -0,0 +1,21 @@
+{
+ "Create Material": "新增物料",
+ "Equipment": "設備",
+ "Equipment Type": "設備類型",
+ "Update Equipment Maintenance and Repair": "更新設備的維護和保養",
+ "Create Equipment": "新增設備",
+ "Edit Equipment": "編輯設備",
+ "Create Equipment Type": "新增設備類型",
+ "Edit Equipment Type": "編輯設備類型",
+ "Equipment Information": "設備資訊",
+ "Equipment Name": "設備名稱",
+ "Equipment Code": "設備編號",
+ "Equipment Details": "設備詳情",
+ "Equipment Type Details": "設備類型詳情",
+ "Equipment not found": "找不到設備",
+ "Last Repair and Maintenance Date": "上次維護和保養日期",
+ "Latest Repair and Maintenance Date": "最新維護和保養日期",
+ "Repair and Maintenance": "維護和保養",
+ "Repair and Maintenance Remarks": "維護和保養備註",
+ "Repair and Maintenance Status": "維護和保養狀態"
+}
diff --git a/src/i18n/zh/finishedGood.json b/src/i18n/zh/finishedGood.json
new file mode 100644
index 0000000..4fbd183
--- /dev/null
+++ b/src/i18n/zh/finishedGood.json
@@ -0,0 +1,4 @@
+{
+ "Finished Good Order": "成品出倉",
+ "Finished Good Detail": "成品出倉詳情"
+}
diff --git a/src/i18n/zh/finishedgoodmanagement.json b/src/i18n/zh/finishedgoodmanagement.json
new file mode 100644
index 0000000..76c02d6
--- /dev/null
+++ b/src/i18n/zh/finishedgoodmanagement.json
@@ -0,0 +1,38 @@
+{
+ "Finished Good Management": "成品出倉管理",
+ "提料順序": "提料順序",
+ "Item Code": "物品編號",
+ "Item Name": "物品名稱",
+ "Search & Jump": "搜索並跳轉",
+ "Jump": "跳轉",
+ "Move Up": "上移",
+ "Move Down": "下移",
+ "Move Top": "置頂",
+ "Move Bottom": "置底",
+ "Add Item": "新增物品",
+ "Saving": "儲存中",
+ "Save": "儲存",
+ "Refresh": "重新載入",
+ "Unsaved changes": "有未儲存的變更",
+ "Order": "順序",
+ "Code": "編號",
+ "Name": "名稱",
+ "Shipping Warehouse": "出貨倉位",
+ "Receiving Warehouse": "入貨倉位",
+ "Actions": "操作",
+ "Loading": "載入中...",
+ "No data available": "沒有資料",
+ "Insert": "插入",
+ "Search": "搜索",
+ "Insert at": "插入位置",
+ "Insert position must be >= 1": "插入位置必須大於或等於 1",
+ "Order number": "順序號碼",
+ "In front of": "前面",
+ "Behind": "後面",
+ "Only show FG items without order": "請先輸入關鍵字再搜索(只會查詢未設定順序的品項)",
+ "Cancel": "取消",
+ "Confirm": "確認",
+ "Move to order": "移動到指定順序",
+ "Target order": "目標順序",
+ "This will move the item to exact order": "確認後會把此品項移到指定順序位置,並自動重排其餘順序"
+}
diff --git a/src/i18n/zh/home.json b/src/i18n/zh/home.json
index 8f319b9..23b8b1b 100644
--- a/src/i18n/zh/home.json
+++ b/src/i18n/zh/home.json
@@ -1,5 +1,4 @@
{
- "Demand Qty": "需求數量",
- "Add some entries!": "添請添加條目"
-
-}
\ No newline at end of file
+ "Demand Qty": "需求數量",
+ "Add some entries!": "請添加條目"
+}
diff --git a/src/i18n/zh/importBom.json b/src/i18n/zh/importBom.json
new file mode 100644
index 0000000..6160967
--- /dev/null
+++ b/src/i18n/zh/importBom.json
@@ -0,0 +1,12 @@
+{
+ "Create Material": "新增材料",
+ "Update Equipment Maintenance and Repair": "更新設備的維護和保養",
+ "Correct BOM List (Can Import)": "正確 BOM 列表(可匯入)",
+ "Issue BOM List": "問題 BOM 列表",
+ "Loading BOM Detail...": "正在載入 BOM 明細…",
+ "Bom Material": "材料清單",
+ "Is Drink": "飲料",
+ "Drink": "飲料",
+ "Powder_Mixture": "箱料粉",
+ "Base Score": "基礎得分"
+}
diff --git a/src/i18n/zh/importExcel.json b/src/i18n/zh/importExcel.json
new file mode 100644
index 0000000..c6a0784
--- /dev/null
+++ b/src/i18n/zh/importExcel.json
@@ -0,0 +1,15 @@
+{
+ "title": "Excel 匯入",
+ "Download Template": "下載範本",
+ "Download failed": "下載失敗",
+ "Downloading...": "正在下載...",
+ "File Name": "檔案名稱",
+ "No Import Record": "沒有導入記錄",
+ "Upload": "上傳",
+ "Upload completed with count": "已更新 {{count}} 個項目。",
+ "Upload failed": "上傳失敗",
+ "Upload row errors": "以下行有問題:",
+ "Upload successful": "上傳成功",
+ "Uploading...": "正在上傳...",
+ "item(s) updated": "個項目已更新。"
+}
diff --git a/src/i18n/zh/inventory.json b/src/i18n/zh/inventory.json
index a3118bf..f418c6a 100644
--- a/src/i18n/zh/inventory.json
+++ b/src/i18n/zh/inventory.json
@@ -3,25 +3,19 @@
"Code": "編號",
"Name": "名稱",
"Type": "類型",
- "Status": "來貨狀態",
+ "Lot No": "批號",
+ "Expiry Date": "到期日",
+ "Warehouse": "倉庫",
+ "材料": "材料",
+ "consumable": "消耗品",
"Qty": "盤點數量",
- "UoM": "單位",
- "Approver Pending": "審核待處理",
- "Approver Approved": "審核通過",
- "Approver Time": "審核時間",
"Total need stock take": "總需盤點數量",
"Waiting for Approver": "待審核數量",
"Total Approved": "已審核數量",
"mat": "原料",
"variance": "差異",
- "Plan Start Date": "計劃開始日期",
- "Total Items": "總貨品數量",
- "Total Lots": "總批號數量",
- "Stock Take Round": "盤點輪次",
"ApproverAll": "審核員",
- "Stock Take Section (can use , to search multiple sections)": "盤點區域(可使用逗號搜索多個區域)",
"Approver All": "審核員全部盤點",
- "Variance %": "差異百分比",
"fg": "成品",
"FG": "成品",
"sfg": "半成品",
@@ -39,207 +33,71 @@
"WIP": "半成品",
"cmb": "消耗品",
"nm": "雜項及非消耗品",
- "Back to List": "返回列表",
- "Start Stock Take Date": "盤點日期",
- "Record Status": "記錄狀態",
- "Stock take record status updated to not match": "盤點記錄狀態更新為要求重點",
"available": "可用",
"unavailable": "不可用",
- "Issue Qty": "問題數量",
"tke": "盤點",
"Total Stock Takes": "總盤點數量",
"Submit completed: {{success}} success, {{errors}} errors": "提交完成:{{success}} 成功,{{errors}} 失敗",
- "No valid input to submit": "請先填寫盤點數量",
"Body is unavailable": "輸入不可用",
- "Submit All Inputted": "提交所有輸入",
- "Submit Bad Item": "提交不良品",
- "Remain available Quantity": "剩餘可用數量",
- "Submitting...": "提交中...",
- "Item-lotNo-ExpiryDate": "貨品-批號-到期日",
- "Submit Miss Item": "提交缺貨",
- "Confirm": "確認",
"Confirm create stock take for all sections?": "確認為所有區域創建盤點?",
- "Item-lotNo-ExpiryDate": "貨品-批號-到期日",
"not available": "不可用",
- "Book Qty": "帳面庫存",
- "Submit Quantity": "實際問題數量",
"Batch Submit All": "批量提交所有",
- "Batch Save All": "批量保存所有",
- "Batch Submit All": "批量提交所有",
- "Batch Save All": "批量保存所有",
"not match": "要求重點",
- "Not Match": "要求重點",
- "Pass": "已盤點",
- "Area": "倉位",
-
- "Selected Qty": "選擇數量",
- "Inventory Difference": "庫存差異",
"Show Search Filters": "顯示搜索器",
"Hide Search Filters": "隱藏搜索器",
- "Stock Take Qty(include Bad Qty)= Available Qty": "盤點數= 可用數",
- "Stock Take Qty Data and Variance Analysis": "盤點數數據與差異分析",
- "View ReStockTake": "查看重新盤點",
- "Stock Take Qty": "盤點數",
- "variance Percentage": "差異百分比",
"-{{Variance}}≤Variance Percentage ≤{{Variance}} will be filtered out": "-{{Variance}}%≤差異百分比≤{{Variance}}%將被過濾掉",
- "Variance filter inclusive only": "反選",
"Variance filter strict bounds": "不使用=",
- "Variance filter exclusive range hint": "只顯示 -{{value}}% {{op}} 差異% {{op}} {{value}}% 的列(範圍外)",
- "Variance filter inclusive range hint": "只顯示 -{{value}}% {{op}} 差異% {{op}} {{value}}% 的列(範圍內)",
- "Stock Take Qty": "盤點數",
- "Total": "總數",
- "Shown": "顯示",
"Filtered out": "過濾掉",
- "ReStockTake": "重新盤點",
- "Stock Taker": "盤點員",
"Total Item Number": "貨品數量",
- "Total Item Kind Number": "貨品種類數量",
"Please enter QTY and Bad QTY": "請輸入盤點數量和不良數量",
- "Available QTY cannot be negative": "可用數量不能為負數",
"Invalid QTY": "無效的數量",
"Stock take qty exceeds maximum": "盤點數量不可超過 999,999,999,999",
"Start Time": "開始時間",
- "Difference": "差異",
"stockTaking": "盤點中",
- "Pick Order Code": "提料單編號",
- "DO Order Code": "送貨單編號",
- "JO Order Code": "工單編號",
- "Picker Name": "提料員",
- "Rows per page": "每頁行數",
-
"rejected": "已拒絕",
"miss": "缺貨",
"bad": "不良",
"expiry": "過期",
- "open":"開倉",
+ "open": "開倉",
"Bom Req. Qty": "需求數(BOM單位)",
- "selected stock take qty": "已選擇盤點數量",
- "book qty": "帳面庫存",
- "start time": "開始時間",
- "end time": "結束時間",
- "Control Time": "操作時間",
- "Stock Taker": "盤點員",
- "Total Item Number": "貨品數量",
- "Start Time": "開始時間",
- "Difference": "差異",
- "stockTaking": "盤點中",
- "selected stock take qty": "已選擇盤點數量",
- "book qty": "帳面庫存",
- "start time": "開始時間",
- "end time": "結束時間",
"notmatch": "要求重點",
- "Only Variance": "僅差異",
- "Control Time": "操作時間",
- "Batch approver save completed: {{success}} success, {{errors}} errors": "批次審核儲存完成:成功 {{success}} 筆,錯誤 {{errors}} 筆",
"pass": "已盤點",
"not pass": "不通過",
"Available": "可用",
"approving": "審核中",
"pending": "待處理",
- "Last Stock Take Date": "上次盤點日期",
- "Remark": "備註",
"notMatch": "要求重點",
- "notMatch": "要求重點",
- "Stock take record saved successfully": "盤點記錄保存成功",
- "View Details": "查看詳細",
"Input": "輸入",
"Something went wrong fetching data in server.": "在伺服器上取得資料時發生錯誤。",
- "First": "第一次",
- "Save": "保存",
- "Second": "第二次",
- "Section": "區域",
- "No data": "沒有數據",
"save": "保存",
"AVAILABLE": "可用",
"View": "查看",
- "Total Sections": "總區域數量",
"approver": "審核員",
- "Approver": "審核員",
"Create Stock Take for All Sections": "為所有區域創建盤點",
- "Create Stock Take (Select Sections)": "建立盤點(選擇區域)",
"Select stock take sections to create hint": "請選擇要建立新盤點輪次的盤點區域(同一批次將共用同一輪次編號)。",
- "Stock take round name": "盤點輪次名稱",
- "Stock take round name placeholder": "選填,例如:五月全廠盤點",
"Select sections placeholder": "可多選",
"Select all sections": "全選區域",
"Clear selection": "清除選取",
"Selected section count": "已選擇 {{count}} 個區域",
- "Floor unassigned": "未設定樓層",
- "No stock take sections from warehouse": "目前沒有盤點區域資料",
"Expand floor sections": "展開此樓層區域",
"Collapse floor sections": "收合此樓層區域",
- "Select all on this floor": "全選此樓層 ({{floor}})",
- "Deselect all on this floor": "取消全選此樓層 ({{floor}})",
- "Creation date": "建立日期",
- "Floor area selection header": "{{floor}} 區域選擇 ({{count}} 區域)",
- "Search section code or name": "搜索代碼或名稱 (例如 ST-042 或 飲品)",
- "Select all sections all floors": "全選區域 (所有樓層)",
- "Clear selection all floors": "清除已選 (所有樓層)",
- "Total selected sections label": "總計已選擇 :",
- "sections unit": "個區域",
- "No sections match search": "沒有符合搜索條件的區域",
"section": "區域",
- "Stock Take Section": "盤點區域",
- "Store ID":"樓層",
- "Warehouse Location": "倉庫位置",
- "UOM": "單位",
"First Qty": "第一次盤點數量",
"Second Qty": "第二次盤點數量",
- "Bad Qty": "不良數量",
"Remarks": "備註",
"Available Qty": "可用數量",
"Sales UoM": "銷售單位",
"Stock UoM": "庫存單位",
"Available Qty Per Smallest Unit": "可用數量 (基本單位)",
"Base UoM": "基本單位",
- "Lot No": "批號",
- "Expiry Date": "到期日",
"No items are selected yet.": "未選擇貨品",
"Item selected": "已選擇貨品",
- "Warehouse": "倉庫",
- "Adjusted By": "處理者",
- "Adjustment": "處理",
- "Adjustment No": "處理編號",
- "Adjustment No, Item, Lot...": "處理編號, 貨品, 批號...",
- "After Qty": "處理後數量",
- "All": "全部",
- "Approved": "已批准",
- "Before Qty": "處理前數量",
- "Damage": "損壞",
- "Date": "日期",
- "Item": "貨品",
- "Location": "位置",
- "Manual": "手動",
- "No adjustments found": "未找到調整",
- "Pending": "待處理",
- "Reason": "原因",
- "Rejected": "已拒絕",
- "Return": "退貨",
- "Search": "搜索",
- "Stock Take": "盤點",
- "This is a demo with fake data. API integration pending.": "",
- "Total Adjustments": "總調整數量",
- "Action": "操作",
- "Actual Qty": "實際數量",
- "Category": "類型",
- "Close": "關閉",
"Delivery Order": "交貨單",
- "Detail": "詳細",
- "Handle Remark": "處理備註",
- "Issue Detail": "問題詳細",
- "Issue No": "問題編號",
- "Issue Remark": "問題備註",
"Job Order": "工單",
- "Mark as Resolved": "標記為已解決",
"Material": "物料",
- "Miss Qty": "缺貨數量",
"UNAVAILABLE": "不可用",
"No issues found": "未找到問題",
- "Approver stock take record saved successfully": "審核員盤點記錄保存成功",
- "Approver input empty; save skipped, row remains pending": "審核員盤點數與不良數皆未輸入,已略過儲存,該列維持待審核",
- "No rows loaded; set search criteria and search first": "尚未載入資料,請設定搜索條件並按搜索",
"Batch approver save completed: {{success}} success, {{skipped}} skipped, {{errors}} errors": "批次審核儲存完成:成功 {{success}} 筆,略過 {{skipped}} 筆,錯誤 {{errors}} 筆",
- "Approver Input": "審核員輸入",
"Approve": "審核",
"complete": "完成",
"completed": "已完成",
@@ -247,23 +105,14 @@
"completed date": "完成日期",
"completed remarks": "完成備註",
"completed status": "完成狀態",
-
- "Pick Order": "提貨單",
"Pick Order, Issue No, Item, Lot...": "揀貨單, 問題編號, 貨品, 批號...",
- "Picker": "盤點員",
"Refresh": "刷新",
- "Required Qty": "所需數量",
"Resolved": "已解決",
"Total Issues": "總問題數量",
- "Inventory Adjustments": "存貨調整",
"Inventory Exception Management": "存貨異常管理",
- "Stock Take Management": "盤點管理",
- "Pick Execution Issues": "揀貨執行問題",
"Back": "返回",
- "Cancel": "取消",
"Confirm Adjustment": "確認調整",
"Counted Qty": "盤點數量",
- "Item Code": "貨品編號",
"Item Name": "貨品名稱",
"Perform Stock Take": "執行盤點",
"Review Variance": "審核差異",
@@ -275,16 +124,6 @@
"Stock take adjustment confirmed! (Demo only)": "盤點調整確認!(僅演示)",
"Stock take adjustment has been confirmed successfully!": "盤點調整確認成功!",
"System Qty": "系統數量",
- "Variance": "差異",
- "Processing...": "處理中...",
- "Disposing...": "處理中...",
- "Batch Disposed All": "批量處理完成",
- "Looked": "已查看",
- "Disposed": "已處置",
- "Miss Item": "缺貨",
- "Bad Item": "不良",
- "Expiry Item": "過期",
- "Batch save completed: {{success}} success, {{errors}} errors": "批量保存完成:{{success}} 成功,{{errors}} 失敗",
"Batch Save Inputted": "批量保存已輸入",
"Batch Save Completed": "批量保存完成",
"Bad Item Handle": "不良品處理",
@@ -302,16 +141,6 @@
"Expiry Item Qty": "過期品數量",
"Handler": "處理人",
"Quantity exceeds available quantity": "數量超過可用數量",
- "Please enter a valid quantity": "請輸入有效數量",
- "Failed to submit": "提交失敗",
- "Unknown error": "未知錯誤",
- "Search Criteria": "搜索條件",
- "Reset": "重置",
- "Defective Qty": "不良數量",
- "Remaining Qty": "剩餘數量",
- "Lot No.": "批號",
- "User ID is required": "需要用戶ID",
-
"Stock Record": "庫存記錄",
"Item-lotNo": "貨品-批號",
"In Qty": "入庫數量",
@@ -320,13 +149,10 @@
"Balance Qty": "庫存數量",
"Start Date": "開始日期",
"End Date": "結束日期",
- "Loading": "加載中",
- "adj": "調整",
- "nor": "正常",
+ "Loading": "加載中",
+ "adj": "調整",
+ "nor": "正常",
"trf": "轉倉",
-
-
-
"Stock transfer successful": "轉倉成功",
"Stock transfer merged ambiguous": "已併入較早建立的批次(同批號有多筆可用)",
"Stock transfer merged existing lot": "轉倉成功(已併入既有批號)",
@@ -341,18 +167,16 @@
"Target Location": "目標倉位",
"Original Qty": "原有數量",
"Qty To Be Transferred": "待轉數量",
+ "Remaining Qty": "剩餘數量",
"Submit": "確認",
-
"Printer": "列印機",
"Print Qty": "列印數量",
"Print": "列印",
"Print sent": "已送出列印",
"Print failed": "列印失敗",
-
"Stock Adjustment": "庫存調整",
"Edit mode": "編輯模式",
"Add entry": "新增倉存",
-
"productLotNo": "產品批號",
"dnNo": "送貨單編號",
"Optional - system will generate": "選填,系統將自動生成",
@@ -363,6 +187,8 @@
"Reason for removal": "移除原因",
"Confirm remove": "確認移除",
"Adjusted Qty": "調整後倉存",
+ "Difference": "差異",
+ "Action": "操作",
"Saved successfully": "儲存成功",
"Save failed": "儲存失敗",
"Remove": "移除",
@@ -376,18 +202,5 @@
"Stop QR Scan": "停止掃碼",
"No Data": "沒有數據",
"Please set at least one search criterion": "請至少設定一項搜索條件",
- "Approver search empty hint": "請設定搜索條件後點擊搜索",
- "Confirm batch save approver": "確認批次儲存審核",
- "Batch save confirm message": "將對目前列表中的 {{count}} 筆盤點記錄執行批次儲存,是否繼續?",
- "Stock take sections in current list": "目前列表涉及 {{count}} 個盤點區域",
- "Confirm create stock take": "確認建立盤點",
- "Not filled": "(未填寫)",
- "Warehouse missing stock take section warn title": "未設定盤點區域的倉庫",
- "Warehouse missing stock take section tooltip has": "有 {{count}} 個倉庫未設定盤點區域,點擊查看",
- "Warehouse missing stock take section tooltip none": "所有倉庫均已設定盤點區域",
- "Warehouse missing stock take section drawer hint": "以下倉庫位置尚未設定盤點區域(ST-xxx),無法納入盤點區域選擇。請至倉庫設定補上。",
- "Warehouse missing stock take section go settings": "前往倉庫設定",
- "Warehouse missing stock take section showing": "顯示前 {{shown}} 筆,共 {{count}} 筆",
- "Warehouse missing stock take section empty": "沒有未設定盤點區域的倉庫"
-
+ "Approver search empty hint": "請設定搜索條件後點擊搜索"
}
diff --git a/src/i18n/zh/itemPrice.json b/src/i18n/zh/itemPrice.json
new file mode 100644
index 0000000..f1ec378
--- /dev/null
+++ b/src/i18n/zh/itemPrice.json
@@ -0,0 +1,30 @@
+{
+ "Price Inquiry": "價格查詢",
+ "No Purchase Order After 2026-01-01": "在2026-01-01後沒有採購記錄",
+ "Code": "編號",
+ "Name": "名稱",
+ "Searching": "搜索中",
+ "No item selected": "未選擇貨品",
+ "Average unit price": "平均單位價格",
+ "Latest market unit price": "最新市場價格",
+ "No Import Record": "沒有導入記錄",
+ "Download Template": "下載範本",
+ "Downloading...": "正在下載...",
+ "Upload": "上傳",
+ "Uploading...": "正在上傳...",
+ "Download failed": "下載失敗",
+ "Upload failed": "上傳失敗",
+ "Upload successful": "上傳成功",
+ "item(s) updated": "個項目已更新。",
+ "Upload row errors": "以下行有問題:",
+ "FG": "成品",
+ "RM": "原料",
+ "SFG": "半成品",
+ "WIP": "半成品",
+ "CMB": "消耗品",
+ "NM": "雜項及非消耗品",
+ "MA": "材料",
+ "MI": "雜項",
+ "CO": "消耗品",
+ "MAT": "材料"
+}
diff --git a/src/i18n/zh/items.json b/src/i18n/zh/items.json
index 6bfdc96..057301c 100644
--- a/src/i18n/zh/items.json
+++ b/src/i18n/zh/items.json
@@ -1,58 +1,70 @@
-{"Demand Forecast Period": "需求預測期",
-"Scheduled At": "預定時間",
-"Product Count(s)": "產品數量",
-"Product Count": "產品數量",
-"Schedule Period": "排程期間",
-"Product": "產品",
-"Details": "詳情",
-"Product Details": "產品詳情",
-"Edit Product / Material": "編輯產品 / 材料",
-"Product / Material": "產品 / 材料",
-"Product / Material Details": "產品 / 材料詳情",
-
-"Qc items": "QC 項目",
-"Qc Category": "質檢模板",
-"Name": "名稱",
-"name": "名稱",
-"description": "描述",
-"Type": "類型",
-"shelfLife": "保質期",
-"remarks": "備註",
-"countryOfOrigin": "原產地",
-"maxQty": "最大數量",
-"Code": "編號",
-"code": "編號",
-"instruction": "說明",
-"lowerLimit": "下限",
-"upperLimit": "上限",
-"no rows": "沒有資料",
-"Save": "儲存",
-"Confirm": "確認",
-"Cancel": "取消",
-"Finished Goods Name": "成品名稱",
-"Reset": "重置",
-"Search": "搜索",
-"Release": "發佈",
-"Actions": "操作",
-"LocationCode": "預設位置",
-"DefaultLocationCode": "預設位置",
-"Special Type": "特殊類型",
-"None": "正常",
-"isEgg": "雞蛋",
-"isFee": "費用",
-"isBag": "袋子",
-"Back": "返回",
-"Status": "狀態",
-"Complete": "完成",
-"Missing Data": "缺少資料",
-"Loading QC items...": "正在加載質檢項目...",
-"Select a QC template to view items": "選擇質檢模板以查看項目",
-"No QC items in this template": "此模板無質檢項目",
-"QC Checklist": "質檢項目",
-"QC Type": "質檢種類",
-"IPQC": "IPQC",
-"EPQC": "EPQC"
-,
- "Item": "貨品",
- "Code or name": "編號或名稱"
-}
\ No newline at end of file
+{
+ "Demand Forecast Period": "需求預測期",
+ "Scheduled At": "預定時間",
+ "Product Count(s)": "產品數量",
+ "Product Count": "產品數量",
+ "Schedule Period": "排程期間",
+ "Product": "產品",
+ "Details": "詳情",
+ "Product Details": "產品詳情",
+ "Edit Product / Material": "編輯物品",
+ "Product / Material": "物品",
+ "Product / Material Details": "物品詳情",
+ "Qc items": "QC 項目",
+ "Qc Category": "質檢模板",
+ "Name": "名稱",
+ "name": "名稱",
+ "description": "描述",
+ "Type": "類型",
+ "shelfLife": "保質期",
+ "remarks": "備註",
+ "countryOfOrigin": "原產地",
+ "maxQty": "最大數量",
+ "Code": "編號",
+ "code": "編號",
+ "instruction": "說明",
+ "lowerLimit": "下限",
+ "upperLimit": "上限",
+ "no rows": "沒有資料",
+ "Save": "儲存",
+ "Confirm": "確認",
+ "Cancel": "取消",
+ "Finished Goods Name": "成品名稱",
+ "Reset": "重置",
+ "Search": "搜索",
+ "Release": "發佈",
+ "Actions": "操作",
+ "LocationCode": "預設位置",
+ "DefaultLocationCode": "預設位置",
+ "Special Type": "特殊類型",
+ "None": "正常",
+ "isEgg": "雞蛋",
+ "isFee": "費用",
+ "isBag": "袋子",
+ "fg": "成品",
+ "wip": "半成品",
+ "mat": "材料",
+ "cmb": "合併",
+ "nm": "非物料",
+ "Back": "返回",
+ "Status": "狀態",
+ "Complete": "完成",
+ "Missing Data": "缺少資料",
+ "Loading QC items...": "正在加載質檢項目...",
+ "Select a QC template to view items": "選擇質檢模板以查看項目",
+ "No QC items in this template": "此模板無質檢項目",
+ "QC Checklist": "質檢項目",
+ "QC Type": "質檢種類",
+ "IPQC": "IPQC",
+ "EPQC": "EPQC",
+ "Item": "貨品",
+ "Code or name": "編號或名稱",
+ "Product": "物品",
+ "Item Code": "物品編號",
+ "Item Name": "物品名稱",
+ "Sales Qty": "銷售數量",
+ "Sales UOM": "銷售單位",
+ "Stock Qty": "庫存數量",
+ "Uom": "單位",
+ "Cost (HKD)": "費用 (HKD)"
+}
diff --git a/src/i18n/zh/jo.json b/src/i18n/zh/jo.json
index 708666a..4a2e6e0 100644
--- a/src/i18n/zh/jo.json
+++ b/src/i18n/zh/jo.json
@@ -1,682 +1,645 @@
{
- "Job Order": "工單",
- "Please select": "請選擇",
- "Edit Job Order Detail": "工單詳情",
- "Details": "細節",
+ "2/F plastic box carton Qty": "2/F 膠茜數目",
+ "2/F plastic box carton qty count": "2/F 膠茜數目",
+ "3/F plastic box carton Qty": "3/F 膠茜數目",
+ "3/F plastic box carton qty count": "3/F 膠茜數目",
+ "4/F plastic box carton Qty": "4/F 膠茜數目",
+ "4/F plastic box carton qty count": "4/F 膠茜數目",
+ "Action": "操作",
"Actions": "操作",
- "Drink": "飲料",
- "Process": "工序",
- "Create Job Order": "建立工單",
- "Code": "工單編號",
- "storing": "待品檢入倉",
- "Name": "成品/半成品名稱",
- "Picked Qty": "已提料數量",
- "Insufficient available quantity on lot (may have been picked by another user)": "掃描的批次已被其他用戶完全提料。請掃描其他批次。",
- "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "請檢查周圍是否有QR碼,可能是剛剛入庫或轉移入庫或轉移出庫。",
- "is expired. Please check around have available QR code or not.": "已過期。請檢查周圍是否有可用的 QR 碼。",
- "Confirm All": "確認所有提料",
- "Wait Time [minutes]": "等待時間(分鐘)",
- "Job Process Status Dashboard": "儀表板 - 工單狀態",
- "Time used": "耗時",
- "In progress": "進行中",
- "Previous page": "上一頁",
- "Next page": "下一頁",
- "Process page summary": "工序 {{from}}–{{to}} / 共 {{total}} 道",
- "Duration hours": "{{count}} 小時",
- "Duration minutes": "{{count}} 分鐘",
- "Duration seconds": "{{count}} 秒",
- "Job process detail: time": "時間",
- "Job process detail: process name": "工序",
- "Job process detail: equipment": "設備",
- "Job process detail: handler": "員工",
- "Job process detail mode label": "工序格顯示",
- "Product process status": "生產流程狀態",
- "stopped": "暫停",
- "cancelled": "已取消",
- "Job dashboard PP status: pending": "工序待處理",
- "Job dashboard PP status: in_progress": "工序進行中",
- "Job dashboard PP status: stopped": "工序暫停",
- "Job dashboard PP status: completed": "工序完成",
- "Job dashboard PP status: cancelled": "工序已取消",
- "This lot is rejected, please scan another lot.": "此批次已拒收,請掃描另一個批次。",
- "Edit": "改數",
- "Code / Lot No": "工單編號/批號",
- "Just Complete": "已完成",
- "Stock Req. Qty": "需求數",
- "Bad Package Qty": "不良包裝數量",
- "Progress": "進度",
- "Search Job Order/ Create Job Order":"搜索工單/建立工單",
- "UoM": "銷售單位",
- "Select Another Bag Lot":"選擇另一個包裝袋",
- "No": "沒有",
- "Powder Mixture": "箱料粉",
- "Powder_Mixture": "箱料粉",
- "Qty will submit": "提交數量",
- "Packaging":"提料中",
- "Overall Time Remaining": "總剩餘時間",
- "User not found with staffNo:": "用戶不存在",
- "Time Remaining": "剩餘時間",
- "Base UOM": "基本單位",
- "Stock UOM": "庫存單位",
- "Over Time": "超時",
- "Staff No:": "員工編號:",
- "Timer Paused": "計時器已暫停",
- "Staff No Required": "員工編號必填",
- "Changeover Time (mins)": "生產後轉換時間(分鐘)",
- "Update Time Information": "更新時間信息",
- "Staff No": "員工編號",
- "Status": "工單狀態",
- "Lot No.": "批號",
- "Pass": "通過",
- "Delete Job Order": "刪除工單",
- "Cancel Job Order": "取消工單",
- "Confirm delete job order": "確認刪除工單",
- "Delete job order confirm message": "確定要刪除此工單嗎?此操作無法復原。",
- "Confirm cancel job order": "確認取消工單",
- "Cancel job order confirm message": "確定要取消此工單嗎?工單將從列表中隱藏。",
- "Bom": "半成品/成品編號",
- "Release": "放單",
- "Pending": "待掃碼",
- "Put Awayed": "已上架",
- "cancel": "已取消",
- "Pending for pick": "待提料",
- "Planning": "計劃中",
- "Processing": "已開始工序",
- "Storing": "成品入倉中",
- "Multiplier": "倍數",
- "Assume End Time": "預計完成時間",
- "Base Qty": "標準生產數",
- "Batch Count": "批數",
- "Production Priority required!": "生產優先度必填!",
- "Update Estimated Production Date": "更新預計生產日期",
- "Create": "建立",
- "Passed Step": "通過步驟",
- "view putaway": "查看上架詳情",
- "process epqc": "進行成品檢驗",
- "Consumed Qty": "消耗數量",
- "Scrap Qty": "損耗數量",
+ "Actual Pick Qty": "實際提料數量",
"Add Bag": "新增包裝袋",
- "Balance": "可用數量",
- "Submit Bag Consumption": "提交包裝袋消耗",
- "Bag Consumption": "包裝袋消耗",
- "Bag": "包裝袋",
- "Select Bag": "選擇包裝袋",
- "scan picked material": "掃碼確認提料",
- "escalation processing": "處理上報記錄",
- "process stockIn": "進行收貨程序",
- "Update Production Priority": "更新生產優先度",
- "minutes": "分鐘",
- "Start Time": "開始時間",
- "release jo": "工單詳情",
- "complete jo": "完成工單",
- "update success": "成功更新資料",
- "Scanned": "已掃碼",
- "Scan Status": "掃碼狀態",
- "Start Job Order": "開始工單",
- "Unable to get user ID": "無法獲取用戶ID",
- "Assignment successful": "分配成功",
- "Target Production Date": "預計生產日期",
- "Production Priority": "生產優先度",
+ "Add Record": "添加記錄",
+ "Add Selected Items to Created Items": "將已選擇的物品添加到創建的物品中",
+ "Add some entries!": "請添加條目",
+ "All": "全部",
+ "All Pick Order Lots": "所有提料單批號",
+ "All floors": "全部樓層",
+ "All pick orders created successfully": "所有提料單建立成功",
+ "Are you sure you want to delete this procoess?": "您確定要刪除此工序嗎?",
"Assignment failed: ": "分配失敗: ",
- "Unknown error": "未知錯誤",
- "Unknown error: ": "未知錯誤: ",
- "Start Qty": "開始數量",
- "End Qty": "結束數量",
- "Balance Qty": "剩餘數量",
- "Bag Lot Lines": "包裝袋批號明細",
+ "Assignment successful": "分配成功",
+ "Assume End Time": "預計完成時間",
+ "At least one issue must be reported": "至少有一個問題必須報告",
+ "Auto-refresh every 1 minute": "每1分鐘自動刷新",
+ "Auto-refresh every 10 minutes": "每10分鐘自動刷新",
+ "Auto-refresh every 15 minutes": "每15分鐘自動刷新",
+ "Auto-refresh every 5 minutes": "每5分鐘自動刷新",
+ "Available Qty": "可用數量",
+ "Available in warehouse": "在倉庫中可用",
+ "BOM Description": "BOM 說明",
+ "BOM Status": "BOM 預備狀況",
+ "BOM Type": "BOM 類型",
+ "Back": "返回",
+ "Back to List": "返回列表",
+ "Bad Item Qty": "不良物品數量",
+ "Bad Package Qty": "不良包裝數量",
+ "Bag": "包裝袋",
+ "Bag Code": "包裝袋編號",
+ "Bag Consumption": "包裝袋消耗",
"Bag Consumption Records": "包裝袋消耗記錄",
"Bag List": "包裝袋列表",
- "Time": "時間",
+ "Bag Lot Lines": "包裝袋批號明細",
"Bag Name": "包裝袋名稱",
- "Bag Code": "包裝袋編號",
-
- "Sequence": "序",
- "Seq": "步驟",
- "SEQ": "步驟",
- "Today": "今天",
- "Yesterday": "昨天",
- "Two Days Ago": "前天",
- "Item Code": "物料編號",
- "Floor": "樓層",
- "Paused": "已暫停",
- "paused": "已暫停",
- "Total pick orders": "總提料單數量",
- "Pause Reason": "暫停原因",
"Bag Usage": "包裝袋使用記錄",
- "Reason": "原因",
-
- "update production priority": "更新生產優先序",
- "Staff No": "員工編號",
- "Please scan staff no": "請掃描員工編號",
- "Stock Status": "可提料",
- "Total lines: ": "所需貨品項目數量: ",
- "Lines with sufficient stock: ": "可提料項目數量: ",
- "Lines with insufficient stock: ": "未能提料項目數量: ",
- "Item Name": "材料名稱",
- "Material Code": "材料編號",
- "Select Unit": "選擇單位",
- "Job Order Pickexcution": "工單提料",
- "Pick Order Detail": "提料單細節",
- "Finished Job Order Record": "已完成工單記錄",
- "No. of Items to be Picked": "需提料數量",
- "No. of Items with Issue During Pick": "問題數量",
- "Pick Start Time": "提料開始時間",
- "Pick End Time": "提料結束時間",
- "FG / WIP Item": "成品/半成品",
- "Pick Order No.- Job Order No.- Item": "提料單編號-工單編號-成品/半成品",
- "Pick Time Taken (minutes)": "提料時間(分鐘)",
- "Index": "編號",
- "Route": "路線",
- "Qty": "數量",
- "Unit": "單位",
- "Issue": "問題",
- "Location": "位置",
- "Scan Result": "掃碼結果",
- "Just Completed (workbench): requires valid quantity; expired rows must not use this button.": "工單對料:需要有效數量;過期項目不能使用此按鈕。",
- "This is last lot, so no available lot.": "這是最後一個批次,所以沒有可用批次。",
- "Expiry Date": "有效期",
- "Target Date": "需求日期",
- "Lot Required Pick Qty": "批號需求數",
- "Available Qty": "可用數量",
-
- "Job Order Match": "工單對料",
- "Lot No": "批號",
- "Submit Required Pick Qty": "提交需求數",
- "All Pick Order Lots": "所有提料單批號",
- "Row per page": "每頁行數",
- "No data available": "沒有資料",
- "jodetail": "工單細節",
- "Start QR Scan": "開始QR掃碼",
- "Stop QR Scan": "停止QR掃碼",
- "Rows per page": "每頁行數",
- "Job Order Item Name": "工單產品名稱",
- "Job Order Code": "工單編號",
- "View Details": "查看詳情",
- "Skip": "跳過",
- "packaging": "提料中",
- "Handler": "提料員",
- "RELEASED": "已放單",
- "Released": "已放單",
- "COMPLETED": "已完成",
- "Now": "現時",
- "Last updated": "最後更新",
- "Auto-refresh every 5 minutes": "每5分鐘自動刷新",
- "Auto-refresh every 10 minutes": "每10分鐘自動刷新",
- "Auto-refresh every 15 minutes": "每15分鐘自動刷新",
- "Auto-refresh every 1 minute": "每1分鐘自動刷新",
-
- "completed Job Order pick orders with Matching": "工單已完成提料和對料",
- "No completed Job Order pick orders with matching found": "沒有相關記錄",
- "completed Job Order pick orders with matching": "工單已完成提料和對料",
- "Total": "總數",
- "Back to List": "返回列表",
- "second Scan Status": "對料狀態",
- "Actual Pick Qty": "實際提料數量",
- "Processing Status": "處理狀態",
- "Lot Availability": "批號可用性",
- "Pick Order Id": "提料單編號",
- "Pick Order Code": "提料單編號",
- "Select a printer": "選擇打印機",
- "Please select a printer": "請選擇打印機",
- "Next": "下一步",
- "Pick Order Conso Code": "提料單組合編號",
- "Enter the number of cartons": "請輸入箱數",
- "Pick Order Target Date": "提料單需求日期",
- "Pick Order Status": "提料單狀態",
- "Second Scan Status": "對料狀態",
- "Job Order Pick Order Details": "工單提料單詳情",
- "Scanning...": "掃碼中",
- "Unassigned Job Orders": "未分配工單",
- "Please scan the item qr code": "請掃描物料二維碼",
- "Please make sure the qty is enough": "物料數量不足",
- "Please make sure all required items are picked": "請確保所有物料已被提取",
- "Do you want to start job order": "是否開始工單",
- "Submit": "提交",
- "issue": "問題",
- "issue remark": "問題描述",
- "handler": "處理者",
- "qty is required": "數量是必需的",
- "qty is not allowed to be greater than remaining available qty": "數量不能大於剩餘可用數量",
- "qty is not allowed to be greater than required qty": "數量不能大於需求數量",
- "qty is not allowed to be greater than picked qty": "數量不能大於已提料數量",
- "QR code verified.": "QR碼驗證成功。",
- "QR code does not match any item in current orders.": "QR碼不匹配當前工單的物料。",
- "This form is for reporting issues only. You must report either missing items or bad items.": "此表單僅用於報告問題。您必須報告缺失的物料或不良的物料。",
- "Pick Execution Issue Form": "提料執行問題表單",
- "Verified Qty": "驗證數量",
- "Missing item Qty": "缺失的物料數量",
- "Bad Item Qty": "不良的物料數量",
- "submit": "提交",
- "Issue Remark": "問題描述",
- "Received Qty": "接收數量",
- "Confirm Lot Substitution": "確認批號替換",
- "Processing...": "處理中",
+ "Balance": "可用數量",
+ "Balance Qty": "剩餘數量",
+ "Base Qty": "標準生產數",
+ "Base UOM": "基本單位",
+ "Batch Count": "批數",
+ "BoM Material": "BOM 材料",
+ "Bom": "BOM",
+ "Bom Req. Qty": "BOM",
+ "Bom Uom": "BOM 單位",
+ "By-product": "副產品",
+ "COMPLETED": "已完成",
+ "Cancel": "取消",
+ "Cancel Job Order": "取消工單",
+ "Cancel job order confirm message": "確定要取消此工單嗎?工單將從列表中隱藏。",
+ "Changeover Time": "生產後轉換時間",
+ "Changeover Time (mins)": "生產後轉換時間(分鐘)",
+ "Changeover Time (mins)": "生產後轉換時間(分鐘)",
+ "Clean Record": "清空記錄",
+ "Code": "工單編號",
+ "Code / Lot No": "工單編號/批號",
"Complete Job Order Record": "已完成工單記錄",
-
- "Lot Details": "批號細節",
- "No lot details available": "沒有批號細節",
- "Second Scan Completed": "對料已完成",
- "Second Scan Pending": "對料待處理",
- "items completed": "物料已完成",
+ "Complete Step": "完成步驟",
+ "Completed": "完成",
+ "Completed Step": "完成步驟",
+ "Confirm": "確認",
+ "Confirm All": "確認所有提料",
+ "Confirm Lot Substitution": "確認批號替換",
+ "Confirm cancel job order": "確認取消工單",
+ "Confirm delete job order": "確認刪除工單",
+ "Consolidate": "整合",
+ "Consolidated Code": "整合編號",
+ "Consumable": "消耗品",
+ "Consumed Qty": "消耗數量",
+ "Continue": "繼續",
+ "Count of Job Orders": "工單數量",
+ "Create": "建立",
+ "Create Job Order": "建立工單",
+ "Create New Group": "創建新組",
+ "Create Pick Order": "創建提料單",
+ "Create Project": "新增專案",
+ "Create Task Template": "新增任務範本",
+ "Created Items": "創建物品",
"Current Stock": "當前庫存",
- "Lot Actual Pick Qty": "批號實際提料數量",
- "Qty Already Picked": "已提料數量",
- "Reject": "拒絕",
- "Stock Unit": "庫存單位",
- "Group": "組",
- "Input Equipment is not match with process": "輸入的設備與流程不匹配",
- "Item": "成品/半成品",
- "Select Date": "選擇日期",
- "No Group": "沒有組",
- "No created items": "沒有創建物料",
- "Order Quantity": "需求數",
- "Bom Req. Qty": "BOM",
- "Bom Uom": "使用單位",
- "Selected": "已選擇",
- "Are you sure you want to delete this procoess?": "您確定要刪除此工序嗎?",
- "Please select item": "請選擇物料",
- "acceptedQty must not greater than": "接受數量不能大於",
- "enter a qty": "請輸入數量",
- "minimal value is 1": "最小值為1",
- "qty": "數量",
- "select qc": "選擇QC",
- "targetDate": "需求日期",
- "type": "類型",
- "uom": "單位",
- "value must be a number": "值必須是數字",
- "update qc info": "更新QC資訊",
+ "Customer": "客戶",
+ "Date": "日期",
+ "Default Warehouse": "默認倉庫",
+ "Defect": "缺陷",
+ "Delete Job Order": "刪除工單",
+ "Delete job order confirm message": "確定要刪除此工單嗎?此操作無法復原。",
+ "Deliver Order": "送貨訂單",
"Delivery Code": "交貨編號",
"Delivery Date": "交貨日期",
+ "Delivery Note Code": "送貨單編號",
+ "Delivery Order": "送貨訂單",
+ "Demand Forecast": "需求預測",
+ "Demand Forecast Setting": "需求預測設定",
"Departure Time": "出發時間",
- "Shop Address": "商店地址",
- "Shop ID": "商店ID",
- "Shop Name": "商店名稱",
- "Shop PO Code": "商店PO編號",
- "Store ID": "商店ID",
- "Ticket No.": "票號",
- "Truck No.": "車線編號",
- "No Item": "沒有物料",
- "None": "沒有",
- "Add Selected Items to Created Items": "將已選擇的物料添加到創建的物料中",
- "All pick orders created successfully": "所有提料單建立成功",
- "Consumable": "消耗品",
- "Create New Group": "創建新組",
- "Create Pick Order": "創建提料單",
- "Created Items": "創建物料",
+ "Describe the issue with bad items": "描述不良物品的問題",
+ "Description": "描述",
+ "Detail Scheduling": "詳細排程",
+ "Details": "詳情",
+ "Do you want to start job order": "是否開始工單",
+ "Download Excel": "下載 Excel",
+ "Drink": "飲料",
+ "Duration hours": "{{count}} 小時",
+ "Duration minutes": "{{count}} 分鐘",
+ "Duration seconds": "{{count}} 秒",
+ "Edit": "改數",
+ "Edit Equipment": "設備詳情",
+ "Edit Equipment Type": "設備類型詳情",
+ "Edit Job Order": "工單詳情",
+ "Edit Job Order Detail": "工單詳情",
"End Product": "成品",
+ "End Qty": "結束數量",
+ "Enter all floors plastic box carton qty": "請輸入各樓層膠茜數目",
+ "Enter bad item quantity (required if no missing items)": "請輸入不良物品數量(如果沒有缺失物品)",
+ "Enter missing quantity (required if no bad items)": "請輸入缺失物品數量(如果沒有不良物品)",
+ "Enter plastic box carton qty": "請輸入膠茜數目",
+ "Enter print quantity": "請輸入打印數量",
+ "Enter the number of cartons": "請輸入箱數",
+ "Enter the number of cartons: ": "請輸入箱數:",
+ "Equipment": "設備",
+ "Equipment Code": "設備編號",
+ "Equipment Details": "設備詳情",
+ "Equipment Name and Code": "設備名稱及編號",
+ "Equipment Type Details": "設備類型詳情",
+ "EquipmentType-EquipmentName-Code": "設備類型-設備名稱-編號",
+ "Escalation History": "升級歷史",
+ "Escalation Info": "升級信息",
+ "Escalation Result": "升級結果",
+ "Estimated Production Date": "預計生產日期",
+ "Exclude Date": "排除日期",
+ "Executing": "執行中",
+ "Expected Lot:": "預期批號:",
+ "Expiry Date": "有效期",
+ "Exporting...": "匯出中...",
+ "FG": "成品",
+ "FG & Material Demand Forecast Detail": "成品及材料需求預測詳情",
+ "FG / WIP Item": "成品/半成品",
+ "FG Production Schedule": "FG 生產排程",
"Failed to create group": "創建組失敗",
+ "Failed to load plastic box carton qty dashboard": "載入膠茜數目使用數量失敗,請稍後再試。",
+ "Failed to submit scan data. Please try again.": "掃碼數據提交失敗. 請重試.",
+ "Finish": "完成",
+ "Finished Good Order": "成品出倉",
+ "Finished Goods Name": "成品名稱",
+ "Finished Job Order Record": "已完成工單記錄",
+ "Finished lines": "完成行",
"First created group": "第一次創建組",
+ "Floor": "樓層",
+ "Group": "組",
+ "Handled By": "處理者",
+ "Handler": "提料員",
+ "Idle": "閒置",
+ "If you confirm, the system will:": "如果您確認,系統將:",
+ "Import Testing": "匯入測試",
+ "In Progress": "進行中",
+ "In progress": "進行中",
+ "In_Progress": "進行中",
+ "Index": "編號",
+ "Input Equipment is not match with process": "輸入的設備與流程不匹配",
+ "Insufficient available quantity on lot (may have been picked by another user)": "掃描的批次已被其他用戶完全提料。請掃描其他批次。",
+ "Invalid Stock In Line Id": "無效庫存行ID",
"Invalid date format": "日期格式無效",
- "Item already exists in created items": "物料已存在於創建的物料中",
- "Job Order not found or has no items": "工單不存在或沒有物料",
+ "Inventory": "庫存",
+ "Is Dark": " 顔色深淺度",
+ "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間順序 | 複雜度",
+ "Is Dense": "濃淡",
+ "Is Float": "浮沉",
+ "Issue": "問題",
+ "Issue Remark": "問題備註",
+ "Item": "成品/半成品",
+ "Item Code": "物品編號",
+ "Item Name": "物品名稱",
+ "Item already exists in created items": "物品已存在於創建的物品中",
+ "Items": "物品",
+ "Jo Pick Order Detail": "工單提料詳情",
+ "Job Order": "工單",
+ "Job Order Code": "工單編號",
+ "Job Order Info": "工單信息",
+ "Job Order Item Name": "工單產品名稱",
+ "Job Order Match": "工單對料",
+ "Job Order No.": "工單編號",
+ "Job Order Pick Execution": "工單提料",
+ "Job Order Pick Order Details": "工單提料單詳情",
+ "Job Order Pickexcution": "工單提料",
+ "Job Order Qty": "工單數量",
+ "Job Order Type": "工單類型",
+ "Job Order not found or has no items": "工單不存在或沒有物品",
+ "Job Process Status Dashboard": "儀表板 - 工單狀態",
+ "Job Type": "工單類型",
+ "Job dashboard PP status: cancelled": "工序已取消",
+ "Job dashboard PP status: completed": "工序完成",
+ "Job dashboard PP status: in_progress": "工序進行中",
+ "Job dashboard PP status: pending": "工序待處理",
+ "Job dashboard PP status: stopped": "工序暫停",
+ "Job process detail mode label": "工序格顯示",
+ "Job process detail: equipment": "設備",
+ "Job process detail: handler": "員工",
+ "Job process detail: process name": "工序",
+ "Job process detail: time": "時間",
+ "Just Complete": "已完成",
+ "Just Completed (workbench): requires valid quantity; expired rows must not use this button.": "工單對料:需要有效數量;過期項目不能使用此按鈕。",
+ "Last 7 days": "最近7天",
+ "Last updated": "最後更新",
"Latest created group": "最新創建組",
+ "Lines with insufficient stock: ": "未能提料項目數量: ",
+ "Lines with sufficient stock: ": "可提料項目數量: ",
"Loading...": "加載中",
- "Material": "物料",
- "No results found": "沒有結果",
- "Please enter at least code or name": "請輸入至少編號或名稱",
- "Please enter quantity for all selected items": "請輸入所有已選擇的物料的數量",
- "Please select at least one item to submit": "請選擇至少一個物料提交",
- "Please select group and enter quantity for all selected items": "請選擇組並輸入所有已選擇的物料的數量",
- "Please select group for all selected items": "請選擇組對所有已選擇的物料",
- "Please select product type": "請選擇產品類型",
- "Please select target date": "請選擇需求日期",
- "Please select type": "請選擇類型",
- "Product Type": "產品類型",
- "Reset": "重置",
- "Search": "搜索",
- "Search Criteria": "搜索條件",
- "Search Items": "搜索物料",
- "Search Results": "搜索結果",
- "Selected items will join above created group": "已選擇的物料將加入上述創建的組",
- "reset": "重置",
+ "Location": "位置",
+ "Lot Actual Pick Qty": "批號實際提料數量",
+ "Lot Availability": "批號可用性",
+ "Lot Details": "批號細節",
+ "Lot No": "批號",
+ "Lot No.": "批號",
+ "Lot Number Mismatch": "批號不匹配",
+ "Lot Required Pick Qty": "批號需求數",
"Lot has been rejected and marked as unavailable.": "批號已被拒絕並標記為不可用。",
+ "LotNo": "批號",
+ "Mail": "郵件",
+ "Management Job Order": "管理工單",
"Manual Input": "手動輸入",
- "Partial quantity submitted. Please submit more or complete the order.": "",
- "Pick order completed successfully!": "提料單完成成功!",
- "Please finish QR code scan and pick order.": "請完成QR碼掃描和提料單。",
- "Please submit the pick order.": "請提交提料單。",
- "Processing QR code...": "處理QR碼...",
- "QR Code Scan for Lot": "批號QR碼掃描",
- "QR Scan Result:": "QR掃描結果:",
- "The input is not the same as the expected lot number.": "輸入的批號與預期批號不同。",
- "This order is insufficient, please pick another lot.": "此訂單不足,請選擇另一個批號。",
- "Verified successfully!": "驗證成功!",
- "At least one issue must be reported": "至少有一個問題必須報告",
- "Available in warehouse": "在倉庫中可用",
- "Remaining Available Qty": "剩餘可用數量",
- "Describe the issue with bad items": "描述不良物料的問題",
- "Enter bad item quantity (required if no missing items)": "請輸入不良物料數量(如果沒有缺失物料)",
- "Enter missing quantity (required if no bad items)": "請輸入缺失物料數量(如果沒有不良物料)",
+ "Matching Stock": "工單對料",
+ "Material": "材料",
+ "Material Code": "材料編號",
+ "Material Pick Status": "物料提料狀態",
"Max": "最大",
- "Note:": "注意:",
- "Qty is not allowed to be greater than required qty": "數量不能大於所需數量",
- "Qty is required": "數量是必需的",
- "Still need to pick": "仍需提料",
- "Verified quantity cannot exceed received quantity": "驗證數量不能超過接收數量",
- "submitting": "提交中",
- "Consolidate": "整合",
- "Consolidated Code": "整合編號",
- "Items": "物料",
- "Released By": "發佈者",
- "Product": "產品",
- "Target Date From": "需求日期從",
- "Target Date To": "需求日期到",
- "Type": "類型",
- "Confirm": "確認",
- "Expected Lot:": "預期批號:",
- "If you confirm, the system will:": "如果您確認,系統將:",
- "Lot Number Mismatch": "批號不匹配",
- "Scanned Lot:": "掃描批號:",
- "The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?": "掃描的物料與預期物料匹配,但批號不同。您想繼續使用不同的批號嗎?",
- "Update your suggested lot to the this scanned lot": "更新您建議的批號為此掃描的批號",
- "Default Warehouse": "默認倉庫",
- "LotNo": "批號",
- "No Warehouse": "沒有倉庫",
- "Please scan warehouse qr code.": "請掃描倉庫QR碼。",
- "Po Code": "PO編號",
- "Putaway Detail": "入庫細節",
- "Select warehouse": "選擇倉庫",
- "Supplier": "供應商",
- "acceptedQty": "接受數量",
- "bind": "綁定",
- "expiryDate": "有效期",
- "itemName": "產品名稱",
- "itemNo": "成品編號",
- "not default warehosue": "不是默認倉庫",
- "printQty": "打印數量",
- "productionDate": "生產日期",
- "warehouse": "倉庫",
- "Add Record": "添加記錄",
- "Add some entries!": "請添加條目",
- "Clean Record": "清空記錄",
- "Escalation History": "升級歷史",
- "Escalation Info": "升級信息",
- "Escalation Result": "升級結果",
- "QC Info": "QC信息",
- "acceptQty": "接受數量",
- "acceptQty must not greater than": "接受數量不能大於",
- "escalation": "升級",
- "failedQty": "失敗數量",
- "qcResult": "QC結果",
- "remarks": "備註",
- "supervisor": "主管",
+ "Missing item Qty": "缺少物品數量",
+ "Missing items": "缺少物品",
+ "Multiplier": "倍數",
+ "N/A": "不適用",
+ "Name": "成品/半成品名稱",
+ "Next": "下一步",
+ "Next page": "下一頁",
+ "No": "沒有",
+ "No Group": "沒有組",
+ "No Item": "沒有物品",
"No Qc": "沒有QC",
- "acceptedWeight": "接受重量",
- "receivedQty": "接收數量",
- "stock in information": "庫存信息",
"No Uom": "沒有單位",
- "Print Pick Record": "打印版頭紙",
- "Printed Successfully.": "成功列印",
- "Submit All Scanned": "提交所有已掃描項目",
- "Submitting...": "提交中...",
- "is unavable. Please check around have available QR code or not.": "此批號不可用,請檢查周圍是否有可用的 QR 碼。",
- "COMPLETED": "已完成",
- "success": "成功",
- "Total (Verified + Bad + Missing) must equal Required quantity": "驗證數量 + 不良數量 + 缺失數量必須等於需求數量",
- "BOM Status": "材料預備狀況",
- "Job Order Type": "工單類型",
- "Estimated Production Date": "預計生產日期",
- "Plan Start": "預計生產日期",
- "Remember plan start as default": "記住為預設日期",
- "Plan Start From": "預計生產日期",
- "Delivery Note Code": "送貨單編號",
- "Plan Start To": "預計生產日期至",
- "By-product": "副產品",
- "Complete Step": "完成步驟",
- "Defect": "缺陷",
- "Output from Process": "流程輸出",
- "Quantity": "數量",
- "Scrap": "廢料",
- "Unit": "單位",
- "Back to List": "返回列表",
- "Production Output Data Entry": "生產輸出數據輸入",
- "Step": "步驟",
- "Quality Check": "品質檢查",
- "Action": "操作",
- "Changeover Time (mins)": "生產後轉換時間(分鐘)",
- "Completed": "完成",
- "completed": "完成",
- "Date": "日期",
- "Failed to submit scan data. Please try again.": "掃碼數據提交失敗. 請重試.",
- "In Progress": "進行中",
- "Is Dark": " 顔色深淺度",
- "Is Dense": "濃淡",
- "Is Float": "浮沉",
- "Job Order Code": "工單編號",
+ "No Warehouse": "沒有倉庫",
+ "No chart data": "沒有圖表資料",
+ "No completed Job Order pick orders with matching found": "沒有相關記錄",
+ "No created items": "沒有創建物品",
+ "No data available": "沒有資料",
+ "No data found": "沒有找到資料",
+ "No lot details available": "沒有批號細節",
+ "No results found": "沒有結果",
+ "No. of Items to be Picked": "需提料數量",
+ "No. of Items with Issue During Pick": "問題數量",
+ "None": "沒有",
+ "Note:": "注意:",
+ "Now": "現時",
+ "Number must be at least 1": "數字必須至少為1",
+ "Number of cartons": "箱數",
+ "Open 挑號 QR 碼 on a pick line first, then scan {2fic} to use manual lot substitution.": "請先點選一列並開啟「挑號 QR 碼」,再掃描 {2fic} 以使用手動換批。",
"Operator": "操作員",
+ "Operator KPI": "操作員KPI",
+ "Operator KPI Dashboard": "儀表板 - 操作員KPI概覽",
+ "Operator Name & No.": "操作員名稱及編號",
+ "Order Complete": "訂單完成",
+ "Order Quantity": "需求數",
+ "Other": "其他",
"Output Qty": "輸出數量",
+ "Output from Process": "流程輸出",
+ "Over Time": "超時",
+ "Overall Time Remaining": "總剩餘時間",
+ "Overview": "總覽",
+ "Packaging": "提料中",
+ "Partial quantity submitted. Please submit more or complete the order.": "已提料部分數量。請提交更多或完成訂單。",
+ "Pass": "通過",
+ "Passed Step": "通過步驟",
+ "Pause": "暫停",
+ "Pause Reason": "暫停原因",
+ "Paused": "已暫停",
"Pending": "待處理",
- "pending": "待處理",
-
- "Please scan equipment code (optional if not required)": "請掃描設備編號(可選)",
+ "Pending for pick": "待提料",
+ "Pick End Time": "提料結束時間",
+ "Pick Execution Issue Form": "提料問題表單",
+ "Pick Order": "提料單",
+ "Pick Order Code": "提料單編號",
+ "Pick Order Conso Code": "提料單組合編號",
+ "Pick Order Detail": "提料單細節",
+ "Pick Order Id": "提料單編號",
+ "Pick Order No.- Job Order No.- Item": "提料單編號-工單編號-成品/半成品",
+ "Pick Order Status": "提料單狀態",
+ "Pick Order Target Date": "提料單需求日期",
+ "Pick Start Time": "提料開始時間",
+ "Pick Time Taken (minutes)": "提料時間(分鐘)",
+ "Pick order completed successfully!": "提料單完成成功!",
+ "Picked Qty": "已提料數量",
+ "Plan Start": "預計生產日期",
+ "Plan Start From": "預計生產日期",
+ "Plan Start To": "預計生產日期至",
+ "Planning": "計劃中",
+ "Plastic box carton Qty": "膠茜數目",
+ "Plastic box carton qty dashboard": "膠茜數目使用數量",
+ "Plastic box carton qty multi period report": "膠茜數目使用數量_多時段報表",
+ "Plastic box carton qty report last 7 days": "膠茜數目使用數量(最近7天)",
+ "Plastic box carton qty report this month": "膠茜數目使用數量(本月)",
+ "Plastic box carton qty report this year": "膠茜數目使用數量(本年)",
+ "Plastic box carton qty usage": "膠茜數目",
+ "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "請檢查周圍是否有QR碼,可能是剛剛入庫或轉移入庫或轉移出庫。",
+ "Please enter at least code or name": "請輸入至少編號或名稱",
+ "Please enter quantity for all selected items": "請輸入所有已選擇的物品的數量",
+ "Please finish QR code scan and pick order.": "請完成QR碼掃描和提料單。",
+ "Please make sure all required items are picked": "請確保所有物品已被提取",
+ "Please make sure the qty is enough": "物品數量不足",
"Please scan equipment code": "請掃描設備編號",
- "Equipment Code": "設備編號",
+ "Please scan equipment code (optional if not required)": "請掃描設備編號(可選)",
"Please scan operator code": "請掃描操作員編號",
"Please scan operator code first": "請先掃描操作員編號",
+ "Please scan staff no": "請掃描員工編號",
+ "Please scan the item qr code": "請掃描物品二維碼",
+ "Please scan warehouse qr code.": "請掃描倉庫QR碼。",
+ "Please select": "請選擇",
+ "Please select a printer": "請選擇打印機",
+ "Please select a printer first": "請先選擇打印機",
+ "Please select at least one item to submit": "請選擇至少一個物品提交",
+ "Please select group and enter quantity for all selected items": "請選擇組並輸入所有已選擇的物品的數量",
+ "Please select group for all selected items": "請選擇組對所有已選擇的物品",
+ "Please select item": "請選擇物品",
+ "Please select product type": "請選擇產品類型",
+ "Please select target date": "請選擇需求日期",
+ "Please select type": "請選擇類型",
+ "Please submit the pick order.": "請提交提料單。",
+ "Po Code": "PO編號",
+ "Powder Mixture": "箱料粉",
+ "Powder_Mixture": "箱料粉",
+ "Previous page": "上一頁",
+ "Print Pick Record": "打印版頭紙",
+ "Print Quantity": "打印數量",
+ "Printed Successfully.": "成功列印",
+ "Printer": "打印機",
+ "Process": "工序",
+ "Process page summary": "工序 {{from}}–{{to}} / 共 {{total}} 道",
+ "Processing": "已開始工序",
+ "Processing QR code...": "處理QR碼...",
+ "Processing Status": "處理狀態",
+ "Processing Time": "生產時間",
"Processing Time (mins)": "步驟時間(分鐘)",
+ "Processing...": "處理中",
+ "Product": "產品",
+ "Product Type": "產品類型",
+ "Product process status": "生產流程狀態",
+ "Production": "生產流程",
+ "Production Date": "生產日期",
+ "Production Equipment Status Dashboard": "儀表板 - 生產設備最新狀態",
+ "Production Output Data": "生產輸出數據",
+ "Production Output Data Entry": "生產輸出數據輸入",
+ "Production Priority": "生產優先序",
+ "Production Priority required!": "生產優先度必填!",
+ "Production Process": "工藝流程",
"Production Process Information": "生產流程信息",
+ "Production Process Line Remark": "工藝明細",
"Production Process Steps": "生產流程步驟",
+ "Production Time Remaining": "生產剩餘時間",
+ "Production date": "生產日期",
+ "Progress": "進度",
+ "Project": "專案",
+ "Projects": "專案",
+ "Purchase Order": "採購單",
+ "Put Away": "上架",
+ "Put Away Scan": "上架掃碼",
+ "Put Awayed": "已上架",
+ "Putaway Detail": "入庫細節",
+ "QC Category": "QC品檢模板",
+ "QC Check Item": "QC品檢項目",
+ "QC Check Template": "QC檢查模板",
+ "QC Info": "QC信息",
+ "QR Code Handle": "二維碼列印及下載",
+ "QR Code Scan for Lot": "批號QR碼掃描",
+ "QR Scan Result:": "QR掃描結果:",
+ "QR code does not match any item in current orders.": "QR碼不匹配當前工單的物品。",
+ "QR code verified.": "QR碼驗證成功。",
+ "Qc Item": "QC 項目",
+ "Qty": "數量",
+ "Qty Already Picked": "已提料數量",
+ "Qty cannot be negative": "數量不可為負數",
+ "Qty is not allowed to be greater than required qty": "數量不能大於所需數量",
+ "Qty is required": "數量是必需的",
+ "Qty must be a whole number": "請輸入整數(不可為小數)",
+ "Qty will submit": "提交數量",
+ "Quality Check": "品質檢查",
+ "Quantity": "數量",
+ "R&D": "研發",
+ "RELEASED": "已放單",
+ "Reason": "原因",
+ "Received Qty": "接收數量",
+ "Reject": "拒絕",
+ "Release": "放單",
+ "Released": "已放單",
+ "Released By": "發佈者",
+ "Remaining Available Qty": "剩餘可用數量",
+ "Remaining Time (min)": "剩餘時間(分鐘)",
+ "Remark": "明細",
+ "Remember plan start as default": "記住為預設日期",
+ "Repair": "維修",
+ "Req. Qty": "需求數量",
+ "Required Qty": "需求數量",
+ "Reset": "重置",
+ "Route": "路線",
+ "Router": "執貨路線",
+ "Row per page": "每頁行數",
+ "Rows per page": "每頁行數",
+ "SEQ": "步驟",
+ "STF": "員工餐",
+ "Save": "儲存",
"Scan Operator & Equipment": "掃描操作員和設備",
+ "Scan Result": "掃碼結果",
+ "Scan Status": "掃碼狀態",
+ "Scanned": "已掃碼",
+ "Scanned Lot:": "掃描批號:",
+ "Scanning...": "掃碼中",
+ "Scrap": "廢料",
+ "Scrap Qty": "損耗數量",
+ "Search": "搜索",
+ "Search Criteria": "搜索條件",
+ "Search Items": "搜索物品",
+ "Search Job Order/ Create Job Order": "搜索工單/建立工單",
+ "Search Results": "搜索結果",
+ "Second Scan Completed": "對料已完成",
+ "Second Scan Pending": "對料待處理",
+ "Second Scan Status": "對料狀態",
+ "Select Another Bag Lot": "選擇另一個包裝袋",
+ "Select Bag": "選擇包裝袋",
+ "Select Date": "選擇日期",
+ "Select Printer": "選擇打印機",
+ "Select Unit": "選擇單位",
+ "Select a printer": "選擇打印機",
+ "Select warehouse": "選擇倉庫",
+ "Selected": "已選擇",
+ "Selected items will join above created group": "已選擇的物品將加入上述創建的組",
+ "Seq": "步驟",
+ "Seq No": "加入步驟",
+ "Seq No Remark": "序號明細",
"Seq:": "步驟",
+ "Sequence": "序",
+ "Setup Time": "生產前預備時間",
"Setup Time (mins)": "生產前預備時間(分鐘)",
+ "Shop Address": "商店地址",
+ "Shop ID": "商店ID",
+ "Shop Name": "商店名稱",
+ "Shop PO Code": "商店PO編號",
+ "Sign out": "登出",
+ "Skip": "跳過",
+ "Staff No": "員工編號",
+ "Staff No Required": "員工編號必填",
+ "Staff No:": "員工編號:",
"Start": "開始",
+ "Start Job Order": "開始工單",
"Start QR Scan": "開始掃碼",
- "Status": "狀態",
- "in_progress": "進行中",
- "In_Progress": "進行中",
- "inProgress": "進行中",
-
+ "Start Qty": "開始數量",
+ "Start Scan": "開始掃碼",
+ "Start Time": "開始時間",
+ "Status": "狀態",
+ "Step": "步驟",
+ "Step Information": "步驟信息",
"Step Name": "名稱",
+ "Still need to pick": "仍需提料",
+ "Stock Available": "庫存數",
+ "Stock Req. Qty": "需求數",
+ "Stock Status": "庫存狀態",
+ "Stock UOM": "庫存單位",
+ "Stock Unit": "庫存單位",
+ "Stop": "停止",
"Stop QR Scan": "停止掃碼",
+ "Stop Scan": "停止掃碼",
+ "Store ID": "商店ID",
+ "Storing": "成品入倉中",
+ "Submit": "提交",
"Submit & Start": "提交並開始",
+ "Submit All Scanned": "提交所有已掃描項目",
+ "Submit Bag Consumption": "提交包裝袋消耗",
+ "Submit Required Pick Qty": "提交需求數",
+ "Submitting...": "提交中...",
+ "Summary": "彙總",
+ "Supplier": "供應商",
+ "Target Date": "需求日期",
+ "Target Date From": "需求日期從",
+ "Target Date To": "需求日期到",
+ "Target Production Date": "目標生產日期",
+ "Task Template": "任務範本",
+ "The input is not the same as the expected lot number.": "輸入的批號與預期批號不同。",
+ "The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?": "掃描的物品與預期物品匹配,但批號不同。您想繼續使用不同的批號嗎?",
+ "This form is for reporting issues only. You must report either missing items or bad items.": "此表單僅用於報告問題。您必須報告缺少的物品或不良物品。",
+ "This is last lot, so no available lot.": "這是最後一個批次,所以沒有可用批次。",
+ "This lot is rejected, please scan another lot.": "此批次已拒收,請掃描另一個批次。",
+ "This month": "本月",
+ "This order is insufficient, please pick another lot.": "此訂單不足,請選擇另一個批號。",
+ "This year": "本年",
+ "Ticket No.": "票號",
+ "Time": "時間",
+ "Time Information(mins)": "時間信息(分鐘)",
+ "Time Remaining": "剩餘時間",
+ "Time used": "耗時",
+ "Timer Paused": "計時器已暫停",
+ "Today": "今天",
+ "Total": "總數",
+ "Total (Verified + Bad + Missing) must equal Required quantity": "總數必須等於需求數量",
+ "Total Processing Time": "總生產時間",
"Total Steps": "總步驟數",
- "Unknown": "",
- "Job Type": "工單類型",
+ "Total lines: ": "所需貨品項目數量: ",
+ "Total pick orders": "總提料單數量",
+ "Total plastic box carton qty": "總膠茜數目",
+ "Total processes": "總流程數",
+ "Truck No.": "車線編號",
+ "Two Days Ago": "前天",
+ "Type": "類型",
+ "Unable to get user ID": "無法獲取用戶ID",
+ "Unassigned Job Orders": "未分配工單",
+ "Unit": "單位",
+ "Unknown": "未知",
+ "Unknown error": "未知錯誤",
+ "Unknown error: ": "未知錯誤: ",
+ "UoM": "銷售單位",
+ "Update Estimated Production Date": "更新預計生產日期",
"Update Job Order": "完成工單",
- "Production Date":"生產日期",
- "Jo Pick Order Detail":"工單提料詳情",
- "WIP": "半成品",
- "R&D": "研發",
- "STF": "員工餐",
- "Other": "其他",
+ "Update Production Priority": "更新生產優先度",
+ "Update Time Information": "更新時間信息",
+ "Update your suggested lot to the this scanned lot": "更新您建議的批號為此掃描的批號",
+ "User not found with staffNo:": "用戶不存在",
"Validation failed. Please check operator and equipment.": "驗證失敗. 請檢查操作員和設備.",
+ "Verified Qty": "驗證數量",
+ "Verified quantity cannot exceed received quantity": "驗證數量不能超過接收數量",
+ "Verified successfully!": "驗證成功!",
"View": "查看",
- "Back": "返回",
- "N/A": "不適用",
- "BoM Material": "材料清單",
- "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間順序 | 複雜度",
- "Enter the number of cartons: ": "請輸入箱數:",
- "Number of cartons": "箱數",
- "You need to enter a number": "您需要輸入一個數字",
- "Number must be at least 1": "數字必須至少為1",
-
- "Job Order Info": "工單信息",
- "Matching Stock": "工單對料",
- "No data found": "沒有找到資料",
- "Print Quantity": "打印數量",
- "Select Printer": "選擇打印機",
- "Printer": "打印機",
- "Enter print quantity": "請輸入打印數量",
- "Production Priority": "生產優先序",
- "Please select a printer first": "請先選擇打印機",
- "Production Process": "工藝流程",
- "Production Process Line Remark": "工藝明細",
- "Remark": "明細",
- "Req. Qty": "需求數量",
- "Seq No": "加入步驟",
- "Seq No Remark": "序號明細",
- "Stock Available": "庫存數",
- "Stock Status": "庫存狀態",
- "Target Production Date": "目標生產日期",
- "Description": "描述",
-
- "id": "ID",
- "Finished lines": "完成行",
- "Invalid Stock In Line Id": "無效庫存行ID",
- "Production date": "生產日期",
- "Required Qty": "需求數量",
- "Total processes": "總流程數",
"View Details": "查看詳情",
- "view stockin": "品檢",
- "Completed Step": "完成步驟",
- "Continue": "繼續",
- "Executing": "執行中",
- "Order Complete": "訂單完成",
- "Pause": "暫停",
- "Production Output Data": "生產輸出數據",
- "Step Information": "步驟信息",
- "Stop": "停止",
- "Demand Forecast Setting": "需求預測設定",
- "EquipmentType-EquipmentName-Code": "設備類型-設備名稱-編號",
-
- "Equipment": "設備",
- "Time Information(mins)": "時間信息(分鐘)",
- "Processing Time": "生產時間",
- "Setup Time": "生產前預備時間",
- "Changeover Time": "生產後轉換時間",
+ "View item In-out And inventory Ledger": "查看物品出入庫及庫存日誌",
+ "WIP": "半成品",
+ "Wait Time [minutes]": "等待時間(分鐘)",
"Warehouse": "倉庫",
- "Supplier": "供應商",
- "Purchase Order":"採購單",
- "Demand Forecast":"需求預測",
- "Pick Order": "提料單",
- "Deliver Order":"送貨訂單",
- "Project":"專案",
- "Product":"產品",
- "Material":"材料",
- "mat":"原料",
+ "Yesterday": "昨天",
+ "You need to enter a number": "您需要輸入一個數字",
+ "acceptQty": "接受數量",
+ "acceptQty must not greater than": "接受數量不能大於",
+ "acceptedQty": "接受數量",
+ "acceptedQty must not greater than": "接受數量不能大於",
+ "acceptedWeight": "接受重量",
+ "bind": "綁定",
+ "bomWarn_close": "關閉",
+ "bomWarn_copyAll": "複製清單",
+ "bomWarn_empty": "目前沒有 BOM 數據問題。",
+ "bomWarn_issue_MISSING_BOM_CODE": "BOM 編號為空",
+ "bomWarn_issue_MISSING_BOM_NAME": "BOM 名稱為空",
+ "bomWarn_issue_MISSING_ITEM": "關聯物品不存在或已刪除",
+ "bomWarn_issue_MISSING_SALES_UOM": "物品缺少銷售單位",
+ "bomWarn_issue_MISSING_STOCK_UOM": "物品缺少庫存單位,品檢可能失敗",
+ "bomWarn_issue_MISSING_STOCK_UOM_CONVERSION": "庫存單位缺少或已刪除 UOM 換算,品檢可能失敗",
+ "bomWarn_issue_MISSING_UOM_CONVERSION": "銷售單位缺少或已刪除 UOM 換算",
+ "bomWarn_loadFailed": "無法載入 BOM 問題清單,請稍後再試。",
+ "bomWarn_refresh": "重新檢查",
+ "bomWarn_refreshing": "檢查中…",
+ "bomWarn_rowBomId": "BOM ID",
+ "bomWarn_rowItemId": "物品 ID",
+ "bomWarn_title": "BOM 數據問題",
+ "bomWarn_tooltipHas": "有 {{count}} 筆 BOM 數據問題",
+ "bomWarn_tooltipNone": "沒有 BOM 數據問題",
+ "cancel": "已取消",
+ "cancelled": "已取消",
+ "complete jo": "完成工單",
+ "completed": "完成",
+ "completed Job Order pick orders with Matching": "工單已完成提料和對料",
+ "completed Job Order pick orders with matching": "工單已完成提料和對料",
"consumables": "消耗品",
- "non-consumables": "非消耗品",
- "fg": "成品",
- "sfg": "半成品",
- "item": "貨品",
- "FG":"成品",
- "FG & Material Demand Forecast Detail":"成品及材料需求預測詳情",
- "View item In-out And inventory Ledger":"查看物料出入庫及庫存日誌",
- "Delivery Order":"送貨訂單",
- "Detail Scheduling":"詳細排程",
- "Customer":"客戶",
- "qcItem":"品檢項目",
- "QC Check Item":"QC品檢項目",
- "QC Category":"QC品檢模板",
- "qcCategory":"品檢模板",
- "QC Check Template":"QC檢查模板",
- "QR Code Handle":"二維碼列印及下載",
- "Mail":"郵件",
- "Import Testing":"匯入測試",
- "Overview": "總覽",
- "Projects": "專案",
- "Create Project": "新增專案",
- "Task Template": "任務範本",
- "Create Task Template": "新增任務範本",
- "Qc Item": "QC 項目",
- "FG Production Schedule": "FG 生產排程",
- "Inventory": "庫存",
- "scheduling":"排程",
- "settings": "設定",
- "items": "物料",
- "edit":"編輯",
- "Edit Equipment Type":"設備類型詳情",
- "Edit Equipment":"設備詳情",
- "equipmentType":"設備類型",
- "Description":"描述",
- "Details": "詳情",
- "Equipment Type Details":"設備類型詳情",
- "Save":"儲存",
- "Cancel":"取消",
- "Equipment Details":"設備詳情",
- "Exclude Date":"排除日期",
- "Finished Goods Name":"成品名稱",
"create": "新增",
+ "edit": "編輯",
+ "enter a qty": "請輸入數量",
+ "equipmentType": "設備類型",
+ "escalation": "升級",
+ "escalation processing": "處理上報記錄",
+ "expiryDate": "有效期",
+ "failedQty": "失敗數量",
+ "fg": "成品",
+ "finishedGood": "成品",
+ "handler": "處理者",
"hr": "小時",
"hrs": "小時",
+ "id": "ID",
+ "inProgress": "進行中",
+ "in_progress": "進行中",
+ "is expired. Please check around have available QR code or not.": "已過期。請檢查周圍是否有可用的 QR 碼。",
+ "is unavable. Please check around have available QR code or not.": "此批號不可用,請檢查周圍是否有可用的 QR 碼。",
+ "issue": "問題",
+ "issue remark": "問題描述",
+ "item": "貨品",
+ "itemName": "產品名稱",
+ "itemNo": "成品編號",
+ "items": "物品",
+ "items completed": "物品已完成",
+ "jodetail": "工單細節",
+ "mat": "原料",
"min": "分鐘",
+ "minimal value is 1": "最小值為1",
"mins": "分鐘",
- "Edit Job Order": "工單詳情",
- "Production": "生產流程",
- "Put Away": "上架",
- "Put Away Scan": "上架掃碼",
- "Finished Good Order": "成品出倉",
- "finishedGood": "成品",
- "Router": "執貨路線",
-"Equipment Name and Code": "設備名稱及編號",
-"Remaining Time (min)": "剩餘時間(分鐘)",
-"Idle": "閒置",
-"Repair": "維修",
-"Production Equipment Status Dashboard": "儀表板 - 生產設備最新狀態",
-"Operator KPI Dashboard": "儀表板 - 操作員KPI概覽",
- "Start Scan": "開始掃碼",
- "Stop Scan": "停止掃碼",
- "Operator Name & No.": "操作員名稱及編號",
- "Count of Job Orders": "工單數量",
- "Total Processing Time": "總生產時間",
- "Material Pick Status": "物料提料狀態",
- "Job Order Qty": "工單數量",
- "Sign out": "登出",
- "Job Order No.": "工單編號",
- "Operator KPI": "操作員KPI",
- "FG / WIP Item": "成品/半成品",
- "Production Time Remaining": "生產剩餘時間",
- "Process": "工序",
- "Start": "開始",
- "This form is for reporting issues only. You must report either missing items or bad items.": "此表單僅用於報告問題。您必須報告缺少的物品或不良物品。",
- "Pick Execution Issue Form": "提料問題表單",
- "Missing items": "缺少物品",
- "Total (Verified + Bad + Missing) must equal Required quantity": "總數必須等於需求數量",
- "Missing item Qty": "缺少物品數量",
- "Bad Item Qty": "不良物品數量",
- "Issue Remark": "問題備註",
+ "minutes": "分鐘",
+ "non-consumables": "非消耗品",
+ "not default warehosue": "不是默認倉庫",
+ "packaging": "提料中",
+ "paused": "已暫停",
+ "pending": "待處理",
+ "printQty": "打印數量",
+ "process epqc": "進行成品檢驗",
+ "process stockIn": "進行收貨程序",
+ "productionDate": "生產日期",
+ "qcCategory": "品檢模板",
+ "qcItem": "品檢項目",
+ "qcResult": "QC結果",
+ "qty": "數量",
+ "qty is not allowed to be greater than picked qty": "數量不能大於已提料數量",
+ "qty is not allowed to be greater than remaining available qty": "數量不能大於剩餘可用數量",
+ "qty is not allowed to be greater than required qty": "數量不能大於需求數量",
+ "qty is required": "數量是必需的",
+ "receivedQty": "接收數量",
+ "release jo": "工單詳情",
+ "remarks": "備註",
+ "reset": "重置",
+ "scan picked material": "掃碼確認提料",
+ "scheduling": "排程",
+ "second Scan Status": "對料狀態",
+ "select qc": "選擇QC",
"seq": "序號",
- "Handled By": "處理者",
- "Job Order Pick Execution": "工單提料",
- "BOM Type": "BOM 類型",
- "BOM Description": "BOM 說明",
- "Floor": "樓層",
- "Finish": "完成",
- "Open 挑號 QR 碼 on a pick line first, then scan {2fic} to use manual lot substitution.": "請先點選一列並開啟「挑號 QR 碼」,再掃描 {2fic} 以使用手動換批。",
- "Enter plastic box carton qty": "請輸入膠茜數目",
- "Enter all floors plastic box carton qty": "請輸入各樓層膠茜數目",
- "2/F plastic box carton Qty": "2/F 膠茜數目",
- "3/F plastic box carton Qty": "3/F 膠茜數目",
- "4/F plastic box carton Qty": "4/F 膠茜數目",
- "Qty cannot be negative": "數量不可為負數",
- "Qty must be a whole number": "請輸入整數(不可為小數)",
- "Plastic box carton Qty": "膠茜數目",
- "Plastic box carton qty dashboard": "膠茜數目使用數量",
- "Plastic box carton qty usage": "膠茜數目",
- "Failed to load plastic box carton qty dashboard": "載入膠茜數目使用數量失敗,請稍後再試。",
- "No chart data": "沒有圖表資料",
- "2/F plastic box carton qty count": "2/F 膠茜數目",
- "3/F plastic box carton qty count": "3/F 膠茜數目",
- "4/F plastic box carton qty count": "4/F 膠茜數目",
- "Total plastic box carton qty": "總膠茜數目",
- "All floors": "全部樓層",
- "Download Excel": "下載 Excel",
- "Exporting...": "匯出中...",
- "Summary": "彙總",
- "Last 7 days": "最近7天",
- "This month": "本月",
- "This year": "本年",
- "Plastic box carton qty report last 7 days": "膠茜數目使用數量(最近7天)",
- "Plastic box carton qty report this month": "膠茜數目使用數量(本月)",
- "Plastic box carton qty report this year": "膠茜數目使用數量(本年)",
- "Plastic box carton qty multi period report": "膠茜數目使用數量_多時段報表",
- "All": "全部",
- "bomWarn_title": "BOM 數據問題",
- "bomWarn_tooltipHas": "有 {{count}} 筆 BOM 數據問題",
- "bomWarn_tooltipNone": "沒有 BOM 數據問題",
- "bomWarn_empty": "目前沒有 BOM 數據問題。",
- "bomWarn_refresh": "重新檢查",
- "bomWarn_refreshing": "檢查中…",
- "bomWarn_copyAll": "複製清單",
- "bomWarn_close": "關閉",
- "bomWarn_loadFailed": "無法載入 BOM 問題清單,請稍後再試。",
- "bomWarn_rowBomId": "BOM ID",
- "bomWarn_rowItemId": "物料 ID",
- "bomWarn_issue_MISSING_BOM_CODE": "BOM 編號為空",
- "bomWarn_issue_MISSING_BOM_NAME": "BOM 名稱為空",
- "bomWarn_issue_MISSING_ITEM": "關聯物料不存在或已刪除",
- "bomWarn_issue_MISSING_SALES_UOM": "物料缺少銷售單位",
- "bomWarn_issue_MISSING_UOM_CONVERSION": "銷售單位缺少或已刪除 UOM 換算",
- "bomWarn_issue_MISSING_STOCK_UOM": "物料缺少庫存單位,品檢可能失敗",
- "bomWarn_issue_MISSING_STOCK_UOM_CONVERSION": "庫存單位缺少或已刪除 UOM 換算,品檢可能失敗"
+ "settings": "設定",
+ "sfg": "半成品",
+ "stock in information": "庫存信息",
+ "stopped": "暫停",
+ "storing": "待品檢入倉",
+ "submit": "提交",
+ "submitting": "提交中",
+ "success": "成功",
+ "supervisor": "主管",
+ "targetDate": "需求日期",
+ "type": "類型",
+ "uom": "單位",
+ "update production priority": "更新生產優先序",
+ "update qc info": "更新QC資訊",
+ "update success": "成功更新資料",
+ "value must be a number": "值必須是數字",
+ "view putaway": "查看上架詳情",
+ "view stockin": "品檢",
+ "warehouse": "倉庫"
}
diff --git a/src/i18n/zh/laserPrint.json b/src/i18n/zh/laserPrint.json
new file mode 100644
index 0000000..1460d76
--- /dev/null
+++ b/src/i18n/zh/laserPrint.json
@@ -0,0 +1,3 @@
+{
+ "title": "檸檬機(激光機)"
+}
diff --git a/src/i18n/zh/login.json b/src/i18n/zh/login.json
index da69471..146be30 100644
--- a/src/i18n/zh/login.json
+++ b/src/i18n/zh/login.json
@@ -1,10 +1,11 @@
{
- "Invalid username or password.": "帳號或密碼錯誤。",
- "Something went wrong. Please try again later.": "出了些問題。請稍後再試。",
- "Username": "帳號",
- "Password": "密碼",
- "Please enter a username": "請輸入帳號",
- "Please enter a password": "請輸入密碼",
- "Login": "登入",
- "Sign In": "登入"
-}
\ No newline at end of file
+ "Invalid username or password.": "帳號或密碼錯誤。",
+ "Login": "登入",
+ "Password": "密碼",
+ "Please enter a password": "請輸入密碼",
+ "Please enter a username": "請輸入帳號",
+ "Sign In": "登入",
+ "Something went wrong. Please try again later.": "出了些問題。請稍後再試。",
+ "Username": "帳號",
+ "toggle password visibility": "切換密碼可見性"
+}
diff --git a/src/i18n/zh/m18ImportTesting.json b/src/i18n/zh/m18ImportTesting.json
index bc93308..89e296c 100644
--- a/src/i18n/zh/m18ImportTesting.json
+++ b/src/i18n/zh/m18ImportTesting.json
@@ -1,16 +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
+ "testing sections tabs": "測試區域分頁",
+ "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": "狀態"
+}
diff --git a/src/i18n/zh/m18Sync.json b/src/i18n/zh/m18Sync.json
new file mode 100644
index 0000000..eafa124
--- /dev/null
+++ b/src/i18n/zh/m18Sync.json
@@ -0,0 +1,3 @@
+{
+ "title": "M18 同步"
+}
diff --git a/src/i18n/zh/mail.json b/src/i18n/zh/mail.json
index 0402484..c583278 100644
--- a/src/i18n/zh/mail.json
+++ b/src/i18n/zh/mail.json
@@ -1,22 +1,25 @@
{
- "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
+ "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",
+ "Save Fail": "儲存失敗",
+ "Save Success": "儲存成功",
+ "send to everyone": "發送給所有人"
+}
diff --git a/src/i18n/zh/masterDataIssue.json b/src/i18n/zh/masterDataIssue.json
index 9fb1d1b..622c549 100644
--- a/src/i18n/zh/masterDataIssue.json
+++ b/src/i18n/zh/masterDataIssue.json
@@ -1,104 +1,101 @@
{
- "Current Stock": "現有庫存",
- "masterDataIssue": "BOM/貨品單位問題",
- "masterDataIssue_pageTitle": "BOM/貨品單位問題",
- "masterDataIssue_tab_bom": "BOM",
- "masterDataIssue_tab_item": "貨品",
- "masterDataIssue_count": "共 {{count}} 筆問題",
- "masterDataIssue_search": "搜索",
- "masterDataIssue_refresh": "重新檢查",
- "masterDataIssue_refreshing": "檢查中…",
- "masterDataIssue_copy": "複製清單",
- "masterDataIssue_empty": "目前沒有問題。",
- "masterDataIssue_loadFailed": "無法載入問題清單,請稍後再試。",
- "masterDataIssue_filter_all": "全部",
- "masterDataIssue_material": "原料",
- "masterDataIssue_col_scope": "範圍",
- "masterDataIssue_col_bom": "BOM",
- "masterDataIssue_col_item": "貨品",
- "masterDataIssue_col_issue": "問題",
- "masterDataIssue_col_expected": "應為",
- "masterDataIssue_col_actual": "實際",
- "masterDataIssue_scope_BOM": "BOM 總表",
- "masterDataIssue_scope_BOM_MATERIAL": "BOM 原材料",
- "masterDataIssue_scope_ITEM": "貨品",
- "masterDataIssue_nav": "數據問題",
- "masterDataIssue_MISSING_BOM_CODE": "BOM 編號為空",
- "masterDataIssue_MISSING_BOM_NAME": "BOM 名稱為空",
- "masterDataIssue_MISSING_ITEM": "關聯貨品不存在或已刪除",
- "masterDataIssue_MISSING_BASE_UOM": "缺少基本單位",
- "masterDataIssue_MISSING_SALES_UOM": "缺少銷售單位",
- "masterDataIssue_MISSING_STOCK_UOM": "缺少庫存單位",
- "masterDataIssue_MISSING_PICKING_UOM": "缺少揀貨單位",
- "masterDataIssue_MISSING_PURCHASE_UOM": "缺少採購單位",
- "masterDataIssue_DELETED_BASE_UOM": "基本單位已刪除",
- "masterDataIssue_DELETED_SALES_UOM": "銷售單位已刪除",
- "masterDataIssue_DELETED_STOCK_UOM": "庫存單位已刪除",
- "masterDataIssue_DELETED_PURCHASE_UOM": "採購單位已刪除",
- "masterDataIssue_MISSING_BASE_UOM_CONVERSION": "基本單位缺少或已刪除 UOM 換算",
- "masterDataIssue_MISSING_SALES_UOM_CONVERSION": "銷售單位缺少或已刪除 UOM 換算",
- "masterDataIssue_MISSING_STOCK_UOM_CONVERSION": "庫存單位缺少或已刪除 UOM 換算",
- "masterDataIssue_MISSING_PICKING_UOM_CONVERSION": "揀貨單位缺少或已刪除 UOM 換算",
- "masterDataIssue_MISSING_PURCHASE_UOM_CONVERSION": "採購單位缺少或已刪除 UOM 換算",
- "masterDataIssue_MISSING_UOM_CONVERSION": "缺少或已刪除 UOM 換算",
- "masterDataIssue_MISSING_STOCK_UOM_CONVERSION": "庫存單位缺少或已刪除 UOM 換算",
- "masterDataIssue_MULTIPLE_BASE_UOM": "多筆基本單位設定",
- "masterDataIssue_MULTIPLE_SALES_UOM": "多筆銷售單位設定",
- "masterDataIssue_MULTIPLE_STOCK_UOM": "多筆庫存單位設定",
- "masterDataIssue_MULTIPLE_PICKING_UOM": "多筆揀貨單位設定",
- "masterDataIssue_MULTIPLE_PURCHASE_UOM": "多筆採購單位設定",
- "masterDataIssue_BOM_OUTPUT_UOM_MISMATCH_SALES": "BOM 產出單位與成品銷售單位不一致",
- "masterDataIssue_BOM_OUTPUT_UOM_TEXT_DRIFT": "BOM 產出單位文字與 UOM 主檔不一致",
- "masterDataIssue_BOM_MATERIAL_MISSING_ITEM": "BOM 原料貨品不存在或已刪除",
- "masterDataIssue_BOM_MATERIAL_SALES_UOM_MISMATCH": "BOM 原料銷售單位與貨品主檔不一致",
- "masterDataIssue_BOM_MATERIAL_BASE_UOM_MISMATCH": "BOM 原料基本單位與貨品主檔不一致",
- "masterDataIssue_BOM_MATERIAL_STOCK_UOM_MISMATCH": "BOM 原料庫存單位與貨品主檔不一致",
- "masterDataIssue_BOM_MATERIAL_UOM_FK_INVALID": "BOM 原料 UOM 參照無效或已刪除",
-
- "masterDataIssue_group_count": "共 {{groups}} 筆 · {{issues}} 項問題",
- "masterDataIssue_col_subject": "主體",
- "masterDataIssue_col_summary": "問題摘要",
- "masterDataIssue_col_actions": "操作",
- "masterDataIssue_viewDetail": "查看詳情",
- "masterDataIssue_close": "關閉",
- "masterDataIssue_detail_subtitle": "共 {{count}} 項問題",
- "masterDataIssue_detail_usedInBom": "出現於 BOM",
- "masterDataIssue_issueCount": "{{count}} 項",
- "masterDataIssue_fgItem": "成品貨品",
- "masterDataIssue_usedInBom": "用於 {{count}} 個 BOM:{{codes}}",
- "masterDataIssue_bomMore": " 等 {{count}} 個",
-
- "masterDataIssue_col_problem": "問題",
- "masterDataIssue_col_bom_uom": "BOM 單位",
- "masterDataIssue_col_item_uom": "M18 單位",
- "masterDataIssue_modifiedAt": "修改時間",
- "masterDataIssue_unit_active": "使用中",
- "masterDataIssue_unit_inactive": "已停用",
- "masterDataIssue_unit_missing": "沒有單位",
- "masterDataIssue_filter_type": "類型",
- "masterDataIssue_unit_base": "基本單位",
- "masterDataIssue_unit_sales": "銷售單位",
- "masterDataIssue_unit_stock": "庫存單位",
- "masterDataIssue_unit_picking": "揀貨單位",
- "masterDataIssue_unit_purchase": "採購單位",
- "masterDataIssue_unit_output": "產出單位",
- "masterDataIssue_line_itemMissing": "缺少:{{units}}",
- "masterDataIssue_line_itemGeneric": "{{problem}}(應為「{{expected}}」,實際「{{actual}}」)",
- "masterDataIssue_line_uomBoth": "{{bom}}:銷售/庫存單位應為「{{expected}}」,BOM 為「{{actual}}」",
- "masterDataIssue_line_uomSales": "{{bom}}:銷售單位應為「{{expected}}」,BOM 為「{{actual}}」",
- "masterDataIssue_line_uomStock": "{{bom}}:庫存單位應為「{{expected}}」,BOM 為「{{actual}}」",
- "masterDataIssue_line_outputUom": "{{bom}}:產出單位應為「{{expected}}」,BOM 為「{{actual}}」",
- "masterDataIssue_line_outputText": "{{bom}}:產出單位文字應為「{{expected}}」,BOM 為「{{actual}}」",
- "masterDataIssue_line_missingUnits": "{{bom}}:缺少 {{units}}",
- "masterDataIssue_line_generic": "{{bom}}:{{problem}}(應為「{{expected}}」,實際「{{actual}}」)",
- "masterDataIssue_line_problemOnly": "{{bom}}:{{problem}}",
- "masterDataIssue_detail_uomBoth": "銷售/庫存單位與主檔不一致",
- "masterDataIssue_detail_uomSales": "銷售單位與主檔不一致",
- "masterDataIssue_detail_uomStock": "庫存單位與主檔不一致",
- "masterDataIssue_detail_uomBase": "基本單位與主檔不一致",
- "masterDataIssue_materialUsedInBom": "用於 BOM:{{codes}}",
- "masterDataIssue_line_pairBoth": "銷售/庫存單位應為「{{expected}}」,BOM 為「{{actual}}」",
- "masterDataIssue_line_pairSales": "銷售單位應為「{{expected}}」,BOM 為「{{actual}}」",
- "masterDataIssue_line_pairStock": "庫存單位應為「{{expected}}」,BOM 為「{{actual}}」",
- "masterDataIssue_line_pairBase": "基本單位應為「{{expected}}」,BOM 為「{{actual}}」"
-}
\ No newline at end of file
+ "Current Stock": "現有庫存",
+ "masterDataIssue": "BOM/貨品單位問題",
+ "masterDataIssue_pageTitle": "BOM/貨品單位問題",
+ "masterDataIssue_tab_bom": "BOM",
+ "masterDataIssue_tab_item": "貨品",
+ "masterDataIssue_count": "共 {{count}} 筆問題",
+ "masterDataIssue_search": "搜索",
+ "masterDataIssue_refresh": "重新檢查",
+ "masterDataIssue_refreshing": "檢查中…",
+ "masterDataIssue_copy": "複製清單",
+ "masterDataIssue_empty": "目前沒有問題。",
+ "masterDataIssue_loadFailed": "無法載入問題清單,請稍後再試。",
+ "masterDataIssue_filter_all": "全部",
+ "masterDataIssue_material": "原料",
+ "masterDataIssue_col_scope": "範圍",
+ "masterDataIssue_col_bom": "BOM",
+ "masterDataIssue_col_item": "貨品",
+ "masterDataIssue_col_issue": "問題",
+ "masterDataIssue_col_expected": "應為",
+ "masterDataIssue_col_actual": "實際",
+ "masterDataIssue_scope_BOM": "BOM 總表",
+ "masterDataIssue_scope_BOM_MATERIAL": "BOM 原材料",
+ "masterDataIssue_scope_ITEM": "貨品",
+ "masterDataIssue_nav": "BOM/貨品單位問題",
+ "masterDataIssue_MISSING_BOM_CODE": "BOM 編號為空",
+ "masterDataIssue_MISSING_BOM_NAME": "BOM 名稱為空",
+ "masterDataIssue_MISSING_ITEM": "關聯貨品不存在或已刪除",
+ "masterDataIssue_MISSING_BASE_UOM": "缺少基本單位",
+ "masterDataIssue_MISSING_SALES_UOM": "缺少銷售單位",
+ "masterDataIssue_MISSING_STOCK_UOM": "缺少庫存單位",
+ "masterDataIssue_MISSING_PICKING_UOM": "缺少揀貨單位",
+ "masterDataIssue_MISSING_PURCHASE_UOM": "缺少採購單位",
+ "masterDataIssue_DELETED_BASE_UOM": "基本單位已刪除",
+ "masterDataIssue_DELETED_SALES_UOM": "銷售單位已刪除",
+ "masterDataIssue_DELETED_STOCK_UOM": "庫存單位已刪除",
+ "masterDataIssue_DELETED_PURCHASE_UOM": "採購單位已刪除",
+ "masterDataIssue_MISSING_BASE_UOM_CONVERSION": "基本單位缺少或已刪除 UOM 換算",
+ "masterDataIssue_MISSING_SALES_UOM_CONVERSION": "銷售單位缺少或已刪除 UOM 換算",
+ "masterDataIssue_MISSING_STOCK_UOM_CONVERSION": "庫存單位缺少或已刪除 UOM 換算",
+ "masterDataIssue_MISSING_PICKING_UOM_CONVERSION": "揀貨單位缺少或已刪除 UOM 換算",
+ "masterDataIssue_MISSING_PURCHASE_UOM_CONVERSION": "採購單位缺少或已刪除 UOM 換算",
+ "masterDataIssue_MISSING_UOM_CONVERSION": "缺少或已刪除 UOM 換算",
+ "masterDataIssue_MULTIPLE_BASE_UOM": "多筆基本單位設定",
+ "masterDataIssue_MULTIPLE_SALES_UOM": "多筆銷售單位設定",
+ "masterDataIssue_MULTIPLE_STOCK_UOM": "多筆庫存單位設定",
+ "masterDataIssue_MULTIPLE_PICKING_UOM": "多筆揀貨單位設定",
+ "masterDataIssue_MULTIPLE_PURCHASE_UOM": "多筆採購單位設定",
+ "masterDataIssue_BOM_OUTPUT_UOM_MISMATCH_SALES": "BOM 產出單位與成品銷售單位不一致",
+ "masterDataIssue_BOM_OUTPUT_UOM_TEXT_DRIFT": "BOM 產出單位文字與 UOM 主檔不一致",
+ "masterDataIssue_BOM_MATERIAL_MISSING_ITEM": "BOM 原料貨品不存在或已刪除",
+ "masterDataIssue_BOM_MATERIAL_SALES_UOM_MISMATCH": "BOM 原料銷售單位與貨品主檔不一致",
+ "masterDataIssue_BOM_MATERIAL_BASE_UOM_MISMATCH": "BOM 原料基本單位與貨品主檔不一致",
+ "masterDataIssue_BOM_MATERIAL_STOCK_UOM_MISMATCH": "BOM 原料庫存單位與貨品主檔不一致",
+ "masterDataIssue_BOM_MATERIAL_UOM_FK_INVALID": "BOM 原料 UOM 參照無效或已刪除",
+ "masterDataIssue_group_count": "共 {{groups}} 筆 · {{issues}} 項問題",
+ "masterDataIssue_col_subject": "主體",
+ "masterDataIssue_col_summary": "問題摘要",
+ "masterDataIssue_col_actions": "操作",
+ "masterDataIssue_viewDetail": "查看詳情",
+ "masterDataIssue_close": "關閉",
+ "masterDataIssue_detail_subtitle": "共 {{count}} 項問題",
+ "masterDataIssue_detail_usedInBom": "出現於 BOM",
+ "masterDataIssue_issueCount": "{{count}} 項",
+ "masterDataIssue_fgItem": "成品貨品",
+ "masterDataIssue_usedInBom": "用於 {{count}} 個 BOM:{{codes}}",
+ "masterDataIssue_bomMore": " 等 {{count}} 個",
+ "masterDataIssue_col_problem": "問題",
+ "masterDataIssue_col_bom_uom": "BOM 單位",
+ "masterDataIssue_col_item_uom": "M18 單位",
+ "masterDataIssue_modifiedAt": "修改時間",
+ "masterDataIssue_unit_active": "使用中",
+ "masterDataIssue_unit_inactive": "已停用",
+ "masterDataIssue_unit_missing": "沒有單位",
+ "masterDataIssue_filter_type": "類型",
+ "masterDataIssue_unit_base": "基本單位",
+ "masterDataIssue_unit_sales": "銷售單位",
+ "masterDataIssue_unit_stock": "庫存單位",
+ "masterDataIssue_unit_picking": "揀貨單位",
+ "masterDataIssue_unit_purchase": "採購單位",
+ "masterDataIssue_unit_output": "產出單位",
+ "masterDataIssue_line_itemMissing": "缺少:{{units}}",
+ "masterDataIssue_line_itemGeneric": "{{problem}}(應為「{{expected}}」,實際「{{actual}}」)",
+ "masterDataIssue_line_uomBoth": "{{bom}}:銷售/庫存單位應為「{{expected}}」,BOM 為「{{actual}}」",
+ "masterDataIssue_line_uomSales": "{{bom}}:銷售單位應為「{{expected}}」,BOM 為「{{actual}}」",
+ "masterDataIssue_line_uomStock": "{{bom}}:庫存單位應為「{{expected}}」,BOM 為「{{actual}}」",
+ "masterDataIssue_line_outputUom": "{{bom}}:產出單位應為「{{expected}}」,BOM 為「{{actual}}」",
+ "masterDataIssue_line_outputText": "{{bom}}:產出單位文字應為「{{expected}}」,BOM 為「{{actual}}」",
+ "masterDataIssue_line_missingUnits": "{{bom}}:缺少 {{units}}",
+ "masterDataIssue_line_generic": "{{bom}}:{{problem}}(應為「{{expected}}」,實際「{{actual}}」)",
+ "masterDataIssue_line_problemOnly": "{{bom}}:{{problem}}",
+ "masterDataIssue_detail_uomBoth": "銷售/庫存單位與主檔不一致",
+ "masterDataIssue_detail_uomSales": "銷售單位與主檔不一致",
+ "masterDataIssue_detail_uomStock": "庫存單位與主檔不一致",
+ "masterDataIssue_detail_uomBase": "基本單位與主檔不一致",
+ "masterDataIssue_materialUsedInBom": "用於 BOM:{{codes}}",
+ "masterDataIssue_line_pairBoth": "銷售/庫存單位應為「{{expected}}」,BOM 為「{{actual}}」",
+ "masterDataIssue_line_pairSales": "銷售單位應為「{{expected}}」,BOM 為「{{actual}}」",
+ "masterDataIssue_line_pairStock": "庫存單位應為「{{expected}}」,BOM 為「{{actual}}」",
+ "masterDataIssue_line_pairBase": "基本單位應為「{{expected}}」,BOM 為「{{actual}}」"
+}
diff --git a/src/i18n/zh/material.json b/src/i18n/zh/material.json
new file mode 100644
index 0000000..6aa2b4d
--- /dev/null
+++ b/src/i18n/zh/material.json
@@ -0,0 +1,4 @@
+{
+ "Material": "材料",
+ "Create Claim": "新增索賠"
+}
diff --git a/src/i18n/zh/navigation.json b/src/i18n/zh/navigation.json
new file mode 100644
index 0000000..8a48e09
--- /dev/null
+++ b/src/i18n/zh/navigation.json
@@ -0,0 +1,99 @@
+{
+ "menu": "選單",
+ "nav.bagPrint": "打袋機",
+ "nav.breadcrumb.bagPrint": "打袋機",
+ "nav.breadcrumb.chart": "圖表報告",
+ "nav.breadcrumb.chartDelivery": "發貨與配送",
+ "nav.breadcrumb.chartForecast": "預測與計劃",
+ "nav.breadcrumb.chartJobOrder": "工單",
+ "nav.breadcrumb.chartJobOrderBoard": "工單即時看板",
+ "nav.breadcrumb.chartPurchase": "採購",
+ "nav.breadcrumb.chartWarehouse": "庫存與倉儲",
+ "nav.breadcrumb.demandForecast": "需求預測設定",
+ "nav.breadcrumb.deliveryOrderFloor": "送貨單樓層",
+ "nav.breadcrumb.doWorkbenchEdit": "DO Workbench 詳情",
+ "nav.breadcrumb.doWorkbenchPick": "DO Workbench 揀貨",
+ "nav.breadcrumb.doWorkbenchSearch": "DO Workbench 搜索",
+ "nav.breadcrumb.equipment": "設備",
+ "nav.breadcrumb.equipmentMaintenanceEdit": "維護編輯",
+ "nav.breadcrumb.finishedGood": "成品出倉",
+ "nav.breadcrumb.finishedGoodManagement": "成品出倉管理",
+ "nav.breadcrumb.home": "總覽",
+ "nav.breadcrumb.importTesting": "匯入測試",
+ "nav.breadcrumb.inventory": "存貨",
+ "nav.breadcrumb.joEdit": "工單詳情",
+ "nav.breadcrumb.joTesting": "工單測試",
+ "nav.breadcrumb.joWorkbench": "工單工作台",
+ "nav.breadcrumb.laserPrint": "檸檬機(激光機)",
+ "nav.breadcrumb.m18Sync": "M18 同步",
+ "nav.breadcrumb.poEdit": "編輯",
+ "nav.breadcrumb.poWorkbench": "採購單工作台",
+ "nav.breadcrumb.priceInquiry": "價格查詢",
+ "nav.breadcrumb.printer": "列印機",
+ "nav.breadcrumb.projects": "專案",
+ "nav.breadcrumb.projectsCreate": "新增專案",
+ "nav.breadcrumb.qcItem": "QC 項目",
+ "nav.breadcrumb.qcItemAll": "QC 綜合管理",
+ "nav.breadcrumb.masterDataIssues": "BOM / 物料單位問題",
+ "nav.breadcrumb.qrCodeHandle": "二維碼列印及下載",
+ "nav.breadcrumb.report": "報告管理",
+ "nav.breadcrumb.routeBoard": "車線看板",
+ "nav.breadcrumb.schedulingDetailed": "詳細排程",
+ "nav.breadcrumb.schedulingDetailedEdit": "FG 生產排程",
+ "nav.breadcrumb.schedulingRough": "需求預測",
+ "nav.breadcrumb.schedulingRoughEdit": "成品及材料需求預測詳情",
+ "nav.breadcrumb.shop": "車線店鋪管理",
+ "nav.breadcrumb.shopDetail": "店鋪詳情",
+ "nav.breadcrumb.tasks": "任務範本",
+ "nav.breadcrumb.tasksCreate": "新增任務範本",
+ "nav.breadcrumb.truckLaneDetail": "車線詳情",
+ "nav.chart.delivery": "發貨與配送",
+ "nav.chart.forecast": "預測與計劃",
+ "nav.chart.jobOrder": "工單",
+ "nav.chart.jobOrderBoard": "工單即時看板",
+ "nav.chart.purchase": "採購",
+ "nav.chart.warehouse": "庫存與倉儲",
+ "nav.chartReports": "圖表報告",
+ "nav.dashboard": "資訊展示面板",
+ "nav.deliveryOrder": "送貨訂單",
+ "nav.jobOrder.bagUsage": "包裝袋使用記錄",
+ "nav.jobOrder.pickExecution": "工單提料",
+ "nav.jobOrder.productionProcess": "工單生產流程",
+ "nav.jobOrder.searchCreate": "搜索工單/ 建立工單",
+ "nav.jobOrderManagement": "管理工單",
+ "nav.laserPrint": "檸檬機(激光機)",
+ "nav.m18Sync": "M18 同步",
+ "nav.productionServer": "正式伺服器",
+ "nav.report": "報告管理",
+ "nav.scheduling": "排程",
+ "nav.settings": "設定",
+ "nav.settings.bomWeighting": "BOM 權重得分",
+ "nav.settings.clientMonitor": "裝置連線監控",
+ "nav.settings.deliveryOrderFloor": "送貨單樓層(供應商)",
+ "nav.settings.demandForecast": "需求預測設定",
+ "nav.settings.equipment": "設備",
+ "nav.settings.importBom": "匯入 BOM",
+ "nav.settings.importExcel": "Excel 匯入",
+ "nav.settings.importTesting": "匯入測試",
+ "nav.settings.items": "物品",
+ "nav.settings.masterDataIssues": "BOM / 物料單位問題",
+ "nav.settings.priceInquiry": "價格查詢",
+ "nav.settings.printer": "列印機",
+ "nav.settings.qcCategory": "QC 品檢模板",
+ "nav.settings.qcItem": "QC 品檢項目",
+ "nav.settings.qcItemAll": "QC 綜合管理",
+ "nav.settings.qrCodeHandle": "二維碼列印及下載",
+ "nav.settings.shopAndTruck": "車線店鋪管理",
+ "nav.settings.user": "用戶",
+ "nav.settings.warehouse": "倉庫",
+ "nav.store.doWorkbench": "新版成品出倉",
+ "nav.store.finishedGoodManagement": "成品出倉管理",
+ "nav.store.inventoryLedger": "查看物品出入庫及庫存日誌",
+ "nav.store.pickOrder": "提料單",
+ "nav.store.purchaseOrder": "採購單",
+ "nav.store.putAwayScan": "上架掃碼",
+ "nav.store.stockIssue": "出倉問題",
+ "nav.store.stockRecord": "庫存記錄",
+ "nav.store.stockTake": "盤點管理",
+ "nav.storeManagement": "倉庫管理"
+}
diff --git a/src/i18n/zh/pickOrder.json b/src/i18n/zh/pickOrder.json
index 5a410fd..846ddbd 100644
--- a/src/i18n/zh/pickOrder.json
+++ b/src/i18n/zh/pickOrder.json
@@ -1,532 +1,521 @@
- {
- "Purchase Order": "採購訂單",
- "Code": "編號",
- "Pick Order Code": "提料單編號",
- "Item Code": "貨品編號",
- "OrderDate": "下單日期",
- "Details": "詳情",
- "Supplier": "供應商",
- "Status": "來貨狀態",
- "N/A": "不適用",
- "Release Pick Orders": "放單",
- "released": "已放單",
- "Loading...": "載入中...",
- "Suggestion success": "建議成功",
- "Scan pick success": "掃描提料成功",
- "Remark": "備註",
- "Available Qty": "可用數量",
- "Picked Qty": "已提料數量",
- "Escalated": "上報狀態",
- "NotEscalated": "無上報",
- "Assigned To": "已分配",
- "Progress": "進度",
- "Select Remark": "選擇備註",
- "Just Complete": "已完成",
- "Skip": "跳過",
- "if need just edit number, please scan the lot again": "如果需要只修改數量,請重新掃描批次。",
- "Total qty (actual pick + miss + bad) cannot exceed available qty: {available}": "總數量(實際提料 + 遺失 + 不良)不能超過可用數量:{{available}}",
- "Confirm Assignment": "確認分配",
- "Required Date": "所需日期",
- "Store": "位置",
- "Available Orders": "可用訂單",
- "This lot is rejected, please scan another lot.": "此批次已拒收,請掃描另一個批次。",
- "Lane Code": "車線號碼",
- "Fetching all matching records...": "正在獲取所有匹配的記錄...",
- "Edit": "改數",
- "Submit Qty": "提交數量",
- "Suggestion success": "建議成功",
- "Just Completed": "已完成",
- "Just Completed (workbench): requires a valid lot number and quantity; expired rows must not use this button.": "已完成(工作台):需有效批號與可提交數量;過期列請勿使用此按鈕。",
- "Do you want to start?": "確定開始嗎?",
- "Start": "開始",
- "Pick Order Code(s)": "提料單編號",
- "Delivery Order Code(s)": "提料單編號",
- "Start Success": "開始成功",
- "Qty will submit": "提交數量",
- "Truck Lance Code": "車線號碼",
- "Pick Order Codes": "提料單編號",
- "Pick Order Lines": "提料單行數",
- "Delivery Order Codes": "提料單編號",
- "Delivery Order Lines": "送貨單行數",
- "Lines Per Pick Order": "每提料單行數",
- "Pick Orders Details": "提料單詳情",
- "Lines": "行數",
- "Before Today": "以前",
- "Truck X": "車線-X",
- "Finsihed good items": "成品項目",
- "kinds": "款",
- "Completed Date": "完成日期",
- "Completed Time": "完成時間",
- "Delivery Order": "送貨單",
- "items": "項目",
- "Select Pick Order:": "選擇提料單:",
- "No Stock Available": "沒有庫存",
- "is expired. Please check around have available QR code or not.": "已過期。請檢查周圍是否有可用的 QR 碼。",
- "Start Fail": "開始失敗",
- "Start PO": "開始採購訂單",
- "Do you want to complete?": "確定完成嗎?",
- "Complete": "完成",
- "Complete Success": "完成成功",
- "Complete Fail": "完成失敗",
- "Complete Pick Order": "完成提料單",
- "General": "一般",
- "Bind Storage": "綁定倉位",
- "itemNo": "貨品編號",
- "itemName": "貨品名稱",
- "qty": "訂單數",
- "Require Qty": "需求數",
- "uom": "計量單位",
- "total weight": "總重量",
- "weight unit": "重量單位",
- "price": "訂單貨值",
- "processed": "已入倉",
- "expiryDate": "到期日",
- "acceptedQty": "是次訂單/來貨/巳來貨數",
- "weight": "重量",
- "start": "開始",
- "qc": "質量控制",
- "escalation": "上報",
- "stock in": "入庫",
- "putaway": "上架",
- "delete": "刪除",
- "qty cannot be greater than remaining qty": "數量不能大於剩餘數",
- "Record pol": "記錄採購訂單",
- "Add some entries!": "請添加條目",
- "draft": "草稿",
- "pending": "待處理",
- "determine1": "上報1",
- "determine2": "上報2",
- "determine3": "上報3",
- "receiving": "收貨中",
- "received": "已收貨",
- "completed": "已完成",
- "rejected": "已拒絕",
- "success": "成功",
- "acceptedQty must not greater than": "接受數量不得大於",
- "minimal value is 1": "最小值為1",
- "value must be a number": "值必須是數字",
- "qc Check": "質量控制檢查",
- "Please select QC": "請選擇質量控制",
- "failQty": "失敗數",
- "select qc": "選擇質量控制",
- "enter a failQty": "請輸入失敗數",
- "qty too big": "數量過大",
- "sampleRate": "抽樣率",
- "sampleWeight": "樣本重量",
- "totalWeight": "總重量",
-
- "Escalation": "上報",
- "to be processed": "待處理",
-
- "Stock In Detail": "入庫詳情",
- "productLotNo": "產品批號",
- "receiptDate": "收貨日期",
- "acceptedWeight": "接受重量",
- "productionDate": "生產日期",
-
- "reportQty": "上報數",
-
- "Default Warehouse": "預設倉庫",
- "Select warehouse": "選擇倉庫",
- "Putaway Detail": "上架詳情",
- "LotNo": "批號",
- "Po Code": "採購訂單編號",
- "No Warehouse": "沒有倉庫",
- "Please scan warehouse qr code.": "請掃描倉庫 QR 碼。",
-
- "Reject": "拒絕",
- "submit": "確認提交",
- "print": "列印",
- "bind": "綁定",
- "Total must equal Required Qty. Missing: {diff}": "總數量必須等於所需數量。缺少:{{diff}}",
- "Total must equal Required Qty. Exceeds by: {diff}": "總數量必須等於所需數量。超出:{{diff}}",
-
- "Batch": "批量",
- "Single": "單量",
- "Release Type": "放單類型",
- "isExtra order": "加單",
- "Etra": "加單",
- "Exit Etra view": "離開加單檢視",
- "Etra Pick Order Detail": "加單",
- "Etra incomplete badge tooltip": "當日未完成加單票:{{count}} 張(待處理/已發佈,不含已結案)",
- "Etra incomplete badge tooltip none": "目前無未完成加單票",
- "Back to normal assign tab": "返回一般指派分頁",
- "Enter isExtra workbench view?": "進入加單檢視?",
- "Etra view groups all add-on tickets by shop and lane for the selected date.": "加單檢視會依選定日期,將 isExtra 票依店鋪與車線顯示。",
- "Etra Ticket Notice": "目前是加單票,顯示與操作已切換為加單模式。",
-
- "Pick Order": "提料單",
- "Type": "類型",
- "Product Type": "貨品類型",
- "Reset": "重置",
- "Search": "搜索",
- "Pick Orders": "提料單",
- "Consolidated Pick Orders": "合併提料單",
- "Pick Order No.": "提料單編號",
- "Pick Order Date": "提料單日期",
- "Pick Order Status": "提貨狀態",
- "Pick Order Type": "提料單類型",
- "Consolidated Code": "合併編號",
- "type": "類型",
- "Items": "項目",
- "Target Date": "需求日期",
- "Released By": "發佈者",
- "Target Date From": "目標日期",
- "Target Date To": "目標日期到",
- "Consolidate": "合併",
- "Stock Unit": "庫存單位",
- "create": "新增",
- "detail": "詳情",
- "Pick Order Detail": "撳單/提料單詳情",
- "item": "貨品",
- "Unit": "單位",
- "reset": "重置",
- "targetDate": "目標日期",
- "remove": "移除",
- "release": "發佈",
- "location": "位置",
- "suggestedLotNo": "建議批次",
- "lotNo": "批次",
- "item name": "貨品名稱",
- "Item Name": "貨品名稱",
- "approval": "審核",
- "lot change": "批次變更",
- "checkout": "出庫",
- "Search Items": "搜索貨品",
- "Search Results": "可選擇貨品",
- "Second Search Results": "第二搜索結果",
- "Second Search Items": "第二搜索項目",
- "Second Search": "第二搜索",
- "Item": "貨品",
- "Order Quantity": "貨品需求數",
- "Current Stock": "現時可用庫存",
- "Selected": "已選",
- "Select Items": "選擇貨品",
- "Assign": "分派提料單",
- "Release": "放單",
- "Pick Execution": "進行提料",
- "Create Pick Order": "建立貨品提料單",
- "Consumable": "消耗品",
- "Material": "食材",
- "Job Order": "工單",
- "End Product": "成品",
- "Lot Expiry Date": "到期日",
- "Lot Location": "位置",
- "Available Lot": "可用提料數",
- "Lot Required Pick Qty": "所需數",
- "Lot Actual Pick Qty": "此單將提數",
- "Lot#": "批號",
- "Submit": "提交",
- "Created Items": "已建立貨品",
- "Create New Group": "建立新提料分組",
- "Group": "分組",
- "Qty Already Picked": "已提料數",
- "Select Job Order Items": "選擇工單貨品",
- "failedQty": "不合格項目數",
- "remarks": "備註",
- "Qc items": "QC 項目",
- "qcItem": "QC 項目",
- "QC Info": "QC 資訊",
- "qcResult": "QC 結果",
- "acceptQty": "接受數",
- "Escalation History": "上報歷史",
- "Group Code": "分組編號",
- "Job Order Code": "工單編號",
- "QC Check": "QC 檢查",
- "QR Code Scan": "QR Code掃描",
- "Pick Order Details": "提料單詳情",
- "Partial quantity submitted. Please submit more or complete the order.": "已提料部分數量。請提交更多或完成訂單。",
- "Pick order completed successfully!": "提料單完成成功!",
- "Lot has been rejected and marked as unavailable.": "批號已拒絕並標記為不可用。",
- "This order is insufficient, please pick another lot.": "此訂單不足,請選擇其他批號。",
- "Please finish QR code scan, QC check and pick order.": "請完成 QR 碼掃描、QC 檢查和提料。",
- "No data available": "沒有資料",
- "Please submit the pick order.": "請提交提料單。",
- "Item lot to be Pick:": "批次貨品提料:",
- "Report and Pick another lot": "上報並需重新選擇批號",
- "Accept Stock Out": "接受出庫",
- "Pick Another Lot": "欠數,並重新選擇批號",
- "Delivery Note Code": "送貨單編號",
- "A4 Printer": "A4 打印機",
- "Label Printer": "標籤打印機",
- "Please select a printer first": "請先選擇打印機",
- "Please select a label printer first": "請先選擇標籤打印機",
-
- "Lot No": "批號",
- "Expiry Date": "到期日",
- "Location": "位置",
- "All Pick Order Lots": "所有提料單批次",
- "Completed": "已完成",
- "Finished Good Order": "成品出倉",
- "Assign and Release": "分派並放單",
- "Original Available Qty": "原可用數",
- "Remaining Available Qty": "剩餘可用數",
- "Please submit pick order.": "請提交提料單。",
- "Please finish QR code scan and pick order.": "請完成 QR 碼掃描和提料。",
- "Please finish QR code scanand pick order.": "請完成 QR 碼掃描和提料。",
- "First created group": "首次建立分組",
- "Latest created group": "最新建立分組",
- "Manual Input": "手動輸入",
- "QR Code Scan for Lot": " QR 碼掃描批次",
- "Processing QR code...": "處理 QR 碼...",
- "The input is not the same as the expected lot number.": "輸入的批次號碼與預期的不符。",
- "Verified successfully!": "驗證成功!",
- "Cancel": "取消",
- "storing": "待品檢入倉",
- "pick successful": "提料成功",
- "Suggestion success": "建議成功",
- "Insufficient available quantity on lot (may have been picked by another user)": "掃描的批次已被其他用戶完全提料。請掃描其他批次。",
- "Scan": "掃描",
- "Before today": "今天之前",
- "Scanned": "已掃描",
- "Loading data...": "正在載入數據...",
- "No available stock for this item": "沒有可用庫存",
- "No lot details available for this item": "沒有批次詳情",
- "Current stock is insufficient or unavailable": "現時可用庫存不足或不可用",
- "Please check inventory status": "請檢查庫存狀態",
- "Rows per page": "每頁行數",
- "QR Scan Result:": "QR 掃描結果:",
- "Action": "操作",
- "Please finish pick order.": "請完成提料。",
- "Lot": "批號",
- "Assign Pick Orders": "分派提料單",
- "Selected Pick Orders": "已選擇提料單數量",
- "Please assgin/release the pickorders to picker": "請分派/放單提料單給提料員。",
- "Assign To": "分派給",
- "No Group": "沒有分組",
- "Selected items will join above created group": "已選擇的貨品將加入以上建立的分組",
- "Issue":"問題",
- "Pick Execution Issue Form":"提料問題表單",
- "Lot line is unavailable":"掃描批次不可用",
- "This form is for reporting issues only. You must report either missing items or bad items.":"此表單僅用於報告問題。您必須報告缺少的貨品或不良貨品。",
- "Bad item Qty":"不良貨品數量",
- "Missing item Qty":"貨品遺失數量",
- "Missing Item Qty":"貨品遺失數量",
- "Bad Item Qty":"不良貨品數量",
- "Bad Package Qty":"不良包裝數量",
- "Lot line is not available (status=UNAVAILABLE)":"掃描批次不可用",
- "Actual Pick Qty":"實際提料數量",
- "Required Qty":"所需數量",
- "Issue Remark":"問題描述",
- "Handler":"提料員",
- "Qty is required":"必需輸入數量",
- "Qty is not allowed to be greater than remaining available qty":"輸入數量不能大於剩餘可用數量",
- "Qty is not allowed to be greater than required qty":"輸入數量不能大於所需數量",
- "At least one issue must be reported":"至少需要報告一個問題",
- "issueRemark":"問題描述是必需的",
- "handler":"提料員",
- "Max":"最大值",
- "Route":"路線",
- "Index":"編號",
- "No FG pick orders found":"沒有成品提料單",
- "Finish Scan?":"完成掃描?",
- "Delivery Code":"出倉單編號",
- "Shop PO Code":"訂單編號",
- "Shop ID":"商店編號",
- "Truck No.":"車線編號",
- "Departure Time":"車線出發時間",
- "Shop Name":"商店名稱",
- "Shop Address":"商店地址",
- "Delivery Date":"目標日期",
- "Pick Execution 2/F":"進行提料 2/F",
- "Pick Execution 4/F":"進行提料 4/F",
- "Pick Execution Detail":"進行提料詳情",
- "Submit Required Pick Qty":"提交所需提料數量",
- "Scan Result":"掃描結果",
- "Ticket No.":"提票號碼",
- "Start QR Scan":"開始QR掃描",
- "Stop QR Scan":"停止QR掃描",
- "Scanning...":"掃描中...",
- "Print DN/Label":"列印送貨單/標籤",
- "Store ID":"儲存編號",
- "QR code does not match any item in current orders.":"QR 碼不符合當前訂單中的任何貨品。",
- "Lot Number Mismatch":"批次號碼不符",
- "The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?":"掃描的貨品與預期的貨品相同,但批次號碼不同。您是否要繼續使用不同的批次?",
- "The scanned item matches the expected item, but the lot number is different. Scan again to confirm: scan the expected lot QR to keep the suggested lot, or scan the other lot QR again to switch.":"掃描貨品相同但批次不同。請再掃描一次以確認:掃描「建議批次」的 QR 可沿用該批次;再掃描「另一批次」的 QR 則切換為該批次。",
- "Expected Lot:":"預期批次:",
- "Scanned Lot:":"掃描批次:",
- "Confirm":"確認",
- "Update your suggested lot to the this scanned lot":"更新您的建議批次為此掃描的批次",
- "Print Draft":"列印草稿",
- "Print Pick Order and DN Label":"列印提料單和送貨單標籤",
- "Print Pick Order":"列印提料單",
- "Print DN Label":"列印送貨單標籤",
- "Print All Draft" : "列印全部草稿",
- "If you confirm, the system will:":"如果您確認,系統將:",
- "After you scan to choose, the system will update the pick line to the lot you confirmed.":"確認後,系統會將您選擇的批次套用到對應提料行。",
- "Or use the Confirm button below if you cannot scan again (same as scanning the other lot again).":"若無法再掃描,可按下「確認」以切換為剛才掃描到的批次(與再掃一次該批次 QR 相同)。",
- "Lot switch failed":"批次切換失敗",
- "The system could not switch to the scanned lot. Review the lots below, then tap Confirm to retry.":"系統無法切換至掃描的批次。請核對下方批次後按「確認」重試。",
- "You can also scan again: expected lot QR keeps the suggested line; scanned lot QR retries the switch.":"您也可以再掃描:掃描建議批次 QR 可保留該行;掃描欲切換批次 QR 可再次嘗試切換。",
- "QR code verified.":"QR 碼驗證成功。",
- "Order Finished":"訂單完成",
- "Submitted Status":"提交狀態",
- "Pick Execution Record":"提料執行記錄",
- "Delivery No.":"送貨單編號",
- "Total":"總數",
- "Completed DO pick orders: ":"已完成送貨單提料單:",
- "No completed DO pick orders found":"沒有已完成送貨單提料單",
-
- "Enter the number of cartons: ": "請輸入總箱數",
- "Number of cartons": "箱數",
- "Select an action for the assigned pick orders.": "選擇分配提料單的動作。",
- "Detail": "詳情",
- "consoCode": "合併編號",
- "status": "狀態",
- "Items Included": "貨品包括",
- "Pick Order Included": "提料單包括",
- "No created items": "沒有已建立的貨品",
- "Please select item": "請選擇貨品",
- "enter a qty": "請輸入數量",
- "update qc info": "更新QC資訊",
- "All lots must be completed before printing": "所有批次必須完成才能打印",
- "Assigning pick order...": "分配提料單...",
- "Enter the number of cartons:": "請輸入總箱數",
- "Finished Good Detail": "成品提貨詳情",
- "Finished Good Record": "成品提貨記錄",
- "Finished Good Record (All)": "成品提貨記錄(全部)",
- "All dates": "全部日期",
- "Search date": "搜索日期",
- "Hide Completed: OFF": "完成: OFF",
- "Hide Completed: ON": "完成: ON",
- "Number must be at least 1": "數量至少為1",
- "Printed Successfully.": "成功列印",
- "Product": "產品",
- "You need to enter a number": "您需要輸入一個數字",
- "Available in warehouse": "在倉庫中可用",
- "Describe the issue with bad items": "描述不良貨品的問題",
- "Enter pick qty or issue qty": "請輸入提料數量或不良數量",
- "Invalid qty": "無效數量",
- "Note:": "注意:",
- "Qty is not allowed to be greater than required/available qty": "數量不能大於所需/可用數量",
- "Still need to pick": "仍需提料",
- "Total exceeds required qty": "總數超過所需數量",
- "submitting": "提交中",
- "Back to List": "返回列表",
- "Delivery No": "送貨單編號",
- "FG orders": "成品訂單",
- "View Details": "查看詳情",
- "No Item": "沒有貨品",
- "None": "沒有",
- "This form is for reporting issues only. You must report either missing items or bad items.": "此表單僅用於報告問題。您必須報告缺少的物品或不良物品。",
- "Add Selected Items to Created Items": "將已選擇的貨品添加到已建立的貨品中",
- "All pick orders created successfully": "所有提料單建立成功",
- "Failed to create group": "建立分組失敗",
- "Invalid date format": "日期格式無效",
- "Item already exists in created items": "貨品已存在於已建立的貨品中",
- "Job Order not found or has no items": "工單不存在或沒有貨品",
- "Loading...": "加載中",
- "No results found": "沒有結果",
- "Please enter at least code or name": "請輸入至少編號或名稱",
- "Please enter quantity for all selected items": "請輸入所有已選擇的貨品的數量",
- "Please select at least one item to submit": "請選擇至少一個貨品提交",
- "Please select group and enter quantity for all selected items": "請選擇分組並輸入所有已選擇的貨品的數量",
- "Please select group for all selected items": "請選擇分組對所有已選擇的貨品",
- "Please select product type": "請選擇產品類型",
- "Please select target date": "請選擇目標日期",
- "Please select type": "請選擇類型",
- "Search Criteria": "搜索條件",
- "Processing...": "處理中",
- "Failed items must have failed quantity": "不合格的貨品必須有不合格數量",
- "QC items without result": "QC項目沒有結果",
- "confirm putaway": "確認上架",
- "email supplier": "發送郵件給供應商",
- "qc processing": "QC處理",
- "submitStockIn": "提交入庫",
- "not default warehosue": "不是默認倉庫",
- "printQty": "打印數量",
- "Shop": "商店名稱",
- "warehouse": "倉庫",
- "Add Record": "添加記錄",
- "Clean Record": "清空記錄",
- "Select": "選擇",
- "Close": "關閉",
- "Truck": "車線",
- "Date": "日期",
- "Delivery Order Code": "送貨單編號",
- "Escalation Info": "升級信息",
- "Escalation Result": "升級結果",
- "acceptQty must not greater than": "接受數量不能大於",
- "supervisor": "主管",
- "No Qc": "沒有QC",
- "receivedQty": "接收數量",
- "stock in information": "入庫信息",
- "No Uom": "沒有單位",
- "Input quantity cannot exceed": "輸入數量不能超過",
- "Quantity cannot be negative": "數量不能為負數",
- "Enter bad item quantity (required if no missing items)": "請輸入不良數量(如果沒有缺少項目)",
- "Enter missing quantity (required if no bad items)": "請輸入缺少數量(如果沒有不良項目)",
- "Submit All Scanned": "提交所有已掃描項目",
- "Submitting...": "提交中...",
- "COMPLETED": "已完成",
- "Confirm print: (": "確認列印全部草稿?(總數量:",
- "piece(s))": "份)",
- "Printing...": "列印中",
- "Please wait...": "請稍後",
- "No available pick order(s) for this floor.": "此樓層沒有可用的提料單",
- "You already have a pick order in progess. Please complete it first before taking next pick order.": "請先完成目前的提料單,再提取下一張",
- "Error occurred during assignment.": "提料單分配錯誤",
- "Info": "消息",
- "Warning": "警告",
- "Error": "錯誤",
- "Batch Print": "批量列印",
- "No entries available": "該樓層未有需處理訂單",
- "Today": "是日",
- "Tomorrow": "翌日",
- "packaging": "提料中",
- "No Stock Available": "沒有庫存可用",
- "This lot is not available, please scan another lot.": "此批號不可用,請掃描其他批號。",
- "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "請檢查周圍是否有 QR 碼,可能有剛剛入庫、轉移入庫或轉移出庫的 QR 碼。",
- "Lot is expired (expiry={{expiry}})": "掃描批號已過期(到期日={{expiry}})",
- "Day After Tomorrow": "後日",
- "Lot line is unavailable": "掃描批次不可用",
- "Select Date": "請選擇日期",
- "Suggest Lot No.": "推薦批號",
- "Search by Shop": "搜索商店",
- "Search by Truck": "搜索貨車",
- "Print DN & Label": "列印提料單和送貨單標籤",
- "Print Label": "列印送貨單標籤",
- "Reprint Label(s)": "補印標籤",
- "Reprint DN Label": "補印送貨單標籤",
- "From carton": "起始箱號",
- "To carton": "結束箱號",
- "Total cartons on shipment": "總箱數",
- "From carton must be at least 1": "起始箱號必須至少為 1",
- "To carton must be greater than or equal to from carton": "結束箱號必須大於或等於起始箱號",
- "Total cartons on shipment must be at least 1": "總箱數必須至少為 1",
- "To carton cannot be greater than total cartons on shipment": "結束箱號不能大於總箱數",
- "Not Yet Finished Released Do Pick Orders": "未完成提料單",
- "Not yet finished released do pick orders": "未完成提料單",
- "Released orders not yet completed - click lane to select and assign": "未完成提料單- 點擊貨車班次選擇並分配",
- "Ticket Release Table": "查看提貨情況",
- "Please take one pick order before printing the draft.": "請先從「撳單/提料單詳情」頁面下方選取提料單,再列印草稿。",
- "No released pick order records found.": "目前沒有可用的提料單。",
- "EDT - Lane Code (Unassigned/Total)": "預計出發時間 - 貨車班次(未撳數/總單數)",
- "Floor ticket": "票別(樓層)",
- "2F ticket": "2/F 票",
- "4F ticket": "4/F 票",
- "4F lane panel legend": "貨車班次 — 裝載序(未撳數/總單數)",
- "Loading sequence n": "板{{n}}",
- "lot QR code": "批號 QR 碼",
- "label Printer" : "標籤打印機",
- "A4 Printer" : "A4 打印機",
- "Loading Sequence": "裝載序",
- "Ticket No": "提票號碼",
- "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated.": "掃描的庫存批行為「不可用」,無法換批或綁定;揀貨行未更新。",
- "is unavable. Please check around have available QR code or not.": "此批號不可用,請檢查周圍是否有可用的 QR 碼。",
- "Lot switch failed; pick line was not marked as checked.": "換批失敗;揀貨行未標為已核對。",
- "Lot confirmation failed. Please try again.": "確認批號失敗,請重試。",
- "Powder Mixture": "箱料粉",
- "This lot is not yet putaway": "此批次尚未上架",
- "Cannot resolve new inventory lot line": "無法解析新批號庫存行(請確認已上架且資料正確)。",
- "Pick order line item is null": "提料單行未關聯物料。",
- "New lot line item does not match pick order line item": "新批號行的物料與提料單行不一致。",
- "Pick order line {{id}} not found": "找不到有關提料單行的資料。",
- "SuggestedPickLot not found for pickOrderLineId {{polId}}": "找不到該提料單行的建議揀貨批",
- "SuggestedPickLot qty is invalid: {{qty}}": "建議揀貨數量無效:{{qty}}。",
- "Reject switch lot: available {{available}} less than required {{required}}": "此批次貨品已被其他送貨單留起,請掃描其他批次。",
- "Reject switch lot: picked {{picked}} already greater or equal required {{required}}": "換批被拒:已揀數量({{picked}})已達或超過建議量({{required}}),無法再拆分換批。",
- "Lot status is unavailable. Cannot switch or bind; pick line was not updated.": "批號狀態為「不可用」,無法換批或綁定;揀貨行未更新。",
- "No lot rows. Select a line in the table above.": "尚無批號資料。請在上方表格勾選一行提料單明細。",
- "No stock out line for this lot": "此批號尚無出庫行,無法提交。"
- }
\ No newline at end of file
+{
+ "Purchase Order": "採購訂單",
+ "Code": "編號",
+ "Pick Order Code": "提料單編號",
+ "Item Code": "貨品編號",
+ "OrderDate": "下單日期",
+ "Details": "詳情",
+ "Supplier": "供應商",
+ "Status": "來貨狀態",
+ "N/A": "不適用",
+ "Release Pick Orders": "放單",
+ "released": "已放單",
+ "Loading...": "加載中",
+ "Suggestion success": "建議成功",
+ "Scan pick success": "掃描提料成功",
+ "Remark": "備註",
+ "Available Qty": "可用數量",
+ "Picked Qty": "已提料數量",
+ "Escalated": "上報狀態",
+ "NotEscalated": "無上報",
+ "Assigned To": "已分配",
+ "Progress": "進度",
+ "Select Remark": "選擇備註",
+ "Just Complete": "已完成",
+ "Skip": "跳過",
+ "if need just edit number, please scan the lot again": "如果需要只修改數量,請重新掃描批次。",
+ "Total qty (actual pick + miss + bad) cannot exceed available qty: {available}": "總數量(實際提料 + 遺失 + 不良)不能超過可用數量:{{available}}",
+ "Confirm Assignment": "確認分配",
+ "Required Date": "所需日期",
+ "Store": "位置",
+ "Available Orders": "可用訂單",
+ "This lot is rejected, please scan another lot.": "此批次已拒收,請掃描另一個批次。",
+ "Lane Code": "車線號碼",
+ "Fetching all matching records...": "正在獲取所有匹配的記錄...",
+ "Edit": "改數",
+ "Submit Qty": "提交數量",
+ "Just Completed": "已完成",
+ "Just Completed (workbench): requires a valid lot number and quantity; expired rows must not use this button.": "已完成(工作台):需有效批號與可提交數量;過期列請勿使用此按鈕。",
+ "Do you want to start?": "確定開始嗎?",
+ "Start": "開始",
+ "Pick Order Code(s)": "提料單編號",
+ "Delivery Order Code(s)": "提料單編號",
+ "Start Success": "開始成功",
+ "Qty will submit": "提交數量",
+ "Truck Lance Code": "車線號碼",
+ "Pick Order Codes": "提料單編號",
+ "Pick Order Lines": "提料單行數",
+ "Delivery Order Codes": "提料單編號",
+ "Delivery Order Lines": "送貨單行數",
+ "Lines Per Pick Order": "每提料單行數",
+ "Pick Orders Details": "提料單詳情",
+ "Lines": "行數",
+ "Before Today": "以前",
+ "Truck X": "車線-X",
+ "Finsihed good items": "成品項目",
+ "kinds": "款",
+ "Completed Date": "完成日期",
+ "Completed Time": "完成時間",
+ "Delivery Order": "送貨單",
+ "items": "項目",
+ "Select Pick Order:": "選擇提料單:",
+ "No Stock Available": "沒有庫存可用",
+ "is expired. Please check around have available QR code or not.": "已過期。請檢查周圍是否有可用的 QR 碼。",
+ "Start Fail": "開始失敗",
+ "Start PO": "開始採購訂單",
+ "Do you want to complete?": "確定完成嗎?",
+ "Complete": "完成",
+ "Complete Success": "完成成功",
+ "Complete Fail": "完成失敗",
+ "Complete Pick Order": "完成提料單",
+ "General": "一般",
+ "Bind Storage": "綁定倉位",
+ "itemNo": "貨品編號",
+ "itemName": "貨品名稱",
+ "qty": "訂單數",
+ "Require Qty": "需求數",
+ "uom": "計量單位",
+ "total weight": "總重量",
+ "weight unit": "重量單位",
+ "price": "訂單貨值",
+ "processed": "已入倉",
+ "expiryDate": "到期日",
+ "acceptedQty": "是次訂單/來貨/巳來貨數",
+ "weight": "重量",
+ "start": "開始",
+ "qc": "質量控制",
+ "escalation": "上報",
+ "stock in": "入庫",
+ "putaway": "上架",
+ "delete": "刪除",
+ "qty cannot be greater than remaining qty": "數量不能大於剩餘數",
+ "Record pol": "記錄採購訂單",
+ "Add some entries!": "請添加條目",
+ "draft": "草稿",
+ "pending": "待處理",
+ "determine1": "上報1",
+ "determine2": "上報2",
+ "determine3": "上報3",
+ "receiving": "收貨中",
+ "received": "已收貨",
+ "completed": "已完成",
+ "rejected": "已拒絕",
+ "success": "成功",
+ "acceptedQty must not greater than": "接受數量不得大於",
+ "minimal value is 1": "最小值為1",
+ "value must be a number": "值必須是數字",
+ "qc Check": "質量控制檢查",
+ "Please select QC": "請選擇質量控制",
+ "failQty": "失敗數",
+ "select qc": "選擇質量控制",
+ "enter a failQty": "請輸入失敗數",
+ "qty too big": "數量過大",
+ "sampleRate": "抽樣率",
+ "sampleWeight": "樣本重量",
+ "totalWeight": "總重量",
+ "Escalation": "上報",
+ "to be processed": "待處理",
+ "Stock In Detail": "入庫詳情",
+ "productLotNo": "產品批號",
+ "receiptDate": "收貨日期",
+ "acceptedWeight": "接受重量",
+ "productionDate": "生產日期",
+ "reportQty": "上報數",
+ "Default Warehouse": "預設倉庫",
+ "Select warehouse": "選擇倉庫",
+ "Putaway Detail": "上架詳情",
+ "LotNo": "批號",
+ "Po Code": "採購訂單編號",
+ "No Warehouse": "沒有倉庫",
+ "Please scan warehouse qr code.": "請掃描倉庫 QR 碼。",
+ "Reject": "拒絕",
+ "submit": "確認提交",
+ "print": "列印",
+ "bind": "綁定",
+ "Total must equal Required Qty. Missing: {diff}": "總數量必須等於所需數量。缺少:{{diff}}",
+ "Total must equal Required Qty. Exceeds by: {diff}": "總數量必須等於所需數量。超出:{{diff}}",
+ "Batch": "批量",
+ "Single": "單量",
+ "Release Type": "放單類型",
+ "isExtra order": "加單",
+ "Etra": "加單",
+ "Exit Etra view": "離開加單檢視",
+ "Etra Pick Order Detail": "加單",
+ "Etra incomplete badge tooltip": "當日未完成加單票:{{count}} 張(待處理/已發佈,不含已結案)",
+ "Etra incomplete badge tooltip none": "目前無未完成加單票",
+ "Back to normal assign tab": "返回一般指派分頁",
+ "Enter isExtra workbench view?": "進入加單檢視?",
+ "Etra view groups all add-on tickets by shop and lane for the selected date.": "加單檢視會依選定日期,將 isExtra 票依店鋪與車線顯示。",
+ "Etra Ticket Notice": "目前是加單票,顯示與操作已切換為加單模式。",
+ "Pick Order": "提料單",
+ "Type": "類型",
+ "Product Type": "貨品類型",
+ "Reset": "重置",
+ "Search": "搜索",
+ "Pick Orders": "提料單",
+ "Consolidated Pick Orders": "合併提料單",
+ "Pick Order No.": "提料單編號",
+ "Pick Order Date": "提料單日期",
+ "Pick Order Status": "提貨狀態",
+ "Pick Order Type": "提料單類型",
+ "Consolidated Code": "合併編號",
+ "type": "類型",
+ "Items": "項目",
+ "Target Date": "需求日期",
+ "Released By": "發佈者",
+ "Target Date From": "目標日期",
+ "Target Date To": "目標日期到",
+ "Consolidate": "合併",
+ "Stock Unit": "庫存單位",
+ "create": "新增",
+ "detail": "詳情",
+ "Pick Order Detail": "撳單/提料單詳情",
+ "item": "貨品",
+ "Unit": "單位",
+ "reset": "重置",
+ "targetDate": "目標日期",
+ "remove": "移除",
+ "release": "發佈",
+ "location": "位置",
+ "suggestedLotNo": "建議批次",
+ "lotNo": "批次",
+ "item name": "貨品名稱",
+ "Item Name": "貨品名稱",
+ "approval": "審核",
+ "lot change": "批次變更",
+ "checkout": "出庫",
+ "Search Items": "搜索貨品",
+ "Search Results": "可選擇貨品",
+ "Second Search Results": "第二搜索結果",
+ "Second Search Items": "第二搜索項目",
+ "Second Search": "第二搜索",
+ "Item": "貨品",
+ "Order Quantity": "貨品需求數",
+ "Current Stock": "現時可用庫存",
+ "Selected": "已選",
+ "Select Items": "選擇貨品",
+ "Assign": "分派提料單",
+ "Release": "放單",
+ "Pick Execution": "進行提料",
+ "Create Pick Order": "建立貨品提料單",
+ "Consumable": "消耗品",
+ "Material": "食材",
+ "Job Order": "工單",
+ "End Product": "成品",
+ "Lot Expiry Date": "到期日",
+ "Lot Location": "位置",
+ "Available Lot": "可用提料數",
+ "Lot Required Pick Qty": "所需數",
+ "Lot Actual Pick Qty": "此單將提數",
+ "Lot#": "批號",
+ "Submit": "提交",
+ "Created Items": "已建立貨品",
+ "Create New Group": "建立新提料分組",
+ "Group": "分組",
+ "Qty Already Picked": "已提料數",
+ "Select Job Order Items": "選擇工單貨品",
+ "failedQty": "不合格項目數",
+ "remarks": "備註",
+ "Qc items": "QC 項目",
+ "qcItem": "QC 項目",
+ "QC Info": "QC 資訊",
+ "qcResult": "QC 結果",
+ "acceptQty": "接受數",
+ "Escalation History": "上報歷史",
+ "Group Code": "分組編號",
+ "Job Order Code": "工單編號",
+ "QC Check": "QC 檢查",
+ "QR Code Scan": "QR Code掃描",
+ "Pick Order Details": "提料單詳情",
+ "Partial quantity submitted. Please submit more or complete the order.": "已提料部分數量。請提交更多或完成訂單。",
+ "Pick order completed successfully!": "提料單完成成功!",
+ "Lot has been rejected and marked as unavailable.": "批號已拒絕並標記為不可用。",
+ "This order is insufficient, please pick another lot.": "此訂單不足,請選擇其他批號。",
+ "Please finish QR code scan, QC check and pick order.": "請完成 QR 碼掃描、QC 檢查和提料。",
+ "No data available": "沒有資料",
+ "Please submit the pick order.": "請提交提料單。",
+ "Item lot to be Pick:": "批次貨品提料:",
+ "Report and Pick another lot": "上報並需重新選擇批號",
+ "Accept Stock Out": "接受出庫",
+ "Pick Another Lot": "欠數,並重新選擇批號",
+ "Delivery Note Code": "送貨單編號",
+ "A4 Printer": "A4 打印機",
+ "Label Printer": "標籤打印機",
+ "Please select a printer first": "請先選擇打印機",
+ "Please select a label printer first": "請先選擇標籤打印機",
+ "Lot No": "批號",
+ "Expiry Date": "到期日",
+ "Location": "位置",
+ "All Pick Order Lots": "所有提料單批次",
+ "Completed": "已完成",
+ "Finished Good Order": "成品出倉",
+ "Assign and Release": "分派並放單",
+ "Original Available Qty": "原可用數",
+ "Remaining Available Qty": "剩餘可用數",
+ "Please submit pick order.": "請提交提料單。",
+ "Please finish QR code scan and pick order.": "請完成 QR 碼掃描和提料。",
+ "Please finish QR code scanand pick order.": "請完成 QR 碼掃描和提料。",
+ "First created group": "首次建立分組",
+ "Latest created group": "最新建立分組",
+ "Manual Input": "手動輸入",
+ "QR Code Scan for Lot": " QR 碼掃描批次",
+ "Processing QR code...": "處理 QR 碼...",
+ "The input is not the same as the expected lot number.": "輸入的批次號碼與預期的不符。",
+ "Verified successfully!": "驗證成功!",
+ "Cancel": "取消",
+ "storing": "待品檢入倉",
+ "pick successful": "提料成功",
+ "Insufficient available quantity on lot (may have been picked by another user)": "掃描的批次已被其他用戶完全提料。請掃描其他批次。",
+ "Scan": "掃描",
+ "Before today": "今天之前",
+ "Scanned": "已掃描",
+ "Loading data...": "正在載入數據...",
+ "No available stock for this item": "沒有可用庫存",
+ "No lot details available for this item": "沒有批次詳情",
+ "Current stock is insufficient or unavailable": "現時可用庫存不足或不可用",
+ "Please check inventory status": "請檢查庫存狀態",
+ "Rows per page": "每頁行數",
+ "QR Scan Result:": "QR 掃描結果:",
+ "Action": "操作",
+ "Please finish pick order.": "請完成提料。",
+ "Lot": "批號",
+ "Assign Pick Orders": "分派提料單",
+ "Selected Pick Orders": "已選擇提料單數量",
+ "Please assgin/release the pickorders to picker": "請分派/放單提料單給提料員。",
+ "Assign To": "分派給",
+ "No Group": "沒有分組",
+ "Selected items will join above created group": "已選擇的貨品將加入以上建立的分組",
+ "Issue": "問題",
+ "Pick Execution Issue Form": "提料問題表單",
+ "Lot line is unavailable": "掃描批次不可用",
+ "This form is for reporting issues only. You must report either missing items or bad items.": "此表單僅用於報告問題。您必須報告缺少的物品或不良物品。",
+ "Bad item Qty": "不良貨品數量",
+ "Missing item Qty": "貨品遺失數量",
+ "Missing Item Qty": "貨品遺失數量",
+ "Bad Item Qty": "不良貨品數量",
+ "Bad Package Qty": "不良包裝數量",
+ "Lot line is not available (status=UNAVAILABLE)": "掃描批次不可用",
+ "Actual Pick Qty": "實際提料數量",
+ "Required Qty": "所需數量",
+ "Issue Remark": "問題描述",
+ "Handler": "提料員",
+ "Qty is required": "必需輸入數量",
+ "Qty is not allowed to be greater than remaining available qty": "輸入數量不能大於剩餘可用數量",
+ "Qty is not allowed to be greater than required qty": "輸入數量不能大於所需數量",
+ "At least one issue must be reported": "至少需要報告一個問題",
+ "issueRemark": "問題描述是必需的",
+ "handler": "提料員",
+ "Max": "最大值",
+ "Route": "路線",
+ "Index": "編號",
+ "No FG pick orders found": "沒有成品提料單",
+ "Finish Scan?": "完成掃描?",
+ "Delivery Code": "出倉單編號",
+ "Shop PO Code": "訂單編號",
+ "Shop ID": "商店編號",
+ "Truck No.": "車線編號",
+ "Departure Time": "車線出發時間",
+ "Shop Name": "商店名稱",
+ "Shop Address": "商店地址",
+ "Delivery Date": "目標日期",
+ "Pick Execution 2/F": "進行提料 2/F",
+ "Pick Execution 4/F": "進行提料 4/F",
+ "Pick Execution Detail": "進行提料詳情",
+ "Submit Required Pick Qty": "提交所需提料數量",
+ "Scan Result": "掃描結果",
+ "Ticket No.": "提票號碼",
+ "Start QR Scan": "開始QR掃描",
+ "Stop QR Scan": "停止QR掃描",
+ "Scanning...": "掃描中...",
+ "Print DN/Label": "列印送貨單/標籤",
+ "Store ID": "儲存編號",
+ "QR code does not match any item in current orders.": "QR 碼不符合當前訂單中的任何貨品。",
+ "Lot Number Mismatch": "批次號碼不符",
+ "The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?": "掃描的貨品與預期的貨品相同,但批次號碼不同。您是否要繼續使用不同的批次?",
+ "The scanned item matches the expected item, but the lot number is different. Scan again to confirm: scan the expected lot QR to keep the suggested lot, or scan the other lot QR again to switch.": "掃描貨品相同但批次不同。請再掃描一次以確認:掃描「建議批次」的 QR 可沿用該批次;再掃描「另一批次」的 QR 則切換為該批次。",
+ "Expected Lot:": "預期批次:",
+ "Scanned Lot:": "掃描批次:",
+ "Confirm": "確認",
+ "Update your suggested lot to the this scanned lot": "更新您的建議批次為此掃描的批次",
+ "Print Draft": "列印草稿",
+ "Print Pick Order and DN Label": "列印提料單和送貨單標籤",
+ "Print Pick Order": "列印提料單",
+ "Print DN Label": "列印送貨單標籤",
+ "Print All Draft": "列印全部草稿",
+ "If you confirm, the system will:": "如果您確認,系統將:",
+ "After you scan to choose, the system will update the pick line to the lot you confirmed.": "確認後,系統會將您選擇的批次套用到對應提料行。",
+ "Or use the Confirm button below if you cannot scan again (same as scanning the other lot again).": "若無法再掃描,可按下「確認」以切換為剛才掃描到的批次(與再掃一次該批次 QR 相同)。",
+ "Lot switch failed": "批次切換失敗",
+ "The system could not switch to the scanned lot. Review the lots below, then tap Confirm to retry.": "系統無法切換至掃描的批次。請核對下方批次後按「確認」重試。",
+ "You can also scan again: expected lot QR keeps the suggested line; scanned lot QR retries the switch.": "您也可以再掃描:掃描建議批次 QR 可保留該行;掃描欲切換批次 QR 可再次嘗試切換。",
+ "QR code verified.": "QR 碼驗證成功。",
+ "Order Finished": "訂單完成",
+ "Submitted Status": "提交狀態",
+ "Pick Execution Record": "提料執行記錄",
+ "Delivery No.": "送貨單編號",
+ "Total": "總數",
+ "Completed DO pick orders: ": "已完成送貨單提料單:",
+ "No completed DO pick orders found": "沒有已完成送貨單提料單",
+ "Enter the number of cartons: ": "請輸入總箱數",
+ "Number of cartons": "箱數",
+ "Select an action for the assigned pick orders.": "選擇分配提料單的動作。",
+ "Detail": "詳情",
+ "consoCode": "合併編號",
+ "status": "狀態",
+ "Items Included": "貨品包括",
+ "Pick Order Included": "提料單包括",
+ "No created items": "沒有已建立的貨品",
+ "Please select item": "請選擇貨品",
+ "enter a qty": "請輸入數量",
+ "update qc info": "更新QC資訊",
+ "All lots must be completed before printing": "所有批次必須完成才能打印",
+ "Assigning pick order...": "分配提料單...",
+ "Enter the number of cartons:": "請輸入總箱數",
+ "Finished Good Detail": "成品提貨詳情",
+ "Finished Good Record": "成品提貨記錄",
+ "Finished Good Record (All)": "成品提貨記錄(全部)",
+ "All dates": "全部日期",
+ "Search date": "搜索日期",
+ "Hide Completed: OFF": "完成: OFF",
+ "Hide Completed: ON": "完成: ON",
+ "Number must be at least 1": "數量至少為1",
+ "Printed Successfully.": "成功列印",
+ "Product": "產品",
+ "You need to enter a number": "您需要輸入一個數字",
+ "Available in warehouse": "在倉庫中可用",
+ "Describe the issue with bad items": "描述不良貨品的問題",
+ "Enter pick qty or issue qty": "請輸入提料數量或不良數量",
+ "Invalid qty": "無效數量",
+ "Note:": "注意:",
+ "Qty is not allowed to be greater than required/available qty": "數量不能大於所需/可用數量",
+ "Still need to pick": "仍需提料",
+ "Total exceeds required qty": "總數超過所需數量",
+ "submitting": "提交中",
+ "Back to List": "返回列表",
+ "Delivery No": "送貨單編號",
+ "FG orders": "成品訂單",
+ "View Details": "查看詳情",
+ "No Item": "沒有貨品",
+ "None": "沒有",
+ "Add Selected Items to Created Items": "將已選擇的貨品添加到已建立的貨品中",
+ "All pick orders created successfully": "所有提料單建立成功",
+ "Failed to create group": "建立分組失敗",
+ "Invalid date format": "日期格式無效",
+ "Item already exists in created items": "貨品已存在於已建立的貨品中",
+ "Job Order not found or has no items": "工單不存在或沒有貨品",
+ "No results found": "沒有結果",
+ "Please enter at least code or name": "請輸入至少編號或名稱",
+ "Please enter quantity for all selected items": "請輸入所有已選擇的貨品的數量",
+ "Please select at least one item to submit": "請選擇至少一個貨品提交",
+ "Please select group and enter quantity for all selected items": "請選擇分組並輸入所有已選擇的貨品的數量",
+ "Please select group for all selected items": "請選擇分組對所有已選擇的貨品",
+ "Please select product type": "請選擇產品類型",
+ "Please select target date": "請選擇目標日期",
+ "Please select type": "請選擇類型",
+ "Search Criteria": "搜索條件",
+ "Processing...": "處理中",
+ "Failed items must have failed quantity": "不合格的貨品必須有不合格數量",
+ "QC items without result": "QC項目沒有結果",
+ "confirm putaway": "確認上架",
+ "email supplier": "發送郵件給供應商",
+ "qc processing": "QC處理",
+ "submitStockIn": "提交入庫",
+ "not default warehosue": "不是默認倉庫",
+ "printQty": "打印數量",
+ "Shop": "商店名稱",
+ "warehouse": "倉庫",
+ "Add Record": "添加記錄",
+ "Clean Record": "清空記錄",
+ "Select": "選擇",
+ "Close": "關閉",
+ "Truck": "車線",
+ "Date": "日期",
+ "Delivery Order Code": "送貨單編號",
+ "Escalation Info": "升級信息",
+ "Escalation Result": "升級結果",
+ "acceptQty must not greater than": "接受數量不能大於",
+ "supervisor": "主管",
+ "No Qc": "沒有QC",
+ "receivedQty": "接收數量",
+ "stock in information": "入庫信息",
+ "No Uom": "沒有單位",
+ "Input quantity cannot exceed": "輸入數量不能超過",
+ "Quantity cannot be negative": "數量不能為負數",
+ "Enter bad item quantity (required if no missing items)": "請輸入不良數量(如果沒有缺少項目)",
+ "Enter missing quantity (required if no bad items)": "請輸入缺少數量(如果沒有不良項目)",
+ "Submit All Scanned": "提交所有已掃描項目",
+ "Submitting...": "提交中...",
+ "COMPLETED": "已完成",
+ "Confirm print: (": "確認列印全部草稿?(總數量:",
+ "piece(s))": "份)",
+ "Printing...": "列印中",
+ "Please wait...": "請稍後",
+ "No available pick order(s) for this floor.": "此樓層沒有可用的提料單",
+ "You already have a pick order in progess. Please complete it first before taking next pick order.": "請先完成目前的提料單,再提取下一張",
+ "Error occurred during assignment.": "提料單分配錯誤",
+ "Info": "消息",
+ "Warning": "警告",
+ "Error": "錯誤",
+ "Batch Print": "批量列印",
+ "No entries available": "該樓層未有需處理訂單",
+ "Today": "是日",
+ "Tomorrow": "翌日",
+ "packaging": "提料中",
+ "This lot is not available, please scan another lot.": "此批號不可用,請掃描其他批號。",
+ "Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "請檢查周圍是否有 QR 碼,可能有剛剛入庫、轉移入庫或轉移出庫的 QR 碼。",
+ "Lot is expired (expiry={{expiry}})": "掃描批號已過期(到期日={{expiry}})",
+ "Day After Tomorrow": "後日",
+ "Select Date": "請選擇日期",
+ "Suggest Lot No.": "推薦批號",
+ "Search by Shop": "搜索商店",
+ "Search by Truck": "搜索貨車",
+ "Print DN & Label": "列印提料單和送貨單標籤",
+ "Print Label": "列印送貨單標籤",
+ "Reprint Label(s)": "補印標籤",
+ "Reprint DN Label": "補印送貨單標籤",
+ "From carton": "起始箱號",
+ "To carton": "結束箱號",
+ "Total cartons on shipment": "總箱數",
+ "From carton must be at least 1": "起始箱號必須至少為 1",
+ "To carton must be greater than or equal to from carton": "結束箱號必須大於或等於起始箱號",
+ "Total cartons on shipment must be at least 1": "總箱數必須至少為 1",
+ "To carton cannot be greater than total cartons on shipment": "結束箱號不能大於總箱數",
+ "Not Yet Finished Released Do Pick Orders": "未完成提料單",
+ "Not yet finished released do pick orders": "未完成提料單",
+ "Released orders not yet completed - click lane to select and assign": "未完成提料單- 點擊貨車班次選擇並分配",
+ "Ticket Release Table": "查看提貨情況",
+ "Please take one pick order before printing the draft.": "請先從「撳單/提料單詳情」頁面下方選取提料單,再列印草稿。",
+ "No released pick order records found.": "目前沒有可用的提料單。",
+ "EDT - Lane Code (Unassigned/Total)": "預計出發時間 - 貨車班次(未撳數/總單數)",
+ "Floor ticket": "票別(樓層)",
+ "2F ticket": "2/F 票",
+ "4F ticket": "4/F 票",
+ "4F lane panel legend": "貨車班次 — 裝載序(未撳數/總單數)",
+ "Loading sequence n": "板{{n}}",
+ "lot QR code": "批號 QR 碼",
+ "label Printer": "標籤打印機",
+ "Loading Sequence": "裝載序",
+ "Ticket No": "提票號碼",
+ "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated.": "掃描的庫存批行為「不可用」,無法換批或綁定;揀貨行未更新。",
+ "is unavable. Please check around have available QR code or not.": "此批號不可用,請檢查周圍是否有可用的 QR 碼。",
+ "Lot switch failed; pick line was not marked as checked.": "換批失敗;揀貨行未標為已核對。",
+ "Lot confirmation failed. Please try again.": "確認批號失敗,請重試。",
+ "Powder Mixture": "箱料粉",
+ "This lot is not yet putaway": "此批次尚未上架",
+ "Cannot resolve new inventory lot line": "無法解析新批號庫存行(請確認已上架且資料正確)。",
+ "Pick order line item is null": "提料單行未關聯物品。",
+ "New lot line item does not match pick order line item": "新批號行的物品與提料單行不一致。",
+ "Pick order line {{id}} not found": "找不到有關提料單行的資料。",
+ "SuggestedPickLot not found for pickOrderLineId {{polId}}": "找不到該提料單行的建議揀貨批",
+ "SuggestedPickLot qty is invalid: {{qty}}": "建議揀貨數量無效:{{qty}}。",
+ "Reject switch lot: available {{available}} less than required {{required}}": "此批次貨品已被其他送貨單留起,請掃描其他批次。",
+ "Reject switch lot: picked {{picked}} already greater or equal required {{required}}": "換批被拒:已揀數量({{picked}})已達或超過建議量({{required}}),無法再拆分換批。",
+ "Lot status is unavailable. Cannot switch or bind; pick line was not updated.": "批號狀態為「不可用」,無法換批或綁定;揀貨行未更新。",
+ "No lot rows. Select a line in the table above.": "尚無批號資料。請在上方表格勾選一行提料單明細。",
+ "No stock out line for this lot": "此批號尚無出庫行,無法提交。",
+ "No data available for this pick order.": "此提料單沒有可用資料。",
+ "Report missing or bad items": "報告缺失或不良物品",
+ "passed": "合格",
+ "failed": "不合格",
+ "confirm_accept_with_fail": "有不合格檢查項目,確認接受出庫?"
+}
diff --git a/src/i18n/zh/po.json b/src/i18n/zh/po.json
index a13c857..b16d4d9 100644
--- a/src/i18n/zh/po.json
+++ b/src/i18n/zh/po.json
@@ -1,16 +1,16 @@
{
- "code": "代码",
- "status": "來貨狀態",
- "escalated": "已升级",
- "notEscalated": "未升级",
- "All": "全部",
- "Pending": "待处理",
- "Receiving": "接收中",
- "Completed": "已完成",
- "Purchase Order": "采购订单",
- "Details": "详情",
- "OrderDate": "订单日期",
- "Supplier": "供应商",
- "Escalated": "已升级",
- "NotEscalated": "未升级"
-}
\ No newline at end of file
+ "code": "代码",
+ "status": "來貨狀態",
+ "escalated": "已升级",
+ "notEscalated": "未升级",
+ "All": "全部",
+ "Pending": "待处理",
+ "Receiving": "接收中",
+ "Completed": "已完成",
+ "Purchase Order": "采购订单",
+ "Details": "详情",
+ "OrderDate": "订单日期",
+ "Supplier": "供应商",
+ "Escalated": "已升级",
+ "NotEscalated": "未升级"
+}
diff --git a/src/i18n/zh/poWorkbench.json b/src/i18n/zh/poWorkbench.json
index 7c656ae..6f84e8e 100644
--- a/src/i18n/zh/poWorkbench.json
+++ b/src/i18n/zh/poWorkbench.json
@@ -1,9 +1,10 @@
{
+ "PO Workbench": "採購單工作台",
"searchCriteria": {
"poPlaceholder": "請掃描PO二維碼或輸入單號",
- "ariaPoSearch": "PO number search",
- "ariaClearPo": "Clear PO number",
- "ariaToggleAdvanced": "Toggle advanced search"
+ "ariaPoSearch": "搜索採購單號",
+ "ariaClearPo": "清除採購單號",
+ "ariaToggleAdvanced": "切換進階搜索"
},
"advanced": {
"title": "進階搜索",
diff --git a/src/i18n/zh/printer.json b/src/i18n/zh/printer.json
new file mode 100644
index 0000000..8f15cce
--- /dev/null
+++ b/src/i18n/zh/printer.json
@@ -0,0 +1,8 @@
+{
+ "Create Printer": "新增列印機",
+ "Edit": "編輯",
+ "PDF Preview": "PDF 預覽",
+ "Print failed": "列印失敗",
+ "Print job sent successfully": "列印作業已成功送出",
+ "Printer": "列印機"
+}
diff --git a/src/i18n/zh/production.json b/src/i18n/zh/production.json
new file mode 100644
index 0000000..446f0e9
--- /dev/null
+++ b/src/i18n/zh/production.json
@@ -0,0 +1,3 @@
+{
+ "Production Process": "生產流程"
+}
diff --git a/src/i18n/zh/productionProcess.json b/src/i18n/zh/productionProcess.json
new file mode 100644
index 0000000..1ded5c0
--- /dev/null
+++ b/src/i18n/zh/productionProcess.json
@@ -0,0 +1,221 @@
+{
+ "Action": "操作",
+ "All": "全部",
+ "An error has occurred. Please try again later.": "發生錯誤,請稍後再試。",
+ "Are you sure you want to delete this process?": "您確定要刪除此工序嗎?",
+ "Assignment successful": "分配成功",
+ "Assume End Time": "預計完成時間",
+ "Assume Time Need": "預計所需時間",
+ "Auto-refresh every 1 minute": "每1分鐘自動刷新",
+ "Auto-refresh every 10 minutes": "每10分鐘自動刷新",
+ "Back": "返回",
+ "Back to List": "返回列表",
+ "Bag": "包裝袋",
+ "Bag Consumption": "包裝袋消耗",
+ "Balance": "可用數量",
+ "Base Qty": "基本數量",
+ "Base UOM": "基本單位",
+ "Batch Count": "批數",
+ "BoM Material": "BOM 材料",
+ "Bom Req. Qty": "BOM",
+ "Bom Uom": "BOM 單位",
+ "By-product": "副產品",
+ "Cancel": "取消",
+ "Cancel Job Order": "取消工單",
+ "Cancel job order confirm message": "確定要取消此工單嗎?工單將從列表中隱藏。",
+ "Changeover Time": "生產後轉換時間",
+ "Changeover Time (mins)": "生產後轉換時間(分鐘)",
+ "Code": "編號",
+ "Complete Step": "完成步驟",
+ "Completed": "完成",
+ "Completed Step": "完成步驟",
+ "Confirm": "確認",
+ "Confirm cancel job order": "確認取消工單",
+ "Confirm delete job order": "確認刪除工單",
+ "Confirm to Pass this Process?": "確認要通過此工序嗎?",
+ "Confirm to update this Job Order?": "確認要完成此工單嗎?",
+ "Consumed Qty": "消耗數量",
+ "Continue": "繼續",
+ "Count of Job Orders": "已處理工單",
+ "Date": "日期",
+ "Defect": "不良品",
+ "Delete job order confirm message": "確定要刪除此工單嗎?此操作無法復原。",
+ "Description": "描述",
+ "Duration hours": "{{count}} 小時",
+ "Duration minutes": "{{count}} 分鐘",
+ "Duration seconds": "{{count}} 秒",
+ "End Time": "完成時間",
+ "Enter any additional production notes...": "輸入其他生產備註...",
+ "Equipment": "設備",
+ "Equipment Code": "設備編號",
+ "Equipment Name and Code": "設備名稱及編號",
+ "Equipment Type": "設備類型",
+ "EquipmentType-EquipmentName-Code": "設備類型-設備名稱-編號",
+ "Estimated Completion Time": "預計完成時間",
+ "Executing": "執行中",
+ "FG / WIP Item": "成品/半成品",
+ "Filtered": "已過濾",
+ "Finished Time": "完成時間",
+ "Finished lines": "已完成流程",
+ "In Progress": "進行中",
+ "In progress": "進行中",
+ "Invalid Job Order Id": "無效工單編號",
+ "Invalid Stock In Line Id": "無效庫存行ID",
+ "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間次序 | 複雜度",
+ "Item": "物品",
+ "Item Code": "物品編號",
+ "Item Name": "物品名稱",
+ "Job Details": "工單編號及生產產品",
+ "Job Order": "工單",
+ "Job Order Code": "工單編號",
+ "Job Order Info": "工單信息",
+ "Job Order No.": "工單編號",
+ "Job Order and Product": "工單及貨品",
+ "Job Order Production Process": "工單生產流程",
+ "Job Process Status Dashboard": "儀表板 - 工單狀態",
+ "Job Type": "工單類型",
+ "Job process detail mode label": "工序格顯示",
+ "Job process detail: equipment": "設備",
+ "Job process detail: handler": "員工",
+ "Job process detail: process name": "工序",
+ "Job process detail: time": "時間",
+ "Just Pass": "已完成",
+ "Last updated": "最後更新",
+ "Lines with insufficient stock: ": "未能提料項目數量: ",
+ "Lines with sufficient stock: ": "可提料項目數量: ",
+ "Lot No": "批號",
+ "Matching Stock": "工單對料",
+ "Material Code": "材料清單",
+ "N/A": "不適用",
+ "Name": "名稱",
+ "Next page": "下一頁",
+ "No data available": "沒有資料",
+ "No data found": "沒有找到資料",
+ "No.": "編號",
+ "Now": "現時",
+ "Operator": "員工資訊",
+ "Operator KPI Dashboard": "儀表板 - 操作員KPI概覽",
+ "Operator Name & No.": "操作員名稱及編號",
+ "Order Complete": "訂單完成",
+ "Output from Process": "工序產出",
+ "Output Quantity": "產出數量",
+ "Over Time": "超時",
+ "Overall Time Remaining": "總剩餘時間",
+ "Passed Step": "通過步驟",
+ "Pause": "暫停",
+ "Pause Reason": "暫停原因",
+ "Paused": "已暫停",
+ "Pending": "待處理",
+ "Plan start (from)": "開始日期(從)",
+ "Plan start (to)": "開始日期(至)",
+ "Please scan equipment code": "請掃描設備編號",
+ "Please scan operator code first": "請先掃描操作員編號",
+ "Please scan staff no": "請掃描員工編號",
+ "Post Prod Time (Minutes)": "收尾時間(分鐘)",
+ "Prep Time (Minutes)": "準備時間(分鐘)",
+ "Previous page": "上一頁",
+ "Printer": "列印機",
+ "Process": "工序",
+ "Process & Equipment": "製程與設備",
+ "Process Description": "工序說明",
+ "Process Name": "工序名稱",
+ "Process Start Time": "工序開始時間",
+ "Process Type": "工序類型",
+ "Process page summary": "工序 {{from}}–{{to}} / 共 {{total}} 道",
+ "Processing Time": "生產時間",
+ "Processing Time (mins)": "步驟時間(分鐘)",
+ "Product process status": "生產流程狀態",
+ "Production Date": "生產日期",
+ "Production Equipment Status Dashboard": "儀表板 - 生產設備最新狀態",
+ "Production Output Data": "生產輸出數據",
+ "Production Output Data Entry": "生產輸出數據輸入",
+ "Production Priority": "生產優先序",
+ "Production Process": "工藝流程",
+ "Production Process Line Remark": "工藝明細",
+ "Production Process Steps": "生產流程步驟",
+ "Production Time Remaining": "生產剩餘時間",
+ "Production date": "生產日期",
+ "Put Awayed Job Orders": "已上架工單",
+ "Qty": "數量",
+ "Quality Check": "品質檢查",
+ "Quantity": "數量",
+ "Reason": "原因",
+ "Release": "放單",
+ "Remaining Time": "剩餘時間",
+ "Remaining Time (min)": "剩餘時間(分鐘)",
+ "Remark": "備註",
+ "Req. Qty": "需求數量",
+ "Required Qty": "需求數量",
+ "Required Time": "所需時間",
+ "SEQ": "步驟",
+ "Save": "儲存",
+ "Scan Operator & Equipment": "掃描操作員和設備",
+ "Scrap": "損耗",
+ "Scrap Qty": "損耗數量",
+ "Search date": "搜索日期",
+ "Searched Item": "已搜索物品",
+ "Select Another Bag Lot": "選擇另一個包裝袋",
+ "Select Bag": "選擇包裝袋",
+ "Select Date": "選擇日期",
+ "Select Printer": "選擇打印機",
+ "Select Unit": "選擇單位",
+ "Seq": "步驟",
+ "Seq No": "加入步驟",
+ "Setup Time": "生產前預備時間",
+ "Setup Time (mins)": "生產前預備時間(分鐘)",
+ "Staff No": "員工編號",
+ "Start": "開始",
+ "Start QR Scan": "開始掃碼",
+ "Start Time": "開始時間",
+ "Status": "狀態",
+ "Step": "步驟",
+ "Step Information": "步驟信息",
+ "Step Name": "名稱",
+ "Step Start Time": "步驟開始時間",
+ "Stock Available": "庫存數",
+ "Stock Req. Qty": "需求數",
+ "Stock Status": "庫存狀態",
+ "Stock UOM": "庫存單位",
+ "Stop QR Scan": "停止掃碼",
+ "Submit & Start": "提交並開始",
+ "Submit Bag Consumption": "提交包裝袋消耗",
+ "Submitting...": "提交中...",
+ "Target Production Date": "目標生產日期",
+ "Time Information(mins)": "時間信息(分鐘)",
+ "Time Remaining": "剩餘時間",
+ "Timer Paused": "計時器已暫停",
+ "Total Processing Time": "總工時",
+ "Total Time": "總時間",
+ "Total finished QC job orders": "總完成QC工單數量",
+ "Total job orders": "總工單數量",
+ "Total lines: ": "總數量:",
+ "Type": "類型",
+ "Unable to get user ID": "無法獲取用戶ID",
+ "Unit": "單位",
+ "Unknown": "未知",
+ "Update Job Order": "完成工單",
+ "Update Production Priority": "更新生產優先序",
+ "Update Target Production Date": "更新目標生產日期",
+ "Update Required Quantity": "更新需求數量",
+ "Update Time Information": "更新時間信息",
+ "View": "查看",
+ "View Details": "查看詳情",
+ "Wait Time": "等待時間",
+ "Waiting QC Put Away Job Orders": "待QC上架工單",
+ "all": "全部",
+ "drink": "飲料",
+ "id": "ID",
+ "mins": "分鐘",
+ "minutes": "分鐘",
+ "FG": "成品",
+ "No processes found for this job order": "找不到此工單的工序",
+ "SFG": "半成品",
+ "WIP": "半成品",
+ "fg": "成品",
+ "other": "其他",
+ "processing": "生產中",
+ "productionProcess": "生產流程",
+ "sfg": "半成品",
+ "view stockin": "品檢",
+ "wip": "半成品"
+}
diff --git a/src/i18n/zh/project.json b/src/i18n/zh/project.json
index f5d7a11..937afa8 100644
--- a/src/i18n/zh/project.json
+++ b/src/i18n/zh/project.json
@@ -1,16 +1,16 @@
{
- "code": "編號",
- "FG & Material Demand Forecast Detail": "FG 及材料需求預測詳情",
- "Release": "發佈",
- "Actions": "操作",
- "Product": "物品",
- "Details": "詳情",
- "View BoM": "查看 BoM",
- "description": "描述",
- "details": "詳情"
-
-
-
-
-
-}
\ No newline at end of file
+ "code": "編號",
+ "FG & Material Demand Forecast Detail": "FG 及材料需求預測詳情",
+ "Release": "發佈",
+ "Actions": "操作",
+ "Product": "物品",
+ "Details": "詳情",
+ "View BoM": "查看 BOM",
+ "description": "描述",
+ "details": "詳情",
+ "Task": "任務",
+ "Create Project": "新增專案",
+ "Projects": "專案",
+ "Project Code": "專案代碼",
+ "Project Code and Name": "專案代碼與名稱"
+}
diff --git a/src/i18n/zh/purchaseOrder.json b/src/i18n/zh/purchaseOrder.json
index c64703d..bcff183 100644
--- a/src/i18n/zh/purchaseOrder.json
+++ b/src/i18n/zh/purchaseOrder.json
@@ -10,8 +10,8 @@
"ETA": "預計到貨日期",
"ETA To": "預計到貨日期至",
"Details": "詳情",
- "Supplier": "供應商",
- "Status": "來貨狀態",
+ "Supplier": "供應商",
+ "Status": "來貨狀態",
"escalateFrom": "上報來源",
"Escalated": "上報狀態",
"NotEscalated": "無上報",
@@ -174,5 +174,11 @@
"submitting": "提交中...",
"Submit": "提交",
"Total must equal Required Qty. Missing": "總數量必須等於所需數量。缺少:{{diff}}",
- "Total must equal Required Qty. Exceeds by": "總數量必須等於所需數量。超出:{{diff}}"
+ "Total must equal Required Qty. Exceeds by": "總數量必須等於所需數量。超出:{{diff}}",
+ "Add Record": "新增",
+ "Clean Record": "重置",
+ "Will start binding procedure after scanning item qr code.": "掃描物品二維碼後將開始綁定流程。",
+ "Quantity": "數量",
+ "Enter quantity": "請輸入數量",
+ "Enter your remark": "請輸入您的備註"
}
diff --git a/src/i18n/zh/qcCategory.json b/src/i18n/zh/qcCategory.json
index b608a76..8628af9 100644
--- a/src/i18n/zh/qcCategory.json
+++ b/src/i18n/zh/qcCategory.json
@@ -1,20 +1,20 @@
{
- "Qc Category": "品檢模板",
- "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 類別更新時間",
- "Name": "名稱",
- "Code": "編號",
- "Description": "描述",
- "Details": "詳情",
- "Delete": "刪除",
- "Qc Item": "QC 項目",
- "Create Qc Category": "新增品檢模板",
- "Edit Qc Item": "編輯品檢項目",
- "Qc Item Details": "品檢項目詳情",
- "Cancel": "取消",
- "Submit": "儲存"
-}
\ No newline at end of file
+ "Qc Category": "品檢模板",
+ "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 類別更新時間",
+ "Name": "名稱",
+ "Code": "編號",
+ "Description": "描述",
+ "Details": "詳情",
+ "Delete": "刪除",
+ "Qc Item": "QC 項目",
+ "Create Qc Category": "新增品檢模板",
+ "Edit Qc Item": "編輯品檢項目",
+ "Qc Item Details": "品檢項目詳情",
+ "Cancel": "取消",
+ "Submit": "儲存"
+}
diff --git a/src/i18n/zh/qcItemAll.json b/src/i18n/zh/qcItemAll.json
index 94b9526..7fbc0e0 100644
--- a/src/i18n/zh/qcItemAll.json
+++ b/src/i18n/zh/qcItemAll.json
@@ -1,27 +1,27 @@
{
"Qc Item All": "QC 綜合管理",
- "Item and Qc Category Mapping": "物料與品檢模板映射",
+ "Item and Qc Category Mapping": "物品與品檢模板映射",
"Qc Category and Qc Item Mapping": "品檢模板與品檢項目映射",
"Qc Category Management": "品檢模板管理",
"Do you want to submit?": "您確定要提交嗎?",
"Do you want to delete?": "您確定要刪除嗎?",
"Confirm": "確認",
- "Item already has type \"{{type}}\" in QcCategory \"{{category}}\". One item can only have each type in one QcCategory.": "物料已於模板「{{category}}」設為類型「{{type}}」,每個物料同一類型只能對應一個模板。",
+ "Item already has type \"{{type}}\" in QcCategory \"{{category}}\". One item can only have each type in one QcCategory.": "物品已於模板「{{category}}」設為類型「{{type}}」,每個物品同一類型只能對應一個模板。",
"Qc Item Management": "品檢項目管理",
"Qc Category": "品檢模板",
"Qc Item": "品檢項目",
- "Item": "物料",
- "Item code not found": "物料不存在",
- "Error validating item code": "驗證物料編號時發生錯誤",
+ "Item": "物品",
+ "Item code not found": "物品不存在",
+ "Error validating item code": "驗證物品編號時發生錯誤",
"Category": "模板",
"Category Type": "模板類型",
- "Enter item code to validate": "請輸入物料編號以驗證",
+ "Enter item code to validate": "請輸入物品編號以驗證",
"Code": "編號",
"Name": "名稱",
"Description": "描述",
"Type": "類型",
"Order": "順序",
- "Item Count": "關聯物料數量",
+ "Item Count": "關聯物品數量",
"Qc Item Count": "關聯品檢項目數量",
"Qc Category Count": "關聯品檢模板數量",
"Actions": "操作",
@@ -44,13 +44,13 @@
"Submit Success": "提交成功",
"Submit Error": "提交失敗",
"Cannot Delete": "無法刪除",
- "Cannot delete QcCategory. It has {itemCount} item(s) and {qcItemCount} qc item(s) linked to it.": "無法刪除品檢模板。它有 {itemCount} 個物料和 {qcItemCount} 個品檢項目與其關聯。",
+ "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.": "無法刪除品檢項目。它與一個或多個品檢模板關聯。",
- "Select Item": "選擇物料",
+ "Select Item": "選擇物品",
"Select Qc Category": "選擇品檢模板",
"Select Qc Item": "選擇品檢項目",
"Select Type": "選擇類型",
- "Item Code": "物料編號",
+ "Item Code": "物品編號",
"Item Name": "產品名稱",
"Qc Category Code": "品檢模板編號",
"Qc Category Name": "品檢模板名稱",
@@ -64,4 +64,3 @@
"Confirm Delete": "確認刪除",
"Are you sure you want to delete this item?": "您確定要刪除此項目嗎?"
}
-
diff --git a/src/i18n/zh/qrCodeHandle.json b/src/i18n/zh/qrCodeHandle.json
new file mode 100644
index 0000000..7779211
--- /dev/null
+++ b/src/i18n/zh/qrCodeHandle.json
@@ -0,0 +1,5 @@
+{
+ "PDF Preview": "PDF 預覽",
+ "QR Code Handle": "二維碼列印及下載",
+ "Equipment": "設備"
+}
diff --git a/src/i18n/zh/report.json b/src/i18n/zh/report.json
new file mode 100644
index 0000000..b3d5b8e
--- /dev/null
+++ b/src/i18n/zh/report.json
@@ -0,0 +1,13 @@
+{
+ "Report": "報告",
+ "title": "報告管理",
+ "selectReport": "選擇報告",
+ "reportList": "報告列表",
+ "selectReportHelper": "選擇報告",
+ "searchCriteria": "搜索條件",
+ "downloadPdf": "下載報告 (PDF)",
+ "downloadExcel": "下載報告 (Excel)",
+ "generatingPdf": "生成 PDF...",
+ "generatingExcel": "生成 Excel...",
+ "generatingReport": "生成報告..."
+}
diff --git a/src/i18n/zh/schedule.json b/src/i18n/zh/schedule.json
index 114cf15..a4b110a 100644
--- a/src/i18n/zh/schedule.json
+++ b/src/i18n/zh/schedule.json
@@ -1,98 +1,121 @@
-{ "Demand Forecast": "需求預測",
- "Total Demand Qty": "總需求量",
- "Total Job Orders": "總工單量",
- "Demand Qty (Day1)": "需求數量(第 1 天)",
- "Demand Qty (Day2)": "需求數量(第 2 天)",
- "Demand Qty (Day3)": "需求數量(第 3 天)",
- "Demand Qty (Day4)": "需求數量(第 4 天)",
- "Demand Qty (Day5)": "需求數量(第 5 天)",
- "Demand Qty (Day6)": "需求數量(第 6 天)",
- "Demand Qty (Day7)": "需求數量(第 7 天)",
- "Demand Forecast Detail": "需求預測詳情",
- "Details": "詳情",
- "Schedule": "排程",
- "Schedule Period": "排程時期",
- "Schedule Period To": "排程時期至",
- "Schedule Detail": "排程詳情",
- "Schedule At": "排程時間",
- "Search": "搜索",
- "Reset": "重置",
- "name": "名稱",
- "Name": "名稱",
- "type": "類型",
- "code": "編號",
- "Code": "編號",
- "CODE": "編號",
- "Product Count": "產品數量",
- "Scheduled At": "排程時間",
- "Demand Forecast Period": "需求預測時期",
- "FG & Material Demand Forecast Detail": "成品及物料需求預測詳情",
- "FG & Material Demand Forecast": "成品及物料需求預測",
- "Total Estimated Demand Qty": "總預估需求量",
- "View By FG": "依成品分類",
- "View By Material": "依物料分類",
- " (Selected)": " (已選擇)",
- "Total FG Item": "總成品項目",
- "Release": "發佈",
- "Actions": "操作",
- "FG Demand List (7 Days)": "成品需求列表(7 天)",
- "FG Demand Date": "成品需求日期",
- "FG Demand Qty": "成品需求數量",
- "Material Demand Date": "物料需求日期",
- "Material Demand List": "物料需求列表",
- "Available Qty": "可用數量",
- "Demand Qty": "需求數量",
- "Confirm": "確認",
- "Cancel": "取消",
- "Edit": "編輯",
- "Delete": "刪除",
- "Save": "儲存",
- "Close": "關閉",
- "Add": "新增",
- "Selected": "已選擇",
- "Unselected": "未選擇",
- "Status": "來貨狀態",
- "Material Demand List (7 Days)": "物料需求列表(7 天)",
- "Mon": "週一",
- "Tue": "週二",
- "Wed": "週三",
- "Thu": "週四",
- "Fri": "週五",
- "Sat": "週六",
- "Sun": "週日",
- "Last Month Average Stock": "上個月平均庫存",
- "Last Month Average Sales": "上個月平均銷售",
- "Safety Stock": "安全庫存",
- "Demand Qty (7 Days)": "需求數量(7 天)",
- "Estimated Production Time": "預估生產時間",
- "Production Priority": "生產優先順序",
- "View BoM": "查看物料清單",
- "Date": "日期",
- "Detail Scheduling": "詳細排程",
- "FG Production Schedule": "成品生產排程",
- "Production Date": "生產日期",
- "Total Job Order": "總工單數量",
- "Total Production Qty": "總生產數量",
- "Job No.": "工單編號",
- "Job Name": "工單名稱",
- "Job Type": "工單類型",
- "Job Status": "工單狀態",
- "Job Priority": "工單優先順序",
- "Job Date": "工單日期",
- "Job Qty": "工單數量",
- "mat": "物料",
- "consumables": "消耗品",
- "non-consumables": "非消耗品",
- "fg": "成品",
- "sfg": "半成品",
- "item": "物品",
- "UoM": "單位",
- "Type": "類型",
- "Test Detailed Schedule": "測試細排",
- "Test Rough Schedule": "測試粗排",
- "detailed": "細排",
- "Detailed": "細排",
- "Product Count(s)": "產品數量",
- "Overall": "總計",
- "Back": "返回"
+{
+ "Demand Forecast": "需求預測",
+ "Total Demand Qty": "總需求量",
+ "Total Job Orders": "總工單量",
+ "Demand Qty (Day1)": "需求數量(第 1 天)",
+ "Demand Qty (Day2)": "需求數量(第 2 天)",
+ "Demand Qty (Day3)": "需求數量(第 3 天)",
+ "Demand Qty (Day4)": "需求數量(第 4 天)",
+ "Demand Qty (Day5)": "需求數量(第 5 天)",
+ "Demand Qty (Day6)": "需求數量(第 6 天)",
+ "Demand Qty (Day7)": "需求數量(第 7 天)",
+ "Demand Forecast Detail": "需求預測詳情",
+ "Details": "詳情",
+ "Schedule": "排程",
+ "Schedule Period": "排程時期",
+ "Schedule Period To": "排程時期至",
+ "Schedule Detail": "排程詳情",
+ "Schedule At": "排程時間",
+ "Search": "搜索",
+ "Reset": "重置",
+ "name": "名稱",
+ "Name": "名稱",
+ "type": "類型",
+ "code": "編號",
+ "Code": "編號",
+ "CODE": "編號",
+ "Product Count": "產品數量",
+ "Sales Qty": "銷售量",
+ "Sales UOM": "銷售單位",
+ "Scheduled At": "排程時間",
+ "Demand Forecast Period": "需求預測時期",
+ "FG & Material Demand Forecast Detail": "成品及物料需求預測詳情",
+ "FG & Material Demand Forecast": "成品及物料需求預測",
+ "Total Estimated Demand Qty": "總預估需求量",
+ "View By FG": "依成品分類",
+ "View By Material": "依物料分類",
+ " (Selected)": " (已選擇)",
+ "Total FG Item": "總成品項目",
+ "Release": "發佈",
+ "Actions": "操作",
+ "FG Demand List (7 Days)": "成品需求列表(7 天)",
+ "FG Demand Date": "成品需求日期",
+ "FG Demand Qty": "成品需求數量",
+ "Material Demand Date": "物料需求日期",
+ "Material Demand List": "物料需求列表",
+ "Available Qty": "可用數量",
+ "Demand Qty": "需求數量",
+ "Confirm": "確認",
+ "Cancel": "取消",
+ "Edit": "編輯",
+ "Delete": "刪除",
+ "Save": "儲存",
+ "Close": "關閉",
+ "Add": "新增",
+ "Selected": "已選擇",
+ "Unselected": "未選擇",
+ "Status": "來貨狀態",
+ "Stock Qty": "存貨量",
+ "Material Demand List (7 Days)": "物料需求列表(7 天)",
+ "Mon": "週一",
+ "Tue": "週二",
+ "Wed": "週三",
+ "Thu": "週四",
+ "Fri": "週五",
+ "Sat": "週六",
+ "Sun": "週日",
+ "Last Month Average Stock": "上個月平均庫存",
+ "Last Month Average Sales": "上個月平均銷售",
+ "Safety Stock": "安全庫存",
+ "Demand Qty (7 Days)": "需求數量(7 天)",
+ "Estimated Production Time": "預估生產時間",
+ "Export Schedule": "匯出排程",
+ "Production Priority": "生產優先順序",
+ "View BoM": "查看 BOM",
+ "Date": "日期",
+ "Detail Scheduling": "詳細排程",
+ "Detailed Schedule": "詳細排程",
+ "FG Production Schedule": "成品生產排程",
+ "Production Date": "生產日期",
+ "Total Job Order": "總工單數量",
+ "Total Production Qty": "總生產數量",
+ "Job No.": "工單編號",
+ "Job Name": "工單名稱",
+ "Job Type": "工單類型",
+ "Job Status": "工單狀態",
+ "Job Priority": "工單優先順序",
+ "Job Date": "工單日期",
+ "Job Qty": "工單數量",
+ "mat": "物料",
+ "consumables": "消耗品",
+ "non-consumables": "非消耗品",
+ "fg": "成品",
+ "sfg": "半成品",
+ "item": "物品",
+ "UoM": "單位",
+ "Type": "類型",
+ "Test Detailed Schedule": "測試細排",
+ "Test Rough Schedule": "測試粗排",
+ "detailed": "細排",
+ "Detailed": "細排",
+ "Product Count(s)": "產品數量",
+ "Overall": "總計",
+ "Back": "返回",
+ "Avg Qty Last Month": "最近每日用量",
+ "Batch Need": "生產批次",
+ "Days Left": "可用日",
+ "Output Qty": "每批次生產數",
+ "Item Name": "物料名稱",
+ "Priority": "優先順序",
+ "Mat Code": "物料編號",
+ "Mat Name": "物料名稱",
+ "Required Qty": "所需數量",
+ "Total Qty Need": "所需總數量",
+ "Purchased Qty": "已採購數量",
+ "On Hand Qty": "現有庫存量",
+ "Unavailable Qty": "不可用數量",
+ "Related Item Code": "相關物料編號",
+ "Related Item Name": "相關物料名稱",
+ "Material Summary": "物料摘要",
+ "Generate Job Order": "生成工單"
}
diff --git a/src/i18n/zh/scheduling.json b/src/i18n/zh/scheduling.json
new file mode 100644
index 0000000..7d8af61
--- /dev/null
+++ b/src/i18n/zh/scheduling.json
@@ -0,0 +1,5 @@
+{
+ "title": "排程",
+ "Scheduling": "排程",
+ "ps": "排程"
+}
diff --git a/src/i18n/zh/settings.json b/src/i18n/zh/settings.json
index febef27..8ab1f97 100644
--- a/src/i18n/zh/settings.json
+++ b/src/i18n/zh/settings.json
@@ -1,14 +1,14 @@
{
- "Demand Forecast Setting": "需求預測設定",
- "QC Check Template": "QC 檢查模板",
- "QC Check Template Details": "QC 檢查模板詳情",
- "QC Check Template Name": "QC 檢查模板名稱",
- "QC Check Template Description": "QC 檢查模板描述",
- "QC Check Template Status": "QC 檢查模板狀態",
- "QC Check Template Created At": "QC 檢查模板建立時間",
- "QC Check Template Updated At": "QC 檢查模板更新時間",
- "Ready to import": "準備匯入",
- "Import Po": "匯入PO",
- "Import Master Data": "匯入主資料"
-
-}
\ No newline at end of file
+ "settings": "設定",
+ "Demand Forecast Setting": "需求預測設定",
+ "QC Check Template": "QC 檢查模板",
+ "QC Check Template Details": "QC 檢查模板詳情",
+ "QC Check Template Name": "QC 檢查模板名稱",
+ "QC Check Template Description": "QC 檢查模板描述",
+ "QC Check Template Status": "QC 檢查模板狀態",
+ "QC Check Template Created At": "QC 檢查模板建立時間",
+ "QC Check Template Updated At": "QC 檢查模板更新時間",
+ "Ready to import": "準備匯入",
+ "Import Po": "匯入PO",
+ "Import Master Data": "匯入主資料"
+}
diff --git a/src/i18n/zh/shop.json b/src/i18n/zh/shop.json
new file mode 100644
index 0000000..6f34ecd
--- /dev/null
+++ b/src/i18n/zh/shop.json
@@ -0,0 +1,471 @@
+{
+ "mtmsRouteWarn_title": "車線資料警示",
+ "mtmsRouteWarn_tooltipHas": "有 {{count}} 筆潛在衝突",
+ "mtmsRouteWarn_tooltipNone": "目前無警示",
+ "mtmsRouteWarn_refresh": "重新整理資料",
+ "mtmsRouteWarn_refreshing": "載入中…",
+ "mtmsRouteWarn_copyAll": "複製全部",
+ "mtmsRouteWarn_parseHint": "有 {{count}} 筆 4F 車線無法判斷星期(未列入警示)",
+ "mtmsRouteWarn_empty": "目前沒有資料衝突。",
+ "mtmsRouteWarn_conflict4f": "4F 同店跨車線 · 星期 {{weekday}}",
+ "mtmsRouteWarn_conflictDep": "非 4F 同店跨車線 · 出車 {{time}}",
+ "mtmsRouteWarn_shop": "店鋪",
+ "mtmsRouteWarn_postAddConflict": "新增店鋪後與其他車線資料衝突(請開啟右上角鈴鐺查看明細)。",
+ "No changes": "沒有變更",
+ "Saved": "已儲存",
+ "Failed to save": "儲存失敗",
+ "Changed": "已變更",
+ "Logistic": "物流商",
+ "Driver": "司機",
+ "Plate": "車牌",
+ "Departure": "出車",
+ "Shops": "店鋪",
+ "Current version": "目前版本",
+ "new arrangement": "新編排",
+ "Submitting...": "提交中…",
+ "saveChanges": "儲存更改",
+ "warnExpand": "展開",
+ "warnCollapse": "收合",
+ "warnClipboardStore": "樓層",
+ "warnClipboardDep": "出車",
+ "warnClipboardWeekday": "星期",
+ "pageTitle": "車線店鋪管理",
+ "importRoutes": "匯入車線",
+ "exportRoutes": "匯出車線",
+ "routeReport": "車線報告",
+ "departureTooltipNeedShops": "先新增店鋪才能設定出車時間",
+ "departureTooltipEditSave": "編輯出車時間(按「儲存更改」寫回)",
+ "departureEditAria": "編輯出車時間",
+ "saveDisabledTooltip": "請先拖曳、編輯出車時間/裝車順序/物流商等變更後再儲存",
+ "cancel": "取消",
+ "drawerClose": "關閉",
+ "tabBoard": "車線看板",
+ "tabLogistics": "物流商管理",
+ "quickIndex": "快速索引",
+ "versionLogDialogTitle": "版本變更紀錄",
+ "emDash": "—",
+ "val_logisticsRequired": "請填寫物流公司、車牌、司機姓名",
+ "val_logisticsDuplicateName": "已有同名物流公司或暫存新增(請換名稱)",
+ "val_phoneInvalid": "請輸入有效聯絡電話(數字)",
+ "err_save": "儲存失敗",
+ "err_invalidMasterId": "無效的主檔 id",
+ "err_exportNeedSelection": "請先於左側勾選要匯出的車線",
+ "err_export": "匯出失敗",
+ "err_noLanes": "目前無車線資料",
+ "err_import": "匯入失敗",
+ "err_dragDuplicateShop": "目標車線已有相同店鋪(同一 shop / 同一 shopCode),無法拖入",
+ "district_err_name": "請輸入地區名稱",
+ "district_err_reserved": "「未分類」已內建,請勿重複新增",
+ "district_err_exists": "此地區已存在",
+ "route_err_code": "請填車線編號",
+ "route_err_departure": "請選擇或輸入出車時間",
+ "route_err_duplicate": "此車線(含備註組合)已存在",
+ "route_err_create": "新增車線失敗",
+ "confirm_addShopConflict": "偵測到 {{count}} 筆可能與其他車線衝突(見右上角鈴鐺)。將先加入畫面,按「儲存更改」才寫入後端。仍要加入?",
+ "confirm_discardDraftShop": "捨棄尚未儲存的「新增店鋪」?",
+ "confirm_removeShop": "從此車線移除此店鋪?(按「儲存更改」才會寫入)",
+ "confirm_schedule_removeShop": "從此車線移除此店鋪?此操作將列入預約排程的刪除項目。",
+ "confirm_clearLane": "確定清空車線「{{laneLabel}}」的 {{count}} 筆店鋪?(按「儲存更改」才會從後端刪除)",
+ "confirm_departureConflict": "變更出車時間後,偵測到 {{count}} 筆可能衝突(見鈴鐺)。仍要套用?",
+ "drag_blockDraftShop": "尚未儲存的「新增店鋪」請先按「儲存更改」寫入,或從卡片刪除草稿後再拖曳。",
+ "nav_unsavedLeave": "有未儲存的更改,確定要離開?",
+ "save_clearedEmptyDistricts": "僅有空地區區塊(尚無店鋪),已清除暫存",
+ "api_fail_createLane": "新增車線失敗",
+ "api_fail_addShop": "新增店鋪失敗",
+ "api_fail_updateLane": "更新車線失敗",
+ "api_fail_deleteShop": "刪除店鋪失敗",
+ "api_fail_updateLogistics": "更新物流商失敗",
+ "diff_loadFail": "載入版本變更失敗",
+ "versionNote_saveFail": "備註儲存失敗",
+ "diff_restoreFail": "恢復失敗",
+ "confirm_restoreDiscardsEdits": "排程版本還原會捨棄目前看板上其他未儲存變更(拖曳、刪除、新增店鋪/車線、物流欄等)。確定繼續?",
+ "diff_restoreScheduled": "已排程還原至版本 #{{versionId}};請按「儲存更改」寫入後端。",
+ "diff_restoreAlreadyPending": "此版本已在排程還原中;請按「儲存更改」套用。",
+ "restore_applied": "已從版本還原並重新載入看板。",
+ "restore_appliedDroppedStaging": "已套用版本還原;本次儲存略過其他暫存變更(請重新編輯)。",
+ "confirm_restoreSaveWillDropStaging": "儲存時將先套用版本還原,本次其他暫存變更會被略過。確定繼續?",
+ "diff_noOlderCompare": "沒有上一筆版本可比較(請選擇較新的版本)",
+ "logistic_needMasterTpl": "「{{name}}」尚無對應物流公司,請先用「新增物流商」建立。",
+ "diffField_logisticsCompany": "物流公司",
+ "diffLogistic_unassigned": "未分配",
+ "diff_onLane": "車線 {{lane}}",
+ "diff_moveTo": "移至 {{lane}}",
+ "diff_addedToLane": "新加入車線 {{lane}}",
+ "diff_removedFromLane": "自 {{lane}} 移除",
+ "diff_editedCaption": "欄位調整(順序 / 分店名 / 時段等)",
+ "diff_restoreToHead": "排程還原至最新版本(須儲存)",
+ "diff_restoreToSelected": "排程還原至此版本(須儲存)",
+ "dialog_close": "關閉",
+ "btn_addLogistics": "新增物流商",
+ "logistics_sidebarEmpty": "無車線(請重新整理或放寬篩選)",
+ "lane_companyChip": "{{count}} 車線",
+ "lane_selectTitle": "車線選擇",
+ "lane_selectedNone": "未選擇車線",
+ "lane_selectedCount": "已選 {{count}} 條",
+ "lane_searchPh": "搜索…",
+ "lane_selectAll": "全選",
+ "floor_label": "樓層",
+ "floor_all": "全部",
+ "filter_clear": "清除",
+ "filter_apply": "確定",
+ "btn_addLane": "新增車線",
+ "tools_title": "操作工具",
+ "shop_searchPh": "搜索店鋪名稱/編號/地區...",
+ "btn_openVersionLog": "查看版本變更",
+ "btn_loading": "載入中…",
+ "btn_refresh": "重新整理",
+ "logistics_overviewTitle": "物流供應商總覽",
+ "version_ui_historyTitle": "版本歷史列表",
+ "version_ui_filterAria": "版本列表篩選",
+ "version_ui_listAria": "版本歷史列表",
+ "version_ui_snapshotBadge": "目前版本",
+ "version_ui_id": "版本#{{id}}",
+ "version_ui_none": "尚無版本",
+ "version_ui_editedBy": "編輯者:{{name}}",
+ "version_note_placeholder": "備註(離開欄位即儲存)",
+ "version_note_saving": "儲存中…",
+ "version_search_label": "搜索",
+ "version_search_placeholder": "版本號 / 備註 / 編輯者",
+ "version_date_label": "日期",
+ "version_empty_filtered": "沒有符合篩選條件的版本",
+ "version_empty_list": "暫時無版本(請先按「儲存更改」)",
+ "diff_clickLeft": "請點擊左側版本查看變更",
+ "diff_oldestSnapshot": "此為當前版本。",
+ "diff_summary_title": "版本摘要",
+ "diff_export_reportBtn": "匯出版本車線報告",
+ "diff_summary_added": "新增",
+ "diff_summary_moved": "移動",
+ "diff_summary_deleted": "刪除",
+ "diff_summary_fieldChange": "欄位變更",
+ "diff_shopList_title": "店鋪變更清單",
+ "diff_staged_boardPendingLine": "看板另有 {{count}} 筆未儲存/已排程項(見下方清單)。",
+ "diff_staged_section_title": "看板未儲存/已排程(尚未寫入後端)",
+ "diff_staged_section_subtitle": "下列與「儲存更改」後才會落庫的狀態一致;與上方版本 diff 分開列,避免與 Excel(僅後端版本)混淆。",
+ "diff_staged_tag_unsaved": "未儲存",
+ "diff_staged_tag_scheduled": "已排程",
+ "diff_staged_restoreScheduled": "已排程還原至版本 #{{versionId}}(須按「儲存更改」才會呼叫 restore)。",
+ "diff_staged_deleteUnknown": "刪除 truck id={{id}}(未儲存;明細請先儲存或取消後重試)",
+ "diff_staged_newLane": "新增車線(未儲存):{{lane}}",
+ "diff_staged_laneLogistic": "整線物流(未儲存):{{lane}} → {{company}}",
+ "diff_staged_emptyDistricts": "空地區區塊(未儲存):{{lane}} — {{names}}",
+ "diff_staged_shopDistrictHint": " · 地區:{{from}}→{{to}}",
+ "diff_staged_shopPendingOnLane": "{{name}}({{code}})— 車線 {{lane}}:有未儲存變更(拖曳/出車/裝載順序等;按「儲存更改」寫入){{districtPart}}",
+ "diff_staged_shopDistrictOnly": "{{name}}({{code}})— 車線 {{lane}}:地區 {{from}}→{{to}}(未儲存;按「儲存更改」寫入)",
+ "diff_staged_pendingLogisticMaster": "新增物流公司(未落庫):{{name}}(車牌 {{plate}});將與路線一併於「儲存更改」寫入",
+ "diff_staged_editLogisticMaster": "修改物流公司(未落庫):{{fromName}}({{fromPlate}})→ {{name}}({{plate}})",
+ "diff_staged_importPending": "匯入 Excel(未落庫):{{file}} — {{sheets}} 個工作表、{{rows}} 列(按「儲存更改」寫入)",
+ "confirm_importDiscardEdits": "匯入將取代目前看板上未儲存的變更,是否繼續?",
+ "import_staged_preview": "已載入匯入預覽:{{file}}({{sheets}} 表 / {{rows}} 列)。按「儲存更改」才會寫入後端。",
+ "err_importEmpty": "匯入檔案無有效車線資料列",
+ "diff_logisticMaster_section": "物流公司變更",
+ "diff_logisticMaster_added": "新增",
+ "diff_logisticMaster_edited": "修改",
+ "diff_noShopDiffHasBoardStaged": "與上一版本相比,店鋪列無差異;下列為看板上尚未按「儲存更改」寫入的變更(含新增物流公司)。",
+ "diff_export_blockedTooltip": "匯出檔為後端兩版本比對,不含看板未儲存變更。請先按「儲存更改」或取消變更後再匯出。",
+ "diff_export_blockedError": "有看板未儲存變更時無法匯出(Excel 僅含已落庫版本)。",
+ "diff_markedCount": "{{count}} 筆變更",
+ "diff_noDiffFromPrev": "與上一版無差異",
+ "diff_loadingEllipsis": "…",
+ "addShop_dialogTitle": "新增店鋪到車線",
+ "addRoute_dialogTitle": "新增配送車線",
+ "addRoute_hint": "確認後先加入看板暫存;須按頂部「儲存更改」才會在後端建立車線(不建立假店鋪列)。",
+ "addRoute_confirm": "確認新增車線",
+ "addRoute_submitting": "新增中…",
+ "district_dialog_add": "新增地區",
+ "district_dialog_edit": "編輯地區",
+ "district_name_label": "地區顯示名稱",
+ "district_name_ph": "空白表示「未分類」",
+ "district_help_null": "未分類對應後端 districtReference 為 null",
+ "district_help_mapped": "顯示名稱經 toDistrictRawValue 寫入各店鋪 districtReference;按「儲存更改」才打 API",
+ "seq_edit_departureLabel": "出車時間",
+ "seq_edit_seqLabel": "裝車順序 (Seq)",
+ "route_new_code_label": "車線編號",
+ "route_new_time_label": "出車時間",
+ "route_new_logistic_label": "物流公司",
+ "route_new_store_label": "樓層",
+ "route_new_remark_label": "車線備註 (4F)",
+ "logistic_companyName": "物流公司名稱",
+ "logistic_plate": "車牌",
+ "logistic_driver": "司機姓名",
+ "logistic_phone": "聯絡電話",
+ "logistic_btn_save": "儲存",
+ "logistic_btn_saveDb": "儲存至資料庫",
+ "shop_autocomplete_label": "選擇店鋪",
+ "shop_autocomplete_ph": "輸入名稱或代碼篩選",
+ "shop_autocomplete_loading": "尚未載入店鋪主檔",
+ "shop_autocomplete_noOptions": "此車線已含所有可選店鋪或無可選項",
+ "dialog_addLogisticsTitle": "新增物流商",
+ "btn_cancelBack": "取消返回",
+ "quickPick_noLanes": "目前無車線(請放寬樓層篩選或重新整理)",
+ "quickPick_noKeyword": "無符合關鍵字的車線",
+ "route_logisticUnspecified": "(未指定——稍後於物流商管理指派)",
+ "dialog_editLogisticsTitle": "編輯物流公司",
+ "btn_apply": "套用",
+ "addShop_confirm": "確認",
+ "addShop_listHint": "同車線內已存在的店鋪代碼不會出現在清單。新增後若要改順序可拖曳;與其他編輯相同,需按「儲存更改」才會寫入後端 truck。",
+ "departureDialog_title": "編輯出車時間",
+ "departureDialog_hint": "套用至此車線所有店鋪列;按上方「儲存更改」寫入後端。",
+ "seqDialog_title": "編輯裝車順序",
+ "seqDialog_hint": "按「儲存更改」後寫入 truck 列。",
+ "logistics_colLaneCount": "{{count}} 條車線",
+ "tooltip_openLaneBoard": "在車線看板開此車線",
+ "aria_openLaneBoard": "開啟車線看板",
+ "tooltip_removeFromLane": "從此車線移除",
+ "tooltip_clearLaneShops": "清空此車線所有店鋪(按「儲存更改」才寫入後端)",
+ "tooltip_pickLane": "選擇車線(加入看板勾選並捲動到該欄)",
+ "aria_pickLane": "選擇車線",
+ "aria_searchLanes": "搜索車線",
+ "logistics_colShopCount": "{{count}} 家店鋪",
+ "tooltip_editLogisticsDb": "編輯物流公司(須按「儲存更改」寫入)",
+ "tooltip_deleteLogistics": "刪除物流公司(須按「儲存更改」寫入)",
+ "aria_editLogistics": "編輯物流公司",
+ "aria_deleteLogistics": "刪除物流公司",
+ "confirm_deleteLogistic": "確定刪除物流公司「{{name}}」?須按「儲存更改」寫入。",
+ "err_logisticDeleteHasLanes": "此物流公司尚有 {{count}} 條車線,請先移走或改派後再刪除。",
+ "diff_staged_deleteLogisticMaster": "刪除物流公司(未落庫):{{name}}",
+ "logistic_btn_apply": "套用",
+ "tooltip_editDistrict": "編輯地區名稱(按「儲存更改」才寫入)",
+ "aria_editDistrict": "編輯地區",
+ "tooltip_removeEmptyDistrict": "移除此暫存區塊(未儲存前可刪)",
+ "aria_removeEmptyDistrict": "移除空區",
+ "tooltip_editSeq": "編輯裝車順序(按「儲存更改」寫回)",
+ "aria_editSeq": "編輯裝車順序",
+ "diff_moveFrom": "從 {{lane}}",
+ "logistics_dirtyColumnBadge": "有未儲存物流更改",
+ "logistics_dirtyLaneBadge": "未儲存物流更改",
+ "lane_shopCountInline": "{{count}} 間店鋪",
+ "btn_addDistrict": "新增地區",
+ "empty_lane_noShops": "無分配店鋪",
+ "btn_addShopToLane": "新增店鋪",
+ "err_loadLanes": "載入車線失敗",
+ "btn_scheduleChange": "預約變更",
+ "schedule_modal_title": "預約變更",
+ "schedule_modal_subtitle": "設定排程變更的生效時間",
+ "schedule_step_time": "1. 設定執行時間",
+ "schedule_exec_date": "執行日期",
+ "schedule_exec_time": "執行時間",
+ "schedule_step_method": "2. 排程與預定變更",
+ "schedule_tab_manual": "拖拽排程",
+ "schedule_tab_import": "匯入車線Excel",
+ "schedule_search_ph": "搜索店舖名稱 / 編號...",
+ "schedule_bulk_target": "批次設定目標:",
+ "schedule_pick_lane": "選擇車線...",
+ "schedule_col_select": "選取",
+ "schedule_col_shop": "店舖資訊",
+ "schedule_col_current_lane": "目前車線",
+ "schedule_col_target_lane": "目標車線",
+ "schedule_col_target_district": "地區",
+ "schedule_col_target_seq": "序號",
+ "schedule_district_original": "沿用店舖原始地區",
+ "schedule_seq_hint": "目標車線內同地區區段的最大序號 +1 為預設值",
+ "schedule_bulk_seq": "統一序號",
+ "schedule_history_line_placement": "目標地區 {{district}} · 序號 {{seq}}",
+ "schedule_line_on_lane": "車線 {{lane}}",
+ "schedule_line_lane_change": "{{from}} → {{to}}",
+ "schedule_line_seq": "序號 {{value}}",
+ "schedule_line_district_change": "地區 {{from}} → {{to}}",
+ "schedule_line_district_target": "地區 {{district}}",
+ "schedule_line_departure_change": "出車 {{from}} → {{to}}",
+ "schedule_line_departure_target": "出車 {{time}}",
+ "schedule_line_remove_from": "自 {{lane}} 移除",
+ "schedule_line_add_to": "新增至 {{lane}}",
+ "schedule_line_ensure_lane": "建立車線 {{lane}}",
+ "schedule_target_unset": "未設定",
+ "schedule_no_shops": "無符合條件的店舖",
+ "schedule_import_title": "匯入車線配置(與看板相同格式)",
+ "schedule_import_hint": "請使用與看板「匯入車線」相同的 車線Excel",
+ "schedule_import_pick": "選擇檔案",
+ "schedule_import_need_datetime": "請先設定執行日期與時間",
+ "schedule_import_no_valid_moves": "檔案中沒有可排程的變更(未偵測到移動、新增、刪除或新建車線)",
+ "schedule_import_preview_summary": "已載入 {{file}}:{{sheets}} 個工作表 / {{rows}} 列 · 可排程 {{valid}} 筆 · 略過 {{errors}} 筆",
+ "schedule_import_plan_summary": "已載入 {{file}}:{{sheets}} 個工作表 / {{rows}} 列 · 移動 {{moves}} · 新增 {{creates}} · 刪除 {{deletes}} · 新建車線 {{ensureLanes}} · 略過 {{errors}} 筆",
+ "schedule_import_col_action": "動作",
+ "schedule_import_col_shop": "店鋪編號",
+ "schedule_import_col_name": "店鋪名稱",
+ "schedule_import_col_lane": "目標車線",
+ "schedule_import_col_seq": "序號",
+ "schedule_import_skipped_title": "略過 {{count}} 筆",
+ "schedule_import_row_error": "{{shop}}({{name}}):{{reason}}",
+ "schedule_import_err_no_truck_row": "店鋪 {{shop}} 尚無看板列,請先於看板匯入或新增",
+ "schedule_import_err_no_target_lane": "店鋪 {{shop}} 缺少目標車線",
+ "schedule_import_err_invalid_departure": "店鋪 {{shop}} 出車時間無效",
+ "schedule_import_err_truck_not_found": "找不到店鋪 {{shop}} 的看板列",
+ "schedule_import_err_placeholder_row": "店鋪 {{shop}} 在空白占位列上",
+ "schedule_action_move": "移動",
+ "schedule_action_create": "新增店鋪",
+ "schedule_action_delete": "刪除",
+ "schedule_action_ensure_lane": "新建車線",
+ "schedule_summary_ready": "所有設定已就緒",
+ "schedule_summary_pending": "待完成目標設定",
+ "schedule_summary_counts": "已選 {{selected}} 個店舖,其中 {{ready}} 個已指派目標車線。",
+ "schedule_summary_changes": "共有 {{count}} 項變更",
+ "schedule_lane_left": "左側車線",
+ "schedule_lane_right": "右側車線",
+ "schedule_review_queue": "變更預覽佇列",
+ "schedule_review_count": "{{count}} 項變更",
+ "schedule_review_empty": "暫無待排程變更",
+ "schedule_review_empty_hint": "請拖曳店鋪以調整其車線分配或裝載排程順序,或使用刪除按鈕移除店鋪",
+ "schedule_review_revert": "復原",
+ "schedule_review_delete_action": "刪除自:",
+ "schedule_review_lane_change": "車線變更:",
+ "schedule_review_district_change": "區域參考:",
+ "schedule_review_seq": "裝載順序:",
+ "schedule_drop_hint": "請拖曳店鋪卡片至此車線",
+ "schedule_moved_badge": "移入",
+ "schedule_drag_seq": "裝載順序 Seq: {{seq}}",
+ "schedule_seq_edit_btn": "編輯裝載順序",
+ "schedule_seq_dialog_hint": "變更會加入右側預覽佇列,確認排程後才套用。",
+ "schedule_planned_label": "執行預定",
+ "schedule_confirm_btn": "確認多項預約變更",
+ "schedule_applied_snackbar": "已登記 {{count}} 筆預約變更並更新看板,請按「儲存更改」寫入後端。",
+ "schedule_err_conflict": "部分店舖無法移至目標車線(重複店鋪或草稿列)。",
+ "schedule_err_execute_at_past": "排程執行時間已過去,請選擇未來的日期與時間。",
+ "schedule_err_open_pending": "店舖列 #{{id}} 已有待執行的排程。",
+ "schedule_err_duplicate_shop": "目標車線上已有店舖 {{shop}}。",
+ "schedule_err_target_lane_missing": "找不到目標車線 {{lane}}。",
+ "schedule_err_target_lane_empty": "目標車線 {{lane}} 尚無店舖,請先加入店舖。",
+ "schedule_err_no_moves": "沒有可排程的店舖移動。",
+ "schedule_err_generic": "排程請求失敗,請稍後再試。",
+ "schedule_reschedule_time_adjusted": "原執行時間已過去,已自動調整為 {{at}}。",
+ "schedule_shop_badge": "已排程變更",
+ "schedule_shop_locked": "排程執行中,此店鋪暫不可手改",
+ "schedule_retry_rejects_partial": "PARTIAL 排程不可重試,請先還原看板後重新建立排程",
+ "schedule_registered_snackbar": "已登記 {{count}} 筆預約變更,將於執行時間由伺服器自動套用。",
+ "schedule_import_parse_summary": "解析完成:有效 {{valid}} 筆,錯誤 {{errors}} 筆",
+ "schedule_import_confirm_btn": "確認匯入並建立排程",
+ "schedule_history_title": "預約任務狀態與歷程中心",
+ "schedule_history_subtitle": "檢視、執行或排查已排程的店舖/車線變更",
+ "schedule_history_filter_all": "全部任務",
+ "schedule_history_filter_pending": "排程中",
+ "schedule_history_filter_success": "已成功",
+ "schedule_history_filter_failed": "已失敗",
+ "schedule_history_empty": "無符合篩選條件的預約任務",
+ "schedule_history_status_pending": "排程中",
+ "schedule_history_status_success": "執行成功",
+ "schedule_history_status_failed": "執行失敗",
+ "schedule_history_created": "創建者:{{by}}",
+ "schedule_history_unknown_user": "系統",
+ "schedule_history_line_counts": "明細 {{total}} 筆 · 成功 {{applied}} · 失敗 {{failed}} · 待執行 {{pending}}",
+ "schedule_history_applied_at": "成功執行時間:{{at}}",
+ "schedule_history_view_lines": "檢視店舖明細",
+ "schedule_history_no_lines": "尚無明細資料",
+ "schedule_history_failed_lines": "{{count}} 筆店舖移線失敗",
+ "schedule_history_success_lines": "{{count}} 筆店舖已成功移線",
+ "schedule_history_apply_now": "立即執行",
+ "schedule_history_cancel": "取消排程",
+ "schedule_history_archived": "已執行",
+ "schedule_history_needs_attention": "需處理",
+ "schedule_history_reschedule": "重新排程",
+ "schedule_history_ignore": "忽略",
+ "schedule_history_status_ignored": "已忽略",
+ "schedule_history_close": "關閉視窗",
+ "schedule_log_failed_hint": "有 {{count}} 個預約任務執行失敗,請查看 Log",
+ "btn_scheduleHistory": "查看預約變更 Log",
+ "id": "ID",
+ "code": "編號",
+ "Shop Name": "店鋪名稱",
+ "Code": "編號",
+ "Name": "名稱",
+ "Addr3": "地址",
+ "TruckLance Status": "車線狀態",
+ "Complete": "完成",
+ "Missing Data": "缺少資料",
+ "No TruckLance": "無車線",
+ "Actions": "操作",
+ "View Detail": "查看詳情",
+ "ShopAndTruck": "車線店鋪管理",
+ "Shop": "店鋪",
+ "Truck Lane": "車線",
+ "Filter by Status": "按狀態篩選",
+ "All": "全部",
+ "Please log in to view shop details": "請登入以查看店鋪詳情",
+ "Shop ID is required": "需要店鋪ID",
+ "Invalid Shop ID": "無效的店鋪ID",
+ "Shop not found": "找不到店鋪",
+ "Failed to load shop details": "載入店鋪詳情失敗",
+ "Failed to delete truck lane": "刪除車線失敗",
+ "Failed to load truck lanes": "載入車線失敗",
+ "Shop Information": "店鋪資訊",
+ "TruckLance Code": "車線編號",
+ "Departure Time": "出發時間",
+ "Please fill in the following required fields:": "請填寫以下必填欄位:",
+ "Failed to create truck": "建立卡車失敗",
+ "Back": "返回",
+ "Addr1": "地址1",
+ "Addr2": "地址2",
+ "Contact No": "聯絡電話",
+ "Contact Email": "聯絡郵箱",
+ "Contact Name": "聯絡人",
+ "Truck Information": "車線資訊",
+ "Add Truck Lane": "新增車線",
+ "Loading Sequence": "裝載順序",
+ "District Reference": "區域參考",
+ "Store ID": "樓層",
+ "Remark": "備註",
+ "No Truck data available": "沒有卡車資料",
+ "Cancel": "取消",
+ "Delete truck lane": "刪除車線",
+ "Add New Truck Lane": "新增車線",
+ "Save": "儲存",
+ "Truck lane code already exists. Please use a different code.": "車線編號已存在,請使用其他編號。",
+ "No Truck Lane data available": "沒有車線資料",
+ "TruckLance Code is required": "需要車線編號",
+ "Truck lane not found": "找不到車線",
+ "Failed to load truck lane detail": "載入車線詳情失敗",
+ "Failed to load shops": "載入店鋪失敗",
+ "Truck lane information is required": "需要車線資訊",
+ "Invalid departure time": "無效的出發時間",
+ "No trucks found for this truck lane": "此車線沒有可更新的資料",
+ "Departure time updated for all shops on this truck lane": "已將出發時間更新至此車線下的所有店鋪",
+ "Failed to save truck data": "儲存卡車資料失敗",
+ "Invalid shop data": "無效的店鋪資料",
+ "Truck shop details updated successfully": "卡車店鋪詳情更新成功",
+ "Failed to save truck shop details": "儲存卡車店鋪詳情失敗",
+ "All shops updated successfully": "所有店鋪已成功更新",
+ "Truck lane deleted successfully": "車線刪除成功",
+ "Shop added to truck lane successfully": "店鋪已成功新增至車線",
+ "Failed to create shop in truck lane": "新增店鋪至車線失敗",
+ "Back to Truck Lane List": "返回車線列表",
+ "No truck lane data available": "沒有車線資料",
+ "Truck Lane Detail": "車線詳情",
+ "Edit departure time": "編輯出發時間",
+ "Cancel editing": "取消編輯",
+ "Shops Using This Truck Lane": "使用此車線的店鋪",
+ "Save All": "全部儲存",
+ "Mass Edit": "批量編輯",
+ "Add Shop": "新增店鋪",
+ "Shop Branch": "店鋪分店",
+ "Shop Code": "店鋪編號",
+ "No shops found using this truck lane": "沒有找到使用此車線的店鋪",
+ "Search or select remark": "搜索或選擇備註",
+ "Not editable for this Store ID": "此樓層不可編輯",
+ "Save changes": "儲存變更",
+ "Edit shop details": "編輯店鋪詳情",
+ "Add Shop to Truck Lane": "新增店鋪至車線",
+ "Search or select shop name": "搜索或選擇店鋪名稱",
+ "Applies to all shops using this truck lane": "將套用至所有使用此車線的店鋪",
+ "Edit loading sequence": "編輯裝載順序",
+ "Edit shop truck lane": "編輯店鋪車線",
+ "Edit truck lane": "編輯車線",
+ "Invalid truck data": "無效的卡車資料",
+ "Loading sequence updated successfully": "裝載順序更新成功",
+ "Failed to load shop detail": "載入店鋪詳情失敗",
+ "Failed to save loading sequence": "儲存裝載順序失敗",
+ "Route Board": "車線看板",
+ "Select a shop first": "請先選擇店鋪",
+ "Select items without order to append to bottom": "只會顯示尚未設定順序的物品",
+ "Shop Detail": "店鋪詳情",
+ "Truck ID is required": "需要卡車ID",
+ "Are you sure you want to delete this truck lane?": "您確定要刪除此車線嗎?",
+ "Search or select branch": "搜索或選擇分店",
+ "Search or select shop code": "搜索或選擇店鋪編號",
+ "versionLogField_departureTime": "發車時段",
+ "versionLogField_loadingSequence": "裝載順序",
+ "versionLogField_branchName": "分店名稱",
+ "versionLogField_districtReference": "區域",
+ "versionLogField_shopCode": "店鋪代碼",
+ "versionLogField_storeId": "樓層/店別",
+ "versionLogField_remark": "備註",
+ "versionLogField_truckLanceCode": "車線代碼",
+ "versionLogField_logisticId": "物流公司"
+}
diff --git a/src/i18n/zh/stockIssue.json b/src/i18n/zh/stockIssue.json
new file mode 100644
index 0000000..ca77898
--- /dev/null
+++ b/src/i18n/zh/stockIssue.json
@@ -0,0 +1,78 @@
+{
+ "Action": "操作",
+ "Available Qty": "可用數量",
+ "Bad Item": "不良",
+ "Bad Item Handle": "不良品處理",
+ "Bad Item Qty": "不良品數量",
+ "Bad Item Records": "不良品處理紀錄",
+ "Batch Disposed All": "批量處理完成",
+ "Book Qty": "帳面庫存",
+ "Cancel": "取消",
+ "Code": "編號",
+ "Defective Qty": "不良數量",
+ "Disposed": "已處置",
+ "Disposing...": "處理中...",
+ "DO Order Code": "送貨單編號",
+ "End Date": "結束日期",
+ "Expiry Date": "到期日",
+ "Expiry End Date": "到期日(結束)",
+ "Expiry Item": "過期",
+ "Expiry Item Handle": "過期品處理",
+ "Expiry Item Qty": "過期品數量",
+ "Expiry Item Records": "過期品處理紀錄",
+ "Expiry Start Date": "到期日(開始)",
+ "Failed to load expiry items": "載入過期品失敗",
+ "Failed to submit": "提交失敗",
+ "Failed to submit expiry item": "提交過期品失敗",
+ "Handled Date": "處理日期",
+ "Handler": "處理人",
+ "Issue Qty": "問題數量",
+ "Item": "貨品",
+ "Item Code": "貨品編號",
+ "Item not found": "找不到貨品",
+ "Item selected": "已選擇貨品",
+ "JO Order Code": "工單編號",
+ "Loading": "加載中",
+ "Location": "位置",
+ "Looked": "已查看",
+ "Lot No": "批號",
+ "Lot No.": "批號",
+ "Miss Item": "缺貨",
+ "Miss Qty": "缺貨數量",
+ "Name": "名稱",
+ "No changes to submit": "沒有可提交的變更",
+ "No items are selected yet.": "未選擇貨品",
+ "No record found": "沒有記錄",
+ "Picker Name": "提料員",
+ "Pick Order Code": "提料單編號",
+ "Please enter a valid quantity": "請輸入有效數量",
+ "Please set at least one search criterion": "請至少設定一項搜索條件",
+ "Processing...": "處理中...",
+ "Quantity exceeds available quantity": "數量超過可用數量",
+ "Remain available Quantity": "剩餘可用數量",
+ "Remaining Qty": "剩餘數量",
+ "Remark": "備註",
+ "Remarks": "備註",
+ "Reset": "重置",
+ "Rows per page": "每頁行數",
+ "Saved successfully": "儲存成功",
+ "Search": "搜索",
+ "Search Criteria": "搜索條件",
+ "Search to load lot lines": "請按搜索以載入批號",
+ "Start Date": "開始日期",
+ "Status": "狀態",
+ "Stock UoM": "庫存單位",
+ "Submit": "確認",
+ "Submit Bad Item": "提交不良品",
+ "Submit Miss Item": "提交缺貨",
+ "Submit Quantity": "實際問題數量",
+ "Submitting...": "提交中...",
+ "Type": "類型",
+ "Unknown error": "未知錯誤",
+ "UoM": "單位",
+ "User ID is required": "需要用戶ID",
+ "Warehouse": "倉庫",
+ "available": "可用",
+ "unavailable": "不可用",
+ "Stock Issue": "出倉問題"
+}
diff --git a/src/i18n/zh/stockRecord.json b/src/i18n/zh/stockRecord.json
new file mode 100644
index 0000000..204e11f
--- /dev/null
+++ b/src/i18n/zh/stockRecord.json
@@ -0,0 +1,32 @@
+{
+ "title": "庫存記錄",
+ "tke": "盤點",
+ "adj": "調整",
+ "nor": "正常",
+ "trf": "轉倉",
+ "open": "開倉",
+ "miss": "缺貨",
+ "bad": "不良",
+ "Start Date": "開始日期",
+ "End Date": "結束日期",
+ "Date": "日期",
+ "Item-lotNo": "貨品-批號",
+ "UOM": "單位",
+ "In Qty": "入庫數量",
+ "Out Qty": "出庫數量",
+ "Balance Qty": "庫存數量",
+ "Loading...": "載入中...",
+ "Type": "類別",
+ "Status": "狀態",
+ "pending": "待處理",
+ "completed": "已完成",
+ "partially_completed": "已部分完成",
+ "receiving": "收貨中",
+ "rejected": "已拒絕",
+ "checked": "已檢查",
+ "determine1": "上報1",
+ "lot-change": "批次更換審批",
+ "qc1": "質檢1",
+ "qc2": "質檢2",
+ "qc3": "質檢3"
+}
diff --git a/src/i18n/zh/stockTake.json b/src/i18n/zh/stockTake.json
new file mode 100644
index 0000000..1929dd1
--- /dev/null
+++ b/src/i18n/zh/stockTake.json
@@ -0,0 +1,179 @@
+{
+ "View Details": "查看詳細",
+ "Back to List": "返回列表",
+ "Stock Take Section": "盤點區域",
+ "Warehouse": "倉庫",
+ "All": "全部",
+ "Rows per page": "每頁行數",
+ "Remark": "備註",
+ "Action": "操作",
+ "Save": "保存",
+ "Selected Qty": "選擇數量",
+ "Not Match": "要求重點",
+ "Search Criteria": "搜索條件",
+ "Stock Take Section (can use , to search multiple sections)": "盤點區域(可使用逗號搜索多個區域)",
+ "Item": "貨品",
+ "Store ID": "樓層",
+ "Pending": "待處理",
+ "Pass": "已盤點",
+ "Reset": "重置",
+ "Search": "搜索",
+ "Cancel": "取消",
+ "Confirm": "確認",
+ "Type": "類型",
+ "Status": "來貨狀態",
+ "Lot No": "批號",
+ "Location": "位置",
+ "Reason": "原因",
+ "Date": "日期",
+ "Pick Order Code": "提料單編號",
+ "Item Code": "貨品編號",
+ "Pick Order": "提貨單",
+ "Required Qty": "所需數量",
+ "Issue Remark": "問題備註",
+ "Stock Take Management": "盤點管理",
+ "Stock Take Round": "盤點輪次",
+ "Plan Start Date": "計劃開始日期",
+ "Total Items": "總貨品數量",
+ "Total Lots": "總批號數量",
+ "Total Sections": "總區域數量",
+ "Section": "區域",
+ "Last Stock Take Date": "上次盤點日期",
+ "Stock Taker": "盤點員",
+ "Approver": "審核員",
+ "start time": "開始時間",
+ "end time": "結束時間",
+ "Control Time": "操作時間",
+ "Approver stock take record saved successfully": "審核員盤點記錄保存成功",
+ "Stock take record status updated to not match": "盤點狀態更新為要求重點",
+ "Batch approver save completed: {{success}} success, {{errors}} errors": "批次審核儲存完成:成功 {{success}} 筆,錯誤 {{errors}} 筆",
+ "Variance %": "差異百分比",
+ "Only Variance": "僅差異",
+ "Batch Save All": "批量保存所有",
+ "Warehouse Location": "倉庫位置",
+ "Item-lotNo-ExpiryDate": "貨品-批號-到期日",
+ "UOM": "單位",
+ "Stock Take Qty(include Bad Qty)= Available Qty": "盤點數= 可用數",
+ "Record Status": "盤點狀態",
+ "No data": "沒有數據",
+ "Difference": "差異",
+ "First": "第一次",
+ "Second": "第二次",
+ "Approver Input": "審核員輸入",
+ "Stock Take Qty": "盤點數",
+ "Bad Qty": "不良數量",
+ "selected stock take qty": "已選擇盤點數量",
+ "book qty": "帳面庫存",
+ "ReStockTake": "重新盤點",
+ "Approver input empty; save skipped, row remains pending": "審核員盤點數與不良數皆未輸入,已略過儲存,該列維持待審核",
+ "No rows loaded; set search criteria and search first": "尚未載入資料,請設定搜索條件並按搜索",
+ "Approver Time": "審核時間",
+ "Stock Take Qty Data and Variance Analysis": "盤點數數據與差異分析",
+ "Book Qty": "帳面庫存",
+ "Inventory Difference": "庫存差異",
+ "variance Percentage": "差異百分比",
+ "Variance": "差異",
+ "Picker": "盤點員",
+ "Variance filter inclusive only": "反選",
+ "Variance filter inclusive range hint": "只顯示 -{{value}}% {{op}} 差異% {{op}} {{value}}% 的列(範圍內)",
+ "Variance filter exclusive range hint": "只顯示 -{{value}}% {{op}} 差異% {{op}} {{value}}% 的列(範圍外)",
+ "Total": "總數",
+ "Shown": "顯示",
+ "Confirm batch save approver": "確認批次儲存審核",
+ "Batch save confirm message": "將對目前列表中的 {{count}} 筆盤點記錄執行批次儲存,是否繼續?",
+ "Stock take sections in current list": "目前列表涉及 {{count}} 個盤點區域",
+ "Stock Take": "盤點",
+ "Manual": "手動",
+ "Damage": "損壞",
+ "Return": "退貨",
+ "Approved": "已批准",
+ "Rejected": "已拒絕",
+ "Adjustment No, Item, Lot...": "處理編號, 貨品, 批號...",
+ "Total Adjustments": "總調整數量",
+ "Adjustment No": "處理編號",
+ "Before Qty": "處理前數量",
+ "After Qty": "處理後數量",
+ "Adjustment": "處理",
+ "Adjusted By": "處理者",
+ "No adjustments found": "未找到調整",
+ "Floor unassigned": "未設定樓層",
+ "Area": "倉位",
+ "Start Stock Take Date": "盤點日期",
+ "Create Stock Take (Select Sections)": "建立盤點(選擇區域)",
+ "Total Item Kind Number": "貨品種類數量",
+ "View ReStockTake": "查看重新盤點",
+ "Warehouse missing stock take section tooltip has": "有 {{count}} 個倉庫未設定盤點區域,點擊查看",
+ "Warehouse missing stock take section tooltip none": "所有倉庫均已設定盤點區域",
+ "Warehouse missing stock take section warn title": "未設定盤點區域的倉庫",
+ "Stock take round name": "盤點輪次名稱",
+ "Stock take round name placeholder": "選填,例如:五月全廠盤點",
+ "Creation date": "建立日期",
+ "No stock take sections from warehouse": "目前沒有盤點區域資料",
+ "Select all sections all floors": "全選區域 (所有樓層)",
+ "Clear selection all floors": "清除已選 (所有樓層)",
+ "Total selected sections label": "總計已選擇 :",
+ "sections unit": "個區域",
+ "Floor area selection header": "{{floor}} 區域選擇 ({{count}} 區域)",
+ "Deselect all on this floor": "取消全選此樓層 ({{floor}})",
+ "Select all on this floor": "全選此樓層 ({{floor}})",
+ "Search section code or name": "搜索代碼或名稱 (例如 ST-042 或 飲品)",
+ "No sections match search": "沒有符合搜索條件的區域",
+ "Confirm create stock take": "確認建立盤點",
+ "Not filled": "(未填寫)",
+ "Warehouse missing stock take section drawer hint": "以下倉庫位置尚未設定盤點區域(ST-xxx),無法納入盤點區域選擇。請至倉庫設定補上。",
+ "Warehouse missing stock take section showing": "顯示前 {{shown}} 筆,共 {{count}} 筆",
+ "Warehouse missing stock take section empty": "沒有未設定盤點區域的倉庫",
+ "Warehouse missing stock take section go settings": "前往倉庫設定",
+ "Available QTY cannot be negative": "可用數量不能為負數",
+ "Stock take record saved successfully": "盤點記錄保存成功",
+ "Batch save completed: {{success}} success, {{errors}} errors": "批量保存完成:{{success}} 成功,{{errors}} 失敗",
+ "No valid input to submit": "請先填寫盤點數量",
+ "Submit All Inputted": "提交所有輸入",
+ "Issue No": "問題編號",
+ "Actual Qty": "實際數量",
+ "Miss Qty": "缺貨數量",
+ "Category": "類型",
+ "Detail": "詳細",
+ "Issue Detail": "問題詳細",
+ "Handle Remark": "處理備註",
+ "Close": "關閉",
+ "Mark as Resolved": "標記為已解決",
+ "Pick Execution Issues": "揀貨執行問題",
+ "Inventory Adjustments": "存貨調整",
+ "Approver Pending": "審核待處理",
+ "Approver Approved": "審核通過",
+ "Created": "已建立",
+ "Skipped": "已略過",
+ "Errors": "錯誤",
+ "Failed to batch save approver stock take records": "批次儲存審核盤點記錄失敗",
+ "Failed to batch save stock take records": "批次儲存盤點記錄失敗",
+ "Failed to save approver stock take record": "儲存審核盤點記錄失敗",
+ "Failed to save stock take record": "儲存盤點記錄失敗",
+ "Failed to update stock take record status": "更新盤點記錄狀態失敗",
+ "First QTY is not available": "第一次盤點數不可用",
+ "Second QTY is not available": "第二次盤點數不可用",
+ "No valid records to batch save": "沒有可批次儲存的有效記錄",
+ "Please enter Approver QTY": "請輸入審核盤點數",
+ "Please enter Approver Bad QTY": "請輸入審核不良數",
+ "Please enter QTY": "請輸入盤點數",
+ "Please enter Second QTY": "請輸入第二次盤點數",
+ "Shortcut Input": "快捷輸入",
+ "Stock take record ID is required": "需要盤點記錄 ID",
+ "Invalid QTY": "無效的數量",
+ "Stock take qty exceeds maximum": "盤點數量不可超過 999,999,999,999",
+ "pass": "已盤點",
+ "notMatch": "要求重點",
+ "notmatch": "要求重點",
+ "completed": "已完成",
+ "stockTaking": "盤點中",
+ "approving": "審核中",
+ "resolved": "已解決",
+ "pending": "待處理",
+ "jo": "工單",
+ "do": "出貨單",
+ "material": "物料",
+ "lot_issue": "批號問題",
+ "quality_issue": "品質問題",
+ "quantity_mismatch": "數量不符",
+ "stock_take": "盤點"
+}
diff --git a/src/i18n/zh/ticketReleaseTable.json b/src/i18n/zh/ticketReleaseTable.json
index aa93d61..fcdaa61 100644
--- a/src/i18n/zh/ticketReleaseTable.json
+++ b/src/i18n/zh/ticketReleaseTable.json
@@ -4,7 +4,7 @@
"Today": "是日",
"Tomorrow": "翌日",
"Day After Tomorrow": "後日",
- "Now": "現時",
+ "Now": "現時",
"Last updated": "最後更新",
"Auto-refresh every 5 minutes": "每5分鐘自動刷新",
"Auto-refresh every 10 minutes": "每10分鐘自動刷新",
@@ -45,4 +45,4 @@
"Operation succeeded": "操作成功",
"Confirm": "確認",
"Cancel": "取消"
-}
\ No newline at end of file
+}
diff --git a/src/i18n/zh/translation.json b/src/i18n/zh/translation.json
index 1453320..af187b8 100644
--- a/src/i18n/zh/translation.json
+++ b/src/i18n/zh/translation.json
@@ -1,4 +1,4 @@
{
- "Release": "發佈",
- "Actions": "操作"
-}
\ No newline at end of file
+ "Release": "發佈",
+ "Actions": "操作"
+}
diff --git a/src/i18n/zh/user.json b/src/i18n/zh/user.json
index b19e88e..618a3da 100644
--- a/src/i18n/zh/user.json
+++ b/src/i18n/zh/user.json
@@ -1,40 +1,48 @@
{
- "Create User": "新增用戶",
- "Edit User": "編輯用戶資料",
- "User Detail": "用戶詳細資料",
- "User Authority": "用戶權限",
- "Authority Pool": "權限池",
- "Allocated Authority": "已分配權限",
- "username": "用戶名稱",
- "Username": "用戶名稱",
- "password": "密碼",
- "Confirm Password": "確認密碼",
- "Reset": "重置",
- "Cancel": "取消",
- "Confirm": "確認",
- "name": "姓名",
- "User ID": "用戶ID",
- "User Name": "用戶名稱",
- "User Group": "用戶群組",
- "Authority": "權限",
- "Edit": "編輯",
- "Delete": "刪除",
- "Add": "新增",
- "authority": "權限",
- "description": "描述",
- "Search by Authority or description or position.": "搜索權限、描述或職位。",
- "Remove": "移除",
- "User": "用戶",
- "user": "用戶",
- "qrcode": "二維碼",
- "staffNo": "員工編號",
- "Rows per page": "每頁行數",
- "Delete Success": "刪除成功",
- "Do you want to delete?": "您確定要刪除嗎?",
- "Maintain User": "維護用戶",
- "Maintain group": "維護群組",
- "view user": "查看用戶",
- "view group": "查看群組",
- "Approval": "審批",
- "Testing": "測試"
-}
\ No newline at end of file
+ "profile": "個人資料",
+ "Create User": "新增用戶",
+ "Edit User": "編輯用戶資料",
+ "Failed to fetch staff list": "無法取得員工列表",
+ "User Detail": "用戶詳細資料",
+ "User Authority": "用戶權限",
+ "Authority Pool": "權限池",
+ "Allocated Authority": "已分配權限",
+ "username": "用戶名稱",
+ "Username": "用戶名稱",
+ "password": "密碼",
+ "Confirm Password": "確認密碼",
+ "Reset": "重置",
+ "Cancel": "取消",
+ "Confirm": "確認",
+ "name": "姓名",
+ "User ID": "用戶ID",
+ "User Name": "用戶名稱",
+ "User Group": "用戶群組",
+ "Authority": "權限",
+ "Edit": "編輯",
+ "Delete": "刪除",
+ "Add": "新增",
+ "authority": "權限",
+ "description": "描述",
+ "Search by Authority or description or position.": "搜索權限、描述或職位。",
+ "Remove": "移除",
+ "User": "用戶",
+ "user": "用戶",
+ "qrcode": "二維碼",
+ "staffNo": "員工編號",
+ "Rows per page": "每頁行數",
+ "Delete Success": "刪除成功",
+ "Do you want to delete?": "您確定要刪除嗎?",
+ "Maintain User": "維護用戶",
+ "Maintain group": "維護群組",
+ "view user": "查看用戶",
+ "view group": "查看群組",
+ "Approval": "審批",
+ "Testing": "測試",
+ "An error has occurred. Please try again later.": "發生錯誤,請稍後再試。",
+ "Please input correct password": "請輸入正確密碼",
+ "Failed to search by name": "依名稱搜尋失敗",
+ "Failed to search by username": "依使用者名稱搜尋失敗",
+ "Staff No is required": "員工編號必填",
+ "User Not Found": "用戶不存在"
+}
diff --git a/src/i18n/zh/warehouse.json b/src/i18n/zh/warehouse.json
index 07df83c..4c825d0 100644
--- a/src/i18n/zh/warehouse.json
+++ b/src/i18n/zh/warehouse.json
@@ -1,45 +1,44 @@
{
- "Create Warehouse": "新增倉庫",
- "Edit Warehouse": "編輯倉庫資料",
- "Warehouse Detail": "倉庫詳細資料",
- "code": "編號",
- "name": "名稱",
- "description": "描述",
- "Edit": "編輯",
- "Delete": "刪除",
- "Delete Success": "刪除成功",
- "Actions": "操作",
- "Add": "新增",
- "Store ID": "樓層",
-
- "Saved": "已儲存",
- "Add Success": "新增成功",
- "Saved Successfully": "儲存成功",
- "Stock Take Section": "盤點區域",
- "Add Warehouse": "新增倉庫",
- "Save": "儲存",
- "Stock Take Section Description": "盤點區域描述",
- "Mapping Details": "對應詳細資料",
- "Warehouses in this section": "此區域內的倉庫",
- "No warehouses": "此區域內沒有倉庫",
- "Remove": "移除",
- "stockTakeSectionDescription": "盤點區域描述",
- "Warehouse List": "倉庫列表",
- "Stock Take Section & Warehouse Mapping": "盤點區域 & 倉庫對應",
- "Warehouse": "倉庫",
- "warehouse": "倉庫",
- "Rows per page": "每頁行數",
- "capacity": "容量",
- "store_id": "樓層",
- "area": "區域",
- "slot": "位置",
- "order": "提料單次序",
- "stockTakeSection": "盤點區域",
- "Do you want to delete?": "您確定要刪除嗎?",
- "Cancel": "取消",
- "Reset": "重置",
- "Confirm": "確認",
- "is required": "必填",
- "Search Criteria": "搜索條件",
- "Search": "搜索"
+ "Create Warehouse": "新增倉庫",
+ "Edit Warehouse": "編輯倉庫資料",
+ "Warehouse Detail": "倉庫詳細資料",
+ "code": "編號",
+ "name": "名稱",
+ "description": "描述",
+ "Edit": "編輯",
+ "Delete": "刪除",
+ "Delete Success": "刪除成功",
+ "Actions": "操作",
+ "Add": "新增",
+ "Store ID": "樓層",
+ "Saved": "已儲存",
+ "Add Success": "新增成功",
+ "Saved Successfully": "儲存成功",
+ "Stock Take Section": "盤點區域",
+ "Add Warehouse": "新增倉庫",
+ "Save": "儲存",
+ "Stock Take Section Description": "盤點區域描述",
+ "Mapping Details": "對應詳細資料",
+ "Warehouses in this section": "此區域內的倉庫",
+ "No warehouses": "此區域內沒有倉庫",
+ "Remove": "移除",
+ "stockTakeSectionDescription": "盤點區域描述",
+ "Warehouse List": "倉庫列表",
+ "Stock Take Section & Warehouse Mapping": "盤點區域 & 倉庫對應",
+ "Warehouse": "倉庫",
+ "warehouse": "倉庫",
+ "Rows per page": "每頁行數",
+ "capacity": "容量",
+ "store_id": "樓層",
+ "area": "區域",
+ "slot": "位置",
+ "order": "提料單次序",
+ "stockTakeSection": "盤點區域",
+ "Do you want to delete?": "您確定要刪除嗎?",
+ "Cancel": "取消",
+ "Reset": "重置",
+ "Confirm": "確認",
+ "is required": "必填",
+ "Search Criteria": "搜索條件",
+ "Search": "搜索"
}