| 
					
				 | 
			
			
				@@ -1,49 +1,58 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { apiRequest } from "./common.js"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import timerManager from "./timerManager.js"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-let _fileViewTimer = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let _logMsgBody = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let _logMsgScrollBox = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let _endPoint = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let _currentFilePath = ""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let _currentFileName = ""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 export function main(container) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	container.innerHTML = ` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  <section class="sub-main-info"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    <fieldset> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <legend>📜 Log Files</legend> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <table class="log-table" id="logFiles"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <thead> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <th width="70%">파일명</th> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <th width="10%">내용</th> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <th width="20%">동작</th> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            </tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          </thead> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <tbody id="logTbody"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <td colspan="3" class="loading-text">로딩 중입니다...</td> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            </tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          </tbody> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        </table> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    </fieldset> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  </section> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  <section class="sub-detail-info"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    <div class="content"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <fieldset id="FileForm"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <legend id="logFileName">Log File View</legend> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <div id="logScroll"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <table> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <tbody id="fileTbody"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                <td class="placeholder-text">목록에서 파일을 선택해주세요.</td> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              </tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            </tbody> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          </table> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      </fieldset> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  </section> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	  <section class="sub-main-info"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		<fieldset> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		  <legend>📜 Log Files</legend> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		  <div class="right-top-button"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			<button id="stopLogFetch" class="button-link">Log File 보기 멈춤</button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		  <div class="info-table-wrapper"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			<table  id="logFiles" class="log-table"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			  <thead> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				<tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				  <th>파일명</th> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				  <th>내용</th> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				  <th>동작</th> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				</tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			  </thead> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			  <tbody id="logTbody"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				<tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				  <td colspan="3" class="loading-text">로딩 중입니다...</td> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				</tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			  </tbody> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			</table> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		</fieldset> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	  </section> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	  <section class="sub-detail-info"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	  <fieldset class="detail-fieldset"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		<legend id="detail-legend">Log File View</legend> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		<div id="logScroll"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		  <table> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			<tbody id="fileTbody"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			  <tr><td class="placeholder-text">목록에서 파일을 선택해주세요.</td></tr> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			</tbody> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		  </table> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	  </fieldset> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	  </section> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   `; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_logMsgBody = document.getElementById("fileTbody"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_logMsgScrollBox = document.getElementById("logScroll"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	apiRequest("GET", "/api/log-files") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		.then(data => { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -61,6 +70,8 @@ export function main(container) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			document.getElementById("logTbody").innerHTML = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				`<tr><td colspan="3" class="error-text">📛 ${err}</td></tr>`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	document.getElementById("stopLogFetch").addEventListener("click", stopLogFetchTimer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 function renderTree(node, parentId, tbody) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -93,8 +104,12 @@ function renderTree(node, parentId, tbody) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		link.addEventListener("click", e => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			e.preventDefault(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			const action = link.dataset.action; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if (action === "view") loadLog(link.dataset.path, link.dataset.name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			else if (action === "download") downloadLog(link.dataset.path, link.dataset.name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (action === "view") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				loadLog(link.dataset.path, link.dataset.name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			else if (action === "download") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				downloadLog(link.dataset.path, link.dataset.name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -104,46 +119,66 @@ function downloadLog(filePath, fileName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	window.open(url, "_blank"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function startLogFetchTimer() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	timerManager.start("logFilesTimer", () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		requestLog(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}, 2000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function stopLogFetchTimer() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	timerManager.stop("logFilesTimer"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_endPoint = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_currentFilePath = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_currentFileName = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function requestLog() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!_currentFileName || !_currentFilePath) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	apiRequest("POST", "/api/log-files/view", { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		fileName: _currentFileName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		filePath: _currentFilePath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		preEndPoint: _endPoint 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}).then(data => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!data?.log) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		_endPoint = data.endPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		appendLog(data.log); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}).catch(err => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		console.error("로그 요청 오류:", err); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 function loadLog(filePath, fileName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if (_fileViewTimer) clearInterval(_fileViewTimer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	const fileTbody = document.getElementById("fileTbody"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	const scrollBox = document.getElementById("logScroll"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	document.getElementById("logFileName").textContent = fileName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	fileTbody.innerHTML = ""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	let endPoint = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	function requestLog() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		$.post("/api/log-files/view", { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			fileName, filePath, preEndPoint: endPoint 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}).done(data => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if (!data?.log) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			endPoint = data.endPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			const tr = document.createElement("tr"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			const td = document.createElement("td"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// const safeHTML = data.log 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// 	.replaceAll("&", "&") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// 	.replaceAll("<", "<") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// 	.replaceAll(">", ">") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// 	.replaceAll("<br>", "<br>"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			td.className = "log-line"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			td.innerHTML = data.log; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// td.textContent = data.log; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			// td.style.whiteSpace = "pre-wrap"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			tr.appendChild(td); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			fileTbody.appendChild(tr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			scrollBox.scrollTop = scrollBox.scrollHeight; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}).fail(err => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			console.error("로그 요청 오류:", err); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	stopLogFetchTimer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	document.getElementById("detail-legend").textContent = fileName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_logMsgBody.innerHTML = ""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_endPoint = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_currentFilePath = filePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_currentFileName = fileName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	requestLog(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	_fileViewTimer = setInterval(requestLog, 2000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	startLogFetchTimer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function appendLog(logMsg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const tr = document.createElement("tr"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const td = document.createElement("td"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	td.className = "log-line"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	td.innerHTML = logMsg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	tr.appendChild(td); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_logMsgBody.appendChild(tr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (_logMsgScrollBox) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		_logMsgScrollBox.scrollTop = _logMsgScrollBox.scrollHeight; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export function cleanupLogFilesView() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	stopLogFetchTimer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |