Files
confirms/app/Views/pages/article/detail.php
2025-12-23 17:26:40 +09:00

1614 lines
69 KiB
PHP

<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
.tbl_basic2 th {
padding: 0 10px;
height: 27px;
border: solid 1px #d8d9de;
background-color: #eff0f4;
letter-spacing: -1px;
font-weight: normal;
color: #5a5f69;
text-align: left;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>아파트단지 DB구축 상세</h1>
<div class="col-md-12 col-xl-12">
<div class="col-lg-12">
<div class="main-card mb-3 card">
<div class="card-body">
<h5 class="card-title">단지 정보</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<colgroup>
<col width="100" />
<col width="300" />
<col width="100" />
<col width="300" />
</colgroup>
<tr>
<th>단지코드</th>
<td><?= esc($apt['hscp_no'] ?? '') ?></td>
<th>주소</th>
<td><?= esc($apt['addr'] ?? '') ?></td>
</tr>
<tr>
<th>단지명</th>
<td><?= esc($apt['rcpt_hscp_nm'] ?? '') ?></td>
<th>상세주소</th>
<td><?= esc($apt['addr2'] ?? '') ?></td>
</tr>
<tr>
<th>입주년월</th>
<td><?= esc($apt['move_ym'] ?? '') ?></td>
<th>총세대수</th>
<td><?= esc($apt['households_cnt'] ?? '') ?></td>
</tr>
<tr>
<th>총동수</th>
<td><?= esc($apt['dong_cnt'] ?? '') ?></td>
<th>메모</th>
<td>
<div class="row g-2 align-items-center">
<div class="col-md-9">
<!-- ✅ 원본: value="" <?= $apt['memo'] ?> -> HTML 속성 깨짐 -->
<input class="form-control" type="text" id="memo"
value="<?= esc($apt['memo'] ?? '') ?>" />
</div>
<div class="col-md-3 text-end">
<button type="button" class="btn btn-outline-light"
onclick="saveMemo('<?= esc($apt['rcpt_no'] ?? '') ?>')">저장</button>
</div>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="main-card mb-3 card">
<div class="card-body">
<h5 class="card-title">담당자 정보</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<colgroup>
<col width="10%" />
<col width="auto" />
<col width="10%" />
<col width="auto" />
<col width="10%" />
<col width="auto" />
<col width="15%" />
</colgroup>
<tr>
<th style="text-align:center">관할본부</th>
<td style="text-align:center">
<select class="form-control" name="bonbu" id="bonbu">
<option value="">선택</option>
<?php foreach (($bonbu ?? []) as $d): ?>
<option value="<?= esc($d['dept_sq']) ?>" <?= (string) ($apt['bonbu'] ?? '') === (string) $d['dept_sq'] ? 'selected' : '' ?>>
<?= esc($d['dept_nm']) ?>
</option>
<?php endforeach; ?>
</select>
</td>
<th style="text-align:center">담당팀</th>
<td style="text-align:center">
<select class="form-control" name="team" id="team">
<option value="">선택</option>
<?php foreach (($team ?? []) as $d): ?>
<?php if ((string) ($apt['bonbu'] ?? '') === (string) ($d['pdept_sq'] ?? '')): ?>
<option value="<?= esc($d['dept_sq']) ?>" <?= (string) ($apt['dept_sq'] ?? '') === (string) $d['dept_sq'] ? 'selected' : '' ?>>
<?= esc($d['dept_nm']) ?>
</option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</td>
<th style="text-align:center">담당자</th>
<td style="text-align:center">
<select class="form-control" name="user" id="user">
<option value="">선택</option>
<?php foreach (($user ?? []) as $d): ?>
<?php if ((string) ($apt['dept_sq'] ?? '') === (string) ($d['dept_sq'] ?? '')): ?>
<option value="<?= esc($d['usr_id']) ?>" <?= (string) ($apt['charger'] ?? '') === (string) $d['usr_id'] ? 'selected' : '' ?>>
<?= esc($d['usr_nm']) ?>
</option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</td>
<td style="text-align:center">
<button type="button" class="btn btn-sm btn-outline-light"
onclick="saveKeeper('<?= esc($apt['rcpt_no'] ?? '') ?>')">저장</button>
</td>
</tr>
</table>
</div>
</div>
<div class="main-card mb-3 card">
<div class="card-body">
<h5 class="card-title">단지 상태 정보</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<colgroup>
<col width="8%" />
<col width="15%" />
<col width="15%" />
<col width="15%" />
<col width="15%" />
<col width="15%" />
</colgroup>
<tr>
<th rowspan="2" style="text-align:center">상태내역</th>
<th style="text-align:center">대상업로드</th>
<th style="text-align:center">사진업로드</th>
<th style="text-align:center">영상업로드</th>
<th style="text-align:center">영상촬영불가</th>
<th style="text-align:center">검수</th>
</tr>
<tr>
<td style="text-align:center;height: 50px;color: #ff0000;">
<b><?= esc($apt['rdate_dt'] ?? '') ?><br><?= esc($apt['rdate_tm'] ?? '') ?></b>
</td>
<td style="text-align:center;color: #ff0000;">
<b>
<?php if (($apt['write_complete_yn'] ?? '') === 'Y'): ?>
<?= esc($apt['rdate_dt_cmpl'] ?? '') ?><br><?= esc($apt['rdate_tm_cmpl'] ?? '') ?>
<?php endif; ?>
</b>
</td>
<td style="text-align:center;color: #ff0000;">
<b><?= esc($apt['rdate_dt_vdo'] ?? '') ?><br><?= esc($apt['rdate_tm_vdo'] ?? '') ?></b>
</td>
<td style="text-align:center;color: #ff0000;">
<b><?= esc($apt['rdate_dt_nvdo'] ?? '') ?><br><?= esc($apt['rdate_tm_nvdo'] ?? '') ?></b>
</td>
<td style="text-align:center;color: #ff0000;">
<b><?= esc($apt['rdate_dt_chk'] ?? '') ?><br><?= esc($apt['rdate_tm_chk'] ?? '') ?></b>
</td>
</tr>
</table>
</div>
</div>
<div class="main-card mb-3 card">
<div class="card-body">
<h5 class="card-title">단지 위치</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<colgroup>
<col width="25%">
<col width="45%">
<col width="30%">
</colgroup>
<tr>
<td colspan="2" style="padding:5px;">
<div id="mapArea" style="width:100%;height:250px;"></div>
</td>
<td rowspan="2" style="vertical-align: top; padding:10px;">
<h5 class="mb-2">단지 특이사항</h5>
<textarea name="note" id="note" class="form-control mb-2"
style="height: 220px;"><?= esc($apt['note'] ?? '') ?></textarea>
<div class="d-flex align-items-center">
<div class="ms-auto">
<button class="btn btn-sm btn-primary"
onclick="saveNote('<?= esc($apt['rcpt_no'] ?? '') ?>')">
저장
</button>
</div>
</div>
</td>
</tr>
<tr>
<th class="text-center align-middle">지도 좌표 수정</th>
<td>
<div class="d-flex align-items-center gap-2 flex-wrap">
<span>위도</span>
<input type="text" id="rcpt_y" name="rcpt_y" class="form-control form-control-sm"
style="width:120px;" value="<?= esc($apt['rcpt_y'] ?? '') ?>">
<span>경도</span>
<input type="text" id="rcpt_x" name="rcpt_x" class="form-control form-control-sm"
style="width:120px;" value="<?= esc($apt['rcpt_x'] ?? '') ?>">
<button class="btn btn-sm btn-outline-secondary ms-auto"
onclick="saveCoordinate('<?= esc($apt['rcpt_no'] ?? '') ?>')">
저장
</button>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="main-card mb-3 card">
<div class="card-body">
<h5 class="card-title">단지 영상 정보</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<!-- <colgroup>
<col width="8%">
<col width="7%">
<col width="11%">
<col width="11%">
<col width="10%">
<col width="12%">
</colgroup> -->
<tbody>
<tr>
<th rowspan="2" style="text-align: center;">동영상</th>
<td rowspan="2" style="text-align: center;">
<img src="/plugin/img/photo.gif" alt="비디오" style="padding: 3px;"><br>
<button class="btn btn-sm btn-outline-success" type="button" id="btn_upload_video">
<i class="fa fa-fw" aria-hidden="true" title="Copy to use file-image-o"></i> 파일
</button>
</td>
<th style="text-align: center;">동영상 촬영불가</th>
<td style="text-align: center;">
<label for="vdo_up_ynx">
<input type="checkbox" name="vdo_up_ynx" id="vdo_up_ynx" value="X"
<?= ($apt['vdo_up_ynx'] ?? '') === 'X' ? 'checked' : '' ?>>
&nbsp;동영상 촬영불가
</label>
</td>
<th style="text-align: center;">영상촬영대상</th>
<td>
<div class="row gx-2 align-items-center">
<div class="col-10">
<select class="form-control form-control-sm" id="video_target">
<option value="">-선택-</option>
<?php foreach ($video as $v): ?>
<option value="<?= $v['cd'] ?>" <?php if ($v['cd'] === $apt['video_target'])
echo "selected"; ?>><?= $v['cd_nm'] ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-auto gap-2">
<button class="btn btn-sm btn-outline-focus" type="button"
onclick="saveVideoTarget('<?= esc($apt['rcpt_no'] ?? '') ?>');">저장</button>
</div>
</div>
</td>
</tr>
<tr>
<th style="text-align: center;">촬영불가사유</th>
<td colspan="3">
<div class="row gx-2 align-items-center">
<div class="col">
<input type="text" class="form-control form-control-sm" id="not_vdo_reson"
value="<?= $apt['not_vdo_reson'] ?>">
</div>
<div class="col-auto">
<button class="btn btn-sm btn-outline-focus" type="button"
onclick="saveVideoReason('<?= esc($apt['rcpt_no'] ?? '') ?>');">저장</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="main-card mb-3 card">
<div class="card-body">
<h5 class="card-title">단지 사진 기본 설정</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<colgroup>
<col width="15%" />
<col width="auto" />
<col width="15%" />
<col width="auto" />
<col width="15%" />
<col width="auto" />
</colgroup>
<tr>
<th style="text-align:center">사진 일괄업로드</th>
<td style="text-align:center">
<button class="btn btn-sm btn-outline-success" type="button" id="btn_upload_photo">
<i class="fa fa-fw" aria-hidden="true" title="Copy to use file-image-o"></i> 파일
</button>
</td>
<th style="text-align:center">사진 일괄삭제</th>
<td style="text-align:center">
<button type="button" class="btn btn-sm btn-outline-danger">삭제</button>
</td>
<th style="text-align:center">단지정보 작성완료</th>
<td style="text-align:center">
<button type="button" class="btn btn-sm btn-outline-light">저장</button>
</td>
</tr>
</table>
</div>
</div>
<div class="main-card mb-3 card">
<div class="card-body">
<h5 class="card-title">단지 사진 및 설명 정보</h5>
<?php if (empty($apt['all_no_pho'] ?? null)): ?>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table" style="text-align:center;">
<colgroup>
<col width="7%">
<col width="9%">
<col width="auto">
<col width="25%">
<col width="4%">
<col width="auto">
</colgroup>
<tbody>
<?php
foreach (($code1 ?? []) as $c1) {
if (($c1['cd'] ?? '') === 'V')
continue; // 동영상 제외
$bFirst = true;
$arrCate2 = [];
foreach (($code2 ?? []) as $cate2) {
if (substr((string) ($cate2['cd'] ?? ''), 0, 1) === (string) ($c1['cd'] ?? '')) {
$arrCate2[] = $cate2;
}
}
$cnt = count($arrCate2);
foreach ($arrCate2 as $c2) {
$c2cd = (string) ($c2['cd'] ?? '');
// ✅ cate2에 해당하는 이미지들만 뽑기 (원본의 reset/foreach/unset 흐름 유지하되 안전하게)
$arrCate2Image = [];
if (!empty($image)) {
foreach ($image as $key => $val) {
if (($val['pho_cate2'] ?? '') === 'V')
continue;
if ((string) ($val['pho_cate2'] ?? '') === $c2cd) {
$arrCate2Image[] = $val;
unset($image[$key]); // 원본 유지
}
}
}
// ✅ 업로드불가 사유(cateInfo)
$arrCate2NU = [];
if (!empty($cateInfo)) {
foreach ($cateInfo as $val) {
if (($val['pho_cate2'] ?? '') === 'V')
continue;
if ((string) ($val['pho_cate2'] ?? '') === $c2cd) {
$arrCate2NU[] = $val;
}
}
}
// ✅ 설명 텍스트는 미리 뽑아서 textarea에 그대로 출력(포매터 안정)
$phoExplain = '';
if (!empty($cateInfo)) {
foreach ($cateInfo as $row) {
if ((string) ($row['pho_cate2'] ?? '') === $c2cd) {
$phoExplain = (string) ($row['pho_explain'] ?? '');
break;
}
}
}
// ✅ 오른쪽 버튼 영역에서 사용할 rcpt_no (원본은 $img 마지막 값 의존이라 위험)
$rcptNoForActions = (string) ($apt['rcpt_no'] ?? '');
if (!empty($arrCate2Image) && !empty($arrCate2Image[0]['rcpt_no'])) {
$rcptNoForActions = (string) $arrCate2Image[0]['rcpt_no'];
}
?>
<tr>
<?php if ($bFirst): ?>
<?php $bFirst = false; ?>
<?php $rowspan = max(1, $cnt); ?>
<th rowspan="<?= $rowspan ?>"><?= esc($c1['cd_nm'] ?? '') ?></th>
<?php endif; ?>
<th><?= esc($c2['cd_nm'] ?? '') ?></th>
<td style="padding: 6px; width: 410px;">
<?php
// formatter 안정: 조건/값을 먼저 계산
$hasImages = !empty($arrCate2Image);
$hasNU = !empty($arrCate2NU);
$rcptNo = (string) ($apt['rcpt_no'] ?? '');
$c2cdSafe = esc($c2cd); // 반복 esc 최소화
// formatter 안정: JS 호출 문자열 미리 구성(속성 내부 PHP 최소화)
$jsSaveNU = "ajax_save_pho_up_nu('{$rcptNo}','{$c2cd}')";
?>
<?php if ($hasImages): ?>
<?php foreach ($arrCate2Image as $img): ?>
<?php
// ✅ link / thumb 계산
$link = (string) ($img['file_path'] ?? '') . (string) ($img['filenm_up'] ?? '');
$thumb = (string) ($img['thumb_path'] ?? '') . (string) ($img['thumb_nm'] ?? '');
if (($img['cloud_upload_yn'] ?? '') === 'Y') {
$link = NCLOUD_OBJECT_STORAGE_URL . $link;
$thumb = NCLOUD_OBJECT_STORAGE_URL . $thumb;
}
// formatter 안정: style 문자열도 if로 분리(삼항 최소화)
$borderStyle = 'border-style: solid; border-color: white; border-width: 3px;';
if (($img['pho_view_yn'] ?? '') === 'Y') {
$borderStyle = 'border-style: solid; border-color: #0284c3; border-width: 3px;';
}
$phoNo = (string) ($img['pho_no'] ?? '');
$chkId = 'pho_no_' . $c2cd . '_' . $phoNo;
?>
<table style="border: 0; float: left;">
<tr>
<td style="border: 0;">
<input type="checkbox" name="pho_no[]" id="<?= esc($chkId) ?>"
value="<?= esc($phoNo) ?>">
<label for="<?= esc($chkId) ?>"><?= esc($phoNo) ?></label>
</td>
</tr>
<tr>
<td style="border: 0;">
<a href="<?= esc($link) ?>" rel="lightbox">
<img src="<?= esc($thumb) ?>" style="<?= esc($borderStyle) ?>" />
</a>
</td>
</tr>
</table>
<?php endforeach; ?>
<?php else: ?>
<?php if ($hasNU): ?>
<?php foreach ($arrCate2NU as $nu): ?>
<?php
$nuVal = (string) ($nu['pho_up_nu'] ?? '');
$chkN = ($nuVal === 'N') ? 'checked' : '';
$chkU = ($nuVal === 'U') ? 'checked' : '';
// formatter 안정: id/name 미리 구성
$nameNU = 'pho_up_nu_' . $c2cd;
$idN = 'pho_up_nu1_' . $c2cd;
$idU = 'pho_up_nu2_' . $c2cd;
?>
&nbsp;&nbsp;<b>사진업로드 불가사유 </b>&nbsp;&nbsp;
<label for="<?= esc($idN) ?>">
<input type="radio" name="<?= esc($nameNU) ?>" id="<?= esc($idN) ?>" value="N"
<?= $chkN ?> />
&nbsp;시설없음
</label>&nbsp;
<label for="<?= esc($idU) ?>">
<input type="radio" name="<?= esc($nameNU) ?>" id="<?= esc($idU) ?>" value="U"
<?= $chkU ?> />
&nbsp;알수없음
</label>&nbsp;&nbsp;&nbsp;
<button class="btn btn-sm btn-outline-focus" type="button"
onclick="savePhoReason('<?= $apt['rcpt_no'] ?>','<?= $c2['cd'] ?>');">저장</button>
<?php endforeach; ?>
<?php else: ?>
<?php
$nameNU = 'pho_up_nu_' . $c2cd;
$idN = 'pho_up_nu1_' . $c2cd;
$idU = 'pho_up_nu2_' . $c2cd;
?>
&nbsp;&nbsp;<b>사진업로드 불가사유 </b>&nbsp;&nbsp;
<label for="<?= esc($idN) ?>">
<input type="radio" name="<?= esc($nameNU) ?>" id="<?= esc($idN) ?>" value="N" />
&nbsp;시설없음
</label>&nbsp;
<label for="<?= esc($idU) ?>">
<input type="radio" name="<?= esc($nameNU) ?>" id="<?= esc($idU) ?>" value="U"
checked="checked" />
&nbsp;알수없음
</label>&nbsp;&nbsp;&nbsp;
<button class="btn btn-sm btn-outline-focus" type="button"
onclick="savePhoReason('<?= $apt['rcpt_no'] ?>','<?= $c2['cd'] ?>');">저장</button>
<?php endif; ?>
<?php endif; ?>
</td>
<?php if (!empty($arrCate2Image)): ?>
<td style="width: 300px;">
<table style="width: 100%; border: 0;" id="tbl-align-left" style="text-align: left;">
<tr>
<td colspan="2" style="border: 0;"><b>선택된 사진을</b></td>
</tr>
<tr>
<td style="border: 0;">
<select name="pho_cate1" id="pho_cate1_<?= esc($c2cd) ?>"
onchange="cate1_onchange('<?= esc($c2cd) ?>')">
<option value="">-대분류-</option>
<?php foreach (($code1 ?? []) as $cate): ?>
<?php if (($cate['cd'] ?? '') === 'V')
continue; ?>
<option value="<?= esc($cate['cd'] ?? '') ?>">
<?= esc($cate['cd_nm'] ?? '') ?>
</option>
<?php endforeach; ?>
</select>&nbsp;
<select name="pho_cate2" id="pho_cate2_<?= esc($c2cd) ?>">
<option value="">-소분류-</option>
</select>&nbsp;
</td>
<td style="border: 0;">
<button type="button" class="btn btn-outline-light"
onclick="saveCate('<?= $img['rcpt_no'] ?>','<?= $c2['cd'] ?>');">저장</button>
</td>
</tr>
<tr>
<td style="border: 0;">
<label for="pho_view_yn1_<?= esc($c2cd) ?>">
<input type="radio" name="pho_view_yn_<?= esc($c2cd) ?>"
id="pho_view_yn1_<?= esc($c2cd) ?>" value="Y">
&nbsp;<span style="color:#0284c3"><b>노출&nbsp;</b></span>
</label>
<label for="pho_view_yn2_<?= esc($c2cd) ?>">
<input type="radio" name="pho_view_yn_<?= esc($c2cd) ?>"
id="pho_view_yn2_<?= esc($c2cd) ?>" value="N">
&nbsp;노출종료&nbsp;
</label>
</td>
<td style="border: 0;">
<button type="button" class="btn btn-outline-light"
onclick="savePhotoView('<?= $img['rcpt_no'] ?>','<?= $c2['cd'] ?>');">저장</button>
</td>
</tr>
<tr>
<td style="border: 0;">
<button type="button" class="btn btn-outline-danger"
onclick="removePhoto('<?= $img['rcpt_no'] ?>','<?= $c2['cd'] ?>');">삭제</button>
</td>
<td style="border: 0;"></td>
</tr>
</table>
</td>
<td>
<input type="button" name="btnGreyMap" id="btnGreyMap" value="지도보기"
onclick="javascript:viewCateMap();" />
</td>
<td id="remaining_<?= esc($c2cd) ?>">
<table style="width: 100%; border: 0;">
<tr>
<td rowspan="3" style="border: 0;">
<!-- ✅ textarea 안에 PHP 로직 제거 -->
<textarea class="form-control" name="pho_explain"
id="pho_explain_<?= esc($c2cd) ?>"
style="width:350px;height:90px;"><?= esc($phoExplain) ?></textarea>
</td>
<td style="border: 0; padding: 0;">
<!-- <span id="count_<?= esc($c2cd) ?>" style="font-weight:bold">0</span> -->
</td>
</tr>
<tr>
<td style="border: 0;"></td>
</tr>
<tr>
<td style="border: 0; padding: 0;">
<button type="button" class="btn btn-sm btn-info"
onclick="savePhoExplain('<?= esc($rcptNoForActions) ?>','<?= esc($c2cd) ?>')">저장</button>
</td>
</tr>
</table>
</td>
<?php else: ?>
<td></td>
<td></td>
<td></td>
<?php endif; ?>
</tr>
<?php
} // foreach cate2
} // foreach cate1
?>
</tbody>
</table>
<?php endif; ?>
</div>
<?php
if (in_array(session('usr_level'), array('1', '2', '70'))): ?>
<div class="card-footer card-footer d-flex justify-content-center">
<button class="mb-2 me-2 btn btn-success"
onclick="ajax_saveCheck('<?= $apt['rcpt_no'] ?>','<?= $apt['hscp_no'] ?>');">검수</button>
<button class="mb-2 me-2 btn btn-warning"
onclick="ajax_resned('<?= $apt['rcpt_no'] ?>','<?= $apt['hscp_no'] ?>');">재전송</button>
</div>
<?php endif; ?>
</div>
</div>
<div class="main-card mb-3 card">
<div class="card-body ">
<h5 class="card-title">정보변경 이력</h5>
<div class="table-scroll">
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<tr>
<th width="90" style="text-align: center;">진행상태</th>
<th width="150" style="text-align: center;">변경내용</th>
<th width="90" style="text-align: center;">처리자(ID)</th>
<th width="120" style="text-align: center;">처리일시</th>
<th style="text-align: center;">세부내용</th>
</tr>
<?php if (!empty($history)) { ?>
<?php foreach ($history as $h) { ?>
<tr>
<td style="text-align: center;"><?= $h['apt_step_nm'] ?></td>
<td style="text-align: center;"><?= $h['changed_type_nm'] ?></td>
<td style="text-align: center;"><?= $h['charged_id'] ?></td>
<td style="text-align: center;"><?= $h['changed_tm'] ?></td>
<?php
if ($h['changed_type'] == 'D' || $h['changed_type'] == 'H' || $h['changed_type'] == 'A') {
?>
<td><?= $h['changed_detail'] ?></td>
<?php
} else {
?>
<td><?= $h['changed_detail_nm'] ?></td>
</tr>
<?php
} ?>
<?php } ?>
<?php } ?>
</table>
</div>
</div>
</div>
</div>
<!-- 동영상 업로드 팝업 -->
<?= $this->section('modals') ?>
<div class="modal fade" id="uploadModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">파일 업로드</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-0">
<form id="frm_file_info" method="post" enctype="multipart/form-data" onsubmit="return false;">
<input type="hidden" name="rcpt_no" value="<?= $apt['rcpt_no'] ?>">
<input type="hidden" name="upload_type" value="photo">
<div class="form-group">
<div class="row">
<!-- 전체 업로드 -->
<div class="col-md-2">
<button class="btn btn-block btn-outline-success" type="button" id="btnUpload">
<i class="pe-7s-up-arrow"></i> 전체업로드 </button>
</div>
<!-- 업로드 취소 -->
<div class="col-md-2">
<button class="btn btn-block btn-outline-danger" type="button" id="btnRemove">
<i class="pe-7s-less"></i> 업로드취소 </button>
</div>
</div>
</div>
<div id="myDropzone" class="form-group dropzone">
</div>
</form>
</div>
</div>
</div>
</div>
<div class="modal" id="mapModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">지도 보기</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-0">
<div id="modalMap" style="width:100%; height:70vh; min-height:500px;"></div>
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<style>
#tbl-align-left {
text-align: left;
}
</style>
<script src="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone-min.js"></script>
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
const bonbuArr = <?= json_encode($bonbu ?? [], JSON_UNESCAPED_UNICODE); ?>;
const teamArr = <?= json_encode($team ?? [], JSON_UNESCAPED_UNICODE); ?>;
const userArr = <?= json_encode($user ?? [], JSON_UNESCAPED_UNICODE); ?>;
var map, marker;
Dropzone.autoDiscover = false;
const lat = parseFloat("<?= esc($apt['rcpt_y'] ?? '0') ?>");
const lng = parseFloat("<?= esc($apt['rcpt_x'] ?? '0') ?>");
$(function () {
$("#bonbu, #team").on("change", function (e) {
const targetId = this.id;
let str = "";
if (targetId === "bonbu") {
const dept_sq = $("#bonbu").val();
str += `<option value="">선택</option>`;
$("#user").html(`<option value="">선택</option>`);
if (teamArr.length > 0) {
for (let i = 0; i < teamArr.length; i++) {
if (String(teamArr[i].pdept_sq) === String(dept_sq)) {
str += `<option value="${teamArr[i].dept_sq}">${teamArr[i].dept_nm}</option>`;
}
}
}
$("#team").html(str);
} else if (targetId === "team") {
const dept_sq = $("#team").val();
str += `<option value="">선택</option>`;
if (userArr.length > 0) {
for (let i = 0; i < userArr.length; i++) {
if (String(userArr[i].dept_sq) === String(dept_sq)) {
// ✅ PHP select가 usr_id를 쓰므로 JS도 usr_id로 통일
str += `<option value="${userArr[i].usr_id}">${userArr[i].usr_nm}</option>`;
}
}
}
$("#user").html(str);
}
});
map = new naver.maps.Map('mapArea', {
center: new naver.maps.LatLng(lat, lng),
useStyleMap: true,
zoom: 15,
minZoom: 1,
mapTypeControl: true,
mapTypeControlOptions: {
style: naver.maps.MapTypeControlStyle.BUTTON,
position: naver.maps.Position.TOP_LEFT
},
zoomControl: true,
zoomControlOptions: {
position: naver.maps.Position.TOP_RIGHT
}
});
marker = new naver.maps.Marker({
position: new naver.maps.LatLng(lat, lng),
map: map
});
// 지도 클릭 이벤트
naver.maps.Event.addListener(map, 'click', function (e) {
const clickLat = e.coord.lat();
const clickLng = e.coord.lng();
// 마커 위치 이동
marker.setPosition(e.coord);
// 콘솔 출력
console.log('위도:', clickLat, '경도:', clickLng);
// input에 값 넣기 (선택)
$('#rcpt_x').val(clickLng); // 경도
$('#rcpt_y').val(clickLat); // 위도
});
// 파일 modal - video
$("#btn_upload_video").on("click", function () {
$("#frm_file_info [name=upload_type]").val("video");
$("#uploadModal").modal("show");
});
$("#btn_upload_photo").on("click", function () {
$("#frm_file_info [name=upload_type]").val("photo");
$("#uploadModal").modal("show");
});
/**
* 파일 Dropzone
* */
const dz = new Dropzone("#myDropzone", {
url: "/article/apt/uploadFile",
method: "post",
paramName: "files",
autoProcessQueue: false, // 자동 업로드 끄기
uploadMultiple: true,
parallelUploads: 20,
maxFilesize: 100,
acceptedFiles: '.jpeg,.jpg,.JPEG,.JPG,.mpg,.MP4',
addRemoveLinks: true,
dictRemoveFile: "삭제",
dictDefaultMessage: "파일을 여기에 드래그하거나 클릭해서 추가하세요",
dictFallbackMessage: "브라우저가 드래그앤드롭을 지원하지 않습니다.",
dictFileTooBig: "파일이 너무 큽니다 (최대 {{maxFilesize}}MB)",
dictInvalidFileType: "허용되지 않은 파일 형식입니다.",
dictResponseError: "서버 오류가 발생했습니다.",
dictCancelUpload: "업로드 취소",
dictRemoveFile: "삭제",
dictMaxFilesExceeded: "더 이상 파일을 추가할 수 없습니다.",
init: function () {
this.on("addedfile", function (file) {
const ext = file.name.split('.').pop().toLowerCase();
const isVideo = (ext === 'mp4' || ext === 'mpg');
// 동영상은 단일 업로드만 허용
if (isVideo && this.files.length > 1) {
alert("동영상 파일은 1개만 업로드할 수 있습니다.");
this.removeFile(file);
return;
}
// 기존에 동영상이 있는데 다른 파일 추가 시 차단
const hasVideo = this.files.some(f => {
const e = f.name.split('.').pop().toLowerCase();
return e === 'mp4' || e === 'mpg';
});
if (hasVideo && !isVideo) {
alert("동영상 업로드 시 다른 파일을 함께 업로드할 수 없습니다.");
this.removeFile(file);
}
});
},
});
dz.on("addedfile", function (file) {
const removeBtn = file.previewElement.querySelector(".dz-remove");
if (removeBtn) {
removeBtn.classList.add(
"btn",
"btn-sm",
"btn-outline-danger",
"mt-2"
);
}
});
let isFormDataAppended = false;
dz.on("sending", function (file, xhr, formData) {
if (isFormDataAppended) return;
formData.append("rcpt_no", $("#frm_file_info [name=rcpt_no]").val());
formData.append("upload_type", $("#frm_file_info [name=upload_type]").val());
isFormDataAppended = true;
});
dz.on("completeMultiple", function () {
isFormDataAppended = false;
});
$("#btnUpload").on("click", function () {
dz.processQueue(); // 업로드 실행
});
$("#btnRemove").on("click", function () {
const files = dz.getAcceptedFiles();
if (files.length === 0) {
alert("삭제할 파일이 없습니다.");
return;
}
files.forEach(function (file) {
dz.removeFile(file);
});
});
});
function cate1_onchange(key) { //key = pho_no
var cate1 = $("#pho_cate1_" + key + " option:selected").val();
var cate2Obj = $("#pho_cate2_" + key);
cate2Obj.empty();
cate2Obj.append("<option value=\"\">-소분류-</option>");
if (cate1 != "") {
$.getJSON("/article/apt/cateJson?pho_cate1=" + cate1, function (result) {
var total = result.length;
for (var i = 0; i < total; i++) {
var cateNm = result[i].cd_nm;
if (total == 1) { //소분류가 1개면 그거 바로 보여주기
cate2Obj.append("<option value=\"" + result[i].cd + "\" selected>" + cateNm + "</option>");
} else {
cate2Obj.append("<option value=\"" + result[i].cd + "\">" + cateNm + "</option>");
}
}
});
}
}
// 메모저장
function saveMemo(rcptNo) {
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var params = {
'rcpt_no': rcptNo,
'memo': $("#memo").val()
};
callAjax("/article/apt/saveAptMemo", params, fn_result);
}
});
}
// 담당자 저장
function saveKeeper(rcptNo) {
if ($("#bonbu").val() == "") {
Swal.fire({
title: "본부를 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
if ($("#team").val() == "") {
Swal.fire({
title: "담당팀을 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
if ($("#user").val() == "") {
Swal.fire({
title: "담담자를 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var params = {
'rcpt_no': rcptNo,
'bonbu': $("#bonbu").val(),
'team': $("#team").val(),
'user': $("#user").val(),
};
callAjax("/article/apt/saveKeeper", params, fn_result);
}
});
}
// 단지특이사항 저장
function saveNote(rcptNo) {
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var params = {
'rcpt_no': rcptNo,
'note': $("#note").val(),
};
callAjax("/article/apt/saveNote", params, fn_result);
}
});
}
// 지도 좌표 저장
function saveCoordinate(rcptNo) {
if ($("#rcpt_y").val() == "") {
Swal.fire({
title: "위도를 입력해 주세요.",
icon: "warning",
draggable: true
});
return;
}
if ($("#rcpt_x").val() == "") {
Swal.fire({
title: "경도를 입력해 주세요.",
icon: "warning",
draggable: true
});
return;
}
swal.fire({
text: "지도좌표를 수정하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var params = {
'rcpt_no': rcptNo,
'rcpt_x': $("#rcpt_x").val(),
'rcpt_y': $("#rcpt_x").val(),
};
callAjax("/article/apt/saveCoordinate", params, fn_result);
}
});
}
// 동영상 촬영정보 저장
function saveVideoTarget(rcptNo) {
if ($("#video_target").val() == "") {
Swal.fire({
title: "영상촬영대상을 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var params = {
'rcpt_no': rcptNo,
'video_target': $("#video_target").val(),
'vdo_up_ynx': $("#vdo_up_ynx").is(":checked") === true ? "X" : "N",
};
callAjax("/article/apt/saveVideoTarget", params, fn_result);
}
});
}
// 촬영불가사유 저장
function saveVideoReason(rcptNo) {
const y = $('#not_vdo_reson').val(); // 사유
const v = $('input:checkbox[id="vdo_up_ynx"]').is(":checked");
const vv = $('input:checkbox[id="vdo_up_ynx"]').val();
if (v === true) {
if (y == "") {
Swal.fire({
title: "사유를 입력해 주세요.",
icon: "warning",
draggable: true
});
return;
}
}
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var params = {
'rcpt_no': rcpt_no,
'not_vdo_reson': y,
'vdo_up_ynx': $("#vdo_up_ynx").is(":checked") === true ? "X" : "N"
};
callAjax("/article/apt/saveVideoReason", params, fn_result);
}
});
}
// 사진업로드 불가사유 저장
function savePhoReason(rcpt_no, cate2_cd) {
var nothing = $('input:radio[id="pho_up_nu1_' + cate2_cd + '"]').is(":checked");
var unknown = $('input:radio[id="pho_up_nu2_' + cate2_cd + '"]').is(":checked");
if (nothing !== true && unknown !== true) {
Swal.fire({
title: "사유를 선택 주세요.",
icon: "warning",
draggable: true
});
return;
}
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var params = {
'rcpt_no': rcpt_no,
'pho_cate2': cate2_cd,
'pho_up_nu': $("input:radio[name=pho_up_nu_F01]:checked").val(),
};
callAjax("/article/apt/savePhoReason", params, fn_result);
}
});
}
// 사진카테고리수정
function saveCate(rcpt_no, cate2_cd) {
var cate1 = $('#pho_cate1_' + cate2_cd).val();
var cate2 = $('#pho_cate2_' + cate2_cd).val();
if (cate1 == '' || cate2 == '') {
Swal.fire({
title: "카테고리를 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
var check = $('input[id^="pho_no_' + cate2_cd + '_"]').serialize();
if (check == '') {
Swal.fire({
title: "사진을 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
var data = $('input[id^="pho_no_' + cate2_cd + '_"], #pho_cate1_' + cate2_cd + ', #pho_cate2_' + cate2_cd).serialize(); //serialize는 배열을 스트링으로 보내주는거다 data로 한번에 던져야함
data += '&rcpt_no=' + rcpt_no;
data += '&nowCate2=' + cate2_cd;
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
// var params = {
// 'rcpt_no': rcpt_no,
// 'pho_no': $('#pho_no' + cate2_cd).val(),
// 'cate1': cate1,
// 'cate2': cate2,
// };
callAjax("/article/apt/saveCate", data, fn_result);
}
});
}
// 사진 노출정보저장
function savePhotoView(rcpt_no, cate2_cd) {
var view1 = $('input:radio[id="pho_view_yn1_' + cate2_cd + '"]').is(":checked");
var view2 = $('input:radio[id="pho_view_yn2_' + cate2_cd + '"]').is(":checked");
if (view1 !== true && view2 !== true) {
Swal.fire({
title: "노출여부를 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
var check = $('input[id^="pho_no_' + cate2_cd + '_"]').serialize();
if (check == '') {
Swal.fire({
title: "사진을 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
var data = $('input[id^="pho_no_' + cate2_cd + '_"], #pho_view_yn1_' + cate2_cd + ', #pho_view_yn2_' + cate2_cd).serialize();
data += '&rcpt_no=' + rcpt_no + '&pho_cate2=' + cate2_cd;
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
callAjax("/article/apt/savePhotoView", data, fn_result);
}
});
}
// 사진정보삭제
function removePhoto(rcpt_no, cate2_cd) {
var data = $('input[id^="pho_no_' + cate2_cd + '_"]').serialize();
if (data == '') {
Swal.fire({
title: "사진을 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
data += '&rcpt_no=' + rcpt_no + '&cate2_cd=' + cate2_cd;
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
callAjax("/article/apt/removePhoto", data, fn_result);
}
});
}
// 사진 설명 저장
function savePhoExplain(rcpt_no, cate2_cd) {
var ex = $('#pho_explain_' + cate2_cd).val();
if (ex.length <= 0) {
Swal.fire({
title: "사진설명을 선택해 주세요.",
icon: "warning",
draggable: true
});
return;
}
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var data = {
'rcpt_no': rcpt_no,
'pho_cate2': cate2_cd,
'pho_explain': ex
};
callAjax("/article/apt/savePhoExplain", data, fn_result);
}
});
}
// 검수 저장
function ajax_saveCheck(rcpt_no, hscp_no) {
var stat = '<?php echo $apt['apt_step'] ?>';
var all_no_pho = '<?php echo $apt['all_no_pho'] ?>';
if (stat == 'S04') {//촬영완료
if (all_no_pho != 'X') { //사진촬영 불가가 아닐때
var gumsu_color = $('#gumsu_yn').css("color");
<?php foreach ($code1 as $row) { ?>
var cnt_color = $('#count_<?php echo $row['cd'] ?>').css("color");
if (gumsu_color == 'rgb(255, 0, 0)' || cnt_color == 'rgb(255, 0, 0)') { //검수여부나 사진설명이 빨간색이면
Swal.fire({
title: "정보를 다시 확인해주세요.",
icon: "warning",
draggable: true
});
return;
}
<?php } ?>
}
swal.fire({
text: "검수완료로 전송하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var data = {
'rcpt_no': rcpt_no,
'hscp_no': hscp_no,
};
callAjax("/article/apt/confirmAptInfo", data, fn_result);
}
});
} else if (stat == 'S05') {
Swal.fire({
title: "이미 전송을 완료했습니다.",
icon: "warning",
draggable: true
});
return;
} else {
Swal.fire({
title: "촬영완료 상태가 아닙니다.",
icon: "warning",
draggable: true
});
return;
}
}
// 재전송
function ajax_resned(rcpt_no, hscp_no) {
var stat = '<?= $apt['apt_step'] ?>';
if (stat !== 'S05') {
Swal.fire({
title: "검수완료 상태가 아닙니다.",
icon: "warning",
draggable: true
});
return;
}
swal.fire({
text: "재전송 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var data = {
'rcpt_no': rcpt_no,
'hscp_no': hscp_no,
};
callAjax("/article/apt/resendAptInfo", data, fn_result);
}
});
}
function callAjax(target, params, callback) {
$.ajax({
url: target,
method: "POST",
dataType: "json",
data: params,
beforeSend: function () {
blockUI.blockPage({
message: tpl
})
},
complete: function () {
blockUI.unblockPage()
},
success: function (result) {
callback(result);
}
});
}
function fn_result(result) {
if (result.code == '0') {
Swal.fire({
title: "정상 처리되었습니다.",
icon: "success",
draggable: true
})
} else {
Swal.fire({
title: result.msg,
icon: "error",
draggable: true
})
}
}
// 지도 모달
function viewCateMap() {
var modalMap = new naver.maps.Map('modalMap', {
center: new naver.maps.LatLng(lat, lng),
useStyleMap: true,
zoom: 20,
minZoom: 15,
mapTypeControl: true,
mapTypeControlOptions: {
style: naver.maps.MapTypeControlStyle.BUTTON,
position: naver.maps.Position.TOP_LEFT
},
zoomControl: true,
zoomControlOptions: {
position: naver.maps.Position.TOP_RIGHT
}
});
new naver.maps.Marker({
position: new naver.maps.LatLng(lat, lng),
map: modalMap
});
setTimeout(() => {
naver.maps.Event.trigger(modalMap, 'resize');
const c = modalMap.getCenter();
modalMap.setCenter(c);
}, 50);
$("#mapModal").modal("show");
}
</script>
<?= $this->endSection() ?>