Files
sam-kd/work/handover_doc.php

1674 lines
64 KiB
PHP
Raw Normal View History

<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if(!isset($_SESSION["level"]) || $_SESSION["level"]>5) {
sleep(1);
header("Location:" . $WebSite . "login/login_form_form.php");
exit;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$title_message = '공사 인수 인계 보고서';
?>
<title><?=$title_message?></title>
<link rel="stylesheet" href="../output/css/style.css">
<style>
/* 메인 테이블 스타일 */
.main-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
font-size: 14px;
}
.main-table td, .main-table th {
border: 1px solid #000;
padding: 5px;
vertical-align: middle;
}
.main-table th {
background-color: #f0f0f0;
font-weight: bold;
text-align: center;
}
/* 서명 관련 스타일 */
.signature-canvas {
border: 1px solid #ccc;
background: white;
cursor: crosshair;
}
.signature-container {
position: relative;
display: inline-block;
width: 100%;
}
.signature-remove {
position: absolute;
top: -4px;
right: -4px;
background: #dc3545;
color: white;
border: none;
border-radius: 50%;
width: 12px;
height: 12px;
font-size: 8px;
cursor: pointer;
display: none;
z-index: 10;
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}
.signature-remove:hover {
background: #c82333;
}
.signature-btn {
background: #007bff;
color: white;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
}
.signature-btn:hover {
background: #0056b3;
}
/* 입력 필드 스타일 */
.form-control-borderless {
border: none;
background: transparent;
width: 100%;
padding: 2px;
}
/* 자동 크기 조정 textarea */
.auto-resize {
resize: none;
overflow: hidden;
min-height: 40px;
transition: height 0.1s ease;
}
/* 모드별 스타일 */
.view-mode .form-control-borderless,
.view-mode input,
.view-mode textarea {
border: none !important;
background: transparent !important;
pointer-events: none !important;
cursor: default !important;
color: #000 !important;
}
.edit-mode .form-control-borderless,
.insert-mode .form-control-borderless,
.edit-mode input,
.insert-mode input,
.edit-mode textarea,
.insert-mode textarea {
border: 1px solid #ced4da !important;
background: white !important;
pointer-events: auto !important;
cursor: text !important;
}
.view-mode .dynamic-button {
display: none !important;
}
.edit-mode .dynamic-button,
.insert-mode .dynamic-button {
display: inline-block !important;
}
/* 조회모드에서 모든 버튼 숨김 (PDF 생성시에도 포함) */
.view-mode .signature-btn {
display: none !important;
}
.view-mode .signature-remove {
display: none !important;
}
/* 테이블 내부의 모든 버튼과 X 버튼 숨김 */
.view-mode .main-table button,
.view-mode .main-table .btn,
.view-mode .dynamic-table button,
.view-mode .dynamic-table .btn,
.view-mode button[onclick*="remove"],
.view-mode button[onclick*="clear"],
.view-mode button[onclick*="add"],
.view-mode button[onclick*="signature"] {
display: none !important;
}
/* 모든 동적 버튼과 X 표시 버튼 숨김 */
.view-mode .dynamic-button,
.view-mode button:contains("×"),
.view-mode button[type="button"] {
display: none !important;
}
/* PDF 인쇄 시에도 버튼 숨김 */
@media print {
.view-mode button,
.view-mode .btn,
.signature-btn,
.signature-remove,
.dynamic-button {
display: none !important;
}
}
/* PDF 생성 시 회의 참석자 '기능' 열 숨김 */
.pdf-mode .attendee-function-column {
display: none !important;
}
/* PDF 생성 시 input 스타일 개선 */
.pdf-mode input,
.pdf-mode textarea {
border: none !important;
background: transparent !important;
outline: none !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
}
/* 조회모드에서 form-control 클래스도 비활성화 */
.view-mode .form-control {
border: none !important;
background: transparent !important;
pointer-events: none !important;
cursor: default !important;
color: #000 !important;
}
.edit-mode .form-control,
.insert-mode .form-control {
border: 1px solid #ced4da !important;
background: white !important;
pointer-events: auto !important;
}
/* 동적 테이블 스타일 */
.dynamic-table {
width: 100%;
border-collapse: collapse;
}
.dynamic-table td {
border: 1px solid #000;
padding: 3px;
}
.btn-add-row {
padding: 2px 8px;
font-size: 12px;
}
/* 회의 참석자 서명 영역 */
.attendee-signature {
min-height: 40px;
border: 1px solid #ddd;
padding: 2px;
}
</style>
</head>
<body class="<?php echo $mode; ?>-mode">
<?php
// 권한 확인
$ApprovalAdmin = false;
// 현재 날짜
$today = date('Y-m-d');
$todayStr = date('y.m.d');
// GET 파라미터 확인
$work_num = isset($_GET['num']) ? $_GET['num'] : '';
$handover_num = isset($_GET['handover_num']) ? $_GET['handover_num'] : '';
// write_form.php에서 전달받은 초기값들
$init_workplacename = isset($_GET['workplacename']) ? $_GET['workplacename'] : '';
$init_contract_amount = isset($_GET['contract_amount']) ? $_GET['contract_amount'] : '';
$init_firstord = isset($_GET['firstord']) ? $_GET['firstord'] : '';
$init_secondord = isset($_GET['secondord']) ? $_GET['secondord'] : '';
// 디버깅을 위한 로그
error_log("handover_doc.php - work_num: " . $work_num . ", handover_num: " . $handover_num);
// work_num 유효성 검사
// if (empty($work_num) || !is_numeric($work_num)) {
// echo "<script>alert('유효하지 않은 작업 번호입니다.'); window.close();</script>";
// exit;
// }
// 모드 설정: handover_num이 0보다 크면 조회모드, 그렇지 않으면 insert모드
$mode = ($handover_num && intval($handover_num) > 0) ? 'view' : 'insert';
// URL에서 mode 파라미터가 있으면 우선 적용
if (isset($_GET['mode']) && $_GET['mode'] == 'edit') {
$mode = 'edit';
}
// 데이터베이스 연결 (PDO 사용)
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// 기존 데이터 로드
$handover_data = null;
if ($handover_num) {
try {
$sql = "SELECT * FROM work_handover WHERE num = ? AND is_deleted = 'N'";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $handover_num, PDO::PARAM_INT);
$stmh->execute();
if ($stmh->rowCount() > 0) {
$handover_data = $stmh->fetch(PDO::FETCH_ASSOC);
}
// echo '<pre>';
// print_r($handover_data['contract_amount']);
// echo '</pre>';
$contract_amount = $handover_data['contract_amount'] ?? '';
} catch (PDOException $Exception) {
print "오류: " . $Exception->getMessage();
}
}
// work 테이블에서 기본 정보 로드
$work_data = null;
if ($work_num) {
try {
$sql = "SELECT * FROM work WHERE num = ?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $work_num, PDO::PARAM_INT);
$stmh->execute();
if ($stmh->rowCount() > 0) {
$work_data = $stmh->fetch(PDO::FETCH_ASSOC);
}
} catch (PDOException $Exception) {
print "오류: " . $Exception->getMessage();
}
}
?>
<!-- 상단 버튼 영역 -->
<div class="container mt-2 mb-2">
<div class="d-flex align-items-center justify-content-end mt-1 m-2">
<?php if ($mode == 'view'): ?>
<button class="btn btn-primary btn-sm me-1 ms-1" onclick="switchToEditMode()">
<i class="bi bi-pencil-fill"></i> 수정
</button>
<button class="btn btn-danger btn-sm me-1 ms-1" onclick="deleteHandover()">
<i class="bi bi-trash-fill"></i> 삭제
</button>
<button class="btn btn-success btn-sm me-1 ms-1" onclick="generatePDF()">
<i class="bi bi-file-earmark-pdf-fill"></i> PDF 저장
</button>
<?php else: ?>
<button class="btn btn-dark btn-sm me-1 ms-1 saveData">
<i class="bi bi-floppy2-fill"></i> 저장
</button>
<?php if ($mode == 'edit'): ?>
<button class="btn btn-secondary btn-sm me-1 ms-1" onclick="switchToViewMode()">
<i class="bi bi-eye-fill"></i> 조회모드
</button>
<?php endif; ?>
<?php endif; ?>
<button class="btn btn-secondary btn-sm me-1 ms-5" onclick="self.close();">
<i class="bi bi-x-lg"></i> 닫기
</button>&nbsp;
</div>
</div>
<div id="content-to-print">
<div class="container-fluid">
<form id="handoverForm">
<input type="hidden" name="work_num" value="<?php echo htmlspecialchars($work_num); ?>">
<input type="hidden" name="handover_num" value="<?php echo htmlspecialchars($handover_num); ?>">
<input type="hidden" id="contract_items_json" name="contract_items_json" value="">
<table>
<tbody>
<tr>
<td rowspan="3" style="width: 60%;">
<div class="row">
<div class="col-sm-2">
<img src="../img/companylogo1.png" alt="경동기업" class="me-1" style="width:150%; height:auto;">
</div>
<div class="col-sm-10">
<div class="d-flex align-items-center justify-content-center m-1">
<span class="text-dark ms-2 me-1 fs-2" > &nbsp; 공사 인수인계 보고서 </span>
</div>
</div>
</div>
</td>
<td class="text-center p-1" style="width : 150px; height:22px; padding:2px;">계약담당</td>
<td class="text-center p-1" style="width : 150px; height:22px; padding:2px;">공사PM</td>
<td class="text-center p-1" style="width : 150px; height:22px; padding:2px;">부서장</td>
<td class="text-center p-1" style="width : 150px; height:22px; padding:2px;">대표</td>
</tr>
<tr style="height:40px;">
<td class="text-center">
<div id="contractManagerDiv" class="signature-container">
<div id="contractManagerSignature" style="min-height: 30px; border: 1px solid #ddd; margin-bottom: 5px; position: relative;">
<?php if ($handover_data && !empty($handover_data['contract_manager_signature']) && strlen(trim($handover_data['contract_manager_signature'])) > 10): ?>
<img src="data:image/png;base64,<?php echo htmlspecialchars($handover_data['contract_manager_signature']); ?>" style="max-width: 100%; max-height: 30px;">
<button type="button" class="signature-remove" onclick="removeSignature('contractManager')" style="display: block;">×</button>
<?php endif; ?>
</div>
<button type="button" class="signature-btn" onclick="openSignatureModal('contractManager')">서명</button>
<input type="hidden" name="contract_manager_signature" value="<?php echo $handover_data ? $handover_data['contract_manager_signature'] : ''; ?>">
<br>
<input type="text" class="form-control" name="contract_manager_date" value="<?php echo $handover_data ? $handover_data['contract_manager_date'] : ''; ?>" placeholder="날짜">
</div>
</td>
<td class="text-center">
<div id="constructionPMDiv" class="signature-container">
<div id="constructionPMSignature" style="min-height: 30px; border: 1px solid #ddd; margin-bottom: 5px; position: relative;">
<?php if ($handover_data && !empty($handover_data['construction_pm_signature']) && strlen(trim($handover_data['construction_pm_signature'])) > 10): ?>
<img src="data:image/png;base64,<?php echo htmlspecialchars($handover_data['construction_pm_signature']); ?>" style="max-width: 100%; max-height: 30px;">
<button type="button" class="signature-remove" onclick="removeSignature('constructionPM')" style="display: block;">×</button>
<?php endif; ?>
</div>
<button type="button" class="signature-btn" onclick="openSignatureModal('constructionPM')">서명</button>
<input type="hidden" name="construction_pm_signature" value="<?php echo $handover_data ? $handover_data['construction_pm_signature'] : ''; ?>">
<br>
<input type="text" class="form-control" name="construction_pm_date" value="<?php echo $handover_data ? $handover_data['construction_pm_date'] : ''; ?>" placeholder="날짜">
</div>
</td>
<td class="text-center">
<div id="departmentHeadDiv" class="signature-container">
<div id="departmentHeadSignature" style="min-height: 30px; border: 1px solid #ddd; margin-bottom: 5px; position: relative;">
<?php if ($handover_data && !empty($handover_data['department_head_signature']) && strlen(trim($handover_data['department_head_signature'])) > 10): ?>
<img src="data:image/png;base64,<?php echo htmlspecialchars($handover_data['department_head_signature']); ?>" style="max-width: 100%; max-height: 30px;">
<button type="button" class="signature-remove" onclick="removeSignature('departmentHead')" style="display: block;">×</button>
<?php endif; ?>
</div>
<button type="button" class="signature-btn" onclick="openSignatureModal('departmentHead')">서명</button>
<input type="hidden" name="department_head_signature" value="<?php echo $handover_data ? $handover_data['department_head_signature'] : ''; ?>">
<br>
<input type="text" class="form-control" name="department_head_date" value="<?php echo $handover_data ? $handover_data['department_head_date'] : ''; ?>" placeholder="날짜">
</div>
</td>
<td class="text-center">
<div id="ceoDiv" class="signature-container">
<div id="ceoSignature" style="min-height: 30px; border: 1px solid #ddd; margin-bottom: 5px; position: relative;">
<?php if ($handover_data && !empty($handover_data['ceo_signature']) && strlen(trim($handover_data['ceo_signature'])) > 10): ?>
<img src="data:image/png;base64,<?php echo htmlspecialchars($handover_data['ceo_signature']); ?>" style="max-width: 100%; max-height: 30px;">
<button type="button" class="signature-remove" onclick="removeSignature('ceo')" style="display: block;">×</button>
<?php endif; ?>
</div>
<button type="button" class="signature-btn" onclick="openSignatureModal('ceo')">서명</button>
<input type="hidden" name="ceo_signature" value="<?php echo $handover_data ? $handover_data['ceo_signature'] : ''; ?>">
<br>
<input type="text" class="form-control" name="ceo_date" value="<?php echo $handover_data ? $handover_data['ceo_date'] : ''; ?>" placeholder="날짜">
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 서명 모달 -->
<div class="modal fade" id="signatureModal" tabindex="-1" aria-labelledby="signatureModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="signatureModalLabel">서명</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="text-center mb-3">
<canvas id="signatureCanvas" class="signature-canvas" width="350" height="200"></canvas>
</div>
<div class="text-center">
<button type="button" class="btn btn-secondary me-2" onclick="clearCanvas()">지우기</button>
<button type="button" class="btn btn-primary" onclick="saveSignature()">확인</button>
</div>
</div>
</div>
</div>
</div>
<!-- 메인 테이블 -->
<div class="container-fluid mt-3 mb-4">
<table class="main-table">
<tbody>
<!-- 현장명 -->
<tr>
<th style="width: 15%;">현장명</th>
<td colspan="3">
<input type="text" class="form-control-borderless text-start" name="workplacename" value="<?php echo $handover_data ? $handover_data['workplacename'] : ($work_data ? $work_data['workplacename'] : $init_workplacename); ?>">
</td>
</tr>
<!-- 발주처 -->
<tr>
<th>발주처</th>
<td colspan="3">
<input type="text" class="form-control-borderless text-start" name="firstord" value="<?php echo $handover_data ? $handover_data['firstord'] : ($work_data ? $work_data['firstord'] : $init_firstord); ?>">
</td>
</tr>
<!-- 시공사 -->
<tr>
<th>시공사</th>
<td colspan="3">
<input type="text" class="form-control-borderless text-start" name="secondord" value="<?php echo $handover_data ? $handover_data['secondord'] : ($work_data ? $work_data['secondord'] : $init_secondord); ?>">
</td>
</tr>
<!-- 준공 계약금액 -->
<tr>
<th rowspan="1" >준공</th>
<td style="width: 30%;">
<input type="month" class="form-control-borderless" name="completion_date" value="<?php
$completion_date = $handover_data ? $handover_data['completion_date'] : '';
// YYYY-MM 형식으로 변환
if (!empty($completion_date)) {
if (preg_match('/^\d{4}-\d{2}$/', $completion_date)) {
echo $completion_date;
} elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $completion_date)) {
echo substr($completion_date, 0, 7); // YYYY-MM-DD -> YYYY-MM
}
}
?>">
</td>
<th style="width: 30%;">계약금액<br>
<input name="priceIncludesVat" id="priceIncludesVat" class="form-control-sm w100px p-0" value="<?php echo $handover_data ? $handover_data['priceIncludesVat'] : '공급가액'; ?>">
</th>
<td style="width: 30%;">
<input type="text" class="form-control-borderless text-start"
style="display: inline-block; width: calc(100% - 20px);"
name="contract_amount"
id="contract_amount"
value="<?php
// $handover_data가 있을 때는 부가세 포함금액이므로 공급가액(10% 부가세 제외)로 변환
if (!empty($contract_amount) && is_numeric(str_replace(',', '', $contract_amount))) {
echo number_format((float)str_replace(',', '', $contract_amount));
}
else {
// 입력값이 부가세 포함(총액)일 경우, 공급가액(부가세 10% 제외)로 변환하여 표시
$amount = $init_contract_amount;
$amount = str_replace(',', '', $amount);
if (is_numeric($amount)) {
// 공급가액 = 총액 / 1.1 (부가세 10% 제외)
$supply_amount = $amount > 0 ? floor($amount / 1.1) : '';
// 원단위가 99로 끝나면 +1 처리
if ($supply_amount !== '' && substr($supply_amount, -2) === '99') {
$supply_amount = $supply_amount + 1;
}
echo $supply_amount !== '' ? number_format($supply_amount) : '';
} else {
echo htmlspecialchars($init_contract_amount);
}
}
?>"
oninput="this.value = this.value.replace(/[^0-9]/g, ''); formatAmountInput(this);"
autocomplete="off"
>
</td>
<script>
// 3자리마다 콤마 자동 입력 함수
function formatAmountInput(el) {
var val = el.value.replace(/[^0-9]/g, '');
if(val === '') {
el.value = '';
return;
}
el.value = val.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
// 페이지 로드 시 기존 값도 콤마 적용
document.addEventListener('DOMContentLoaded', function() {
var amt = document.getElementById('contract_amount');
if(amt) formatAmountInput(amt);
});
</script>
</tr>
<!-- 계약 ITEM (동적 테이블) -->
<tr>
<th >계약<br>ITEM</th>
<td colspan="3" style="padding: 0;">
<div style="text-align: right; padding: 5px;">
<button type="button" class="btn btn-sm btn-outline-primary btn-add-row dynamic-button" onclick="addContractItem()">
<i class="bi bi-plus-circle"></i> 추가
</button>
</div>
<table id="contractItemTable" class="dynamic-table">
<!-- 구분 수량, 비고 -->
<thead class="table-secondary">
<tr>
<td style="width: 33%;">구분</td>
<td style="width: 10%;">수량</td>
<td style="width: 54%;">비고</td>
</tr>
</thead>
<tbody id="contractItemTableBody">
<!-- 동적 행들이 여기에 추가됩니다 -->
</tbody>
</tr>
</table>
</td>
</tr>
<!-- 집행유무 -->
<tr>
<th>집행유무</th>
<td colspan="3">
<div style="display: flex; gap: 10px;">
<div style="flex: 1;">
<label>2 배관 유무:</label>
<input type="text" class="form-control-borderless" style="display: inline-block; width: calc(100% - 100px);" name="secondary_piping" value="<?php echo $handover_data ? $handover_data['secondary_piping'] : ''; ?>">
</div>
<div style="flex: 1;">
<label>도장 & 코킹 유무:</label>
<input type="text" class="form-control-borderless" style="display: inline-block; width: calc(100% - 120px);" name="painting_caulking" value="<?php echo $handover_data ? $handover_data['painting_caulking'] : ''; ?>">
</div>
</div>
</td>
</tr>
<!-- 장비 실행금액 -->
<tr>
<th rowspan="2">장비 <br>실행금액</th>
<td colspan="3">
<textarea class="form-control-borderless auto-resize" name="equipment_cost" style="width: 100%; resize: none; overflow: hidden; min-height: 40px;"><?php echo $handover_data ? $handover_data['equipment_cost'] : ''; ?></textarea>
</td>
</tr>
<!-- 특이사항 -->
<tr>
<th>특이사항</th>
<td colspan="3">
<textarea class="form-control-borderless auto-resize" name="special_notes" style="width: 100%; resize: none; overflow: hidden; min-height: 40px;"><?php echo $handover_data ? $handover_data['special_notes'] : ''; ?></textarea>
</td>
</tr>
<tr>
<tr>
<th rowspan="1">회의 참석자</th>
<td colspan="3" style="padding: 0;">
<div style="text-align: right; padding: 5px;">
<button type="button" class="btn btn-sm btn-outline-primary btn-add-row dynamic-button" onclick="addAttendee()">
<i class="bi bi-plus-circle"></i> 참석자 추가
</button>
</div>
<table id="attendeeTable" class="dynamic-table">
<!-- 회의 참석자 (동적 테이블) -->
<thead>
<tr>
<th style="width: 10%;">성명</th>
<th class="attendee-function-column" style="width: 15%;">기능</th>
<th style="width: 20%;">서명</th>
<th style="width: 55%;">미이행 사유</th>
</tr>
</thead>
<tbody id="attendeeTableBody">
<!-- 동적 행들이 여기에 추가됩니다 -->
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</form>
</div>
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
if(loader)
loader.style.display = 'none';
});
// 수정 모드로 전환
function switchToEditMode() {
const workNum = '<?php echo $work_num; ?>';
const handoverNum = '<?php echo $handover_num; ?>';
window.location.href = `handover_doc.php?num=${workNum}&handover_num=${handoverNum}&mode=edit`;
}
// 조회 모드로 전환
function switchToViewMode() {
const workNum = '<?php echo $work_num; ?>';
const handoverNum = '<?php echo $handover_num; ?>';
window.location.href = `handover_doc.php?num=${workNum}&handover_num=${handoverNum}`;
}
function saveHandover() {
// 폼 데이터 수집
const formData = new FormData(document.getElementById('handoverForm'));
// 계약 ITEM 데이터 수집 (동적 테이블에서)
const contractItems = collectContractItems();
// 회의 참석자 데이터 수집 (동적 테이블에서)
const meetingAttendees = collectAttendees();
// 서명 데이터 수집 (상단 결재 서명들)
const signatureData = {
contract_manager_signature: formData.get('contract_manager_signature') || '',
contract_manager_date: formData.get('contract_manager_date') || '',
construction_pm_signature: formData.get('construction_pm_signature') || '',
construction_pm_date: formData.get('construction_pm_date') || '',
department_head_signature: formData.get('department_head_signature') || '',
department_head_date: formData.get('department_head_date') || '',
ceo_signature: formData.get('ceo_signature') || '',
ceo_date: formData.get('ceo_date') || ''
};
// work_num 값 확인
const workNum = formData.get('work_num') || '<?php echo $work_num; ?>';
const handoverNum = formData.get('handover_num') || '<?php echo $handover_num; ?>';
console.log('work_num:', workNum);
console.log('handover_num:', handoverNum);
// work_num이 없거나 유효하지 않은 경우는 신규 작업으로 처리
if (workNum === 'undefined' || workNum === 'null') {
workNum = '';
}
// 최종 데이터 구성
const finalData = {
work_num: workNum,
handover_num: handoverNum,
workplacename: formData.get('workplacename') || '',
firstord: formData.get('firstord') || '',
secondord: formData.get('secondord') || '',
completion_date: formData.get('completion_date') || '',
contract_amount: formData.get('contract_amount') || '',
contract_items: JSON.stringify(contractItems),
execution_status: '', // 기존 필드 유지
secondary_piping: formData.get('secondary_piping') || '',
painting_caulking: formData.get('painting_caulking') || '',
equipment_cost: formData.get('equipment_cost') || '',
special_notes: formData.get('special_notes') || '',
meeting_attendees: JSON.stringify(meetingAttendees),
// 상단 결재 서명 데이터
contract_manager_signature: signatureData.contract_manager_signature,
contract_manager_date: signatureData.contract_manager_date,
construction_pm_signature: signatureData.construction_pm_signature,
construction_pm_date: signatureData.construction_pm_date,
department_head_signature: signatureData.department_head_signature,
department_head_date: signatureData.department_head_date,
ceo_signature: signatureData.ceo_signature,
ceo_date: signatureData.ceo_date,
regist_user: '<?php echo isset($user_name) ? $user_name : $_SESSION["user_name"]; ?>',
priceIncludesVat: formData.get('priceIncludesVat') || ''
};
// 디버깅을 위한 콘솔 출력
console.log('PHP에서 받은 work_num:', '<?php echo $work_num; ?>');
console.log('PHP에서 받은 handover_num:', '<?php echo $handover_num; ?>');
console.log('저장할 데이터:', finalData);
console.log('계약 ITEM:', contractItems);
console.log('회의 참석자:', meetingAttendees);
console.log('서명 데이터:', signatureData);
console.log('FormData에서 가져온 서명들:');
console.log(' - contract_manager_signature:', formData.get('contract_manager_signature'));
console.log(' - construction_pm_signature:', formData.get('construction_pm_signature'));
console.log(' - department_head_signature:', formData.get('department_head_signature'));
console.log(' - ceo_signature:', formData.get('ceo_signature'));
// AJAX로 데이터 전송
fetch('insert_handover.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(finalData)
})
.then(response => {
// 응답이 JSON인지 확인
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return response.json();
} else {
// JSON이 아닌 경우 텍스트로 받아서 로그 출력
return response.text().then(text => {
console.error('Non-JSON response:', text);
throw new Error('서버에서 유효하지 않은 응답을 받았습니다.');
});
}
})
.then(data => {
if (data.success) {
Swal.fire({
title: '성공',
text: '인수인계 보고서가 저장되었습니다.',
icon: 'success',
confirmButtonText: '확인'
}).then(() => {
// 저장 후 조회모드로 리다이렉션 (응답에서 받은 work_num 사용)
const workNum = data.work_num || finalData.work_num;
const handoverNum = data.handover_num;
window.location.href = `handover_doc.php?num=${workNum}&handover_num=${handoverNum}`;
});
} else {
Swal.fire({
title: '오류',
text: '저장 중 오류가 발생했습니다: ' + (data.message || '알 수 없는 오류'),
icon: 'error',
confirmButtonText: '확인'
});
}
})
.catch(error => {
console.error('Error:', error);
Swal.fire({
title: '오류',
text: '저장 중 오류가 발생했습니다.',
icon: 'error',
confirmButtonText: '확인'
});
});
}
function printDocument() {
window.print();
}
function exportPDF() {
// PDF 내보내기 기능 (추후 구현)
alert('PDF 내보내기 기능은 추후 구현 예정입니다.');
}
function resetForm() {
if (confirm('모든 입력 내용을 초기화하시겠습니까?')) {
document.getElementById('handoverForm').reset();
}
}
function deleteHandover() {
Swal.fire({
title: '삭제 확인',
text: '인수인계 보고서를 삭제하시겠습니까?\n삭제된 데이터는 복구할 수 없습니다.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: '삭제',
cancelButtonText: '취소',
confirmButtonColor: '#dc3545',
reverseButtons: true
}).then((result) => {
if (result.isConfirmed) {
const handoverNum = '<?php echo $handover_num; ?>';
// 삭제 진행 중 표시
Swal.fire({
title: '삭제 중...',
text: '잠시만 기다려주세요.',
allowOutsideClick: false,
allowEscapeKey: false,
showConfirmButton: false,
didOpen: () => {
Swal.showLoading();
}
});
fetch('delete_handover.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ handover_num: handoverNum })
})
.then(response => {
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return response.json();
} else {
return response.text().then(text => {
console.error('Non-JSON response:', text);
throw new Error('서버에서 유효하지 않은 응답을 받았습니다.');
});
}
})
.then(data => {
if (data.success) {
Swal.fire({
title: '삭제 완료',
text: '인수인계 보고서가 삭제되었습니다.',
icon: 'success',
confirmButtonText: '확인'
}).then(() => {
// 삭제 후 창 닫기 또는 목록으로 이동
window.close();
});
} else {
Swal.fire({
title: '삭제 실패',
text: '삭제 중 오류가 발생했습니다: ' + (data.message || '알 수 없는 오류'),
icon: 'error',
confirmButtonText: '확인'
});
}
})
.catch(error => {
console.error('Error:', error);
Swal.fire({
title: '오류',
text: '삭제 중 오류가 발생했습니다.',
icon: 'error',
confirmButtonText: '확인'
});
});
}
});
}
// viewBendingWork.php 참조 기능들
$(document).ready(function() {
// 품질 승인 버튼 클릭 이벤트
$('.approvalBtn').click(function() {
// 승인자의 이름과 오늘 날짜 가져오기
const userName = '<?=$user_name?>'; // PHP로부터 가져온 사용자 이름
const todayStr = '<?=$todayStr?>'; // PHP로부터 가져온 오늘 날짜
// 승인 정보를 approvalDiv에 표시
$('#approvalDiv').html(
'<input type="text" class="form-control" name="approver_name" value="' + userName + '" readonly><br>' +
'<input type="text" class="form-control" name="approver_date" value="' + todayStr + '" readonly>'
);
$('#approvalDiv').show();
// 검토 정보도 표시
$('#reviewDiv').html(
'<input type="text" class="form-control" name="reviewer_name" value="' + userName + '" readonly><br>' +
'<input type="text" class="form-control" name="reviewer_date" value="' + todayStr + '" readonly>'
);
$('#reviewDiv').show();
});
// 서버 저장 버튼 클릭 이벤트
$('.saveData').off('click').on('click', function() {
saveHandover();
});
});
// PDF 생성 함수
function generatePDF() {
var workplace = '<?php echo $handover_data ? htmlspecialchars($handover_data["workplacename"], ENT_QUOTES) : ""; ?>';
var deadline = '<?php echo $handover_data ? htmlspecialchars($handover_data["completion_date"], ENT_QUOTES) : ""; ?>';
var result = 'JUIL인수인계_보고서(' + workplace + ')' + deadline + '.pdf';
var element = document.getElementById('content-to-print');
// PDF 생성 전 처리
preparePDFMode();
var opt = {
margin: [10, 3, 12, 3], // Top, right, bottom, left margins
filename: result,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {
scale: 1,
useCORS: true,
allowTaint: true
},
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: { mode: [''] }
};
// PDF 생성 및 완료 후 복원
html2pdf().from(element).set(opt).save().then(() => {
// PDF 생성 완료 후 원래 상태로 복원
restoreFromPDFMode();
}).catch((error) => {
console.error('PDF 생성 오류:', error);
// 오류 발생 시에도 복원
restoreFromPDFMode();
});
}
// 결재 취소 기능
$(document).on('click', '.remove-approval', function() {
// 결재 정보를 지우고 화면에서 숨김
$('#approvalDiv').html('').hide();
$('#reviewDiv').html('').hide();
Toastify({
text: "결재 정보가 삭제되었습니다.",
duration: 2000,
close: true,
gravity: "top",
position: "center",
style: {
background: "linear-gradient(to right, #ff5f6d, #ffc371)"
},
}).showToast();
});
function captureReturnKey(e) {
if(e.keyCode==13 && e.srcElement.type != 'textarea')
return false;
}
// 서명 관련 변수
let currentSignatureType = '';
let signatureCanvas = null;
let signatureContext = null;
let isDrawing = false;
let lastX = 0;
let lastY = 0;
// 서명 캔버스 초기화
function initSignatureCanvas() {
const canvas = document.getElementById('signatureCanvas');
signatureCanvas = canvas;
signatureContext = canvas.getContext('2d');
// 캔버스 스타일 설정
signatureContext.strokeStyle = '#000';
signatureContext.lineWidth = 2;
signatureContext.lineCap = 'round';
signatureContext.lineJoin = 'round';
// 이벤트 리스너 추가
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
// 터치 이벤트 추가 (모바일 지원)
canvas.addEventListener('touchstart', handleTouchStart);
canvas.addEventListener('touchmove', handleTouchMove);
canvas.addEventListener('touchend', stopDrawing);
// 모달이 닫힐 때 캔버스 초기화
$('#signatureModal').on('hidden.bs.modal', function () {
if (signatureContext) {
signatureContext.clearRect(0, 0, signatureCanvas.width, signatureCanvas.height);
}
isDrawing = false;
});
}
// 마우스 이벤트 처리
function startDrawing(e) {
isDrawing = true;
const rect = signatureCanvas.getBoundingClientRect();
lastX = e.clientX - rect.left;
lastY = e.clientY - rect.top;
}
function draw(e) {
if (!isDrawing) return;
e.preventDefault();
const rect = signatureCanvas.getBoundingClientRect();
const currentX = e.clientX - rect.left;
const currentY = e.clientY - rect.top;
signatureContext.beginPath();
signatureContext.moveTo(lastX, lastY);
signatureContext.lineTo(currentX, currentY);
signatureContext.stroke();
lastX = currentX;
lastY = currentY;
}
function stopDrawing() {
isDrawing = false;
}
// 터치 이벤트 처리
function handleTouchStart(e) {
e.preventDefault();
const touch = e.touches[0];
const rect = signatureCanvas.getBoundingClientRect();
lastX = touch.clientX - rect.left;
lastY = touch.clientY - rect.top;
isDrawing = true;
}
function handleTouchMove(e) {
e.preventDefault();
if (!isDrawing) return;
const touch = e.touches[0];
const rect = signatureCanvas.getBoundingClientRect();
const currentX = touch.clientX - rect.left;
const currentY = touch.clientY - rect.top;
signatureContext.beginPath();
signatureContext.moveTo(lastX, lastY);
signatureContext.lineTo(currentX, currentY);
signatureContext.stroke();
lastX = currentX;
lastY = currentY;
}
// 캔버스 지우기
function clearCanvas() {
signatureContext.clearRect(0, 0, signatureCanvas.width, signatureCanvas.height);
}
// 서명 모달 열기
function openSignatureModal(signatureType) {
// 조회모드에서는 서명 모달을 열지 않음
const mode = '<?php echo $mode; ?>';
if (mode === 'view') {
return false;
}
currentSignatureType = signatureType;
// 모달 제목 설정
let title = '';
switch(signatureType) {
case 'contractManager':
title = '계약담당 서명';
break;
case 'constructionPM':
title = '공사PM 서명';
break;
case 'departmentHead':
title = '부서장 서명';
break;
case 'ceo':
title = '대표 서명';
break;
}
$('#signatureModalLabel').text(title);
$('#signatureModal').modal('show');
// 모달이 완전히 열린 후 캔버스 초기화
setTimeout(() => {
initSignatureCanvas();
// 캔버스 초기화 (이전 서명 지우기)
if (signatureContext) {
signatureContext.clearRect(0, 0, signatureCanvas.width, signatureCanvas.height);
}
}, 300);
}
// 서명 저장
function saveSignature() {
// 캔버스가 비어있는지 확인
const imageData = signatureContext.getImageData(0, 0, signatureCanvas.width, signatureCanvas.height);
const hasContent = imageData.data.some(channel => channel !== 0);
if (!hasContent) {
Swal.fire({
title: '알림',
text: '서명을 그려주세요.',
icon: 'warning',
confirmButtonText: '확인'
});
return;
}
// base64로 변환
const signatureDataUrl = signatureCanvas.toDataURL('image/png');
const base64Data = signatureDataUrl.split(',')[1]; // data:image/png;base64, 부분 제거
// 참석자 서명인 경우
if (currentSignatureType.startsWith('attendee_')) {
const attendeeIndex = currentSignatureType.split('_')[1];
// hidden input 업데이트
const hiddenInput = document.getElementById(`attendeeSignatureInput${attendeeIndex}`);
if (hiddenInput) {
hiddenInput.value = base64Data;
}
// 서명 이미지 표시
const signatureDisplay = document.getElementById(`attendeeSignatureDisplay${attendeeIndex}`);
if (signatureDisplay) {
signatureDisplay.innerHTML = `
<img src="${signatureDataUrl}" style="max-width: 100%; max-height: 40px;">
<button type="button" class="btn btn-sm btn-danger dynamic-button" onclick="clearAttendeeSignature(${attendeeIndex})" style="position: absolute; top: 2px; right: 2px; padding: 1px 4px; font-size: 10px;">×</button>
`;
}
} else {
// 기존 서명 처리 (계약담당, 공사PM 등)
let inputName = '';
switch(currentSignatureType) {
case 'contractManager':
inputName = 'contract_manager_signature';
break;
case 'constructionPM':
inputName = 'construction_pm_signature';
break;
case 'departmentHead':
inputName = 'department_head_signature';
break;
case 'ceo':
inputName = 'ceo_signature';
break;
}
const hiddenInput = document.querySelector(`input[name="${inputName}"]`);
if (hiddenInput) {
hiddenInput.value = base64Data;
}
// 서명 이미지 표시
const signatureDiv = document.getElementById(`${currentSignatureType}Signature`);
if (signatureDiv) {
signatureDiv.innerHTML = `
<img src="${signatureDataUrl}" style="max-width: 100%; max-height: 30px;">
<button type="button" class="signature-remove" onclick="removeSignature('${currentSignatureType}')" style="display: block;">×</button>
`;
}
// 날짜 자동 입력
let dateFieldName = '';
switch(currentSignatureType) {
case 'contractManager':
dateFieldName = 'contract_manager_date';
break;
case 'constructionPM':
dateFieldName = 'construction_pm_date';
break;
case 'departmentHead':
dateFieldName = 'department_head_date';
break;
case 'ceo':
dateFieldName = 'ceo_date';
break;
}
const dateInput = document.querySelector(`input[name="${dateFieldName}"]`);
if (dateInput) {
const today = new Date();
const year = today.getFullYear().toString().slice(-2); // 년도 뒤 2자리
const month = String(today.getMonth() + 1).padStart(2, '0'); // 월 2자리
const day = String(today.getDate()).padStart(2, '0'); // 일 2자리
const formattedDate = `${year}.${month}.${day}`;
dateInput.value = formattedDate;
}
}
// 모달 닫기
$('#signatureModal').modal('hide');
// 성공 메시지
Swal.fire({
title: '성공',
text: '서명이 저장되었습니다.',
icon: 'success',
timer: 1500,
showConfirmButton: false
});
}
// 서명 삭제
function removeSignature(signatureType) {
Swal.fire({
title: '확인',
text: '서명을 지우시겠어요?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '네',
cancelButtonText: '아니오'
}).then((result) => {
if (result.isConfirmed) {
// hidden input 초기화
let inputName = '';
switch(signatureType) {
case 'contractManager':
inputName = 'contract_manager_signature';
break;
case 'constructionPM':
inputName = 'construction_pm_signature';
break;
case 'departmentHead':
inputName = 'department_head_signature';
break;
case 'ceo':
inputName = 'ceo_signature';
break;
}
const hiddenInput = document.querySelector(`input[name="${inputName}"]`);
if (hiddenInput) {
hiddenInput.value = '';
}
// 날짜 입력 필드 초기화
let dateFieldName = '';
switch(signatureType) {
case 'contractManager':
dateFieldName = 'contract_manager_date';
break;
case 'constructionPM':
dateFieldName = 'construction_pm_date';
break;
case 'departmentHead':
dateFieldName = 'department_head_date';
break;
case 'ceo':
dateFieldName = 'ceo_date';
break;
}
const dateInput = document.querySelector(`input[name="${dateFieldName}"]`);
if (dateInput) {
dateInput.value = '';
}
// 서명 이미지 제거
const signatureDiv = document.getElementById(`${signatureType}Signature`);
if (signatureDiv) {
signatureDiv.innerHTML = '';
}
Swal.fire({
title: '완료',
text: '서명이 삭제되었습니다.',
icon: 'success',
timer: 1500,
showConfirmButton: false
});
}
});
}
// 계약 ITEM 동적 테이블 관련 전역 변수
let contractItemData = [];
// 모든 input 요소에 autocomplete='off' 속성 적용 (jQuery 사용)
$(document).ready(function() {
$('input').attr('autocomplete', 'off');
// 기존 계약 ITEM 데이터 로드
loadContractItems();
// 기존 회의 참석자 데이터 로드
loadAttendees();
// textarea 자동 크기 조정 기능 적용
autoResizeTextareas();
// 모드에 따른 입력 요소 상태 설정
setModeState();
});
// 모드에 따른 입력 요소 상태 설정
function setModeState() {
const mode = '<?php echo $mode; ?>';
const isViewMode = mode === 'view';
if (isViewMode) {
// 조회모드: 모든 입력 요소 비활성화
$('input, textarea, select').prop('disabled', true).prop('readonly', true);
// 서명 버튼 클릭 이벤트 제거 및 숨김
$('.signature-btn').off('click').addClass('disabled').hide();
$('.signature-remove').off('click').addClass('disabled').hide();
// 동적 버튼들의 클릭 이벤트 제거 및 숨김
$('.dynamic-button').off('click').addClass('disabled').hide();
// 테이블 내 모든 버튼 숨김
$('.main-table button, .dynamic-table button').hide();
$('button[type="button"]').hide();
$('button[onclick*="signature"]').hide();
$('button[onclick*="remove"]').hide();
$('button[onclick*="clear"]').hide();
$('button[onclick*="add"]').hide();
console.log('조회모드: 모든 입력 요소와 버튼이 비활성화되었습니다.');
} else {
// 수정/신규모드: 모든 입력 요소 활성화
$('input, textarea, select').prop('disabled', false).prop('readonly', false);
// hidden input은 readonly 제거
$('input[type="hidden"]').prop('readonly', false);
console.log('편집모드: 모든 입력 요소가 활성화되었습니다.');
}
}
// textarea 자동 크기 조정 함수
function autoResizeTextareas() {
// 기존 textarea에 자동 크기 조정 적용
$('textarea').each(function() {
autoResizeTextarea(this);
});
// 동적으로 생성되는 textarea에도 적용하기 위한 이벤트 델리게이션
$(document).on('input propertychange paste keyup', 'textarea', function() {
autoResizeTextarea(this);
});
// 페이지 로드 후 잠시 뒤 다시 한번 크기 조정 (폰트 로딩 완료 후)
setTimeout(function() {
$('textarea').each(function() {
autoResizeTextarea(this);
});
}, 500);
}
// 개별 textarea 자동 크기 조정 함수
function autoResizeTextarea(textarea) {
// 최소 높이 설정
const minHeight = 40;
// 현재 높이를 최소값으로 리셋
textarea.style.height = minHeight + 'px';
// 스크롤 높이가 더 크면 그에 맞춰 조정
if (textarea.scrollHeight > minHeight) {
textarea.style.height = textarea.scrollHeight + 'px';
}
}
// 계약 ITEM 데이터 로드
function loadContractItems() {
<?php if ($handover_data && $handover_data['contract_items']): ?>
try {
var contractItems = JSON.parse('<?php echo addslashes($handover_data['contract_items']); ?>');
if (contractItems && contractItems.length > 0) {
contractItems.forEach(function(item) {
addContractItem(item);
});
} else {
// 기본 행 추가
addContractItem();
}
} catch (e) {
console.error('계약 ITEM 데이터 파싱 오류:', e);
addContractItem(); // 기본 행 추가
}
<?php else: ?>
// 기본 행 몇 개 추가
addContractItem({item_name: '철재방화셔터', quantity: '', note: ''});
addContractItem({item_name: '스크린방화셔터', quantity: '', note: ''});
<?php endif; ?>
}
// 회의 참석자 데이터 로드
function loadAttendees() {
<?php if ($handover_data && $handover_data['meeting_attendees']): ?>
try {
var attendees = JSON.parse('<?php echo addslashes($handover_data['meeting_attendees']); ?>');
if (attendees && attendees.length > 0) {
attendees.forEach(function(attendee) {
addAttendee(attendee);
});
} else {
// 기본 참석자 추가
addAttendee();
}
} catch (e) {
console.error('회의 참석자 데이터 파싱 오류:', e);
addAttendee(); // 기본 행 추가
}
<?php else: ?>
// 기본 참석자 추가
addAttendee({name: '신승표', signature: '', unfulfilled_reason: ''});
addAttendee({name: '유민수', signature: '', unfulfilled_reason: ''});
addAttendee({name: '계도건', signature: '', unfulfilled_reason: ''});
addAttendee({name: '윤희채', signature: '', unfulfilled_reason: ''});
<?php endif; ?>
}
// 계약 ITEM 행 추가
function addContractItem(data = null) {
// 조회모드에서는 사용자가 직접 행 추가 불가 (데이터 로드시에는 허용)
const mode = '<?php echo $mode; ?>';
if (mode === 'view' && !data) {
return false;
}
var rowData = data || { item_name: '', quantity: '', note: '' };
var newRow = $('<tr>');
// 구분 컬럼
newRow.append('<td ><input type="text" name="contract_item_name[]" class="form-control-borderless" value="' + (rowData.item_name || '') + '" placeholder="구분 입력"></td>');
// 수량 컬럼
newRow.append('<td ><input type="text" name="contract_item_quantity[]" class="form-control-borderless" value="' + (rowData.quantity || '') + '" placeholder="수량 입력"></td>');
// 비고 컬럼 (삭제 버튼 포함)
newRow.append('<td style="position: relative;">\
<input type="text" name="contract_item_note[]" class="form-control-borderless" value="' + (rowData.note || '') + '" placeholder="비고 입력" style="padding-right: 30px;">\
<button type="button" class="btn btn-sm btn-danger dynamic-button" onclick="removeContractItem(this)" style="position: absolute; right: 5px; top: 50%; transform: translateY(-50%); padding: 2px 6px; font-size: 11px;">×</button>\
</td>');
$('#contractItemTableBody').append(newRow);
// 새로 추가된 요소에 모드 설정 적용
setModeState();
}
// 회의 참석자 행 추가
function addAttendee(data = null) {
// 조회모드에서는 사용자가 직접 행 추가 불가 (데이터 로드시에는 허용)
const mode = '<?php echo $mode; ?>';
if (mode === 'view' && !data) {
return false;
}
var rowData = data || { name: '', function: '', signature: '', unfulfilled_reason: '' };
var attendeeIndex = $('#attendeeTableBody tr').length;
var newRow = $('<tr>');
// 성명 컬럼
newRow.append('<td><input type="text" name="attendee_name[]" class="form-control-borderless" value="' + (rowData.name || '') + '" placeholder="성명 입력"></td>');
// 기능 컬럼 (서명 버튼과 삭제 버튼)
newRow.append('<td class="attendee-function-column" style="text-align: center;">\
<button type="button" class="btn btn-sm btn-primary dynamic-button" onclick="openAttendeeSignatureModal(' + attendeeIndex + ')">서명</button>\
<button type="button" class="btn btn-sm btn-outline-danger mt-1 dynamic-button" onclick="removeAttendee(this)" style="padding: 2px 6px; font-size: 11px;">×</button>\
</td>');
// 서명 컬럼 (서명 이미지 표시)
var signatureHtml = '';
if (rowData.signature) {
signatureHtml = '<img src="data:image/png;base64,' + rowData.signature + '" style="max-width: 100%; max-height: 40px;">\
<button type="button" class="btn btn-sm btn-danger dynamic-button" onclick="clearAttendeeSignature(' + attendeeIndex + ')" style="position: absolute; top: 2px; right: 2px; padding: 1px 4px; font-size: 10px;">×</button>';
}
newRow.append('<td style="text-align: center; position: relative;">\
<div id="attendeeSignatureDisplay' + attendeeIndex + '" style="min-height: 40px;">' + signatureHtml + '</div>\
<input type="hidden" name="attendee_signature[]" id="attendeeSignatureInput' + attendeeIndex + '" value="' + (rowData.signature || '') + '">\
</td>');
// 미이행 사유 컬럼
newRow.append('<td>\
<input type="text" name="attendee_unfulfilled[]" class="form-control-borderless" value="' + (rowData.unfulfilled_reason || '') + '" placeholder="미이행 사유">\
</td>');
$('#attendeeTableBody').append(newRow);
// 새로 추가된 요소에 모드 설정 적용
setModeState();
}
// 계약 ITEM 행 삭제
function removeContractItem(button) {
var row = $(button).closest('tr');
if ($('#contractItemTableBody tr').length > 1) {
row.remove();
} else {
Swal.fire({
title: '알림',
text: '최소 하나의 행은 유지해야 합니다.',
icon: 'warning',
confirmButtonText: '확인'
});
}
}
// 회의 참석자 행 삭제
function removeAttendee(button) {
var row = $(button).closest('tr');
if ($('#attendeeTableBody tr').length > 1) {
row.remove();
} else {
Swal.fire({
title: '알림',
text: '최소 한 명의 참석자는 유지해야 합니다.',
icon: 'warning',
confirmButtonText: '확인'
});
}
}
// 참석자 서명 모달 열기
function openAttendeeSignatureModal(index) {
// 조회모드에서는 서명 모달을 열지 않음
const mode = '<?php echo $mode; ?>';
if (mode === 'view') {
return false;
}
currentSignatureType = 'attendee_' + index;
$('#signatureModalLabel').text('참석자 서명');
$('#signatureModal').modal('show');
setTimeout(() => {
initSignatureCanvas();
if (signatureContext) {
signatureContext.clearRect(0, 0, signatureCanvas.width, signatureCanvas.height);
}
}, 300);
}
// 참석자 서명 삭제
function clearAttendeeSignature(index) {
Swal.fire({
title: '확인',
text: '서명을 삭제하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '네',
cancelButtonText: '아니오'
}).then((result) => {
if (result.isConfirmed) {
// hidden input 초기화
const hiddenInput = document.getElementById(`attendeeSignatureInput${index}`);
if (hiddenInput) {
hiddenInput.value = '';
}
// 서명 이미지 제거
const signatureDisplay = document.getElementById(`attendeeSignatureDisplay${index}`);
if (signatureDisplay) {
signatureDisplay.innerHTML = '';
}
Swal.fire({
title: '완료',
text: '서명이 삭제되었습니다.',
icon: 'success',
timer: 1500,
showConfirmButton: false
});
}
});
}
// 계약 ITEM 데이터 수집 및 JSON 변환
function collectContractItems() {
var data = [];
$('#contractItemTableBody tr').each(function() {
var row = $(this);
var itemName = row.find('input[name="contract_item_name[]"]').val();
var quantity = row.find('input[name="contract_item_quantity[]"]').val();
var note = row.find('input[name="contract_item_note[]"]').val();
if (itemName || quantity || note) {
data.push({
item_name: itemName,
quantity: quantity,
note: note
});
}
});
$('#contract_items_json').val(JSON.stringify(data));
return data;
}
// 회의 참석자 데이터 수집
function collectAttendees() {
var data = [];
$('#attendeeTableBody tr').each(function(index) {
var row = $(this);
var name = row.find('input[name="attendee_name[]"]').val() || '';
var signature = $(`#attendeeSignatureInput${index}`).val() || '';
var unfulfilled = row.find('input[name="attendee_unfulfilled[]"]').val() || '';
// 빈 행도 포함하여 순서 유지 (최소한 이름이나 서명이 있는 경우만)
if (name || signature || unfulfilled) {
data.push({
name: name,
signature: signature, // base64 서명 데이터
unfulfilled_reason: unfulfilled
});
}
});
return data;
}
// PDF 모드 준비 함수
function preparePDFMode() {
// body에 pdf-mode 클래스 추가
document.body.classList.add('pdf-mode');
// 모든 input과 textarea의 readonly 속성 임시 제거
$('input, textarea').each(function() {
const $this = $(this);
// 현재 readonly 상태를 data 속성에 저장
if ($this.prop('readonly')) {
$this.attr('data-was-readonly', 'true');
$this.prop('readonly', false);
}
if ($this.prop('disabled')) {
$this.attr('data-was-disabled', 'true');
$this.prop('disabled', false);
}
});
console.log('PDF 모드 준비 완료: readonly 속성 제거됨');
}
// PDF 모드에서 원래 상태로 복원 함수
function restoreFromPDFMode() {
// pdf-mode 클래스 제거
document.body.classList.remove('pdf-mode');
// readonly 속성 복원
$('input, textarea').each(function() {
const $this = $(this);
if ($this.attr('data-was-readonly') === 'true') {
$this.prop('readonly', true);
$this.removeAttr('data-was-readonly');
}
if ($this.attr('data-was-disabled') === 'true') {
$this.prop('disabled', true);
$this.removeAttr('data-was-disabled');
}
});
// 조회 모드인 경우 다시 모드 상태 적용
const mode = '<?php echo $mode; ?>';
if (mode === 'view') {
setModeState();
}
console.log('PDF 모드에서 복원 완료: readonly 속성 복구됨');
}
</script>
</body>
</html>