From cfe14e563f17ceca485f245cdec886744a33ec88 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Fri, 22 Aug 2025 18:15:19 +0800 Subject: [PATCH] add escalation table in dashboard & routing to po --- src/app/api/dashboard/index.ts | 2 +- src/app/api/escalation/index.ts | 5 + src/app/api/pickOrder/actions.ts | 2 +- .../DashboardPage/DashboardPage.tsx | 7 +- .../EscalationLogTable.tsx} | 95 +++++++++++++++---- src/components/PoDetail/PoDetail.tsx | 6 ++ src/components/PoDetail/PoInputGrid.tsx | 32 ++++--- .../PoDetail/QcStockInModalVer2.tsx | 7 +- src/components/PoDetail/StockInFormVer2.tsx | 4 +- src/i18n/zh/dashboard.json | 83 ++++++++-------- 10 files changed, 163 insertions(+), 80 deletions(-) rename src/components/DashboardPage/{QC/SupervisorQcApproval.tsx => escalation/EscalationLogTable.tsx} (52%) diff --git a/src/app/api/dashboard/index.ts b/src/app/api/dashboard/index.ts index 4b7ba4e..efc661e 100644 --- a/src/app/api/dashboard/index.ts +++ b/src/app/api/dashboard/index.ts @@ -6,7 +6,7 @@ import { serverFetchJson } from "../../utils/fetchUtil"; import { BASE_API_URL } from "../../../config/api"; import { Uom } from "../settings/uom"; import { RecordsRes } from "../utils"; -import { IQCItems } from "@/components/DashboardPage/QC/SupervisorQcApproval"; +// import { IQCItems } from "@/components/DashboardPage/QC/SupervisorQcApproval"; export interface PoResult { id: number; diff --git a/src/app/api/escalation/index.ts b/src/app/api/escalation/index.ts index 1c0d0f2..abfb30a 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; + personInCharge?: string; personInChargeDepartment?: string; personInChargeName?: string; personInChargeTitle?: string; @@ -17,6 +18,10 @@ export interface EscalationResult { itemName?: string; demandQty?: number; acceptedQty?: number; + purchaseUomCode?: string; + purchaseUomDesc?: string; + stockUomCode?: string; + stockUomDesc?: string; stockInLineId?: number; stockOutLineId?: number; qcFailCount?: number; diff --git a/src/app/api/pickOrder/actions.ts b/src/app/api/pickOrder/actions.ts index b2d18ec..79cb0df 100644 --- a/src/app/api/pickOrder/actions.ts +++ b/src/app/api/pickOrder/actions.ts @@ -147,7 +147,7 @@ export interface GetPickOrderLineInfo { itemId: number; itemCode: string; itemName: string; - availableQty: number; + availableQty: number | null; requiredQty: number; uomCode: string; uomDesc: string; diff --git a/src/components/DashboardPage/DashboardPage.tsx b/src/components/DashboardPage/DashboardPage.tsx index e675775..f631d12 100644 --- a/src/components/DashboardPage/DashboardPage.tsx +++ b/src/components/DashboardPage/DashboardPage.tsx @@ -14,8 +14,9 @@ import ApplicationCompletionChart from "./chart/ApplicationCompletionChart"; import OrderCompletionChart from "./chart/OrderCompletionChart"; import DashboardBox from "./Dashboardbox"; import CollapsibleCard from "./CollapsibleCard"; -import SupervisorQcApproval, { IQCItems } from "./QC/SupervisorQcApproval"; +// import SupervisorQcApproval, { IQCItems } from "./QC/SupervisorQcApproval"; import { EscalationResult } from "@/app/api/escalation"; +import EscalationLogTable from "./escalation/EscalationLogTable"; type Props = { // iqc: IQCItems[] | undefined escalationLogs: EscalationResult[] @@ -32,9 +33,9 @@ const DashboardPage: React.FC = ({ - + - + diff --git a/src/components/DashboardPage/QC/SupervisorQcApproval.tsx b/src/components/DashboardPage/escalation/EscalationLogTable.tsx similarity index 52% rename from src/components/DashboardPage/QC/SupervisorQcApproval.tsx rename to src/components/DashboardPage/escalation/EscalationLogTable.tsx index 1611b7f..a71e89e 100644 --- a/src/components/DashboardPage/QC/SupervisorQcApproval.tsx +++ b/src/components/DashboardPage/escalation/EscalationLogTable.tsx @@ -2,9 +2,13 @@ import { Box, Card, CardActionArea, CardContent, CardHeader, Grid, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography } from "@mui/material"; import { useRouter } from "next/navigation"; -import { useCallback, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { usePathname } from "next/navigation"; import { useTranslation } from "react-i18next"; +import { EscalationResult } from "@/app/api/escalation"; +import { Column } from "@/components/SearchResults"; +import SearchResults from "@/components/SearchResults/SearchResults"; +import { arrayToDateString } from "@/app/utils/formatUtil"; export type IQCItems = { id: number; @@ -18,11 +22,11 @@ export type IQCItems = { }; type Props = { - items: IQCItems[]; + items: EscalationResult[]; }; -const SupervisorQcApproval: React.FC = ({ - items +const EscalationLogTable: React.FC = ({ + items }) => { const { t } = useTranslation("dashboard"); const CARD_HEADER = t("stock in escalation list") @@ -31,8 +35,8 @@ const SupervisorQcApproval: React.FC = ({ const router = useRouter(); const [selectedId, setSelectedId] = useState(null); -const navigateTo = useCallback( - (item: IQCItems) => { + const navigateTo = useCallback( + (item: EscalationResult) => { setSelectedId(item.id); console.log(pathname) router.replace(`/po/edit?id=${item.poId}&polId=${item.polId}&stockInLineId=${item.stockInLineId}`); @@ -40,17 +44,62 @@ const navigateTo = useCallback( [router, pathname] ); - const handleKeyDown = useCallback( - (e: React.KeyboardEvent, item: IQCItems) => { - if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault(); - navigateTo(item); - } - }, - [navigateTo] - ); + const onRowClick = useCallback((item: EscalationResult) => { + router.push(`/po/edit?id=${item.poId}&selectedIds=${item.poId}&polId=${item.polId}&stockInLineId=${item.stockInLineId}`); + }, [router]) + + // const handleKeyDown = useCallback( + // (e: React.KeyboardEvent, item: EscalationResult) => { + // if (e.key === 'Enter' || e.key === ' ') { + // e.preventDefault(); + // navigateTo(item); + // } + // }, + // [navigateTo] + // ); - return ( + const columns = useMemo[]>( + () => [ + { + name: "personInCharge", + label: t("Responsible for handling colleagues") + }, + { + name: "acceptedQty", + label: t("Received Qty"), + align: "right", + headerAlign: "right" + }, + { + name: "purchaseUomDesc", + label: t("Purchase UoM") + }, + { + name: "dnDate", + label: t("DN Date"), + renderCell: (params) => { + return params.dnDate ? arrayToDateString(params.dnDate) : "N/A" + } + }, + { + name: "qcTotalCount", + label: t("QC Completed Count"), + align: "right", + headerAlign: "right" + }, + { + name: "qcFailCount", + label: t("QC Fail Count"), + align: "right", + headerAlign: "right" + }, + { + name: "reason", + label: t("Reason"), + }, + ], []) + + {/* return ( @@ -87,7 +136,15 @@ const navigateTo = useCallback(
- ); - }; + );*/} + return ( + + ) +}; -export default SupervisorQcApproval; +export default EscalationLogTable; diff --git a/src/components/PoDetail/PoDetail.tsx b/src/components/PoDetail/PoDetail.tsx index 1715d8b..1a9a04a 100644 --- a/src/components/PoDetail/PoDetail.tsx +++ b/src/components/PoDetail/PoDetail.tsx @@ -210,6 +210,12 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { const searchParams = useSearchParams(); const [selectedRow, setSelectedRow] = useState(null); + const defaultPolId = searchParams.get("polId") + useEffect(() => { + if (defaultPolId) { + setSelectedRow(rows.find((r) => r.id.toString() === defaultPolId) ?? null) + } + }, []) const [stockInLine, setStockInLine] = useState([]); const [processedQty, setProcessedQty] = useState(0); diff --git a/src/components/PoDetail/PoInputGrid.tsx b/src/components/PoDetail/PoInputGrid.tsx index c6221cb..3a41fcd 100644 --- a/src/components/PoDetail/PoInputGrid.tsx +++ b/src/components/PoDetail/PoInputGrid.tsx @@ -270,6 +270,7 @@ function PoInputGrid({ const [newOpen, setNewOpen] = useState(false); const stockInLineId = searchParams.get("stockInLineId"); + const poLineId = searchParams.get("poLineId"); const closeNewModal = useCallback(() => { const newParams = new URLSearchParams(searchParams.toString()); newParams.delete("stockInLineId"); // Remove the parameter @@ -282,46 +283,51 @@ const closeNewModal = useCallback(() => { // Open modal const openNewModal = useCallback(() => { - setNewOpen(true); + setNewOpen(() => true); }, []); // Button handler to update the URL and open the modal const handleNewQC = useCallback( - (id: GridRowId, params: any) => async () => { + (id: GridRowId, params: any) => async() => { // console.log(id) // console.log(params) - setBtnIsLoading(true); + // setBtnIsLoading(true); setRowModesModel((prev) => ({ ...prev, [id]: { mode: GridRowModes.View }, })); const qcResult = await fetchQcDefaultValue(id); - setModalInfo({ + setModalInfo(() => ({ ...params.row, qcResult: qcResult, receivedQty: itemDetail.receivedQty, - }); + })); setTimeout(() => { const newParams = new URLSearchParams(searchParams.toString()); newParams.set("stockInLineId", id.toString()); // Ensure `set` to avoid duplicates router.replace(`${pathname}?${newParams.toString()}`); - console.log("hello") + // console.log("hello") openNewModal() - setBtnIsLoading(false); + // setBtnIsLoading(false); }, 200); }, [fetchQcDefaultValue, openNewModal, pathname, router, searchParams] ); + // Open modal if `stockInLineId` exists in the URL + const [firstCheckForSil, setFirstCheckForSil] = useState(false) useEffect(() => { - if (stockInLineId) { - console.log("heeloo") - console.log(stockInLineId) - handleNewQC(stockInLineId, apiRef.current.getRow(stockInLineId)); + if (stockInLineId && itemDetail && !firstCheckForSil) { + // console.log("heeloo") + // console.log(stockInLineId) + // console.log(apiRef.current.getRow(stockInLineId)) + setFirstCheckForSil(true) + const fn = handleNewQC(stockInLineId, {row: apiRef.current.getRow(stockInLineId)}); + fn(); } - }, [stockInLineId, newOpen, handleNewQC, apiRef]); + }, [stockInLineId, poLineId, itemDetail]); const handleEscalation = useCallback( (id: GridRowId, params: any) => () => { // setBtnIsLoading(true); @@ -580,7 +586,7 @@ const closeNewModal = useCallback(() => { }} onClick={handleNewQC(params.row.id, params)} color="inherit" - key="edit" + key={`edit`} />, = ({ qc, warehouse, }) => { - console.log(warehouse); const { t, i18n: { language }, @@ -116,8 +115,10 @@ const [qcItems, setQcItems] = useState(dummyQCData) const [viewOnly, setViewOnly] = useState(false); useEffect(() => { - const isViewOnly = itemDetail.status.toLowerCase() == "completed" || itemDetail.status.toLowerCase() == "rejected" - setViewOnly(isViewOnly) + if (itemDetail && itemDetail.status) { + const isViewOnly = itemDetail.status.toLowerCase() == "completed" || itemDetail.status.toLowerCase() == "rejected" + setViewOnly(isViewOnly) + } }, [itemDetail]); const [openPutaway, setOpenPutaway] = useState(false); diff --git a/src/components/PoDetail/StockInFormVer2.tsx b/src/components/PoDetail/StockInFormVer2.tsx index 9342757..82880fb 100644 --- a/src/components/PoDetail/StockInFormVer2.tsx +++ b/src/components/PoDetail/StockInFormVer2.tsx @@ -311,10 +311,10 @@ const StockInFormVer2: React.FC = ({
diff --git a/src/i18n/zh/dashboard.json b/src/i18n/zh/dashboard.json index 0c2df71..175f2e1 100644 --- a/src/i18n/zh/dashboard.json +++ b/src/i18n/zh/dashboard.json @@ -1,39 +1,46 @@ { - "Dashboard": "資訊展示面板", - "Order status": "訂單狀態", - "pending": "未收貨", - "receiving": "收貨中", - "total": "未完成總數", - "Warehouse temperature record": "倉庫溫度記錄", - "Warehouse type": "倉庫類型", - "Last 6 hours": "過去6小時", - "Last 24 hours": "過去24小時", - "Cold storage": "冷藏倉", - "Normal temperature storage": "常溫倉", - "Temperature status": "溫度狀態", - "Humidity status": "濕度狀態", - "Warehouse status": "倉庫狀態", - "Progress chart": "進度圖表", - "Purchase Order Code": "採購單號", - "Item Name": "貨品名稱", - "Escalation Level": "上報等級", - "Reason": "原因", - "Order completion": "訂單完成度", - "Raw material": "原料", - "Consumable": "消耗品", - "Shipment": "出貨", - "Extracted order": "已提取提料單", - "Pending order": "待提取提料單", - "Temperature": "溫度", - "Humidity": "濕度", - "Pending storage": "待入倉物料", - "Total storage": "已入倉物料", - "Application completion": "提料申請完成度", - "Processed application": "已處理提料申請", - "Pending application": "待處理提料申請", - "pending inspection material": "待品檢物料", - "inspected material": "已品檢物料", - "total material": "物料總數", - - "stock in escalation list": "收貨已上報列表" - } + "Dashboard": "資訊展示面板", + "Order status": "訂單狀態", + "pending": "未收貨", + "receiving": "收貨中", + "total": "未完成總數", + "Warehouse temperature record": "倉庫溫度記錄", + "Warehouse type": "倉庫類型", + "Last 6 hours": "過去6小時", + "Last 24 hours": "過去24小時", + "Cold storage": "冷藏倉", + "Normal temperature storage": "常溫倉", + "Temperature status": "溫度狀態", + "Humidity status": "濕度狀態", + "Warehouse status": "倉庫狀態", + "Progress chart": "進度圖表", + "Purchase Order Code": "採購單號", + "Item Name": "貨品名稱", + "Escalation Level": "上報等級", + "Reason": "原因", + "Order completion": "訂單完成度", + "Raw material": "原料", + "Consumable": "消耗品", + "Shipment": "出貨", + "Extracted order": "已提取提料單", + "Pending order": "待提取提料單", + "Temperature": "溫度", + "Humidity": "濕度", + "Pending storage": "待入倉物料", + "Total storage": "已入倉物料", + "Application completion": "提料申請完成度", + "Processed application": "已處理提料申請", + "Pending application": "待處理提料申請", + "pending inspection material": "待品檢物料", + "inspected material": "已品檢物料", + "total material": "物料總數", + "stock in escalation list": "收貨已上報列表", + "Responsible for handling colleagues": "負責處理同事", + "Completed QC Total": "品檢完成數量", + "QC Fail Count": "品檢不合格數量", + "DN Date": "送貨日期", + "Received Qty": "收貨數量", + "Escalation List": "上報列表", + "Purchase UoM": "計量單位", + "QC Completed Count": "品檢完成數量" +}