1551 lines
52 KiB
Plaintext
1551 lines
52 KiB
Plaintext
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
|
<%@ page import="com.pms.common.utils.*"%>
|
|
<%@ page import="java.util.*" %>
|
|
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
|
|
<%@include file= "/init.jsp" %>
|
|
<%
|
|
// init.jsp에서 이미 connectUserName이 설정되어 있음
|
|
String userName = connectUserName;
|
|
String userId = connectUserId;
|
|
|
|
// 전화번호는 별도로 조회 필요
|
|
String userPhone = "";
|
|
try {
|
|
com.pms.common.SqlMapConfig sqlMapConfig = com.pms.common.SqlMapConfig.getInstance();
|
|
org.apache.ibatis.session.SqlSession sqlSession = sqlMapConfig.getSqlSession(false);
|
|
|
|
Map<String, Object> paramMap = new HashMap<String, Object>();
|
|
paramMap.put("userId", userId);
|
|
|
|
Map<String, Object> userInfo = (Map<String, Object>) sqlSession.selectOne("login.getUserInfo", paramMap);
|
|
|
|
if(userInfo != null) {
|
|
// MyBatis가 소문자로 변환하므로 소문자 우선 시도
|
|
String cellPhone = (String)userInfo.get("cell_phone");
|
|
String tel = (String)userInfo.get("tel");
|
|
|
|
// 소문자로 안되면 대문자 시도 (호환성)
|
|
if(cellPhone == null) {
|
|
cellPhone = (String)userInfo.get("CELL_PHONE");
|
|
}
|
|
if(tel == null) {
|
|
tel = (String)userInfo.get("TEL");
|
|
}
|
|
|
|
userPhone = CommonUtils.checkNull(cellPhone);
|
|
if("".equals(userPhone)) {
|
|
userPhone = CommonUtils.checkNull(tel);
|
|
}
|
|
}
|
|
sqlSession.close();
|
|
} catch(Exception e) {
|
|
System.out.println("전화번호 조회 오류: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
|
|
String objId = CommonUtils.checkNull(request.getParameter("objId"));
|
|
String templateObjId = CommonUtils.checkNull(request.getParameter("templateObjId"));
|
|
%>
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
<title><%=Constants.SYSTEM_NAME%> - 견적서 양식1</title>
|
|
<style type="text/css">
|
|
@media print {
|
|
@page {
|
|
size: A4;
|
|
margin: 10mm;
|
|
}
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
.no-print {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
body {
|
|
font-family: "Malgun Gothic", "맑은 고딕", Arial, sans-serif;
|
|
font-size: 12pt;
|
|
margin: 0;
|
|
padding: 20px;
|
|
padding-bottom: 100px; /* 고정 버튼 영역을 위한 하단 여백 */
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.estimate-container {
|
|
width: 210mm;
|
|
min-height: 297mm;
|
|
background: white;
|
|
margin: 0 auto;
|
|
padding: 20mm;
|
|
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.header-section {
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.title {
|
|
text-align: center;
|
|
font-size: 28pt;
|
|
font-weight: bold;
|
|
letter-spacing: 20px;
|
|
margin-bottom: 40px;
|
|
padding: 10px 0;
|
|
}
|
|
|
|
.info-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.info-table td {
|
|
padding: 5px 8px;
|
|
border: 1px solid #000;
|
|
font-size: 9pt;
|
|
}
|
|
|
|
.info-table .label {
|
|
background-color: #f0f0f0;
|
|
font-weight: bold;
|
|
width: 80px;
|
|
text-align: center;
|
|
}
|
|
|
|
.company-info {
|
|
float: right;
|
|
text-align: right;
|
|
margin-top: -80px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.company-stamp {
|
|
width: 120px;
|
|
height: 120px;
|
|
border: 2px solid #e74c3c;
|
|
border-radius: 50%;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-bottom: 10px;
|
|
position: relative;
|
|
}
|
|
|
|
.company-stamp-text {
|
|
writing-mode: vertical-rl;
|
|
font-size: 16pt;
|
|
font-weight: bold;
|
|
color: #e74c3c;
|
|
letter-spacing: 3px;
|
|
}
|
|
|
|
.company-details {
|
|
font-size: 9pt;
|
|
line-height: 1.6;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.greeting {
|
|
font-size: 11pt;
|
|
margin-bottom: 20px;
|
|
line-height: 1.8;
|
|
}
|
|
|
|
.items-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.items-table th,
|
|
.items-table td {
|
|
border: 1px solid #000;
|
|
padding: 3px 5px;
|
|
text-align: center;
|
|
font-size: 9pt;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.items-table th {
|
|
background-color: #f0f0f0;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.items-table .col-no { width: 6%; }
|
|
.items-table .col-desc { width: 20%; }
|
|
.items-table .col-spec { width: 22%; }
|
|
.items-table .col-qty { width: 7%; }
|
|
.items-table .col-unit { width: 8%; }
|
|
.items-table .col-price { width: 11%; }
|
|
.items-table .col-amount { width: 11%; }
|
|
.items-table .col-note { width: 15%; }
|
|
|
|
.items-table .text-left {
|
|
text-align: left;
|
|
}
|
|
|
|
.items-table .text-right {
|
|
text-align: right;
|
|
}
|
|
|
|
.notes-section {
|
|
margin-top: 30px;
|
|
font-size: 10pt;
|
|
line-height: 1.8;
|
|
}
|
|
|
|
.notes-title {
|
|
font-weight: bold;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.footer-company {
|
|
text-align: right;
|
|
margin-top: 40px;
|
|
font-size: 12pt;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.btn-area {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
text-align: right;
|
|
padding: 15px 30px;
|
|
background-color: #ffffff;
|
|
border-top: 3px solid #007bff;
|
|
box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
|
|
z-index: 1000;
|
|
}
|
|
|
|
/* 견적서 전용 버튼 스타일 */
|
|
.estimate-btn {
|
|
display: inline-block;
|
|
padding: 5px 15px;
|
|
margin: 0 2px;
|
|
font-size: 12px;
|
|
font-weight: normal;
|
|
cursor: pointer;
|
|
border: 1px solid #60a5fa;
|
|
background-color: #60a5fa;
|
|
color: white;
|
|
border-radius: 3px;
|
|
transition: all 0.3s;
|
|
line-height: 1;
|
|
vertical-align: middle;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.estimate-btn:hover {
|
|
background-color: #1e3a8a;
|
|
border-color: #1e3a8a;
|
|
box-shadow: 0 2px 6px rgba(0,123,255,0.4);
|
|
}
|
|
|
|
.estimate-btn:active {
|
|
background-color: #1e3a8a;
|
|
border-color: #1e3a8a;
|
|
box-shadow: 0 1px 3px rgba(96,165,250,0.3);
|
|
}
|
|
|
|
input[type="text"],
|
|
textarea {
|
|
border: none;
|
|
outline: none;
|
|
background: transparent;
|
|
width: 100%;
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
}
|
|
|
|
textarea {
|
|
resize: vertical;
|
|
min-height: 25px;
|
|
padding: 2px;
|
|
}
|
|
|
|
.editable {
|
|
background-color: transparent;
|
|
}
|
|
|
|
@media print {
|
|
.editable {
|
|
background-color: transparent;
|
|
}
|
|
}
|
|
</style>
|
|
<script type="text/javascript">
|
|
// 전역 변수로 저장 (데이터 로드 시 설정됨)
|
|
var g_contractObjId = "<%=objId%>";
|
|
var g_templateObjId = "<%=templateObjId%>";
|
|
var g_exchangeRate = 1; // 환율 (기본값 1)
|
|
var g_currencyName = "KRW"; // 통화명 (기본값 원화)
|
|
var g_apprStatus = ""; // 결재상태
|
|
var g_userPhone = "<%=userPhone%>"; // 로그인 사용자 연락처
|
|
|
|
$(function(){
|
|
|
|
// 로그인 사용자 정보 디버깅
|
|
//console.log("=== 로그인 사용자 정보 ===");
|
|
//console.log("g_userPhone:", g_userPhone);
|
|
|
|
// 로그인 사용자 정보 자동 입력
|
|
// HTML에서 이미 초기값이 설정되어 있으므로 연락처만 설정
|
|
$("#manager_contact").val(g_userPhone || "");
|
|
$("#manager_name").val('<%=connectUserDeptName%> '+' <%=connectUserName%>');
|
|
|
|
//console.log("manager_contact 설정값:", $("#manager_contact").val());
|
|
|
|
// 시행일자 datepicker 초기화
|
|
$("#executor").datepicker({
|
|
changeMonth: true,
|
|
changeYear: true,
|
|
dateFormat: 'yy-mm-dd'
|
|
});
|
|
|
|
// 수신처(고객사) select2 초기화
|
|
$("#recipient").select2({
|
|
width: '100%',
|
|
placeholder: '고객사 선택'
|
|
});
|
|
|
|
// 수신처 변경 시 수신인 자동 입력
|
|
$("#recipient").change(function(){
|
|
// 데이터 로드 중이 아닐 때만 수신인 자동 로드
|
|
if(!window.isLoadingData) {
|
|
fn_loadCustomerContact($(this).val());
|
|
}
|
|
});
|
|
|
|
// templateObjId가 있으면 기존 데이터 로드
|
|
var templateObjId = "<%=templateObjId%>";
|
|
if(templateObjId && templateObjId !== ""){
|
|
fn_loadTemplateData(templateObjId);
|
|
}
|
|
|
|
// 인쇄 버튼
|
|
$("#btnPrint").click(function(){
|
|
window.print();
|
|
});
|
|
|
|
// 저장 버튼
|
|
$("#btnSave").click(function(){
|
|
if(confirm("견적서를 저장하시겠습니까?")) {
|
|
fn_save();
|
|
}
|
|
});
|
|
|
|
// 닫기 버튼
|
|
$("#btnClose").click(function(){
|
|
self.close();
|
|
});
|
|
|
|
// 행 추가 버튼
|
|
$("#btnAddRow").click(function(){
|
|
fn_addItemRow();
|
|
});
|
|
|
|
// 금액 자동 계산
|
|
$(document).on("change keyup", ".item-qty, .item-price", function(){
|
|
fn_calculateAmount($(this).closest("tr"));
|
|
fn_calculateTotal(); // 합계 재계산
|
|
});
|
|
|
|
// 금액 필드 직접 수정 시에도 합계 재계산
|
|
$(document).on("change keyup", ".item-amount", function(){
|
|
fn_calculateTotal(); // 합계 재계산
|
|
});
|
|
|
|
// 콤마 자동 추가 (동적 요소 포함)
|
|
$(document).on("blur", ".item-price, .item-amount", function(){
|
|
var val = $(this).val().replace(/,/g, "").replace(/₩/g, "");
|
|
if(!isNaN(val) && val !== "") {
|
|
$(this).val(addComma(val));
|
|
}
|
|
fn_calculateTotal(); // blur 시에도 합계 재계산
|
|
});
|
|
|
|
// 단가 입력 시 실시간 콤마 처리
|
|
$(document).on("input", ".item-price", function(){
|
|
var val = $(this).val().replace(/,/g, "");
|
|
var cursorPos = this.selectionStart;
|
|
var commasBefore = ($(this).val().substring(0, cursorPos).match(/,/g) || []).length;
|
|
|
|
if(!isNaN(val) && val !== "") {
|
|
$(this).val(addComma(val));
|
|
// 커서 위치 조정
|
|
var commasAfter = ($(this).val().substring(0, cursorPos).match(/,/g) || []).length;
|
|
var newPos = cursorPos + (commasAfter - commasBefore);
|
|
this.setSelectionRange(newPos, newPos);
|
|
}
|
|
});
|
|
|
|
// 데이터 로드
|
|
if("<%=objId%>" !== "" && "<%=objId%>" !== "-1") {
|
|
fn_loadData();
|
|
} else {
|
|
// 새 견적서 작성 시 기본 행의 셀렉트박스 초기화
|
|
fn_initItemDescSelect('default_item_1');
|
|
fn_initItemDescSelect('default_item_2');
|
|
|
|
// 초기 로드 시 합계 계산
|
|
fn_calculateTotal();
|
|
|
|
// 새로 등록 시 명시적으로 작성중 상태 설정
|
|
g_apprStatus = "작성중";
|
|
fn_controlButtons();
|
|
}
|
|
});
|
|
|
|
// 결재상태에 따라 버튼 표시 제어
|
|
function fn_controlButtons() {
|
|
console.log("=== fn_controlButtons 호출 ===");
|
|
console.log("g_apprStatus:", g_apprStatus);
|
|
|
|
if(g_apprStatus === "결재완료") {
|
|
console.log("결재완료 상태 - 입력 필드 비활성화");
|
|
// 결재완료된 경우 행추가, 저장 버튼 숨김
|
|
$("#btnAddRow").hide();
|
|
$("#btnSave").hide();
|
|
|
|
// 모든 입력 필드를 읽기 전용으로 변경
|
|
$("input, textarea").attr("readonly", true);
|
|
$("input, textarea").css("background-color", "#f5f5f5");
|
|
|
|
// select 박스 비활성화 (고객사 선택 등)
|
|
$("select").attr("disabled", true);
|
|
$("select").css("background-color", "#f5f5f5");
|
|
|
|
// datepicker 비활성화
|
|
$("#executor").datepicker("option", "disabled", true);
|
|
|
|
// 삭제 버튼 숨김
|
|
$(".btn-delete-row").hide();
|
|
} else {
|
|
console.log("결재완료 아님 - 입력 필드 활성화");
|
|
// 결재완료가 아닌 경우 버튼 표시
|
|
$("#btnAddRow").show();
|
|
$("#btnSave").show();
|
|
|
|
// 입력 필드 활성화
|
|
$("input, textarea").attr("readonly", false);
|
|
$("input, textarea").css("background-color", "");
|
|
|
|
// select 박스 활성화
|
|
$("select").attr("disabled", false);
|
|
$("select").css("background-color", "");
|
|
|
|
// datepicker 활성화
|
|
$("#executor").datepicker("option", "disabled", false);
|
|
|
|
// 삭제 버튼 표시
|
|
$(".btn-delete-row").show();
|
|
}
|
|
}
|
|
|
|
// 금액 계산
|
|
function fn_calculateAmount(row) {
|
|
var qty = row.find(".item-qty").val().replace(/,/g, "") || "0";
|
|
var price = row.find(".item-price").val().replace(/,/g, "") || "0";
|
|
|
|
var amount = parseInt(qty) * parseInt(price);
|
|
if(!isNaN(amount)) {
|
|
row.find(".item-amount").val(addComma(amount));
|
|
}
|
|
}
|
|
|
|
// 합계 계산 (금액 컬럼의 총합)
|
|
function fn_calculateTotal() {
|
|
var total = 0;
|
|
|
|
// 품목 행만 순회 (계 행, 원화환산 행, 비고 행, 참조사항 행, 회사명 행 제외)
|
|
$("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row, .notes-row, .footer-row").each(function(){
|
|
var amount = $(this).find(".item-amount").val() || "0";
|
|
// 콤마와 통화 기호 제거 후 숫자로 변환
|
|
amount = amount.replace(/,/g, "").replace(/₩/g, "").replace(/\$/g, "").replace(/€/g, "").replace(/¥/g, "");
|
|
var numAmount = parseInt(amount) || 0;
|
|
total += numAmount;
|
|
});
|
|
|
|
// 합계 행에 통화 기호와 함께 표시
|
|
var currencySymbol = getCurrencySymbol();
|
|
$("#totalAmount").text(currencySymbol + addComma(total));
|
|
|
|
// 원화환산 금액 계산 및 표시
|
|
fn_calculateTotalKRW(total);
|
|
}
|
|
|
|
// 원화환산 공급가액 계산
|
|
function fn_calculateTotalKRW(total) {
|
|
var totalKRW = total * g_exchangeRate;
|
|
$("#totalAmountKRW").text("₩" + addComma(Math.round(totalKRW)));
|
|
}
|
|
|
|
// 콤마 추가
|
|
function addComma(num) {
|
|
var regexp = /\B(?=(\d{3})+(?!\d))/g;
|
|
return num.toString().replace(regexp, ',');
|
|
}
|
|
|
|
// 통화 기호 반환
|
|
function getCurrencySymbol() {
|
|
if(g_currencyName.indexOf("달러") >= 0 || g_currencyName === "USD") {
|
|
return "$";
|
|
} else if(g_currencyName.indexOf("유로") >= 0 || g_currencyName === "EUR") {
|
|
return "€";
|
|
} else if(g_currencyName.indexOf("엔") >= 0 || g_currencyName === "JPY") {
|
|
return "¥";
|
|
} else if(g_currencyName.indexOf("위안") >= 0 || g_currencyName === "CNY") {
|
|
return "¥";
|
|
} else {
|
|
return "₩"; // 기본값 원화
|
|
}
|
|
}
|
|
|
|
// 품명 셀렉트박스 초기화 함수
|
|
function fn_initItemDescSelect(itemId) {
|
|
$("#" + itemId + " .item-desc-select").select2({
|
|
placeholder: "품명 입력하여 검색...",
|
|
allowClear: true,
|
|
width: '100%',
|
|
minimumInputLength: 1,
|
|
language: {
|
|
inputTooShort: function() {
|
|
return "최소 1글자 이상 입력하세요";
|
|
},
|
|
searching: function() {
|
|
return "검색 중...";
|
|
},
|
|
noResults: function() {
|
|
return "검색 결과가 없습니다";
|
|
}
|
|
},
|
|
ajax: {
|
|
url: '/contractMgmt/searchPartList.do',
|
|
dataType: 'json',
|
|
type: 'POST',
|
|
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
delay: 250,
|
|
data: function(params) {
|
|
return {
|
|
searchTerm: params.term
|
|
};
|
|
},
|
|
processResults: function(data) {
|
|
var results = $.map(data, function(item) {
|
|
var objId = item.OBJID || item.objid || item.objId;
|
|
var partNo = item.PART_NO || item.part_no || item.partNo;
|
|
var partName = item.PART_NAME || item.part_name || item.partName;
|
|
var spec = item.SPECIFICATION || item.specification || '';
|
|
|
|
return {
|
|
id: objId,
|
|
text: partName,
|
|
partName: partName,
|
|
partNo: partNo,
|
|
spec: spec
|
|
};
|
|
});
|
|
|
|
return {
|
|
results: results
|
|
};
|
|
},
|
|
cache: true
|
|
}
|
|
});
|
|
|
|
// 품명 선택 시 hidden 필드와 규격 자동 입력 (select2:select는 같은 값 재선택 시에도 발생)
|
|
$("#" + itemId + " .item-desc-select").on('select2:select', function(e) {
|
|
var selectedData = e.params.data;
|
|
if(selectedData) {
|
|
$("#" + itemId + " .item-desc").val(selectedData.text);
|
|
$("#" + itemId + " .item-part-objid").val(selectedData.id); // part_objid 저장
|
|
if(selectedData.spec) {
|
|
$("#" + itemId + " .item-spec").val(selectedData.spec);
|
|
}
|
|
}
|
|
});
|
|
|
|
// 품명 선택 해제 시 (X 버튼 클릭)
|
|
$("#" + itemId + " .item-desc-select").on('select2:clear', function() {
|
|
$("#" + itemId + " .item-desc").val('');
|
|
$("#" + itemId + " .item-part-objid").val(''); // part_objid 초기화
|
|
});
|
|
}
|
|
|
|
// 행 추가 함수
|
|
function fn_addItemRow() {
|
|
// 계 행, 원화환산 행, 비고 행, 참조사항 행, 회사명 행 제외하고 품목 행 개수 계산
|
|
var itemRows = $("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row, .notes-row, .footer-row");
|
|
var nextNo = itemRows.length + 1;
|
|
|
|
// 새 행 생성
|
|
var itemId = 'item_' + new Date().getTime();
|
|
var newRow = '<tr id="' + itemId + '">' +
|
|
'<td>' + nextNo + '</td>' +
|
|
'<td class="text-left editable">' +
|
|
'<select class="item-desc-select" style="width:100%;"></select>' +
|
|
'<input type="hidden" class="item-desc" value="">' +
|
|
'<input type="hidden" class="item-part-objid" value="">' +
|
|
'</td>' +
|
|
'<td class="text-left editable"><textarea class="item-spec"></textarea></td>' +
|
|
'<td class="editable"><input type="text" class="item-qty" value=""></td>' +
|
|
'<td class="editable"><input type="text" class="item-unit" value="EA"></td>' +
|
|
'<td class="text-right editable"><input type="text" class="item-price" value=""></td>' +
|
|
'<td class="text-right editable"><input type="text" class="item-amount" value="" readonly></td>' +
|
|
'<td class="editable"><input type="text" class="item-note" value=""></td>' +
|
|
'</tr>';
|
|
|
|
// 계 행 바로 위에 추가
|
|
$(".total-row").before(newRow);
|
|
|
|
// 품명 셀렉트박스 초기화
|
|
fn_initItemDescSelect(itemId);
|
|
|
|
// 합계 재계산
|
|
fn_calculateTotal();
|
|
}
|
|
|
|
// 데이터 로드
|
|
function fn_loadData() {
|
|
$.ajax({
|
|
url: "/contractMgmt/getEstimateDetail.do",
|
|
type: "POST",
|
|
data: {
|
|
objId: "<%=objId%>"
|
|
},
|
|
dataType: "json",
|
|
success: function(data) {
|
|
if(data && data.estimate) {
|
|
// 환율 정보 저장 (소문자 우선)
|
|
var exchangeRate = data.estimate.exchange_rate || data.estimate.EXCHANGE_RATE || "1";
|
|
var currencyName = data.estimate.contract_currency_name || data.estimate.CONTRACT_CURRENCY_NAME || "KRW";
|
|
|
|
g_exchangeRate = parseFloat(exchangeRate);
|
|
g_currencyName = currencyName;
|
|
|
|
// 결재상태 저장
|
|
g_apprStatus = data.estimate.APPR_STATUS || "작성중";
|
|
|
|
// 데이터 바인딩
|
|
$("#executor").val(data.estimate.EXECUTOR || "");
|
|
|
|
// 데이터 로드 중 플래그 설정 (수신인 자동 로드 방지)
|
|
window.isLoadingData = true;
|
|
|
|
// 수신처 설정
|
|
var recipientValue = data.estimate.RECIPIENT || "";
|
|
$("#recipient").val(recipientValue).trigger('change');
|
|
|
|
// 플래그 해제
|
|
setTimeout(function() {
|
|
window.isLoadingData = false;
|
|
}, 100);
|
|
|
|
$("#estimate_no").val(data.estimate.ESTIMATE_NO || "");
|
|
$("#contact_person").val(data.estimate.CONTACT_PERSON || "");
|
|
$("#greeting_text").val(data.estimate.GREETING_TEXT || "견적을 요청해 주셔서 대단히 감사합니다.\n하기와 같이 견적서를 제출합니다.");
|
|
|
|
// 담당자/연락처는 저장된 값이 있을 때만 덮어씀
|
|
var managerName = data.estimate.MANAGER_NAME || "";
|
|
var managerContact = data.estimate.MANAGER_CONTACT || "";
|
|
if(managerName && managerName !== "" && managerName !== "영업부") {
|
|
$("#manager_name").val(managerName);
|
|
}
|
|
if(managerContact && managerContact !== "") {
|
|
$("#manager_contact").val(managerContact);
|
|
}
|
|
|
|
/* 품목 데이터 로드 - 주석처리 (새로 작성 시 빈 템플릿 사용)
|
|
if(data.items && data.items.length > 0) {
|
|
// 기존 행 초기화 후 데이터 추가
|
|
var itemsHtml = "";
|
|
for(var i = 0; i < data.items.length; i++) {
|
|
var item = data.items[i];
|
|
var itemId = 'loaded_item_' + i;
|
|
itemsHtml += '<tr id="' + itemId + '">';
|
|
itemsHtml += '<td>' + (i + 1) + '</td>';
|
|
itemsHtml += '<td class="text-left editable">';
|
|
itemsHtml += '<select class="item-desc-select" style="width:100%;">';
|
|
// PART_OBJID가 없으면 기존 텍스트를 옵션으로 표시
|
|
var description = item.DESCRIPTION || '';
|
|
if(description) {
|
|
itemsHtml += '<option value="" selected>' + description + '</option>';
|
|
}
|
|
itemsHtml += '</select>';
|
|
itemsHtml += '<input type="hidden" class="item-desc" value="' + description + '">';
|
|
itemsHtml += '<input type="hidden" class="item-part-objid" value="' + (item.PART_OBJID || item.part_objid || '') + '">';
|
|
itemsHtml += '</td>';
|
|
itemsHtml += '<td class="text-left editable"><textarea class="item-spec">' + (item.SPECIFICATION || '') + '</textarea></td>';
|
|
itemsHtml += '<td class="editable"><input type="text" class="item-qty" value="' + (item.QUANTITY || '') + '"></td>';
|
|
itemsHtml += '<td class="editable"><input type="text" class="item-unit" value="' + (item.UNIT || 'EA') + '"></td>';
|
|
itemsHtml += '<td class="text-right editable"><input type="text" class="item-price" value="' + (item.UNIT_PRICE ? addComma(item.UNIT_PRICE) : '') + '"></td>';
|
|
itemsHtml += '<td class="text-right editable"><input type="text" class="item-amount" value="' + (item.AMOUNT ? addComma(item.AMOUNT) : '') + '" readonly></td>';
|
|
itemsHtml += '<td class="editable"><input type="text" class="item-note" value="' + (item.NOTE || '') + '"></td>';
|
|
itemsHtml += '</tr>';
|
|
}
|
|
|
|
// 계 행 추가
|
|
itemsHtml += '<tr class="total-row">';
|
|
itemsHtml += '<td colspan="6" style="text-align: center; font-weight: bold; background-color: #f0f0f0;">계</td>';
|
|
itemsHtml += '<td class="text-right" style="font-weight: bold; background-color: #f0f0f0;"><span id="totalAmount">0</span></td>';
|
|
itemsHtml += '<td style="background-color: #f0f0f0;"></td>';
|
|
itemsHtml += '</tr>';
|
|
|
|
// 원화환산 공급가액 행 추가 (숨김)
|
|
itemsHtml += '<tr class="total-krw-row" style="display: none;">';
|
|
itemsHtml += '<td colspan="6" style="text-align: center; font-weight: bold; background-color: #e8f4f8;">원화환산 공급가액 (KRW)</td>';
|
|
itemsHtml += '<td class="text-right" style="font-weight: bold; background-color: #e8f4f8;"><span id="totalAmountKRW">0</span></td>';
|
|
itemsHtml += '<td style="background-color: #e8f4f8;"></td>';
|
|
itemsHtml += '</tr>';
|
|
|
|
// 비고 행 추가
|
|
itemsHtml += '<tr class="remarks-row">';
|
|
itemsHtml += '<td colspan="8" style="height: 100px; vertical-align: top; padding: 10px; text-align: left;">';
|
|
itemsHtml += '<div style="font-weight: bold; margin-bottom: 10px; text-align: left;"><비고></div>';
|
|
itemsHtml += '<textarea id="note_remarks" style="width: 100%; height: 70px; border: none; resize: none; font-family: inherit; font-size: 10pt; text-align: left;"></textarea>';
|
|
itemsHtml += '</td>';
|
|
itemsHtml += '</tr>';
|
|
|
|
$("#itemsTableBody").html(itemsHtml);
|
|
|
|
// 로드된 품목의 셀렉트박스 초기화 및 데이터 설정
|
|
for(var i = 0; i < data.items.length; i++) {
|
|
var item = data.items[i];
|
|
var itemId = 'loaded_item_' + i;
|
|
var partObjId = item.PART_OBJID || item.part_objid || '';
|
|
|
|
// PART_OBJID가 있으면 해당 품목을 셀렉트박스에 설정
|
|
if(partObjId) {
|
|
// AJAX로 품목 정보 조회하여 셀렉트박스에 옵션 추가
|
|
$.ajax({
|
|
url: '/contractMgmt/searchPartList.do',
|
|
type: 'POST',
|
|
data: { partObjId: partObjId },
|
|
dataType: 'json',
|
|
async: false, // 동기 처리
|
|
success: function(partData) {
|
|
if(partData && partData.length > 0) {
|
|
var part = partData[0];
|
|
var objId = part.OBJID || part.objid || part.objId;
|
|
var partName = part.PART_NAME || part.part_name || part.partName;
|
|
var spec = part.SPEC || part.spec || '';
|
|
|
|
// 옵션 생성 및 추가 (selected 상태로)
|
|
var newOption = new Option(partName, objId, true, true);
|
|
$("#" + itemId + " .item-desc-select").append(newOption);
|
|
|
|
// hidden 필드 업데이트
|
|
$("#" + itemId + " .item-desc").val(partName);
|
|
$("#" + itemId + " .item-part-objid").val(objId);
|
|
|
|
// 규격이 있으면 자동 입력
|
|
if(spec) {
|
|
$("#" + itemId + " .item-spec").val(spec);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// 셀렉트박스 초기화 (옵션 추가 후)
|
|
fn_initItemDescSelect(itemId);
|
|
}
|
|
|
|
// 비고 로드 (테이블 생성 직후)
|
|
$("#note_remarks").val(data.estimate.NOTE_REMARKS || "");
|
|
|
|
// 합계 계산
|
|
fn_calculateTotal();
|
|
}
|
|
*/ // 품목 데이터 로드 주석처리 끝
|
|
|
|
// 새로 작성 시 기본 행의 셀렉트박스 초기화
|
|
fn_initItemDescSelect('default_item_1');
|
|
fn_initItemDescSelect('default_item_2');
|
|
|
|
// 초기 로드 시 합계 계산
|
|
fn_calculateTotal();
|
|
|
|
// 하단 비고 로드
|
|
$("#note1").val(data.estimate.NOTE1 || "1. 견적유효기간: 일");
|
|
$("#note2").val(data.estimate.NOTE2 || "2. 납품기간: 발주 후 1주 이내");
|
|
$("#note3").val(data.estimate.NOTE3 || "3. VAT 별도");
|
|
$("#note4").val(data.estimate.NOTE4 || "4. 결제 조건 : 기존 결제조건에 따름.");
|
|
|
|
// 결재상태에 따라 버튼 제어
|
|
fn_controlButtons();
|
|
}
|
|
},
|
|
error: function() {
|
|
Swal.fire("데이터를 불러오는데 실패했습니다.");
|
|
}
|
|
});
|
|
}
|
|
|
|
// 기존 견적서 데이터 로드 (templateObjId 기준)
|
|
function fn_loadTemplateData(templateObjId){
|
|
$.ajax({
|
|
url: "/contractMgmt/getEstimateTemplateDataByObjId.do",
|
|
type: "POST",
|
|
data: { templateObjId: templateObjId },
|
|
dataType: "json",
|
|
success: function(data){
|
|
console.log("견적서 데이터:", data); // 디버깅용
|
|
|
|
if(data.result === "success" && data.template){
|
|
var template = data.template;
|
|
|
|
// CONTRACT_OBJID를 전역 변수에 저장 (저장 시 사용)
|
|
var contractObjId = template.CONTRACT_OBJID || template.contract_objid || template.contractObjId || "";
|
|
if(contractObjId) {
|
|
g_contractObjId = contractObjId;
|
|
}
|
|
|
|
// 환율 정보 저장 (소문자 우선)
|
|
var exchangeRate = template.exchange_rate || template.EXCHANGE_RATE || template.exchangeRate || "1";
|
|
var currencyName = template.contract_currency_name || template.CONTRACT_CURRENCY_NAME || template.contractCurrencyName || "KRW";
|
|
|
|
g_exchangeRate = parseFloat(exchangeRate);
|
|
g_currencyName = currencyName;
|
|
|
|
// 결재상태 저장
|
|
g_apprStatus = template.appr_status || template.APPR_STATUS || template.apprStatus || "작성중";
|
|
|
|
// 대문자/소문자 모두 지원
|
|
var executor = template.EXECUTOR || template.executor || "";
|
|
var recipient = template.RECIPIENT || template.recipient || "";
|
|
var recipientName = template.RECIPIENT_NAME || template.recipient_name || template.recipientName || "";
|
|
var estimateNo = template.ESTIMATE_NO || template.estimate_no || template.estimateNo || "";
|
|
var contactPerson = template.CONTACT_PERSON || template.contact_person || template.contactPerson || "";
|
|
var greetingText = template.GREETING_TEXT || template.greeting_text || template.greetingText || "";
|
|
var note1 = template.NOTE1 || template.note1 || "";
|
|
var note2 = template.NOTE2 || template.note2 || "";
|
|
var note3 = template.NOTE3 || template.note3 || "";
|
|
var note4 = template.NOTE4 || template.note4 || "";
|
|
var managerName = template.MANAGER_NAME || template.manager_name || template.managerName || "영업부";
|
|
var managerContact = template.MANAGER_CONTACT || template.manager_contact || template.managerContact || "";
|
|
|
|
// 기본 정보 채우기
|
|
$("#executor").val(executor);
|
|
|
|
// 데이터 로드 중 플래그 설정 (수신인 자동 로드 방지)
|
|
window.isLoadingData = true;
|
|
|
|
// 수신처 설정
|
|
if(recipient && recipient !== "") {
|
|
// OBJID로 셀렉트박스 선택
|
|
$("#recipient").val(recipient).trigger('change');
|
|
}
|
|
|
|
// 플래그 해제
|
|
setTimeout(function() {
|
|
window.isLoadingData = false;
|
|
}, 100);
|
|
|
|
$("#estimate_no").val(estimateNo);
|
|
$("#contact_person").val(contactPerson);
|
|
$("#greeting_text").val(greetingText);
|
|
|
|
// 담당자/연락처는 저장된 값이 있을 때만 덮어씀
|
|
if(managerName && managerName !== "" && managerName !== "영업부") {
|
|
$("#manager_name").val(managerName);
|
|
}
|
|
if(managerContact && managerContact !== "") {
|
|
$("#manager_contact").val(managerContact);
|
|
}
|
|
|
|
// 테이블 내 비고는 나중에 설정 (textarea 생성 후)
|
|
var noteRemarks = template.NOTE_REMARKS || template.note_remarks || template.noteRemarks || "";
|
|
|
|
// 품목 데이터 채우기
|
|
if(data.items && data.items.length > 0){
|
|
$("#itemsTableBody").empty();
|
|
|
|
// 품목 HTML 생성
|
|
var itemsHtml = "";
|
|
for(var i = 0; i < data.items.length; i++) {
|
|
var item = data.items[i];
|
|
var itemId = 'template_item_' + i;
|
|
var description = item.DESCRIPTION || item.description || '';
|
|
var specification = item.SPECIFICATION || item.specification || '';
|
|
var quantity = item.QUANTITY || item.quantity || '';
|
|
var unit = item.UNIT || item.unit || '';
|
|
var unitPrice = item.UNIT_PRICE || item.unit_price || item.unitPrice || '';
|
|
var amount = item.AMOUNT || item.amount || '';
|
|
var note = item.NOTE || item.note || '';
|
|
var partObjId = item.PART_OBJID || item.part_objid || '';
|
|
|
|
// 단가와 금액에 콤마 추가
|
|
var unitPriceFormatted = unitPrice ? addComma(unitPrice) : '';
|
|
var amountFormatted = amount ? addComma(amount) : '';
|
|
|
|
itemsHtml += '<tr id="' + itemId + '">';
|
|
itemsHtml += '<td>' + (i + 1) + '</td>';
|
|
itemsHtml += '<td class="text-left editable">';
|
|
itemsHtml += '<select class="item-desc-select" style="width:100%;">';
|
|
// PART_OBJID가 없으면 기존 텍스트를 옵션으로 표시
|
|
if(description) {
|
|
itemsHtml += '<option value="" selected>' + description + '</option>';
|
|
}
|
|
itemsHtml += '</select>';
|
|
itemsHtml += '<input type="hidden" class="item-desc" value="' + description + '">';
|
|
itemsHtml += '<input type="hidden" class="item-part-objid" value="' + partObjId + '">';
|
|
itemsHtml += '</td>';
|
|
itemsHtml += '<td class="text-left editable"><textarea class="item-spec">' + specification + '</textarea></td>';
|
|
itemsHtml += '<td class="editable"><input type="text" class="item-qty" value="' + quantity + '"></td>';
|
|
itemsHtml += '<td class="editable"><input type="text" class="item-unit" value="' + unit + '"></td>';
|
|
itemsHtml += '<td class="text-right editable"><input type="text" class="item-price" value="' + unitPriceFormatted + '"></td>';
|
|
itemsHtml += '<td class="text-right editable"><input type="text" class="item-amount" value="' + amountFormatted + '" readonly></td>';
|
|
itemsHtml += '<td class="editable"><input type="text" class="item-note" value="' + note + '"></td>';
|
|
itemsHtml += '</tr>';
|
|
}
|
|
|
|
// 계 행 추가
|
|
itemsHtml += '<tr class="total-row">';
|
|
itemsHtml += '<td colspan="6" style="text-align: center; font-weight: bold; background-color: #f0f0f0;">계</td>';
|
|
itemsHtml += '<td class="text-right" style="font-weight: bold; background-color: #f0f0f0;"><span id="totalAmount">0</span></td>';
|
|
itemsHtml += '<td style="background-color: #f0f0f0;"></td>';
|
|
itemsHtml += '</tr>';
|
|
|
|
// 원화환산 공급가액 행 추가 (숨김)
|
|
itemsHtml += '<tr class="total-krw-row" style="display: none;">';
|
|
itemsHtml += '<td colspan="6" style="text-align: center; font-weight: bold; background-color: #e8f4f8;">원화환산 공급가액 (KRW)</td>';
|
|
itemsHtml += '<td class="text-right" style="font-weight: bold; background-color: #e8f4f8;"><span id="totalAmountKRW">0</span></td>';
|
|
itemsHtml += '<td style="background-color: #e8f4f8;"></td>';
|
|
itemsHtml += '</tr>';
|
|
|
|
// 비고 행 추가
|
|
itemsHtml += '<tr class="remarks-row">';
|
|
itemsHtml += '<td colspan="8" style="height: 100px; vertical-align: top; padding: 10px; text-align: left;">';
|
|
itemsHtml += '<div style="font-weight: bold; margin-bottom: 10px; text-align: left;"><비고></div>';
|
|
itemsHtml += '<textarea id="note_remarks" style="width: 100%; height: 70px; border: none; resize: none; font-family: inherit; font-size: 10pt; text-align: left;"></textarea>';
|
|
itemsHtml += '</td>';
|
|
itemsHtml += '</tr>';
|
|
|
|
// 참조사항 행 추가
|
|
itemsHtml += '<tr class="notes-row">';
|
|
itemsHtml += '<td colspan="8" style="vertical-align: top; padding: 10px; text-align: left; border: 1px solid #000;">';
|
|
itemsHtml += '<div style="font-weight: bold; margin-bottom: 10px; text-align: left;"><참조사항></div>';
|
|
itemsHtml += '<div class="editable" style="margin-bottom: 5px;"><input type="text" id="note1" value="1. 견적유효기간: 일" style="width: 100%; border: none; background: transparent; font-size: 10pt;"></div>';
|
|
itemsHtml += '<div class="editable" style="margin-bottom: 5px;"><input type="text" id="note2" value="2. 납품기간: 발주 후 1주 이내" style="width: 100%; border: none; background: transparent; font-size: 10pt;"></div>';
|
|
itemsHtml += '<div class="editable" style="margin-bottom: 5px;"><input type="text" id="note3" value="3. VAT 별도" style="width: 100%; border: none; background: transparent; font-size: 10pt;"></div>';
|
|
itemsHtml += '<div class="editable" style="margin-bottom: 5px;"><input type="text" id="note4" value="4. 결제 조건 : 기존 결제조건에 따름." style="width: 100%; border: none; background: transparent; font-size: 10pt;"></div>';
|
|
itemsHtml += '</td>';
|
|
itemsHtml += '</tr>';
|
|
|
|
// 하단 회사명 행 추가
|
|
itemsHtml += '<tr class="footer-row">';
|
|
itemsHtml += '<td colspan="8" style="text-align: right; padding: 15px; font-size: 10pt; font-weight: bold; border: none;">';
|
|
itemsHtml += '㈜알피에스';
|
|
itemsHtml += '</td>';
|
|
itemsHtml += '</tr>';
|
|
|
|
// HTML 삽입
|
|
$("#itemsTableBody").html(itemsHtml);
|
|
|
|
// 셀렉트박스 초기화 및 데이터 설정
|
|
for(var i = 0; i < data.items.length; i++) {
|
|
var item = data.items[i];
|
|
var itemId = 'template_item_' + i;
|
|
var partObjId = item.PART_OBJID || item.part_objid || '';
|
|
|
|
// PART_OBJID가 있으면 해당 품목을 셀렉트박스에 설정
|
|
if(partObjId) {
|
|
// AJAX로 품목 정보 조회하여 셀렉트박스에 옵션 추가
|
|
$.ajax({
|
|
url: '/contractMgmt/searchPartList.do',
|
|
type: 'POST',
|
|
data: { partObjId: partObjId },
|
|
dataType: 'json',
|
|
async: false, // 동기 처리
|
|
success: function(partData) {
|
|
if(partData && partData.length > 0) {
|
|
var part = partData[0];
|
|
var objId = part.OBJID || part.objid || part.objId;
|
|
var partName = part.PART_NAME || part.part_name || part.partName;
|
|
var spec = part.SPEC || part.spec || '';
|
|
|
|
// 옵션 생성 및 추가 (selected 상태로)
|
|
var newOption = new Option(partName, objId, true, true);
|
|
$("#" + itemId + " .item-desc-select").append(newOption);
|
|
|
|
// hidden 필드 업데이트
|
|
$("#" + itemId + " .item-desc").val(partName);
|
|
$("#" + itemId + " .item-part-objid").val(objId);
|
|
|
|
// 규격이 있으면 자동 입력 (기존 값이 없을 때만)
|
|
if(spec && !$("#" + itemId + " .item-spec").val()) {
|
|
$("#" + itemId + " .item-spec").val(spec);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// 셀렉트박스 초기화 (옵션 추가 후)
|
|
fn_initItemDescSelect(itemId);
|
|
}
|
|
|
|
// 테이블 내 비고 값 설정 (textarea 생성 직후)
|
|
$("#note_remarks").val(noteRemarks);
|
|
|
|
// 참조사항 값 설정 (input 생성 직후)
|
|
$("#note1").val(note1 || "1. 견적유효기간: 일");
|
|
$("#note2").val(note2 || "2. 납품기간: 발주 후 1주 이내");
|
|
$("#note3").val(note3 || "3. VAT 별도");
|
|
$("#note4").val(note4 || "4. 결제 조건 : 기존 결제조건에 따름.");
|
|
|
|
// 합계 계산
|
|
fn_calculateTotal();
|
|
|
|
// 결재상태에 따라 버튼 제어
|
|
fn_controlButtons();
|
|
|
|
// 데이터 로딩 완료 플래그 설정
|
|
window.dataLoaded = true;
|
|
console.log("견적서 데이터 로딩 완료");
|
|
}
|
|
} else {
|
|
console.error("데이터 로드 실패:", data);
|
|
window.dataLoaded = false;
|
|
Swal.fire("데이터를 불러오는데 실패했습니다.");
|
|
}
|
|
},
|
|
error: function(xhr, status, error){
|
|
console.error("AJAX 오류:", xhr, status, error);
|
|
Swal.fire("데이터를 불러오는데 실패했습니다.");
|
|
}
|
|
});
|
|
}
|
|
|
|
// 저장
|
|
// 고객사 담당자 정보 로드
|
|
function fn_loadCustomerContact(customerObjId) {
|
|
if(!customerObjId || customerObjId === "") {
|
|
$("#contact_person").val("");
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: "/contractMgmt/getCustomerContactInfo.do",
|
|
type: "POST",
|
|
data: { customerObjId: customerObjId },
|
|
dataType: "json",
|
|
success: function(data) {
|
|
if(data && data.contactPerson) {
|
|
$("#contact_person").val(data.contactPerson + " 귀하");
|
|
} else {
|
|
$("#contact_person").val("구매 담당자님 귀하");
|
|
}
|
|
},
|
|
error: function() {
|
|
$("#contact_person").val("구매 담당자님 귀하");
|
|
}
|
|
});
|
|
}
|
|
|
|
function fn_save() {
|
|
var items = [];
|
|
// 계 행, 원화환산 행, 비고 행, 참조사항 행, 회사명 행 제외하고 품목 행만 저장
|
|
$("#itemsTableBody tr").not(".total-row, .total-krw-row, .remarks-row, .notes-row, .footer-row").each(function(idx) {
|
|
var row = $(this);
|
|
var quantity = row.find(".item-qty").val() || "";
|
|
var unitPrice = row.find(".item-price").val() || "";
|
|
var amount = row.find(".item-amount").val() || "";
|
|
|
|
items.push({
|
|
seq: idx + 1,
|
|
part_objid: row.find(".item-part-objid").val() || "", // part_objid 추가
|
|
description: row.find(".item-desc").val() || "",
|
|
specification: row.find(".item-spec").val() || "",
|
|
quantity: quantity.replace(/,/g, ""), // 콤마 제거
|
|
unit: row.find(".item-unit").val() || "",
|
|
unit_price: unitPrice.replace(/,/g, ""), // 콤마 제거
|
|
amount: amount.replace(/,/g, "").replace(/₩/g, ""), // 콤마와 ₩ 제거
|
|
note: row.find(".item-note").val() || ""
|
|
});
|
|
});
|
|
|
|
// objId는 CONTRACT_OBJID를 의미함
|
|
var contractObjId = g_contractObjId;
|
|
|
|
// 유효성 검사
|
|
if(!contractObjId || contractObjId === "" || contractObjId === "-1") {
|
|
Swal.fire("견적서를 저장할 수 없습니다. 영업정보가 없습니다.");
|
|
return;
|
|
}
|
|
|
|
// 합계 계산 (통화 기호와 콤마 제거한 순수 숫자)
|
|
var totalAmount = $("#totalAmount").text().replace(/[^0-9.]/g, "");
|
|
var totalAmountKRW = $("#totalAmountKRW").text().replace(/[^0-9.]/g, "");
|
|
|
|
// 디버깅: 품목 데이터 확인
|
|
console.log("저장할 품목 데이터:", items);
|
|
|
|
var formData = {
|
|
objId: contractObjId,
|
|
template_type: "1",
|
|
executor: $("#executor").val(),
|
|
recipient: $("#recipient").val(),
|
|
estimate_no: $("#estimate_no").val(),
|
|
contact_person: $("#contact_person").val(),
|
|
greeting_text: $("#greeting_text").val(),
|
|
total_amount: totalAmount, // 합계
|
|
total_amount_krw: totalAmountKRW, // 원화환산 공급가액
|
|
manager_name: $("#manager_name").val(), // 담당자
|
|
manager_contact: $("#manager_contact").val(), // 연락처
|
|
note_remarks: $("#note_remarks").val(), // 테이블 내 비고
|
|
note1: $("#note1").val(),
|
|
note2: $("#note2").val(),
|
|
note3: $("#note3").val(),
|
|
note4: $("#note4").val(),
|
|
items: JSON.stringify(items)
|
|
};
|
|
|
|
// templateObjId가 있을 때만 추가 (기존 견적서 수정 시에만)
|
|
if(g_templateObjId && g_templateObjId !== "" && g_templateObjId !== "-1") {
|
|
formData.templateObjId = g_templateObjId;
|
|
}
|
|
|
|
console.log("저장 데이터:", formData); // 디버깅용
|
|
console.log("신규 작성:", !formData.templateObjId); // 디버깅용
|
|
|
|
$.ajax({
|
|
url: "/contractMgmt/saveEstimate.do",
|
|
type: "POST",
|
|
data: formData,
|
|
dataType: "json",
|
|
success: function(data) {
|
|
console.log("저장 결과:", data); // 디버깅용
|
|
if(data.result === "success") {
|
|
Swal.fire({
|
|
title: "저장되었습니다.",
|
|
icon: "success"
|
|
}).then(function() {
|
|
if(opener && opener.fn_search) {
|
|
opener.fn_search();
|
|
}
|
|
self.close();
|
|
});
|
|
} else {
|
|
Swal.fire("저장에 실패했습니다." + (data.message ? "\n" + data.message : ""));
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error("저장 오류:", xhr, status, error); // 디버깅용
|
|
Swal.fire("저장 중 오류가 발생했습니다.");
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div class="estimate-container">
|
|
<!-- 제목 -->
|
|
<div class="title">견 적 서</div>
|
|
|
|
<!-- 상단 정보 테이블 -->
|
|
<table class="info-table">
|
|
<colgroup>
|
|
<col width="80px" />
|
|
<col width="*" />
|
|
<col width="50px" />
|
|
<col width="300px" />
|
|
</colgroup>
|
|
<tr>
|
|
<td class="label">시행일자</td>
|
|
<td class="editable">
|
|
<input type="text" id="executor" class="date_icon" value="" style="width: 150px;">
|
|
</td>
|
|
<td rowspan="4" style="border: none"></td>
|
|
<td rowspan="4" style="text-align: center; border: none; vertical-align: middle; padding: 0;">
|
|
<div style="width: 100%; text-align: center; margin-bottom: 5px;">
|
|
<img src="/images/company_stamp.png" alt="회사 도장" style="width: 100%; height: auto;"
|
|
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
|
|
<div class="company-stamp" style="display: none; width: 100%; height: 250px;">
|
|
<div class="company-stamp-text">㈊알피에스<br>RPS CO., LTD<br>대표이사이동준</div>
|
|
</div>
|
|
</div>
|
|
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="label">수신처</td>
|
|
<td class="editable">
|
|
<select id="recipient" style="width: 100%; border: none; font-size: 9pt; padding: 2px;">
|
|
<option value="">고객사 선택</option>
|
|
${code_map.customer_cd}
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="label">수신인</td>
|
|
<td class="editable">
|
|
<input type="text" id="contact_person" value="구매 담당자님 귀하" readonly style="background-color: #f5f5f5;">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="label">견적번호</td>
|
|
<td class="editable">
|
|
<input type="text" id="estimate_no" value="">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- 인사말 -->
|
|
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 10px; padding: 0px 5px;">
|
|
<!-- 왼쪽: 인사말 -->
|
|
<div style="line-height: 1.6; font-size: 10pt;">
|
|
견적을 요청해 주셔서 대단히 감사합니다.<br>
|
|
하기와 같이 견적서를 제출합니다.
|
|
</div>
|
|
<!-- 오른쪽: 담당자 정보 및 부가세 별도 -->
|
|
<div style="text-align: right; font-size: 9pt; line-height: 1.8;">
|
|
담당자 : <input type="text" id="manager_name" value="" readonly style="width: 120px; border: none; border-bottom: 1px solid #ddd; font-size: 9pt; padding: 2px; background-color: #f5f5f5;"><br>
|
|
연락처 : <input type="text" id="manager_contact" value="" readonly style="width: 120px; border: none; border-bottom: 1px solid #ddd; font-size: 9pt; padding: 2px; background-color: #f5f5f5;"><br><br>
|
|
<span style="font-size: 10pt; margin-top: 5px; display: inline-block;">부가세 별도</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 품목 테이블 -->
|
|
<table class="items-table">
|
|
<thead>
|
|
<tr>
|
|
<th class="col-no">번호<br>NO.</th>
|
|
<th class="col-desc">품 명<br>DESCRIPTION</th>
|
|
<th class="col-spec">규 격<br>SPECIFICATION</th>
|
|
<th class="col-qty">수량<br>Q'TY</th>
|
|
<th class="col-unit">단위<br>UNIT</th>
|
|
<th class="col-price">단 가<br>UNIT<br>PRICE</th>
|
|
<th class="col-amount">금 액<br>AMOUNT</th>
|
|
<th class="col-note">비고</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="itemsTableBody">
|
|
<tr id="default_item_1">
|
|
<td>1</td>
|
|
<td class="text-left editable">
|
|
<select class="item-desc-select" style="width:100%;"></select>
|
|
<input type="hidden" class="item-desc" value="">
|
|
<input type="hidden" class="item-part-objid" value="">
|
|
</td>
|
|
<td class="text-left editable"><textarea class="item-spec"></textarea></td>
|
|
<td class="editable"><input type="text" class="item-qty" value=""></td>
|
|
<td class="editable"><input type="text" class="item-unit" value="EA"></td>
|
|
<td class="text-right editable"><input type="text" class="item-price" value=""></td>
|
|
<td class="text-right editable"><input type="text" class="item-amount" value="" readonly></td>
|
|
<td class="editable"><input type="text" class="item-note" value=""></td>
|
|
</tr>
|
|
<tr id="default_item_2">
|
|
<td>2</td>
|
|
<td class="text-left editable">
|
|
<select class="item-desc-select" style="width:100%;"></select>
|
|
<input type="hidden" class="item-desc" value="">
|
|
<input type="hidden" class="item-part-objid" value="">
|
|
</td>
|
|
<td class="text-left editable"><textarea class="item-spec"></textarea></td>
|
|
<td class="editable"><input type="text" class="item-qty" value=""></td>
|
|
<td class="editable"><input type="text" class="item-unit" value="EA"></td>
|
|
<td class="text-right editable"><input type="text" class="item-price" value=""></td>
|
|
<td class="text-right editable"><input type="text" class="item-amount" value="" readonly></td>
|
|
<td class="editable"><input type="text" class="item-note" value=""></td>
|
|
</tr>
|
|
<!-- 계 행 -->
|
|
<tr class="total-row">
|
|
<td colspan="6" style="text-align: center; font-weight: bold; background-color: #f0f0f0;">계</td>
|
|
<td class="text-right" style="font-weight: bold; background-color: #f0f0f0;"><span id="totalAmount">0</span></td>
|
|
<td style="background-color: #f0f0f0;"></td>
|
|
</tr>
|
|
<!-- 원화환산 공급가액 행 (숨김) -->
|
|
<tr class="total-krw-row" style="display: none;">
|
|
<td colspan="6" style="text-align: center; font-weight: bold; background-color: #e8f4f8;">원화환산 공급가액 (KRW)</td>
|
|
<td class="text-right" style="font-weight: bold; background-color: #e8f4f8;"><span id="totalAmountKRW">0</span></td>
|
|
<td style="background-color: #e8f4f8;"></td>
|
|
</tr>
|
|
<!-- 비고 행 -->
|
|
<tr class="remarks-row">
|
|
<td colspan="8" style="height: 100px; vertical-align: top; padding: 10px; text-align: left;">
|
|
<div style="font-weight: bold; margin-bottom: 10px; text-align: left;"><비고></div>
|
|
<textarea id="note_remarks" style="width: 100%; height: 70px; border: none; resize: none; font-family: inherit; font-size: 10pt; text-align: left;"></textarea>
|
|
</td>
|
|
</tr>
|
|
<!-- 참조사항 행 -->
|
|
<tr class="notes-row">
|
|
<td colspan="8" style="vertical-align: top; padding: 10px; text-align: left; border: 1px solid #000;">
|
|
<div style="font-weight: bold; margin-bottom: 10px; text-align: left;"><참조사항></div>
|
|
<div class="editable" style="margin-bottom: 5px;"><input type="text" id="note1" value="1. 견적유효기간: 일" style="width: 100%; border: none; background: transparent; font-size: 10pt;"></div>
|
|
<div class="editable" style="margin-bottom: 5px;"><input type="text" id="note2" value="2. 납품기간: 발주 후 1주 이내" style="width: 100%; border: none; background: transparent; font-size: 10pt;"></div>
|
|
<div class="editable" style="margin-bottom: 5px;"><input type="text" id="note3" value="3. VAT 별도" style="width: 100%; border: none; background: transparent; font-size: 10pt;"></div>
|
|
<div class="editable" style="margin-bottom: 5px;"><input type="text" id="note4" value="4. 결제 조건 : 기존 결제조건에 따름." style="width: 100%; border: none; background: transparent; font-size: 10pt;"></div>
|
|
</td>
|
|
</tr>
|
|
<!-- 하단 회사명 행 -->
|
|
<tr class="footer-row">
|
|
<td colspan="8" style="text-align: right; padding: 15px; font-size: 10pt; font-weight: bold; border: none;">
|
|
㈜알피에스
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- 버튼 영역 -->
|
|
<div class="btn-area no-print">
|
|
<button type="button" id="btnAddRow" class="estimate-btn">행 추가</button>
|
|
<button type="button" id="btnPrint" class="estimate-btn">인쇄</button>
|
|
<button type="button" id="btnDownloadPdf" class="estimate-btn">PDF 다운로드</button>
|
|
<button type="button" id="btnSave" class="estimate-btn">저장</button>
|
|
<button type="button" id="btnClose" class="estimate-btn">닫기</button>
|
|
</div>
|
|
|
|
<!-- html2canvas 및 jsPDF 라이브러리 -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>
|
|
<script>
|
|
|
|
// PDF 다운로드 버튼 클릭 이벤트
|
|
$("#btnDownloadPdf").click(function(){
|
|
fn_generatePdf();
|
|
});
|
|
|
|
// PDF 생성 함수
|
|
function fn_generatePdf() {
|
|
// 라이브러리 로드 확인
|
|
if(typeof html2canvas === 'undefined') {
|
|
Swal.fire({
|
|
title: '오류',
|
|
text: 'html2canvas 라이브러리가 로드되지 않았습니다.',
|
|
icon: 'error'
|
|
});
|
|
return;
|
|
}
|
|
|
|
if(typeof jsPDF === 'undefined') {
|
|
Swal.fire({
|
|
title: '오류',
|
|
text: 'jsPDF 라이브러리가 로드되지 않았습니다.',
|
|
icon: 'error'
|
|
});
|
|
return;
|
|
}
|
|
|
|
Swal.fire({
|
|
title: 'PDF 생성 중...',
|
|
text: '잠시만 기다려주세요.',
|
|
allowOutsideClick: false,
|
|
onOpen: () => {
|
|
Swal.showLoading();
|
|
}
|
|
});
|
|
|
|
// 버튼 영역 임시 숨김
|
|
$('.btn-area').hide();
|
|
|
|
// PDF 생성을 위해 스타일 조정
|
|
var container = $('.estimate-container');
|
|
var originalBg = container.css('background');
|
|
var originalShadow = container.css('box-shadow');
|
|
var originalPadding = container.css('padding');
|
|
|
|
// 깔끔한 PDF를 위해 배경, 그림자, 패딩 제거
|
|
container.css({
|
|
'background': 'white',
|
|
'box-shadow': 'none',
|
|
'padding': '10mm'
|
|
});
|
|
|
|
// body 배경색도 흰색으로
|
|
var originalBodyBg = $('body').css('background-color');
|
|
$('body').css('background-color', 'white');
|
|
|
|
// 견적서 컨테이너 캡처
|
|
html2canvas(document.querySelector('.estimate-container'), {
|
|
scale: 2, // 적절한 해상도 (파일 크기 최적화)
|
|
useCORS: true,
|
|
logging: false,
|
|
backgroundColor: '#ffffff'
|
|
}).then(function(canvas) {
|
|
// 스타일 복원
|
|
container.css({
|
|
'background': originalBg,
|
|
'box-shadow': originalShadow,
|
|
'padding': originalPadding
|
|
});
|
|
$('body').css('background-color', originalBodyBg);
|
|
// 버튼 영역 다시 표시
|
|
$('.btn-area').show();
|
|
|
|
try {
|
|
// Canvas를 JPEG 이미지로 변환 (PNG보다 파일 크기 작음)
|
|
var imgData = canvas.toDataURL('image/jpeg', 0.85); // 85% 품질
|
|
|
|
// PDF 생성 (A4 크기)
|
|
var pdf = new jsPDF('p', 'mm', 'a4');
|
|
var imgWidth = 210; // A4 width in mm
|
|
var pageHeight = 297; // A4 height in mm
|
|
var imgHeight = canvas.height * imgWidth / canvas.width;
|
|
var heightLeft = imgHeight;
|
|
var position = 0;
|
|
|
|
// 첫 페이지 추가 (JPEG 압축)
|
|
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
|
heightLeft -= pageHeight;
|
|
|
|
// 페이지가 넘어가면 추가 페이지 생성
|
|
while (heightLeft >= 0) {
|
|
position = heightLeft - imgHeight;
|
|
pdf.addPage();
|
|
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
|
heightLeft -= pageHeight;
|
|
}
|
|
|
|
// 파일명 생성
|
|
var estimateNo = $("#estimate_no").val() || "견적서";
|
|
var fileName = estimateNo + '.pdf';
|
|
|
|
// PDF 다운로드
|
|
pdf.save(fileName);
|
|
|
|
Swal.close();
|
|
Swal.fire({
|
|
title: 'PDF 생성 완료',
|
|
text: 'PDF 파일이 다운로드되었습니다.',
|
|
icon: 'success',
|
|
timer: 2000
|
|
});
|
|
} catch(pdfError) {
|
|
Swal.close();
|
|
console.error('PDF 생성 오류:', pdfError);
|
|
Swal.fire({
|
|
title: '오류',
|
|
text: 'PDF 생성 중 오류가 발생했습니다: ' + pdfError.message,
|
|
icon: 'error'
|
|
});
|
|
}
|
|
}).catch(function(error) {
|
|
$('.btn-area').show();
|
|
Swal.close();
|
|
console.error('Canvas 캡처 오류:', error);
|
|
Swal.fire({
|
|
title: '오류',
|
|
text: '페이지 캡처 중 오류가 발생했습니다: ' + error.message,
|
|
icon: 'error'
|
|
});
|
|
});
|
|
}
|
|
|
|
// PDF를 Base64로 생성하여 서버로 전송하는 함수
|
|
function fn_generateAndUploadPdf(callback) {
|
|
console.log('fn_generateAndUploadPdf 호출됨');
|
|
|
|
// 라이브러리 로드 확인
|
|
if(typeof html2canvas === 'undefined' || typeof jsPDF === 'undefined') {
|
|
console.error('필요한 라이브러리가 로드되지 않았습니다.');
|
|
if(callback && typeof callback === 'function') {
|
|
callback(null);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// 버튼 영역 임시 숨김
|
|
$('.btn-area').hide();
|
|
|
|
// PDF 생성을 위해 스타일 조정
|
|
var container = $('.estimate-container');
|
|
var originalBg = container.css('background');
|
|
var originalShadow = container.css('box-shadow');
|
|
var originalPadding = container.css('padding');
|
|
|
|
// 깔끔한 PDF를 위해 배경, 그림자, 패딩 제거
|
|
container.css({
|
|
'background': 'white',
|
|
'box-shadow': 'none',
|
|
'padding': '10mm'
|
|
});
|
|
|
|
// body 배경색도 흰색으로
|
|
var originalBodyBg = $('body').css('background-color');
|
|
$('body').css('background-color', 'white');
|
|
|
|
// 견적서 컨테이너 캡처
|
|
html2canvas(document.querySelector('.estimate-container'), {
|
|
scale: 2, // 적절한 해상도 (파일 크기 최적화)
|
|
useCORS: true,
|
|
logging: false,
|
|
backgroundColor: '#ffffff'
|
|
}).then(function(canvas) {
|
|
console.log('Canvas 캡처 완료');
|
|
|
|
// 스타일 복원
|
|
container.css({
|
|
'background': originalBg,
|
|
'box-shadow': originalShadow,
|
|
'padding': originalPadding
|
|
});
|
|
$('body').css('background-color', originalBodyBg);
|
|
|
|
// 버튼 영역 다시 표시
|
|
$('.btn-area').show();
|
|
|
|
try {
|
|
// Canvas를 JPEG 이미지로 변환 (PNG보다 파일 크기 작음)
|
|
var imgData = canvas.toDataURL('image/jpeg', 0.85); // 85% 품질
|
|
console.log('이미지 변환 완료');
|
|
|
|
// PDF 생성
|
|
var pdf = new jsPDF('p', 'mm', 'a4');
|
|
var imgWidth = 210;
|
|
var pageHeight = 297;
|
|
var imgHeight = canvas.height * imgWidth / canvas.width;
|
|
var heightLeft = imgHeight;
|
|
var position = 0;
|
|
|
|
// JPEG 이미지 추가 (압축됨)
|
|
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
|
heightLeft -= pageHeight;
|
|
|
|
while (heightLeft >= 0) {
|
|
position = heightLeft - imgHeight;
|
|
pdf.addPage();
|
|
pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight, undefined, 'FAST');
|
|
heightLeft -= pageHeight;
|
|
}
|
|
|
|
console.log('PDF 생성 완료');
|
|
|
|
// PDF를 Base64로 변환
|
|
var pdfBase64 = pdf.output('dataurlstring').split(',')[1];
|
|
console.log('PDF Base64 생성 완료, 길이:', pdfBase64.length);
|
|
|
|
// 콜백 함수 호출 (메일 발송 등에 사용)
|
|
if(callback && typeof callback === 'function') {
|
|
callback(pdfBase64);
|
|
}
|
|
} catch(pdfError) {
|
|
console.error('PDF 생성 중 오류:', pdfError);
|
|
if(callback && typeof callback === 'function') {
|
|
callback(null);
|
|
}
|
|
}
|
|
|
|
}).catch(function(error) {
|
|
$('.btn-area').show();
|
|
console.error('Canvas 캡처 오류:', error);
|
|
if(callback && typeof callback === 'function') {
|
|
callback(null);
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|