feat: 품목정보 상세 패널 추가 및 프로젝트/근태/권한 기능 확장

- Items: 우측에 이미지, 담당자, 입고/발주내역 패널 추가 (fItems 윈폼 동일)
- Project: 목록 및 상세 다이얼로그 구현
- Kuntae: 오류검사/수정 기능 추가
- UserAuth: 사용자 권한 관리 페이지 추가
- UserGroup: 그룹정보 다이얼로그로 전환
- Header: 사용자 메뉴 서브메뉴 방향 수정, 즐겨찾기 기능
- Backend API: Items 상세/담당자/구매내역, 근태 오류검사, 프로젝트 목록 등

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
backuppc
2025-11-28 17:36:20 +09:00
parent c9b5d756e1
commit adcdc40169
32 changed files with 6668 additions and 292 deletions

View File

@@ -228,6 +228,50 @@ namespace Project.Web
}
}
/// <summary>
/// 즐겨찾기 목록 조회 (grp=17)
/// memo가 표시명, svalue가 URL
/// </summary>
public string Favorite_GetList()
{
try
{
var sql = "select isnull(code,'') as code, isnull(memo,'') as name, isnull(svalue,'') as url " +
"from common WITH (nolock) " +
"where gcode = @gcode and grp = '17' and isnull(code,'') <> '' " +
"order by code";
var cs = Properties.Settings.Default.gwcs;
var cn = new SqlConnection(cs);
var cmd = new SqlCommand(sql, cn);
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
var da = new SqlDataAdapter(cmd);
var dt = new DataTable();
da.Fill(dt);
da.Dispose();
cmd.Dispose();
cn.Dispose();
var result = new System.Collections.Generic.List<object>();
foreach (DataRow dr in dt.Rows)
{
result.Add(new
{
name = dr["name"]?.ToString() ?? "",
url = dr["url"]?.ToString() ?? ""
});
}
return JsonConvert.SerializeObject(new { Success = true, Data = result });
}
catch (Exception ex)
{
Console.WriteLine($"Favorite_GetList 오류: {ex.Message}");
return JsonConvert.SerializeObject(new { Success = false, Data = new object[] { }, Message = ex.Message });
}
}
#endregion
#region Items API
@@ -421,6 +465,349 @@ namespace Project.Web
}
}
/// <summary>
/// 품목 이미지 조회 (Base64 반환)
/// </summary>
public string Items_GetImage(int idx)
{
try
{
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand("SELECT image FROM Items WHERE idx = @idx AND gcode = @gcode", cn))
{
cmd.Parameters.AddWithValue("@idx", idx);
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cn.Open();
var data = cmd.ExecuteScalar() as byte[];
if (data != null && data.Length > 0)
{
var base64 = Convert.ToBase64String(data);
return JsonConvert.SerializeObject(new { Success = true, Data = base64 });
}
return JsonConvert.SerializeObject(new { Success = true, Data = (string)null });
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "이미지 조회 실패: " + ex.Message });
}
}
/// <summary>
/// 품목 이미지 저장 (Base64 입력)
/// </summary>
public string Items_SaveImage(int idx, string base64Image)
{
try
{
byte[] imageData = null;
if (!string.IsNullOrEmpty(base64Image))
{
// data:image/png;base64, 형식 제거
if (base64Image.Contains(","))
{
base64Image = base64Image.Substring(base64Image.IndexOf(",") + 1);
}
imageData = Convert.FromBase64String(base64Image);
// 이미지 크기 조정 (640x480 제한, WinForms과 동일)
using (var ms = new System.IO.MemoryStream(imageData))
using (var img = System.Drawing.Image.FromStream(ms))
{
System.Drawing.Image resized = img;
bool needResize = false;
if (img.Width > 640)
{
var newRate = 640.0 / img.Width;
var newHeight = (int)(img.Height * newRate);
resized = new System.Drawing.Bitmap(640, newHeight);
using (var g = System.Drawing.Graphics.FromImage(resized))
{
g.DrawImage(img, new System.Drawing.Rectangle(0, 0, 640, newHeight));
}
needResize = true;
}
else if (img.Height > 480)
{
var newRate = 480.0 / img.Height;
var newWidth = (int)(img.Width * newRate);
resized = new System.Drawing.Bitmap(newWidth, 480);
using (var g = System.Drawing.Graphics.FromImage(resized))
{
g.DrawImage(img, new System.Drawing.Rectangle(0, 0, newWidth, 480));
}
needResize = true;
}
using (var outMs = new System.IO.MemoryStream())
{
resized.Save(outMs, System.Drawing.Imaging.ImageFormat.Jpeg);
imageData = outMs.ToArray();
}
if (needResize)
{
resized.Dispose();
}
}
}
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand("UPDATE Items SET image = @image, wuid = @wuid, wdate = GETDATE() WHERE idx = @idx AND gcode = @gcode", cn))
{
cmd.Parameters.AddWithValue("@idx", idx);
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@wuid", info.Login.no);
if (imageData != null)
{
cmd.Parameters.Add("@image", SqlDbType.VarBinary, -1).Value = imageData;
}
else
{
cmd.Parameters.Add("@image", SqlDbType.VarBinary, -1).Value = DBNull.Value;
}
cn.Open();
var result = cmd.ExecuteNonQuery();
return JsonConvert.SerializeObject(new { Success = result > 0, Message = result > 0 ? "이미지가 저장되었습니다." : "이미지 저장에 실패했습니다." });
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "이미지 저장 실패: " + ex.Message });
}
}
/// <summary>
/// 품목 이미지 삭제
/// </summary>
public string Items_DeleteImage(int idx)
{
return Items_SaveImage(idx, null);
}
/// <summary>
/// 품목의 공급처 담당자 조회
/// </summary>
public string Items_GetSupplierStaff(int supplyIdx)
{
try
{
if (supplyIdx <= 0)
{
return JsonConvert.SerializeObject(new { Success = true, Data = new object[] { } });
}
var sql = @"SELECT idx, name, grade, dept, tel, email, memo
FROM Staff WITH (NOLOCK)
WHERE gcode = @gcode AND cid = @cid";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@cid", supplyIdx);
var da = new SqlDataAdapter(cmd);
var dt = new DataTable();
da.Fill(dt);
var result = new System.Collections.Generic.List<object>();
foreach (DataRow dr in dt.Rows)
{
var name = dr["name"]?.ToString() ?? "";
var grade = dr["grade"]?.ToString() ?? "";
if (!string.IsNullOrEmpty(grade))
{
name += $"({grade})";
}
result.Add(new
{
idx = Convert.ToInt32(dr["idx"]),
name = name,
tel = dr["tel"]?.ToString() ?? "",
email = dr["email"]?.ToString() ?? "",
dept = dr["dept"]?.ToString() ?? ""
});
}
return JsonConvert.SerializeObject(new { Success = true, Data = result });
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "담당자 조회 실패: " + ex.Message });
}
}
/// <summary>
/// 품목의 최근 입고내역 조회 (indate 기준)
/// </summary>
public string Items_GetIncomingHistory(int itemIdx)
{
try
{
var sql = @"SELECT TOP 10 idx, indate, request, pumqty, pumprice, state
FROM Purchase WITH (NOLOCK)
WHERE pumidx = @pumidx
AND ISNULL(indate, '') <> ''
AND ISNULL(isdel, 0) = 0
ORDER BY indate DESC";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@pumidx", itemIdx);
var da = new SqlDataAdapter(cmd);
var dt = new DataTable();
da.Fill(dt);
var result = new System.Collections.Generic.List<object>();
foreach (DataRow dr in dt.Rows)
{
var date = dr["indate"]?.ToString() ?? "";
// 년도 2자리로 표시 (2024-01-01 -> 24-01-01)
if (date.Length > 9) date = date.Substring(2);
result.Add(new
{
idx = Convert.ToInt32(dr["idx"]),
date = date,
request = dr["request"]?.ToString() ?? "",
qty = dr["pumqty"] == DBNull.Value ? 0 : Convert.ToInt32(dr["pumqty"]),
price = dr["pumprice"] == DBNull.Value ? 0m : Convert.ToDecimal(dr["pumprice"]),
state = dr["state"]?.ToString() ?? ""
});
}
return JsonConvert.SerializeObject(new { Success = true, Data = result });
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "입고내역 조회 실패: " + ex.Message });
}
}
/// <summary>
/// 품목의 발주내역 조회 (pdate 기준)
/// </summary>
public string Items_GetOrderHistory(int itemIdx)
{
try
{
var sql = @"SELECT TOP 10 idx, pdate, request, pumqty, pumprice, state
FROM Purchase WITH (NOLOCK)
WHERE pumidx = @pumidx
AND state <> 'Cancled'
AND ISNULL(isdel, 0) = 0
ORDER BY pdate DESC";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@pumidx", itemIdx);
var da = new SqlDataAdapter(cmd);
var dt = new DataTable();
da.Fill(dt);
var result = new System.Collections.Generic.List<object>();
foreach (DataRow dr in dt.Rows)
{
var date = dr["pdate"]?.ToString() ?? "";
// 년도 2자리로 표시 (2024-01-01 -> 24-01-01)
if (date.Length > 9) date = date.Substring(2);
result.Add(new
{
idx = Convert.ToInt32(dr["idx"]),
date = date,
request = dr["request"]?.ToString() ?? "",
qty = dr["pumqty"] == DBNull.Value ? 0 : Convert.ToInt32(dr["pumqty"]),
price = dr["pumprice"] == DBNull.Value ? 0m : Convert.ToDecimal(dr["pumprice"]),
state = dr["state"]?.ToString() ?? ""
});
}
return JsonConvert.SerializeObject(new { Success = true, Data = result });
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "발주내역 조회 실패: " + ex.Message });
}
}
/// <summary>
/// 품목 상세 정보 조회 (supplyidx 포함)
/// </summary>
public string Items_GetDetail(int idx)
{
try
{
var sql = @"SELECT idx, sid, cate, name, model, scale, unit, price, supply, supplyidx, manu, storage, disable, memo
FROM Items WITH (NOLOCK)
WHERE idx = @idx AND gcode = @gcode";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@idx", idx);
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cn.Open();
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
var item = new
{
idx = reader.GetInt32(reader.GetOrdinal("idx")),
sid = reader["sid"]?.ToString() ?? "",
cate = reader["cate"]?.ToString() ?? "",
name = reader["name"]?.ToString() ?? "",
model = reader["model"]?.ToString() ?? "",
scale = reader["scale"]?.ToString() ?? "",
unit = reader["unit"]?.ToString() ?? "",
price = reader["price"] == DBNull.Value ? 0m : Convert.ToDecimal(reader["price"]),
supply = reader["supply"]?.ToString() ?? "",
supplyidx = reader["supplyidx"] == DBNull.Value ? -1 : Convert.ToInt32(reader["supplyidx"]),
manu = reader["manu"]?.ToString() ?? "",
storage = reader["storage"]?.ToString() ?? "",
disable = reader["disable"] != DBNull.Value && Convert.ToBoolean(reader["disable"]),
memo = reader["memo"]?.ToString() ?? ""
};
return JsonConvert.SerializeObject(new { Success = true, Data = item });
}
else
{
return JsonConvert.SerializeObject(new { Success = false, Message = "품목을 찾을 수 없습니다." });
}
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "품목 상세 조회 실패: " + ex.Message });
}
}
#endregion
}
}

