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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user