Files
wace_plm/WebContent/WEB-INF/view/contractMgmt/estimateTemplate2.jsp
hjjeong 60356f886c feat: 견적서 작성 기능 추가 (일반 견적서, 장비 견적서)
- 견적서 템플릿 2종 추가 (estimateTemplate1.jsp, estimateTemplate2.jsp)
- 견적서 작성 팝업 기능 구현 (estimateList_new.jsp)
- 견적서 템플릿 컨트롤러 및 서비스 메서드 추가
- 견적서 템플릿용 DB 테이블 스키마 생성 스크립트 추가
- 회사 직인 이미지 추가
- 견적서 양식: A4 인쇄 최적화, 동적 품목 추가/수정, 자동 금액 계산
2025-10-15 15:45:34 +09:00

719 lines
19 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" %>
<%
PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
String userId = CommonUtils.checkNull(person.getUserId());
String objId = CommonUtils.checkNull(request.getParameter("objId"));
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%> - 장비 견적서</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: 10pt;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.estimate-container {
width: 210mm;
min-height: 297mm;
background: white;
margin: 0 auto;
padding: 15mm;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
box-sizing: border-box;
}
.header-section {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20px;
}
.logo-section {
flex: 0 0 150px;
}
.logo-img {
width: 120px;
height: auto;
}
.title-section {
flex: 1;
text-align: center;
}
.title {
font-size: 24pt;
font-weight: bold;
letter-spacing: 15px;
margin-bottom: 20px;
}
.company-info {
flex: 0 0 200px;
text-align: right;
font-size: 9pt;
line-height: 1.5;
}
.company-name {
font-weight: bold;
font-size: 10pt;
margin-bottom: 5px;
}
.basic-info {
display: flex;
gap: 10px;
margin-bottom: 20px;
font-size: 10pt;
}
.basic-info-left {
flex: 0 0 40%;
}
.basic-info-right {
flex: 1;
}
.info-row {
display: flex;
margin-bottom: 5px;
}
.info-label {
width: 80px;
font-weight: bold;
}
.info-value {
flex: 1;
}
.model-header {
background-color: #90EE90;
padding: 8px;
text-align: center;
font-weight: bold;
border: 1px solid #000;
margin-bottom: 0;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 0;
}
.items-table th,
.items-table td {
border: 1px solid #000;
padding: 8px;
font-size: 9pt;
}
.items-table th {
background-color: #E8E8E8;
font-weight: bold;
text-align: center;
}
.items-table .col-no { width: 5%; text-align: center; }
.items-table .col-desc { width: 25%; }
.items-table .col-spec { width: 30%; }
.items-table .col-qty { width: 7%; text-align: center; }
.items-table .col-price { width: 12%; text-align: right; }
.items-table .col-amount { width: 12%; text-align: right; }
.items-table .col-remark { width: 9%; text-align: center; }
.category-row {
background-color: #f0f0f0;
font-weight: bold;
}
.subtotal-row {
background-color: #FFFF00;
font-weight: bold;
}
.subtotal-row td {
text-align: center;
}
.detail-row {
height: 60px;
}
.notes-section {
margin-top: 20px;
padding: 15px;
border: 1px solid #ddd;
font-size: 9pt;
line-height: 1.8;
}
.notes-section ul {
margin: 5px 0;
padding-left: 20px;
}
.notes-section li {
margin-bottom: 5px;
}
.footer-section {
display: flex;
justify-content: space-between;
margin-top: 20px;
font-size: 8pt;
color: #666;
}
.company-footer {
text-align: right;
font-weight: bold;
font-size: 11pt;
}
input[type="text"],
textarea {
border: none;
outline: none;
background: transparent;
width: 100%;
font-family: inherit;
font-size: inherit;
}
.editable {
background-color: #fffef0;
}
.highlight {
background-color: #FFFF00 !important;
}
.vat-badge {
background-color: #FFFF00;
padding: 3px 8px;
font-weight: bold;
display: inline-block;
}
.btn-area {
text-align: center;
margin-top: 20px;
padding: 10px;
}
.plm_btns {
padding: 10px 30px;
margin: 0 5px;
font-size: 14px;
cursor: pointer;
}
@media print {
.editable {
background-color: transparent;
}
}
</style>
<script type="text/javascript">
$(function(){
// 인쇄 버튼
$("#btnPrint").click(function(){
window.print();
});
// 저장 버튼
$("#btnSave").click(function(){
if(confirm("장비 견적서를 저장하시겠습니까?")) {
fn_save();
}
});
// 닫기 버튼
$("#btnClose").click(function(){
self.close();
});
// 금액 자동 계산
$(".item-qty, .item-price").on("change keyup", function(){
fn_calculateAmount($(this).closest("tr"));
fn_calculateSubtotal($(this).closest("tbody"));
});
// 콤마 자동 추가
$(".item-price, .item-amount, .subtotal-amount").on("blur", function(){
var val = $(this).val().replace(/,/g, "");
if(!isNaN(val) && val !== "") {
$(this).val(addComma(val));
}
});
// 데이터 로드
if("<%=objId%>" !== "" && "<%=objId%>" !== "-1") {
fn_loadData();
}
});
// 금액 계산
function fn_calculateAmount(row) {
if(row.hasClass("category-row") || row.hasClass("subtotal-row")) {
return;
}
var qty = row.find(".item-qty").val() || "1";
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_calculateSubtotal(tbody) {
var total = 0;
tbody.find("tr:not(.category-row):not(.subtotal-row)").each(function() {
var amount = $(this).find(".item-amount").val();
if(amount) {
var numAmount = parseInt(amount.replace(/,/g, "").replace(/-/g, ""));
if(!isNaN(numAmount)) {
total += numAmount;
}
}
});
tbody.find(".subtotal-amount").val(addComma(total));
}
// 콤마 추가
function addComma(num) {
var regexp = /\B(?=(\d{3})+(?!\d))/g;
return num.toString().replace(regexp, ',');
}
// 데이터 로드
function fn_loadData() {
$.ajax({
url: "/contractMgmt/getEstimateDetail.do",
type: "POST",
data: {
objId: "<%=objId%>",
template_type: "2"
},
dataType: "json",
success: function(data) {
if(data && data.estimate) {
// 기본 정보 바인딩
$("#executor_date").val(data.estimate.EXECUTOR_DATE || "");
$("#recipient").val(data.estimate.RECIPIENT || "");
$("#model_name").val(data.estimate.MODEL_NAME || "");
$("#model_code").val(data.estimate.MODEL_CODE || "RUV-RA500S");
// 품목 데이터 로드 (카테고리별로 구분된 경우)
if(data.items && data.items.length > 0) {
// 데이터 바인딩 로직
}
}
},
error: function() {
Swal.fire("데이터를 불러오는데 실패했습니다.");
}
});
}
// 저장
function fn_save() {
var categories = [];
// 각 카테고리별 데이터 수집
$(".category-section").each(function() {
var section = $(this);
var categoryName = section.data("category");
var items = [];
section.find("tr.detail-row").each(function() {
var row = $(this);
items.push({
description: row.find(".item-desc").val(),
specification: row.find(".item-spec").val(),
quantity: row.find(".item-qty").val(),
unit_price: row.find(".item-price").val().replace(/,/g, ""),
amount: row.find(".item-amount").val().replace(/,/g, ""),
remark: row.find(".item-remark").val()
});
});
var subtotal = section.find(".subtotal-amount").val().replace(/,/g, "");
categories.push({
category: categoryName,
items: items,
subtotal: subtotal
});
});
var formData = {
objId: "<%=objId%>",
template_type: "2",
executor_date: $("#executor_date").val(),
recipient: $("#recipient").val(),
model_name: $("#model_name").val(),
model_code: $("#model_code").val(),
categories: JSON.stringify(categories)
};
$.ajax({
url: "/contractMgmt/saveEstimate.do",
type: "POST",
data: formData,
dataType: "json",
success: function(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("저장에 실패했습니다.");
}
},
error: function() {
Swal.fire("저장 중 오류가 발생했습니다.");
}
});
}
</script>
</head>
<body>
<div class="estimate-container">
<!-- 헤더 섹션 -->
<div class="header-section">
<div class="logo-section">
<div style="border: 1px solid #ccc; padding: 20px; text-align: center; font-weight: bold; color: #0066cc;">
RPS<br>
<span style="font-size: 8pt;">A division of Cimcherry</span>
</div>
</div>
<div class="title-section">
<div class="title">견 적 서</div>
</div>
<div class="company-info">
<div class="company-name">RPS CO., LTD</div>
<div>대전광역시 유성구 국제과학로 10로 8</div>
<div>TEL: (042)602-3300, FAX: (042)672-3399</div>
</div>
</div>
<!-- 기본 정보 -->
<div class="basic-info">
<div class="basic-info-left">
<div class="info-row">
<div class="info-label">시행일자 :</div>
<div class="info-value editable">
<input type="text" id="executor_date" value="">
</div>
</div>
<div class="info-row">
<div class="info-label">수신처 :</div>
<div class="info-value editable">
<input type="text" id="recipient" value="">
</div>
</div>
<div class="info-row">
<div class="info-label">품  명 :</div>
<div class="info-value editable">
<input type="text" id="model_name" value="RUV-RA500S">
</div>
</div>
</div>
</div>
<!-- 설비 Model 헤더 -->
<div class="model-header">
설비 Model : <span class="editable" style="display: inline-block; min-width: 200px;">
<input type="text" id="model_code" value="RUV-RA500S" style="text-align: center; font-weight: bold;">
</span>
</div>
<!-- 품목 테이블 헤더 -->
<table class="items-table">
<thead>
<tr>
<th class="col-no">NO</th>
<th class="col-desc">DESCRIPTION</th>
<th class="col-spec">SPECIFICATION</th>
<th class="col-qty">Q'TY</th>
<th>UNIT PRICE</th>
<th>AMOUNT</th>
<th class="col-remark">REMARK</th>
</tr>
</thead>
</table>
<!-- 1. 초음파 CNC Machine -->
<table class="items-table category-section" data-category="cnc_machine">
<tbody>
<tr class="category-row">
<td class="col-no">1</td>
<td colspan="6">초음파 CNC Machine</td>
</tr>
<tr class="detail-row">
<td></td>
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable">
<div><input type="text" value="Hole 가공" style="margin-bottom: 5px;"></div>
<div class="highlight"><input type="text" class="item-spec" value="최종 견적가"></div>
</td>
<td class="editable"><input type="text" class="item-qty" value="1"></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable">
<div class="vat-badge">VAT 별도</div>
</td>
</tr>
<tr class="detail-row">
<td></td>
<td colspan="2" class="editable"><input type="text" value="기구"></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 2. 초음파 스캔용 오돔 -->
<table class="items-table category-section" data-category="scan_odom">
<tbody>
<tr class="category-row">
<td class="col-no">2</td>
<td colspan="6">초음파 스캔용 오돔</td>
</tr>
<tr class="detail-row">
<td></td>
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 3. 전장 -->
<table class="items-table category-section" data-category="electric">
<tbody>
<tr class="category-row">
<td class="col-no">3</td>
<td colspan="6">전장</td>
</tr>
<tr class="detail-row">
<td></td>
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
</tbody>
</table>
<!-- 4. UTILITY -->
<table class="items-table category-section" data-category="utility">
<tbody>
<tr class="category-row">
<td class="col-no">4</td>
<td colspan="6">UTILITY</td>
</tr>
<tr class="detail-row">
<td></td>
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
</tbody>
</table>
<!-- 5. 자동화 -->
<table class="items-table category-section" data-category="automation">
<tbody>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
<tr class="category-row">
<td class="col-no">5</td>
<td colspan="6">자동화</td>
</tr>
<tr class="detail-row">
<td></td>
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 6. Option -->
<table class="items-table category-section" data-category="option">
<tbody>
<tr class="category-row">
<td class="col-no">6</td>
<td colspan="6">Option</td>
</tr>
<tr class="detail-row">
<td></td>
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 7. Set up -->
<table class="items-table category-section" data-category="setup">
<tbody>
<tr class="category-row">
<td class="col-no">7</td>
<td colspan="6">Set up</td>
</tr>
<tr class="detail-row">
<td></td>
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 8. 포장/운송 -->
<table class="items-table category-section" data-category="packing">
<tbody>
<tr class="category-row">
<td class="col-no">8</td>
<td colspan="6">포장/운송</td>
</tr>
<tr class="detail-row">
<td></td>
<td class="editable"><input type="text" class="item-desc" value=""></td>
<td class="editable"><input type="text" class="item-spec" value=""></td>
<td class="editable"><input type="text" class="item-qty" value=""></td>
<td class="editable"><input type="text" class="item-price" value=""></td>
<td class="editable"><input type="text" class="item-amount" value="" readonly></td>
<td class="editable"><input type="text" class="item-remark" value=""></td>
</tr>
<tr class="subtotal-row">
<td colspan="5">Subtotal</td>
<td class="editable"><input type="text" class="subtotal-amount" value="-" readonly></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 비고 섹션 -->
<div class="notes-section">
<ul style="list-style: none; padding-left: 0;">
<li>■ 최종 견적가는 부가세 별도입니다.</li>
<li>■ 장비 납기 : 발주 후 7개월</li>
<li>■ 운송 조건 : -</li>
<li>■ 결제 조건 : 계약금 : 30% / 잔금 : 70%</li>
<li style="padding-left: 20px;">- 계약금 : 발주</li>
<li style="padding-left: 20px;">- 잔금 : 검사 완료 후</li>
<li>■ 특이사항 : 최종 장비 사양 확인 후 추가 변경 발생 시 견적 재산정 진행</li>
<li>■ Warrenty Period: 1년(소모성 parts 제외)</li>
<li>■ 주의 : RPS 등의의인 초음파 스캔용 임의 탈거 또는 세척시 보증 할 수 없음.</li>
<li>■ 패킹 견적은 양산 20대 기준의 견적조건 운송 장비 전달 시 동일한 가격 적용 모로.</li>
</ul>
</div>
<!-- 푸터 -->
<div class="footer-section">
<div>* 견적유효기간: 4/5</div>
<div class="company-footer">(㈜)알피에스</div>
</div>
<div style="text-align: right; font-size: 7pt; color: #999; margin-top: 5px;">
* RPS 견적서 - 문서번호: RPS-SE-사업부명 양식 제치부작성 적용본 등을은 결제안전버리
</div>
</div>
<!-- 버튼 영역 -->
<div class="btn-area no-print">
<input type="button" value="인쇄" id="btnPrint" class="plm_btns">
<input type="button" value="저장" id="btnSave" class="plm_btns">
<input type="button" value="닫기" id="btnClose" class="plm_btns">
</div>
</body>
</html>