From ae4fe7a66e7337bb93b53797c342dd56f3bec3ce Mon Sep 17 00:00:00 2001 From: kjs Date: Tue, 17 Mar 2026 17:37:40 +0900 Subject: [PATCH] chore: update .gitignore and remove quick insert options from button configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added new entries to .gitignore for multi-agent MCP task queue and related rules. - Removed "즉시 저장" (quick insert) options from the ScreenSettingModal and BasicTab components to streamline button configurations. - Cleaned up unused event options in the V2ButtonConfigPanel to enhance clarity and maintainability. These changes aim to improve project organization and simplify the user interface by eliminating redundant options. --- .gitignore | 6 ++++ backend-node/src/app.ts | 1 + backend-node/src/database/db.ts | 3 +- .../admin/dashboard/DashboardTopMenu.tsx | 6 ++-- .../admin/dashboard/utils/queryHelpers.ts | 19 ++++++------ .../components/dashboard/DashboardViewer.tsx | 6 ++-- .../widgets/DeliveryTodayStatsWidget.tsx | 3 +- .../dashboard/widgets/MapTestWidgetV2.tsx | 2 +- .../report/designer/ReportPreviewModal.tsx | 3 +- .../EnhancedInteractiveScreenViewer.tsx | 9 ++++-- .../screen/InteractiveDataTable.tsx | 9 ++++-- .../screen/InteractiveScreenViewer.tsx | 9 ++++-- .../screen/InteractiveScreenViewerDynamic.tsx | 9 ++++-- .../components/screen/ScreenSettingModal.tsx | 1 - .../screen/config-panels/DateConfigPanel.tsx | 6 ++-- .../config-panels/button-config/BasicTab.tsx | 4 --- .../components/screen/widgets/FlowWidget.tsx | 6 ++-- .../screen/widgets/types/DateWidget.tsx | 6 ++-- .../components/unified/UnifiedRepeater.tsx | 12 +++++--- frontend/components/v2/V2Repeater.tsx | 7 +++-- .../v2/config-panels/V2ButtonConfigPanel.tsx | 12 -------- frontend/components/vehicle/VehicleReport.tsx | 4 +-- .../date-input/DateInputComponent.tsx | 3 +- .../modal-repeater-table/RepeaterTable.tsx | 4 +-- .../SimpleRepeaterTableComponent.tsx | 3 +- .../table-list/TableListComponent.tsx | 3 +- .../v2-table-list/TableListComponent.tsx | 3 +- .../TimelineSchedulerComponent.tsx | 7 +++-- .../components/ItemTimelineCard.tsx | 2 +- .../hooks/useTimelineData.ts | 2 +- .../utils/conflictDetection.ts | 2 +- .../pop-components/pop-search/types.ts | 2 +- frontend/lib/services/enhancedFormService.ts | 2 +- frontend/lib/utils/autoGeneration.ts | 9 +++--- frontend/lib/utils/buttonActions.ts | 6 ++-- frontend/lib/utils/formValidation.ts | 2 +- frontend/lib/utils/localDate.ts | 30 +++++++++++++++++++ .../services/ScheduleGeneratorService.ts | 4 +-- 38 files changed, 144 insertions(+), 83 deletions(-) create mode 100644 frontend/lib/utils/localDate.ts diff --git a/.gitignore b/.gitignore index 552d1265..b6114eb7 100644 --- a/.gitignore +++ b/.gitignore @@ -182,3 +182,9 @@ scripts/browser-test-*.js # 개인 작업 문서 popdocs/ .cursor/rules/popdocs-safety.mdc + +# 멀티 에이전트 MCP 태스크 큐 +mcp-task-queue/ +.cursor/rules/multi-agent-pm.mdc +.cursor/rules/multi-agent-worker.mdc +.cursor/rules/multi-agent-tester.mdc diff --git a/backend-node/src/app.ts b/backend-node/src/app.ts index 0cd44741..41926dd0 100644 --- a/backend-node/src/app.ts +++ b/backend-node/src/app.ts @@ -1,4 +1,5 @@ import "dotenv/config"; +process.env.TZ = "Asia/Seoul"; import "express-async-errors"; // async 라우트 핸들러의 에러를 Express 에러 핸들러로 자동 전달 import express from "express"; import cors from "cors"; diff --git a/backend-node/src/database/db.ts b/backend-node/src/database/db.ts index 6fc10cf1..d74e6cd8 100644 --- a/backend-node/src/database/db.ts +++ b/backend-node/src/database/db.ts @@ -66,8 +66,9 @@ export const initializePool = (): Pool => { // 연결 풀 이벤트 핸들러 pool.on("connect", (client) => { + client.query("SET timezone = 'Asia/Seoul'"); if (config.debug) { - console.log("✅ PostgreSQL 클라이언트 연결 생성"); + console.log("✅ PostgreSQL 클라이언트 연결 생성 (timezone: Asia/Seoul)"); } }); diff --git a/frontend/components/admin/dashboard/DashboardTopMenu.tsx b/frontend/components/admin/dashboard/DashboardTopMenu.tsx index 1f0419c7..eeaa73fc 100644 --- a/frontend/components/admin/dashboard/DashboardTopMenu.tsx +++ b/frontend/components/admin/dashboard/DashboardTopMenu.tsx @@ -82,7 +82,8 @@ export function DashboardTopMenu({ ) => { if (format === "png") { const link = document.createElement("a"); - const filename = `${dashboardTitle || "dashboard"}_${new Date().toISOString().split("T")[0]}.png`; + const _fd = new Date(); + const filename = `${dashboardTitle || "dashboard"}_${_fd.getFullYear()}-${String(_fd.getMonth() + 1).padStart(2, "0")}-${String(_fd.getDate()).padStart(2, "0")}.png`; link.download = filename; link.href = dataUrl; document.body.appendChild(link); @@ -111,7 +112,8 @@ export function DashboardTopMenu({ }); pdf.addImage(dataUrl, "PNG", 0, 0, imgWidth, imgHeight); - const filename = `${dashboardTitle || "dashboard"}_${new Date().toISOString().split("T")[0]}.pdf`; + const _pd = new Date(); + const filename = `${dashboardTitle || "dashboard"}_${_pd.getFullYear()}-${String(_pd.getMonth() + 1).padStart(2, "0")}-${String(_pd.getDate()).padStart(2, "0")}.pdf`; pdf.save(filename); } }; diff --git a/frontend/components/admin/dashboard/utils/queryHelpers.ts b/frontend/components/admin/dashboard/utils/queryHelpers.ts index b5220eb4..ef405d9f 100644 --- a/frontend/components/admin/dashboard/utils/queryHelpers.ts +++ b/frontend/components/admin/dashboard/utils/queryHelpers.ts @@ -100,36 +100,37 @@ export function getQuickDateRange(range: "today" | "week" | "month" | "year"): { } { const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + const fmtDate = (d: Date) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; switch (range) { case "today": return { - startDate: today.toISOString().split("T")[0], - endDate: today.toISOString().split("T")[0], + startDate: fmtDate(today), + endDate: fmtDate(today), }; case "week": { const weekStart = new Date(today); - weekStart.setDate(today.getDate() - today.getDay()); // 일요일부터 + weekStart.setDate(today.getDate() - today.getDay()); return { - startDate: weekStart.toISOString().split("T")[0], - endDate: today.toISOString().split("T")[0], + startDate: fmtDate(weekStart), + endDate: fmtDate(today), }; } case "month": { const monthStart = new Date(today.getFullYear(), today.getMonth(), 1); return { - startDate: monthStart.toISOString().split("T")[0], - endDate: today.toISOString().split("T")[0], + startDate: fmtDate(monthStart), + endDate: fmtDate(today), }; } case "year": { const yearStart = new Date(today.getFullYear(), 0, 1); return { - startDate: yearStart.toISOString().split("T")[0], - endDate: today.toISOString().split("T")[0], + startDate: fmtDate(yearStart), + endDate: fmtDate(today), }; } diff --git a/frontend/components/dashboard/DashboardViewer.tsx b/frontend/components/dashboard/DashboardViewer.tsx index 94e6aa8a..a2e83b0c 100644 --- a/frontend/components/dashboard/DashboardViewer.tsx +++ b/frontend/components/dashboard/DashboardViewer.tsx @@ -217,7 +217,8 @@ export function DashboardViewer({ if (format === "png") { console.log("💾 PNG 다운로드 시작..."); const link = document.createElement("a"); - const filename = `${dashboardTitle || "dashboard"}_${new Date().toISOString().split("T")[0]}.png`; + const _dvd = new Date(); + const filename = `${dashboardTitle || "dashboard"}_${_dvd.getFullYear()}-${String(_dvd.getMonth() + 1).padStart(2, "0")}-${String(_dvd.getDate()).padStart(2, "0")}.png`; link.download = filename; link.href = dataUrl; document.body.appendChild(link); @@ -253,7 +254,8 @@ export function DashboardViewer({ }); pdf.addImage(dataUrl, "PNG", 0, 0, imgWidth, imgHeight); - const filename = `${dashboardTitle || "dashboard"}_${new Date().toISOString().split("T")[0]}.pdf`; + const _dvp = new Date(); + const filename = `${dashboardTitle || "dashboard"}_${_dvp.getFullYear()}-${String(_dvp.getMonth() + 1).padStart(2, "0")}-${String(_dvp.getDate()).padStart(2, "0")}.pdf`; pdf.save(filename); console.log("✅ PDF 다운로드 완료:", filename); } diff --git a/frontend/components/dashboard/widgets/DeliveryTodayStatsWidget.tsx b/frontend/components/dashboard/widgets/DeliveryTodayStatsWidget.tsx index ac01e4ef..5f8eb721 100644 --- a/frontend/components/dashboard/widgets/DeliveryTodayStatsWidget.tsx +++ b/frontend/components/dashboard/widgets/DeliveryTodayStatsWidget.tsx @@ -61,7 +61,8 @@ export default function DeliveryTodayStatsWidget({ element }: DeliveryTodayStats // 데이터 처리 if (result.success && result.data?.rows) { const rows = result.data.rows; - const today = new Date().toISOString().split("T")[0]; + const _td = new Date(); + const today = `${_td.getFullYear()}-${String(_td.getMonth() + 1).padStart(2, "0")}-${String(_td.getDate()).padStart(2, "0")}`; // 오늘 발송 건수 (created_at 기준) const shippedToday = rows.filter((row: any) => { diff --git a/frontend/components/dashboard/widgets/MapTestWidgetV2.tsx b/frontend/components/dashboard/widgets/MapTestWidgetV2.tsx index 5a546dbf..72133672 100644 --- a/frontend/components/dashboard/widgets/MapTestWidgetV2.tsx +++ b/frontend/components/dashboard/widgets/MapTestWidgetV2.tsx @@ -101,7 +101,7 @@ export default function MapTestWidgetV2({ element }: MapTestWidgetV2Props) { const [routePoints, setRoutePoints] = useState([]); const [selectedUserId, setSelectedUserId] = useState(null); const [routeLoading, setRouteLoading] = useState(false); - const [routeDate, setRouteDate] = useState(new Date().toISOString().split("T")[0]); // YYYY-MM-DD 형식 + const [routeDate, setRouteDate] = useState(() => { const d = new Date(); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; }); // 공차/운행 정보 상태 const [tripInfo, setTripInfo] = useState>({}); diff --git a/frontend/components/report/designer/ReportPreviewModal.tsx b/frontend/components/report/designer/ReportPreviewModal.tsx index bc7fc774..e5fb16f7 100644 --- a/frontend/components/report/designer/ReportPreviewModal.tsx +++ b/frontend/components/report/designer/ReportPreviewModal.tsx @@ -1120,7 +1120,8 @@ export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) const blob = new Blob([response.data], { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", }); - const timestamp = new Date().toISOString().slice(0, 10); + const _rpd = new Date(); + const timestamp = `${_rpd.getFullYear()}-${String(_rpd.getMonth() + 1).padStart(2, "0")}-${String(_rpd.getDate()).padStart(2, "0")}`; const url = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; diff --git a/frontend/components/screen/EnhancedInteractiveScreenViewer.tsx b/frontend/components/screen/EnhancedInteractiveScreenViewer.tsx index ea291a6e..160d6b20 100644 --- a/frontend/components/screen/EnhancedInteractiveScreenViewer.tsx +++ b/frontend/components/screen/EnhancedInteractiveScreenViewer.tsx @@ -86,13 +86,16 @@ export const EnhancedInteractiveScreenViewer: React.FC => { const now = new Date(); + const pad = (n: number) => String(n).padStart(2, "0"); + const localDate = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; + const localTime = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`; switch (autoValueType) { case "current_datetime": - return now.toISOString().slice(0, 19).replace("T", " "); + return `${localDate} ${localTime}`; case "current_date": - return now.toISOString().slice(0, 10); + return localDate; case "current_time": - return now.toTimeString().slice(0, 8); + return localTime; case "current_user": return userName || "사용자"; case "uuid": diff --git a/frontend/components/screen/InteractiveDataTable.tsx b/frontend/components/screen/InteractiveDataTable.tsx index 9b5f1693..177b83e2 100644 --- a/frontend/components/screen/InteractiveDataTable.tsx +++ b/frontend/components/screen/InteractiveDataTable.tsx @@ -1155,13 +1155,16 @@ export const InteractiveDataTable: React.FC = ({ const generateAutoValue = useCallback( (autoValueType: string): string => { const now = new Date(); + const pad = (n: number) => String(n).padStart(2, "0"); + const localDate = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; + const localTime = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`; switch (autoValueType) { case "current_datetime": - return now.toISOString().slice(0, 19); // YYYY-MM-DDTHH:mm:ss + return `${localDate} ${localTime}`; case "current_date": - return now.toISOString().slice(0, 10); // YYYY-MM-DD + return localDate; case "current_time": - return now.toTimeString().slice(0, 8); // HH:mm:ss + return localTime; case "current_user": return currentUser?.userName || currentUser?.userId || "unknown_user"; case "uuid": diff --git a/frontend/components/screen/InteractiveScreenViewer.tsx b/frontend/components/screen/InteractiveScreenViewer.tsx index 17fd7616..4d215ae3 100644 --- a/frontend/components/screen/InteractiveScreenViewer.tsx +++ b/frontend/components/screen/InteractiveScreenViewer.tsx @@ -357,13 +357,16 @@ export const InteractiveScreenViewer: React.FC = ( // 자동값 생성 함수 const generateAutoValue = useCallback(async (autoValueType: string, ruleId?: string): Promise => { const now = new Date(); + const pad = (n: number) => String(n).padStart(2, "0"); + const localDate = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; + const localTime = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`; switch (autoValueType) { case "current_datetime": - return now.toISOString().slice(0, 19).replace("T", " "); // YYYY-MM-DD HH:mm:ss + return `${localDate} ${localTime}`; case "current_date": - return now.toISOString().slice(0, 10); // YYYY-MM-DD + return localDate; case "current_time": - return now.toTimeString().slice(0, 8); // HH:mm:ss + return localTime; case "current_user": // 실제 접속중인 사용자명 사용 return userName || "사용자"; // 사용자명이 없으면 기본값 diff --git a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx index d6111b64..fe61d5cc 100644 --- a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx +++ b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx @@ -183,13 +183,16 @@ export const InteractiveScreenViewerDynamic: React.FC { const now = new Date(); + const pad = (n: number) => String(n).padStart(2, "0"); + const localDate = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; + const localTime = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`; switch (autoValueType) { case "current_datetime": - return now.toISOString().slice(0, 19).replace("T", " "); + return `${localDate} ${localTime}`; case "current_date": - return now.toISOString().slice(0, 10); + return localDate; case "current_time": - return now.toTimeString().slice(0, 8); + return localTime; case "current_user": return userName || "사용자"; case "uuid": diff --git a/frontend/components/screen/ScreenSettingModal.tsx b/frontend/components/screen/ScreenSettingModal.tsx index 52f4ebd5..9da3d182 100644 --- a/frontend/components/screen/ScreenSettingModal.tsx +++ b/frontend/components/screen/ScreenSettingModal.tsx @@ -3852,7 +3852,6 @@ function ControlManagementTab({ openModalWithData: "데이터+모달", openRelatedModal: "연관모달", transferData: "데이터전달", - quickInsert: "즉시저장", control: "제어흐름", view_table_history: "이력보기", excel_download: "엑셀다운", diff --git a/frontend/components/screen/config-panels/DateConfigPanel.tsx b/frontend/components/screen/config-panels/DateConfigPanel.tsx index cddac6cb..5b6b1303 100644 --- a/frontend/components/screen/config-panels/DateConfigPanel.tsx +++ b/frontend/components/screen/config-panels/DateConfigPanel.tsx @@ -56,9 +56,11 @@ export const DateConfigPanel: React.FC = ({ // 현재 날짜 설정 const setCurrentDate = (field: "minDate" | "maxDate" | "defaultValue") => { const now = new Date(); + const pad = (n: number) => String(n).padStart(2, "0"); + const d = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; const dateString = localConfig.showTime - ? now.toISOString().slice(0, 16) // YYYY-MM-DDTHH:mm - : now.toISOString().slice(0, 10); // YYYY-MM-DD + ? `${d}T${pad(now.getHours())}:${pad(now.getMinutes())}` + : d; updateConfig(field, dateString); }; diff --git a/frontend/components/screen/config-panels/button-config/BasicTab.tsx b/frontend/components/screen/config-panels/button-config/BasicTab.tsx index 6bf05f70..f569c857 100644 --- a/frontend/components/screen/config-panels/button-config/BasicTab.tsx +++ b/frontend/components/screen/config-panels/button-config/BasicTab.tsx @@ -263,7 +263,6 @@ export const BasicTab: React.FC = ({ {/* 고급 기능 */} - 즉시 저장 제어 흐름 결재 요청 @@ -271,9 +270,6 @@ export const BasicTab: React.FC = ({ 바코드 스캔 운행알림 및 종료 - {/* 이벤트 버스 */} - 이벤트 발송 - {/* 복사 */} 복사 (품목코드 초기화) diff --git a/frontend/components/screen/widgets/FlowWidget.tsx b/frontend/components/screen/widgets/FlowWidget.tsx index 27e6a91b..fb2b9318 100644 --- a/frontend/components/screen/widgets/FlowWidget.tsx +++ b/frontend/components/screen/widgets/FlowWidget.tsx @@ -1018,7 +1018,8 @@ export function FlowWidget({ const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data"); - const fileName = `${flowName || "flow"}_data_${new Date().toISOString().split("T")[0]}.xlsx`; + const _fxd = new Date(); + const fileName = `${flowName || "flow"}_data_${_fxd.getFullYear()}-${String(_fxd.getMonth() + 1).padStart(2, "0")}-${String(_fxd.getDate()).padStart(2, "0")}.xlsx`; XLSX.writeFile(wb, fileName); toast.success(`${exportData.length}개 행이 Excel로 내보내기 되었습니다.`); @@ -1183,7 +1184,8 @@ export function FlowWidget({ } } - const fileName = `${flowName || "flow"}_data_${new Date().toISOString().split("T")[0]}.pdf`; + const _fpd = new Date(); + const fileName = `${flowName || "flow"}_data_${_fpd.getFullYear()}-${String(_fpd.getMonth() + 1).padStart(2, "0")}-${String(_fpd.getDate()).padStart(2, "0")}.pdf`; doc.save(fileName); toast.success(`${exportData.length}개 행이 PDF로 내보내기 되었습니다.`, { id: "pdf-export" }); diff --git a/frontend/components/screen/widgets/types/DateWidget.tsx b/frontend/components/screen/widgets/types/DateWidget.tsx index 3b0f47e2..61643ce4 100644 --- a/frontend/components/screen/widgets/types/DateWidget.tsx +++ b/frontend/components/screen/widgets/types/DateWidget.tsx @@ -52,8 +52,10 @@ export const DateWidget: React.FC = ({ component, value, const getDefaultValue = (): string => { if (config?.defaultValue === "current") { const now = new Date(); - if (isDatetime) return now.toISOString().slice(0, 16); - return now.toISOString().slice(0, 10); + const pad = (n: number) => String(n).padStart(2, "0"); + const d = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; + if (isDatetime) return `${d}T${pad(now.getHours())}:${pad(now.getMinutes())}`; + return d; } return ""; }; diff --git a/frontend/components/unified/UnifiedRepeater.tsx b/frontend/components/unified/UnifiedRepeater.tsx index 2f521665..96ef868b 100644 --- a/frontend/components/unified/UnifiedRepeater.tsx +++ b/frontend/components/unified/UnifiedRepeater.tsx @@ -680,11 +680,15 @@ export const UnifiedRepeater: React.FC = ({ const now = new Date(); switch (col.autoFill.type) { - case "currentDate": - return now.toISOString().split("T")[0]; // YYYY-MM-DD + case "currentDate": { + const pad = (n: number) => String(n).padStart(2, "0"); + return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; + } - case "currentDateTime": - return now.toISOString().slice(0, 19).replace("T", " "); // YYYY-MM-DD HH:mm:ss + case "currentDateTime": { + const pad = (n: number) => String(n).padStart(2, "0"); + return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`; + } case "sequence": return rowIndex + 1; // 1부터 시작하는 순번 diff --git a/frontend/components/v2/V2Repeater.tsx b/frontend/components/v2/V2Repeater.tsx index 3b36dd6b..b920e54f 100644 --- a/frontend/components/v2/V2Repeater.tsx +++ b/frontend/components/v2/V2Repeater.tsx @@ -1041,12 +1041,15 @@ export const V2Repeater: React.FC = ({ const now = new Date(); + const pad = (n: number) => String(n).padStart(2, "0"); + const localDate = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; + const localTime = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`; switch (col.autoFill.type) { case "currentDate": - return now.toISOString().split("T")[0]; // YYYY-MM-DD + return localDate; case "currentDateTime": - return now.toISOString().slice(0, 19).replace("T", " "); // YYYY-MM-DD HH:mm:ss + return `${localDate} ${localTime}`; case "sequence": return rowIndex + 1; // 1부터 시작하는 순번 diff --git a/frontend/components/v2/config-panels/V2ButtonConfigPanel.tsx b/frontend/components/v2/config-panels/V2ButtonConfigPanel.tsx index a36cd8c9..ab7f8732 100644 --- a/frontend/components/v2/config-panels/V2ButtonConfigPanel.tsx +++ b/frontend/components/v2/config-panels/V2ButtonConfigPanel.tsx @@ -130,12 +130,6 @@ const ACTION_TYPE_CARDS = [ title: "엑셀 업로드", description: "엑셀 파일을 올려요", }, - { - value: "quickInsert", - icon: Zap, - title: "즉시 저장", - description: "바로 저장해요", - }, { value: "approval", icon: Check, @@ -148,12 +142,6 @@ const ACTION_TYPE_CARDS = [ title: "제어 흐름", description: "흐름을 제어해요", }, - { - value: "event", - icon: Send, - title: "이벤트 발송", - description: "이벤트를 보내요", - }, { value: "copy", icon: Copy, diff --git a/frontend/components/vehicle/VehicleReport.tsx b/frontend/components/vehicle/VehicleReport.tsx index e075dd15..2bca91d3 100644 --- a/frontend/components/vehicle/VehicleReport.tsx +++ b/frontend/components/vehicle/VehicleReport.tsx @@ -56,10 +56,10 @@ export default function VehicleReport() { // 일별 통계 const [dailyData, setDailyData] = useState([]); const [dailyStartDate, setDailyStartDate] = useState( - new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split("T")[0] + (() => { const d = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; })() ); const [dailyEndDate, setDailyEndDate] = useState( - new Date().toISOString().split("T")[0] + (() => { const d = new Date(); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; })() ); const [dailyLoading, setDailyLoading] = useState(false); diff --git a/frontend/lib/registry/components/date-input/DateInputComponent.tsx b/frontend/lib/registry/components/date-input/DateInputComponent.tsx index 93efccf0..73dda0f7 100644 --- a/frontend/lib/registry/components/date-input/DateInputComponent.tsx +++ b/frontend/lib/registry/components/date-input/DateInputComponent.tsx @@ -53,7 +53,8 @@ export const DateInputComponent: React.FC = ({ // 자동생성 로직 useEffect(() => { if (finalAutoGeneration?.enabled) { - const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD + const n = new Date(); + const today = `${n.getFullYear()}-${String(n.getMonth() + 1).padStart(2, "0")}-${String(n.getDate()).padStart(2, "0")}`; setAutoGeneratedValue(today); // 인터랙티브 모드에서 폼 데이터에도 설정 diff --git a/frontend/lib/registry/components/modal-repeater-table/RepeaterTable.tsx b/frontend/lib/registry/components/modal-repeater-table/RepeaterTable.tsx index 85db9002..4b8cb23d 100644 --- a/frontend/lib/registry/components/modal-repeater-table/RepeaterTable.tsx +++ b/frontend/lib/registry/components/modal-repeater-table/RepeaterTable.tsx @@ -653,9 +653,9 @@ export function RepeaterTable({ if (typeof val === "string" && val.includes("T")) { return val.split("T")[0]; } - // Date 객체이면 변환 + // Date 객체이면 로컬 날짜로 변환 if (val instanceof Date) { - return val.toISOString().split("T")[0]; + return `${val.getFullYear()}-${String(val.getMonth() + 1).padStart(2, "0")}-${String(val.getDate()).padStart(2, "0")}`; } return String(val); }; diff --git a/frontend/lib/registry/components/simple-repeater-table/SimpleRepeaterTableComponent.tsx b/frontend/lib/registry/components/simple-repeater-table/SimpleRepeaterTableComponent.tsx index e4e172f6..f215b665 100644 --- a/frontend/lib/registry/components/simple-repeater-table/SimpleRepeaterTableComponent.tsx +++ b/frontend/lib/registry/components/simple-repeater-table/SimpleRepeaterTableComponent.tsx @@ -448,7 +448,8 @@ export function SimpleRepeaterTableComponent({ } else if (col.type === "number") { newRow[col.field] = 0; } else if (col.type === "date") { - newRow[col.field] = new Date().toISOString().split("T")[0]; + const _n = new Date(); + newRow[col.field] = `${_n.getFullYear()}-${String(_n.getMonth() + 1).padStart(2, "0")}-${String(_n.getDate()).padStart(2, "0")}`; } else { newRow[col.field] = ""; } diff --git a/frontend/lib/registry/components/table-list/TableListComponent.tsx b/frontend/lib/registry/components/table-list/TableListComponent.tsx index 119cca53..80d84b7a 100644 --- a/frontend/lib/registry/components/table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/table-list/TableListComponent.tsx @@ -2707,7 +2707,8 @@ export const TableListComponent: React.FC = ({ XLSX.utils.book_append_sheet(wb, ws, tableLabel || "데이터"); // 파일명 생성 - const fileName = `${tableLabel || tableConfig.selectedTable || "export"}_${new Date().toISOString().split("T")[0]}.xlsx`; + const _en = new Date(); + const fileName = `${tableLabel || tableConfig.selectedTable || "export"}_${_en.getFullYear()}-${String(_en.getMonth() + 1).padStart(2, "0")}-${String(_en.getDate()).padStart(2, "0")}.xlsx`; // 파일 다운로드 XLSX.writeFile(wb, fileName); diff --git a/frontend/lib/registry/components/v2-table-list/TableListComponent.tsx b/frontend/lib/registry/components/v2-table-list/TableListComponent.tsx index 4649350b..d1faf281 100644 --- a/frontend/lib/registry/components/v2-table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/v2-table-list/TableListComponent.tsx @@ -3006,7 +3006,8 @@ export const TableListComponent: React.FC = ({ XLSX.utils.book_append_sheet(wb, ws, tableLabel || "데이터"); // 파일명 생성 - const fileName = `${tableLabel || tableConfig.selectedTable || "export"}_${new Date().toISOString().split("T")[0]}.xlsx`; + const _en = new Date(); + const fileName = `${tableLabel || tableConfig.selectedTable || "export"}_${_en.getFullYear()}-${String(_en.getMonth() + 1).padStart(2, "0")}-${String(_en.getDate()).padStart(2, "0")}.xlsx`; // 파일 다운로드 XLSX.writeFile(wb, fileName); diff --git a/frontend/lib/registry/components/v2-timeline-scheduler/TimelineSchedulerComponent.tsx b/frontend/lib/registry/components/v2-timeline-scheduler/TimelineSchedulerComponent.tsx index 075e8eca..b80c1142 100644 --- a/frontend/lib/registry/components/v2-timeline-scheduler/TimelineSchedulerComponent.tsx +++ b/frontend/lib/registry/components/v2-timeline-scheduler/TimelineSchedulerComponent.tsx @@ -227,7 +227,7 @@ export function TimelineSchedulerComponent({ if (onCellClick) { onCellClick({ resourceId, - date: date.toISOString().split("T")[0], + date: `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`, }); } }, @@ -343,7 +343,7 @@ export function TimelineSchedulerComponent({ if (onAddSchedule && effectiveResources.length > 0) { onAddSchedule( effectiveResources[0].id, - new Date().toISOString().split("T")[0] + (() => { const _n = new Date(); return `${_n.getFullYear()}-${String(_n.getMonth() + 1).padStart(2, "0")}-${String(_n.getDate()).padStart(2, "0")}`; })() ); } }, [onAddSchedule, effectiveResources]); @@ -383,7 +383,8 @@ export function TimelineSchedulerComponent({ const items = Array.from(grouped.entries()).map(([code, rows]) => { const totalQty = rows.reduce((sum: number, r: any) => sum + (Number(r[qtyField]) || 0), 0); const dates = rows.map((r: any) => r[dateField]).filter(Boolean).sort(); - const earliestDate = dates[0] || new Date().toISOString().split("T")[0]; + const _dn = new Date(); + const earliestDate = dates[0] || `${_dn.getFullYear()}-${String(_dn.getMonth() + 1).padStart(2, "0")}-${String(_dn.getDate()).padStart(2, "0")}`; const first = rows[0]; return { item_code: code, diff --git a/frontend/lib/registry/components/v2-timeline-scheduler/components/ItemTimelineCard.tsx b/frontend/lib/registry/components/v2-timeline-scheduler/components/ItemTimelineCard.tsx index 01e72a1c..37fb46d8 100644 --- a/frontend/lib/registry/components/v2-timeline-scheduler/components/ItemTimelineCard.tsx +++ b/frontend/lib/registry/components/v2-timeline-scheduler/components/ItemTimelineCard.tsx @@ -28,7 +28,7 @@ interface ItemTimelineCardProps { onScheduleClick?: (schedule: ScheduleItem) => void; } -const toDateString = (d: Date) => d.toISOString().split("T")[0]; +const toDateString = (d: Date) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; const addDays = (d: Date, n: number) => { const r = new Date(d); diff --git a/frontend/lib/registry/components/v2-timeline-scheduler/hooks/useTimelineData.ts b/frontend/lib/registry/components/v2-timeline-scheduler/hooks/useTimelineData.ts index 8e2e1b53..5e30633f 100644 --- a/frontend/lib/registry/components/v2-timeline-scheduler/hooks/useTimelineData.ts +++ b/frontend/lib/registry/components/v2-timeline-scheduler/hooks/useTimelineData.ts @@ -13,7 +13,7 @@ const SCHEDULE_TABLE = "schedule_mng"; * 날짜를 ISO 문자열로 변환 (시간 제외) */ const toDateString = (date: Date): string => { - return date.toISOString().split("T")[0]; + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`; }; /** diff --git a/frontend/lib/registry/components/v2-timeline-scheduler/utils/conflictDetection.ts b/frontend/lib/registry/components/v2-timeline-scheduler/utils/conflictDetection.ts index 98b9fbb1..27d16b6c 100644 --- a/frontend/lib/registry/components/v2-timeline-scheduler/utils/conflictDetection.ts +++ b/frontend/lib/registry/components/v2-timeline-scheduler/utils/conflictDetection.ts @@ -54,5 +54,5 @@ export function detectConflicts(schedules: ScheduleItem[]): Set { export function addDaysToDateString(dateStr: string, days: number): string { const date = new Date(dateStr); date.setDate(date.getDate() + days); - return date.toISOString().split("T")[0]; + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`; } diff --git a/frontend/lib/registry/pop-components/pop-search/types.ts b/frontend/lib/registry/pop-components/pop-search/types.ts index 6b284b60..5d455121 100644 --- a/frontend/lib/registry/pop-components/pop-search/types.ts +++ b/frontend/lib/registry/pop-components/pop-search/types.ts @@ -251,7 +251,7 @@ export function computeDateRange( preset: DatePresetOption ): { preset: DatePresetOption; from: string; to: string } | null { const now = new Date(); - const fmt = (d: Date) => d.toISOString().split("T")[0]; + const fmt = (d: Date) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; switch (preset) { case "today": diff --git a/frontend/lib/services/enhancedFormService.ts b/frontend/lib/services/enhancedFormService.ts index 70bcc106..946288e8 100644 --- a/frontend/lib/services/enhancedFormService.ts +++ b/frontend/lib/services/enhancedFormService.ts @@ -349,7 +349,7 @@ export class EnhancedFormService { if (lowerDataType.includes("date")) { const date = new Date(value); - return isNaN(date.getTime()) ? null : date.toISOString().split("T")[0]; + return isNaN(date.getTime()) ? null : `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`; } if (lowerDataType.includes("time")) { diff --git a/frontend/lib/utils/autoGeneration.ts b/frontend/lib/utils/autoGeneration.ts index d9124bf9..be635370 100644 --- a/frontend/lib/utils/autoGeneration.ts +++ b/frontend/lib/utils/autoGeneration.ts @@ -1,6 +1,7 @@ "use client"; import { AutoGenerationType, AutoGenerationConfig } from "@/types/screen"; +import { toLocalDate, toLocalTime, toLocalDateTime } from "@/lib/utils/localDate"; /** * 자동생성 값 생성 유틸리티 @@ -52,19 +53,19 @@ export class AutoGenerationUtils { let result: string; switch (format) { case "date": - result = now.toISOString().split("T")[0]; // YYYY-MM-DD + result = toLocalDate(now); break; case "time": - result = now.toTimeString().split(" ")[0]; // HH:mm:ss + result = toLocalTime(now); break; case "datetime": - result = now.toISOString().replace("T", " ").split(".")[0]; // YYYY-MM-DD HH:mm:ss + result = toLocalDateTime(now); break; case "timestamp": result = now.getTime().toString(); break; default: - result = now.toISOString(); // ISO 8601 format + result = toLocalDateTime(now); break; } diff --git a/frontend/lib/utils/buttonActions.ts b/frontend/lib/utils/buttonActions.ts index 5ea616e2..60ed18e0 100644 --- a/frontend/lib/utils/buttonActions.ts +++ b/frontend/lib/utils/buttonActions.ts @@ -5156,7 +5156,8 @@ export class ButtonActionExecutor { const menuName = localStorage.getItem("currentMenuName"); if (menuName) defaultFileName = menuName; } - const fileName = config.excelFileName || `${defaultFileName}_${new Date().toISOString().split("T")[0]}.xlsx`; + const _xd = new Date(); + const fileName = config.excelFileName || `${defaultFileName}_${_xd.getFullYear()}-${String(_xd.getMonth() + 1).padStart(2, "0")}-${String(_xd.getDate()).padStart(2, "0")}.xlsx`; const sheetName = config.excelSheetName || "Sheet1"; await exportToExcel(dataToExport, fileName, sheetName, true); @@ -5262,7 +5263,8 @@ export class ButtonActionExecutor { } } - const fileName = config.excelFileName || `${defaultFileName}_${new Date().toISOString().split("T")[0]}.xlsx`; + const _xd2 = new Date(); + const fileName = config.excelFileName || `${defaultFileName}_${_xd2.getFullYear()}-${String(_xd2.getMonth() + 1).padStart(2, "0")}-${String(_xd2.getDate()).padStart(2, "0")}.xlsx`; const sheetName = config.excelSheetName || "Sheet1"; const includeHeaders = config.excelIncludeHeaders !== false; diff --git a/frontend/lib/utils/formValidation.ts b/frontend/lib/utils/formValidation.ts index 48cb60e1..d272d942 100644 --- a/frontend/lib/utils/formValidation.ts +++ b/frontend/lib/utils/formValidation.ts @@ -440,7 +440,7 @@ const validateDateField = (fieldName: string, value: any, config?: Record