품질관리_고객CS관리

This commit is contained in:
2025-12-09 11:53:57 +09:00
parent d3e2ffa662
commit a4a066390d
11 changed files with 1378 additions and 274 deletions

View File

@@ -0,0 +1,347 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.pms.common.utils.*"%>
<%@ page import="java.util.*" %>
<%@include file= "/init.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<style>
/* 이미지 미리보기 영역 */
.image-preview-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 10px;
max-height: 300px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
background: #f9f9f9;
}
.image-preview-item {
position: relative;
width: 120px;
height: 120px;
border: 1px solid #ccc;
border-radius: 4px;
overflow: hidden;
background: #fff;
}
.image-preview-item img {
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
}
.image-preview-item .delete-btn {
position: absolute;
top: 2px;
right: 2px;
width: 20px;
height: 20px;
background: rgba(255, 0, 0, 0.8);
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
font-size: 12px;
line-height: 18px;
text-align: center;
}
.image-preview-item .delete-btn:hover {
background: rgba(255, 0, 0, 1);
}
.image-preview-item .file-name {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: rgba(0,0,0,0.6);
color: white;
font-size: 10px;
padding: 2px 4px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.no-image-msg {
width: 100%;
text-align: center;
color: #999;
padding: 30px;
}
/* 드래그앤드롭 영역 */
.drop-zone {
border: 2px dashed #ccc;
border-radius: 8px;
padding: 20px;
text-align: center;
color: #666;
margin-bottom: 10px;
transition: all 0.3s;
}
.drop-zone.dragover {
border-color: #007bff;
background: #e8f4ff;
}
.drop-zone p {
margin: 0;
font-size: 14px;
}
</style>
</head>
<script>
var callbackFnc = "${param.callbackFnc}";
var _isChanged = false;
var _fileCnt = 0;
// 이미지 확장자 목록
var allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
$(document).ready(function(){
$("#btn_close").click(function(){
openerCallback();
self.close(0);
});
// 드래그앤드롭 이벤트 설정
setupDropZone();
// 이미지 목록 조회
loadImageList();
// 파일 선택 시 확장자 검사
$("#imageFile").change(function(){
validateImageFiles(this.files);
});
// 업로드 버튼
$("#btnUpload").click(function(){
var files = $("#imageFile")[0].files;
if(files.length > 0){
if(validateImageFiles(files)){
uploadImages(files);
}
}else{
Swal.fire("선택된 이미지가 없습니다.");
}
});
});
// 드래그앤드롭 영역 설정
function setupDropZone(){
var dropZone = document.getElementById("imageDropZone");
dropZone.addEventListener("dragover", function(e){
e.preventDefault();
e.stopPropagation();
$(this).addClass("dragover");
});
dropZone.addEventListener("dragleave", function(e){
e.preventDefault();
e.stopPropagation();
$(this).removeClass("dragover");
});
dropZone.addEventListener("drop", function(e){
e.preventDefault();
e.stopPropagation();
$(this).removeClass("dragover");
var files = e.dataTransfer.files;
if(files.length > 0){
if(validateImageFiles(files)){
uploadImages(files);
}
}
});
}
// 이미지 파일 검증
function validateImageFiles(files){
for(var i = 0; i < files.length; i++){
var fileName = files[i].name;
var ext = fileName.split('.').pop().toLowerCase();
if(allowedExtensions.indexOf(ext) === -1){
Swal.fire({
icon: 'error',
title: '허용되지 않는 파일 형식',
text: '이미지 파일만 업로드 가능합니다.\n허용 확장자: ' + allowedExtensions.join(', ')
});
$("#imageFile").val("");
return false;
}
}
return true;
}
// 이미지 업로드 - 기존 fnc_fileMultiUpload 함수 사용
function uploadImages(files){
fnc_fileMultiUpload(files, null, "${param.targetObjId}", "${param.docType}", "${param.docTypeName}", null, "loadImageList", null, "");
}
// 이미지 목록 조회
function loadImageList(){
$.ajax({
url: "/common/getFileList.do",
type: "POST",
data: {
"targetObjId": "${param.targetObjId}",
"docType": "${param.docType}"
},
dataType: "json",
async: false,
success: function(data){
// 부모 창 새로고침
if(opener && typeof opener.fn_search == "function"){
opener.fn_search();
}
_fileCnt = data.length;
renderImageList(data);
openerCallback();
},
error: function(){
console.error("이미지 목록 조회 실패");
}
});
}
// 이미지 목록 렌더링
function renderImageList(data){
var container = $("#imagePreviewArea");
container.empty();
if(data.length == 0){
container.append('<div class="no-image-msg">등록된 이미지가 없습니다.</div>');
return;
}
$.each(data, function(i, file){
var ext = file.UPPER_FILE_EXT;
// 이미지 파일인 경우만 표시
if(allowedExtensions.indexOf(ext.toLowerCase()) > -1){
// objId 기반으로 이미지 표시 (viewImageByObjId.do 사용)
var imgSrc = "/common/viewImageByObjId.do?objId=" + file.OBJID;
var html = '<div class="image-preview-item">';
html += '<img src="' + imgSrc + '" onclick="viewImage(\'' + imgSrc + '\')" title="클릭하여 원본보기">';
// 삭제 권한 체크
if(file.WRITER == "${connectUserId}" || "${connectUserId}" == "plm_admin"){
html += '<button type="button" class="delete-btn" onclick="deleteImage(\'' + file.OBJID + '\', event)" title="삭제">×</button>';
}
html += '<div class="file-name" title="' + file.REAL_FILE_NAME + '">' + file.REAL_FILE_NAME + '</div>';
html += '</div>';
container.append(html);
}
});
// 이미지가 하나도 없는 경우
if(container.children().length == 0){
container.append('<div class="no-image-msg">등록된 이미지가 없습니다.</div>');
}
}
// 이미지 원본 보기 - 새 창에서 이미지 표시
function viewImage(imgUrl){
var img = new Image();
img.src = imgUrl;
// 이미지 크기에 맞게 팝업 열기
img.onload = function(){
var width = Math.min(img.width + 30, 1200);
var height = Math.min(img.height + 30, 800);
window.open(imgUrl, "ImageViewPopUp", "width=" + width + ",height=" + height + ",scrollbars=yes,resizable=yes");
};
// 이미지 로딩 실패시 기본 크기로 열기
img.onerror = function(){
window.open(imgUrl, "ImageViewPopUp", "width=800,height=600,scrollbars=yes,resizable=yes");
};
}
// 이미지 삭제
function deleteImage(fileObjId, event){
// 이벤트 전파 방지
if(event){
event.preventDefault();
event.stopPropagation();
}
if(confirm("이미지를 삭제하시겠습니까?")){
$.ajax({
url: "/common/deleteFileInfo.do",
type: "POST",
data: {"objId": fileObjId},
dataType: "json",
success: function(){
loadImageList();
// 부모 창 새로고침
if(opener && typeof opener.fn_search == "function"){
opener.fn_search();
}
},
error: function(){
alert("삭제 실패: 서버 통신 오류가 발생했습니다.");
}
});
}
}
// 부모 창 콜백
function openerCallback(){
if((fnc_isEmpty(callbackFnc) || callbackFnc == "fnc_tabulCallbackFnc") && opener && opener.fnc_tabulCallbackFnc){
opener.fnc_tabulCallbackFnc("${param.targetObjId}", "${param.docType}", "${param.columnField}", _fileCnt);
}else if(fnc_checkNull(callbackFnc) != "" && opener){
opener.eval(callbackFnc+"();");
}
}
</script>
<body>
<form name="form1" action="" method="post">
<input type="hidden" name="fileList" id="fileList" />
<section class="business_staff_popup_min_width">
<div class="plm_menu_name">
<h2>
<span>이미지 등록</span>
</h2>
</div>
<div id="businessPopupFormWrap">
<table class="pmsPopupForm">
<tr>
<td class="input_title align_c" style="width:80px;">이미지<br>업로드</td>
<td>
<!-- 드래그앤드롭 영역 -->
<div id="imageDropZone" class="drop-zone">
<p>📷 이미지 파일을 여기에 드래그하거나 아래에서 선택하세요</p>
<p style="font-size:11px; color:#999; margin-top:5px;">허용 확장자: jpg, jpeg, png, gif, bmp, webp</p>
</div>
<!-- 파일 선택 -->
<div style="margin-bottom: 10px;">
<input type="file" name="imageFile" id="imageFile" multiple accept="image/*">
<input type="button" id="btnUpload" value="업로드" class="plm_btns">
</div>
</td>
</tr>
<tr>
<td class="input_title align_c">이미지<br>목록</td>
<td>
<!-- 이미지 미리보기 영역 -->
<div id="imagePreviewArea" class="image-preview-container">
<div class="no-image-msg">등록된 이미지가 없습니다.</div>
</div>
</td>
</tr>
</table>
<div class="btn_wrap">
<div class="plm_btn_wrap_center">
<input type="button" value="닫기" id="btn_close" class="plm_btns">
</div>
</div>
</div>
</section>
</form>
</body>
</html>

View File

@@ -3,23 +3,84 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page import="com.pms.common.utils.*"%>
<%@ page import="java.util.*" %>
<%@include file= "/init.jsp" %>
<%@include file= "/init_new.jsp" %>
<%
String menuObjId = request.getParameter("menuObjId");
String menuName = CommonUtils.getMenuName(menuObjId, "조치결과 등록");
String actionType = CommonUtils.checkNull(request.getParameter("actionType"));
// 뷰 모드인지 판단
boolean isViewMode = "view".equals(actionType);
String menuName = isViewMode ? "조치결과 조회" : CommonUtils.getMenuName(menuObjId, "조치결과 등록");
Map info = (Map)request.getAttribute("info");
if(info == null) info = new HashMap();
String objId = CommonUtils.checkNull(info.get("objid"));
// 오늘 날짜
String today = new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date());
String actionDate = CommonUtils.checkNull(info.get("action_date"));
if(actionDate.isEmpty()) actionDate = today;
// 조치자
String actionUserName = CommonUtils.checkNull(info.get("action_user_name"));
if(actionUserName.isEmpty()) actionUserName = connectUserName;
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<style>
body { min-height: auto !important; }
.two_column_container {
display: flex;
gap: 15px;
padding: 10px;
}
.two_column_container > div {
flex: 1;
}
.two_column_container .pmsPopuptable tr {
height: 38px;
}
</style>
</head>
<script type="text/javascript">
var isViewMode = <%=isViewMode%>;
$(document).ready(function(){
fnc_datepick();
$('.select2').select2();
// 기존 값 선택
var savedBlameDecision = "${info.blame_decision}";
var savedStatus = "${info.status}";
if(savedBlameDecision) $("#BLAME_DECISION").val(savedBlameDecision).trigger('change');
if(savedStatus) $("#STATUS").val(savedStatus).trigger('change');
// 뷰 모드일 경우 입력 필드 비활성화
if(isViewMode){
$("#form1 input, #form1 textarea, #form1 select").prop("disabled", true);
$("#btnSave, #btnUpload, #file1").hide();
// 파일 삭제 버튼 숨기기
$(".delete_btn").parent().hide();
} else {
// 첨부파일 드래그앤드랍 설정 (뷰 모드가 아닐 때만)
fnc_setFileDropZone("srDropZone", "<%=objId%>", "CUSTOMER_CS_ACTION", "조치첨부", "srAreaDraw", false, null, null, null, "");
}
srAreaDraw();
// 파일 업로드 버튼
$("#btnUpload").click(function(){
var files = $("#file1")[0].files;
if(files.length > 0){
fnc_fileMultiUpload(files, null, "<%=objId%>", "CUSTOMER_CS_ACTION", "조치첨부", null, "srAreaDraw", null, "");
$("#file1").val("");
}else{
Swal.fire("선택된 파일이 없습니다.");
}
});
// 저장
$("#btnSave").click(function(){
@@ -32,105 +93,321 @@ $(document).ready(function(){
});
});
// 첨부파일 목록 새로고침
function srAreaDraw(){
fn_fileCallback("sr", "CUSTOMER_CS_ACTION");
}
// 첨부파일 목록 조회
function fn_fileCallback(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 appendText = "";
var fileExt = data[i].UPPER_FILE_EXT;
appendText += "<tr>";
appendText += "<td>" + (i + 1) + "</td>";
if(fileExt == 'PDF'){
appendText += "<td class='align_l'><a href='javascript:fnc_viewPdfFile(\"" + data[i].OBJID + "\")'>&nbsp;&nbsp;" + data[i].REAL_FILE_NAME + "</a>";
}else{
appendText += "<td class='align_l'><a href='javascript:fnc_downloadFile(\"" + data[i].OBJID + "\")'>&nbsp;&nbsp;" + data[i].REAL_FILE_NAME + "</a>";
}
// 뷰 모드가 아닐 때만 삭제 버튼 표시
if(!isViewMode){
appendText += "<a href='javascript:fn_fileDelete(\"" + data[i].OBJID + "\")'><div class='delete_btn'></div></a>";
}
appendText += "</td>";
appendText += "<td>" + data[i].REGDATE + "</td>";
appendText += "<td>" + data[i].FILE_SIZE + "</td>";
appendText += "</tr>";
$("#" + areaId + "FileArea").append(appendText);
});
}else{
var appendText = "<tr><td colspan='4'>첨부 파일이 없습니다.</td></tr>";
$("#" + areaId + "FileArea").append(appendText);
}
}
});
}
// PDF 미리보기
function fnc_viewPdfFile(fileObjId){
window.open("/common/downloadFile.do?objId=" + fileObjId, "_blank");
}
// 첨부파일 삭제
function fn_fileDelete(fileObjId){
// 뷰 모드에서는 삭제 불가
if(isViewMode) return;
if(confirm("파일을 삭제하시겠습니까?")){
$.ajax({
url: "/common/deleteFileInfo.do",
type: "POST",
data: {"objId": fileObjId},
dataType: "json",
async: false,
success: function(data){
srAreaDraw();
}
});
}
}
function fn_save(){
// TODO: 저장 로직 구현
Swal.fire("저장 기능 준비중입니다.");
// 유효성 검사
if(!fnc_valitate("form1")){
return;
}
Swal.fire({
title: '저장하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '저장',
cancelButtonText: '취소'
}).then((result) => {
if(result.isConfirmed){
$.ajax({
url: "/quality/saveCustomerCsAction.do",
type: "POST",
data: $("#form1").serialize(),
dataType: "json",
success: function(result){
if(result.RESULT == "SUCCESS"){
Swal.fire({
title: '저장되었습니다.',
icon: 'success'
}).then(() => {
if(window.opener && window.opener.fn_search){
window.opener.fn_search();
}
window.close();
});
} else {
Swal.fire({
title: '저장 실패',
text: result.MESSAGE || '저장 중 오류가 발생했습니다.',
icon: 'error'
});
}
},
error: function(xhr, status, error){
Swal.fire({
title: '저장 실패',
text: '서버 통신 오류가 발생했습니다.',
icon: 'error'
});
}
});
}
});
}
</script>
<body>
<form name="form1" id="form1" method="post">
<input type="hidden" name="OBJID" id="OBJID" value="<%=CommonUtils.checkNull(info.get("OBJID"))%>">
<div class="popup_wrap">
<div class="popup_header">
<h2><%=menuName%></h2>
<div class="btnArea">
<input type="button" class="plm_btns" value="저장" id="btnSave">
<input type="button" class="plm_btns" value="닫기" id="btnClose">
<input type="hidden" name="OBJID" id="OBJID" value="${info.objid}">
<section class="business_staff_popup_min_width">
<div class="plm_menu_name">
<h2>
<span><%=menuName%></span>
</h2>
</div>
<div id="EntirePopupFormWrap">
<div class="two_column_container">
<!-- 왼쪽: 접수 정보 -->
<div>
<div class="form_popup_title">
<span>접수 정보</span>
</div>
<table class="">
<colgroup>
<col width="90%" />
</colgroup>
<tr>
<td>
<table class="pmsPopuptable">
<colgroup>
<col width="20%" />
<col width="30%" />
<col width="20%" />
<col width="30%" />
</colgroup>
<tr>
<!-- <td class="input_title"><label>접수번호</label></td>
<td>${info.receipt_no}</td> -->
<td class="input_title"><label>접수일</label></td>
<td>${info.receipt_date}</td>
<td class="input_title"><label>수량</label></td>
<td>${info.qty}</td>
</tr>
<tr>
<td class="input_title"><label>고객사</label></td>
<td>${info.customer_name}</td>
</tr>
<tr>
<!-- <td class="input_title"><label>모델명</label></td>
<td>${info.model_name}</td> -->
<td class="input_title"><label>품명</label></td>
<td>${info.product_name}</td>
<td class="input_title"><label>품번</label></td>
<td>${info.product_no}</td>
</tr>
<tr>
<td class="input_title"><label>부품품명</label></td>
<td>${info.part_name}</td>
<td class="input_title"><label>부품품번</label></td>
<td>${info.part_no}</td>
</tr>
<tr>
<td class="input_title"><label>생산일</label></td>
<td>${info.production_date}</td>
<td class="input_title"><label>판매일</label></td>
<td>${info.sales_date}</td>
</tr>
<tr>
<td class="input_title"><label>S/N</label></td>
<td>${info.serial_no}</td>
<td class="input_title"><label>제조사</label></td>
<td colspan="3">${info.manufacturer}</td>
</tr>
<tr>
<td class="input_title"><label>불만내용</label></td>
<td colspan="3">
<textarea rows="4" style="width:100%;" readonly>${info.complaint_content}</textarea>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<!-- 오른쪽: 조치결과 등록 -->
<div>
<div class="form_popup_title">
<span>조치결과 등록</span>
</div>
<table class="">
<colgroup>
<col width="110%" />
</colgroup>
<tr>
<td>
<table class="pmsPopuptable">
<colgroup>
<col width="20%" />
<col width="30%" />
<col width="20%" />
<col width="30%" />
</colgroup>
<tr>
<td class="input_title"><label>귀책판정 <span style="color:red;">*</span></label></td>
<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>
</select>
</td>
<td class="input_title"><label>상태 <span style="color:red;">*</span></label></td>
<td>
<select name="STATUS" id="STATUS" class="select2" required reqTitle="상태" type="select">
<option value="">선택</option>
<option value="Open">Open</option>
<option value="Closed">Closed</option>
</select>
</td>
</tr>
<tr>
<td class="input_title"><label>조치일 <span style="color:red;">*</span></label></td>
<td>
<input type="text" name="ACTION_DATE" id="ACTION_DATE" class="date_icon" value="<%=actionDate%>" required reqTitle="조치일">
</td>
<td class="input_title"><label>조치자 <span style="color:red;">*</span></label></td>
<td>
<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 colspan="3">
<textarea name="ACTION_CONTENT" id="ACTION_CONTENT" rows="3" style="width:100%;" required reqTitle="조치내용" type="text">${info.action_content}</textarea>
</td>
</tr>
<tr>
<td class="input_title"><label>비고</label></td>
<td colspan="3">
<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="file1" id="file1" multiple style="width:80%;">
<input type="button" id="btnUpload" value="업로드" class="plm_btns">
</div>
<div id="srFileAreaTable" class="spec_data_in_table">
<div style="overflow-y:auto;">
<table class="fileListscrollThead" style="width:100% !important;">
<colgroup>
<col width="30px">
<col width="*">
<col width="80px">
<col width="60px">
</colgroup>
<tr>
<td>No</td>
<td>파일명</td>
<td>등록일</td>
<td>Size</td>
</tr>
</table>
</div>
<div style="max-height: 80px; overflow-y: auto; border-bottom: 1px solid #cacaca;">
<table class="fileListscrollTbody">
<colgroup>
<col width="30px">
<col width="*">
<col width="80px">
<col width="60px">
</colgroup>
<tbody id="srFileArea">
</tbody>
</table>
</div>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</div>
<div class="popup_content">
<h3 style="margin-bottom:10px;">■ 접수 정보</h3>
<table class="plm_form_table">
<colgroup>
<col width="100px"><col width="*">
<col width="100px"><col width="*">
<col width="100px"><col width="*">
</colgroup>
<tbody>
<tr>
<td class="label">접수번호</td>
<td><input type="text" name="RECEIPT_NO" id="RECEIPT_NO" value="<%=CommonUtils.checkNull(info.get("RECEIPT_NO"))%>" readonly></td>
<td class="label">접수일</td>
<td><input type="text" name="RECEIPT_DATE" id="RECEIPT_DATE" value="<%=CommonUtils.checkNull(info.get("RECEIPT_DATE"))%>" readonly></td>
<td class="label">고객사</td>
<td><input type="text" name="CUSTOMER_NAME" id="CUSTOMER_NAME" value="<%=CommonUtils.checkNull(info.get("CUSTOMER_NAME"))%>" readonly></td>
</tr>
<tr>
<td class="label">모델명</td>
<td><input type="text" name="MODEL_NAME" id="MODEL_NAME" value="<%=CommonUtils.checkNull(info.get("MODEL_NAME"))%>" readonly></td>
<td class="label">제품명</td>
<td><input type="text" name="PRODUCT_NAME" id="PRODUCT_NAME" value="<%=CommonUtils.checkNull(info.get("PRODUCT_NAME"))%>" readonly></td>
<td class="label">품번</td>
<td><input type="text" name="PART_NO" id="PART_NO" value="<%=CommonUtils.checkNull(info.get("PART_NO"))%>" readonly></td>
</tr>
<tr>
<td class="label">불만내용</td>
<td colspan="5"><textarea name="COMPLAINT_CONTENT" id="COMPLAINT_CONTENT" rows="2" style="width:100%;" readonly><%=CommonUtils.checkNull(info.get("COMPLAINT_CONTENT"))%></textarea></td>
</tr>
</tbody>
</table>
<h3 style="margin:20px 0 10px 0;">■ 조치 정보</h3>
<table class="plm_form_table">
<colgroup>
<col width="100px"><col width="*">
<col width="100px"><col width="*">
<col width="100px"><col width="*">
</colgroup>
<tbody>
<tr>
<td class="label">조치일</td>
<td><input type="text" name="ACTION_DATE" id="ACTION_DATE" class="date_icon" value="<%=CommonUtils.checkNull(info.get("ACTION_DATE"))%>"></td>
<td class="label">조치자</td>
<td><input type="text" name="ACTION_USER_NAME" id="ACTION_USER_NAME" value="<%=CommonUtils.checkNull(info.get("ACTION_USER_NAME"))%>"></td>
<td class="label">상태</td>
<td>
<select name="STATUS" id="STATUS">
<option value="접수" <%="접수".equals(info.get("STATUS"))?"selected":""%>>접수</option>
<option value="처리중" <%="처리중".equals(info.get("STATUS"))?"selected":""%>>처리중</option>
<option value="완료" <%="완료".equals(info.get("STATUS"))?"selected":""%>>완료</option>
</select>
</td>
</tr>
<tr>
<td class="label">귀책판정</td>
<td>
<select name="BLAME_DECISION" id="BLAME_DECISION">
<option value="">선택</option>
<option value="자사" <%="자사".equals(info.get("BLAME_DECISION"))?"selected":""%>>자사</option>
<option value="고객" <%="고객".equals(info.get("BLAME_DECISION"))?"selected":""%>>고객</option>
<option value="협력사" <%="협력사".equals(info.get("BLAME_DECISION"))?"selected":""%>>협력사</option>
</select>
</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td class="label">조치내용</td>
<td colspan="5"><textarea name="ACTION_CONTENT" id="ACTION_CONTENT" rows="3" style="width:100%;"><%=CommonUtils.checkNull(info.get("ACTION_CONTENT"))%></textarea></td>
</tr>
<tr>
<td class="label">비고</td>
<td colspan="5"><textarea name="REMARK" id="REMARK" rows="2" style="width:100%;"><%=CommonUtils.checkNull(info.get("REMARK"))%></textarea></td>
</tr>
</tbody>
</table>
</div>
<div class="btn_wrap">
<div class="plm_btn_wrap_center">
<input type="button" value="저장" id="btnSave" class="plm_btns">
<input type="button" value="닫기" id="btnClose" class="plm_btns">
</div>
</div>
</section>
</form>
</body>
</html>

