diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d15a935 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,116 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is a Korean Enterprise GroupWare system built with C# .NET Framework 4.6 and Windows Forms. The application serves as a comprehensive business management system that includes project management, purchasing, attendance tracking, reporting, and web-based functionality. The project runs on port 7979 (previously 9000) and includes both desktop and web components. + +## Architecture + +### Main Application (Project/EETGW.csproj) +- **Entry Point**: `Project/Program.cs` - Handles WebView2Runtime extraction and starts the main form +- **Main Form**: `Project/fMain.cs` - Primary application window +- **Web Server**: Integrated OWIN-based web server for HTTP API and static files +- **Database**: Microsoft SQL Server with Entity Framework 6.2.0 +- **Target Framework**: .NET Framework 4.6 + +### Key Components + +1. **Web Layer** (`Project/Web/`): + - **Startup.cs**: OWIN configuration for HTTP API and static file serving + - **Controllers**: API controllers for various business functions (Home, Project, Purchase, Item, etc.) + - **wwwroot**: Static web assets (HTML, CSS, JS files) + +2. **SubProjects**: Modular components with specific business functionality: + - **FPJ0000**: Project management module + - **FCM0000**: Customer management + - **FEQ0000**: Equipment management + - **FBS0000**: Holiday/attendance management + - **FCOMMON**: Shared common functionality + - **WebServer**: Additional web services + - **AmkorRestfulService**: REST API services + +3. **Sub Components** (`Sub/`): + - **arCtl**: Custom controls library + - **arftp**: FTP functionality + - **tcpservice**: TCP communication services + - **YARTE**: HTML editor component + - **StaffLayoutCtl**: Staff layout controls + +### Technology Stack +- **UI Framework**: Windows Forms with custom controls (FarPoint Spread grids) +- **Web Framework**: OWIN with ASP.NET Web API 5.2.9 +- **Database ORM**: Entity Framework 6.2.0 +- **JSON Processing**: Newtonsoft.Json 13.0.3 +- **Web Browser**: Microsoft WebView2 1.0.2210.55 +- **Reports**: Microsoft ReportViewer 15.0 +- **Excel Processing**: libxl.net and CsvHelper 30.0.1 + +## Development Commands + +### Building the Solution +```bash +# Build the entire solution +msbuild EETGW.sln /p:Configuration=Debug /p:Platform="Any CPU" + +# Build for release +msbuild EETGW.sln /p:Configuration=Release /p:Platform="Any CPU" + +# Build specific project +msbuild Project/EETGW.csproj /p:Configuration=Debug +``` + +### Running the Application +- **Debug Mode**: Run from Visual Studio or build and execute the output from `Project/bin/Debug/` +- **Web Server**: Automatically starts on port 7979 when the application launches +- **Database**: Ensure SQL Server connection string is configured in app.config + +### Package Management +- Uses NuGet packages defined in `packages.config` files throughout the solution +- Restore packages using: `nuget restore EETGW.sln` + +## Configuration + +### Database Connection +- Connection strings configured in individual `app.config` files +- Primary database connection in `Project/app.config` +- Uses Entity Framework with SQL Server + +### Web Server Configuration +- **Port**: 7979 (configured in startup) +- **Static Files**: Served from `Project/Web/wwwroot/` +- **API Routes**: Configured in `Project/Web/Startup.cs` +- **CORS**: Enabled for all origins + +### Build Configurations +- **Debug**: Outputs to `Project/bin/Debug/` with x86 platform target +- **Release**: Optimized build configuration +- Different output paths for various configurations (see EETGW.csproj) + +## Key Conventions + +### Code Organization +- Korean comments and variable names are common throughout the codebase +- Business logic separated into modular SubProjects +- Shared functionality centralized in FCOMMON project +- Custom controls and utilities in Sub/ directory + +### File Structure +- Each SubProject has its own namespace and assembly +- Form files follow naming convention: `f[FormName].cs` with corresponding `.Designer.cs` and `.resx` +- Dataset files use `.xsd` schemas with generated code + +### Dependencies +- Heavy use of FarPoint Spread controls for data grids +- Custom logging via ArLog.Net4.dll +- Settings management through ArSetting.Net4.dll +- Multiple third-party libraries for Excel, FTP, and web functionality + +## Development Notes + +- WebView2Runtime is automatically extracted on first run from WebView2Runtime.zip +- The application includes comprehensive error handling and logging +- Multiple authentication methods including AD integration +- Supports both Korean and English localization +- Includes extensive reporting capabilities with RDLC files \ No newline at end of file diff --git a/Project/Dialog/fCommon.cs b/Project/Dialog/fCommon.cs index 2de46fd..6a6d3fb 100644 --- a/Project/Dialog/fCommon.cs +++ b/Project/Dialog/fCommon.cs @@ -22,7 +22,8 @@ namespace Project.Dialog { InitializeComponent(); - + this.Text = "공용코드 관리"; + this.Size = new Size(1000, 900); InitializeWebView2(); diff --git a/Project/EETGW.csproj b/Project/EETGW.csproj index 51a57bb..96236e1 100644 --- a/Project/EETGW.csproj +++ b/Project/EETGW.csproj @@ -204,7 +204,7 @@ ..\packages\Owin.1.0\lib\net40\Owin.dll - C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\System.dll + ..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\System.dll ..\packages\System.Buffers.4.5.1\lib\netstandard1.1\System.Buffers.dll @@ -670,22 +670,25 @@ PreserveNewest - + PreserveNewest - + + + PreserveNewest + PreserveNewest - + PreserveNewest - - + + PreserveNewest - - + + PreserveNewest - - + + PreserveNewest @@ -770,9 +773,7 @@ - - - + diff --git a/Project/Web/Controller/CommonController.cs b/Project/Web/Controller/CommonController.cs index e672256..997dfe8 100644 --- a/Project/Web/Controller/CommonController.cs +++ b/Project/Web/Controller/CommonController.cs @@ -15,20 +15,34 @@ namespace Project.Web.Controllers public HttpResponseMessage GetList(string grp=null) { var sql = string.Empty; - sql = "select *" + - " from common" + - " where gcode = @gcode" + - " and grp = @grp" + - " order by code,svalue"; + + if (string.IsNullOrEmpty(grp)) + { + // grp가 없으면 모든 그룹의 데이터를 가져옴 + sql = "select *" + + " from common" + + " where gcode = @gcode" + + " order by grp, code, svalue"; + } + else + { + // 특정 그룹의 데이터만 가져옴 + sql = "select *" + + " from common" + + " where gcode = @gcode" + + " and grp = @grp" + + " order by code,svalue"; + } - var cs = Properties.Settings.Default.gwcs;// "Data Source=K4FASQL.kr.ds.amkor.com,50150;Initial Catalog=EE;Persist Security Info=True;User ID=eeadm;Password=uJnU8a8q&DJ+ug-D!"; + var cs = Properties.Settings.Default.gwcs; var cn = new System.Data.SqlClient.SqlConnection(cs); var cmd = new System.Data.SqlClient.SqlCommand(sql, cn); cmd.Parameters.AddWithValue("gcode", FCOMMON.info.Login.gcode); - // 날짜 파라미터가 없으면 기본값 사용 (현재 월) - var grpCode = !string.IsNullOrEmpty(grp) ? grp : "99"; - cmd.Parameters.AddWithValue("grp", grpCode); + if (!string.IsNullOrEmpty(grp)) + { + cmd.Parameters.AddWithValue("grp", grp); + } var da = new System.Data.SqlClient.SqlDataAdapter(cmd); var dt = new System.Data.DataTable(); @@ -83,7 +97,262 @@ namespace Project.Web.Controllers return resp; } - + [HttpPost] + public HttpResponseMessage Save([FromBody] CommonModel model) + { + try + { + var cs = Properties.Settings.Default.gwcs; + var cn = new System.Data.SqlClient.SqlConnection(cs); + var sql = string.Empty; + var cmd = new System.Data.SqlClient.SqlCommand(); + cmd.Connection = cn; + + if (model.idx > 0) + { + // 업데이트 + sql = @"UPDATE common SET + grp = @grp, + code = @code, + svalue = @svalue, + ivalue = @ivalue, + fvalue = @fvalue, + svalue2 = @svalue2, + memo = @memo, + wuid = @wuid, + wdate = GETDATE() + WHERE idx = @idx AND gcode = @gcode"; + } + else + { + // 신규 추가 + sql = @"INSERT INTO common (gcode, grp, code, svalue, ivalue, fvalue, svalue2, memo, wuid, wdate) + VALUES (@gcode, @grp, @code, @svalue, @ivalue, @fvalue, @svalue2, @memo, @wuid, GETDATE())"; + } + + cmd.CommandText = sql; + cmd.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + cmd.Parameters.AddWithValue("@grp", model.grp ?? ""); + cmd.Parameters.AddWithValue("@code", model.code ?? ""); + cmd.Parameters.AddWithValue("@svalue", model.svalue ?? ""); + cmd.Parameters.AddWithValue("@ivalue", model.ivalue); + cmd.Parameters.AddWithValue("@fvalue", model.fvalue); + cmd.Parameters.AddWithValue("@svalue2", model.svalue2 ?? ""); + cmd.Parameters.AddWithValue("@memo", model.memo ?? ""); + cmd.Parameters.AddWithValue("@wuid", FCOMMON.info.Login.no); + + if (model.idx > 0) + { + cmd.Parameters.AddWithValue("@idx", model.idx); + } + + cn.Open(); + var result = cmd.ExecuteNonQuery(); + cn.Close(); + + cmd.Dispose(); + cn.Dispose(); + + var response = new + { + Success = result > 0, + Message = result > 0 ? "저장되었습니다." : "저장에 실패했습니다." + }; + + return CreateJsonResponse(response); + } + catch (Exception ex) + { + var response = new + { + Success = false, + Message = "오류가 발생했습니다: " + ex.Message + }; + return CreateJsonResponse(response); + } + } + + [HttpPost] + public HttpResponseMessage Delete([FromBody] DeleteModel model) + { + try + { + var cs = Properties.Settings.Default.gwcs; + var cn = new System.Data.SqlClient.SqlConnection(cs); + var sql = "DELETE FROM common WHERE idx = @idx AND gcode = @gcode"; + var cmd = new System.Data.SqlClient.SqlCommand(sql, cn); + + cmd.Parameters.AddWithValue("@idx", model.idx); + cmd.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + + cn.Open(); + var result = cmd.ExecuteNonQuery(); + cn.Close(); + + cmd.Dispose(); + cn.Dispose(); + + var response = new + { + Success = result > 0, + Message = result > 0 ? "삭제되었습니다." : "삭제에 실패했습니다." + }; + + return CreateJsonResponse(response); + } + catch (Exception ex) + { + var response = new + { + Success = false, + Message = "오류가 발생했습니다: " + ex.Message + }; + return CreateJsonResponse(response); + } + } + + [HttpGet] + public HttpResponseMessage GetGroups() + { + try + { + var sql = "select code, svalue from common WITH (nolock) " + + "where gcode = @gcode and grp = '99' " + + "order by code"; + + var cs = Properties.Settings.Default.gwcs; + var cn = new System.Data.SqlClient.SqlConnection(cs); + var cmd = new System.Data.SqlClient.SqlCommand(sql, cn); + cmd.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + + var da = new System.Data.SqlClient.SqlDataAdapter(cmd); + var dt = new System.Data.DataTable(); + da.Fill(dt); + da.Dispose(); + cmd.Dispose(); + cn.Dispose(); + + var txtjson = JsonConvert.SerializeObject(dt, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + + var resp = new HttpResponseMessage() + { + Content = new StringContent( + txtjson, + System.Text.Encoding.UTF8, + "application/json") + }; + + return resp; + } + catch (Exception ex) + { + var response = new + { + Message = ex.Message, + }; + return CreateJsonResponse(response); + } + } + + [HttpPost] + public HttpResponseMessage InitializeGroups() + { + try + { + var cs = Properties.Settings.Default.gwcs; + var cn = new System.Data.SqlClient.SqlConnection(cs); + + // 기본 그룹코드들 정의 + var defaultGroups = new[] + { + new { code = "01", svalue = "부서코드" }, + new { code = "02", svalue = "직급코드" }, + new { code = "03", svalue = "공정코드" }, + new { code = "04", svalue = "품목분류" }, + new { code = "05", svalue = "업체분류" }, + new { code = "06", svalue = "제조공정" }, + new { code = "07", svalue = "장비제조" }, + new { code = "08", svalue = "장비모델" }, + new { code = "09", svalue = "장비기술" }, + new { code = "99", svalue = "기타" } + }; + + cn.Open(); + + int insertedCount = 0; + foreach (var group in defaultGroups) + { + // 이미 존재하는지 확인 + var checkSql = "SELECT COUNT(*) FROM common WHERE gcode = @gcode AND grp = '99' AND code = @code"; + var checkCmd = new System.Data.SqlClient.SqlCommand(checkSql, cn); + checkCmd.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + checkCmd.Parameters.AddWithValue("@code", group.code); + + var exists = (int)checkCmd.ExecuteScalar() > 0; + checkCmd.Dispose(); + + if (!exists) + { + // 새로 추가 + var insertSql = @"INSERT INTO common (gcode, grp, code, svalue, ivalue, fvalue, svalue2, memo, wuid, wdate) + VALUES (@gcode, '99', @code, @svalue, 0, 0.0, '', '코드그룹 정의', @wuid, GETDATE())"; + var insertCmd = new System.Data.SqlClient.SqlCommand(insertSql, cn); + insertCmd.Parameters.AddWithValue("@gcode", FCOMMON.info.Login.gcode); + insertCmd.Parameters.AddWithValue("@code", group.code); + insertCmd.Parameters.AddWithValue("@svalue", group.svalue); + insertCmd.Parameters.AddWithValue("@wuid", FCOMMON.info.Login.no); + + insertCmd.ExecuteNonQuery(); + insertCmd.Dispose(); + insertedCount++; + } + } + + cn.Close(); + cn.Dispose(); + + var response = new + { + Success = true, + Message = $"그룹코드 초기화 완료. {insertedCount}개 추가됨." + }; + + return CreateJsonResponse(response); + } + catch (Exception ex) + { + var response = new + { + Success = false, + Message = "오류가 발생했습니다: " + ex.Message + }; + return CreateJsonResponse(response); + } + } + + private HttpResponseMessage CreateJsonResponse(object data) + { + var json = JsonConvert.SerializeObject(data, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); + + return new HttpResponseMessage() + { + Content = new StringContent( + json, + System.Text.Encoding.UTF8, + "application/json") + }; + } + } + + public class DeleteModel + { + public int idx { get; set; } } public class CommonModel diff --git a/Project/Web/Controller/HomeController.cs b/Project/Web/Controller/HomeController.cs index 740da4f..9888c16 100644 --- a/Project/Web/Controller/HomeController.cs +++ b/Project/Web/Controller/HomeController.cs @@ -322,8 +322,8 @@ namespace Project.Web.Controllers [HttpGet] public HttpResponseMessage Index() { - // 직접 파일을 읽어서 반환 - var filePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web", "wwwroot", "index.html"); + // DashBoard로 리디렉션하도록 변경 + var filePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web", "wwwroot", "DashBoard", "index.html"); var contents = string.Empty; if (System.IO.File.Exists(filePath)) diff --git a/Project/Web/Startup.cs b/Project/Web/Startup.cs index 9beefa9..99d848b 100644 --- a/Project/Web/Startup.cs +++ b/Project/Web/Startup.cs @@ -22,6 +22,13 @@ namespace Project.OWIN //라우팅 설정 config.MapHttpAttributeRoutes(); + // 컨트롤러만 있는 경우 기본 액션을 Index로 설정 + config.Routes.MapHttpRoute( + name: "ControllerOnly", + routeTemplate: "{controller}", + defaults: new { action = "Index" } + ); + config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "{controller}/{action}/{id}", diff --git a/Project/Web/wwwroot/Common.html b/Project/Web/wwwroot/Common.html index 78a467a..aaa8d52 100644 --- a/Project/Web/wwwroot/Common.html +++ b/Project/Web/wwwroot/Common.html @@ -23,8 +23,694 @@ } } + - -intro file + +
+ +
+

