first commit 2

This commit is contained in:
hmw1001
2026-06-11 18:47:38 +09:00
parent c768729ce6
commit 6f534e33a6
11095 changed files with 1595758 additions and 0 deletions
@@ -0,0 +1,450 @@
<?php
if (!defined('_GNUBOARD_')) exit;
// 💡 [수정] 사용할 전역 변수를 명시적으로 선언하여 스코프 문제를 해결합니다.
global $g5, $w, $bo_table, $wr_id;
// 1. 원본 글 ID 찾기 (고객의 요청 내용을 보여주기 위함)
$write_table = $g5['write_prefix'] . $bo_table;
$original_wr_id = $wr_id; // 기본값 (w=r 일 때)
if ($w == 'u') {
// 답변 수정 시 원본 글 ID 찾기 (wr_num이 같고 wr_reply가 없는 글)
$row_curr = sql_fetch("SELECT wr_num FROM {$write_table} WHERE wr_id = '{$wr_id}'");
if ($row_curr) {
$row_origin = sql_fetch("SELECT wr_id FROM {$write_table} WHERE wr_num = '{$row_curr['wr_num']}' AND wr_reply = ''");
if ($row_origin) {
$original_wr_id = $row_origin['wr_id'];
}
}
}
// 2. 원본 견적 정보 로드 (고객 요청)
$original_estimate = sql_fetch("SELECT * FROM estimate WHERE wr_id = '{$original_wr_id}'");
if (!$original_estimate) {
echo "<div class='alert alert-danger'>원본 견적 요청 정보를 찾을 수 없습니다.</div>";
return;
}
// 3. 아이템 로드 (입력 폼에 뿌려줄 데이터)
// 신규 작성이면 고객 요청 아이템을 불러오고, 수정이면 내가 저장한 아이템을 불러옴
$target_estimate_id = $original_estimate['id'];
$final_amount_value = 0; // 최종 금액 초기값
if ($w == 'u') {
// 내 답변글에 연결된 estimate 정보 확인
$my_estimate = sql_fetch("SELECT id, commission_fee FROM estimate WHERE wr_id = '{$wr_id}'");
if ($my_estimate) {
$target_estimate_id = $my_estimate['id'];
$final_amount_value = $my_estimate['commission_fee']; // 저장된 최종 금액
}
}
$sql_items = "SELECT * FROM estimate_item WHERE estimate_id = '{$target_estimate_id}' ORDER BY no ASC";
$result_items = sql_query($sql_items);
$items = [];
while($item = sql_fetch_array($result_items)) {
// 신규 작성 시, 고객이 입력한 아이템을 가져오지만 가격 정보 등은 초기화해야 할 수도 있음
// 하지만 대리점이 '고객 요청대로' 견적을 내는 경우가 많으므로 기본값으로 둠.
// 단, w=r일 때 price, amount는 0으로 초기화하는 것이 좋을 수 있음 (견적을 새로 내는 것이므로)
if ($w == 'r') {
$item['price'] = '';
$item['amount'] = '';
}
$items[] = $item;
}
$item_count = count($items);
// 설정 배열 (기존 order2.php 유지)
$estimate_headers = array(
"no", "위치", "품명", "창비율", "창호형태", "교체위치", "색상", "규격", "유리두께", "유리색상", "방충망", "시정장치", "시공여부", "브랜드","수량", "단가", "금액"
);
$window_ratio_options = array("2W(1:1)","2W(비대칭)우","2W(비대칭)좌","3W(1:2:1)","4W");
$window_type_options = array("단창", "이중창", "분합창", "발코니창");
$replace_part_options = array("외부접한창", "내창");
$color_options = array("화이트", "도장");
$glass_thickness_options = array("22mm", "24mm", "26mm");
$glass_color_options = array("로이그린","그린투명","미스트(불투명)", "투명");
$screen_options = array("", "");
$handle_options = array("오토락", "크리센트");
$install_options = array("O", "X");
$brand_options = array("LX지인","KCC","현대 홈샤시","금호휴그린","홈씨씨창호","청암홈샤시","에이스윈도우","피엔에스홈즈", "중앙리빙샤시","윈체","예림창호","재현하늘창","이끌림");
?>
<link rel="stylesheet" href="/program/estimate.css">
<style>
/* view.skin.php 스타일 적용 */
.house-info { width:100%; border-collapse:collapse; margin-bottom:25px; background:#f9fafc; font-size:1em; }
.house-info th, .house-info td { border:1px solid #e2e6ea; padding:10px 14px; text-align:left; font-weight:normal; }
.house-info th { background:#e7f0fa; color:#1a3b5d; font-weight:bold; min-width:80px; }
.house-info td { background:#fff; }
.table-scroll {width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* order2.php의 입력 폼 스타일을 위해 view-table 클래스 대신 기존 스타일을 조금 수정해서 사용하거나 view-table을 기반으로 input 스타일 추가 */
.estimate-table { width:100%; border-collapse:collapse; background:#fff; font-size:0.97em; margin-bottom:30px; box-shadow:0 2px 12px rgba(0,0,0,0.06); border-radius:8px; overflow:hidden; }
.estimate-table th, .estimate-table td { border:1px solid #e2e6ea; padding:8px 5px; text-align:center; vertical-align: middle; }
.estimate-table th { background:#3d6cb9; color:#fff; font-weight:bold; font-size:1em; white-space: nowrap; }
.estimate-table input[type="text"], .estimate-table input[type="number"], .estimate-table select {
width: 100%; box-sizing: border-box; padding: 5px; border: 1px solid #ddd; border-radius: 4px;
}
.spec-input-wrap { display: flex; align-items: center; justify-content: center; }
.spec-sep { margin: 0 5px; }
.row-number { font-weight: bold; }
.del-row-btn { background: #ff5b5b; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; }
/* view.skin.php와 유사한 헤더 스타일 */
.order-view-container h3 { font-size: 1.2em; margin-bottom: 15px; color: #333; border-left: 5px solid #3d6cb9; padding-left: 10px; }
</style>
<div class="order-view-container">
<div class="order-common-specs">
<h3>견적 공통 사양 (고객 요청)</h3>
<table class="house-info">
<tbody>
<tr>
<th>주거공간 형태</th>
<td><?php echo htmlspecialchars($original_estimate['house_type'] ?? ''); ?></td>
<th>공간 규모</th>
<td><?php echo htmlspecialchars($original_estimate['house_size'] ?? ''); ?></td>
</tr>
<tr>
<th>프레임 소재</th>
<td><?php echo htmlspecialchars($original_estimate['material'] ?? ''); ?></td>
<th>프레임 컬러</th>
<td><?php echo ($original_estimate['color'] == '색지정') ? htmlspecialchars($original_estimate['temp_2'] ?? '') : htmlspecialchars($original_estimate['color'] ?? ''); ?></td>
</tr>
<tr>
<th>유리두께</th>
<td><?php echo htmlspecialchars($original_estimate['glass_thickness'] ?? ''); ?></td>
<th>시공포함</th>
<td><?php echo htmlspecialchars($original_estimate['install'] ?? ''); ?></td>
</tr>
<tr>
<th>제품구매</th>
<td><?php echo htmlspecialchars($original_estimate['temp_1'] ?? ''); ?></td>
</tr>
</tbody>
</table>
</div>
<div class="order-individual-specs">
<h3 style="margin-top: 30px;">개별 창 상세 견적 작성</h3>
<!-- 원본 데이터 유지를 위한 히든 필드들 -->
<input type="hidden" name="site_name" value="<?php echo htmlspecialchars($original_estimate['site_name'] ?? ''); ?>">
<div class="table-scroll">
<table id="estimate_table" class="estimate-table">
<thead>
<tr>
<?php foreach($estimate_headers as $header) { echo "<th>{$header}</th>"; } ?>
<th>관리</th>
</tr>
</thead>
<tbody id="estimate_body">
<?php
for($i=0; $i < max(1, $item_count); $i++) {
$item = isset($items[$i]) ? $items[$i] : array();
echo "<tr>";
foreach($estimate_headers as $key) {
echo "<td>";
// 💡 [수정] Deprecated 오류 수정 (${var} -> {$var})
if($key == "no") {
$no = isset($item['no']) ? $item['no'] : ($i+1);
echo "<span class='row-number'>{$no}</span>";
echo "<input type='hidden' name='estimate[{$i}][no]' value='{$no}'>";
} else if($key == "위치") {
echo "<input type='text' name='estimate[{$i}][location]' value='".htmlspecialchars($item['location'] ?? '')."'>";
} else if($key == "창비율") {
echo "<select name='estimate[{$i}][windowRatio]'>";
foreach($window_ratio_options as $opt) {
$sel = (isset($item['windowRatio']) && $item['windowRatio']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "창호형태") {
echo "<select name='estimate[{$i}][windowType]'>";
foreach($window_type_options as $opt) {
$sel = (isset($item['windowType']) && $item['windowType']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "교체위치") {
echo "<select name='estimate[{$i}][replacePart]'>";
foreach($replace_part_options as $opt) {
$sel = (isset($item['replacePart']) && $item['replacePart']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "색상") {
echo "<select name='estimate[{$i}][color]'>";
foreach($color_options as $opt) {
$sel = (isset($item['color']) && $item['color']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "규격") {
$w_val = htmlspecialchars($item['spec_width'] ?? '');
$h_val = htmlspecialchars($item['spec_height'] ?? '');
echo "<div class='spec-input-wrap'>";
echo "<input type='text' name='estimate[{$i}][spec_width]' value='{$w_val}' style='width:50px;' placeholder='가로'>";
echo "<span class='spec-sep'>x</span>";
echo "<input type='text' name='estimate[{$i}][spec_height]' value='{$h_val}' style='width:50px;' placeholder='세로'>";
echo "</div>";
} else if($key == "유리두께") {
echo "<select name='estimate[{$i}][glass_thickness]'>";
foreach($glass_thickness_options as $opt) {
$sel = (isset($item['glass_thickness']) && $item['glass_thickness']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "유리색상") {
echo "<select name='estimate[{$i}][glass_color]'>";
foreach($glass_color_options as $opt) {
$sel = (isset($item['glass_color']) && $item['glass_color']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "방충망") {
echo "<select name='estimate[{$i}][screen]'>";
foreach($screen_options as $opt) {
$sel = (isset($item['screen']) && $item['screen']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "시정장치") {
echo "<select name='estimate[{$i}][handle]'>";
foreach($handle_options as $opt) {
$sel = (isset($item['handle']) && $item['handle']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "시공여부") {
echo "<select name='estimate[{$i}][install]'>";
foreach($install_options as $opt) {
$sel = (isset($item['install']) && $item['install']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "브랜드") {
echo "<select name='estimate[{$i}][brand]'>";
foreach($brand_options as $opt) {
$sel = (isset($item['brand']) && $item['brand']==$opt) ? "selected" : "";
echo "<option value='{$opt}' {$sel}>{$opt}</option>";
}
echo "</select>";
} else if($key == "수량") {
$v = isset($item['qty']) ? $item['qty'] : 1;
echo "<input type='number' name='estimate[{$i}][qty]' value='{$v}' min='1' style='width:50px;text-align:center' onchange='calcAmount(this)'>";
} else if($key == "단가") {
$v = isset($item['price']) ? $item['price'] : "";
echo "<input type='number' name='estimate[{$i}][price]' value='{$v}' min='0' style='width:90px;' onchange='calcAmount(this)' required placeholder='단가입력'>";
} else if($key == "금액") {
$v = isset($item['amount']) ? $item['amount'] : "";
echo "<input type='number' name='estimate[{$i}][amount]' value='{$v}' min='0' style='width:90px;' readonly tabindex='-1'>";
} else {
// 품명 등 기타
$fieldName = ($key == "품명") ? "product" : $key;
$v = isset($item[$fieldName]) ? $item[$fieldName] : "";
echo "<input type='text' name='estimate[{$i}][{$fieldName}]' value='".htmlspecialchars($v)."' style='width:80px;'>";
}
echo "</td>";
}
echo "<td><button type='button' class='del-row-btn' onclick='deleteRow(this)'>삭제</button></td>";
echo "</tr>";
}
?>
</tbody>
<tfoot>
<tr>
<td colspan="<?php echo count($estimate_headers); ?>" style="text-align:right; font-weight:bold; padding: 15px;">
합계: <input type="text" name="estimate[final_amount]" id="total_sum" value="<?php echo $final_amount_value; ?>" readonly style="width:120px; font-weight:bold; text-align:right; border:none; border-bottom:1px solid #000; font-size:1.1em;"> 원
</td>
<td>
<button type="button" onclick="addRow()" style="background:#337ab7; color:#fff; border:none; padding:5px 10px; border-radius:4px; cursor:pointer;">행추가</button>
</td>
</tr>
</tfoot>
</table>
</div>
<!-- 💡 [추가] 삭제 버튼 -->
<?php if ($w == 'u') { ?>
<div style="margin-top: 20px; text-align: right;">
<button type="button" onclick="deleteProposal(<?php echo $wr_id; ?>)" style="background:#d9534f; color:#fff; border:none; padding:10px 20px; border-radius:4px; cursor:pointer; font-weight:bold;">
견적 제안 삭제
</button>
</div>
<?php } ?>
</div>
</div>
<script>
// 기존 자바스크립트 로직 유지 및 보완
function addRow() {
var tbody = document.getElementById('estimate_body');
var rowCount = tbody.rows.length; // 현재 행 개수를 기준으로 인덱스 설정 (주의: 삭제 후 추가 시 인덱스 꼬임 방지를 위해 타임스탬프 등을 쓸 수도 있으나, 여기서는 rowCount 사용)
// 정확한 인덱싱을 위해 현재 마지막 행의 input name에서 인덱스를 추출하는 것이 안전하지만,
// 여기서는 단순히 행 개수를 늘리는 방식으로 구현 (서버 사이드에서 배열로 받으므로 인덱스 연속성 중요하지 않음)
var idx = rowCount;
var headers = <?php echo json_encode($estimate_headers); ?>;
var windowRatio = <?php echo json_encode($window_ratio_options); ?>;
var windowType = <?php echo json_encode($window_type_options); ?>;
var replacePart = <?php echo json_encode($replace_part_options); ?>;
var colorOptions = <?php echo json_encode($color_options); ?>;
var glassThicknessOptions = <?php echo json_encode($glass_thickness_options); ?>;
var glassColorOptions = <?php echo json_encode($glass_color_options); ?>;
var screenOptions = <?php echo json_encode($screen_options); ?>;
var handleOptions = <?php echo json_encode($handle_options); ?>;
var installOptions = <?php echo json_encode($install_options); ?>;
var brandOptions = <?php echo json_encode($brand_options); ?>;
var tr = document.createElement('tr');
headers.forEach(function(key) {
var td = document.createElement('td');
if(key == "no") {
td.innerHTML = `<span class='row-number'>${idx+1}</span><input type='hidden' name='estimate[${idx}][no]' value='${idx+1}'>`;
} else if(key == "위치") {
td.innerHTML = `<input type='text' name='estimate[${idx}][location]' value=''>`;
} else if(key == "창비율") {
td.appendChild(makeSelect(`estimate[${idx}][windowRatio]`, windowRatio));
} else if(key == "창호형태") {
td.appendChild(makeSelect(`estimate[${idx}][windowType]`, windowType));
} else if(key == "교체위치") {
td.appendChild(makeSelect(`estimate[${idx}][replacePart]`, replacePart));
} else if(key == "색상") {
td.appendChild(makeSelect(`estimate[${idx}][color]`, colorOptions));
} else if(key == "규격") {
td.innerHTML = `<div class='spec-input-wrap'>
<input type='text' name='estimate[${idx}][spec_width]' style='width:50px;' placeholder='가로'>
<span class='spec-sep'>x</span>
<input type='text' name='estimate[${idx}][spec_height]' style='width:50px;' placeholder='세로'>
</div>`;
} else if(key == "유리두께") {
td.appendChild(makeSelect(`estimate[${idx}][glass_thickness]`, glassThicknessOptions));
} else if(key == "유리색상") {
td.appendChild(makeSelect(`estimate[${idx}][glass_color]`, glassColorOptions));
} else if(key == "방충망") {
td.appendChild(makeSelect(`estimate[${idx}][screen]`, screenOptions));
} else if(key == "시정장치") {
td.appendChild(makeSelect(`estimate[${idx}][handle]`, handleOptions));
} else if(key == "시공여부") {
td.appendChild(makeSelect(`estimate[${idx}][install]`, installOptions));
} else if(key == "브랜드") {
td.appendChild(makeSelect(`estimate[${idx}][brand]`, brandOptions));
} else if(key == "수량") {
td.innerHTML = `<input type='number' name='estimate[${idx}][qty]' value='1' min='1' style='width:50px;text-align:center' onchange='calcAmount(this)'>`;
} else if(key == "단가") {
td.innerHTML = `<input type='number' name='estimate[${idx}][price]' value='' min='0' style='width:90px;' onchange='calcAmount(this)' required placeholder='단가입력'>`;
} else if(key == "금액") {
td.innerHTML = `<input type='number' name='estimate[${idx}][amount]' value='' min='0' style='width:90px;' readonly tabindex='-1'>`;
} else {
var fieldName = (key == "품명") ? "product" : key;
td.innerHTML = `<input type='text' name='estimate[${idx}][${fieldName}]' value='' style='width:80px;'>`;
}
tr.appendChild(td);
});
var tdDel = document.createElement('td');
tdDel.innerHTML = `<button type='button' class='del-row-btn' onclick='deleteRow(this)'>삭제</button>`;
tr.appendChild(tdDel);
tbody.appendChild(tr);
updateRowNumbers();
}
function deleteRow(btn) {
var tr = btn.closest('tr');
tr.parentNode.removeChild(tr);
updateRowNumbers();
calcTotal();
}
function makeSelect(name, options) {
var select = document.createElement('select');
select.name = name;
for(var i=0; i<options.length; i++) {
var opt = document.createElement('option');
opt.value = options[i];
opt.textContent = options[i];
select.appendChild(opt);
}
return select;
}
function updateRowNumbers() {
var tbody = document.getElementById('estimate_body');
var rows = tbody.rows;
for(var i=0; i<rows.length; i++) {
var firstCell = rows[i].cells[0];
var span = firstCell.querySelector('.row-number');
var input = firstCell.querySelector('input[type="hidden"]');
if(span) span.textContent = (i + 1);
// name 속성의 인덱스도 재정렬해주면 좋음 (PHP 배열 수신 시 인덱스 누락 방지)
// 여기서는 간단하게 번호만 업데이트
}
}
function calcAmount(el) {
var tr = el.closest('tr');
var qtyInput = tr.querySelector('input[name*="[qty]"]');
var priceInput = tr.querySelector('input[name*="[price]"]');
if(qtyInput && priceInput) {
var qty = parseInt(qtyInput.value) || 0;
var price = parseInt(priceInput.value) || 0;
var amountInput = tr.querySelector('input[name*="[amount]"]');
if(amountInput) {
var amount = qty * price;
amountInput.value = amount;
}
}
calcTotal();
}
function calcTotal() {
var tbody = document.getElementById('estimate_body');
var rows = tbody.rows;
var sum = 0;
for(var i=0; i<rows.length; i++) {
var amountInput = rows[i].querySelector('input[name*="[amount]"]');
if(amountInput) {
var val = parseInt(amountInput.value) || 0;
sum += val;
}
}
var totalInput = document.getElementById('total_sum');
if(totalInput) totalInput.value = sum;
}
// 초기 로드시 합계 계산
window.addEventListener('load', function() {
calcTotal();
});
// 💡 [추가] 견적 제안 삭제 함수
function deleteProposal(wr_id) {
if(!confirm('정말로 이 견적 제안을 삭제하시겠습니까?\n삭제된 데이터는 복구할 수 없습니다.')) return;
// AJAX로 삭제 요청 보내기
var xhr = new XMLHttpRequest();
xhr.open('POST', '<?php echo $board_skin_url; ?>/delete_proposal.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status == 200) {
var res = JSON.parse(xhr.responseText);
if(res.success) {
alert('견적 제안이 삭제되었습니다.');
location.href = '<?php echo get_pretty_url($bo_table); ?>';
} else {
alert('삭제 실패: ' + res.message);
}
}
};
// 💡 [수정] bo_table 값도 함께 전송
xhr.send('wr_id=' + wr_id + '&bo_table=<?php echo $bo_table; ?>');
}
</script>