diff --git a/app/Config/Routes.php b/app/Config/Routes.php index f969561..5686df9 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'); @@ -62,6 +61,7 @@ $routes->group('article', ['namespace' => 'App\Controllers\Article'], function ( $routes->post('apt/chgAptVideoTarget', 'Apt::chgAptVideoTarget'); $routes->post('apt/chkTakeAptPhotoCnt', 'Apt::chkTakeAptPhotoCnt'); $routes->get('apt/excel', 'Apt::excel'); + $routes->post('apt/uploadExcel', 'Apt::uploadExcel'); /** API - 아파트단지 상세 */ $routes->post('apt/saveKeeper', 'Apt::saveKeeper'); @@ -73,11 +73,46 @@ $routes->group('article', ['namespace' => 'App\Controllers\Article'], function ( $routes->post('apt/savePhoReason', 'Apt::savePhoReason'); $routes->post('apt/saveCate', 'Apt::saveCate'); $routes->post('apt/savePhotoView', 'Apt::savePhotoView'); - $routes->post('apt/savePhotoView', 'Apt::savePhotoView'); + $routes->post('apt/removePhoto', 'Apt::removePhoto'); $routes->post('apt/confirmAptInfo', 'Apt::confirmAptInfo'); $routes->post('apt/resendAptInfo', 'Apt::resendAptInfo'); + $routes->post('apt/savePhoExplain', 'Apt::savePhoExplain'); + $routes->post('apt/saveWriteComplete', 'Apt::saveWriteComplete'); $routes->post('apt/uploadFile', 'Apt::uploadFile'); + $routes->post('apt/savePhoCate', 'Apt::savePhoCate'); + $routes->post('apt/reqRemovePho', 'Apt::reqRemovePho'); + + + // 단지번호 변경/삭제 + $routes->get('apt/del_chg_hscp_no', 'DelChgApt::lists'); + + /** + * 단지번호 변경/삭제 - API + */ + $routes->get('apt/delChgApt/getAptLists', 'DelChgApt::getAptLists'); + $routes->post('apt/delChgApt/chgAptHscp', 'Apt::chgAptHscp'); + + + // 아파트 평면도 + $routes->get('apt/lists2', 'Ground::lists'); + $routes->get('apt/ground/detail/(:num)/(:num)', 'Ground::detail/$1/$2'); + + /** + * 아파트 평면도 - API + */ + $routes->get('apt/ground/getAptLists', 'Ground::getAptLists'); + $routes->get('apt/ground/excel', 'Ground::excel'); + $routes->post('apt/ground/uploadExcel', 'Ground::uploadExcel'); + $routes->post('apt/ground/chgAptDamdang', 'Ground::chgAptDamdang'); + $routes->post('apt/ground/uploadFile', 'Ground::uploadFile'); + $routes->get('apt/ground/print', 'Ground::print'); + + $routes->post('apt/ground/saveMemo', 'Ground::saveMemo'); + $routes->post('apt/ground/saveKeeper', 'Ground::saveKeeper'); + $routes->post('apt/ground/statusChange', 'Ground::statusChange'); + $routes->post('apt/ground/saveNote', 'Ground::saveNote'); + }); diff --git a/app/Controllers/Article/Apt.php b/app/Controllers/Article/Apt.php index e431459..311a6d9 100644 --- a/app/Controllers/Article/Apt.php +++ b/app/Controllers/Article/Apt.php @@ -6,7 +6,6 @@ use App\Controllers\BaseController; use App\Libraries\MyUpload; use App\Models\article\AptModel; use App\Models\common\CodeModel; -use MY_Upload; class Apt extends BaseController { @@ -167,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' => '담당자정보 누락', + ]); } @@ -193,7 +198,10 @@ class Apt extends BaseController } } else { - throw new Exception("저장할 데이터 누락"); + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '저장데이터 누락', + ]); } return $this->response->setJSON([ @@ -259,12 +267,67 @@ class Apt extends BaseController } } + // 엑셀 업로드 + public function uploadExcel() + { + try { + + $payload = $this->request->getJSON(true); + $datas = $payload['datas'] ?? null; + + if (count($datas) === 0) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => "데이터 없음", + ]); + } + + + foreach ($datas as $data) { + $rdate = date("Y-m-d H:i:s"); + + $params = [ + 'row_no' => $data[0], + 'hscp_no' => $data[1], + 'uni_hscp_no' => $data[2], + 'region_cd' => $data[3], + 'addr' => $data[4], + 'addr2' => $data[5], + 'apt_cate_nm' => $data[6], + 'rcpt_hscp_nm' => $data[7], + 'move_ym' => $data[8], + 'households_cnt' => $data[9], + 'dong_cnt' => $data[10], + 'pyeong_cnt' => $data[11], + 'dongho' => $data[12], + 'use_yn' => $data[13], + 'rcpt_x' => $data[14], + 'rcpt_y' => $data[15], + 'pho_exept_yn' => $data[16], + 'rdate' => $rdate, + ]; + + // INSERT apt_receipt, apt_result + $this->aptModel->saveExcelUploadData($params); + + } + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } // 엑셀 다운로드 public function excel() { - - try { $data = [ @@ -673,6 +736,34 @@ class Apt extends BaseController } } + // 단지정보 작성완료 + public function saveWriteComplete() + { + try { + + $rcpt_no = $this->request->getPost('rcpt_no'); + if (empty($rcpt_no)) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '정보누락' + ]); + } + + $this->aptModel->saveWriteComplete($rcpt_no); + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } + // 검수완료 저장 public function confirmAptInfo() { @@ -868,11 +959,7 @@ class Apt extends BaseController $rcpt_no = $this->request->getPost('rcpt_no'); $uploadType = $this->request->getPost('upload_type'); $files = $this->request->getFiles(); - $imgPath = "/upload/apt_file/" . $rcpt_no . "/"; - - $imgPath = NCLOUD_OBJECT_STORAGE_URL . $imgPath; - $moviePath = $imgPath; - $photo360Path = $imgPath; + $uploadPath = "/upload/apt_file/" . $rcpt_no . "/"; if (!isset($files['files'])) { return $this->response->setJSON([ @@ -881,36 +968,267 @@ class Apt extends BaseController ]); } - if ($uploadType === "photo") { + $arrUploadfile = []; + foreach ($files['files'] as $file) { - // foreach ($files['files'] as $file) { - // if ($file->isValid()) { - // $file->move(WRITEPATH . 'uploads'); + $uploadData = $lib->do_upload2($file, $uploadPath); - // INSERT apt_photo + if ($uploadData !== false) { + $arrUploadfile[] = $uploadData; + } - print_r($_FILES); - // } + } + + $gps_lat = null; + $gps_lon = null; + $camDate = null; + 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); - // $imageDataBlob = file_get_contents($object_storage_url); - // $im = new Imagick(); - // $im->readImageBlob($imageDataBlob); - // $im->thumbnailImage(105, 80, false); - // $thumb_im = $im->getImageBlob(); - // $lib->upload_object_storage_imagick(); + $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; + } + } else { + $xy = $this->aptModel->getDetail($rcpt_no); + + $gps_lat = $xy['rcpt_y']; + $gps_lon = $xy['rcpt_x']; + } + + + } + + $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'], // 저장파일명 + 'upload_path' => $uploadPath, // 저장경로 + 'thumb_name' => $base . '_thumb.jpg', + 'cam_date' => $camDate, // 촬영일 + ]; + + $res = $this->aptModel->saveImg($uploadParam); + log_message('debug', 'apt_file :: rcpt_no : ' . $rcpt_no . ', fileName : ' . $uploadFile['file_name']); + + } + } } else if ($uploadType === "video") { + + $arrUploadfile = []; + foreach ($files['files'] as $file) { + + $uploadData = $lib->do_upload2($file, $uploadPath); + + if ($uploadData !== false) { + $arrUploadfile[] = $uploadData; + } + + } + + // print_r($arrUploadfile); + // exit; + + if (!empty($arrUploadfile)) { + foreach ($arrUploadfile as $key => $uploadFile) { + $uploadParam = [ + 'rcpt_no' => $rcpt_no, // 접수번호 + 'origin_name' => $uploadFile['origin_name'], // 원본파일명 + 'file_name' => $uploadFile['file_name'], // 저장파일명 + 'upload_path' => $uploadPath, // 저장경로 + // 'thumb_name' => $base . '_thumb.jpg', + // 'cam_date' => $camDate, // 촬영일 + ]; + + + // 동영상 정보 저장 + $this->aptModel->saveVideo($uploadParam); + + } + } + + } + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } + + // 업로드파일삭제 + public function reqRemovePho() + { + try { + + $type = $this->request->getPost('type'); + + + if ($type === "all") { + $rcpt_no = $this->request->getPost('rcpt_no'); + + // 사진 일괄 삭제 + $this->aptModel->removeAllPho($rcpt_no); + + + } else if ($type === "select") { + $phoNo = $this->request->getPost('phoNo'); // ✅ 배열로 들어옴 + + if (!is_array($phoNo)) + $phoNo = [$phoNo]; + + if (empty($phoNo)) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '데이터 누락' + ]); + } + + // 선택 사진 삭제 + $this->aptModel->removePho($phoNo); + + + } 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 savePhoCate() + { + try { + + $rcpt_no = $this->request->getPost('rcpt_no'); + $code1 = $this->request->getPost('code1'); + $code2 = $this->request->getPost('code2'); + $phoNo = $this->request->getPost('phoNo'); + + if (!is_array($phoNo)) + $phoNo = [$phoNo]; + + if (empty($phoNo)) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '데이터 누락' + ]); + } + + foreach ($phoNo as $pho) { + + $data = [ + 'rcpt_no' => $rcpt_no, + 'pho_no' => $pho, + 'code1' => $code1, + 'code2' => $code2, + ]; + + // 카테고리 지정 + $this->aptModel->updatePhoCate($data); + + } + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + } catch (\Exception $e) { return $this->response->setJSON([ diff --git a/app/Controllers/Article/DelChgApt.php b/app/Controllers/Article/DelChgApt.php new file mode 100644 index 0000000..8b30e16 --- /dev/null +++ b/app/Controllers/Article/DelChgApt.php @@ -0,0 +1,129 @@ +model = new DelChgAptModel(); + } + + public function lists(): string + { + return view("pages/article/delChgView"); + } + + + public function getAptLists() + { + $start = (int) $this->request->getGet('start') ?: 0; + $end = (int) $this->request->getGet('length') ?: 10; + + $data = [ + 'hscpNo' => $this->request->getGet('hscpNo') ?: '', + ]; + + $totalCount = $this->model->getTotalCount($data); + + + $datas = $this->model->getAptLists($start, $end, $data); + + + return $this->response->setJSON(body: [ + 'recordsTotal' => $totalCount, + 'recordsFiltered' => $totalCount, + 'data' => $datas, + ]); + } + + // 단지코드 변경 + public function chgAptHscp() + { + try { + + $rcptNo = $this->request->getPost('rcpt_no'); + + if (empty($rcptNo)) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '접수번호 누락' + ]); + } + + $data = [ + 'rcptNo' => $rcptNo, + 'hscpNo' => $this->request->getPost('hscp_no'), + ]; + + // 기존 단지코드 있는지 체크 + $exits = $this->model->chkExistAptHscp($data); + if ($exits) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '이미 존재하는 단지코드' + ]); + } + + // 단지코드 저장 + $this->model->saveAptHscp($data); + + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } + + // 아파트단지 삭제 + public function deleteAptHscp() + { + try { + + $rcptNo = $this->request->getPost('rcpt_no'); + + if (empty($rcptNo)) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => '접수번호 누락' + ]); + } + + $data = [ + 'rcptNo' => $rcptNo, + ]; + + // 단지코드 저장 + $this->model->deleteAptHscp($data); + + + 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/Controllers/Article/Ground.php b/app/Controllers/Article/Ground.php new file mode 100644 index 0000000..f374494 --- /dev/null +++ b/app/Controllers/Article/Ground.php @@ -0,0 +1,569 @@ +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 uploadExcel() + { + try { + + $payload = $this->request->getJSON(true); + $datas = $payload['datas'] ?? null; + + if (count($datas) === 0) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => "데이터 없음", + ]); + } + + foreach ($datas as $data) { + $rdate = date("Y-m-d H:i:s"); + + $params = [ + 'hscp_no' => $data[1], + 'region_cd' => $data[2], + 'part_no' => $data[0], + 'apt_step' => 'S01', + 'addr' => $data[3] . ' ' . $data[4] . ' ' . $data[5], + 'addr2' => $data[6], + 'rcpt_hscp_nm' => $data[7], + 'apt_cate_nm' => $data[8], + 'pyeong_cnt' => $data[9], + 'rcpt_x' => $data[10], + 'rcpt_y' => $data[11], + 'ginsert_tm' => $rdate, + ]; + + // INSERT apt_ground + $this->model->saveExcelUploadData($params); + + } + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } + + // 엑셀 다운로드 + 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 detail($rcpt_no, $hscp_no): string + { + + if ($rcpt_no == null || $hscp_no == null) { + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); + } + + $bonbu = $this->model->getBonbuList(); + $team = $this->model->getTeamList(); + $user = $this->model->getUserList(); + + // 상세정보 + $apt = $this->model->getDetail($rcpt_no, $hscp_no); + + // 동일단지 + $rdata = $this->model->getDetailLists($rcpt_no, $hscp_no); + + // 변경이력 + $history = $this->model->getHistory($rcpt_no); + + return view("pages/article/detail2", [ + 'bonbu' => $bonbu, + 'team' => $team, + 'user' => $user, + 'apt' => $apt, + 'rdata' => $rdata, + 'history' => $history, + ]); + } + + // 메모저장 + public function saveMemo() + { + try { + + $data = [ + 'rcpt_no' => $this->request->getPost('rcpt_no'), + 'memo' => $this->request->getPost('memo'), + ]; + + // UPDATE apt_ground + $this->model->saveMemo($data); + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } + + // 담당자 변경 + public function saveKeeper() + { + try { + + + $data = [ + 'rcpt_no' => $this->request->getPost('rcpt_no'), + 'bonbu' => $this->request->getPost('bonbu'), + 'team' => $this->request->getPost('team'), + 'user' => $this->request->getPost('user'), + ]; + + + // UPDATE apt_ground + $this->model->saveKeeper($data); + + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } + + // 단지상태변경 + public function statusChange() + { + $lib = new MyUpload(); + + try { + + $type = $this->request->getPost('type'); + $rcpt_no = $this->request->getPost('rcpt_no'); + + + if ($type === "phoX") { + $apt = $this->model->getDetail($rcpt_no, ""); + + if (!empty($apt['pho_no'])) { + $path = $apt['file_path'] . "" . $apt['filenm_up']; + + $lib->deleteFile($path); + } + + + } + + // UPDATE apt_ground + $this->model->statusChange($rcpt_no, $type); + + + return $this->response->setJSON([ + 'code' => '0', + 'msg' => 'success' + ]); + + } catch (\Exception $e) { + return $this->response->setJSON([ + 'code' => '9', + 'msg' => $e->getMessage(), + ]); + } + } + + // 단지 특이사항 저장 + public function saveNote() + { + try { + + $rcpt_no = $this->request->getPost('rcpt_no'); + + + $data = [ + 'rcpt_no' => $rcpt_no, + 'note' => $this->request->getPost('note'), + ]; + + + // UPDATE apt_ground + $this->model->saveNote($data); + + + 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/Controllers/Manage/Scomplex.php b/app/Controllers/Manage/Scomplex.php index 00bc5e4..608a3ec 100644 --- a/app/Controllers/Manage/Scomplex.php +++ b/app/Controllers/Manage/Scomplex.php @@ -1,10 +1,10 @@ isValid()) { + $this->set_error('upload_invalid_file'); + return false; + } + + // 업로드 전인데 hasMoved()가 true면 비정상 상태 + if ($file->hasMoved()) { + $this->set_error('upload_file_already_moved'); + return false; + } + + $newName = $file->getRandomName(); + + // ✅ PHP 임시 업로드 파일 경로 (writable로 move() 필요 없음) + $tmpFile = $file->getTempName(); + if (!is_file($tmpFile)) { + $this->set_error('upload_temp_file_missing'); + log_message('error', 'do_upload2 temp file missing: ' . $tmpFile); + return false; + } + + // ✅ 클라우드에 올라갈 "Key"를 직접 만든다 (로컬 경로 절대 넣지 말기) + // 예시: upload/tmp/랜덤파일명 또는 upload/apt_file/{rcpt_no}/... + $objectKey = $filePath . $newName; + + $up = $this->upload_object_storage($objectKey, $tmpFile, 'file'); + if ($up === false) { + $this->set_error('upload_destination_cloud_error'); + return false; + } + + // (선택) tmp 파일 삭제 + @unlink($tmpFile); + + $this->s3_data = [ + 'object_key' => $objectKey, + 'object_storage_url' => $up['object_storage_url'] ?? null, + 'origin_name' => $file->getClientName(), + 'file_name' => basename($objectKey), // xxxx.jpg + 'base_name' => pathinfo($objectKey, PATHINFO_FILENAME), // xxxx + 'ext' => pathinfo($objectKey, PATHINFO_EXTENSION), // jpg + ]; + + + log_message('debug', 's3_data=' . json_encode($this->s3_data ?? null, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); + + + return $this->s3_data; + } + + /** + * + */ + public function deleteFile($key) + { + $s3Client = $this->makeS3Client(); + + try { + + $s3Client->deleteObject([ + 'Bucket' => NCLOUD_S3_BUCKET, + 'Key' => ltrim($key, '/'), + ]); + + return true; + } catch (\Throwable $e) { + return false; + } + } + + /** + * S3(NCLOUD) 파일 업로드 + * 추가일 2025.12.24 + * 작성자 - yangsh + */ public function do_upload(string $field = 'userfile'): bool { + $request = service('request'); $file = $request->getFile($field); + var_dump($file); + if (!$file) { $this->set_error('upload_no_file_selected'); return false; @@ -222,10 +310,13 @@ class MyUpload $this->errors[] = $msg; } - // -------------------------------------------------------------------- - // === 너의 기존 S3 메서드들 (CI4용으로 client 생성만 보강) === - public function upload_object_storage(string $key, string $temp_file, string $type = 'file'): bool + /** + * S3(NCLOUD) 파일 업로드 + * 수정일 2025.12.24 + * 작성자 - yangsh + */ + public function upload_object_storage(string $key, string $temp_file, string $type = 'file'): array|false { // CI3 코드의 경로 치환 로직 유지 (FCPATH는 CI4에도 존재) $object_storage_upload_path = str_replace(FCPATH, '/', $key); @@ -236,27 +327,77 @@ class MyUpload $s3Client = $this->makeS3Client(); try { - $body = file_get_contents($temp_file); + // $body = file_get_contents($temp_file); + + // $response = $s3Client->putObject([ + // 'Bucket' => NCLOUD_S3_BUCKET, + // 'Key' => ltrim($object_storage_upload_path, '/'), + // 'Body' => $body, + // 'ACL' => 'public-read', + // ]); $response = $s3Client->putObject([ 'Bucket' => NCLOUD_S3_BUCKET, 'Key' => ltrim($object_storage_upload_path, '/'), - 'Body' => $body, + 'SourceFile' => $temp_file, // ✅ 동영상도 OK 'ACL' => 'public-read', + + // (선택) 타입별 ContentType 지정 (브라우저 재생/다운로드에 중요) + // 'ContentType' => $this->guessMime($temp_file, $type), ]); - $this->s3_data = [ - 'object_storage_upload_path' => $object_storage_upload_path, + // $this->s3_data = [ + // 'object_storage_upload_path' => $object_storage_upload_path, + // 'object_storage_url' => $response['ObjectURL'] ?? null, + // ]; + + return [ 'object_storage_url' => $response['ObjectURL'] ?? null, ]; } catch (\Throwable $e) { // 운영에서는 echo 지양. 로그로 남기는 걸 추천 // log_message('error', $e->getMessage()); + log_message('error', '[S3 UPLOAD FAIL] ' . $e->getMessage()); + log_message('error', '[S3 UPLOAD TRACE] ' . $e->getTraceAsString()); + return false; + } + + } + + /** + * S3(NCLOUD) 파일 업로드 - 썸네일 + * 추가일 2025.12.24 + * 작성자 - yangsh + */ + public function upload_object_storage_imagick2($key, $blobData): bool + { + $object_storage_upload_path = str_replace(FCPATH, '/', $key); + $object_storage_upload_path = str_replace('/image/confirms_upload/', '/upload/', $object_storage_upload_path); + $object_storage_upload_path = str_replace('//', '/', $object_storage_upload_path); + $object_storage_upload_path = str_replace('/home/www/upload/confirms_upload/', '/upload/', $object_storage_upload_path); + + $s3Client = $this->makeS3Client(); + + try { + + $response = $s3Client->putObject([ + 'Bucket' => NCLOUD_S3_BUCKET, + 'Key' => ltrim($object_storage_upload_path, '/'), + 'Body' => $blobData, + 'ACL' => 'public-read', + ]); + + + } catch (\Throwable $e) { + // 운영에서는 echo 지양. 로그로 남기는 걸 추천 + log_message('error', '[S3 UPLOAD FAIL] ' . $e->getMessage()); + log_message('error', '[S3 UPLOAD TRACE] ' . $e->getTraceAsString()); return false; } return true; + } public function upload_object_storage_imagick(string $key, $blobData): bool @@ -306,28 +447,18 @@ class MyUpload protected function makeS3Client(): S3Client { - // AWS SDK v2: S3Client::factory / v3+: new S3Client - if (method_exists(S3Client::class, 'factory')) { - /** @noinspection PhpUndefinedMethodInspection */ - return S3Client::factory([ - 'key' => NCLOUD_S3_KEY, - 'secret' => NCLOUD_S3_SECRET, - 'endpoint' => NCLOUD_S3_ENDPOINT, - 'debug' => true, - 'ssl.certificate_authority' => false, - ]); - } + $region = defined('NCLOUD_S3_REGION') ? NCLOUD_S3_REGION : 'ap-northeast-2'; + + // ✅ credentials를 provider로 강제하면 provider-chain(IMDS) 안 탐 + $creds = new Credentials(NCLOUD_S3_KEY, NCLOUD_S3_SECRET); + $provider = CredentialProvider::fromCredentials($creds); return new S3Client([ - 'endpoint' => NCLOUD_S3_ENDPOINT, - 'credentials' => [ - 'key' => NCLOUD_S3_KEY, - 'secret' => NCLOUD_S3_SECRET, - ], - 'region' => defined('NCLOUD_S3_REGION') ? NCLOUD_S3_REGION : 'kr-standard', 'version' => 'latest', - // (보안주의) 필요하면 verify 설정을 추가 - // 'http' => ['verify' => false], + 'region' => $region, + 'endpoint' => NCLOUD_S3_ENDPOINT, + 'credentials' => $provider, + 'use_path_style_endpoint' => true, ]); } diff --git a/app/Models/article/AptModel.php b/app/Models/article/AptModel.php index 47752ca..071e356 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']) . "'"; @@ -631,6 +683,77 @@ class AptModel extends Model ]; } + // 엑셀업로드 저장 + public function saveExcelUploadData($params) + { + + $this->db->transStart(); + + $builder = $this->db->table('apt_receipt'); + $res = $builder->insert($params); + + if ($res === false) { + return [ + 'success' => false, + 'msg' => "단지코드 : {$params['hscp_no']} 저장실패", + ]; + } + + $rcpt_no = $this->db->insertID(); + + $params2 = [ + 'rcpt_no' => $rcpt_no, + 'hscp_no' => $params['hscp_no'], + 'region_cd' => $params['region_cd'], + 'charger' => '', + 'dept_sq' => '', + 'addr' => $params['addr'], + 'addr2' => $params['addr2'], + 'rcpt_hscp_nm' => $params['rcpt_hscp_nm'], + 'rcpt_x' => $params['rcpt_x'], + 'rcpt_y' => $params['rcpt_y'], + 'move_ym' => $params['move_ym'], + 'households_cnt' => $params['households_cnt'], + 'dong_cnt' => $params['dong_cnt'], + 'apt_cate_nm' => $params['apt_cate_nm'], + 'apt_step' => 'S01', + 'check_yn' => 'N', + 'resend_yn' => 'N', + 'memo' => '', + 'pho_up_yn' => 'N', + 'vdo_up_ynx' => 'N', + 'vdo_up_tm' => NULL, + 'video_target' => 'N', + 'not_vdo_reson' => '', + 'note' => '', + 'not_vdo_tm' => NULL, + 'check_tm' => NULL, + 'write_complete_yn' => 'N', + 'write_complete_tm' => NULL, + 'all_no_pho' => NULL, + 'syncid' => '', + 'sync_comp' => NULL, + 'sync_wait_cnt' => '0' + ]; + + $builder = $this->db->table('apt_result'); + $res = $builder->insert($params2); + + if ($res === false) { + return [ + 'success' => false, + 'msg' => "단지코드 : {$params['hscp_no']} 저장실패", + ]; + } + + $this->db->transComplete(); + + // 성공 + return [ + 'success' => true, + ]; + } + // 엑셀 다운로드 public function getExcelList($data) { @@ -729,6 +852,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']) . "'"; @@ -772,6 +908,7 @@ class AptModel extends Model ,b.memo, b.note, b.video_target, b.vdo_up_ynx, b.not_vdo_reson, b.apt_step, b.not_vdo_tm, b.check_yn, b.resend_yn, b.write_complete_yn, b.all_no_pho ,b.write_complete_tm, DATE_FORMAT(b.write_complete_tm, '%Y-%m-%d') as rdate_dt_cmpl ,DATE_FORMAT(b.write_complete_tm, '%H:%i:%s') as rdate_tm_cmpl ,b.charger, b.dept_sq ,(SELECT pdept_sq FROM departments WHERE dept_sq = b.dept_sq) bonbu + ,IFNULL((SELECT CONCAT(file_path, '', filenm_up) FROM apt_photo WHERE rcpt_no = a.rcpt_no AND pho_cate1 = 'V' AND pho_cate2 = 'V01' ORDER BY pho_no DESC LIMIT 1), '') AS vdo_path FROM apt_receipt a JOIN apt_result b ON a.rcpt_no = b.rcpt_no @@ -1030,8 +1167,24 @@ class AptModel extends Model 'pho_cate2' => $params['pho_cate2'], ]; - $this->db->where_in('pho_no', $params['pho_no']); - $result = $this->db->update('apt_photo', $data); + $phoNos = $params['pho_no'] ?? []; + + if (!is_array($phoNos)) { + $phoNos = [$phoNos]; + } + + if (empty($phoNos)) { + return [ + 'success' => false, + 'msg' => '대상 pho_no가 없습니다.', + ]; + } + + $builder = $this->db->table('apt_photo'); + + $builder->whereIn('pho_no', $phoNos); + $result = $builder->update($data); + if ($result === false) { return [ @@ -1182,6 +1335,31 @@ class AptModel extends Model ]; } + // 단지정보 작성완료 + public function saveWriteComplete($rcpt_no) + { + $sql = " UPDATE apt_result" . + " SET write_complete_yn = 'Y'" . + " ,apt_step = CASE WHEN vdo_up_ynx = 'N' THEN 'S02' ELSE 'S04' END" . + " ,write_complete_tm = now()" . + " WHERE rcpt_no = ? "; + + if ($this->db->query($sql, [$rcpt_no])) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $now = $this->getDetail($rcpt_no); + $this->saveHistory($rcpt_no, $now['apt_step'], 'C', 'C1', session('usr_id')); + + // 성공 + return [ + 'success' => true, + ]; + } + // 단지실사 API 정보 public function new_api_photo_send_data($rcpt_no) @@ -1246,4 +1424,153 @@ class AptModel extends Model 'success' => true, ]; } + + + // 업로드 파일정보 저장 + public function saveImg($params) + { + $sql = "INSERT INTO apt_photo + (rcpt_no, pho_lati, pho_long, filenm, filenm_up, pho_view_yn, pho_date, insert_tm, file_path, use_yn, thumb_path, thumb_nm, cloud_upload_yn) + VALUES + ( + {$params['rcpt_no']}, + '{$params['gps_lat']}', + '{$params['gps_lon']}', + '{$params['origin_name']}', + '{$params['file_name']}', + 'Y', + '{$params['cam_date']}', + NOW(), + '{$params['upload_path']}', + 'Y', + '{$params['upload_path']}', + '{$params['thumb_name']}', + 'Y' + ) + "; + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + return [ + 'success' => true, + ]; + } + + // 동영상 정보 저장 + public function saveVideo($params) + { + $sql = "INSERT INTO apt_photo + (rcpt_no, pho_cate1, pho_cate2, filenm, filenm_up, insert_tm, file_path, use_yn, cloud_upload_yn) + VALUES + ( + {$params['rcpt_no']}, + 'V', + 'V01', + '{$params['origin_name']}', + '{$params['file_name']}', + NOW(), + '{$params['upload_path']}', + 'Y', + 'Y' + ) + "; + + // print ($sql); + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $sql = "UPDATE apt_result" . + " SET vdo_up_ynx = 'Y'" . + " ,not_vdo_reson = ''" . + " ,video_target = 'Y'" . + " ,not_vdo_tm = NULL " . + " ,vdo_up_tm = NOW() " . + " ,apt_step = 'S03'" . + " WHERE rcpt_no = {$params['rcpt_no']}"; + + $this->db->query($sql); + + // print ($sql); + + //히스토리 + $this->saveHistory($params['rcpt_no'], 'S03', 'F', 'F1', session('usr_id')); + + return [ + 'success' => true, + ]; + } + + + // 업로드파일 일괄삭제 + public function removeAllPho($rcpt_no) + { + $sql = "UPDATE apt_photo" . + " SET use_yn = 'N'" . + " WHERE rcpt_no = ? "; + + if ($this->db->query($sql, [$rcpt_no]) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + return [ + 'success' => true, + ]; + } + + // 선택파일 삭제 + public function removePho($params) + { + $builder = $this->db->table('apt_photo'); + + $builder->whereIn('pho_no', $params); + + $result = $builder->update([ + 'use_yn' => 'N', + ]); + + if ($result === false) { + return [ + 'success' => false, + 'msg' => 'DB 업데이트 실패', + ]; + } + + return [ + 'success' => true, + ]; + } + + // 카테고리 지정 + public function updatePhoCate($data) + { + $sql = "UPDATE apt_photo SET + pho_cate1 = '{$data['code1']}', + pho_cate2 = '{$data['code2']}' + WHERE pho_no = {$data['pho_no']} + "; + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장 실패', + ]; + } + + return [ + 'success' => true, + ]; + } } \ No newline at end of file diff --git a/app/Models/article/DelChgAptModel.php b/app/Models/article/DelChgAptModel.php new file mode 100644 index 0000000..e177684 --- /dev/null +++ b/app/Models/article/DelChgAptModel.php @@ -0,0 +1,138 @@ +db->query($sql); + + return $query->getRow()->cnt; + } + + public function getAptLists($start, $end, $data) + { + $sql = "SELECT rcpt_no, hscp_no, rcpt_hscp_nm FROM apt_receipt WHERE 1=1 "; + + if (!empty($data['hscpNo'])) { + $sql .= "AND hscp_no LIKE CONCAT('%', '{$data['hscpNo']}', '%')"; + } + + $sql .= "LIMIT {$start}, {$end} "; + + $query = $this->db->query($sql); + + return $query->getResultArray(); + } + + + public function chkExistAptHscp($data) + { + $sql = "SELECT COUNT(*) AS cnt FROM apt_receipt WHERE 1=1 "; + + $sql .= "AND hscp_no = '{$data['hscpNo']}' "; + $sql .= "AND rcpt_no != {$data['rcptNo']} "; + + $query = $this->db->query($sql); + + return $query->getRow()->cnt; + } + + // 단지코드 정보 변경 + public function saveAptHscp($data) + { + $this->db->transStart(); + + $sql = "UPDATE apt_receipt SET "; + $sql .= "hscp_no = {$data['hscpNo']} "; + $sql .= "WHERE rcpt_no = {$data['rcptNo']} "; + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $sql = "UPDATE apt_result SET "; + $sql .= "hscp_no = {$data['hscpNo']} "; + $sql .= "WHERE rcpt_no = {$data['rcptNo']} "; + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $this->db->transComplete(); + + // 성공 + return [ + 'success' => true, + ]; + } + + // 아파트 정보 삭제 + public function deleteAptHscp($data) + { + $this->db->transStart(); + + $sql = "DELETE FROM apt_history WHERE rcpt_no = {$data['rcptNo']} "; + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $sql = "DELETE FROM apt_category WHERE rcpt_no = {$data['rcptNo']} "; + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $sql = "DELETE FROM apt_photo WHERE rcpt_no = {$data['rcptNo']} "; + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $sql = "DELETE FROM apt_result WHERE rcpt_no = {$data['rcptNo']} "; + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $sql = "DELETE FROM apt_receipt WHERE rcpt_no = {$data['rcptNo']} "; + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $this->db->transComplete(); + + // 성공 + return [ + 'success' => true, + ]; + } + +} \ No newline at end of file diff --git a/app/Models/article/GroundModel.php b/app/Models/article/GroundModel.php new file mode 100644 index 0000000..790533f --- /dev/null +++ b/app/Models/article/GroundModel.php @@ -0,0 +1,964 @@ +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 saveExcelUploadData($params) + { + $this->db->transStart(); + + $builder = $this->db->table('apt_ground'); + $res = $builder->insert($params); + + if ($res === false) { + return [ + 'success' => false, + 'msg' => "구분코드 : {$params['part_no']} 저장실패", + ]; + } + + $rcpt_no = $this->db->insertID(); + + $this->saveHistory($rcpt_no, $params['apt_step'], 'U', 'U1', session('usr_id')); + + $this->db->transComplete(); + + // 성공 + return [ + 'success' => true, + ]; + } + + // 엑셀 다운로드 + 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 getDetail($rcpt_no, $hscp_no) + { + $sql = "SELECT + a.rcpt_no, a.hscp_no, a.part_no, a.addr, a.addr2, a.rcpt_hscp_nm, a.move_ym, a.households_cnt, a.dong_cnt, a.pyeong_cnt, a.apt_cate_nm, a.region_cd, a.rcpt_x, a.rcpt_y + ,a.vdo_up_tm, DATE_FORMAT(a.vdo_up_tm, '%Y-%m-%d') as rdate_dt_vdo ,DATE_FORMAT(a.vdo_up_tm, '%H:%i:%s') as rdate_tm_vdo + ,a.check_tm, DATE_FORMAT(a.check_tm, '%Y-%m-%d') as rdate_dt_chk ,DATE_FORMAT(a.check_tm, '%H:%i:%s') as rdate_tm_chk + ,a.memo, a.note, a.video_target, a.vdo_up_ynx, a.not_vdo_reson, a.apt_step, a.check_yn, a.resend_yn, a.write_complete_yn, a.all_no_pho + ,a.write_complete_tm, DATE_FORMAT(a.write_complete_tm, '%Y-%m-%d') as rdate_dt_cmpl ,DATE_FORMAT(a.write_complete_tm, '%H:%i:%s') as rdate_tm_cmpl + ,a.charger, a.dept_sq ,(SELECT pdept_sq FROM departments WHERE dept_sq = a.dept_sq) bonbu + ,a.send_end_tm, a.supply_no_tm + ,d.pho_cate2, d.pho_explain, d.pho_up_nu + ,gp.pho_no ,gp.filenm_up, gp.file_path, gp.thumb_nm, gp.cloud_upload_yn, gp.insert_tm + FROM + apt_ground a + LEFT JOIN apt_category d ON a.rcpt_no = d.rcpt_no + LEFT JOIN apt_ground_photo 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) AND gp.use_yn = 'Y' + + WHERE a.rcpt_no = {$rcpt_no} "; + + if (!empty($hscp_no)) { + $sql .= "AND a.hscp_no = {$hscp_no} "; + } + + + $query = $this->db->query($sql, [$rcpt_no]); + + return $query->getRowArray(); + } + + // 동일단지 + public function getDetailLists($rcpt_no, $hscp_no) + { + $sql = "SELECT + a.rcpt_no, a.hscp_no, a.part_no, a.addr, a.addr2, a.rcpt_hscp_nm, a.move_ym, a.households_cnt, a.dong_cnt, a.pyeong_cnt, a.apt_cate_nm, a.region_cd, a.rcpt_x, a.rcpt_y + ,a.vdo_up_tm, DATE_FORMAT(a.vdo_up_tm, '%Y-%m-%d') as rdate_dt_vdo ,DATE_FORMAT(a.vdo_up_tm, '%H:%i:%s') as rdate_tm_vdo + ,a.check_tm, DATE_FORMAT(a.check_tm, '%Y-%m-%d') as rdate_dt_chk ,DATE_FORMAT(a.check_tm, '%H:%i:%s') as rdate_tm_chk + ,a.memo, a.note, a.video_target, a.vdo_up_ynx, a.not_vdo_reson, a.apt_step, a.check_yn, a.resend_yn, a.write_complete_yn, a.all_no_pho + ,a.write_complete_tm, DATE_FORMAT(a.write_complete_tm, '%Y-%m-%d') as rdate_dt_cmpl ,DATE_FORMAT(a.write_complete_tm, '%H:%i:%s') as rdate_tm_cmpl + ,a.charger, a.dept_sq ,(SELECT pdept_sq FROM departments WHERE dept_sq = a.dept_sq) bonbu, b.usr_nm, i.dept_nm + ,a.send_end_tm, a.supply_no_tm + ,d.pho_cate2, d.pho_explain, d.pho_up_nu + ,gp.pho_no, gp.filenm ,gp.filenm_up, gp.file_path, gp.thumb_nm, gp.cloud_upload_yn, gp.insert_tm + FROM + apt_ground a + LEFT JOIN apt_category d ON a.rcpt_no = d.rcpt_no + LEFT JOIN apt_ground_photo 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) AND gp.use_yn = 'Y' + LEFT JOIN users b ON a.charger = b.usr_id + LEFT JOIN departments i ON a.dept_sq = i.dept_sq + WHERE a.rcpt_no = {$rcpt_no} AND a.hscp_no != {$hscp_no} "; + + + $query = $this->db->query($sql); + + return $query->getResultArray(); + } + + // 정보변경이력 + public function getHistory($rcpt_no) + { + $sql = " SELECT seq," . + " rcpt_no, " . + " apt_step, get_code_name('APT_GROUND_STEP',apt_step) AS apt_step_nm, " . + " changed_type, get_code_name('APT_GROUND_CHANGED_TYPE',changed_type) AS changed_type_nm, " . + " changed_detail, get_code_name('APT_GROUND_CHANGED_DETAIL',changed_detail) AS changed_detail_nm, " . + " charged_id, " . + " changed_tm, DATE_FORMAT(changed_tm, '%Y-%m-%d') as rdate_dt, DATE_FORMAT(changed_tm, '%H:%i:%s') as rdate_tm" . + " FROM apt_ground_history" . + " WHERE rcpt_no = ?" . + " ORDER BY changed_tm DESC"; + + + + $query = $this->db->query($sql, [$rcpt_no]); + + return $query->getResultArray(); + } + + // 메모저장 + public function saveMemo($data) + { + $sql = "UPDATE apt_ground SET + memo = '{$data['memo']}' + WHERE rcpt_no = {$data['rcpt_no']} + "; + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + + $row = $this->getDetail($data['rcpt_no'], ""); + $this->saveHistory($data['rcpt_no'], $row['apt_step'], 'C', 'A1', session('usr_id')); + + return [ + 'success' => true, + ]; + + } + + // 담당자 변경 + public function saveKeeper($data) + { + $sql = "UPDATE apt_ground SET + dept_sq = {$data['team']}, charger = '{$data['user']}' + WHERE rcpt_no = {$data['rcpt_no']} + "; + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $row = $this->getDetail($data['rcpt_no'], ""); + $this->saveHistory($data['rcpt_no'], $row['apt_step'], 'C', 'A1', session('usr_id')); + + return [ + 'success' => true, + ]; + } + + // 단지상태변경 + public function statusChange($rcpt_no, $type) + { + $this->db->transStart(); + $data = [ + $rcpt_no + ]; + + + if ($type === "phoX") { + $detail = 'C1'; + + + $sql = "UPDATE apt_ground" . + " SET gpho_up_yn = 'N'" . + " ,apt_step = 'S01'" . + " WHERE rcpt_no = ?"; + + + if ($this->db->query($sql, $data) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $sql = "delete from apt_ground_photo" . + " WHERE rcpt_no = ?"; + + $this->db->query($sql, $data); + + + } else if ($type === "phoY") { + $detail = 'C3'; + + $sql = "UPDATE apt_ground" . + " SET gpho_up_yn = 'Y'" . + " ,apt_step = 'S03'" . + " WHERE rcpt_no = ?"; + + if ($this->db->query($sql, $data) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $sql = "UPDATE apt_ground_photo" . + " SET insert_tm = NOW()" . + " WHERE rcpt_no = ?"; + + $this->db->query($sql, $data); + + } else if ($type === "sendE") { + $detail = 'C4'; + + $sql = "UPDATE apt_ground" . + " SET send_end_tm = NOW()" . + " ,supply_no_tm = NULL" . + " ,apt_step = 'S04'" . + " WHERE rcpt_no = ?"; + + if ($this->db->query($sql, $data) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + } else if ($type === "suppN") { + $detail = 'C2'; + + $sql = "UPDATE apt_ground" . + " SET all_no_pho = 'Y'" . + " ,apt_step = 'S02'" . + " ,supply_no_tm = NOW()" . + " ,send_end_tm = NULL" . + " WHERE rcpt_no = ?"; + + if ($this->db->query($sql, $data) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + } + + $row = $this->getDetail($rcpt_no, ""); + $this->saveHistory($rcpt_no, $row['apt_step'], 'E', $detail, session('usr_id')); + + $this->db->transComplete(); + + return [ + 'success' => true, + ]; + + } + + // 단지 특이사항 저장 + public function saveNote($data) + { + $sql = "UPDATE apt_ground SET + note = '{$data['note']}' + WHERE rcpt_no = {$data['rcpt_no']} + "; + + if ($this->db->query($sql) === false) { + return [ + 'success' => false, + 'msg' => '저장실패', + ]; + } + + $row = $this->getDetail($data['rcpt_no'], ""); + $this->saveHistory($data['rcpt_no'], $row['apt_step'], 'C', 'D1', session('usr_id')); + + return [ + 'success' => true, + ]; + } + + // 평면도 정보 저장 + public function saveImg($data) + { + $this->db->transStart(); + + $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' => '저장실패', + ]; + } + + + $sql = "UPDATE apt_ground SET + gpho_up_yn = 'Y', apt_step = 'S03' + WHERE rcpt_no = {$data['rcpt_no']} + "; + + $this->db->query($sql); + + $this->db->transComplete(); + + return [ + 'success' => true, + ]; + } + + + // 이력 저장 + public function saveHistory($rcpt_no, $apt_step, $changed_type, $changed_detail, $charged_id) + { + $sql = "INSERT INTO apt_ground_history" . + " (rcpt_no, apt_step, changed_type, changed_detail, charged_id, changed_tm)" . + " VALUES (?, ?, ?, ?, ?, NOW())"; + $data = [ + $rcpt_no, + $apt_step, + $changed_type, + $changed_detail, + $charged_id + ]; + + + $res = $this->db->query($sql, $data); + } + +} \ No newline at end of file diff --git a/app/Models/common/CodeModel.php b/app/Models/common/CodeModel.php index 9fdcdce..c258b2c 100644 --- a/app/Models/common/CodeModel.php +++ b/app/Models/common/CodeModel.php @@ -32,7 +32,7 @@ class CodeModel extends Model ->getResultArray(); } - public function getCategoryCodeList($category = array(), $useYn = '') + public function getCategoryCodeList($category = [], $useYn = '') { $this->db->select('category, cd, cd_nm, use_yn'); $this->db->from('codes'); diff --git a/app/Views/layouts/sidebar.php b/app/Views/layouts/sidebar.php index 9534dca..a9b6632 100644 --- a/app/Views/layouts/sidebar.php +++ b/app/Views/layouts/sidebar.php @@ -93,6 +93,21 @@ extend('layouts/main') ?> + +section('content') ?> + + +

