diff --git a/Project/Web/MachineBridge/MachineBridge.Board.cs b/Project/Web/MachineBridge/MachineBridge.Board.cs index 86855ad..bda7759 100644 --- a/Project/Web/MachineBridge/MachineBridge.Board.cs +++ b/Project/Web/MachineBridge/MachineBridge.Board.cs @@ -154,5 +154,150 @@ namespace Project.Web return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message }); } } + + /// + /// 게시판 추가 + /// + public string Board_Add(int bidx, string header, string cate, string title, string contents) + { + try + { + if (string.IsNullOrEmpty(info.Login.no) || string.IsNullOrEmpty(info.Login.gcode)) + { + return JsonConvert.SerializeObject(new { Success = false, Message = "로그인이 필요합니다." }); + } + + var connStr = Project.Properties.Settings.Default.CS; + using (var conn = new SqlConnection(connStr)) + { + conn.Open(); + + var cmd = new SqlCommand(@" + INSERT INTO Board (bidx, header, cate, title, contents, wuid, wdate, gcode) + VALUES (@bidx, @header, @cate, @title, @contents, @wuid, GETDATE(), @gcode); + SELECT SCOPE_IDENTITY();", conn); + + cmd.Parameters.Add("@bidx", SqlDbType.Int).Value = bidx; + cmd.Parameters.Add("@header", SqlDbType.NVarChar).Value = string.IsNullOrEmpty(header) ? (object)DBNull.Value : header; + cmd.Parameters.Add("@cate", SqlDbType.NVarChar).Value = string.IsNullOrEmpty(cate) ? (object)DBNull.Value : cate; + cmd.Parameters.Add("@title", SqlDbType.NVarChar).Value = title; + cmd.Parameters.Add("@contents", SqlDbType.NVarChar).Value = contents; + cmd.Parameters.Add("@wuid", SqlDbType.VarChar).Value = info.Login.no; + cmd.Parameters.Add("@gcode", SqlDbType.VarChar).Value = info.Login.gcode; + + var newIdx = Convert.ToInt32(cmd.ExecuteScalar()); + + return JsonConvert.SerializeObject(new { Success = true, Message = "등록되었습니다.", Data = new { idx = newIdx } }); + } + } + catch (Exception ex) + { + return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message }); + } + } + + /// + /// 게시판 수정 + /// + public string Board_Edit(int idx, string header, string cate, string title, string contents) + { + try + { + if (string.IsNullOrEmpty(info.Login.no) || string.IsNullOrEmpty(info.Login.gcode)) + { + return JsonConvert.SerializeObject(new { Success = false, Message = "로그인이 필요합니다." }); + } + + var connStr = Project.Properties.Settings.Default.CS; + using (var conn = new SqlConnection(connStr)) + { + conn.Open(); + + // 권한 확인: 작성자 본인이거나 레벨 9 이상만 수정 가능 + var checkCmd = new SqlCommand("SELECT wuid FROM Board WHERE idx = @idx", conn); + checkCmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx; + var originalWuid = checkCmd.ExecuteScalar()?.ToString(); + + if (originalWuid != info.Login.no && info.Login.level < 9) + { + return JsonConvert.SerializeObject(new { Success = false, Message = "수정 권한이 없습니다." }); + } + + var cmd = new SqlCommand(@" + UPDATE Board + SET header = @header, cate = @cate, title = @title, contents = @contents + WHERE idx = @idx", conn); + + cmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx; + cmd.Parameters.Add("@header", SqlDbType.NVarChar).Value = string.IsNullOrEmpty(header) ? (object)DBNull.Value : header; + cmd.Parameters.Add("@cate", SqlDbType.NVarChar).Value = string.IsNullOrEmpty(cate) ? (object)DBNull.Value : cate; + cmd.Parameters.Add("@title", SqlDbType.NVarChar).Value = title; + cmd.Parameters.Add("@contents", SqlDbType.NVarChar).Value = contents; + + var affected = cmd.ExecuteNonQuery(); + + if (affected > 0) + { + return JsonConvert.SerializeObject(new { Success = true, Message = "수정되었습니다." }); + } + else + { + return JsonConvert.SerializeObject(new { Success = false, Message = "수정할 데이터를 찾을 수 없습니다." }); + } + } + } + catch (Exception ex) + { + return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message }); + } + } + + /// + /// 게시판 삭제 + /// + public string Board_Delete(int idx) + { + try + { + if (string.IsNullOrEmpty(info.Login.no) || string.IsNullOrEmpty(info.Login.gcode)) + { + return JsonConvert.SerializeObject(new { Success = false, Message = "로그인이 필요합니다." }); + } + + var connStr = Project.Properties.Settings.Default.CS; + using (var conn = new SqlConnection(connStr)) + { + conn.Open(); + + // 권한 확인: 작성자 본인이거나 레벨 9 이상만 삭제 가능 + var checkCmd = new SqlCommand("SELECT wuid FROM Board WHERE idx = @idx", conn); + checkCmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx; + var originalWuid = checkCmd.ExecuteScalar()?.ToString(); + + if (originalWuid != info.Login.no && info.Login.level < 9) + { + return JsonConvert.SerializeObject(new { Success = false, Message = "삭제 권한이 없습니다." }); + } + + var cmd = new SqlCommand("DELETE FROM Board WHERE idx = @idx", conn); + cmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx; + + var affected = cmd.ExecuteNonQuery(); + + if (affected > 0) + { + return JsonConvert.SerializeObject(new { Success = true, Message = "삭제되었습니다." }); + } + else + { + return JsonConvert.SerializeObject(new { Success = false, Message = "삭제할 데이터를 찾을 수 없습니다." }); + } + } + } + catch (Exception ex) + { + return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message }); + } + } } } diff --git a/Project/Web/MachineBridge/WebSocketServer.cs b/Project/Web/MachineBridge/WebSocketServer.cs index 892650d..c96e3b2 100644 --- a/Project/Web/MachineBridge/WebSocketServer.cs +++ b/Project/Web/MachineBridge/WebSocketServer.cs @@ -917,6 +917,41 @@ namespace Project.Web } break; + case "BOARD_ADD": + { + int bidx = json.bidx ?? 5; + string header = json.header ?? ""; + string cate = json.cate ?? ""; + string title = json.title ?? ""; + string contents = json.contents ?? ""; + string result = _bridge.Board_Add(bidx, header, cate, title, contents); + var response = new { type = "BOARD_ADDED", data = JsonConvert.DeserializeObject(result) }; + await Send(socket, JsonConvert.SerializeObject(response)); + } + break; + + case "BOARD_EDIT": + { + int idx = json.idx ?? 0; + string header = json.header ?? ""; + string cate = json.cate ?? ""; + string title = json.title ?? ""; + string contents = json.contents ?? ""; + string result = _bridge.Board_Edit(idx, header, cate, title, contents); + var response = new { type = "BOARD_EDITED", data = JsonConvert.DeserializeObject(result) }; + await Send(socket, JsonConvert.SerializeObject(response)); + } + break; + + case "BOARD_DELETE": + { + int idx = json.idx ?? 0; + string result = _bridge.Board_Delete(idx); + var response = new { type = "BOARD_DELETED", data = JsonConvert.DeserializeObject(result) }; + await Send(socket, JsonConvert.SerializeObject(response)); + } + break; + // ===== Mail API (메일 발신 내역) ===== case "MAIL_GET_LIST": { diff --git a/Project/frontend/src/communication.ts b/Project/frontend/src/communication.ts index 66cdabf..c245152 100644 --- a/Project/frontend/src/communication.ts +++ b/Project/frontend/src/communication.ts @@ -1264,6 +1264,56 @@ class CommunicationLayer { } } + /** + * 게시판 추가 + * @param bidx 게시판 인덱스 + * @param header 헤더 + * @param cate 카테고리 + * @param title 제목 + * @param contents 내용 + * @returns ApiResponse + */ + public async addBoard(bidx: number, header: string, cate: string, title: string, contents: string): Promise { + if (isWebView && machine) { + const result = await machine.Board_Add(bidx, header, cate, title, contents); + return JSON.parse(result); + } else { + return this.wsRequest('BOARD_ADD', 'BOARD_ADDED', { bidx, header, cate, title, contents }); + } + } + + /** + * 게시판 수정 + * @param idx 게시판 글 인덱스 + * @param header 헤더 + * @param cate 카테고리 + * @param title 제목 + * @param contents 내용 + * @returns ApiResponse + */ + public async editBoard(idx: number, header: string, cate: string, title: string, contents: string): Promise { + if (isWebView && machine) { + const result = await machine.Board_Edit(idx, header, cate, title, contents); + return JSON.parse(result); + } else { + return this.wsRequest('BOARD_EDIT', 'BOARD_EDITED', { idx, header, cate, title, contents }); + } + } + + /** + * 게시판 삭제 + * @param idx 게시판 글 인덱스 + * @returns ApiResponse + */ + public async deleteBoard(idx: number): Promise { + if (isWebView && machine) { + const result = await machine.Board_Delete(idx); + return JSON.parse(result); + } else { + return this.wsRequest('BOARD_DELETE', 'BOARD_DELETED', { idx }); + } + } + /** * 메일 발신 내역 조회 * @param startDate 시작일 (yyyy-MM-dd) diff --git a/Project/frontend/src/pages/PatchList.tsx b/Project/frontend/src/pages/PatchList.tsx index 4abfa9e..cfbfd2b 100644 --- a/Project/frontend/src/pages/PatchList.tsx +++ b/Project/frontend/src/pages/PatchList.tsx @@ -87,15 +87,73 @@ export function PatchList() { if (!editFormData) return; try { - // TODO: Board_Edit API 구현 필요 - alert('게시판 수정 API가 아직 구현되지 않았습니다.'); - console.log('수정할 데이터:', editFormData); + const isNew = editFormData.idx === 0; + + if (isNew) { + // 신규 등록 + const response = await comms.addBoard( + 5, // bidx: 패치내역 + editFormData.header || '', + editFormData.cate || '', + editFormData.title || '', + editFormData.contents || '' + ); + + if (response.Success) { + alert('등록되었습니다.'); + setShowEditModal(false); + setEditFormData(null); + loadData(); + } else { + alert(response.Message || '등록에 실패했습니다.'); + } + } else { + // 수정 + const response = await comms.editBoard( + editFormData.idx, + editFormData.header || '', + editFormData.cate || '', + editFormData.title || '', + editFormData.contents || '' + ); + + if (response.Success) { + alert('수정되었습니다.'); + setShowEditModal(false); + setEditFormData(null); + loadData(); + } else { + alert(response.Message || '수정에 실패했습니다.'); + } + } } catch (error) { console.error('저장 오류:', error); alert('저장 중 오류가 발생했습니다.'); } }; + const handleDelete = async () => { + if (!editFormData || editFormData.idx === 0) return; + + if (!confirm('정말 삭제하시겠습니까?')) return; + + try { + const response = await comms.deleteBoard(editFormData.idx); + + if (response.Success) { + alert('삭제되었습니다.'); + setShowEditModal(false); + setEditFormData(null); + loadData(); + } else { + alert(response.Message || '삭제에 실패했습니다.'); + } + } catch (error) { + console.error('삭제 오류:', error); + alert('삭제 중 오류가 발생했습니다.'); + } + }; + const formatDate = (dateStr: string | null) => { if (!dateStr) return '-'; try { @@ -359,19 +417,31 @@ export function PatchList() { -
- - +
+
+ {editFormData && editFormData.idx > 0 && ( + + )} +
+
+ + +
diff --git a/Project/frontend/src/types.ts b/Project/frontend/src/types.ts index 6f327d7..f3707b1 100644 --- a/Project/frontend/src/types.ts +++ b/Project/frontend/src/types.ts @@ -459,6 +459,9 @@ export interface MachineBridgeInterface { // Board API (게시판 - 패치내역 등) Board_GetList(bidx: number, searchKey: string): Promise; Board_GetDetail(idx: number): Promise; + Board_Add(bidx: number, header: string, cate: string, title: string, contents: string): Promise; + Board_Edit(idx: number, header: string, cate: string, title: string, contents: string): Promise; + Board_Delete(idx: number): Promise; // Mail API (메일 발신 내역) Mail_GetList(startDate: string, endDate: string, searchKey: string): Promise;