From 9b2ee87542c5f30e60ededc8f3eff82c15bee6b3 Mon Sep 17 00:00:00 2001 From: backuppc Date: Tue, 2 Dec 2025 15:35:28 +0900 Subject: [PATCH] Implement Customs API backend and frontend integration --- .../MachineBridge/MachineBridge.Customs.cs | 178 ++++++++++++++++++ Project/frontend/src/communication.ts | 29 +++ Project/frontend/src/pages/Customs.tsx | 58 +++--- Project/frontend/src/types.ts | 25 +++ 4 files changed, 256 insertions(+), 34 deletions(-) create mode 100644 Project/Web/MachineBridge/MachineBridge.Customs.cs diff --git a/Project/Web/MachineBridge/MachineBridge.Customs.cs b/Project/Web/MachineBridge/MachineBridge.Customs.cs new file mode 100644 index 0000000..308975b --- /dev/null +++ b/Project/Web/MachineBridge/MachineBridge.Customs.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq; +using Newtonsoft.Json; +using FCOMMON; + +namespace Project.Web +{ + public partial class MachineBridge + { + #region Customs API + + /// + /// 업체정보 목록 조회 + /// + public string Customs_GetList(string searchKey = "") + { + try + { + // 로그인 체크 + if (string.IsNullOrEmpty(info.Login.no) || string.IsNullOrEmpty(info.Login.gcode)) + { + return JsonConvert.SerializeObject(new { Success = false, Message = "로그인이 필요합니다." }); + } + + var connStr = Properties.Settings.Default.CS; + using (var conn = new SqlConnection(connStr)) + { + conn.Open(); + var cmd = new SqlCommand(); + cmd.Connection = conn; + + // 검색 조건이 있으면 필터링 + if (string.IsNullOrEmpty(searchKey)) + { + cmd.CommandText = @" + SELECT idx, grp, name, owner, ownertel, address, tel, fax, email, memo, + wuid, wdate, uptae, staff, stafftel, name2, gcode + FROM Customs WITH (nolock) + WHERE gcode = @gcode + ORDER BY name"; + } + else + { + // 여러 필드에서 검색 (fCustoms.cs의 btFind_Click 로직 참고) + cmd.CommandText = @" + SELECT idx, grp, name, owner, ownertel, address, tel, fax, email, memo, + wuid, wdate, uptae, staff, stafftel, name2, gcode + FROM Customs WITH (nolock) + WHERE gcode = @gcode + AND (stafftel LIKE @search + OR grp LIKE @search + OR name2 LIKE @search + OR name LIKE @search + OR owner LIKE @search + OR address LIKE @search + OR tel LIKE @search + OR email LIKE @search + OR memo LIKE @search + OR staff LIKE @search) + ORDER BY name"; + cmd.Parameters.Add("@search", SqlDbType.NVarChar).Value = "%" + searchKey.Replace("'", "''") + "%"; + } + + cmd.Parameters.Add("@gcode", SqlDbType.VarChar).Value = info.Login.gcode; + + var list = new List(); + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + list.Add(new + { + idx = reader["idx"], + grp = reader["grp"] != DBNull.Value ? reader["grp"] : "", + name = reader["name"] != DBNull.Value ? reader["name"] : "", + owner = reader["owner"] != DBNull.Value ? reader["owner"] : "", + ownertel = reader["ownertel"] != DBNull.Value ? reader["ownertel"] : "", + address = reader["address"] != DBNull.Value ? reader["address"] : "", + tel = reader["tel"] != DBNull.Value ? reader["tel"] : "", + fax = reader["fax"] != DBNull.Value ? reader["fax"] : "", + email = reader["email"] != DBNull.Value ? reader["email"] : "", + memo = reader["memo"] != DBNull.Value ? reader["memo"] : "", + wuid = reader["wuid"], + wdate = reader["wdate"], + uptae = reader["uptae"] != DBNull.Value ? reader["uptae"] : "", + staff = reader["staff"] != DBNull.Value ? reader["staff"] : "", + stafftel = reader["stafftel"] != DBNull.Value ? reader["stafftel"] : "", + name2 = reader["name2"] != DBNull.Value ? reader["name2"] : "", + gcode = reader["gcode"] + }); + } + } + + return JsonConvert.SerializeObject(new { Success = true, Message = "", Data = list }); + } + } + catch (Exception ex) + { + return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message, Data = (object)null }); + } + } + + /// + /// 업체정보 상세 조회 + /// + public string Customs_GetDetail(int idx) + { + try + { + // 로그인 체크 + if (string.IsNullOrEmpty(info.Login.no) || string.IsNullOrEmpty(info.Login.gcode)) + { + return JsonConvert.SerializeObject(new { Success = false, Message = "로그인이 필요합니다." }); + } + + var connStr = Properties.Settings.Default.CS; + using (var conn = new SqlConnection(connStr)) + { + conn.Open(); + var cmd = new SqlCommand(); + cmd.Connection = conn; + cmd.CommandText = @" + SELECT idx, grp, name, owner, ownertel, address, tel, fax, email, memo, + wuid, wdate, uptae, staff, stafftel, name2, gcode + FROM Customs WITH (nolock) + WHERE idx = @idx AND gcode = @gcode"; + + cmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx; + cmd.Parameters.Add("@gcode", SqlDbType.VarChar).Value = info.Login.gcode; + + object result = null; + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + result = new + { + idx = reader["idx"], + grp = reader["grp"] != DBNull.Value ? reader["grp"] : "", + name = reader["name"] != DBNull.Value ? reader["name"] : "", + owner = reader["owner"] != DBNull.Value ? reader["owner"] : "", + ownertel = reader["ownertel"] != DBNull.Value ? reader["ownertel"] : "", + address = reader["address"] != DBNull.Value ? reader["address"] : "", + tel = reader["tel"] != DBNull.Value ? reader["tel"] : "", + fax = reader["fax"] != DBNull.Value ? reader["fax"] : "", + email = reader["email"] != DBNull.Value ? reader["email"] : "", + memo = reader["memo"] != DBNull.Value ? reader["memo"] : "", + wuid = reader["wuid"], + wdate = reader["wdate"], + uptae = reader["uptae"] != DBNull.Value ? reader["uptae"] : "", + staff = reader["staff"] != DBNull.Value ? reader["staff"] : "", + stafftel = reader["stafftel"] != DBNull.Value ? reader["stafftel"] : "", + name2 = reader["name2"] != DBNull.Value ? reader["name2"] : "", + gcode = reader["gcode"] + }; + } + } + + if (result == null) + { + return JsonConvert.SerializeObject(new { Success = false, Message = "해당 업체 정보를 찾을 수 없습니다.", Data = (object)null }); + } + + return JsonConvert.SerializeObject(new { Success = true, Message = "", Data = result }); + } + } + catch (Exception ex) + { + return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message, Data = (object)null }); + } + } + + #endregion + } +} diff --git a/Project/frontend/src/communication.ts b/Project/frontend/src/communication.ts index edc4e41..66cdabf 100644 --- a/Project/frontend/src/communication.ts +++ b/Project/frontend/src/communication.ts @@ -41,6 +41,7 @@ import type { MachineBridgeInterface, BoardItem, MailItem, + CustomItem, } from '@/types'; // WebView2 환경 감지 @@ -1278,6 +1279,34 @@ class CommunicationLayer { return this.wsRequest>('MAIL_GET_LIST', 'MAIL_LIST_DATA', { startDate, endDate, searchKey }); } } + + /** + * 업체정보 목록 조회 + * @param searchKey 검색어 + * @returns ApiResponse + */ + public async getCustomsList(searchKey: string = ''): Promise> { + if (isWebView && machine) { + const result = await machine.Customs_GetList(searchKey); + return JSON.parse(result); + } else { + return this.wsRequest>('CUSTOMS_GET_LIST', 'CUSTOMS_LIST_DATA', { searchKey }); + } + } + + /** + * 업체정보 상세 조회 + * @param idx 업체 인덱스 + * @returns ApiResponse + */ + public async getCustomsDetail(idx: number): Promise> { + if (isWebView && machine) { + const result = await machine.Customs_GetDetail(idx); + return JSON.parse(result); + } else { + return this.wsRequest>('CUSTOMS_GET_DETAIL', 'CUSTOMS_DETAIL_DATA', { idx }); + } + } } export const comms = new CommunicationLayer(); diff --git a/Project/frontend/src/pages/Customs.tsx b/Project/frontend/src/pages/Customs.tsx index dd9e6c3..cf26688 100644 --- a/Project/frontend/src/pages/Customs.tsx +++ b/Project/frontend/src/pages/Customs.tsx @@ -1,21 +1,7 @@ import { useState, useEffect } from 'react'; import { Building, Search, RefreshCw } from 'lucide-react'; - -// 임시 타입 정의 (실제 타입은 백엔드에 맞게 수정 필요) -interface CustomItem { - idx: number; - ccode: string; - cname: string; - gubun: string; - addr: string; - tel: string; - fax: string; - email: string; - ceo: string; - busino: string; - uptae: string; - jongmok: string; -} +import { comms } from '@/communication'; +import type { CustomItem } from '@/types'; export function Customs() { const [customsList, setCustomsList] = useState([]); @@ -29,19 +15,18 @@ export function Customs() { const loadData = async () => { setLoading(true); try { - // TODO: 실제 API 호출로 변경 필요 - // const response = await comms.getCustomsList(searchKey); - // if (response.Success && response.Data) { - // setCustomsList(response.Data); - // } - - // 임시 데이터 - console.log('업체정보 조회 (구현 필요):', { searchKey }); - alert('업체정보 API가 아직 구현되지 않았습니다.'); - setCustomsList([]); + const response = await comms.getCustomsList(searchKey); + if (response.Success && response.Data) { + setCustomsList(response.Data); + } else { + console.error('업체정보 조회 실패:', response.Message); + alert(response.Message || '업체정보 조회에 실패했습니다.'); + setCustomsList([]); + } } catch (error) { console.error('업체정보 로드 오류:', error); alert('데이터를 불러오는 중 오류가 발생했습니다.'); + setCustomsList([]); } finally { setLoading(false); } @@ -63,7 +48,7 @@ export function Customs() { value={searchKey} onChange={(e) => setSearchKey(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - placeholder="업체명, 사업자번호, 대표자 등" + placeholder="업체명, 대표자, 전화번호, 이메일, 담당자 등" className="flex-1 h-10 bg-white/20 border border-white/30 rounded-lg px-3 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400" /> @@ -115,16 +100,21 @@ export function Customs() { >
-

{item.cname}

-
-
대표: {item.ceo}
-
사업자: {item.busino}
-
업태: {item.uptae}
+

+ {item.name} + {item.name2 && ({item.name2})} +

+
+ {item.grp &&
구분: {item.grp}
} + {item.owner &&
대표: {item.owner}
} + {item.uptae &&
업태: {item.uptae}
} + {item.address &&
{item.address}
}
-
{item.tel}
-
{item.email}
+ {item.tel &&
{item.tel}
} + {item.email &&
{item.email}
} + {item.staff &&
담당: {item.staff}
}
diff --git a/Project/frontend/src/types.ts b/Project/frontend/src/types.ts index c92fd45..6f327d7 100644 --- a/Project/frontend/src/types.ts +++ b/Project/frontend/src/types.ts @@ -462,6 +462,10 @@ export interface MachineBridgeInterface { // Mail API (메일 발신 내역) Mail_GetList(startDate: string, endDate: string, searchKey: string): Promise; + + // Customs API (업체정보) + Customs_GetList(searchKey: string): Promise; + Customs_GetDetail(idx: number): Promise; } // 사용자 권한 정보 타입 @@ -859,3 +863,24 @@ export interface MailItem { cate: string; wdate: string | null; } + +// 업체정보 타입 +export interface CustomItem { + idx: number; + grp: string; + name: string; + owner: string; + ownertel: string; + address: string; + tel: string; + fax: string; + email: string; + memo: string; + wuid: string; + wdate: string; + uptae: string; + staff: string; + stafftel: string; + name2: string; + gcode: string; +}