View File

@@ -3,21 +3,40 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page import="com.pms.common.utils.*"%>
<%@ page import="java.util.*" %>
<%@include file= "/init.jsp" %>
<%@include file= "/init_new.jsp" %>
<%
String menuObjId = request.getParameter("menuObjId");
String menuName = CommonUtils.getMenuName(menuObjId, "고객 불량 등록");
String actionType = CommonUtils.checkNull(request.getParameter("actionType"));
// OBJID가 없으면 신규 생성 (첨부파일 연결용)
String objId = CommonUtils.checkNull(request.getAttribute("info") != null ? ((Map)request.getAttribute("info")).get("objid") : "");
boolean isNew = objId.isEmpty() || "new".equals(actionType);
if(objId.isEmpty()){
objId = String.valueOf(CommonUtils.createObjId());
}
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<style>
body { min-height: auto !important; }
</style>
</head>
<script type="text/javascript">
$(document).ready(function(){
fnc_datepick();
$('.select2').select2();
// 수정 모드인 경우 기존 값 선택
var savedBlameDecision = "${info.blame_decision}";
var savedStatus = "${info.status}";
if(savedBlameDecision) $("#BLAME_DECISION").val(savedBlameDecision).trigger('change');
if(savedStatus) $("#STATUS").val(savedStatus).trigger('change');
// 저장
$("#btnSave").click(function(){
@@ -30,88 +49,173 @@ $(document).ready(function(){
});
});
// PDF 미리보기
function fnc_viewPdfFile(fileObjId){
window.open("/common/downloadFile.do?objId=" + fileObjId, "_blank");
}
function fn_save(){
// TODO: 저장 로직 구현
Swal.fire("저장 기능 준비중입니다.");
// 유효성 검사
if(!fnc_valitate("form1")){
return;
}
Swal.fire({
title: '저장하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '저장',
cancelButtonText: '취소'
}).then((result) => {
if(result.isConfirmed){
$.ajax({
url: "/quality/saveCustomerCsDefect.do",
type: "POST",
data: $("#form1").serialize(),
dataType: "json",
success: function(result){
if(result.RESULT == "SUCCESS"){
Swal.fire({
title: '저장되었습니다.',
icon: 'success'
}).then(() => {
if(window.opener && window.opener.fn_search){
window.opener.fn_search();
}
window.close();
});
} else {
Swal.fire({
title: '저장 실패',
text: result.MESSAGE || '저장 중 오류가 발생했습니다.',
icon: 'error'
});
}
},
error: function(xhr, status, error){
Swal.fire({
title: '저장 실패',
text: '서버 통신 오류가 발생했습니다.',
icon: 'error'
});
}
});
}
});
}
</script>
<body>
<form name="form1" id="form1" method="post">
<div class="popup_wrap">
<div class="popup_header">
<h2><%=menuName%></h2>
<div class="btnArea">
<input type="button" class="plm_btns" value="저장" id="btnSave">
<input type="button" class="plm_btns" value="닫기" id="btnClose">
</div>
<input type="hidden" name="OBJID" id="OBJID" value="<%=objId%>">
<input type="hidden" name="ATTACH_FILE_OBJID" id="ATTACH_FILE_OBJID" value="<%=objId%>">
<input type="hidden" name="IS_NEW" id="IS_NEW" value="<%=isNew%>">
<section class="business_staff_popup_min_width">
<div class="plm_menu_name">
<h2>
<span><%=menuName%></span>
</h2>
</div>
<div id="EntirePopupFormWrap">
<div class="form_popup_title">
<span>기본정보</span>
</div>
<div class="popup_content">
<table class="plm_form_table">
<colgroup>
<col width="100px"><col width="*">
<col width="100px"><col width="*">
<col width="100px"><col width="*">
</colgroup>
<tbody>
<tr>
<td class="label">접수일</td>
<td><input type="text" name="RECEIPT_DATE" id="RECEIPT_DATE" class="date_icon"></td>
<td class="label">수량</td>
<td><input type="text" name="QTY" id="QTY"></td>
<td class="label">고객사</td>
<td><input type="text" name="CUSTOMER_NAME" id="CUSTOMER_NAME"></td>
</tr>
<tr>
<td class="label">모델명</td>
<td><input type="text" name="MODEL_NAME" id="MODEL_NAME"></td>
<td class="label">제품명</td>
<td><input type="text" name="PRODUCT_NAME" id="PRODUCT_NAME"></td>
<td class="label">품번</td>
<td><input type="text" name="PART_NO" id="PART_NO"></td>
</tr>
<tr>
<td class="label">생산일</td>
<td><input type="text" name="PRODUCTION_DATE" id="PRODUCTION_DATE" class="date_icon"></td>
<td class="label">판매일</td>
<td><input type="text" name="SALES_DATE" id="SALES_DATE" class="date_icon"></td>
<td class="label">S/N</td>
<td><input type="text" name="SERIAL_NO" id="SERIAL_NO"></td>
</tr>
<tr>
<td class="label">제조사</td>
<td><input type="text" name="MANUFACTURER" id="MANUFACTURER"></td>
<td class="label">귀책판정</td>
<td>
<select name="BLAME_DECISION" id="BLAME_DECISION">
<option value="">선택</option>
<option value="자사">자사</option>
<option value="고객">고객</option>
<option value="협력사">협력사</option>
</select>
</td>
<td class="label">상태</td>
<td>
<select name="STATUS" id="STATUS">
<option value="접수">접수</option>
<option value="처리중">처리중</option>
<option value="완료">완료</option>
</select>
</td>
</tr>
<tr>
<td class="label">불만내용</td>
<td colspan="5"><textarea name="COMPLAINT_CONTENT" id="COMPLAINT_CONTENT" rows="3" style="width:100%;"></textarea></td>
</tr>
<tr>
<td class="label">비고</td>
<td colspan="5"><textarea name="REMARK" id="REMARK" rows="2" style="width:100%;"></textarea></td>
</tr>
</tbody>
</table>
<table class="pmsPopupForm">
<colgroup>
<col width="15%" />
<col width="35%" />
<col width="15%" />
<col width="35%" />
</colgroup>
<tr>
<td class="input_title"><label>접수일 <span style="color:red;">*</span></label></td>
<td>
<input type="text" name="RECEIPT_DATE" id="RECEIPT_DATE" class="date_icon" required reqTitle="접수일" value="${info.receipt_date}">
</td>
<td class="input_title"><label>수량 <span style="color:red;">*</span></label></td>
<td>
<input type="text" name="QTY" id="QTY" value="${info.qty}" required reqTitle="수량">
</td>
</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%;">
<option value="">선택</option>
${code_map.customer_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="모델명">
</td> -->
</tr>
<tr>
<td class="input_title"><label>품명 <span style="color:red;">*</span></label></td>
<td>
<input type="text" name="PRODUCT_NAME" id="PRODUCT_NAME" value="${info.product_name}" required reqTitle="품명">
</td>
<td class="input_title"><label>품번 <span style="color:red;">*</span></label></td>
<td>
<input type="text" name="PRODUCT_NO" id="PRODUCT_NO" value="${info.product_no}" required reqTitle="품번">
</td>
</tr>
<tr>
<td class="input_title"><label>부품품명 <span style="color:red;">*</span></label></td>
<td>
<input type="text" name="PART_NAME" id="PART_NAME" value="${info.part_name}" required reqTitle="부품품명">
</td>
<td class="input_title"><label>부품품번 <span style="color:red;">*</span></label></td>
<td>
<input type="text" name="PART_NO" id="PART_NO" value="${info.part_no}" required reqTitle="부품품번">
</td>
</tr>
<tr>
<td class="input_title"><label>생산일</label></td>
<td>
<input type="text" name="PRODUCTION_DATE" id="PRODUCTION_DATE" class="date_icon" value="${info.production_date}">
</td>
<td class="input_title"><label>판매일</label></td>
<td>
<input type="text" name="SALES_DATE" id="SALES_DATE" class="date_icon" value="${info.sales_date}">
</td>
</tr>
<tr>
<td class="input_title"><label>S/N</label></td>
<td>
<input type="text" name="SERIAL_NO" id="SERIAL_NO" value="${info.serial_no}">
</td>
<td class="input_title"><label>제조사</label></td>
<td>
<input type="text" name="MANUFACTURER" id="MANUFACTURER" value="${info.manufacturer}">
</td>
</tr>
<tr>
<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>
</tr>
</table>
</div>
<div class="btn_wrap">
<div class="plm_btn_wrap_center">
<input type="button" value="저장" id="btnSave" class="plm_btns">
<input type="button" value="닫기" id="btnClose" class="plm_btns">
</div>
</div>
</section>
</form>
</body>
</html>

View File

@@ -22,11 +22,12 @@ String menuName = CommonUtils.getMenuName(menuObjId, "고객 CS 관리");
.status-receipt { color: #007bff; font-weight: bold; }
.status-progress { color: #ffc107; font-weight: bold; }
.status-complete { color: #28a745; font-weight: bold; }
/* 검색필터 아이템 스타일 */
.search-item { display: flex; align-items: center; gap: 5px; }
.search-item label { font-weight: bold; white-space: nowrap; min-width: 60px; }
.search-item input, .search-item select { height: 28px; }
body, html {
overflow-x: hidden;
width: 100%;
margin: 0;
padding: 0;
}
</style>
<script type="text/javascript">
@@ -61,17 +62,42 @@ $(document).ready(function(){
fn_search();
});
// 접수번호 클릭 시 조치결과 뷰 팝업
function fn_viewActionPopUp(objId){
var popup_width = 1200;
var popup_height = 600;
var hiddenForm = document.hiddenForm;
var target = "customerCsActionViewPopUp";
var url = "/quality/customerCsActionFormPopUp.do";
fn_centerPopup(popup_width, popup_height, "", target);
hiddenForm.action = url;
hiddenForm.OBJID.value = objId;
hiddenForm.actionType.value = 'view'; // 뷰 모드
hiddenForm.target = target;
hiddenForm.submit();
}
// 컬럼: 접수번호, 접수일, 수량, 고객사, 모델명, 제품명, 품번, 생산일, 판매일, S/N, 제조사, 불만내용, 조치내용, 귀책판정, 상태, 비고, 조치일, 조치자, 첨부파일
var columns = [
{headerHozAlign:'center', hozAlign:'center', minWidth:110, widthGrow:1, title:'접수번호', field:'RECEIPT_NO'},
{headerHozAlign:'center', hozAlign:'center', minWidth:120, widthGrow:1, title:'접수번호', field:'RECEIPT_NO', frozen: true,
formatter:fnc_createGridAnchorTag,
cellClick: function(e, cell){
var objId = fnc_checkNull(cell.getData().OBJID);
fn_viewActionPopUp(objId);
}
},
{headerHozAlign:'center', hozAlign:'center', minWidth:100, widthGrow:1, title:'접수일', field:'RECEIPT_DATE'},
{headerHozAlign:'center', hozAlign:'right', minWidth:70, widthGrow:1, title:'수량', field:'QTY',
formatter:"money", formatterParams:{thousand:",", precision:false}
},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'고객사', field:'CUSTOMER_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'모델명', field:'MODEL_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:100, widthGrow:1, title:'품명', field:'PRODUCT_NAME'},
{headerHozAlign:'center', hozAlign:'left', minWidth:150, widthGrow:1, title:'고객사', field:'CUSTOMER_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:'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'},
@@ -91,17 +117,18 @@ 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:70, widthGrow:1, title:'첨부파일', field:'ATTACH_FILE',
formatter: function(cell, formatterParams, onRendered){
var fileYn = fnc_checkNull(cell.getValue());
if(fileYn === 'Y'){
return '<a href="#" class="file_icon" style="display:inline-block; width:20px; height:20px;"></a>';
}
return '<a href="#" class="file_empty_icon" style="display:inline-block; width:20px; height:20px;"></a>';
},
{headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'이미지', field:'IMAGE_FILE',
formatter:fnc_subInfoValueFormatter,
cellClick:function(e, cell){
var objId = fnc_checkNull(cell.getData().OBJID);
fn_openAttachFilePopUp(objId);
fn_openImageFilePopUp(objId);
}
},
{headerHozAlign:'center', hozAlign:'center', minWidth:80, widthGrow:1, title:'첨부파일', field:'ATTACH_FILE',
formatter:fnc_subInfoValueFormatter,
cellClick:function(e, cell){
var objid = fnc_checkNull(cell.getData().OBJID);
fn_FileRegist(objid,"CUSTOMER_CS_ACTION","조치첨부");
}
}
];
@@ -130,8 +157,10 @@ function fn_reset(){
// 고객 불량 등록 팝업
function fn_registDefectPopUp(){
var popup_width = 1200;
var popup_height = 800;
var selected = _tabulGrid.getSelectedData();
var popup_width = 800;
var popup_height = 450;
var hiddenForm = document.hiddenForm;
var target = "customerCsDefectPopUp";
var url = "/quality/customerCsDefectFormPopUp.do";
@@ -139,7 +168,14 @@ function fn_registDefectPopUp(){
fn_centerPopup(popup_width, popup_height, "", target);
hiddenForm.action = url;
hiddenForm.actionType.value = 'new';
// 선택된 행이 있으면 수정 모드, 없으면 신규 등록
if(selected.length == 1){
hiddenForm.OBJID.value = selected[0].OBJID;
hiddenForm.actionType.value = 'edit';
} else {
hiddenForm.OBJID.value = '';
hiddenForm.actionType.value = 'new';
}
hiddenForm.target = target;
hiddenForm.submit();
}
@@ -157,7 +193,7 @@ function fn_registActionPopUp(){
}
var popup_width = 1200;
var popup_height = 800;
var popup_height = 600;
var hiddenForm = document.hiddenForm;
var target = "customerCsActionPopUp";
var url = "/quality/customerCsActionFormPopUp.do";
@@ -171,12 +207,26 @@ function fn_registActionPopUp(){
hiddenForm.submit();
}
// 이미지 파일 팝업
function fn_openImageFilePopUp(objId){
var popup_width = 650;
var popup_height = 550;
var url = "/common/ImageRegistPopup.do?targetObjId=" + objId + "&docType=CUSTOMER_CS_IMAGE&docTypeName=이미지";
window.open(url, "imageFilePopUp", "width="+popup_width+",height="+popup_height+",scrollbars=yes,resizable=yes");
}
// 첨부파일 팝업
function fn_openAttachFilePopUp(objId){
var popup_width = 800;
var popup_height = 600;
var url = "/common/filePopUp.do?OBJID=" + objId + "&FILE_TYPE=ATTACH";
window.open(url, "attachFilePopUp", "width="+popup_width+",height="+popup_height+",scrollbars=yes,resizable=yes");
function fn_FileRegist(objId, docType, docTypeName){
var popup_width = 800;
var popup_height = 300;
var objId = objId;
var docType = docType;
var docTypeName = docTypeName;
var params = "?targetObjId="+objId+"&docType="+docType+"&docTypeName="+docTypeName;
var url = "/projectConcept/FileRegistPopup.do"+params;
fn_centerPopup(popup_width, popup_height, url);
}
</script>
@@ -201,66 +251,63 @@ function fn_openAttachFilePopUp(objId){
</div>
<div id="plmSearchZon">
<div style="display:flex; flex-wrap:wrap; gap:10px; align-items:center;">
<div class="search-item">
<label>접수일</label>
<input type="text" name="search_receipt_date_from" id="search_receipt_date_from" class="date_icon" style="width:100px;" autocomplete="off">
<span>~</span>
<input type="text" name="search_receipt_date_to" id="search_receipt_date_to" class="date_icon" style="width:100px;" autocomplete="off">
</div>
<div class="search-item">
<label>고객사</label>
<input type="text" name="search_customer_name" id="search_customer_name" style="width:100px;" autocomplete="off">
</div>
<div class="search-item">
<label>모델명</label>
<input type="text" name="search_model_name" id="search_model_name" style="width:100px;" autocomplete="off">
</div>
<div class="search-item">
<label>품명</label>
<input type="text" name="search_product_name" id="search_product_name" style="width:100px;" autocomplete="off">
</div>
<div class="search-item">
<label>품번</label>
<input type="text" name="search_part_no" id="search_part_no" style="width:100px;" autocomplete="off">
</div>
<div class="search-item">
<label>S/N</label>
<input type="text" name="search_serial_no" id="search_serial_no" style="width:100px;" autocomplete="off">
</div>
<div class="search-item">
<label>제조사</label>
<input type="text" name="search_manufacturer" id="search_manufacturer" style="width:100px;" autocomplete="off">
</div>
<div class="search-item">
<label>귀책판정</label>
<select name="search_blame_decision" id="search_blame_decision" style="width:90px;">
<option value="">전체</option>
<option value="자사">자사</option>
<option value="고객">고객</option>
<option value="협력사">협력사</option>
</select>
</div>
<div class="search-item">
<label>상태</label>
<select name="search_status" id="search_status" style="width:90px;">
<option value="">전체</option>
<option value="접수">접수</option>
<option value="처리중">처리중</option>
<option value="완료">완료</option>
</select>
</div>
<div class="search-item">
<label>조치일</label>
<input type="text" name="search_action_date_from" id="search_action_date_from" class="date_icon" style="width:100px;" autocomplete="off">
<span>~</span>
<input type="text" name="search_action_date_to" id="search_action_date_to" class="date_icon" style="width:100px;" autocomplete="off">
</div>
<div class="search-item">
<label>조치자</label>
<input type="text" name="search_action_user" id="search_action_user" style="width:100px;" autocomplete="off">
</div>
</div>
<table class="">
<tr>
<td><label>접수일</label></td>
<td>
<input type="text" name="search_receipt_date_from" id="search_receipt_date_from" class="date_icon" style="width:100px;" autocomplete="off">~
<input type="text" name="search_receipt_date_to" id="search_receipt_date_to" class="date_icon" style="width:100px;" autocomplete="off">
</td>
<td><label>고객사</label></td>
<td>
<select name="search_customer_objid" id="search_customer_objid" class="select2" autocomplete="off" style="width:230px;">
<option value="">전체</option>
${code_map.customer_cd}
</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>
<td><input type="text" name="search_product_name" id="search_product_name" style="" autocomplete="off"></td>
<td><label>부품품번</label></td>
<td><input type="text" name="search_part_no" id="search_part_no" style="width:215px;" autocomplete="off"></td>
<td><label>부품품명</label></td>
<td><input type="text" name="search_part_name" id="search_part_name" style="" autocomplete="off"></td>
</tr>
<tr>
<td><label>S/N</label></td>
<td><input type="text" name="search_serial_no" id="search_serial_no" style="width:215px;" autocomplete="off"></td>
<td><label>제조사</label></td>
<td><input type="text" name="search_manufacturer" id="search_manufacturer" style="width:230px;" autocomplete="off"></td>
<td><label>귀책판정</label></td>
<td>
<select name="search_blame_decision" id="search_blame_decision" class="select2" autocomplete="off" style="">
<option value="">전체</option>
<option value="R">R</option>
<option value="C">C</option>
<option value="O">O</option>
</select>
</td>
<td><label>상태</label></td>
<td>
<select name="search_status" id="search_status" class="select2" autocomplete="off" style="">
<option value="">전체</option>
<option value="Open">Open</option>
<option value="Closed">Closed</option>
</select>
</td>
<td><label>조치일</label></td>
<td>
<input type="text" name="search_action_date_from" id="search_action_date_from" class="date_icon" style="width:100px;" autocomplete="off">~
<input type="text" name="search_action_date_to" id="search_action_date_to" class="date_icon" style="width:100px;" autocomplete="off">
</td>
<td><label>조치자</label></td>
<td><input type="text" name="search_action_user" id="search_action_user" style="" autocomplete="off"></td>
</tr>
</table>
</div>
<%@include file= "/WEB-INF/view/common/common_gridArea.jsp" %>

View File

@@ -43,6 +43,13 @@ String menuName = CommonUtils.getMenuName(menuObjId, "수입검사 관리");
.inspection-ng { color: #dc3545; font-weight: bold; cursor: pointer; }
.inspection-ok { color: #28a745; font-weight: bold; cursor: pointer; }
.inspection-ng:hover, .inspection-ok:hover { text-decoration: underline; }
body, html {
overflow-x: hidden;
width: 100%;
margin: 0;
padding: 0;
}
</style>
<script type="text/javascript">

View File

@@ -18,6 +18,12 @@ String menuName = CommonUtils.getMenuName(menuObjId, "공정검사 관리");
</head>
<style>
body, html {
overflow-x: hidden;
width: 100%;
margin: 0;
padding: 0;
}
.select2-selection__choice {
font-size: 11px;
background-color: #fff !important;

View File

@@ -0,0 +1,68 @@
<%@ page import="java.io.*, java.util.*" %>
<%@ page import="java.net.URLEncoder"%>
<%!
public void viewImage(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
// request attribute에서 파일 정보 가져오기 (컨트롤러에서 설정)
String attDir = (String) req.getAttribute("attDir");
String savedFileName = (String) req.getAttribute("savedFileName");
String realFileName = (String) req.getAttribute("realFileName");
if(attDir == null || savedFileName == null) {
System.out.println("viewImageByObjId: 파일 정보 없음");
return;
}
FileInputStream fis = null;
// 헤더 컨텐츠 타입 설정
res.reset();
// 파일 확장자로 컨텐츠 타입 결정
String ext = "";
if(savedFileName.lastIndexOf(".") > -1) {
ext = savedFileName.substring(savedFileName.lastIndexOf(".") + 1).toLowerCase();
}
if("png".equals(ext)) {
res.setContentType("image/png");
} else if("gif".equals(ext)) {
res.setContentType("image/gif");
} else if("bmp".equals(ext)) {
res.setContentType("image/bmp");
} else if("webp".equals(ext)) {
res.setContentType("image/webp");
} else {
res.setContentType("image/jpeg");
}
ServletOutputStream out = res.getOutputStream();
try {
File file = new File(attDir, savedFileName);
System.out.println("viewImageByObjId: " + file.getAbsolutePath());
fis = new FileInputStream(file);
byte[] buf = new byte[4 * 1024];
int bytesRead;
while((bytesRead = fis.read(buf)) != -1) {
out.write(buf, 0, bytesRead);
}
} catch(FileNotFoundException e) {
out.println("File Not Found");
System.out.println("viewImageByObjId File Not Found: attDir[" + attDir + "] savedFileName[" + savedFileName + "]");
} catch(IOException e) {
out.println("Problem sending file: " + e.getMessage());
System.out.println("viewImageByObjId Problem sending file: " + e.getMessage());
} finally {
if(fis != null) {
fis.close();
}
}
}
%>
<%
out.clear();
out = pageContext.pushBody();
viewImage(request, response);
%>