From 06e266425ce5574d226c8d9dbb23cac955e09ee2 Mon Sep 17 00:00:00 2001 From: yangsh Date: Fri, 26 Dec 2025 17:21:21 +0900 Subject: [PATCH] =?UTF-8?q?=EC=95=84=ED=8C=8C=ED=8A=B8=ED=8F=89=EB=A9=B4?= =?UTF-8?q?=EB=8F=84=20=EB=AA=A9=EB=A1=9D=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Config/Routes.php | 16 +- app/Controllers/Article/Apt.php | 17 +- app/Controllers/Article/DelChgApt.php | 5 + app/Controllers/Article/Ground.php | 358 +++++++ app/Models/article/AptModel.php | 65 ++ app/Models/article/GroundModel.php | 651 +++++++++++++ app/Views/pages/article/lists.php | 45 +- app/Views/pages/article/lists2.php | 1289 +++++++++++++++++++++++++ 8 files changed, 2407 insertions(+), 39 deletions(-) create mode 100644 app/Controllers/Article/Ground.php create mode 100644 app/Models/article/GroundModel.php create mode 100644 app/Views/pages/article/lists2.php diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 707c0ef..ece01fe 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -54,7 +54,6 @@ $routes->group('article', ['namespace' => 'App\Controllers\Article'], function ( // 관할포인트 인쇄 $routes->get('apt/print', 'Apt::print'); - /** API - 아파트단지 */ $routes->get('apt/getAptLists', 'Apt::getAptLists'); $routes->post('apt/saveAptMemo', 'Apt::saveAptMemo'); @@ -92,6 +91,21 @@ $routes->group('article', ['namespace' => 'App\Controllers\Article'], function ( */ $routes->get('apt/delChgApt/getAptLists', 'DelChgApt::getAptLists'); $routes->post('apt/delChgApt/chgAptHscp', 'Apt::chgAptHscp'); + + + // 아파트 평면도 + $routes->get('apt/lists2', 'Ground::lists'); + + /** + * 아파트 평면도 - API + */ + $routes->get('apt/ground/getAptLists', 'Ground::getAptLists'); + $routes->get('apt/ground/excel', 'Ground::excel'); + $routes->post('apt/ground/chgAptDamdang', 'Ground::chgAptDamdang'); + $routes->post('apt/ground/uploadFile', 'Ground::uploadFile'); + $routes->get('apt/ground/print', 'Ground::print'); + + }); /** diff --git a/app/Controllers/Article/Apt.php b/app/Controllers/Article/Apt.php index 65ca672..1d6b958 100644 --- a/app/Controllers/Article/Apt.php +++ b/app/Controllers/Article/Apt.php @@ -166,11 +166,17 @@ class Apt extends BaseController $damdang = $this->request->getPost(index: 'damdang'); if (empty($team)) { - throw new Exception("팀정보 누락"); + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '팀정보 누락', + ]); } if (empty($damdang)) { - throw new Exception("담당자정보 누락"); + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '담당자정보 누락', + ]); } @@ -192,7 +198,10 @@ class Apt extends BaseController } } else { - throw new Exception("저장할 데이터 누락"); + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '저장데이터 누락', + ]); } return $this->response->setJSON([ @@ -262,8 +271,6 @@ class Apt extends BaseController // 엑셀 다운로드 public function excel() { - - try { $data = [ diff --git a/app/Controllers/Article/DelChgApt.php b/app/Controllers/Article/DelChgApt.php index 3545ba1..8b30e16 100644 --- a/app/Controllers/Article/DelChgApt.php +++ b/app/Controllers/Article/DelChgApt.php @@ -4,6 +4,11 @@ namespace App\Controllers\Article; use App\Controllers\BaseController; use App\Models\article\DelChgAptModel; +/** + * 단지코드관리 + * 2025.12.26 + * 작성자 : yangsh + */ class DelChgApt extends BaseController { private $model; diff --git a/app/Controllers/Article/Ground.php b/app/Controllers/Article/Ground.php new file mode 100644 index 0000000..db20cd4 --- /dev/null +++ b/app/Controllers/Article/Ground.php @@ -0,0 +1,358 @@ +model = new GroundModel(); + $this->codeModel = new CodeModel(); + } + + public function lists(): string + { + + $codes = $this->codeModel->getCodeLists(['VIDEO_TARGET', 'APT_GROUND_STEP', 'PHO_YN', 'VDO_YN']); // 코드조회 + $sido = $this->model->getAreaList(); // 지역조회 + $bonbu = $this->model->getBonbuList(); // 본부 + $team = $this->model->getTeamList(); // 팀 + $user = $this->model->getUserList(); // 유저 + + return view("pages/article/lists2", [ + 'codes' => $codes, + 'sido' => $sido, + 'bonbu' => $bonbu, + 'team' => $team, + 'user' => $user, + ]); + } + + // 아파트단지목록 조회 + public function getAptLists() + { + + $start = (int) $this->request->getGet('start') ?: 0; + $end = (int) $this->request->getGet('length') ?: 10; + + $data = [ + 'hscp_no' => $this->request->getGet('hscp_no'), // 단지코드 + 'part_no' => $this->request->getGet('part_no'), // 구분코드 + 'srcSido' => $this->request->getGet('srcSido'), // 시|도 + 'srcGugun' => $this->request->getGet('srcGugun'), // 시|군|구 + 'srcDong' => $this->request->getGet('srcDong'), // 읍|면|동 + + 'rcpt_hscp_nm' => $this->request->getGet('rcpt_hscp_nm'), // 단지명 + 'sdate' => $this->request->getGet('sdate'), // 시작일 + 'edate' => $this->request->getGet('edate'), // 종료일 + + 'bonbu' => $this->request->getGet('bonbu'), // 본부 + 'team' => $this->request->getGet('team'), // 팀 + 'damdang' => $this->request->getGet('damdang'), // 담당 + + 'stat' => $this->request->getGet('stat'), // 진행상태 + ]; + + $totalCount = $this->model->getTotalCount($data); + $datas = $this->model->getAptLists($start, $end, $data); + + $deptStatistics = $this->model->getDeptStatistics($data); // 조직별통계 + $areaStatistics = $this->model->getStatistics($data); // 지역별통계 + + return $this->response->setJSON(body: [ + 'draw' => (int) ($this->request->getGetPost('draw') ?? 0), // 서버사이드면 권장 + 'recordsTotal' => $totalCount, + 'recordsFiltered' => $totalCount, + 'data' => $datas, + 'widgets' => [ + 'deptList' => $deptStatistics, + 'areaStats' => $areaStatistics, + ], + ]); + + } + + // 엑셀 다운로드 + public function excel() + { + try { + + $data = [ + 'hscp_no' => $this->request->getGet('hscp_no'), // 단지코드 + 'part_no' => $this->request->getGet('part_no'), // 구분코드 + 'srcSido' => $this->request->getGet('srcSido'), // 시|도 + 'srcGugun' => $this->request->getGet('srcGugun'), // 시|군|구 + 'srcDong' => $this->request->getGet('srcDong'), // 읍|면|동 + + 'rcpt_hscp_nm' => $this->request->getGet('rcpt_hscp_nm'), // 단지명 + 'sdate' => $this->request->getGet('sdate'), // 시작일 + 'edate' => $this->request->getGet('edate'), // 종료일 + + 'bonbu' => $this->request->getGet('bonbu'), // 본부 + 'team' => $this->request->getGet('team'), // 팀 + 'damdang' => $this->request->getGet('damdang'), // 담당 + + 'stat' => $this->request->getGet('stat'), // 진행상태 + ]; + + $datas = $this->model->getExcelList($data); + + return $this->response->setJSON(body: [ + 'data' => $datas, + ]); + + } catch (\Exception $e) { + $e->getPrevious()->getTraceAsString(); + } + } + + + // 관할포인트 인쇄 - 화면 + public function print(): string + { + $deptSq = $this->request->getGet('depChk'); + $dept_cnt = count($deptSq); + + + $listDept = $this->model->getDeptMapList($deptSq); + + if (!empty($listDept)) { + $lati = 0; + $long = 0; + foreach ($listDept as $dept) { + $lati += $dept['rcpt_y']; + $long += $dept['rcpt_x']; + } + + $lati = $lati / $dept_cnt; + $long = $long / $dept_cnt; + } + + return view("pages/article/printMap", [ + // 'lati' => $lati, + // 'long' => $long, + 'listDept' => $listDept, + ]); + } + + // 담당자정보변경 + public function chgAptDamdang() + { + try { + + $team = $this->request->getPost('team'); + $damdang = $this->request->getPost(index: 'damdang'); + + if (empty($team)) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '팀정보 누락', + ]); + } + + if (empty($damdang)) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '담당자정보 누락', + ]); + } + + + $rows = $this->request->getPost('rows'); + + $rows = json_decode($rows, true); + + if (count($rows) > 0) { + foreach ($rows as $row) { + $params = [ + $team, + $damdang, + $row['rcpt_no'], + ]; + + + // UPDATE apt_result + $this->model->updateAptDamdang($params); + + } + } else { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '저장데이터 누락', + ]); + } + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } + + + // 파일업로드(평면도) + public function uploadFile() + { + $lib = new MyUpload(); + + try { + + $rcpt_no = $this->request->getPost('rcpt_no'); + $files = $this->request->getFiles(); + $uploadPath = "/upload/apt_file/" . $rcpt_no . "/"; + + + if (!isset($rcpt_no)) { + return $this->response->setJSON([ + 'success' => false, + 'msg' => '접수번호 누락' + ]); + } + + if (!isset($files['file'])) { + return $this->response->setJSON([ + 'success' => false, + 'msg' => '파일 없음' + ]); + } + + + $arrUploadfile = []; + $file = $files['file']; + if ($file->isValid() && !$file->hasMoved()) { + $uploadData = $lib->do_upload2($file, $uploadPath); + + if ($uploadData !== false) { + $arrUploadfile[] = $uploadData; + } + } + + $gps_lat = null; + $gps_lon = null; + $camDate = null; + // print_r($arrUploadfile); + // exit; + if (!empty($arrUploadfile)) { + foreach ($arrUploadfile as $key => $uploadFile) { + $object_storage_url = $uploadFile['object_storage_url']; + $arrExifData = @exif_read_data($object_storage_url); + if (!empty($arrExifData)) { + $notFound = "Unavailable"; + if (@array_key_exists('DateTime', $arrExifData)) { + $camDate = $arrExifData['DateTime']; + } else { + $camDate = $notFound; + } + + $imageMetaData = $camDate; + $camDate = substr(str_replace(':', '-', $camDate), 0, 10); + + $arrGPS = $arrExifData['GPS'] ?? null; + + if (empty($arrGPS)) { // GPS 섹션이 없으면, 개별 키로도 체크 + if (!empty($arrExifData['GPSLongitude']) && !empty($arrExifData['GPSLatitude'])) { + $arrGPS = [ + 'GPSLongitude' => $arrExifData['GPSLongitude'], + 'GPSLatitude' => $arrExifData['GPSLatitude'], + ]; + } + } + + if ( + !empty($arrGPS) + && !empty($arrGPS['GPSLongitude']) + && !empty($arrGPS['GPSLatitude']) + && is_array($arrGPS['GPSLongitude']) + && is_array($arrGPS['GPSLatitude']) + ) { //GPS 정보가 있다면 + if (@array_key_exists('GPSLongitude', $arrGPS) && (@array_key_exists('GPSLatitude', $arrGPS))) { + list($temp_d1, $temp_d2) = sscanf($arrGPS["GPSLatitude"][0], "%d/%d"); //문자->숫자로 계산 + $gps_lat_d = $temp_d1 / $temp_d2; + list($temp_d1, $temp_d2) = sscanf($arrGPS["GPSLatitude"][1], "%d/%d"); + $gps_lat_m = $temp_d1 / $temp_d2; + list($temp_d1, $temp_d2) = sscanf($arrGPS["GPSLatitude"][2], "%d/%d"); + $gps_lat_s = $temp_d1 / $temp_d2; + + list($temp_d1, $temp_d2) = sscanf($arrGPS["GPSLongitude"][0], "%d/%d"); //문자->숫자로 계산 + $gps_lon_d = $temp_d1 / $temp_d2; + list($temp_d1, $temp_d2) = sscanf($arrGPS["GPSLongitude"][1], "%d/%d"); + $gps_lon_m = $temp_d1 / $temp_d2; + list($temp_d1, $temp_d2) = sscanf($arrGPS["GPSLongitude"][2], "%d/%d"); + $gps_lon_s = $temp_d1 / $temp_d2; + + $gps_lat = $gps_lat_d + $gps_lat_m / 60 + $gps_lat_s / 3600; //도분초를 도로 변환 + $gps_lon = $gps_lon_d + $gps_lon_m / 60 + $gps_lon_s / 3600; + } + } + + } + + $base = $uploadFile['base_name']; // xxxx + $dir = rtrim(dirname($uploadFile['object_key']), '/'); // upload/apt_file/2 + $thumbKey = $dir . '/' . $base . '_thumb.jpg'; + + $imageDataBlob = file_get_contents($object_storage_url); + $im = new \Imagick(); + $im->readImageBlob($imageDataBlob); + $im->thumbnailImage(105, 80, false); + $thumb_im = $im->getImageBlob(); + // 썸네일 s3 전송 + $lib->upload_object_storage_imagick2($thumbKey, $thumb_im); + + + /** + * 파일업로드 내용 저장 + * rcpt_no, pho_lati, pho_long, filenm, filenm_up, file_path, thumb_path, thumb_nm, cloud_upload_yn + * + */ + $uploadParam = [ + 'rcpt_no' => $rcpt_no, // 접수번호 + 'gps_lat' => $gps_lat, // latitude + 'gps_lon' => $gps_lon, // longitude + 'origin_name' => $uploadFile['origin_name'], // 원본파일명 + 'file_name' => $uploadFile['file_name'], // 저장파일명 + 'file_ext' => '.' . $uploadFile['ext'], // 파일확장자 + 'upload_path' => $uploadPath, // 저장경로 + 'thumb_name' => $base . '_thumb.jpg', + 'cam_date' => $camDate, // 촬영일 + ]; + + // INSERT INTO apt_ground_photo + $res = $this->model->saveImg($uploadParam); + log_message('debug', 'apt_ground_file :: rcpt_no : ' . $rcpt_no . ', fileName : ' . $uploadFile['file_name']); + + } + } + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } +} \ No newline at end of file diff --git a/app/Models/article/AptModel.php b/app/Models/article/AptModel.php index 20d8bc7..4704df6 100644 --- a/app/Models/article/AptModel.php +++ b/app/Models/article/AptModel.php @@ -203,6 +203,19 @@ class AptModel extends Model $sql .= "AND a.dong_cnt <= {$data['dong_cnt2']} "; } + // 담당자 + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + // 진행상태 if (!empty($data['stat']) && is_array($data['stat'])) { $statList = "'" . implode("','", $data['stat']) . "'"; @@ -296,6 +309,19 @@ class AptModel extends Model $sql .= "AND a.dong_cnt <= {$data['dong_cnt2']} "; } + // 담당자 + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + // 진행상태 if (!empty($data['stat']) && is_array($data['stat'])) { $statList = "'" . implode("','", $data['stat']) . "'"; @@ -391,6 +417,19 @@ class AptModel extends Model $sql .= "AND a.dong_cnt <= {$data['dong_cnt2']} "; } + // 담당자 + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + // 진행상태 if (!empty($data['stat']) && is_array($data['stat'])) { $statList = "'" . implode("','", $data['stat']) . "'"; @@ -491,6 +530,19 @@ class AptModel extends Model $sql .= "AND a.dong_cnt <= {$data['dong_cnt2']} "; } + // 담당자 + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + // 진행상태 if (!empty($data['stat']) && is_array($data['stat'])) { $statList = "'" . implode("','", $data['stat']) . "'"; @@ -729,6 +781,19 @@ class AptModel extends Model $sql .= "AND a.dong_cnt <= {$data['dong_cnt2']} "; } + // 담당자 + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + // 진행상태 if (!empty($data['stat']) && is_array($data['stat'])) { $statList = "'" . implode("','", $data['stat']) . "'"; diff --git a/app/Models/article/GroundModel.php b/app/Models/article/GroundModel.php new file mode 100644 index 0000000..b7f8955 --- /dev/null +++ b/app/Models/article/GroundModel.php @@ -0,0 +1,651 @@ +db->query($sql, [$gugun]); + + } else if (!empty($sido)) { + $chk_sido = substr($sido, '0', '2'); + + if ($chk_sido === '36') { + $sido = substr($sido, '0', '4'); + $sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " . + "FROM region_codes a " . + "LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " . + "WHERE a.region_cd LIKE concat(?, '%') " . + "AND a.region_cd NOT LIKE '%000000' " . + "AND a.region_cd LIKE '%00' " . + "AND a.use_yn = 'Y' " . + "AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " . + "ORDER BY a.region_nm ASC"; + } else { + $sido = substr($sido, '0', '2'); + $sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" . + " FROM region_codes a" . + " LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" . + " WHERE a.region_cd LIKE concat(?, '%')" . + " AND a.region_cd NOT LIKE '%00000000'" . + " AND a.region_cd LIKE '%00000'" . + " AND a.use_yn = 'Y'" . + " AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" . + " ORDER BY a.region_nm ASC"; + } + + $query = $this->db->query($sql, [$sido]); + } else { + $sql = "SELECT a.region_cd, a.region_nm " . + "FROM region_codes a " . + "WHERE (a.region_cd LIKE '%00000000' " . + "AND a.use_yn = 'Y') " . + "OR region_cd = 3611000000;"; + + $query = $this->db->query($sql); + } + + + return $query->getResultArray(); + } + + + // 소속본부조회 + public function getBonbuList() + { + $sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" . + " FROM departments" . + " WHERE depth = 1" . + " AND use_yn = 'Y'" . + " ORDER BY lft"; + + $query = $this->db->query($sql); + + + return $query->getResultArray(); + } + + // 소속팀 조회 + public function getTeamList() + { + $sql = "SELECT dept_sq, pdept_sq, dept_nm" . + " FROM departments" . + " WHERE depth = 2" . + " AND use_yn = 'Y'" . + " ORDER BY dept_nm"; + + $query = $this->db->query($sql); + + + return $query->getResultArray(); + } + + // 유저 조회 + public function getUserList() + { + $sql = "SELECT + a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq + FROM users a + WHERE + a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70') + AND a.use_yn = 'Y' + AND EXISTS ( + SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y' + WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y' + ) + ORDER BY a.usr_level DESC, a.usr_nm ASC "; + + $query = $this->db->query($sql); + + return $query->getResultArray(); + } + + public function getTotalCount($data) + { + $sql = "SELECT COUNT(*) AS cnt + FROM apt_ground AS a + LEFT JOIN apt_ground_photo AS gp ON gp.pho_no = (SELECT p.pho_no + FROM apt_ground_photo p + WHERE p.rcpt_no = a.rcpt_no + ORDER BY p.pho_no DESC + LIMIT 1) + LEFT JOIN users b ON a.charger = b.usr_id + LEFT JOIN region_codes e ON a.region_cd = e.region_cd + LEFT JOIN departments i ON a.dept_sq = i.dept_sq + LEFT JOIN codes f ON a.write_complete_yn = f.cd AND f.category = 'PHO_YN' + LEFT JOIN codes h ON a.vdo_up_ynx = h.cd AND h.category = 'VDO_YN' + LEFT JOIN codes g ON a.apt_step = g.cd AND g.category = 'APT_STEP' + LEFT JOIN apt_history j ON a.rcpt_no = j.rcpt_no AND j.changed_detail = 'C2' AND NOT EXISTS (SELECT 'x' FROM apt_history WHERE changed_detail LIKE 'A%' AND rcpt_no = j.rcpt_no) "; + + $sql .= "WHERE 1=1 "; + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.hscp_no LIKE CONCAT('%', '{$data['hscp_no']}', '%') "; + } else { + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.part_no LIKE CONCAT('%', '{$data['part_no']}', '%') "; + } + + if (!empty($data['rcpt_hscp_nm'])) { + $sql .= "AND a.rcpt_hscp_nm LIKE CONCAT('%', '{$data['rcpt_hscp_nm']}', '%') "; + } + + // 법정동코드로 지역구분 + if (!empty($data['srcDong'])) { + $sql .= "AND a.region_cd = '{$data['srcDong']}' "; + } else { + if (!empty($data['srcGugun'])) { + $str_gugun = substr($data['srcGugun'], '0', '2'); + if ($str_gugun == '36') { //세종시는 군구가 없고 바로 동이라서 예외 + $sql .= "AND a.region_cd = '{$data['srcGugun']}' "; + } else { + $gugunPrefix = substr($data['srcGugun'], '0', '5'); + $sql .= "AND a.region_cd LIKE '{$gugunPrefix}%' "; + } + } else { + if (!empty($data['srcSido'])) { + $sidoPrefix = substr($data['srcSido'], '0', '2'); + $sql .= "AND a.region_cd LIKE '{$sidoPrefix}%' "; + } + } + } + + //촬영일자 == 단지정보작성완료 일자 + if (!empty($data['sdate'])) { + $sql .= "AND b.write_complete_tm >= '{$data['sdate']} 00:00:00' "; + } + + if (!empty($data['edate'])) { + $sql .= "AND b.write_complete_tm <= '{$data['edate']} 00:00:00' "; + } + + // 담당자 + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + + // 진행상태 + if (!empty($data['stat']) && is_array($data['stat'])) { + $statList = "'" . implode("','", $data['stat']) . "'"; + $sql .= " AND a.apt_step IN ({$statList}) "; + } + + } + + + $query = $this->db->query($sql); + + + return $query->getRow()->cnt; + } + + public function getAptLists($start, $end, $data) + { + $sql = "SELECT + a.rcpt_no, a.hscp_no, a.part_no, a.addr, a.addr2, a.rcpt_hscp_nm, a.pyeong_cnt, a.households_cnt, a.dong_cnt, a.rcpt_hscp_nm, + a.apt_cate_nm, a.rcpt_x, a.rcpt_y, + a.charger, a.memo, a.write_complete_yn, a.gpho_up_yn, a.vdo_up_ynx, a.apt_step, a.video_target, a.all_no_pho, a.send_end_tm, + a.dept_sq, a.vdo_up_tm, a.not_vdo_tm, a.check_tm, a.write_complete_tm, + b.usr_nm, i.dept_nm, j.changed_tm, gp.pho_no, gp.filenm, gp.filenm_up, gp.file_path, gp.file_ext, gp.cloud_upload_yn, gp.insert_tm + FROM + apt_ground AS a + LEFT JOIN apt_ground_photo AS gp ON gp.pho_no = (SELECT p.pho_no + FROM apt_ground_photo p + WHERE p.rcpt_no = a.rcpt_no + ORDER BY p.pho_no DESC + LIMIT 1) + LEFT JOIN users b ON a.charger = b.usr_id + LEFT JOIN region_codes e ON a.region_cd = e.region_cd + LEFT JOIN departments i ON a.dept_sq = i.dept_sq + LEFT JOIN codes f ON a.write_complete_yn = f.cd AND f.category = 'PHO_YN' + LEFT JOIN codes h ON a.vdo_up_ynx = h.cd AND h.category = 'VDO_YN' + LEFT JOIN codes g ON a.apt_step = g.cd AND g.category = 'APT_STEP' + LEFT JOIN apt_history j ON a.rcpt_no = j.rcpt_no AND j.changed_detail = 'C2' AND NOT EXISTS (SELECT 'x' FROM apt_history WHERE changed_detail LIKE 'A%' AND rcpt_no = j.rcpt_no) "; + + $sql .= "WHERE 1=1 "; + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.hscp_no LIKE CONCAT('%', '{$data['hscp_no']}', '%') "; + } else { + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.part_no LIKE CONCAT('%', '{$data['part_no']}', '%') "; + } + + if (!empty($data['rcpt_hscp_nm'])) { + $sql .= "AND a.rcpt_hscp_nm LIKE CONCAT('%', '{$data['rcpt_hscp_nm']}', '%') "; + } + + // 법정동코드로 지역구분 + if (!empty($data['srcDong'])) { + $sql .= "AND a.region_cd = '{$data['srcDong']}' "; + } else { + if (!empty($data['srcGugun'])) { + $str_gugun = substr($data['srcGugun'], '0', '2'); + if ($str_gugun == '36') { //세종시는 군구가 없고 바로 동이라서 예외 + $sql .= "AND a.region_cd = '{$data['srcGugun']}' "; + } else { + $gugunPrefix = substr($data['srcGugun'], '0', '5'); + $sql .= "AND a.region_cd LIKE '{$gugunPrefix}%' "; + } + } else { + if (!empty($data['srcSido'])) { + $sidoPrefix = substr($data['srcSido'], '0', '2'); + $sql .= "AND a.region_cd LIKE '{$sidoPrefix}%' "; + } + } + } + + //촬영일자 == 단지정보작성완료 일자 + if (!empty($data['sdate'])) { + $sql .= "AND b.write_complete_tm >= '{$data['sdate']} 00:00:00' "; + } + + if (!empty($data['edate'])) { + $sql .= "AND b.write_complete_tm <= '{$data['edate']} 00:00:00' "; + } + + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + + // 진행상태 + if (!empty($data['stat']) && is_array($data['stat'])) { + $statList = "'" . implode("','", $data['stat']) . "'"; + $sql .= " AND a.apt_step IN ({$statList}) "; + } + + } + + + $sql .= "LIMIT {$start}, {$end}"; + + $query = $this->db->query($sql); + + return $query->getResultArray(); + } + + + // 조직별 통계 + public function getDeptStatistics($data) + { + $sql = "SELECT + a.dept_sq, IFNULL(f.dept_nm, '') AS bonbu_nm, IFNULL(i.dept_nm, '미지정') AS team_nm, COUNT(a.dept_sq) as cnt + FROM + apt_ground a + LEFT JOIN apt_ground_photo AS gp ON gp.pho_no = (SELECT p.pho_no + FROM apt_ground_photo p + WHERE p.rcpt_no = a.rcpt_no + ORDER BY p.pho_no DESC + LIMIT 1) + LEFT JOIN users c ON a.charger = c.usr_id + LEFT JOIN region_codes e ON a.region_cd = e.region_cd + LEFT JOIN departments i ON a.dept_sq = i.dept_sq + LEFT JOIN departments f ON i.dept_sq = f.dept_sq "; + + $sql .= "WHERE 1=1 "; + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.hscp_no LIKE CONCAT('%', '{$data['hscp_no']}', '%') "; + } else { + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.part_no LIKE CONCAT('%', '{$data['part_no']}', '%') "; + } + + if (!empty($data['rcpt_hscp_nm'])) { + $sql .= "AND a.rcpt_hscp_nm LIKE CONCAT('%', '{$data['rcpt_hscp_nm']}', '%') "; + } + + // 법정동코드로 지역구분 + if (!empty($data['srcDong'])) { + $sql .= "AND a.region_cd = '{$data['srcDong']}' "; + } else { + if (!empty($data['srcGugun'])) { + $str_gugun = substr($data['srcGugun'], '0', '2'); + if ($str_gugun == '36') { //세종시는 군구가 없고 바로 동이라서 예외 + $sql .= "AND a.region_cd = '{$data['srcGugun']}' "; + } else { + $gugunPrefix = substr($data['srcGugun'], '0', '5'); + $sql .= "AND a.region_cd LIKE '{$gugunPrefix}%' "; + } + } else { + if (!empty($data['srcSido'])) { + $sidoPrefix = substr($data['srcSido'], '0', '2'); + $sql .= "AND a.region_cd LIKE '{$sidoPrefix}%' "; + } + } + } + + //촬영일자 == 단지정보작성완료 일자 + if (!empty($data['sdate'])) { + $sql .= "AND b.write_complete_tm >= '{$data['sdate']} 00:00:00' "; + } + + if (!empty($data['edate'])) { + $sql .= "AND b.write_complete_tm <= '{$data['edate']} 00:00:00' "; + } + + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + + // 진행상태 + if (!empty($data['stat']) && is_array($data['stat'])) { + $statList = "'" . implode("','", $data['stat']) . "'"; + $sql .= " AND a.apt_step IN ({$statList}) "; + } + + } + + $sql .= "GROUP BY a.dept_sq ORDER BY bonbu_nm ASC, team_nm ASC "; + + $query = $this->db->query($sql); + + return $query->getResultArray(); + } + + // 지역별 통계 + public function getStatistics($data) + { + $sql = "SELECT + a.addr AS addr, COUNT(a.addr) AS cnt + FROM + apt_ground a + LEFT JOIN apt_ground_photo gp ON a.rcpt_no = gp.rcpt_no + LEFT JOIN users c ON a.charger = c.usr_id + LEFT JOIN region_codes e ON a.region_cd = e.region_cd + LEFT JOIN departments i ON a.dept_sq = i.dept_sq "; + + $sql .= "WHERE 1=1 "; + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.hscp_no LIKE CONCAT('%', '{$data['hscp_no']}', '%') "; + } else { + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.part_no LIKE CONCAT('%', '{$data['part_no']}', '%') "; + } + + if (!empty($data['rcpt_hscp_nm'])) { + $sql .= "AND a.rcpt_hscp_nm LIKE CONCAT('%', '{$data['rcpt_hscp_nm']}', '%') "; + } + + // 법정동코드로 지역구분 + if (!empty($data['srcDong'])) { + $sql .= "AND a.region_cd = '{$data['srcDong']}' "; + } else { + if (!empty($data['srcGugun'])) { + $str_gugun = substr($data['srcGugun'], '0', '2'); + if ($str_gugun == '36') { //세종시는 군구가 없고 바로 동이라서 예외 + $sql .= "AND a.region_cd = '{$data['srcGugun']}' "; + } else { + $gugunPrefix = substr($data['srcGugun'], '0', '5'); + $sql .= "AND a.region_cd LIKE '{$gugunPrefix}%' "; + } + } else { + if (!empty($data['srcSido'])) { + $sidoPrefix = substr($data['srcSido'], '0', '2'); + $sql .= "AND a.region_cd LIKE '{$sidoPrefix}%' "; + } + } + } + + //촬영일자 == 단지정보작성완료 일자 + if (!empty($data['sdate'])) { + $sql .= "AND b.write_complete_tm >= '{$data['sdate']} 00:00:00' "; + } + + if (!empty($data['edate'])) { + $sql .= "AND b.write_complete_tm <= '{$data['edate']} 00:00:00' "; + } + + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + + // 진행상태 + if (!empty($data['stat']) && is_array($data['stat'])) { + $statList = "'" . implode("','", $data['stat']) . "'"; + $sql .= " AND a.apt_step IN ({$statList}) "; + } + + } + + $sql .= "GROUP BY a.addr ORDER BY a.addr ASC "; + + $query = $this->db->query($sql); + + return $query->getResultArray(); + } + + // 엑셀 다운로드 + public function getExcelList($data) + { + $sql = "SELECT + a.part_no AS '구분코드', + a.hscp_no AS '단지코드', + SUBSTRING_INDEX(a.addr, ' ', 1) AS '시도', + SUBSTRING_INDEX(a.addr, ' ', 2) AS '시군구', + SUBSTRING_INDEX(a.addr, ' ', 3) AS '읍면동', + a.addr2 AS '지번', + a.rcpt_hscp_nm AS '단지명', + a.apt_cate_nm AS '단지유형', + a.pyeong_cnt AS '평형', + i.dept_nm AS '방문팀', + b.usr_nm AS '담당자', + gp.insert_tm AS '촬영일자', + a.rcpt_x AS '단지X좌표', + a.rcpt_y AS '단지Y좌표' + FROM + apt_ground AS a + LEFT JOIN apt_ground_photo AS gp ON gp.pho_no = (SELECT p.pho_no + FROM apt_ground_photo p + WHERE p.rcpt_no = a.rcpt_no + ORDER BY p.pho_no DESC + LIMIT 1) + LEFT JOIN users b ON a.charger = b.usr_id + LEFT JOIN region_codes e ON a.region_cd = e.region_cd + LEFT JOIN departments i ON a.dept_sq = i.dept_sq + LEFT JOIN codes f ON a.write_complete_yn = f.cd AND f.category = 'PHO_YN' + LEFT JOIN codes h ON a.vdo_up_ynx = h.cd AND h.category = 'VDO_YN' + LEFT JOIN codes g ON a.apt_step = g.cd AND g.category = 'APT_STEP' + LEFT JOIN apt_history j ON a.rcpt_no = j.rcpt_no AND j.changed_detail = 'C2' AND NOT EXISTS (SELECT 'x' FROM apt_history WHERE changed_detail LIKE 'A%' AND rcpt_no = j.rcpt_no) "; + + $sql .= "WHERE 1=1 "; + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.hscp_no LIKE CONCAT('%', '{$data['hscp_no']}', '%') "; + } else { + + if (!empty($data['hscp_no'])) { + $sql .= "AND a.part_no LIKE CONCAT('%', '{$data['part_no']}', '%') "; + } + + if (!empty($data['rcpt_hscp_nm'])) { + $sql .= "AND a.rcpt_hscp_nm LIKE CONCAT('%', '{$data['rcpt_hscp_nm']}', '%') "; + } + + // 법정동코드로 지역구분 + if (!empty($data['srcDong'])) { + $sql .= "AND a.region_cd = '{$data['srcDong']}' "; + } else { + if (!empty($data['srcGugun'])) { + $str_gugun = substr($data['srcGugun'], '0', '2'); + if ($str_gugun == '36') { //세종시는 군구가 없고 바로 동이라서 예외 + $sql .= "AND a.region_cd = '{$data['srcGugun']}' "; + } else { + $gugunPrefix = substr($data['srcGugun'], '0', '5'); + $sql .= "AND a.region_cd LIKE '{$gugunPrefix}%' "; + } + } else { + if (!empty($data['srcSido'])) { + $sidoPrefix = substr($data['srcSido'], '0', '2'); + $sql .= "AND a.region_cd LIKE '{$sidoPrefix}%' "; + } + } + } + + //촬영일자 == 단지정보작성완료 일자 + if (!empty($data['sdate'])) { + $sql .= "AND b.write_complete_tm >= '{$data['sdate']} 00:00:00' "; + } + + if (!empty($data['edate'])) { + $sql .= "AND b.write_complete_tm <= '{$data['edate']} 00:00:00' "; + } + + if (!empty($data['damdang'])) { + $sql .= "AND a.charger = '{$data['damdang']}' "; + } else { + if (!empty($data['team'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['team']}') "; + } else { + if (!empty($data['bonbu'])) { + $sql .= "AND a.dept_sq IN (SELECT h.dept_sq FROM departments i INNER JOIN departments h ON h.lft >= i.lft AND h.lft <= i.rgt WHERE i.dept_sq = '{$data['bonbu']}') "; + } + } + } + + // 진행상태 + if (!empty($data['stat']) && is_array($data['stat'])) { + $statList = "'" . implode("','", $data['stat']) . "'"; + $sql .= " AND a.apt_step IN ({$statList}) "; + } + + } + + $query = $this->db->query($sql); + + return $query->getResultArray(); + } + + // 지도 마커 조회 + public function getDeptMapList($deptSq) + { + $sql = "SELECT + a.hscp_no, a.rcpt_hscp_nm, a.rcpt_no, a.dept_sq, a.rcpt_x, a.rcpt_y + , a.charger, i.dept_nm, i.pdept_sq, i.dept_desc, c.usr_nm, c.usr_id + ,(SELECT pdept_sq FROM departments WHERE dept_sq = i.dept_sq) bonbu + FROM + apt_ground a + LEFT JOIN apt_ground_photo AS gp ON gp.pho_no = (SELECT p.pho_no + FROM apt_ground_photo p + WHERE p.rcpt_no = a.rcpt_no + ORDER BY p.pho_no DESC + LIMIT 1) + LEFT JOIN users c ON a.charger = c.usr_id + LEFT JOIN region_codes e ON a.region_cd = e.region_cd + LEFT JOIN departments i ON a.dept_sq = i.dept_sq + LEFT JOIN codes f ON a.write_complete_yn = f.cd AND f.category = 'PHO_YN' + LEFT JOIN codes h ON a.vdo_up_ynx = h.cd AND h.category = 'VDO_YN' + LEFT JOIN codes g ON a.apt_step = g.cd AND g.category = 'APT_STEP' "; + + $sql .= "WHERE 1=1 "; + + if (!empty($deptSq)) { + $datas = "'" . implode("','", $deptSq) . "'"; + $sql .= " AND a.dept_sq IN ({$datas}) "; + } + + $query = $this->db->query($sql); + + return $query->getResultArray(); + } + + // 아파트 담당자 정보변경 + public function updateAptDamdang($params) + { + $sql = "UPDATE apt_ground SET "; + $sql .= "dept_sq = ?, charger = ? "; + $sql .= "WHERE rcpt_no = ? "; + + $this->db->query($sql, $params); + + + if ($this->db->transStatus() === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + // 성공 + return [ + 'success' => true, + ]; + } + + + // 평면도 정보 저장 + public function saveImg($data) + { + $sql = "INSERT INTO apt_ground_photo + (rcpt_no, filenm, filenm_up, file_ext, insert_tm, file_path, thumb_path, thumb_nm, use_yn, cloud_upload_yn) + VALUES + ({$data['rcpt_no']}, '{$data['origin_name']}', '{$data['file_name']}', '{$data['file_ext']}', NOW(), '{$data['upload_path']}', '{$data['upload_path']}' + , '{$data['thumb_name']}', 'Y', 'Y') + "; + + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + return [ + 'success' => true, + ]; + } +} \ No newline at end of file diff --git a/app/Views/pages/article/lists.php b/app/Views/pages/article/lists.php index 9b15d45..ec87d6c 100644 --- a/app/Views/pages/article/lists.php +++ b/app/Views/pages/article/lists.php @@ -191,37 +191,16 @@ onclick="progressStatAll(this, this.checked);"> - -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
+ + +
+ + +
+ + @@ -536,7 +515,7 @@ // 이 팀이 현재 본부에 속한 팀인지 체크 if (String(userArr[i].dept_sq) === String(dept_sq)) { str += ` - + `; } } @@ -653,7 +632,7 @@ } }, "columnDefs": [ - { targets: 0, orderable: false, className: 'text-center' }, + { className: 'text-center', targets: '_all' }, { 'targets': '_all', "defaultContent": "" }, // { 'className': 'text-center', 'targets': [0, 2, 3, 4] }, ], diff --git a/app/Views/pages/article/lists2.php b/app/Views/pages/article/lists2.php new file mode 100644 index 0000000..e198b2f --- /dev/null +++ b/app/Views/pages/article/lists2.php @@ -0,0 +1,1289 @@ +extend('layouts/main') ?> + +section('content') ?> + + +

아파트 평면도 내역

+ +
+
+
+ +
+
+
+ + + + + +
+
+ +
+ + 단지코드/구분코드를 입력하면 다른 조건은 무시됩니다. + +
+ +
+ + +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+
+ +
+ +
+ + ~ + +
+
+ + +
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+
+ + +
+ + +
+ + +
+ + +
+
+ +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + +
+ + 관할본부방문담당배정건수
+
+
+ + +
+
+ +
+
+
+
+ + + + + + + + +
방문담당배정건수
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+ + + + + + + + +
+ +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+ + 진행상태구분코드단지코드주소단지명평형방문팀담당업로드미리보기다운로드
+
+
+
+ + +section('modals') ?> + + + + + +endSection() ?> + + + + + + + + +endSection() ?> \ No newline at end of file