diff --git a/Project/Web/Controller/JobreportController.cs b/Project/Web/Controller/JobreportController.cs index f6c37c1..4a682f1 100644 --- a/Project/Web/Controller/JobreportController.cs +++ b/Project/Web/Controller/JobreportController.cs @@ -1,5 +1,6 @@ using Microsoft.Owin; using System; +using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Web; @@ -17,35 +18,228 @@ namespace Project.Web.Controllers } // DELETE api/values/5 - public void Delete(int id) + [HttpDelete] + public HttpResponseMessage Delete(int id) { + try + { + if (id <= 0) + { + throw new Exception("유효하지 않은 업무일지 ID입니다."); + } + + // 직접 SQL 삭제 실행 + string connectionString = Properties.Settings.Default.gwcs; + using (var connection = new System.Data.SqlClient.SqlConnection(connectionString)) + { + connection.Open(); + + string deleteSql = @" + DELETE FROM JobReport + WHERE idx = @idx AND gcode = @gcode"; + + using (var command = new System.Data.SqlClient.SqlCommand(deleteSql, connection)) + { + command.Parameters.AddWithValue("@idx", id); + command.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + + int rowsAffected = command.ExecuteNonQuery(); + + if (rowsAffected == 0) + { + throw new Exception("업무일지를 찾을 수 없거나 삭제 권한이 없습니다."); + } + } + } + + var jsonData = "{\"success\":true,\"message\":\"데이터가 성공적으로 삭제되었습니다.\"}"; + + var resp = new HttpResponseMessage() + { + Content = new StringContent( + jsonData, + System.Text.Encoding.UTF8, + "application/json") + }; + + return resp; + } + catch (Exception ex) + { + var errorResp = new HttpResponseMessage() + { + Content = new StringContent( + $"{{\"success\":false,\"message\":\"{EscapeJsonString(ex.Message)}\"}}", + System.Text.Encoding.UTF8, + "application/json") + }; + return errorResp; + } } [HttpPost] - public string Add(FormCollection tbpdate) + public string Add(FormCollection formData) { - var vals = Request.GetQueryNameValuePairs(); - return string.Empty; + try + { + // 폼 데이터에서 값 추출 + var pdate = formData["pdate"] ?? DateTime.Now.ToShortDateString(); + var status = formData["status"] ?? ""; + var projectName = formData["projectName"] ?? ""; + var requestpart = formData["requestpart"] ?? ""; + var type = formData["type"] ?? ""; + var description = formData["description"] ?? ""; + var otStart = formData["otStart"] ?? ""; + var otEnd = formData["otEnd"] ?? ""; + + decimal hrs = 0; + decimal.TryParse(formData["hrs"], out hrs); + + decimal ot = 0; + decimal.TryParse(formData["ot"], out ot); + + // 직접 SQL 삽입 실행 + string connectionString = Properties.Settings.Default.gwcs; + using (var connection = new System.Data.SqlClient.SqlConnection(connectionString)) + { + connection.Open(); + + string insertSql = @" + INSERT INTO JobReport + (gcode, pdate, projectName, uid, requestpart, status, type, description, hrs, ot, otStart, otEnd, wuid, wdate) + VALUES + (@gcode, @pdate, @projectName, @uid, @requestpart, @status, @type, @description, @hrs, @ot, @otStart, @otEnd, @wuid, @wdate)"; + + using (var command = new System.Data.SqlClient.SqlCommand(insertSql, connection)) + { + command.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + command.Parameters.AddWithValue("@pdate", pdate); + command.Parameters.AddWithValue("@projectName", projectName); + command.Parameters.AddWithValue("@uid", FCOMMON.info.Login.no); + command.Parameters.AddWithValue("@requestpart", requestpart); + command.Parameters.AddWithValue("@status", status); + command.Parameters.AddWithValue("@type", type); + command.Parameters.AddWithValue("@description", description); + command.Parameters.AddWithValue("@hrs", hrs); + command.Parameters.AddWithValue("@ot", ot); + command.Parameters.AddWithValue("@otStart", string.IsNullOrEmpty(otStart) ? (object)DBNull.Value : otStart); + command.Parameters.AddWithValue("@otEnd", string.IsNullOrEmpty(otEnd) ? (object)DBNull.Value : otEnd); + command.Parameters.AddWithValue("@wuid", FCOMMON.info.Login.no); + command.Parameters.AddWithValue("@wdate", DateTime.Now); + + command.ExecuteNonQuery(); + } + } + + return "{\"success\":true,\"message\":\"데이터가 성공적으로 저장되었습니다.\"}"; + } + catch (Exception ex) + { + return $"{{\"success\":false,\"message\":\"{EscapeJsonString(ex.Message)}\"}}"; + } } - //[HttpPost] - //public string Edit([FromBody] string value) - //{ - // var vals = Request.GetQueryNameValuePairs(); - - // var req = Request.GetRequestContext(); - - // return string.Empty; - //} - [HttpPost] - public string Edit(FormCollection value) + public HttpResponseMessage Edit() { - var vals = Request.GetQueryNameValuePairs(); + try + { + // Request.Form에서 직접 값 추출 + var idx = HttpContext.Current.Request.Form["idx"]; + var pdate = HttpContext.Current.Request.Form["pdate"] ?? DateTime.Now.ToShortDateString(); + var status = HttpContext.Current.Request.Form["status"] ?? ""; + var projectName = HttpContext.Current.Request.Form["projectName"] ?? ""; + var requestpart = HttpContext.Current.Request.Form["requestpart"] ?? ""; + var type = HttpContext.Current.Request.Form["type"] ?? ""; + var description = HttpContext.Current.Request.Form["description"] ?? ""; + var otStart = HttpContext.Current.Request.Form["otStart"] ?? ""; + var otEnd = HttpContext.Current.Request.Form["otEnd"] ?? ""; + + decimal hrs = 0; + decimal.TryParse(HttpContext.Current.Request.Form["hrs"], out hrs); + + decimal ot = 0; + decimal.TryParse(HttpContext.Current.Request.Form["ot"], out ot); - var req = Request.GetRequestContext(); + int idxNum = 0; + int.TryParse(idx, out idxNum); - return string.Empty; + if (idxNum <= 0) + { + throw new Exception("유효하지 않은 업무일지 ID입니다."); + } + + // 직접 SQL 업데이트 실행 + string connectionString = Properties.Settings.Default.gwcs; + using (var connection = new System.Data.SqlClient.SqlConnection(connectionString)) + { + connection.Open(); + + string updateSql = @" + UPDATE JobReport + SET pdate = @pdate, + status = @status, + projectName = @projectName, + requestpart = @requestpart, + type = @type, + description = @description, + hrs = @hrs, + ot = @ot, + otStart = @otStart, + otEnd = @otEnd, + wuid = @wuid, + wdate = @wdate + WHERE idx = @idx AND gcode = @gcode"; + + using (var command = new System.Data.SqlClient.SqlCommand(updateSql, connection)) + { + command.Parameters.AddWithValue("@idx", idxNum); + command.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + command.Parameters.AddWithValue("@pdate", pdate); + command.Parameters.AddWithValue("@status", status); + command.Parameters.AddWithValue("@projectName", projectName); + command.Parameters.AddWithValue("@requestpart", requestpart); + command.Parameters.AddWithValue("@type", type); + command.Parameters.AddWithValue("@description", description); + command.Parameters.AddWithValue("@hrs", hrs); + command.Parameters.AddWithValue("@ot", ot); + command.Parameters.AddWithValue("@otStart", string.IsNullOrEmpty(otStart) ? (object)DBNull.Value : otStart); + command.Parameters.AddWithValue("@otEnd", string.IsNullOrEmpty(otEnd) ? (object)DBNull.Value : otEnd); + command.Parameters.AddWithValue("@wuid", FCOMMON.info.Login.no); + command.Parameters.AddWithValue("@wdate", DateTime.Now); + + int rowsAffected = command.ExecuteNonQuery(); + + if (rowsAffected == 0) + { + throw new Exception("업무일지를 찾을 수 없거나 수정 권한이 없습니다."); + } + } + } + + var jsonData = "{\"success\":true,\"message\":\"데이터가 성공적으로 수정되었습니다.\"}"; + + var resp = new HttpResponseMessage() + { + Content = new StringContent( + jsonData, + System.Text.Encoding.UTF8, + "application/json") + }; + + return resp; + } + catch (Exception ex) + { + var errorResp = new HttpResponseMessage() + { + Content = new StringContent( + $"{{\"success\":false,\"message\":\"{EscapeJsonString(ex.Message)}\"}}", + System.Text.Encoding.UTF8, + "application/json") + }; + return errorResp; + } } [HttpGet] @@ -315,5 +509,317 @@ namespace Project.Web.Controllers return resp; } + + [HttpGet] + public HttpResponseMessage GetJobDetail(int id) + { + try + { + // 특정 업무일지의 전체 정보 조회 + string connectionString = Properties.Settings.Default.gwcs; + + using (var connection = new System.Data.SqlClient.SqlConnection(connectionString)) + { + connection.Open(); + + string selectSql = @" + SELECT idx, pdate, gcode, uid as id, '' as name, '' as process, type, '' as svalue, + hrs, ot, requestpart, '' as package, '' as userProcess, status, projectName, + description, '' as ww, otStart, otEnd, ot as ot2, '' as otReason, + '' as grade, '' as indate, '' as outdate, pidx + FROM JobReport WITH (NOLOCK) + WHERE gcode = @gcode AND uid = @uid AND idx = @idx"; + + using (var command = new System.Data.SqlClient.SqlCommand(selectSql, connection)) + { + command.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + command.Parameters.AddWithValue("@uid", FCOMMON.info.Login.no); + command.Parameters.AddWithValue("@idx", id); + + using (var reader = command.ExecuteReader()) + { + if (reader.Read()) + { + var item = new + { + idx = reader["idx"], + pdate = reader["pdate"], + gcode = reader["gcode"], + id = reader["id"], + name = reader["name"], + process = reader["process"], + type = reader["type"], + svalue = reader["svalue"], + hrs = reader["hrs"], + ot = reader["ot"], + requestpart = reader["requestpart"], + package = reader["package"], + userProcess = reader["userProcess"], + status = reader["status"], + projectName = reader["projectName"], + description = reader["description"], // 전체 내용 + ww = reader["ww"], + otStart = reader["otStart"], + otEnd = reader["otEnd"], + ot2 = reader["ot2"], + otReason = reader["otReason"], + grade = reader["grade"], + indate = reader["indate"], + outdate = reader["outdate"], + pidx = reader["pidx"] + }; + + // JSON 형태로 변환 + decimal hrs = 0; + decimal ot = 0; + int idx = 0; + int pidx = 0; + + try { hrs = Convert.ToDecimal(item.hrs); } catch { hrs = 0; } + try { ot = Convert.ToDecimal(item.ot); } catch { ot = 0; } + try { idx = Convert.ToInt32(item.idx); } catch { idx = 0; } + try { pidx = Convert.ToInt32(item.pidx); } catch { pidx = 0; } + + var desc = EscapeJsonString(item.description?.ToString() ?? ""); // 전체 내용 + var pdate = EscapeJsonString(item.pdate?.ToString() ?? ""); + var status = EscapeJsonString(item.status?.ToString() ?? ""); + var type = EscapeJsonString(item.type?.ToString() ?? ""); + var projectName = EscapeJsonString(item.projectName?.ToString() ?? ""); + var requestpart = EscapeJsonString(item.requestpart?.ToString() ?? ""); + var otStart = EscapeJsonString(item.otStart?.ToString() ?? ""); + var otEnd = EscapeJsonString(item.otEnd?.ToString() ?? ""); + + var jsonData = "{"; + jsonData += $"\"pdate\":\"{pdate}\","; + jsonData += $"\"status\":\"{status}\","; + jsonData += $"\"type\":\"{type}\","; + jsonData += $"\"projectName\":\"{projectName}\","; + jsonData += $"\"requestpart\":\"{requestpart}\","; + jsonData += $"\"hrs\":{hrs},"; + jsonData += $"\"ot\":{ot},"; + jsonData += $"\"description\":\"{desc}\","; + jsonData += $"\"otStart\":\"{otStart}\","; + jsonData += $"\"otEnd\":\"{otEnd}\","; + jsonData += $"\"idx\":{idx},"; + jsonData += $"\"pidx\":{pidx}"; + jsonData += "}"; + + var resp = new HttpResponseMessage() + { + Content = new StringContent( + jsonData, + System.Text.Encoding.UTF8, + "application/json") + }; + + return resp; + } + } + } + } + + // 데이터를 찾을 수 없는 경우 + var errorResp = new HttpResponseMessage() + { + Content = new StringContent( + "{\"error\":\"데이터를 찾을 수 없습니다.\"}", + System.Text.Encoding.UTF8, + "application/json") + }; + return errorResp; + } + catch (Exception ex) + { + var errorResp = new HttpResponseMessage() + { + Content = new StringContent( + $"{{\"error\":\"{ex.Message}\"}}", + System.Text.Encoding.UTF8, + "application/json") + }; + return errorResp; + } + } + + [HttpGet] + public HttpResponseMessage GetJobData() + { + try + { + var gets = Request.GetQueryNameValuePairs(); + var startDateParam = gets.Where(t => t.Key == "startDate").FirstOrDefault(); + var endDateParam = gets.Where(t => t.Key == "endDate").FirstOrDefault(); + + var startDate = startDateParam.Key != null ? startDateParam.Value : null; + var endDate = endDateParam.Key != null ? endDateParam.Value : null; + + // 날짜 파라미터 처리 + string sd, ed; + if (!string.IsNullOrEmpty(startDate) && !string.IsNullOrEmpty(endDate)) + { + sd = startDate; + ed = endDate; + } + else + { + // 기본값: 오늘부터 -2주 + var now = DateTime.Now; + var twoWeeksAgo = now.AddDays(-14); + sd = twoWeeksAgo.ToShortDateString(); + ed = now.ToShortDateString(); + } + + // 직접 SQL로 데이터 조회 + string connectionString = Properties.Settings.Default.gwcs; + var jobReports = new List(); + + using (var connection = new System.Data.SqlClient.SqlConnection(connectionString)) + { + connection.Open(); + + string selectSql = @" + SELECT idx, pdate, gcode, uid as id, '' as name, '' as process, type, '' as svalue, + hrs, ot, requestpart, '' as package, '' as userProcess, status, projectName, + description, '' as ww, otStart, otEnd, ot as ot2, '' as otReason, + '' as grade, '' as indate, '' as outdate, pidx + FROM JobReport WITH (NOLOCK) + WHERE gcode = @gcode AND uid = @uid AND pdate BETWEEN @startDate AND @endDate + ORDER BY pdate DESC"; + + using (var command = new System.Data.SqlClient.SqlCommand(selectSql, connection)) + { + command.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + command.Parameters.AddWithValue("@uid", FCOMMON.info.Login.no); + command.Parameters.AddWithValue("@startDate", sd); + command.Parameters.AddWithValue("@endDate", ed); + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + jobReports.Add(new + { + idx = reader["idx"], + pdate = reader["pdate"], + gcode = reader["gcode"], + id = reader["id"], + name = reader["name"], + process = reader["process"], + type = reader["type"], + svalue = reader["svalue"], + hrs = reader["hrs"], + ot = reader["ot"], + requestpart = reader["requestpart"], + package = reader["package"], + userProcess = reader["userProcess"], + status = reader["status"], + projectName = reader["projectName"], + description = reader["description"], + ww = reader["ww"], + otStart = reader["otStart"], + otEnd = reader["otEnd"], + ot2 = reader["ot2"], + otReason = reader["otReason"], + grade = reader["grade"], + indate = reader["indate"], + outdate = reader["outdate"], + pidx = reader["pidx"] + }); + } + } + } + } + + // JSON 형태로 변환 + var jsonData = "["; + bool first = true; + + if (jobReports != null) + { + foreach (var item in jobReports) + { + if (!first) jsonData += ","; + first = false; + + // DBNull 처리를 위한 안전한 변환 + decimal hrs = 0; + decimal ot = 0; + int idx = 0; + int pidx = 0; + + try { hrs = Convert.ToDecimal(item.hrs); } catch { hrs = 0; } + try { ot = Convert.ToDecimal(item.ot); } catch { ot = 0; } + try { idx = Convert.ToInt32(item.idx); } catch { idx = 0; } + try { pidx = Convert.ToInt32(item.pidx); } catch { pidx = 0; } + + // 안전한 JSON 문자열 이스케이프 처리 및 25자 제한 + var fullDesc = item.description?.ToString() ?? ""; + var desc = EscapeJsonString(fullDesc.Length > 25 ? fullDesc.Substring(0, 25) + "..." : fullDesc); + var pdate = EscapeJsonString(item.pdate?.ToString() ?? ""); + var ww = EscapeJsonString(item.ww?.ToString() ?? ""); + var name = EscapeJsonString(item.name?.ToString() ?? ""); + var status = EscapeJsonString(item.status?.ToString() ?? ""); + var type = EscapeJsonString(item.type?.ToString() ?? ""); + var projectName = EscapeJsonString(item.projectName?.ToString() ?? ""); + var requestpart = EscapeJsonString(item.requestpart?.ToString() ?? ""); + var userProcess = EscapeJsonString(item.userProcess?.ToString() ?? ""); + + jsonData += "{"; + jsonData += $"\"pdate\":\"{pdate}\","; + jsonData += $"\"ww\":\"{ww}\","; + jsonData += $"\"name\":\"{name}\","; + jsonData += $"\"status\":\"{status}\","; + jsonData += $"\"type\":\"{type}\","; + jsonData += $"\"projectName\":\"{projectName}\","; + jsonData += $"\"requestpart\":\"{requestpart}\","; + jsonData += $"\"userProcess\":\"{userProcess}\","; + jsonData += $"\"hrs\":{hrs},"; + jsonData += $"\"ot\":{ot},"; + jsonData += $"\"description\":\"{desc}\","; + jsonData += $"\"idx\":{idx},"; + jsonData += $"\"pidx\":{pidx}"; + jsonData += "}"; + } + } + jsonData += "]"; + + var resp = new HttpResponseMessage() + { + Content = new StringContent( + jsonData, + System.Text.Encoding.UTF8, + "application/json") + }; + + return resp; + } + catch (Exception ex) + { + var errorResp = new HttpResponseMessage() + { + Content = new StringContent( + $"{{\"error\":\"{ex.Message}\"}}", + System.Text.Encoding.UTF8, + "application/json") + }; + return errorResp; + } + } + + private string EscapeJsonString(string input) + { + if (string.IsNullOrEmpty(input)) + return ""; + + // 제어 문자 제거 (0x00-0x1F 범위) + var cleanInput = System.Text.RegularExpressions.Regex.Replace(input, @"[\x00-\x08\x0B\x0C\x0E-\x1F]", ""); + + return cleanInput + .Replace("\\", "\\\\") // 백슬래시 + .Replace("\"", "\\\"") // 따옴표 + .Replace("\n", "\\n") // 개행 + .Replace("\r", "\\r") // 캐리지 리턴 + .Replace("\t", "\\t"); // 탭 + } } -} +} \ No newline at end of file diff --git a/Project/Web/wwwroot/DashBoard/index.html b/Project/Web/wwwroot/DashBoard/index.html index b2572d1..957bef3 100644 --- a/Project/Web/wwwroot/DashBoard/index.html +++ b/Project/Web/wwwroot/DashBoard/index.html @@ -1052,11 +1052,13 @@ ${seqnoText} - ${expireText ? `${expireText}` : ''} +
+ ${expireText ? `
${expireText}
` : ''} + ${todo.request ? `
요청: ${todo.request}
` : ''} +

${todo.title || '제목 없음'}

${todo.remark || ''}

- ${todo.request ? `

요청자: ${todo.request}

` : ''} `; }); diff --git a/Project/Web/wwwroot/Jobreport/index.html b/Project/Web/wwwroot/Jobreport/index.html index 26665b8..5d1d905 100644 --- a/Project/Web/wwwroot/Jobreport/index.html +++ b/Project/Web/wwwroot/Jobreport/index.html @@ -157,8 +157,9 @@
-

총 근무시간

-

0h

+

오늘 근무시간

+

0h

+

(목표 8시간의 0%)

@@ -245,29 +246,19 @@ 상태 + + 근무시간 + 프로젝트명 + 업무내용 요청부서 - - 패키지 - 타입 - - 프로세스 - - 업무내용 - - 근무시간 - - - 초과근무 - - 초과근무 시간 @@ -318,18 +309,32 @@ -