공용코드 관리

+

시스템 공용코드를 관리합니다

+
+ + +
+
+ + + +
+

🚧 개발중인 기능입니다

+

일부 기능이 정상적으로 동작하지 않을 수 있습니다.

+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + + + + + + + + + + + + + + +
코드비고값(문자열)값(숫자)값(실수)값2작업
+
+
+

0

+
+
+ + + +
+ + + + + + + + \ No newline at end of file diff --git a/Project/Web/wwwroot/DashBoard/index.html b/Project/Web/wwwroot/DashBoard/index.html index b28d73e..4ce4b96 100644 --- a/Project/Web/wwwroot/DashBoard/index.html +++ b/Project/Web/wwwroot/DashBoard/index.html @@ -3,6 +3,10 @@ + + + + 근태현황 대시보드 + - - -
-
-
-
- -

업무일지

-
-
- -
- -
+ + + +
+ +
+

업무일지

+
+ +
+
-
- -
+ +
+
+ + + +
+

🚧 개발중인 기능입니다

+

일부 기능이 정상적으로 동작하지 않을 수 있습니다.

+
+
+
+ -
-
+
+
-
- +
+
-

총 업무일수

-

0

+

총 업무일수

+

0

-
+
-
- +
+
-

총 근무시간

-

0h