조직 관리

+ +
+
+
+
+
+ +
+ + +
+ + +
+ +
+ +
+
+
+
+ + +
+
+
조직 관리
+
+ + + + + + + + + + + + + +
순번단지코드단지구역명단지코드변경
+
+ +
+
+
+ + + + + +endSection() ?> \ No newline at end of file diff --git a/app/Views/pages/article/detail.php b/app/Views/pages/article/detail.php index 1486799..e653295 100644 --- a/app/Views/pages/article/detail.php +++ b/app/Views/pages/article/detail.php @@ -42,6 +42,31 @@ background-color: #ff0000 !important; color: #fff !important; } + + .dropzone { + min-height: 260px; + background-color: #fafbfc; + } + + .dropzone:hover { + background-color: #f4f6f8; + } + + #myDropzone { + position: relative; + padding-top: 110px; + /* 메시지 영역 높이만큼 */ + } + + #uploadModal .modal-dialog { + max-width: 1140px; + /* modal-xl */ + } + + #uploadModal .modal-content { + height: 450px; + max-height: 450px; + }

아파트단지 DB구축 상세

@@ -85,12 +110,11 @@
-
-
@@ -116,7 +140,7 @@ 관할본부 - @@ -142,7 +166,7 @@ 담당자 - @@ -155,7 +179,7 @@ - @@ -227,7 +251,7 @@
단지 특이사항
+ style="height: 220px;resize: none;">
@@ -279,10 +303,21 @@ 동영상 - 비디오
- +
+ + + + + 비디오
+ + +
동영상 촬영불가 @@ -352,17 +387,181 @@ 사진 일괄삭제 - + 단지정보 작성완료 - +
+ $val) { + if (empty($val['pho_cate2'])) { + $arrPho[] = $val; + unset($image[$key]); + } + } + + if (!empty($arrPho)): + ?> + +
+
+
+
카테고리 미지정 이미지
+ +
+
+ + +
+ +
+
+ +
+ +
+
+ + <?= esc($fileNm) ?> + + +
+ + +
+
+
+ + + +
+
+ +
+ + +
단지 사진 및 설명 정보
@@ -493,7 +692,7 @@ - + @@ -635,7 +834,7 @@ + style="width:350px;height:90px;resize: none;"> @@ -671,7 +870,7 @@
- -
+ +
+
+
+ 파일을 드래그하거나 클릭해서 추가하세요
+ + 사진 여러 장 가능 / 동영상은 1개만 + +
@@ -773,6 +979,25 @@
+ + endSection() ?> + +
+
+ +
+
+
단지 정보
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
단지코드구분코드
주소지번
단지명평형
단지유형메모 +
+
+ +
+
+ +
+
+
+
+
+ +
+
+
담당자 정보
+ + + + + + + + + + + + + + + + + + + + + + +
관할본부 + + 담당팀 + + 담당자 + + + +
+
+
+ +
+
+
단지 상태 정보
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
상태내역미촬영수급불가촬영전송완료
+ + + + + + + + + + + + + +
상태 변경 + + + + + + + +
+
+
+ +
+
+
단지 위치
+ + + + + + + + + + + + + + + + + +
+
+
+
단지 특이사항
+ + + +
+
+ +
+
+
지도 좌표 수정 +
+ 위도 + + + 경도 + + + +
+
+
+
+ +
+
+
동일 단지 정보
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
진행상태구분코드단지코드주소단지명평형방문팀담당촬영일자업로드미리보기다운로드
동일단지 데이터가 없습니다.
+ + + + + + + + + 다운로드 + +
+
+
+ +
+
+
평면도 정보
+ + + + + + + + + + + +
평면도 + + + 비디오 + + 비디오 + + + + +
+
+
+ +
+
+
정보변경 이력
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
진행상태변경내용처리자(ID)처리일시세부내용
+
+
+
+ +
+
+ + +section('modals') ?> + + + +endSection() ?> + + + + + + + + +endSection() ?> \ No newline at end of file diff --git a/app/Views/pages/article/lists.php b/app/Views/pages/article/lists.php index 9b15d45..7d97a0b 100644 --- a/app/Views/pages/article/lists.php +++ b/app/Views/pages/article/lists.php @@ -44,6 +44,15 @@ background-color: #ff0000 !important; color: #fff !important; } + + #excelList.dataTable { + width: max-content !important; + } + + table.dataTable td, + table.dataTable th { + white-space: nowrap; + }

