Files
wace_plm/WebContent/WEB-INF/view/salesMng/quotationRequestFormPopup.jsp

528 lines
13 KiB
Plaintext

<%@ 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>
<script type="text/javascript" src="/js/tabulator/tabulator_custom.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.header {
padding: 15px 20px;
background: #f5f5f5;
border-bottom: 2px solid #ddd;
}
.header h3 {
margin: 0 0 10px 0;
color: #333;
}
.info-table {
width: 100%;
border-collapse: collapse;
background: #fff;
border: 1px solid #ddd;
}
.info-table td {
padding: 8px 15px;
border: 1px solid #eee;
}
.info-table label {
font-weight: bold;
color: #555;
margin-right: 8px;
}
.info-table span {
color: #333;
}
.content {
flex: 1;
padding: 20px;
overflow: auto;
}
.status-badge {
display: inline-block;
padding: 3px 10px;
border-radius: 3px;
font-size: 12px;
font-weight: bold;
}
.status-create { background: #e3f2fd; color: #1976d2; }
.status-sent { background: #fff3e0; color: #f57c00; }
.status-received { background: #e8f5e9; color: #388e3c; }
.status-completed { background: #f3e5f5; color: #7b1fa2; }
.vendor-type-badge {
display: inline-block;
padding: 2px 8px;
border-radius: 3px;
font-size: 11px;
font-weight: bold;
}
.vendor-supply { background: #e3f2fd; color: #1976d2; }
.vendor-processing { background: #e8f5e9; color: #388e3c; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div style="float: left;">
<h3 style="margin: 0;">
견적요청서
<c:if test="${not empty resultMap.QUOTATION_REQUEST_NO}">
- ${resultMap.QUOTATION_REQUEST_NO}
</c:if>
<c:choose>
<c:when test="${resultMap.STATUS eq 'create'}">
<span class="status-badge status-create">작성중</span>
</c:when>
<c:when test="${resultMap.STATUS eq 'sent'}">
<span class="status-badge status-sent">발송완료</span>
</c:when>
<c:when test="${resultMap.STATUS eq 'received'}">
<span class="status-badge status-received">견적수신</span>
</c:when>
<c:when test="${resultMap.STATUS eq 'completed'}">
<span class="status-badge status-completed">완료</span>
</c:when>
</c:choose>
</h3>
</div>
<div style="float: right;">
<input type="button" value="저장" class="plm_btns" onclick="fn_save();" style="margin-right: 5px;">
<input type="button" value="닫기" class="plm_btns" onclick="window.close();">
</div>
<div style="clear: both;"></div>
<!-- 프로젝트/업체 정보 -->
<table class="info-table" style="margin-top: 15px;">
<tr>
<td style="width:25%;">
<label>프로젝트번호:</label>
<span id="infoProjectNo">${resultMap.PROJECT_NO}</span>
</td>
<td style="width:25%;">
<label>구매유형:</label>
<span id="infoPurchaseType">${resultMap.PURCHASE_TYPE_NAME}</span>
</td>
<td style="width:25%;">
<label>주문유형:</label>
<span id="infoOrderType">${resultMap.ORDER_TYPE_NAME}</span>
</td>
<td style="width:25%;">
<label>제품구분:</label>
<span id="infoProductName">${resultMap.PRODUCT_NAME_TITLE}</span>
</td>
</tr>
<tr>
<td>
<label>요청번호:</label>
<span id="infoRequestNo">${resultMap.REQUEST_MNG_NO}</span>
</td>
<td colspan="2">
<label>업체명:</label>
<span id="infoVendorName" style="font-weight: bold; color: #1976d2;">${resultMap.VENDOR_NAME}</span>
<c:choose>
<c:when test="${resultMap.VENDOR_TYPE eq 'SUPPLY'}">
<span class="vendor-type-badge vendor-supply">공급업체</span>
</c:when>
<c:when test="${resultMap.VENDOR_TYPE eq 'PROCESSING'}">
<span class="vendor-type-badge vendor-processing">가공업체</span>
</c:when>
</c:choose>
</td>
<td>
<label>업체 이메일:</label>
<span id="infoVendorEmail">${resultMap.VENDOR_EMAIL}</span>
</td>
</tr>
<c:if test="${not empty resultMap.MAIL_SEND_DATE_TITLE}">
<tr>
<td colspan="4">
<label>메일발송일:</label>
<span id="infoMailSendDate" style="color: green;">${resultMap.MAIL_SEND_DATE_TITLE}</span>
</td>
</tr>
</c:if>
</table>
</div>
<div class="content">
<div style="margin-bottom: 20px;">
<%-- 업체유형 설명 주석처리
<c:choose>
<c:when test="${resultMap.VENDOR_TYPE eq 'SUPPLY'}">
<span style="font-weight: bold; color: #1976d2;">공급업체 견적 - 품번/품명/제작수량 기준</span>
</c:when>
<c:when test="${resultMap.VENDOR_TYPE eq 'PROCESSING'}">
<span style="font-weight: bold; color: #388e3c;">가공업체 견적 - 소재품번/소재재질/규격/발주수량 기준</span>
</c:when>
</c:choose>
--%>
<span style="float: right; color: #666; font-size: 12px;">
* 단가 입력 후 저장하면 구매리스트에 자동 반영됩니다.
</span>
</div>
<div id="quotationDetailTable"></div>
</div>
</div>
<script>
var _tabulGrid;
var quotationRequestMasterObjid = "${resultMap.OBJID}";
var vendorType = "${resultMap.VENDOR_TYPE}";
var currentStatus = "${resultMap.STATUS}";
$(document).ready(function(){
fn_initGrid();
fn_loadDetailList();
});
// 그리드 초기화
function fn_initGrid() {
var columns = [];
// 공통 컬럼
columns.push({title:'OBJID', field:'OBJID', visible:false});
columns.push({title:'SALES_REQUEST_PART_OBJID', field:'SALES_REQUEST_PART_OBJID', visible:false});
columns.push({title:'PART_OBJID', field:'PART_OBJID', visible:false});
// No
columns.push({
headerHozAlign: 'center',
hozAlign: 'center',
width: 50,
title: 'No',
field: 'ROW_NUM',
formatter: "rownum"
});
// 업체유형에 따라 다른 컬럼 표시
if(vendorType === 'PROCESSING') {
// 가공업체: 품번, 품명, 규격(없음), 제작수량
columns.push({
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 2,
title: '품번',
field: 'PART_NO'
});
columns.push({
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 3,
title: '품명',
field: 'PART_NAME'
});
columns.push({
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '규격',
field: 'SIZE',
formatter: function(cell) {
return '-';
}
});
columns.push({
headerHozAlign: 'center',
hozAlign: 'right',
width: 100,
title: '제작수량',
field: 'QTY',
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
});
} else {
// 공급업체: 소재품번, 소재재질, 규격, 발주수량
columns.push({
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 2,
title: '소재품번',
field: 'PART_NO'
});
columns.push({
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 2,
title: '소재재질',
field: 'RAW_MATERIAL'
});
columns.push({
headerHozAlign: 'center',
hozAlign: 'left',
width: 120,
title: '규격',
field: 'SIZE'
});
columns.push({
headerHozAlign: 'center',
hozAlign: 'right',
width: 100,
title: '발주수량',
field: 'QTY',
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
});
}
// 업체명
columns.push({
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 1.5,
title: vendorType === 'PROCESSING' ? '가공업체' : '공급업체',
field: 'VENDOR_NAME'
});
// 환종
columns.push({
headerHozAlign: 'center',
hozAlign: 'center',
width: 70,
title: '환종',
field: 'CURRENCY_NAME'
});
// 단가 (수정가능 - 클릭 시 전체 선택)
columns.push({
headerHozAlign: 'center',
hozAlign: 'right',
width: 120,
title: '<span style="background-color: #FFFF00; padding: 2px 5px;">단가</span>',
field: 'UNIT_PRICE',
editor: function(cell, onRendered, success, cancel) {
var input = document.createElement("input");
input.type = "number";
input.style.width = "100%";
input.style.boxSizing = "border-box";
input.style.textAlign = "right";
input.value = cell.getValue() || '';
onRendered(function() {
input.focus();
input.select();
});
function onComplete() {
var val = input.value;
success(val !== '' ? Number(val) : 0);
}
input.addEventListener("blur", onComplete);
input.addEventListener("keydown", function(e) {
if(e.keyCode === 13) onComplete();
if(e.keyCode === 27) cancel();
});
return input;
},
editable: true,
formatter: function(cell) {
var value = cell.getValue();
return value ? Number(value).toLocaleString() : '0';
}
});
// 입고요청일 (수정가능 - datepicker + 복사/붙여넣기 지원)
columns.push({
headerHozAlign: 'center',
hozAlign: 'center',
width: 130,
title: '<span style="background-color: #FFFF00; padding: 2px 5px;">입고요청일</span>',
field: 'DELIVERY_REQUEST_DATE',
editor: function(cell, onRendered, success, cancel) {
var input = document.createElement("input");
input.type = "text";
input.style.width = "100%";
input.style.boxSizing = "border-box";
input.style.textAlign = "center";
input.value = cell.getValue() || '';
var isCompleted = false;
function onComplete(val) {
if(isCompleted) return;
isCompleted = true;
try { $(input).datepicker("hide"); $(input).datepicker("destroy"); } catch(e) {}
success(val);
}
onRendered(function() {
$(input).datepicker({
dateFormat: 'yy-mm-dd',
changeMonth: true,
changeYear: true,
onSelect: function(dateText) {
onComplete(dateText);
},
onClose: function() {
onComplete(input.value);
}
});
input.focus();
input.select();
});
input.addEventListener("keydown", function(e) {
if(e.keyCode === 13) { e.preventDefault(); onComplete(input.value); }
if(e.keyCode === 27) cancel();
});
return input;
},
editable: true
});
// // 총단가 (자동계산) - 주석처리
// columns.push({
// headerHozAlign: 'center',
// hozAlign: 'right',
// width: 120,
// title: '총단가',
// field: 'TOTAL_PRICE',
// formatter: function(cell) {
// var data = cell.getRow().getData();
// var qty = parseFloat(data.QTY) || 0;
// var unitPrice = parseFloat(data.UNIT_PRICE) || 0;
// var totalPrice = qty * unitPrice;
// return totalPrice > 0 ? totalPrice.toLocaleString() : '0';
// }
// });
// // 비고 - 주석처리
// columns.push({
// headerHozAlign: 'center',
// hozAlign: 'left',
// widthGrow: 2,
// title: '비고',
// field: 'REMARK',
// editor: 'input',
// editable: true
// });
_tabulGrid = new Tabulator("#quotationDetailTable", {
layout: "fitColumns",
height: "calc(100vh - 300px)",
columns: columns,
data: [],
placeholder: "데이터가 없습니다."
});
// 셀 편집 이벤트 (총단가 자동 계산)
_tabulGrid.on("cellEdited", function(cell) {
var field = cell.getField();
var row = cell.getRow();
if(field === 'UNIT_PRICE') {
row.reformat();
}
});
}
// 상세 목록 조회
function fn_loadDetailList() {
if(!quotationRequestMasterObjid || quotationRequestMasterObjid === '') {
return;
}
$.ajax({
url: "/salesMng/getQuotationRequestDetailList.do",
method: 'post',
data: {
QUOTATION_REQUEST_MASTER_OBJID: quotationRequestMasterObjid
},
dataType: 'json',
success: function(data) {
if(data && data.list) {
_tabulGrid.setData(data.list);
}
},
error: function(jqxhr, status, error){
console.error("상세 목록 조회 오류:", error);
Swal.fire({
title: '오류',
text: '상세 목록 조회 중 오류가 발생했습니다.',
icon: 'error'
});
}
});
}
// 저장
function fn_save() {
var gridData = _tabulGrid.getData();
if(!gridData || gridData.length === 0) {
Swal.fire({
title: '알림',
text: '저장할 데이터가 없습니다.',
icon: 'warning'
});
return;
}
Swal.fire({
title: '확인',
text: '저장하시겠습니까?\n단가가 구매리스트에 자동 반영됩니다.',
icon: 'question',
showCancelButton: true,
confirmButtonText: '확인',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
url: "/salesMng/saveQuotationRequestPrice.do",
method: 'post',
data: {
QUOTATION_REQUEST_MASTER_OBJID: quotationRequestMasterObjid,
DETAIL_LIST: JSON.stringify(gridData)
},
dataType: 'json',
success: function(data) {
if(data && (data.resultFlag === 'S' || data.RESULTFLAG === 'S')) {
Swal.fire({
title: '성공',
text: data.message || '저장되었습니다.',
icon: 'success'
}).then(() => {
if(opener && opener.fn_search) {
opener.fn_search();
}
});
} else {
Swal.fire({
title: '실패',
text: data.message || data.MESSAGE || '저장에 실패했습니다.',
icon: 'error'
});
}
},
error: function(jqxhr, status, error){
console.error("저장 오류:", error);
Swal.fire({
title: '오류',
text: '저장 중 오류가 발생했습니다.',
icon: 'error'
});
}
});
}
});
}
</script>
</body>
</html>