+

총 근무시간

+

0h

-
+
-
- +
+
-

총 초과근무

-

0h

+

총 초과근무

+

0h

-
+
-
- +
+
-

진행중 프로젝트

-

0

+

진행중 프로젝트

+

0

-
-
+
+
- +
- - ~ - + + ~ +
- - @@ -121,22 +223,22 @@
- -
- - + +
- - @@ -146,43 +248,43 @@
-
+
- - +
+ - - - - - - - - - + - - + - +
+ 날짜 + 상태 + 프로젝트명 + 요청부서 + 패키지 + 타입 + 프로세스 업무내용 + 업무내용 근무시간 + 초과근무 초과근무 시간초과근무 시간
@@ -190,27 +292,27 @@
-
+ - +
+ + +
+

근태관리

+

출퇴근 시간 및 휴가 관리

+
+ + +
+
+ + + +
+

🚧 개발중인 기능입니다

+

일부 기능이 정상적으로 동작하지 않을 수 있습니다.

+
+
+
-
+
- - + +
- - + +
- @@ -88,66 +183,66 @@
-
-
+
+
-
- +
+
-

휴가사용

-

0

+

휴가사용

+

0

-
+
-
- +
+
-

대체사용

-

0

+

대체사용

+

0

-
+
-
- +
+
-

잔량(년차)

-

0

+

잔량(년차)

+

0

-
+
-
- +
+
-

잔량(대체)

-

0

+

잔량(대체)

+

0

-
-
-

근태 상세 내역

-
- - +
+ - - - - - - - - - + + + + + + + + + - - + + - - - - + + + + - - - + + + - + - - @@ -291,12 +386,131 @@
구분시작일종료일사번성명사용(일)사용(H)발생(일)발생(H)구분시작일종료일사번성명사용(일)사용(H)발생(일)발생(H)내용#내용#잔량(일)잔량(H)전일(일)전일(H)잔량(일)잔량(H)전일(일)전일(H)소스등록자등록일소스등록자등록일