From 54a785c14987950c2bce0f4ce2ed938cb46f54cd Mon Sep 17 00:00:00 2001 From: caadiq Date: Sat, 28 Mar 2026 18:11:28 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=204=EA=B1=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 한진택배 UNKNOWN 테이블 헤더 이벤트 필터링 - 다이얼로그 수정 상태 초기화 (parcelId 변경 시) - 모바일 수정 input 오버플로우 수정 (min-w-0) - 이벤트 시간 KST 변환 수정 (toMysqlDatetime) Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/src/plugins/tracker.js | 30 +++++++++++++++--------- backend/src/routes/parcels.js | 4 +++- backend/src/services/cron.js | 4 +++- frontend/src/components/ParcelDialog.jsx | 10 ++++++-- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/backend/src/plugins/tracker.js b/backend/src/plugins/tracker.js index 71e61d0..9074621 100644 --- a/backend/src/plugins/tracker.js +++ b/backend/src/plugins/tracker.js @@ -66,17 +66,25 @@ async function trackerPlugin(fastify) { return null; } - // 이벤트 정리 - const events = (trackInfo.events?.edges || []).map((edge) => { - const node = edge.node; - return { - status: node.status?.code || 'UNKNOWN', - statusName: node.status?.name || '', - description: node.description || '', - location: node.location?.name || '', - time: node.time || null, - }; - }); + // 이벤트 정리 (한진택배 테이블 헤더 필터링) + const events = (trackInfo.events?.edges || []) + .map((edge) => { + const node = edge.node; + return { + status: node.status?.code || 'UNKNOWN', + statusName: node.status?.name || '', + description: node.description || '', + location: node.location?.name || '', + time: node.time || null, + }; + }) + .filter((event) => { + if (event.status === 'UNKNOWN' && + (event.description === '배송 진행상황' || event.location === '상품위치')) { + return false; + } + return true; + }); // 마지막 이벤트 const lastEvent = trackInfo.lastEvent diff --git a/backend/src/routes/parcels.js b/backend/src/routes/parcels.js index 843c0e9..95c6b76 100644 --- a/backend/src/routes/parcels.js +++ b/backend/src/routes/parcels.js @@ -198,7 +198,9 @@ function toMysqlDatetime(isoString) { if (!isoString) return null; const d = new Date(isoString); if (isNaN(d.getTime())) return null; - return d.toISOString().slice(0, 19).replace('T', ' '); + // KST(+09:00) 기준으로 변환 + const kst = new Date(d.getTime() + 9 * 60 * 60 * 1000); + return kst.toISOString().slice(0, 19).replace('T', ' '); } async function refreshParcel(fastify, parcelId) { diff --git a/backend/src/services/cron.js b/backend/src/services/cron.js index 3314604..c4a799d 100644 --- a/backend/src/services/cron.js +++ b/backend/src/services/cron.js @@ -4,7 +4,9 @@ function toMysqlDatetime(isoString) { if (!isoString) return null; const d = new Date(isoString); if (isNaN(d.getTime())) return null; - return d.toISOString().slice(0, 19).replace('T', ' '); + // KST(+09:00) 기준으로 변환 + const kst = new Date(d.getTime() + 9 * 60 * 60 * 1000); + return kst.toISOString().slice(0, 19).replace('T', ' '); } export function startCronJobs(fastify) { diff --git a/frontend/src/components/ParcelDialog.jsx b/frontend/src/components/ParcelDialog.jsx index db9dc48..3aa05c3 100644 --- a/frontend/src/components/ParcelDialog.jsx +++ b/frontend/src/components/ParcelDialog.jsx @@ -1,7 +1,7 @@ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { AnimatePresence, motion } from "framer-motion"; import { X, Trash2, RefreshCw, Pencil, Check, Loader2, Copy } from "lucide-react"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import useToastStore from "@/stores/useToastStore"; import dayjs from "dayjs"; import { @@ -20,6 +20,12 @@ function ParcelDialog({ parcelId, onClose }) { const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const showToast = useToastStore((s) => s.show); + useEffect(() => { + setEditing(false); + setEditLabel(""); + setShowDeleteConfirm(false); + }, [parcelId]); + const { data: parcel, isLoading } = useQuery({ queryKey: ["parcel", parcelId], queryFn: () => fetchParcel(parcelId), @@ -114,7 +120,7 @@ function ParcelDialog({ parcelId, onClose }) { type="text" value={editLabel} onChange={(e) => setEditLabel(e.target.value)} - className="h-full border-0 border-b-2 border-primary bg-transparent px-0 text-lg lg:text-xl font-semibold text-gray-900 flex-1 focus:outline-none focus:border-primary-dark placeholder:text-gray-300" + className="h-full border-0 border-b-2 border-primary bg-transparent px-0 text-lg lg:text-xl font-semibold text-gray-900 flex-1 min-w-0 focus:outline-none focus:border-primary-dark placeholder:text-gray-300" placeholder="별칭을 입력하세요" autoFocus onKeyDown={(e) =>