feat: React 프론트엔드 기능 대폭 확장

- 월별근무표: 휴일/근무일 관리, 자동 초기화
- 메일양식: 템플릿 CRUD, To/CC/BCC 설정
- 그룹정보: 부서 관리, 비트 연산 기반 권한 설정
- 업무일지: 수정 성공 메시지 제거, 오늘 근무시간 필터링 수정
- 웹소켓 메시지 type 충돌 버그 수정

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
backuppc
2025-11-27 17:25:31 +09:00
parent b57af6dad7
commit c9b5d756e1
65 changed files with 14028 additions and 467 deletions

View File

@@ -229,5 +229,198 @@ namespace Project.Web
}
#endregion
#region Items API
/// <summary>
/// 품목 카테고리 목록 조회
/// </summary>
public string Items_GetCategories()
{
try
{
var sql = "SELECT DISTINCT cate FROM Items WITH (NOLOCK) WHERE gcode = @gcode AND ISNULL(cate,'') <> '' ORDER BY cate";
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<string>();
foreach (DataRow dr in dt.Rows)
{
result.Add(dr["cate"]?.ToString() ?? "");
}
return JsonConvert.SerializeObject(new { Success = true, Data = result });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "카테고리 조회 실패: " + ex.Message });
}
}
/// <summary>
/// 품목 목록 조회
/// </summary>
public string Items_GetList(string category, string searchKey)
{
try
{
var cateSearch = string.IsNullOrEmpty(category) || category == "all" ? "%" : category;
var skey = string.IsNullOrEmpty(searchKey) || searchKey == "%" ? "%" : $"%{searchKey}%";
var sql = @"SELECT idx, sid, cate, name, model, scale, unit, price, supply, manu, storage, disable, memo
FROM Items WITH (NOLOCK)
WHERE gcode = @gcode
AND ISNULL(cate,'') LIKE @cate
AND (ISNULL(sid,'') LIKE @search OR ISNULL(name,'') LIKE @search OR ISNULL(model,'') LIKE @search)
ORDER BY sid, name";
var cs = Properties.Settings.Default.gwcs;
var cn = new SqlConnection(cs);
var cmd = new SqlCommand(sql, cn);
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@cate", cateSearch);
cmd.Parameters.AddWithValue("@search", skey);
var da = new SqlDataAdapter(cmd);
var dt = new DataTable();
da.Fill(dt);
da.Dispose();
cmd.Dispose();
cn.Dispose();
return JsonConvert.SerializeObject(dt, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "품목 조회 실패: " + ex.Message });
}
}
/// <summary>
/// 품목 저장
/// </summary>
public string Items_Save(int idx, string sid, string cate, string name, string model,
string scale, string unit, decimal price, string supply, string manu, string storage, bool disable, string memo)
{
try
{
var cs = Properties.Settings.Default.gwcs;
var cn = new SqlConnection(cs);
var sql = string.Empty;
var cmd = new SqlCommand();
cmd.Connection = cn;
// 신규 추가 시 SID 중복 체크
if (idx == 0 && !string.IsNullOrEmpty(sid))
{
var checkSql = "SELECT COUNT(*) FROM Items WITH (NOLOCK) WHERE gcode = @gcode AND sid = @sid";
var checkCmd = new SqlCommand(checkSql, cn);
checkCmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
checkCmd.Parameters.AddWithValue("@sid", sid);
cn.Open();
var count = (int)checkCmd.ExecuteScalar();
cn.Close();
checkCmd.Dispose();
if (count > 0)
{
cn.Dispose();
return JsonConvert.SerializeObject(new { Success = false, Message = $"이미 존재하는 SID입니다: {sid}" });
}
}
if (idx > 0)
{
sql = @"UPDATE Items SET
sid = @sid, cate = @cate, name = @name, model = @model,
scale = @scale, unit = @unit, price = @price, supply = @supply,
manu = @manu, storage = @storage, disable = @disable, memo = @memo,
wuid = @wuid, wdate = GETDATE()
WHERE idx = @idx AND gcode = @gcode";
}
else
{
sql = @"INSERT INTO Items (gcode, sid, cate, name, model, scale, unit, price, supply, manu, storage, disable, memo, wuid, wdate)
VALUES (@gcode, @sid, @cate, @name, @model, @scale, @unit, @price, @supply, @manu, @storage, @disable, @memo, @wuid, GETDATE())";
}
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cmd.Parameters.AddWithValue("@sid", sid ?? "");
cmd.Parameters.AddWithValue("@cate", cate ?? "");
cmd.Parameters.AddWithValue("@name", name ?? "");
cmd.Parameters.AddWithValue("@model", model ?? "");
cmd.Parameters.AddWithValue("@scale", scale ?? "");
cmd.Parameters.AddWithValue("@unit", unit ?? "");
cmd.Parameters.AddWithValue("@price", price);
cmd.Parameters.AddWithValue("@supply", supply ?? "");
cmd.Parameters.AddWithValue("@manu", manu ?? "");
cmd.Parameters.AddWithValue("@storage", storage ?? "");
cmd.Parameters.AddWithValue("@disable", disable);
cmd.Parameters.AddWithValue("@memo", memo ?? "");
cmd.Parameters.AddWithValue("@wuid", info.Login.no);
if (idx > 0)
{
cmd.Parameters.AddWithValue("@idx", idx);
}
cn.Open();
var result = cmd.ExecuteNonQuery();
cn.Close();
cmd.Dispose();
cn.Dispose();
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_Delete(int idx)
{
try
{
var cs = Properties.Settings.Default.gwcs;
var cn = new SqlConnection(cs);
var sql = "DELETE FROM Items WHERE idx = @idx AND gcode = @gcode";
var cmd = new SqlCommand(sql, cn);
cmd.Parameters.AddWithValue("@idx", idx);
cmd.Parameters.AddWithValue("@gcode", info.Login.gcode);
cn.Open();
var result = cmd.ExecuteNonQuery();
cn.Close();
cmd.Dispose();
cn.Dispose();
return JsonConvert.SerializeObject(new { Success = result > 0, Message = result > 0 ? "삭제되었습니다." : "삭제에 실패했습니다." });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { Success = false, Message = "삭제 실패: " + ex.Message });
}
}
#endregion
}
}