diff --git a/src/app/api/escalation/index.ts b/src/app/api/escalation/index.ts index 96350e5..3b1031b 100644 --- a/src/app/api/escalation/index.ts +++ b/src/app/api/escalation/index.ts @@ -7,6 +7,7 @@ import { cache } from "react"; export interface EscalationResult { id: number; + submitter?: string; handler?: string; handlerDepartment?: string; handlerName?: string; diff --git a/src/app/api/po/actions.ts b/src/app/api/po/actions.ts index 3cd261c..03a6650 100644 --- a/src/app/api/po/actions.ts +++ b/src/app/api/po/actions.ts @@ -38,7 +38,8 @@ export interface StockInLineEntry { } export interface PurchaseQcResult{ - id: number; + id?: number; + qcItemId: number; qcPassed?: boolean; failQty?: number; remarks?: string; diff --git a/src/app/api/qc/index.ts b/src/app/api/qc/index.ts index a99d457..7fb9691 100644 --- a/src/app/api/qc/index.ts +++ b/src/app/api/qc/index.ts @@ -16,7 +16,8 @@ export interface QcItemWithChecks { } export interface QcData { - id: number, + id?: number, + qcItemId: number, code: string, name: string, qcDescription: string, diff --git a/src/app/api/user/actions.ts b/src/app/api/user/actions.ts index 7602a10..95b3404 100644 --- a/src/app/api/user/actions.ts +++ b/src/app/api/user/actions.ts @@ -104,7 +104,7 @@ export const adminChangePassword = async (data: any) => { }; export const fetchEscalationCombo = async () => { - return serverFetchJson(`${BASE_API_URL}/user/escalation-combo`, { + return serverFetchJson(`${BASE_API_URL}/user/escalation-combo`, { next: { tags: ["escalationCombo"]} }) }; \ No newline at end of file diff --git a/src/components/DashboardPage/escalation/EscalationLogTable.tsx b/src/components/DashboardPage/escalation/EscalationLogTable.tsx index e097134..52b47e3 100644 --- a/src/components/DashboardPage/escalation/EscalationLogTable.tsx +++ b/src/components/DashboardPage/escalation/EscalationLogTable.tsx @@ -89,6 +89,13 @@ const EscalationLogTable: React.FC = ({ const columns_dashboard = useMemo[]>( () => [ + { + name: "submitter", + label: t("escalateFrom"), + align: "left", + headerAlign: "left", + sx: { width: "15%", minWidth: 100 }, + }, { name: "poCode", label: t("Po Code"), @@ -138,6 +145,13 @@ const EscalationLogTable: React.FC = ({ const columns_qc = useMemo[]>( () => [ + { + name: "submitter", + label: t("escalateFrom"), + align: "left", + headerAlign: "left", + sx: { width: "15%", minWidth: 100 }, + }, { name: "handler", label: t("Responsible for handling colleagues"), @@ -153,12 +167,12 @@ const EscalationLogTable: React.FC = ({ }, { name: "recordDate", - label: t("escalated date"), + label: t("escalated datetime"), align: "right", headerAlign: "right", sx: { width: "10%", minWidth: 100 }, renderCell: (params) => { - return arrayToDateString(params.recordDate); + return arrayToDateTimeString(params.recordDate); } }, { diff --git a/src/components/PoDetail/EscalationComponent.tsx b/src/components/PoDetail/EscalationComponent.tsx index 9dafe46..f363dbf 100644 --- a/src/components/PoDetail/EscalationComponent.tsx +++ b/src/components/PoDetail/EscalationComponent.tsx @@ -24,6 +24,7 @@ import { useTranslation } from 'react-i18next'; import { Controller, useFormContext } from 'react-hook-form'; import { EscalationInput, ModalFormInput } from '@/app/api/po/actions'; import { EscalationCombo } from "@/app/api/user"; +import { fetchEscalationCombo } from "@/app/api/user/actions"; import { FireExtinguisher } from '@mui/icons-material'; interface NameOption { @@ -41,14 +42,14 @@ interface Props { forSupervisor: boolean isCollapsed: boolean setIsCollapsed: Dispatch> - escalationCombo: EscalationCombo[] + // escalationCombo: EscalationCombo[] } const EscalationComponent: React.FC = ({ forSupervisor, isCollapsed, setIsCollapsed, - escalationCombo + // escalationCombo }) => { const { t } = useTranslation("purchaseOrder"); @@ -58,6 +59,18 @@ const EscalationComponent: React.FC = ({ message: '', }); + const [escalationCombo, setEscalationCombo] = useState([]); + + useEffect(() => { + async function fetchData() { + if (escalationCombo.length < 1) { + const escCombo = await fetchEscalationCombo(); + setEscalationCombo(escCombo); + } + } + fetchData(); + }, []) + const nameOptions: NameOption[] = [ { value: '', label: '請選擇姓名...' }, { value: 'john', label: '張大明' }, diff --git a/src/components/PoDetail/PoDetail.tsx b/src/components/PoDetail/PoDetail.tsx index 4d332bd..2071652 100644 --- a/src/components/PoDetail/PoDetail.tsx +++ b/src/components/PoDetail/PoDetail.tsx @@ -89,7 +89,6 @@ type Props = { qc: QcItemWithChecks[]; warehouse: WarehouseResult[]; printerCombo: PrinterCombo[]; - escalationCombo: EscalationCombo[]; }; type EntryError = @@ -192,7 +191,7 @@ interface PolInputResult { dnQty: number, } -const PoDetail: React.FC = ({ po, qc, warehouse, printerCombo, escalationCombo }) => { +const PoDetail: React.FC = ({ po, qc, warehouse, printerCombo }) => { const cameras = useContext(CameraContext); // console.log(cameras); const { t } = useTranslation("purchaseOrder"); @@ -865,7 +864,6 @@ const PoDetail: React.FC = ({ po, qc, warehouse, printerCombo, escalation fetchPoDetail={fetchPoDetail} handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} printerCombo={printerCombo} - escalationCombo={escalationCombo} /> diff --git a/src/components/PoDetail/PoDetailWrapper.tsx b/src/components/PoDetail/PoDetailWrapper.tsx index 88041ab..bf968f3 100644 --- a/src/components/PoDetail/PoDetailWrapper.tsx +++ b/src/components/PoDetail/PoDetailWrapper.tsx @@ -27,17 +27,15 @@ const PoDetailWrapper: React.FC & SubComponents = async ({ id }) => { warehouse, qc, printerCombo, - escalationCombo, ] = await Promise.all([ fetchPoWithStockInLines(id), fetchWarehouseList(), fetchQcItemCheck(), fetchPrinterCombo(), - fetchEscalationCombo() ]); // const poWithStockInLine = await fetchPoWithStockInLines(id) console.log("%c pol:", "color:green", poWithStockInLine); - return ; + return ; }; PoDetailWrapper.Loading = PoDetailLoading; diff --git a/src/components/PoDetail/PoInputGrid.tsx b/src/components/PoDetail/PoInputGrid.tsx index 4951a33..0921dd6 100644 --- a/src/components/PoDetail/PoInputGrid.tsx +++ b/src/components/PoDetail/PoInputGrid.tsx @@ -83,7 +83,6 @@ interface Props { fetchPoDetail: (poId: string) => void; handleMailTemplateForStockInLine: (stockInLineId: number) => void; printerCombo: PrinterCombo[]; - escalationCombo: EscalationCombo[]; } export type StockInLineEntryError = { @@ -125,7 +124,6 @@ function PoInputGrid({ fetchPoDetail, handleMailTemplateForStockInLine, printerCombo, - escalationCombo }: Props) { const { t } = useTranslation("purchaseOrder"); @@ -307,7 +305,6 @@ const closeNewModal = useCallback(() => { const handleNewQC = useCallback( (id: GridRowId, params: any) => async() => { // console.log(id) - console.log("params", params.row) // setBtnIsLoading(true); setRowModesModel((prev) => ({ ...prev, @@ -955,7 +952,6 @@ const closeNewModal = useCallback(() => { itemDetail={modalInfo} handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} printerCombo={printerCombo} - escalationCombo={escalationCombo} /> ) diff --git a/src/components/PoDetail/QcComponent.tsx b/src/components/PoDetail/QcComponent.tsx index 90f33de..40855d4 100644 --- a/src/components/PoDetail/QcComponent.tsx +++ b/src/components/PoDetail/QcComponent.tsx @@ -60,9 +60,8 @@ import CollapsibleCard from "../CollapsibleCard/CollapsibleCard"; interface Props { itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] }; - qc: QcItemWithChecks[]; + // qc: QcItemWithChecks[]; disabled: boolean; - escalationCombo: EscalationCombo[]; // qcItems: QcData[] // setQcItems: Dispatch> } @@ -75,7 +74,7 @@ type EntryError = type QcRow = TableRow, EntryError>; // fetchQcItemCheck -const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escalationCombo }) => { +const QcComponent: React.FC = ({ itemDetail, disabled = false }) => { const { t } = useTranslation("purchaseOrder"); const apiRef = useGridApiRef(); const { @@ -94,12 +93,16 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala const [tabIndex, setTabIndex] = useState(0); const [rowSelectionModel, setRowSelectionModel] = useState(); const [escalationHistory, setEscalationHistory] = useState(dummyEscalationHistory); - // const [qcResult, setQcResult] = useState(); const qcAccept = watch("qcAccept"); const qcDecision = watch("qcDecision"); //WIP // const qcResult = useMemo(() => [...watch("qcResult")], [watch("qcResult")]); - const qcResult = [...watch("qcResult")]; + + const qcRecord = useMemo(() => { // Need testing + const value = watch('qcResult'); console.log("%c QC update!", "color:green", value); + return Array.isArray(value) ? [...value] : []; + }, [watch('qcResult')]); const [qcHistory, setQcHistory] = useState([]); + const [qcResult, setQcResult] = useState([]); // const [qcAccept, setQcAccept] = useState(true); // const [qcItems, setQcItems] = useState(dummyQCData) @@ -118,12 +121,16 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala }, ], [] ) - const handleTabChange = useCallback>( - (_e, newValue) => { - setTabIndex(newValue); - }, - [], - ); + const handleTabChange = useCallback>( + (_e, newValue) => { + setTabIndex(newValue); + }, + [], + ); + + const isExist = (data : string | number | undefined) => { + return (data !== null && data !== undefined); + } // W I P // const validateFieldFail = (field : FieldPath, condition: boolean, message: string) : boolean => { @@ -225,6 +232,10 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala return ; } + const qcDisabled = (row : PurchaseQcResult) => { + return disabled || isExist(row.escalationLogId); + }; + const qcColumns: GridColDef[] = useMemo(() => [ { field: "code", @@ -245,7 +256,7 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala flex: 1.5, renderCell: (params) => { const rowValue = params.row; - const index = params.api.getRowIndexRelativeToVisibleRows(params.id); + const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id); // console.log(rowValue.row); return ( @@ -267,7 +278,7 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala value="true" control={} label="合格" - disabled={disabled || itemDetail.status == "escalated"} + disabled={qcDisabled(rowValue)} sx={{ color: rowValue.qcPassed === true ? "green" : "inherit", "& .Mui-checked": {color: "green"} @@ -277,7 +288,7 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala value="false" control={} label="不合格" - disabled={disabled || itemDetail.status == "escalated"} + disabled={qcDisabled(rowValue)} sx={{ color: rowValue.qcPassed === false ? "red" : "inherit", "& .Mui-checked": {color: "red"} @@ -294,22 +305,27 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala flex: 1, // editable: true, renderCell: (params) => { - const index = params.api.getRowIndexRelativeToVisibleRows(params.id); + const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id); return ( { + disabled={params.row.qcPassed || qcDisabled(params.row)} + /* TODO improve */ + /* Reference: https://grok.com/share/c2hhcmQtNA%3D%3D_10787069-3eec-40af-a7cc-bacbdb86bf05 */ + onChange={(e) => { const v = e.target.value; const next = v === '' ? undefined : Number(v); if (Number.isNaN(next)) return; - // setQcItems((prev) => - // prev.map((r) => (r.id === params.id ? { ...r, failQty: next } : r)) - // ); setValue(`qcResult.${index}.failQty`, next); }} + // onBlur={(e) => { + // const v = e.target.value; + // const next = v === '' ? undefined : Number(v); + // if (Number.isNaN(next)) return; + // setValue(`qcResult.${index}.failQty`, next); + // }} onClick={(e) => e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} @@ -324,12 +340,12 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala headerName: t("remarks"), flex: 2, renderCell: (params) => { - const index = params.api.getRowIndexRelativeToVisibleRows(params.id); + const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id); return ( { const value = e.target.value; setValue(`qcResult.${index}.remarks`, value); @@ -365,15 +381,31 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala }, [itemDetail?.demandQty, itemDetail?.acceptedQty, setValue]); useEffect(() => { - // console.log("Qc Result updated:", qcResult); - if (qcResult.length < 1) { // New QC - const mutableQcData = dummyQCData; - // const mutableQcData = JSON.parse(JSON.stringify(dummyQCData)); - // replace([mutableQcData]); - setValue("qcResult", mutableQcData); - // setValue("qcResult.0.qcPassed", false); + console.log("%c Qc Record updated:", "color:red", qcRecord); + if (qcRecord.length < 1) { // New QC + const fetchedQcData = dummyQCData; //TODO fetch from DB + setValue("qcResult", fetchedQcData); + } else { + if (itemDetail.status == "escalated") { // Copy the previous QC data for editing + if (qcRecord.find((qc) => !isExist(qc.escalationLogId)) === undefined) { + const copiedQcData = qcRecord.map(qc => ({ ...qc, escalationLogId: undefined })); + const mutableQcData = [...qcRecord, ...copiedQcData]; + setValue("qcResult", mutableQcData); + } + } + + if (qcRecord.length > 0) { + if (qcResult.length < 1) { // Set QC Result + const filteredQcResult = qcRecord.filter((qc) => !isExist(qc.escalationLogId)); + setQcResult(filteredQcResult); + } + if (qcHistory.length < 1) { // Set QC History + const filteredQcHistory = qcRecord.filter((qc) => isExist(qc.escalationLogId)); + setQcHistory(filteredQcHistory); + } + } } - }, [qcResult, setValue]) + }, [qcRecord, setValue]) // const [openCollapse, setOpenCollapse] = useState(false) const [isCollapsed, setIsCollapsed] = useState(true); @@ -415,16 +447,16 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala } } - useEffect(() => { - if (qcHistory.length < 1) { - setQcHistory(qcResult.filter((qc) => {qc.escalationLogId != null})); - console.log("QC History updated:", qcHistory); - } - }, [watch("qcResult")]); + // }, [watch("qcResult")]); // useEffect(() => { // // onFailedOpenCollapse(qcItems) // }, [qcItems]); + const getRowId = (row :any) => { + return qcRecord.findIndex(qc => qc == row); + // return row.id || `${row.name}-${Math.random().toString(36).substr(2, 9)}`; + }; + return ( <> @@ -475,6 +507,7 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala // rows={disabled? qcResult:qcItems} autoHeight sortModel={[]} + getRowId={getRowId} /> @@ -497,7 +530,7 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala 0 ? qcResult : qcItems} // rows={disabled? qcResult:qcItems} autoHeight @@ -536,8 +569,8 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala onChange={(e) => { const value = e.target.value.toString();// === 'true'; - const input = document.getElementById('accQty') as HTMLInputElement; - console.log("%c Error", "color:pink", errors.acceptQty); + const input = document.getElementById('accQty') as HTMLInputElement; //TODO improve + console.log("%c AccQty Error", "color:pink", errors.acceptQty); if (input) { // Selected Reject in new flow with Error if (value == "1") { // Selected Accept input.value = Number(accQty).toString(); @@ -641,7 +674,6 @@ const QcComponent: React.FC = ({ qc, itemDetail, disabled = false, escala forSupervisor={false} isCollapsed={isCollapsed} setIsCollapsed={setIsCollapsed} - escalationCombo={escalationCombo} /> )} {/* {qcAccept && diff --git a/src/components/PoDetail/QcStockInModalVer2.tsx b/src/components/PoDetail/QcStockInModalVer2.tsx index dfb7f74..145cc89 100644 --- a/src/components/PoDetail/QcStockInModalVer2.tsx +++ b/src/components/PoDetail/QcStockInModalVer2.tsx @@ -67,7 +67,6 @@ interface CommonProps extends Omit { // type: "qc" | "stockIn" | "escalation" | "putaway" | "reject"; handleMailTemplateForStockInLine: (stockInLineId: number) => void; printerCombo: PrinterCombo[]; - escalationCombo: EscalationCombo[]; onClose: () => void; } interface Props extends CommonProps { @@ -87,7 +86,6 @@ const PoQcStockInModalVer2: React.FC = ({ warehouse, handleMailTemplateForStockInLine, printerCombo, - escalationCombo }) => { const { t, @@ -110,9 +108,10 @@ const defaultNewValue = useMemo(() => { escResult: (itemDetail.escResult && itemDetail.escResult?.length > 0) ? itemDetail.escResult : [], productionDate: itemDetail.productionDate ? arrayToDateString(itemDetail.productionDate, "input") : undefined, expiryDate: itemDetail.expiryDate ? arrayToDateString(itemDetail.expiryDate, "input") : undefined, - receiptDate: itemDetail.receiptDate ?? dayjs().add(0, "month").format(INPUT_DATE_FORMAT), + receiptDate: itemDetail.receiptDate ? arrayToDateString(itemDetail.receiptDate, "input") + : dayjs().add(0, "month").format(INPUT_DATE_FORMAT), acceptQty: itemDetail.demandQty?? itemDetail.acceptedQty, - warehouseId: itemDetail.defaultWarehouseId ?? 1 + warehouseId: itemDetail.defaultWarehouseId ?? 1, } ) },[itemDetail]) @@ -153,10 +152,6 @@ const [qcItems, setQcItems] = useState(dummyQCData) }, [itemDetail]); useEffect(() => { - const qcRes = itemDetail?.qcResult; - // if (!qcRes || qcRes?.length <= 0) { - // itemDetail.qcResult = dummyQCData; - // } formProps.reset({ ...defaultNewValue }) @@ -220,7 +215,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) const qcAccept = data.qcDecision == 1; // const qcAccept = data.qcAccept; let acceptQty = Number(data.acceptQty); - const qcResults = data.qcResult || dummyQCData; // qcItems; + const qcResults = data.qcResult?.filter((qc) => qc.escalationLogId === undefined) || []; // Remove old QC data // const qcResults = data.qcResult as PurchaseQcResult[]; // qcItems; // const qcResults = viewOnly? data.qcResult as PurchaseQcResult[] : qcItems; @@ -290,16 +285,17 @@ const [qcItems, setQcItems] = useState(dummyQCData) qcAccept: qcAccept? qcAccept : false, acceptQty: acceptQty? acceptQty : 0, - qcResult: itemDetail.status != "escalated" ? qcResults.map(item => ({ - id: item.id, - qcItemId: item.id, + // qcResult: itemDetail.status != "escalated" ? qcResults.map(item => ({ + qcResult: qcResults.map(item => ({ + // id: item.id, + qcItemId: item.qcItemId, // code: item.code, // qcDescription: item.qcDescription, qcPassed: item.qcPassed? item.qcPassed : false, failQty: (item.failQty && !item.qcPassed) ? item.failQty : 0, // failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0, - remarks: item.remarks || '' - })) : [], + remarks: item.remarks || '', + })), }; // const qcData = data; @@ -389,7 +385,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) status: data.status, //TODO Fix it! // ...data, - dnDate : data.dnDate? arrayToDateString(data.dnDate) : dayjsToInputDateString(dayjs()), + dnDate : data.dnDate? arrayToDateString(data.dnDate, "input") : dayjsToInputDateString(dayjs()), productionDate : arrayToDateString(data.productionDate, "input"), expiryDate : arrayToDateString(data.expiryDate, "input"), receiptDate : arrayToDateString(data.receiptDate, "input"), @@ -406,8 +402,6 @@ const [qcItems, setQcItems] = useState(dummyQCData) alert("請新增上架資料!"); return; } - console.log(typeof data.putAwayLines!![0].qty + " = 'number'"); - console.log(typeof data.putAwayLines!![0].qty !== "number"); if (data.putAwayLines!!.filter((line) => /[^0-9]/.test(String(line.qty))).length > 0) { //TODO Improve alert("上架數量不正確!"); return; @@ -471,11 +465,11 @@ const [qcItems, setQcItems] = useState(dummyQCData) return isPassed }, [acceptQty, formProps]) - useEffect(() => { - // maybe check if submitted before - console.log("Modal QC Items updated:", qcItems); - // checkQcIsPassed(qcItems) - }, [qcItems, checkQcIsPassed]) + // useEffect(() => { + // // maybe check if submitted before + // console.log("Modal QC Items updated:", qcItems); + // // checkQcIsPassed(qcItems) + // }, [qcItems, checkQcIsPassed]) return ( <> @@ -576,10 +570,9 @@ const [qcItems, setQcItems] = useState(dummyQCData) alignItems="flex-start" > diff --git a/src/components/PoDetail/dummyQcTemplate.tsx b/src/components/PoDetail/dummyQcTemplate.tsx index 0b3df54..b27768c 100644 --- a/src/components/PoDetail/dummyQcTemplate.tsx +++ b/src/components/PoDetail/dummyQcTemplate.tsx @@ -12,7 +12,8 @@ import { QcData } from "@/app/api/qc" export const dummyQCData: QcData[] = [ { - id: 4, + id: 1, + qcItemId: 4, code: "包裝", qcDescription: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", name: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", @@ -21,7 +22,8 @@ export const dummyQCData: QcData[] = [ remarks: undefined, }, { - id: 5, + id: 2, + qcItemId: 5, code: "肉質", qcDescription: "肉質鬆散,則不合格", name: "肉質鬆散,則不合格", @@ -30,7 +32,8 @@ export const dummyQCData: QcData[] = [ remarks: undefined, }, { - id: 6, + id: 3, + qcItemId: 6, code: "顔色", qcDescription: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", name: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", @@ -39,7 +42,8 @@ export const dummyQCData: QcData[] = [ remarks: undefined, }, { - id: 7, + id: 4, + qcItemId: 7, code: "狀態", qcDescription: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", name: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", @@ -48,7 +52,8 @@ export const dummyQCData: QcData[] = [ remarks: undefined, }, { - id: 8, + id: 5, + qcItemId: 8, code: "異物", qcDescription: "有不屬於本食材的雜質,則不合格", name: "有不屬於本食材的雜質,則不合格", diff --git a/src/i18n/zh/dashboard.json b/src/i18n/zh/dashboard.json index 9de6d0f..472d2f4 100644 --- a/src/i18n/zh/dashboard.json +++ b/src/i18n/zh/dashboard.json @@ -34,6 +34,7 @@ "Pending application": "待處理提料申請", "pending inspection material": "待品檢物料", "rejected": "已拒絕", + "accepted": "已收貨", "escalated": "已上報", "inspected material": "已品檢物料", "total material": "物料總數", @@ -50,5 +51,6 @@ "QC Completed Count": "品檢完成數量", "QC Fail-Total Count": "品檢不合格/總數", "escalationStatus": "上報狀態", - "escalated datetime": "上報時間" + "escalated datetime": "上報時間", + "escalateFrom": "上報同事" }