View File

@@ -93,16 +93,19 @@ namespace Project.Web
}
/// <summary>
/// 업무일지 상세 조회 (vJobReportForUser 뷰 사용)
/// 업무일지 상세 조회 (vJobReportForUser 뷰 + JobReport 테이블 조인)
/// </summary>
public string Jobreport_GetDetail(int id)
{
try
{
var sql = @"SELECT idx, pidx, pdate, id, name, type, svalue, hrs, ot, requestpart, package,
userprocess, status, projectName, description, ww, otpms, process
FROM vJobReportForUser WITH (nolock)
WHERE idx = @idx AND gcode = @gcode";
// 뷰에서 기본 정보 조회, 원본 테이블에서 jobgrp, tag 추가 조회
var sql = @"SELECT v.idx, v.pidx, v.pdate, v.id, v.name, v.type, v.svalue, v.hrs, v.ot,
v.requestpart, v.package, v.userprocess, v.status, v.projectName, v.description,
v.ww, v.otpms, v.process, j.jobgrp, j.tag
FROM vJobReportForUser v WITH (nolock)
INNER JOIN JobReport j WITH (nolock) ON v.idx = j.idx
WHERE v.idx = @idx AND v.gcode = @gcode";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
@@ -137,7 +140,7 @@ namespace Project.Web
/// <summary>
/// 업무일지 추가 (JobReport 테이블)
/// </summary>
public string Jobreport_Add(string pdate, string projectName, string requestpart, string package,
public string Jobreport_Add(string pdate, string projectName, int pidx, string requestpart, string package,
string type, string process, string status, string description, double hrs, double ot, string jobgrp, string tag)
{
try
@@ -152,7 +155,7 @@ namespace Project.Web
var sql = @"INSERT INTO JobReport (gcode, uid, pdate, projectName, requestpart, package,
type, process, status, description, hrs, ot, jobgrp, tag, wuid, wdate, pidx)
VALUES (@gcode, @uid, @pdate, @projectName, @requestpart, @package,
@type, @process, @status, @description, @hrs, @ot, @jobgrp, @tag, @wuid, GETDATE(), -1);
@type, @process, @status, @description, @hrs, @ot, @jobgrp, @tag, @wuid, GETDATE(), @pidx);
SELECT SCOPE_IDENTITY();";
var cs = Properties.Settings.Default.gwcs;
@@ -163,6 +166,7 @@ namespace Project.Web
cmd.Parameters.AddWithValue("@uid", info.Login.no);
cmd.Parameters.AddWithValue("@pdate", pdate);
cmd.Parameters.AddWithValue("@projectName", projectName ?? "");
cmd.Parameters.AddWithValue("@pidx", pidx);
cmd.Parameters.AddWithValue("@requestpart", requestpart ?? "");
cmd.Parameters.AddWithValue("@package", package ?? "");
cmd.Parameters.AddWithValue("@type", type ?? "");
@@ -189,7 +193,7 @@ namespace Project.Web
/// <summary>
/// 업무일지 수정 (JobReport 테이블)
/// </summary>
public string Jobreport_Edit(int idx, string pdate, string projectName, string requestpart, string package,
public string Jobreport_Edit(int idx, string pdate, string projectName, int pidx, string requestpart, string package,
string type, string process, string status, string description, double hrs, double ot, string jobgrp, string tag)
{
try
@@ -224,7 +228,7 @@ namespace Project.Web
}
var sql = @"UPDATE JobReport SET
pdate = @pdate, projectName = @projectName, requestpart = @requestpart,
pdate = @pdate, projectName = @projectName, pidx = @pidx, requestpart = @requestpart,
package = @package, type = @type, process = @process, status = @status,
description = @description, hrs = @hrs, ot = @ot, jobgrp = @jobgrp, tag = @tag,
wuid = @wuid, wdate = GETDATE()
@@ -238,6 +242,7 @@ namespace Project.Web
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@pdate", pdate);
cmd.Parameters.AddWithValue("@projectName", projectName ?? "");
cmd.Parameters.AddWithValue("@pidx", pidx);
cmd.Parameters.AddWithValue("@requestpart", requestpart ?? "");
cmd.Parameters.AddWithValue("@package", package ?? "");
cmd.Parameters.AddWithValue("@type", type ?? "");

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using Newtonsoft.Json;
using FCOMMON;
@@ -11,6 +12,33 @@ namespace Project.Web
{
#region Kuntae API
#region
public class KuntaeErrorCheckResult
{
public string Date { get; set; }
public string Gubun { get; set; }
public string OccurDay { get; set; }
public string OccurTime { get; set; }
public string UseDay { get; set; }
public string UseTime { get; set; }
public string CateError { get; set; }
public bool IsError { get; set; }
public bool IsMagam { get; set; }
}
public class KuntaeErrorCheckProgress
{
public string CurrentDate { get; set; }
public double JobreportOT { get; set; }
public double HolidayRequestDay { get; set; }
public double HolidayRequestTime { get; set; }
public double KuntaeCRDay { get; set; }
public double KuntaeCRTime { get; set; }
public double KuntaeDRDay { get; set; }
public double KuntaeDRTime { get; set; }
}
#endregion
/// <summary>
/// 근태 목록 조회
/// </summary>
@@ -90,6 +118,350 @@ namespace Project.Web
}
}
/// <summary>
/// 근태 오류 검사 실행
/// </summary>
public string Kuntae_ErrorCheck(string sd, string ed)
{
try
{
var startDate = DateTime.Parse(sd);
var endDate = DateTime.Parse(ed);
var gcode = info.Login.gcode;
var uid = info.Login.no;
var okList = new List<KuntaeErrorCheckResult>();
var ngList = new List<KuntaeErrorCheckResult>();
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
{
cn.Open();
using (var cmd = new SqlCommand("", cn))
{
cmd.Parameters.Add("@gcode", SqlDbType.VarChar).Value = gcode;
cmd.Parameters.Add("@uid", SqlDbType.VarChar).Value = uid;
var idx = 0;
while (true)
{
var currentDate = startDate.AddDays(idx++);
if (currentDate > endDate) break;
var pdate = currentDate.ToString("yyyy-MM-dd");
var result = CheckDateError(cmd, pdate, gcode);
if (result.IsError)
ngList.Add(result);
else
okList.Add(result);
}
}
}
return JsonConvert.SerializeObject(new {
Success = true,
OkList = okList,
NgList = ngList
});
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 특정 날짜의 오류 검사
/// </summary>
private KuntaeErrorCheckResult CheckDateError(SqlCommand cmd, string pdate, string gcode)
{
var result = new KuntaeErrorCheckResult
{
Date = pdate,
Gubun = "입력/생성",
IsError = false,
IsMagam = false
};
// 1. 업무일지 OT2 합계 (발생시간)
cmd.CommandText = $"SELECT SUM(ISNULL(ot2,0)) FROM jobreport WHERE gcode = @gcode AND pdate='{pdate}' AND ISNULL(ot,0) > 0 AND ISNULL(ot2,0) > 0";
var jobreportOT = 0.0;
var objJobreport = cmd.ExecuteScalar();
if (objJobreport != null && objJobreport != DBNull.Value)
jobreportOT = Convert.ToDouble(objJobreport);
// 2. 휴가신청 확인 (승인된 것만)
cmd.CommandText = $"SELECT cate, SUM(HolyDays), SUM(HolyTimes) FROM EETGW_HolydayRequest WHERE gcode = @gcode AND sdate = '{pdate}' AND ISNULL(conf,0) = 1 GROUP BY cate";
var holidayDay = 0.0;
var holidayTime = 0.0;
var cateListD = new Dictionary<string, double>();
var cateListT = new Dictionary<string, double>();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var cate = reader[0].ToString();
var vDay = reader[1] != DBNull.Value ? Convert.ToDouble(reader[1]) : 0.0;
var vTime = reader[2] != DBNull.Value ? Convert.ToDouble(reader[2]) : 0.0;
holidayDay += vDay;
holidayTime += vTime;
if (vDay != 0.0)
{
if (cateListD.ContainsKey(cate))
cateListD[cate] += vDay;
else
cateListD.Add(cate, vDay);
}
if (vTime != 0.0)
{
if (cateListT.ContainsKey(cate))
cateListT[cate] += vTime;
else
cateListT.Add(cate, vTime);
}
}
}
// 3. 근태입력자료 확인
cmd.CommandText = $@"SELECT cate, SUM(term), SUM(crtime), SUM(termdr), SUM(drtime), SUM(drtimepms)
FROM Holyday
WHERE gcode = @gcode AND sdate = '{pdate}' AND ISNULL(extidx,-1) <> -1
GROUP BY cate";
var kuntaeCRDay = 0.0;
var kuntaeCRTime = 0.0;
var kuntaeDRDay = 0.0;
var kuntaeDRTime = 0.0;
var dCRD = new Dictionary<string, double>();
var dCRT = new Dictionary<string, double>();
var dDRD = new Dictionary<string, double>();
var dDRT = new Dictionary<string, double>();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var cate = reader[0].ToString();
var vCRD = reader[1] != DBNull.Value ? Convert.ToDouble(reader[1]) : 0.0;
var vCRT = reader[2] != DBNull.Value ? Convert.ToDouble(reader[2]) : 0.0;
var vDRD = reader[3] != DBNull.Value ? Convert.ToDouble(reader[3]) : 0.0;
var vDRT = reader[4] != DBNull.Value ? Convert.ToDouble(reader[4]) : 0.0;
if (vCRD != 0.0)
{
if (dCRD.ContainsKey(cate)) dCRD[cate] += vCRD;
else dCRD.Add(cate, vCRD);
}
if (vCRT != 0.0)
{
if (dCRT.ContainsKey(cate)) dCRT[cate] += vCRT;
else dCRT.Add(cate, vCRT);
}
if (vDRD != 0.0)
{
if (dDRD.ContainsKey(cate)) dDRD[cate] += vDRD;
else dDRD.Add(cate, vDRD);
}
if (vDRT != 0.0)
{
if (dDRT.ContainsKey(cate)) dDRT[cate] += vDRT;
else dDRT.Add(cate, vDRT);
}
kuntaeCRDay += vCRD;
kuntaeCRTime += vCRT;
kuntaeDRDay += vDRD;
kuntaeDRTime += vDRT;
}
}
// 4. 카테고리별 데이터 확인
var sbCate = new StringBuilder();
var cateErr = false;
// 휴가신청(일) vs 근태입력(CR일)
foreach (var item in cateListD)
{
if (!dCRD.ContainsKey(item.Key))
{
sbCate.Append($"{item.Key}(X)");
cateErr = true;
break;
}
else if (dCRD[item.Key] != item.Value)
{
sbCate.Append($"{item.Key}({dCRD[item.Key]}|{item.Value})");
cateErr = true;
break;
}
}
if (!cateErr)
{
foreach (var item in cateListT)
{
if (!dCRT.ContainsKey(item.Key))
{
sbCate.Append($"{item.Key}(X)");
cateErr = true;
break;
}
else if (dCRT[item.Key] != item.Value)
{
sbCate.Append($"{item.Key}({dCRT[item.Key]}|{item.Value})");
cateErr = true;
break;
}
}
}
if (!cateErr)
{
foreach (var item in dCRD)
{
if (item.Key.Equals("대체")) continue;
if (!cateListD.ContainsKey(item.Key))
{
sbCate.Append($"{item.Key}(X)");
cateErr = true;
break;
}
else if (cateListD[item.Key] != item.Value)
{
sbCate.Append($"{item.Key}({cateListD[item.Key]}|{item.Value})");
cateErr = true;
break;
}
}
}
if (!cateErr)
{
foreach (var item in dCRT)
{
if (item.Key.Equals("대체")) continue;
if (!cateListT.ContainsKey(item.Key))
{
sbCate.Append($"{item.Key}(X)");
cateErr = true;
break;
}
else if (cateListT[item.Key] != item.Value)
{
sbCate.Append($"{item.Key}({cateListT[item.Key]}|{item.Value})");
cateErr = true;
break;
}
}
}
// 5. 결과 생성
result.OccurDay = $"--/{kuntaeDRDay}";
result.OccurTime = $"{jobreportOT}/{kuntaeDRTime}";
result.UseDay = $"{holidayDay}/{kuntaeCRDay}";
result.UseTime = $"{holidayTime}/{kuntaeCRTime}";
result.CateError = sbCate.ToString();
// 오류 여부 판단
if (jobreportOT != kuntaeDRTime) result.IsError = true;
if (holidayDay != kuntaeCRDay) result.IsError = true;
if (holidayTime != kuntaeCRTime) result.IsError = true;
if (cateErr) result.IsError = true;
// 마감 여부 확인
if (result.IsError)
{
result.IsMagam = DBM.GetMagamStatus(pdate.Substring(0, 7));
}
return result;
}
/// <summary>
/// 근태 오류 수정 (재생성)
/// </summary>
public string Kuntae_FixError(string pdate)
{
try
{
var gcode = info.Login.gcode;
var uid = info.Login.no;
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
{
cn.Open();
using (var cmd = new SqlCommand("", cn))
{
cmd.Parameters.Add("@gcode", SqlDbType.VarChar).Value = gcode;
cmd.Parameters.Add("@uid", SqlDbType.VarChar).Value = uid;
cmd.Parameters.Add("@pdate", SqlDbType.VarChar).Value = pdate;
// 1. 근태-업무일지자료 삭제
cmd.CommandText = "DELETE FROM Holyday WHERE gcode = @gcode AND extcate = 'HO' AND sdate = @pdate AND ISNULL(extidx,-1) <> -1";
var cnt1 = cmd.ExecuteNonQuery();
// 2. 근태-업무일지자료 생성
cmd.CommandText = @"INSERT INTO Holyday(gcode, cate, sdate, edate, term, crtime, termdr, DrTime, contents, [uid], wdate, wuid, extcate, extidx)
SELECT gcode, '대체', pdate, pdate, 0, 0, 0, ISNULL(ot2,0), projectname, uid, GETDATE(), @uid + '-ERR', 'HO', idx
FROM jobreport
WHERE gcode = @gcode AND pdate = @pdate AND ISNULL(ot2,0) > 0 AND ISNULL(ot,0) > 0";
var cnt2 = cmd.ExecuteNonQuery();
// 3. 근태-휴가신청자료 삭제
cmd.CommandText = "DELETE FROM Holyday WHERE gcode = @gcode AND extcate = '휴가' AND sdate = @pdate AND ISNULL(extidx,-1) <> -1";
var cnt3 = cmd.ExecuteNonQuery();
// 4. 근태-휴가신청자료 생성 (승인완료된 자료 대상)
cmd.CommandText = @"INSERT INTO Holyday(gcode, cate, sdate, edate, term, crtime, termdr, DrTime, contents, [uid], wdate, wuid, extcate, extidx)
SELECT gcode, cate, sdate, edate, ISNULL(holydays,0), ISNULL(holytimes,0), 0, 0, HolyReason, uid, GETDATE(), @uid + '-ERR', '휴가', idx
FROM EETGW_HolydayRequest
WHERE gcode = @gcode AND sdate = @pdate AND ISNULL(conf,0) = 1";
var cnt4 = cmd.ExecuteNonQuery();
return JsonConvert.SerializeObject(new {
Success = true,
Message = $"{pdate} 재생성 완료 (삭제: {cnt1 + cnt3}건, 생성: {cnt2 + cnt4}건)"
});
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 여러 날짜 오류 일괄 수정
/// </summary>
public string Kuntae_FixErrors(string dates)
{
try
{
var dateList = JsonConvert.DeserializeObject<List<string>>(dates);
var results = new List<object>();
foreach (var date in dateList)
{
var resultJson = Kuntae_FixError(date);
var resultObj = JsonConvert.DeserializeObject<dynamic>(resultJson);
results.Add(new { Date = date, Success = (bool)resultObj.Success, Message = (string)resultObj.Message });
}
return JsonConvert.SerializeObject(new { Success = true, Results = results });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
#endregion
}
}

View File

@@ -206,5 +206,431 @@ namespace Project.Web
}
#endregion
#region Project Search API ()
/// <summary>
/// 업무일지용 프로젝트 검색 (Projects 테이블 + 과거 업무일지 항목명)
/// </summary>
public string Project_Search(string keyword)
{
try
{
var cs = Properties.Settings.Default.gwcs;
var result = new List<object>();
// 1. Projects 테이블에서 검색
var sqlProjects = @"SELECT idx, name,
ISNULL(userManager,'') as userManager,
ISNULL(userMain,'') as userMain,
ISNULL(status,'') as status
FROM Projects WITH (nolock)
WHERE gcode = @gcode
AND (name LIKE @keyword OR CAST(idx AS VARCHAR) LIKE @keyword)
AND status NOT IN ('보류', '취소', '완료(보고)')
ORDER BY status DESC, pdate DESC, name";
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sqlProjects, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@keyword", "%" + (keyword ?? "") + "%");
using (var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
foreach (DataRow row in dt.Rows)
{
result.Add(new
{
idx = Convert.ToInt32(row["idx"]),
name = row["name"]?.ToString() ?? "",
userManager = row["userManager"]?.ToString() ?? "",
userMain = row["userMain"]?.ToString() ?? "",
status = row["status"]?.ToString() ?? "",
source = "project"
});
}
}
}
// 2. 과거 업무일지 항목명에서 검색 (프로젝트에 없는 항목들)
var sqlJobItems = @"SELECT TOP 50
MAX(pdate) as lastDate,
projectName,
ISNULL(MAX(pidx), -1) as pidx
FROM JobReport WITH (nolock)
WHERE gcode = @gcode
AND projectName LIKE @keyword
AND projectName IS NOT NULL
AND projectName <> ''
GROUP BY projectName
ORDER BY MAX(pdate) DESC";
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sqlJobItems, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@keyword", "%" + (keyword ?? "") + "%");
using (var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
foreach (DataRow row in dt.Rows)
{
var pidx = row["pidx"] != DBNull.Value ? Convert.ToInt32(row["pidx"]) : -1;
var projectName = row["projectName"]?.ToString() ?? "";
// 이미 Projects에서 가져온 항목과 중복 체크
if (!result.Exists(r => ((dynamic)r).name == projectName))
{
result.Add(new
{
idx = pidx,
name = projectName,
userManager = "",
userMain = "",
status = "",
source = "jobreport",
lastDate = row["lastDate"] != DBNull.Value
? Convert.ToDateTime(row["lastDate"]).ToString("yyyy-MM-dd")
: ""
});
}
}
}
}
return JsonConvert.SerializeObject(new { Success = true, Data = result });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 현재 사용자의 프로젝트 목록 (업무일지 콤보박스용)
/// </summary>
public string Project_GetUserProjects()
{
try
{
var cs = Properties.Settings.Default.gwcs;
var userName = info.Login.no;
var sql = @"SELECT idx, name, ISNULL(status,'') as status
FROM Projects WITH (nolock)
WHERE gcode = @gcode
AND (ISNULL(userManager,'') LIKE @userName
OR ISNULL(userMain,'') LIKE @userName
OR ISNULL(usersub,'') LIKE @userName)
AND status NOT IN ('보류', '취소', '완료(보고)')
ORDER BY status DESC, pdate DESC, name";
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@userName", "%" + userName + "%");
using (var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
return JsonConvert.SerializeObject(new { Success = true, Data = dt });
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
#endregion
#region Project List API (fProjectList )
/// <summary>
/// 프로젝트 분류(category) 목록 조회
/// </summary>
public string Project_GetCategories()
{
try
{
var sql = @"SELECT category FROM projects WITH (nolock)
WHERE gcode = @gcode AND ISNULL(category,'') <> ''
GROUP BY category ORDER BY category";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
var result = new List<string> { "--전체--" };
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
result.Add(rdr[0]?.ToString() ?? "");
}
}
return JsonConvert.SerializeObject(new { Success = true, Data = result });
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 프로젝트 공정(userprocess) 목록 조회
/// </summary>
public string Project_GetProcesses()
{
try
{
var sql = @"SELECT userprocess FROM projects WITH (nolock)
WHERE gcode = @gcode AND ISNULL(userprocess,'') <> ''
GROUP BY userprocess ORDER BY userprocess";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
var result = new List<string> { "전체" };
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
result.Add(rdr[0]?.ToString() ?? "");
}
}
return JsonConvert.SerializeObject(new { Success = true, Data = result });
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 프로젝트 목록 조회 (fProjectList 화면용)
/// </summary>
public string Project_GetList(string statusFilter, string category, string process, string userFilter, string yearStart, string yearEnd, string dateType)
{
try
{
var sql = @"SELECT idx, pidx, status, asset, [level], rev,
[process], part, pdate, [name], userManager, usermain, usersub, userhw2, reqstaff,
costo, costn, cnt, remark_req, remark_ans, sdate, ddate, edate, odate, progress,
bmajoritem, memo, wuid, wdate, orderno, crdue, import, [path], userprocess,
bCost, bFanOut, bHighlight, div, model, serial,
championid, designid, epanelid, softwareid,
effect_tangible, effect_intangible,
dbo.getUserName2(championid, usermanager) as name_champion,
dbo.getUserName2(designid, usermain) as name_design,
dbo.getUserName2(epanelid, userhw2) as name_epanel,
dbo.getUserName2(softwareid, usersub) as name_software,
category, ReqLine, ReqSite, ReqPackage, ReqPlant, pno, kdate, jasmin, sfi,
(SELECT MAX(pdate) FROM ProjectsHistory WHERE pidx = Projects.idx) as lasthistory_date,
dbo.getLastProjectScheduleNo(gcode, idx) as lastSchNo,
cramount, panelimage, Priority, sfi_count,
dbo.getScheduleProgress(idx) as ProgressPrj,
dbo.getProjectFinishRate(gcode, idx) AS finishrate
FROM Projects WITH (nolock)
WHERE gcode = @gcode AND ISNULL(div,'') <> 'EB' AND ISNULL(isdel,0) = 0";
var parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("@gcode", info.Login.gcode));
// 상태 필터
if (!string.IsNullOrEmpty(statusFilter) && statusFilter != "all")
{
var statuses = statusFilter.Split(',');
var statusParams = new List<string>();
for (int i = 0; i < statuses.Length; i++)
{
var paramName = "@status" + i;
statusParams.Add(paramName);
parameters.Add(new SqlParameter(paramName, statuses[i].Trim()));
}
sql += " AND status IN (" + string.Join(",", statusParams) + ")";
}
// 분류 필터
if (!string.IsNullOrEmpty(category) && category != "--전체--")
{
sql += " AND ISNULL(category,'') LIKE @category";
parameters.Add(new SqlParameter("@category", category + "%"));
}
// 공정 필터
if (!string.IsNullOrEmpty(process) && process != "전체")
{
sql += " AND ISNULL(userprocess,'') = @process";
parameters.Add(new SqlParameter("@process", process));
}
// 사용자 필터
if (!string.IsNullOrEmpty(userFilter))
{
sql += @" AND (ISNULL(userManager,'') LIKE @userFilter
OR ISNULL(usermain,'') LIKE @userFilter
OR ISNULL(reqstaff,'') LIKE @userFilter
OR ISNULL(usersub,'') LIKE @userFilter
OR dbo.getUserName(championid) LIKE @userFilter
OR dbo.getUserName(designid) LIKE @userFilter
OR dbo.getUserName(epanelid) LIKE @userFilter
OR dbo.getUserName(softwareid) LIKE @userFilter)";
parameters.Add(new SqlParameter("@userFilter", "%" + userFilter + "%"));
}
// 날짜 필터
if (!string.IsNullOrEmpty(dateType) && dateType != "0" && !string.IsNullOrEmpty(yearStart))
{
string dateField = "sdate";
switch (dateType)
{
case "1": dateField = "sdate"; break;
case "2": dateField = "ddate"; break;
case "3": dateField = "edate"; break;
case "4": dateField = "odate"; break;
}
sql += $" AND {dateField} BETWEEN @dateStart AND @dateEnd";
parameters.Add(new SqlParameter("@dateStart", yearStart + "-01-01"));
parameters.Add(new SqlParameter("@dateEnd", (string.IsNullOrEmpty(yearEnd) ? yearStart : yearEnd) + "-12-31"));
}
// 정렬
sql += @" ORDER BY (CASE
WHEN status = '진행' THEN '0'
WHEN status = '검토' THEN '1'
WHEN status = '대기' THEN '2'
WHEN status = '완료' THEN '3'
WHEN status = '완료(보고)' THEN '4'
WHEN status = '보류' THEN '5'
WHEN status = '취소' THEN '9'
ELSE '5' END), userManager, sdate";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddRange(parameters.ToArray());
using (var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
// 상태별 건수 집계
var statusCounts = new Dictionary<string, int>
{
{ "검토", 0 }, { "진행", 0 }, { "대기", 0 },
{ "보류", 0 }, { "완료", 0 }, { "완료(보고)", 0 }, { "취소", 0 }
};
decimal sumCosto = 0, sumCostn = 0;
foreach (DataRow row in dt.Rows)
{
var st = row["status"]?.ToString() ?? "";
if (statusCounts.ContainsKey(st))
statusCounts[st]++;
if (row["costo"] != DBNull.Value) sumCosto += Convert.ToDecimal(row["costo"]);
if (row["costn"] != DBNull.Value) sumCostn += Convert.ToDecimal(row["costn"]);
}
return JsonConvert.SerializeObject(new
{
Success = true,
Data = dt,
StatusCounts = statusCounts,
TotalCosto = sumCosto,
TotalCostn = sumCostn,
CurrentUser = info.Login.nameK
}, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 프로젝트 히스토리 조회
/// </summary>
public string Project_GetHistory(int projectIdx)
{
try
{
var sql = @"SELECT idx, pidx, pdate, progress, remark, wuid, wdate,
dbo.getUserName(wuid) as wname
FROM ProjectsHistory WITH (nolock)
WHERE pidx = @pidx
ORDER BY pdate DESC, idx DESC";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@pidx", projectIdx);
using (var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
return JsonConvert.SerializeObject(new { Success = true, Data = dt });
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 프로젝트 일일 메모 조회
/// </summary>
public string Project_GetDailyMemo(int projectIdx)
{
try
{
var sql = @"SELECT idx, pidx, pdate, remark, wuid, wdate,
dbo.getUserName(wuid) as wname
FROM EETGW_ProjecthistoryD WITH (nolock)
WHERE pidx = @pidx
ORDER BY pdate DESC, idx DESC";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@pidx", projectIdx);
using (var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
return JsonConvert.SerializeObject(new { Success = true, Data = dt });
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
#endregion
}
}

View File

@@ -0,0 +1,339 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using Newtonsoft.Json;
using FCOMMON;
namespace Project.Web
{
public partial class MachineBridge
{
#region UserAuth API ( )
/// <summary>
/// 사용자 권한 접근 가능 여부 확인 (Level 5 이상 또는 account 권한 5 이상)
/// </summary>
public string UserAuth_CanAccess()
{
try
{
int curLevel = Math.Max(info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.account));
bool canAccess = curLevel >= 5;
return JsonConvert.SerializeObject(new
{
Success = true,
CanAccess = canAccess,
Level = curLevel,
Message = canAccess ? "" : "(관리자/계정담당자) 전용 메뉴 입니다"
});
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 사용자 권한 목록 조회
/// </summary>
public string UserAuth_GetList()
{
try
{
var sql = @"SELECT idx, [user], gcode, account, purchase, purchaseEB, holyday,
project, jobreport, scheapp, equipment, otconfirm, holyreq, kuntae
FROM Auth WITH (nolock)
WHERE gcode = @gcode
ORDER BY [user]";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
using (var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
return JsonConvert.SerializeObject(new { Success = true, Data = dt });
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 사용자 권한 저장 (추가/수정)
/// </summary>
public string UserAuth_Save(int idx, string user, int account, int purchase, int purchaseEB,
int holyday, int project, int jobreport, int scheapp, int equipment, int otconfirm, int holyreq, int kuntae)
{
try
{
var cs = Properties.Settings.Default.gwcs;
if (idx == 0)
{
// 신규 추가
// 먼저 중복 확인
using (var cn = new SqlConnection(cs))
{
var checkSql = "SELECT COUNT(*) FROM Auth WHERE gcode = @gcode AND [user] = @user";
using (var cmd = new SqlCommand(checkSql, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@user", user ?? "");
cn.Open();
var count = (int)cmd.ExecuteScalar();
if (count > 0)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "이미 등록된 사용자입니다." });
}
}
}
var sql = @"INSERT INTO Auth (gcode, [user], account, purchase, purchaseEB, holyday,
project, jobreport, scheapp, equipment, otconfirm, holyreq, kuntae)
VALUES (@gcode, @user, @account, @purchase, @purchaseEB, @holyday,
@project, @jobreport, @scheapp, @equipment, @otconfirm, @holyreq, @kuntae);
SELECT SCOPE_IDENTITY();";
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@user", user ?? "");
cmd.Parameters.AddWithValue("@account", account);
cmd.Parameters.AddWithValue("@purchase", purchase);
cmd.Parameters.AddWithValue("@purchaseEB", purchaseEB);
cmd.Parameters.AddWithValue("@holyday", holyday);
cmd.Parameters.AddWithValue("@project", project);
cmd.Parameters.AddWithValue("@jobreport", jobreport);
cmd.Parameters.AddWithValue("@scheapp", scheapp);
cmd.Parameters.AddWithValue("@equipment", equipment);
cmd.Parameters.AddWithValue("@otconfirm", otconfirm);
cmd.Parameters.AddWithValue("@holyreq", holyreq);
cmd.Parameters.AddWithValue("@kuntae", kuntae);
cn.Open();
var newId = Convert.ToInt32(cmd.ExecuteScalar());
return JsonConvert.SerializeObject(new { Success = true, Message = "저장되었습니다.", Data = new { idx = newId } });
}
}
else
{
// 수정
var sql = @"UPDATE Auth SET
[user] = @user, account = @account, purchase = @purchase, purchaseEB = @purchaseEB,
holyday = @holyday, project = @project, jobreport = @jobreport, scheapp = @scheapp,
equipment = @equipment, otconfirm = @otconfirm, holyreq = @holyreq, kuntae = @kuntae
WHERE idx = @idx AND gcode = @gcode";
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@idx", idx);
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@user", user ?? "");
cmd.Parameters.AddWithValue("@account", account);
cmd.Parameters.AddWithValue("@purchase", purchase);
cmd.Parameters.AddWithValue("@purchaseEB", purchaseEB);
cmd.Parameters.AddWithValue("@holyday", holyday);
cmd.Parameters.AddWithValue("@project", project);
cmd.Parameters.AddWithValue("@jobreport", jobreport);
cmd.Parameters.AddWithValue("@scheapp", scheapp);
cmd.Parameters.AddWithValue("@equipment", equipment);
cmd.Parameters.AddWithValue("@otconfirm", otconfirm);
cmd.Parameters.AddWithValue("@holyreq", holyreq);
cmd.Parameters.AddWithValue("@kuntae", kuntae);
cn.Open();
var result = cmd.ExecuteNonQuery();
return JsonConvert.SerializeObject(new { Success = result > 0, Message = result > 0 ? "수정되었습니다." : "수정에 실패했습니다." });
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 사용자 권한 삭제
/// </summary>
public string UserAuth_Delete(int idx)
{
try
{
var sql = "DELETE FROM Auth WHERE idx = @idx AND gcode = @gcode";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@idx", idx);
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cn.Open();
var result = cmd.ExecuteNonQuery();
return JsonConvert.SerializeObject(new { Success = result > 0, Message = result > 0 ? "삭제되었습니다." : "삭제에 실패했습니다." });
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 권한 항목 정보 반환 (프론트엔드 표시용)
/// </summary>
public string UserAuth_GetFields()
{
var fields = new[]
{
new { field = "user", label = "사용자 ID", description = "권한을 설정할 사용자 ID" },
new { field = "account", label = "계정", description = "계정 관리 권한" },
new { field = "purchase", label = "구매", description = "구매 관리 권한" },
new { field = "purchaseEB", label = "구매(전자실)", description = "전자실 구매 권한" },
new { field = "holyday", label = "출근부", description = "출근부 관리 권한" },
new { field = "project", label = "프로젝트", description = "프로젝트 관리 권한" },
new { field = "jobreport", label = "업무일지", description = "업무일지 관리 권한" },
new { field = "scheapp", label = "스케쥴", description = "스케쥴 관리 권한" },
new { field = "equipment", label = "장비목록", description = "장비 목록 관리 권한" },
new { field = "otconfirm", label = "OT승인", description = "초과근무 승인 권한" },
new { field = "holyreq", label = "휴가요청", description = "휴가 요청 관리 권한" },
new { field = "kuntae", label = "근태", description = "근태 관리 권한" },
};
return JsonConvert.SerializeObject(new { Success = true, Data = fields });
}
/// <summary>
/// 범용 권한 체크 API
/// authType: purchase, holyday, project, jobreport, savecost, equipment, otconfirm, kuntae, holyreq, account, purchaseEB
/// requiredLevel: 필요한 최소 레벨 (기본값 5)
/// </summary>
public string CheckAuth(string authType, int requiredLevel = 5)
{
try
{
// 사용자 기본 레벨
int userLevel = info.Login.level;
// authType에 해당하는 권한 레벨 조회
int authLevel = 0;
if (!string.IsNullOrEmpty(authType))
{
if (Enum.TryParse<DBM.eAuthType>(authType, true, out var eType))
{
authLevel = DBM.getAuth(eType);
}
}
// 둘 중 높은 값 사용
int effectiveLevel = Math.Max(userLevel, authLevel);
bool canAccess = effectiveLevel >= requiredLevel;
return JsonConvert.SerializeObject(new
{
Success = true,
CanAccess = canAccess,
UserLevel = userLevel,
AuthLevel = authLevel,
EffectiveLevel = effectiveLevel,
RequiredLevel = requiredLevel,
AuthType = authType,
Message = canAccess ? "" : $"이 기능은 레벨 {requiredLevel} 이상 권한이 필요합니다."
});
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
/// <summary>
/// 현재 로그인한 사용자의 전체 권한 정보 조회
/// </summary>
public string GetMyAuth()
{
try
{
var sql = @"SELECT idx, [user], account, purchase, purchaseEB, holyday,
project, jobreport, scheapp, equipment, otconfirm, holyreq, kuntae
FROM Auth WITH (nolock)
WHERE gcode = @gcode AND [user] = @user";
var cs = Properties.Settings.Default.gwcs;
using (var cn = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@user", info.Login.no);
cn.Open();
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
return JsonConvert.SerializeObject(new
{
Success = true,
Data = new
{
UserLevel = info.Login.level,
account = reader["account"] != DBNull.Value ? (int)reader["account"] : 0,
purchase = reader["purchase"] != DBNull.Value ? (int)reader["purchase"] : 0,
purchaseEB = reader["purchaseEB"] != DBNull.Value ? (int)reader["purchaseEB"] : 0,
holyday = reader["holyday"] != DBNull.Value ? (int)reader["holyday"] : 0,
project = reader["project"] != DBNull.Value ? (int)reader["project"] : 0,
jobreport = reader["jobreport"] != DBNull.Value ? (int)reader["jobreport"] : 0,
scheapp = reader["scheapp"] != DBNull.Value ? (int)reader["scheapp"] : 0,
equipment = reader["equipment"] != DBNull.Value ? (int)reader["equipment"] : 0,
otconfirm = reader["otconfirm"] != DBNull.Value ? (int)reader["otconfirm"] : 0,
holyreq = reader["holyreq"] != DBNull.Value ? (int)reader["holyreq"] : 0,
kuntae = reader["kuntae"] != DBNull.Value ? (int)reader["kuntae"] : 0,
}
});
}
else
{
// Auth 테이블에 없는 경우 기본값 반환
return JsonConvert.SerializeObject(new
{
Success = true,
Data = new
{
UserLevel = info.Login.level,
account = 0,
purchase = 0,
purchaseEB = 0,
holyday = 0,
project = 0,
jobreport = 0,
scheapp = 0,
equipment = 0,
otconfirm = 0,
holyreq = 0,
kuntae = 0,
}
});
}
}
}
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
}
}
#endregion
}
}

View File

@@ -411,6 +411,14 @@ namespace Project.Web
}
break;
case "FAVORITE_GET_LIST":
{
string result = _bridge.Favorite_GetList();
var response = new { type = "FAVORITE_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== Items API =====
case "ITEMS_GET_CATEGORIES":
{
@@ -460,6 +468,70 @@ namespace Project.Web
}
break;
case "ITEMS_GET_IMAGE":
{
int idx = json.idx ?? 0;
string result = _bridge.Items_GetImage(idx);
var response = new { type = "ITEMS_IMAGE_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "ITEMS_SAVE_IMAGE":
{
int idx = json.idx ?? 0;
string base64Image = json.base64Image ?? "";
string result = _bridge.Items_SaveImage(idx, base64Image);
var response = new { type = "ITEMS_IMAGE_SAVED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "ITEMS_DELETE_IMAGE":
{
int idx = json.idx ?? 0;
string result = _bridge.Items_DeleteImage(idx);
var response = new { type = "ITEMS_IMAGE_DELETED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "ITEMS_GET_DETAIL":
{
int idx = json.idx ?? 0;
string result = _bridge.Items_GetDetail(idx);
var response = new { type = "ITEMS_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "ITEMS_GET_SUPPLIER_STAFF":
{
int supplyIdx = json.supplyIdx ?? 0;
string result = _bridge.Items_GetSupplierStaff(supplyIdx);
var response = new { type = "ITEMS_SUPPLIER_STAFF_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "ITEMS_GET_INCOMING_HISTORY":
{
int itemIdx = json.itemIdx ?? 0;
string result = _bridge.Items_GetIncomingHistory(itemIdx);
var response = new { type = "ITEMS_INCOMING_HISTORY_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "ITEMS_GET_ORDER_HISTORY":
{
int itemIdx = json.itemIdx ?? 0;
string result = _bridge.Items_GetOrderHistory(itemIdx);
var response = new { type = "ITEMS_ORDER_HISTORY_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== UserList API =====
case "USERLIST_GET_CURRENT_LEVEL":
{
@@ -563,9 +635,10 @@ namespace Project.Web
{
string pdate = json.pdate ?? "";
string projectName = json.projectName ?? "";
int pidx = json.pidx ?? -1;
string requestpart = json.requestpart ?? "";
string package = json.package ?? "";
string type1 = json.type ?? "";
string jobType = json.jobType ?? ""; // type -> jobType (WebSocket type 필드 충돌 방지)
string process = json.process ?? "";
string status = json.status ?? "진행 완료";
string description = json.description ?? "";
@@ -573,7 +646,7 @@ namespace Project.Web
double ot = json.ot ?? 0.0;
string jobgrp = json.jobgrp ?? "";
string tag = json.tag ?? "";
string result = _bridge.Jobreport_Add(pdate, projectName, requestpart, package, type1, process, status, description, hrs, ot, jobgrp, tag);
string result = _bridge.Jobreport_Add(pdate, projectName, pidx, requestpart, package, jobType, process, status, description, hrs, ot, jobgrp, tag);
var response = new { type = "JOBREPORT_ADDED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
@@ -584,9 +657,10 @@ namespace Project.Web
int idx = json.idx ?? 0;
string pdate = json.pdate ?? "";
string projectName = json.projectName ?? "";
int pidx = json.pidx ?? -1;
string requestpart = json.requestpart ?? "";
string package = json.package ?? "";
string type2 = json.type ?? "";
string jobType = json.jobType ?? ""; // type -> jobType (WebSocket type 필드 충돌 방지)
string process = json.process ?? "";
string status = json.status ?? "";
string description = json.description ?? "";
@@ -594,7 +668,7 @@ namespace Project.Web
double ot = json.ot ?? 0.0;
string jobgrp = json.jobgrp ?? "";
string tag = json.tag ?? "";
string result = _bridge.Jobreport_Edit(idx, pdate, projectName, requestpart, package, type2, process, status, description, hrs, ot, jobgrp, tag);
string result = _bridge.Jobreport_Edit(idx, pdate, projectName, pidx, requestpart, package, jobType, process, status, description, hrs, ot, jobgrp, tag);
var response = new { type = "JOBREPORT_EDITED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
@@ -635,6 +709,354 @@ namespace Project.Web
}
break;
// ===== Kuntae API =====
case "GET_KUNTAE_LIST":
{
string sd = json.sd ?? "";
string ed = json.ed ?? "";
string result = _bridge.Kuntae_GetList(sd, ed);
var response = new { type = "KUNTAE_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "DELETE_KUNTAE":
{
int id = json.id ?? 0;
string result = _bridge.Kuntae_Delete(id);
var response = new { type = "KUNTAE_DELETED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== Holiday API (월별근무표) =====
case "HOLIDAY_GET_LIST":
{
string month = json.month ?? "";
string result = _bridge.Holiday_GetList(month);
var response = new { type = "HOLIDAY_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "HOLIDAY_SAVE":
{
string month = json.month ?? "";
string holidaysJson = JsonConvert.SerializeObject(json.holidays);
string result = _bridge.Holiday_Save(month, holidaysJson);
var response = new { type = "HOLIDAY_SAVED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "HOLIDAY_INITIALIZE":
{
string month = json.month ?? "";
string result = _bridge.Holiday_Initialize(month);
var response = new { type = "HOLIDAY_INITIALIZED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== MailForm API (메일양식) =====
case "MAILFORM_GET_LIST":
{
string result = _bridge.MailForm_GetList();
var response = new { type = "MAILFORM_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "MAILFORM_GET_DETAIL":
{
int idx = json.idx ?? 0;
string result = _bridge.MailForm_GetDetail(idx);
var response = new { type = "MAILFORM_DETAIL_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "MAILFORM_ADD":
{
string cate = json.cate ?? "";
string title = json.title ?? "";
string tolist = json.tolist ?? "";
string bcc = json.bcc ?? "";
string cc = json.cc ?? "";
string subject = json.subject ?? "";
string tail = json.tail ?? "";
string body = json.body ?? "";
bool selfTo = json.selfTo ?? false;
bool selfCC = json.selfCC ?? false;
bool selfBCC = json.selfBCC ?? false;
string exceptmail = json.exceptmail ?? "";
string exceptmailcc = json.exceptmailcc ?? "";
string result = _bridge.MailForm_Add(cate, title, tolist, bcc, cc, subject, tail, body, selfTo, selfCC, selfBCC, exceptmail, exceptmailcc);
var response = new { type = "MAILFORM_ADDED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "MAILFORM_EDIT":
{
int idx = json.idx ?? 0;
string cate = json.cate ?? "";
string title = json.title ?? "";
string tolist = json.tolist ?? "";
string bcc = json.bcc ?? "";
string cc = json.cc ?? "";
string subject = json.subject ?? "";
string tail = json.tail ?? "";
string body = json.body ?? "";
bool selfTo = json.selfTo ?? false;
bool selfCC = json.selfCC ?? false;
bool selfBCC = json.selfBCC ?? false;
string exceptmail = json.exceptmail ?? "";
string exceptmailcc = json.exceptmailcc ?? "";
string result = _bridge.MailForm_Edit(idx, cate, title, tolist, bcc, cc, subject, tail, body, selfTo, selfCC, selfBCC, exceptmail, exceptmailcc);
var response = new { type = "MAILFORM_EDITED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "MAILFORM_DELETE":
{
int idx = json.idx ?? 0;
string result = _bridge.MailForm_Delete(idx);
var response = new { type = "MAILFORM_DELETED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== UserGroup API (그룹정보/권한설정) =====
case "USERGROUP_GET_LIST":
{
string result = _bridge.UserGroup_GetList();
var response = new { type = "USERGROUP_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "USERGROUP_ADD":
{
string dept = json.dept ?? "";
string path_kj = json.path_kj ?? "";
int permission = json.permission ?? 1;
bool advpurchase = json.advpurchase ?? false;
bool advkisul = json.advkisul ?? false;
string managerinfo = json.managerinfo ?? "";
string devinfo = json.devinfo ?? "";
bool usemail = json.usemail ?? false;
string result = _bridge.UserGroup_Add(dept, path_kj, permission, advpurchase, advkisul, managerinfo, devinfo, usemail);
var response = new { type = "USERGROUP_ADDED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "USERGROUP_EDIT":
{
string originalDept = json.originalDept ?? "";
string dept = json.dept ?? "";
string path_kj = json.path_kj ?? "";
int permission = json.permission ?? 1;
bool advpurchase = json.advpurchase ?? false;
bool advkisul = json.advkisul ?? false;
string managerinfo = json.managerinfo ?? "";
string devinfo = json.devinfo ?? "";
bool usemail = json.usemail ?? false;
string result = _bridge.UserGroup_Edit(originalDept, dept, path_kj, permission, advpurchase, advkisul, managerinfo, devinfo, usemail);
var response = new { type = "USERGROUP_EDITED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "USERGROUP_DELETE":
{
string dept = json.dept ?? "";
string result = _bridge.UserGroup_Delete(dept);
var response = new { type = "USERGROUP_DELETED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "USERGROUP_GET_PERMISSION_INFO":
{
string result = _bridge.UserGroup_GetPermissionInfo();
var response = new { type = "USERGROUP_PERMISSION_INFO", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== UserAuth API (사용자 권한) =====
case "USERAUTH_CAN_ACCESS":
{
string result = _bridge.UserAuth_CanAccess();
var response = new { type = "USERAUTH_CAN_ACCESS_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "USERAUTH_GET_LIST":
{
string result = _bridge.UserAuth_GetList();
var response = new { type = "USERAUTH_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "USERAUTH_SAVE":
{
int idx = json.idx ?? 0;
string user = json.user ?? "";
int account = json.account ?? 0;
int purchase = json.purchase ?? 0;
int purchaseEB = json.purchaseEB ?? 0;
int holyday = json.holyday ?? 0;
int project = json.project ?? 0;
int jobreport = json.jobreport ?? 0;
int scheapp = json.scheapp ?? 0;
int equipment = json.equipment ?? 0;
int otconfirm = json.otconfirm ?? 0;
int holyreq = json.holyreq ?? 0;
int kuntae = json.kuntae ?? 0;
string result = _bridge.UserAuth_Save(idx, user, account, purchase, purchaseEB, holyday, project, jobreport, scheapp, equipment, otconfirm, holyreq, kuntae);
var response = new { type = "USERAUTH_SAVED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "USERAUTH_DELETE":
{
int idx = json.idx ?? 0;
string result = _bridge.UserAuth_Delete(idx);
var response = new { type = "USERAUTH_DELETED", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "USERAUTH_GET_FIELDS":
{
string result = _bridge.UserAuth_GetFields();
var response = new { type = "USERAUTH_FIELDS_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== 범용 권한 체크 API =====
case "CHECK_AUTH":
{
string authType = json.authType ?? "";
int requiredLevel = json.requiredLevel ?? 5;
string result = _bridge.CheckAuth(authType, requiredLevel);
var response = new { type = "CHECK_AUTH_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "GET_MY_AUTH":
{
string result = _bridge.GetMyAuth();
var response = new { type = "MY_AUTH_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== 프로젝트 검색 API (업무일지용) =====
case "PROJECT_SEARCH":
{
string keyword = json.keyword ?? "";
string result = _bridge.Project_Search(keyword);
var response = new { type = "PROJECT_SEARCH_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "PROJECT_GET_USER_PROJECTS":
{
string result = _bridge.Project_GetUserProjects();
var response = new { type = "PROJECT_USER_PROJECTS_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "PROJECT_GET_CATEGORIES":
{
string result = _bridge.Project_GetCategories();
var response = new { type = "PROJECT_CATEGORIES_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "PROJECT_GET_PROCESSES":
{
string result = _bridge.Project_GetProcesses();
var response = new { type = "PROJECT_PROCESSES_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "PROJECT_GET_LIST":
{
string statusFilter = json.statusFilter ?? "";
string category = json.category ?? "";
string process = json.process ?? "";
string userFilter = json.userFilter ?? "";
string yearStart = json.yearStart ?? "";
string yearEnd = json.yearEnd ?? "";
string dateType = json.dateType ?? "0";
string result = _bridge.Project_GetList(statusFilter, category, process, userFilter, yearStart, yearEnd, dateType);
var response = new { type = "PROJECT_LIST_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "PROJECT_GET_HISTORY":
{
int projectIdx = json.projectIdx ?? 0;
string result = _bridge.Project_GetHistory(projectIdx);
var response = new { type = "PROJECT_HISTORY_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "PROJECT_GET_DAILY_MEMO":
{
int projectIdx = json.projectIdx ?? 0;
string result = _bridge.Project_GetDailyMemo(projectIdx);
var response = new { type = "PROJECT_DAILY_MEMO_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
// ===== 근태 오류검사 API =====
case "KUNTAE_ERROR_CHECK":
{
string sd = json.sd ?? "";
string ed = json.ed ?? "";
string result = _bridge.Kuntae_ErrorCheck(sd, ed);
var response = new { type = "KUNTAE_ERROR_CHECK_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "KUNTAE_FIX_ERROR":
{
string pdate = json.pdate ?? "";
string result = _bridge.Kuntae_FixError(pdate);
var response = new { type = "KUNTAE_FIX_ERROR_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
case "KUNTAE_FIX_ERRORS":
{
string dates = JsonConvert.SerializeObject(json.dates);
string result = _bridge.Kuntae_FixErrors(dates);
var response = new { type = "KUNTAE_FIX_ERRORS_DATA", data = JsonConvert.DeserializeObject(result) };
await Send(socket, JsonConvert.SerializeObject(response));
}
break;
default:
Console.WriteLine($"[WS] Unknown message type: {type}");
break;