diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 1d9d655..5f8143e 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') ?>
+
+= $this->section('content') ?>
+
+
+
조직 관리
+
+
+
+
+
+
+
+
+
+
+
+
+ | 순번 |
+ 단지코드 |
+ 단지구역명 |
+ 단지코드변경 |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+= $this->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 @@
|
| 관할본부 |
- |
@@ -227,7 +251,7 @@
단지 특이사항
+ style="height: 220px;resize: none;">= esc($apt['note'] ?? '') ?>
@@ -279,10 +303,21 @@
| 동영상 |
- 
-
+
+
+
+
+
+ 
+
+
+
|
동영상 촬영불가 |
@@ -352,17 +387,181 @@
|
사진 일괄삭제 |
-
+
|
단지정보 작성완료 |
-
+
|
+ $val) {
+ if (empty($val['pho_cate2'])) {
+ $arrPho[] = $val;
+ unset($image[$key]);
+ }
+ }
+
+ if (!empty($arrPho)):
+ ?>
+
+
+
+
+
카테고리 미지정 이미지
+
+
+
+
+
+
+
= count($arrPho) ?>건
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
단지 사진 및 설명 정보
@@ -493,7 +692,7 @@
-
+
|
@@ -635,7 +834,7 @@
+ style="width:350px;height:90px;resize: none;">= esc($phoExplain) ?>
@@ -671,7 +870,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -111,10 +107,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -160,7 +170,7 @@
-
+
-본부-
= $d['dept_nm'] ?>
@@ -168,12 +178,12 @@
-
+
-팀-
-
+
-담당자-
@@ -191,37 +201,16 @@
onclick="progressStatAll(this, this.checked);">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -307,18 +296,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 엑셀 첫 행은 헤더로 인식됩니다.
+ - 컬럼 순서 및 개수는 샘플양식과 동일해야 합니다.
+
+
+
+
+
+
+
+
+ | 줄번호 |
+ 단지코드 |
+ 통합단지코드 |
+ 법정동코드 |
+ 주소 |
+ 상세주소 |
+ 단지유형 |
+ 단지명 |
+ 입주년월 |
+ 총세대수 |
+ 총동수 |
+ 평형수 |
+ 동호수 |
+ 사용여부 |
+ 경도 |
+ 위도 |
+ 사진촬영제외 |
+
+
+
+
+
+
+
+
+
+
+
= $this->endSection() ?>
@@ -409,7 +469,7 @@
const teamArr = = json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
const userArr = = json_encode($user, JSON_UNESCAPED_UNICODE); ?>;
- var table;
+ var table, excelTbl;
$(function () {
@@ -536,7 +596,7 @@
// 이 팀이 현재 본부에 속한 팀인지 체크
if (String(userArr[i].dept_sq) === String(dept_sq)) {
str += `
- ${userArr[i].usr_nm}
+ ${userArr[i].usr_nm}
`;
}
}
@@ -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 = ``;
+ 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 @@
+= $this->extend('layouts/main') ?>
+
+= $this->section('content') ?>
+
+
+아파트 평면도 내역
+
+
+
+
+
+
+= $this->section('modals') ?>
+
+
+
+
+
+
+
+
+
+ ![미리보기]()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 엑셀 첫 행은 헤더로 인식됩니다.
+ - 컬럼 순서 및 개수는 샘플양식과 동일해야 합니다.
+
+
+
+
+
+
+
+
+ | 구분코드 |
+ 단지코드 |
+ 법정동코드 |
+ 시/도 |
+ 시/군/구 |
+ 읍/면/동 |
+ 상세주소 |
+ 단지명 |
+ 구분명 |
+ 평수 |
+ 총동수 |
+ 경도 |
+ 위도 |
+
+
+
+
+
+
+
+
+
+
+
+= $this->endSection() ?>
+
+
+
+
+
+
+
+
+= $this->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
|