고객CS 관리 수정

This commit is contained in:
2025-12-17 11:41:30 +09:00
parent 805d0da1df
commit b5a36f00ef
5 changed files with 175 additions and 25 deletions

View File

@@ -62,7 +62,7 @@ $(document).ready(function(){
// 뷰 모드일 경우 입력 필드 비활성화
if(isViewMode){
$("#form1 input, #form1 textarea, #form1 select").prop("disabled", true);
$("#btnSave, #btnUpload, #file1").hide();
$("#btnSave, #btnUpload, #btnImgUpload, #file1, #imgFile1").hide();
// 파일 삭제 버튼 숨기기
$(".delete_btn").parent().hide();
} else {
@@ -70,6 +70,7 @@ $(document).ready(function(){
fnc_setFileDropZone("srDropZone", "<%=objId%>", "CUSTOMER_CS_ACTION", "조치첨부", "srAreaDraw", false, null, null, null, "");
}
srAreaDraw();
imgAreaDraw();
// 파일 업로드 버튼
$("#btnUpload").click(function(){
@@ -82,6 +83,26 @@ $(document).ready(function(){
}
});
// 이미지 업로드 버튼
$("#btnImgUpload").click(function(){
var files = $("#imgFile1")[0].files;
if(files.length > 0){
// 이미지 파일 확장자 검사
var allowedExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
for(var i = 0; i < files.length; i++){
var ext = files[i].name.split('.').pop().toLowerCase();
if(allowedExts.indexOf(ext) < 0){
Swal.fire("이미지 파일만 업로드 가능합니다. (jpg, jpeg, png, gif, bmp, webp)");
return;
}
}
fnc_fileMultiUpload(files, null, "<%=objId%>", "CUSTOMER_CS_IMAGE", "조치이미지", null, "imgAreaDraw", null, "");
$("#imgFile1").val("");
}else{
Swal.fire("선택된 파일이 없습니다.");
}
});
// 저장
$("#btnSave").click(function(){
fn_save();
@@ -98,6 +119,72 @@ function srAreaDraw(){
fn_fileCallback("sr", "CUSTOMER_CS_ACTION");
}
// 이미지 목록 새로고침
function imgAreaDraw(){
fn_imageCallback("img", "CUSTOMER_CS_IMAGE");
}
// 이미지 목록 조회
function fn_imageCallback(areaId, fileType){
$.ajax({
url: "/common/getFileList.do",
type: "POST",
data: {"targetObjId": "<%=objId%>", "docType": fileType},
dataType: "json",
async: false,
success: function(data){
$("#" + areaId + "FileArea").empty();
if(data.length > 0){
$.each(data, function(i){
var appendHtml = '<div style="display:inline-block; margin:5px; text-align:center; cursor:pointer; position:relative;" onclick="fn_viewImage(\'/common/downloadFile.do?objId=' + data[i].OBJID + '\')">';
appendHtml += '<img src="/common/downloadFile.do?objId=' + data[i].OBJID + '" style="width:80px; height:80px; object-fit:cover; border:1px solid #ddd; border-radius:4px;">';
if(!isViewMode){
appendHtml += '<a href="javascript:fn_imageDelete(\'' + data[i].OBJID + '\', event)" style="position:absolute; top:-5px; right:-5px; background:#ff4444; color:#fff; border-radius:50%; width:18px; height:18px; line-height:18px; text-align:center; font-size:12px; text-decoration:none;">×</a>';
}
appendHtml += '<div style="font-size:10px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:80px;" title="' + data[i].REAL_FILE_NAME + '">' + data[i].REAL_FILE_NAME + '</div>';
appendHtml += '</div>';
$("#" + areaId + "FileArea").append(appendHtml);
});
}else{
$("#" + areaId + "FileArea").append('<div style="color:#999; padding:10px;">등록된 이미지가 없습니다.</div>');
}
}
});
}
// 이미지 원본 보기
function fn_viewImage(imgSrc){
var img = new Image();
img.onload = function(){
var width = Math.min(this.width, 1200);
var height = Math.min(this.height, 800);
window.open(imgSrc, "_blank", "width=" + width + ",height=" + height + ",scrollbars=yes,resizable=yes");
};
img.src = imgSrc;
}
// 이미지 삭제
function fn_imageDelete(fileObjId, event){
if(event){
event.preventDefault();
event.stopPropagation();
}
if(isViewMode) return;
if(confirm("이미지를 삭제하시겠습니까?")){
$.ajax({
url: "/common/deleteFileInfo.do",
type: "POST",
data: {"objId": fileObjId},
dataType: "json",
async: false,
success: function(data){
imgAreaDraw();
}
});
}
}
// 첨부파일 목록 조회
function fn_fileCallback(areaId, fileType){
$.ajax({
@@ -254,6 +341,8 @@ function fn_save(){
<tr>
<td class="input_title"><label>고객사</label></td>
<td>${info.customer_name}</td>
<td class="input_title"><label>제품구분</label></td>
<td>${info.product_type_name}</td>
</tr>
<tr>
<!-- <td class="input_title"><label>모델명</label></td>
@@ -283,7 +372,7 @@ function fn_save(){
<td colspan="3">${info.manufacturer}</td>
</tr>
<tr>
<td class="input_title"><label>불만내용</label></td>
<td class="input_title"><label>이슈내용</label></td>
<td colspan="3">
<textarea rows="4" style="width:100%;" readonly>${info.complaint_content}</textarea>
</td>
@@ -317,9 +406,9 @@ function fn_save(){
<td>
<select name="BLAME_DECISION" id="BLAME_DECISION" class="select2" required reqTitle="귀책판정" type="select">
<option value="">선택</option>
<option value="R">R</option>
<option value="C">C</option>
<option value="O">O</option>
<option value="R" ${info.BLAME_DECISION eq 'R' ? 'selected' : ''}>RPS</option>
<option value="C" ${info.BLAME_DECISION eq 'C' ? 'selected' : ''}>고객사</option>
<option value="O" ${info.BLAME_DECISION eq 'O' ? 'selected' : ''}>외주업체</option>
</select>
</td>
<td class="input_title"><label>상태 <span style="color:red;">*</span></label></td>
@@ -341,6 +430,15 @@ function fn_save(){
<input type="text" name="ACTION_USER_NAME" id="ACTION_USER_NAME" value="<%=actionUserName%>" readonly>
</td>
</tr>
<tr>
<td class="input_title"><label>조치구분 <span style="color:red;">*</span></label></td>
<td>
<select name="ACTION_TYPE" id="ACTION_TYPE" class="select2" required reqTitle="조치구분" type="select">
<option value="">선택</option>
${code_map.action_type}
</select>
</td>
</tr>
<tr>
<td class="input_title"><label>조치내용 <span style="color:red;">*</span></label></td>
<td colspan="3">
@@ -353,6 +451,17 @@ function fn_save(){
<textarea name="REMARK" id="REMARK" rows="2" style="width:100%;">${info.remark}</textarea>
</td>
</tr>
<tr>
<td class="input_title"><label>이미지</label></td>
<td colspan="3">
<div style="margin-bottom: 5px;">
<input type="file" name="imgFile1" id="imgFile1" multiple accept="image/*" style="width:80%;">
<input type="button" id="btnImgUpload" value="업로드" class="plm_btns">
</div>
<div id="imgFileArea" style="min-height:50px; border:1px dashed #ccc; border-radius:4px; padding:5px; background:#fafafa;">
</div>
</td>
</tr>
<tr>
<td class="input_title"><label>첨부파일</label></td>
<td colspan="3">

View File

@@ -143,7 +143,7 @@ function fn_save(){
<input type="text" name="QTY" id="QTY" value="${info.qty}" required reqTitle="수량">
</td>
</tr>
<tr>
<tr>
<td class="input_title"><label>고객사 <span style="color:red;">*</span></label></td>
<td>
<select name="CUSTOMER_OBJID" id="CUSTOMER_OBJID" class="select2" required reqTitle="고객사" type="select" style="width:100%;">
@@ -151,6 +151,13 @@ function fn_save(){
${code_map.customer_cd}
</select>
</td>
<td class="input_title"><label>제품구분 <span style="color:red;">*</span></label></td>
<td>
<select name="MODEL_NAME" id="MODEL_NAME" class="select2" required reqTitle="제품구분" type="select" style="width:100%;">
<option value="">선택</option>
${code_map.product_cd}
</select>
</td>
<!-- <td class="input_title"><label>모델명 <span style="color:red;">*</span></label></td>
<td>
<input type="text" name="MODEL_NAME" id="MODEL_NAME" value="${info.model_name}" required reqTitle="모델명">
@@ -200,7 +207,7 @@ function fn_save(){
</td>
</tr>
<tr>
<td class="input_title"><label>불만내용 <span style="color:red;">*</span></label></td>
<td class="input_title"><label>이슈내용 <span style="color:red;">*</span></label></td>
<td colspan="3">
<textarea name="COMPLAINT_CONTENT" id="COMPLAINT_CONTENT" rows="3" style="width:100%;" required reqTitle="불만내용" type="text">${info.complaint_content}</textarea>
</td>

View File

@@ -65,7 +65,7 @@ $(document).ready(function(){
// 접수번호 클릭 시 조치결과 뷰 팝업
function fn_viewActionPopUp(objId){
var popup_width = 1200;
var popup_height = 600;
var popup_height = 800;
var hiddenForm = document.hiddenForm;
var target = "customerCsActionViewPopUp";
var url = "/quality/customerCsActionFormPopUp.do";
@@ -93,19 +93,22 @@ var columns = [
formatter:"money", formatterParams:{thousand:",", precision:false}
},
{headerHozAlign:'center', hozAlign:'left', minWidth:150, widthGrow:1, title:'고객사', field:'CUSTOMER_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'제품구분', field:'PRODUCT_TYPE_NAME'},
//{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'모델명', field:'MODEL_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품명', field:'PART_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품번', field:'PART_NO'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품품명', field:'PRODUCT_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품품번', field:'PRODUCT_NO'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품명', field:'PRODUCT_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품번', field:'PRODUCT_NO'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품품명', field:'PART_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품품번', field:'PART_NO'},
{headerHozAlign:'center', hozAlign:'center', minWidth:90, widthGrow:1, title:'생산일', field:'PRODUCTION_DATE'},
{headerHozAlign:'center', hozAlign:'center', minWidth:90, widthGrow:1, title:'판매일', field:'SALES_DATE'},
{headerHozAlign:'center', hozAlign:'center', minWidth:100, widthGrow:1, title:'S/N', field:'SERIAL_NO'},
{headerHozAlign:'center', hozAlign:'left', minWidth:80, widthGrow:1, title:'제조사', field:'MANUFACTURER'},
{headerHozAlign:'center', hozAlign:'left', minWidth:120, widthGrow:2, title:'불만내용', field:'COMPLAINT_CONTENT'},
{headerHozAlign:'center', hozAlign:'left', minWidth:120, widthGrow:2, title:'이슈내용', field:'COMPLAINT_CONTENT'},
{headerHozAlign:'center', hozAlign:'left', minWidth:120, widthGrow:2, title:'조치구분', field:'ACTION_TYPE_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:120, widthGrow:2, title:'조치내용', field:'ACTION_CONTENT'},
{headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'귀책판정', field:'BLAME_DECISION'},
{headerHozAlign:'center', hozAlign:'center', minWidth:70, widthGrow:1, title:'상태', field:'STATUS',
{headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'귀책판정', field:'BLAME_DECISION_NAME'},
{headerHozAlign:'center', hozAlign:'center', minWidth:90, widthGrow:1, title:'상태(C/O)', field:'STATUS',
formatter: function(cell, formatterParams, onRendered){
var val = fnc_checkNull(cell.getValue());
if(val === '접수') return '<span class="status-receipt">접수</span>';
@@ -117,14 +120,14 @@ var columns = [
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'비고', field:'REMARK'},
{headerHozAlign:'center', hozAlign:'center', minWidth:90, widthGrow:1, title:'조치일', field:'ACTION_DATE'},
{headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'조치자', field:'ACTION_USER_NAME'},
{headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'이미지', field:'IMAGE_FILE',
{headerHozAlign:'center', hozAlign:'center', minWidth:90, widthGrow:1, title:'이미지파일', field:'IMAGE_FILE',
formatter:fnc_subInfoValueFormatter,
cellClick:function(e, cell){
var objId = fnc_checkNull(cell.getData().OBJID);
fn_openImageFilePopUp(objId);
}
},
{headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'첨부파일', field:'ATTACH_FILE',
{headerHozAlign:'center', hozAlign:'center', minWidth:90, widthGrow:1, title:'첨부파일', field:'ATTACH_FILE',
formatter:fnc_subInfoValueFormatter,
cellClick:function(e, cell){
var objid = fnc_checkNull(cell.getData().OBJID);
@@ -193,7 +196,7 @@ function fn_registActionPopUp(){
}
var popup_width = 1200;
var popup_height = 600;
var popup_height = 800;
var hiddenForm = document.hiddenForm;
var target = "customerCsActionPopUp";
var url = "/quality/customerCsActionFormPopUp.do";
@@ -244,7 +247,7 @@ function fn_FileRegist(objId, docType, docTypeName){
<span><%=menuName%></span>
</h2>
<div class="btnArea">
<input type="button" class="plm_btns" value="고객 불량 등록" id="btnRegistDefect">
<input type="button" class="plm_btns" value="고객 이슈 등록" id="btnRegistDefect">
<input type="button" class="plm_btns" value="조치결과 등록" id="btnRegistAction">
<input type="button" class="plm_btns" value="조회" id="btnSearch">
</div>
@@ -260,11 +263,18 @@ function fn_FileRegist(objId, docType, docTypeName){
</td>
<td><label>고객사</label></td>
<td>
<select name="search_customer_objid" id="search_customer_objid" class="select2" autocomplete="off" style="width:230px;">
<select name="search_customer_objid" id="search_customer_objid" class="select2" autocomplete="off" style="width:180px;">
<option value="">전체</option>
${code_map.customer_cd}
</select>
</td>
<!-- <td><label>제품구분</label></td>
<td>
<select name="search_product_type" id="search_product_type" class="select2" autocomplete="off" style="width:120px;">
<option value="">전체</option>
${code_map.product_type}
</select>
</td> -->
<td><label>품번</label></td>
<td><input type="text" name="search_product_no" id="search_product_no" style="" autocomplete="off"></td>
<td><label>품명</label></td>

View File

@@ -656,6 +656,8 @@ public class QualityController {
try {
// 고객사
code_map.put("customer_cd", commonService.bizMakeOptionList("", "", "common.getClientMngSupplySelect"));
// 제품구분
code_map.put("product_type", commonService.bizMakeOptionList("0000001", (String)paramMap.get("search_product_type"), "common.getCodeselect"));
request.setAttribute("code_map", code_map);
} catch(Exception e) {
e.printStackTrace();
@@ -689,6 +691,8 @@ public class QualityController {
}
// 고객사
code_map.put("customer_cd", commonService.bizMakeOptionList("", CommonUtils.nullToEmpty((String)info.get("customer_objid")), "common.getClientMngSupplySelect"));
// 제품구분
code_map.put("product_cd", commonService.bizMakeOptionList("0000001", CommonUtils.nullToEmpty((String)info.get("PRODUCT_TYPE")), "common.getCodeselect"));
} catch(Exception e) {
e.printStackTrace();
}
@@ -711,8 +715,19 @@ public class QualityController {
*/
@RequestMapping("/quality/customerCsActionFormPopUp.do")
public String customerCsActionFormPopUp(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
Map info = service.getCustomerCsInfo(paramMap);
Map code_map = new HashMap();
Map info = new HashMap();
try {
info = service.getCustomerCsInfo(paramMap);
// 조치구분
code_map.put("action_type", commonService.bizMakeOptionList("0001835", CommonUtils.nullToEmpty((String)info.get("action_type")), "common.getCodeselect"));
} catch(Exception e) {
e.printStackTrace();
}
request.setAttribute("info", info);
request.setAttribute("code_map", code_map);
return "/quality/customerCsActionFormPopUp";
}

View File

@@ -1393,7 +1393,8 @@
, CCS.QTY
, CCS.CUSTOMER_OBJID
, (SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = CCS.CUSTOMER_OBJID) AS CUSTOMER_NAME
, CCS.MODEL_NAME
, CCS.MODEL_NAME AS PRODUCT_TYPE
, CODE_NAME(CCS.MODEL_NAME) AS PRODUCT_TYPE_NAME
, CCS.PRODUCT_NAME
, CCS.PART_NO
, CCS.PRODUCT_NO
@@ -1403,8 +1404,11 @@
, CCS.SERIAL_NO
, CCS.MANUFACTURER
, CCS.COMPLAINT_CONTENT
, CCS.ACTION_TYPE
, CODE_NAME(CCS.ACTION_TYPE) AS ACTION_TYPE_NAME
, CCS.ACTION_CONTENT
, CCS.BLAME_DECISION
, CASE CCS.BLAME_DECISION WHEN 'R' THEN 'RPS' WHEN 'C' THEN '고객사' WHEN 'O' THEN '외주업체' ELSE CCS.BLAME_DECISION END AS BLAME_DECISION_NAME
, CCS.STATUS
, CCS.REMARK
, CCS.ACTION_DATE
@@ -1423,8 +1427,8 @@
<if test="search_customer_objid != null and search_customer_objid != ''">
AND CCS.CUSTOMER_OBJID = #{search_customer_objid}
</if>
<if test="search_model_name != null and search_model_name != ''">
AND UPPER(CCS.MODEL_NAME) LIKE UPPER('%' || #{search_model_name} || '%')
<if test="search_product_type != null and search_product_type != ''">
AND CCS.MODEL_NAME = #{search_product_type}
</if>
<if test="search_product_no != null and search_product_no != ''">
AND UPPER(CCS.PRODUCT_NO) LIKE UPPER('%' || #{search_product_no} || '%')
@@ -1473,7 +1477,8 @@
, CCS.QTY
, CCS.CUSTOMER_OBJID
, (SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = CCS.CUSTOMER_OBJID) AS CUSTOMER_NAME
, CCS.MODEL_NAME
, CCS.MODEL_NAME AS PRODUCT_TYPE
, CODE_NAME(CCS.MODEL_NAME) AS PRODUCT_TYPE_NAME
, CCS.PRODUCT_NAME
, CCS.PART_NO
, CCS.PRODUCT_NO
@@ -1483,8 +1488,11 @@
, CCS.SERIAL_NO
, CCS.MANUFACTURER
, CCS.COMPLAINT_CONTENT
, CCS.ACTION_TYPE
, CODE_NAME(CCS.ACTION_TYPE) AS ACTION_TYPE_NAME
, CCS.ACTION_CONTENT
, CCS.BLAME_DECISION
, CASE CCS.BLAME_DECISION WHEN 'R' THEN 'RPS' WHEN 'C' THEN '고객사' WHEN 'O' THEN '외주업체' ELSE CCS.BLAME_DECISION END AS BLAME_DECISION_NAME
, CCS.STATUS
, CCS.REMARK
, CCS.ACTION_DATE
@@ -1579,6 +1587,7 @@
, STATUS = #{STATUS}
, REMARK = #{REMARK}
, MOD_DATE = NOW()
, ACTION_TYPE = #{ACTION_TYPE}
WHERE OBJID = #{OBJID}
</update>