아파트단지 DB구축 현황

@@ -73,19 +82,6 @@
- -
- - -
- - -
- - -
-
@@ -111,10 +107,24 @@
+ + +
+ + +
+ + +
+ + +
+
-
@@ -160,7 +170,7 @@
- @@ -168,12 +178,12 @@
-
-
@@ -191,37 +201,16 @@ onclick="progressStatAll(this, this.checked);">
- -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
+ + +
+ + +
+ + @@ -307,18 +296,18 @@
- - - @@ -330,7 +319,7 @@ 영상대상 - @@ -345,6 +334,10 @@
+ + @@ -395,6 +388,73 @@
+ + endSection() ?> @@ -409,7 +469,7 @@ const teamArr = ; const userArr = ; - var table; + var table, excelTbl; $(function () { @@ -536,7 +596,7 @@ // 이 팀이 현재 본부에 속한 팀인지 체크 if (String(userArr[i].dept_sq) === String(dept_sq)) { str += ` - + `; } } @@ -653,12 +713,12 @@ } }, "columnDefs": [ - { targets: 0, orderable: false, className: 'text-center' }, + { className: 'text-center', targets: '_all' }, { 'targets': '_all', "defaultContent": "" }, // { 'className': 'text-center', 'targets': [0, 2, 3, 4] }, ], columns: [ - { data: null, render: fn_chk_render, width: "50px" }, + { data: null, render: fn_chk_render, width: "50px", className: "dt-no-rowclick" }, { data: 'apt_step', render: fn_stat_render, width: "80px" }, { data: 'hscp_no', width: "50px" }, @@ -672,9 +732,9 @@ { data: 'usr_nm', width: "50px" }, { data: 'write_complete_yn', width: "50px" }, { data: 'vdo_up_ynx', render: fn_vdo_ynx_render, width: "50px" }, - { data: null, render: fn_select_render, width: "80px" }, - { data: null, render: fn_memo_render, width: "80px" }, - { data: null, render: fn_btn_render, width: "80px" }, + { data: null, render: fn_select_render, width: "80px", className: "dt-no-rowclick" }, + { data: null, render: fn_memo_render, width: "80px", className: "dt-no-rowclick" }, + { data: null, render: fn_btn_render, width: "80px", className: "dt-no-rowclick" }, ], // 옵션들 예시 paging: true, @@ -683,7 +743,9 @@ serverSide: true, }); - $('#resultList tbody').on('click', 'tr', function () { + $('#resultList tbody').on('click', 'tr', function (e) { + if ($(e.target).closest('td.dt-no-rowclick').length) return; + const rowData = table.row(this).data(); if (!rowData) return; @@ -695,6 +757,136 @@ table.ajax.reload() }); + // 엑셀업로드 click + $("#excel-upload").on("click", function () { + $("#excel").val(""); + $("#excelList").DataTable().clear().destroy(); + + $("#excelModal").modal("show"); + + }); + + // 엑셀 업로드 + $("#excel").on("change", async function () { + const file = this.files[0]; + if (!file) return; + + const bodyRows = await readExcelBodyOnly(file); + renderExcelDataTable(bodyRows); + + }); + + // 엑셀 업로드 저장 + $("#btnUpload").on("click", function () { + + const dt = $("#excelList").DataTable(); + + // 전체 row 데이터 (모든 페이지) + const excelData = dt.rows().data().toArray(); + + if (excelData.length === 0) { + Swal.fire({ + title: "업로드할 데이터가 없습니다.", + icon: "warning" + }); + return; + } + + const headers = [ + "줄번호", "단지코드", "통합단지코드", "법정동코드", "주소" + , "상세주소", "단지유형", "단지명" + , "입주년월", "총세대수", "총동수", "평형수", "동호수" + , "사용여부", "경도", "위도", "사진촬영제외" + ]; + + const errors = []; + let hasError = false; + for (let rowIdx = 0; rowIdx < excelData.length; rowIdx++) { + const row = excelData[rowIdx]; + + for (let colIdx = 0; colIdx < headers.length; colIdx++) { + const colName = headers[colIdx]; + const val = row[colIdx]; + + + if (val === undefined || val === null || String(val).trim() === "") { + Swal.fire({ + title: `${rowIdx + 1}행 ${colName} 데이터 누락`, + icon: "warning" + }); + + hasError = true; + break; + } + } + + if (hasError) break; + } + + if (hasError) return; + + swal.fire({ + text: "저장 하시겠습니까?", + type: "warning", + showCancelButton: true, + confirmButtonText: "예", + cancelButtonText: "아니오", + closeOnConfirm: false, + closeOnCancel: true, + confirmButtonColor: "#3085d6", + cancelButtonColor: "#d33", + }).then((result) => { + if (result.isConfirmed) { + $.ajax({ + url: '/article/apt/uploadExcel', + contentType: 'application/json;charset=UTF-8', + method: 'POST', + data: JSON.stringify({ datas: excelData }), + beforeSend: function () { + blockUI.blockPage({ + message: tpl + }) + }, + complete: function () { + blockUI.unblockPage() + }, + error: function (xhr, error, thrown) { + blockUI.unblockPage() + var msg = ""; + if (xhr.responseText != null) { + msg = xhr.responseText + } else { + msg = "잠시후 다시 시도해 주세요." + } + + Swal.fire({ + title: msg, + icon: "error" + }) + }, + success: function (result) { + + if (result.code == '0') { + $("#btnSearch").trigger('click') + $("#excelModal").modal("hide") + Swal.fire({ + title: '정상 처리되었습니다.', + icon: "success" + + }) + } else { + Swal.fire({ + title: result.msg, + icon: "error" + }) + } + } + }); + } + }); + + + }); // 엑셀 다운로드 click $("#excel-download").on("click", function () { @@ -835,7 +1027,7 @@ Swal.fire({ title: msg, icon: "error" - }) + }); }, success: function (result) { @@ -958,6 +1150,48 @@ }); + async function readExcelBodyOnly(file) { + const data = await file.arrayBuffer(); + const wb = XLSX.read(data, { type: "array" }); + const ws = wb.Sheets[wb.SheetNames[0]]; + + const rows2d = XLSX.utils.sheet_to_json(ws, { + header: 1, + defval: "", + raw: false + }); + + // 첫 줄(엑셀 헤더) 제거 + 빈 행 제거 + return rows2d + .slice(1) + .filter(r => r.some(v => String(v).trim() !== "")); + } + + function renderExcelDataTable(data2d) { + // 이미 DataTable이 있으면 파괴 후 재생성(컬럼 구조가 바뀔 수 있으니) + if ($.fn.DataTable.isDataTable("#excelList")) { + $("#excelList").DataTable().clear().destroy(); + } + + excelTbl = $("#excelList").DataTable({ + language: lang_kor, + columnDefs: [ + { className: 'text-center dt-nowrap', targets: '_all' }, + ], + data: data2d, + searching: false, + ordering: false, + destroy: true, + deferRender: true, + pageLength: 10, + lengthMenu: [10, 25, 50, 100], + scrollX: true, + autoWidth: true, + }); + } + + + function hscp_no_enter(event) { if (event.keyCode == 13) { table.ajax.reload() @@ -1023,7 +1257,7 @@ const video = extractCode('VIDEO_TARGET'); const rowIndex = meta.row; - var str = ``; str += ``; for (var i = 0; i < video.length; i++) { if (video[i].cd == row.video_target) { @@ -1073,10 +1307,6 @@ // 단지정보저장 function fn_save_info(row, idx) { - console.log('+++') - console.log(row) - console.log('idx ?? ' + idx) - console.log('+++') const target = $("#video_target_" + idx).val(); console.log(target) diff --git a/app/Views/pages/article/lists2.php b/app/Views/pages/article/lists2.php new file mode 100644 index 0000000..3b6655b --- /dev/null +++ b/app/Views/pages/article/lists2.php @@ -0,0 +1,1544 @@ +extend('layouts/main') ?> + +section('content') ?> + + +

아파트 평면도 내역

+ +
+
+
+ +
+
+
+ + + + + +
+
+ +
+ + 단지코드/구분코드를 입력하면 다른 조건은 무시됩니다. + +
+ +
+ + +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+
+ +
+ +
+ + ~ + +
+
+ + +
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+
+ + +
+ + +
+ + +
+ + +
+
+ +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + +
+ + 관할본부방문담당배정건수
+
+
+ + +
+
+ +
+
+
+
+ + + + + + + + +
방문담당배정건수
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+ + + + + + + + +
+ +
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+ + 진행상태구분코드단지코드주소단지명평형방문팀담당업로드미리보기다운로드
+
+
+
+ + +section('modals') ?> + + + + + + + +endSection() ?> + + + + + + + + +endSection() ?> \ No newline at end of file diff --git a/public/plugin/sample/sample.xlsx b/public/plugin/sample/sample.xlsx new file mode 100644 index 0000000..5152b00 Binary files /dev/null and b/public/plugin/sample/sample.xlsx differ diff --git a/public/plugin/sample/sample_apt.xlsx b/public/plugin/sample/sample_apt.xlsx new file mode 100644 index 0000000..47c97fc Binary files /dev/null and b/public/plugin/sample/sample_apt.xlsx differ diff --git a/public/plugin/sample/sample_apt_ground.xlsx b/public/plugin/sample/sample_apt_ground.xlsx new file mode 100644 index 0000000..e44fed7 Binary files /dev/null and b/public/plugin/sample/sample_apt_ground.xlsx differ