Merge pull request 'merge' (#4) from feature/template into master

Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/4
This commit was merged in pull request #4.
This commit is contained in:
2025-12-23 08:45:26 +00:00
35 changed files with 7025 additions and 83 deletions

View File

@@ -77,3 +77,13 @@ defined('EXIT_USER_INPUT') || define('EXIT_USER_INPUT', 7); // invalid u
defined('EXIT_DATABASE') || define('EXIT_DATABASE', 8); // database error defined('EXIT_DATABASE') || define('EXIT_DATABASE', 8); // database error
defined('EXIT__AUTO_MIN') || define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code defined('EXIT__AUTO_MIN') || define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code
defined('EXIT__AUTO_MAX') || define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code defined('EXIT__AUTO_MAX') || define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code
/**
* ncloud url
*/
define('NCLOUD_OBJECT_STORAGE_URL', 'https://kr.object.ncloudstorage.com/confirms-object');
define('NCLOUD_S3_KEY', 'ncp_iam_BPAMKR3l50hXJiQ6qpSP');
define('NCLOUD_S3_SECRET', 'ncp_iam_BPKMKRW2GU59UE59I1QftVGst6NJgnmbSc');
define('NCLOUD_S3_BUCKET', 'confirms-object');
define('NCLOUD_S3_ENDPOINT', 'https://kr.object.ncloudstorage.com');

View File

@@ -43,6 +43,44 @@ $routes->group('board', ['namespace' => 'App\Controllers\Board'], function ($rou
}); });
/**
* 아파트단지 DB구축 그룹
*/
$routes->group('article', ['namespace' => 'App\Controllers\Article'], function ($routes) {
// 아파트단지DB구축현황
$routes->get('apt/lists', 'Apt::lists');
$routes->get('apt/detail/(:num)', 'Apt::detail/$1');
// 관할포인트 인쇄
$routes->get('apt/print', 'Apt::print');
/** API - 아파트단지 */
$routes->get('apt/getAptLists', 'Apt::getAptLists');
$routes->post('apt/saveAptMemo', 'Apt::saveAptMemo');
$routes->post('apt/chgAptDamdang', 'Apt::chgAptDamdang');
$routes->post('apt/chgAptVideoTarget', 'Apt::chgAptVideoTarget');
$routes->post('apt/chkTakeAptPhotoCnt', 'Apt::chkTakeAptPhotoCnt');
$routes->get('apt/excel', 'Apt::excel');
/** API - 아파트단지 상세 */
$routes->post('apt/saveKeeper', 'Apt::saveKeeper');
$routes->post('apt/saveCoordinate', 'Apt::saveCoordinate');
$routes->post('apt/saveNote', 'Apt::saveNote');
$routes->post('apt/saveVideoTarget', 'Apt::saveVideoTarget');
$routes->post('apt/saveVideoReason', 'Apt::saveVideoReason');
$routes->get('apt/cateJson', 'Apt::cateJson');
$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/confirmAptInfo', 'Apt::confirmAptInfo');
$routes->post('apt/resendAptInfo', 'Apt::resendAptInfo');
$routes->post('apt/uploadFile', 'Apt::uploadFile');
});
/** /**
* 실적관리 (results) 그룹 * 실적관리 (results) 그룹
*/ */

View File

@@ -0,0 +1,995 @@
<?php
namespace App\Controllers\article;
use App\Controllers\article\Exception;
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
{
private $aptModel, $codeModel;
public function __construct()
{
$this->aptModel = new AptModel();
$this->codeModel = new CodeModel();
}
// 아파트단지
public function lists(): string
{
$codes = $this->codeModel->getCodeLists(['VIDEO_TARGET', 'APT_STEP', 'PHO_YN', 'VDO_YN']); // 코드조회
$sido = $this->aptModel->getAreaList(); // 지역조회
$bonbu = $this->aptModel->getBonbuList(); // 본부
$team = $this->aptModel->getTeamList(); // 팀
$user = $this->aptModel->getUserList(); // 유저
return view("pages/article/lists", [
'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'), // 단지코드
'pho_no' => $this->request->getGet('pho_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'), // 종료일
'households_cnt1' => $this->request->getGet('households_cnt1'), // 총세대수1
'households_cnt2' => $this->request->getGet('households_cnt2'), // 총세대수2
'dong_cnt1' => $this->request->getGet('dong_cnt1'), // 총동수1
'dong_cnt2' => $this->request->getGet('dong_cnt2'), // 총동수2
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'stat' => $this->request->getGet('stat'), // 진행상태
];
$totalCount = $this->aptModel->getTotalCount($data);
$datas = $this->aptModel->getAptLists($start, $end, $data);
$deptStatistics = $this->aptModel->getDeptStatistics($data); // 조직별통계
$areaStatistics = $this->aptModel->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 chkTakeAptPhotoCnt()
{
$data = $this->aptModel->chkTakeAptPhotoCnt();
return $this->response->setJSON(
body:
$data
);
}
// 관할포인트 인쇄 - 화면
public function print(): string
{
$deptSq = $this->request->getGet('depChk');
$dept_cnt = count($deptSq);
$listDept = $this->aptModel->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 saveAptMemo()
{
try {
$rcpt_no = $this->request->getPost('rcpt_no');
$video_target = $this->request->getPost('video_target');
if (empty($rcpt_no)) {
throw new Exception("단지정보 누락");
}
$params = [
'target' => $video_target,
'memo' => $this->request->getPost('memo') ?: '',
'rcpt_no' => $rcpt_no,
];
// UPDATE apt_result
$this->aptModel->saveAptMemo($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 담당자정보변경
public function chgAptDamdang()
{
try {
$team = $this->request->getPost('team');
$damdang = $this->request->getPost(index: 'damdang');
if (empty($team)) {
throw new Exception("팀정보 누락");
}
if (empty($damdang)) {
throw new Exception("담당자정보 누락");
}
$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->aptModel->updateAptDamdang($params);
}
} else {
throw new Exception("저장할 데이터 누락");
}
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 영상담당 정보 저장
public function chgAptVideoTarget()
{
try {
$target = $this->request->getPost('video');
if (empty($target)) {
throw new Exception("영상대상 정보 누락");
}
$rows = $this->request->getPost('rows');
$rows = json_decode($rows, true);
if (count($rows) > 0) {
foreach ($rows as $row) {
$params = [
'target' => $target,
'apt_step' => $row['apt_step'],
'rcpt_no' => $row['rcpt_no'],
'usr_id' => session('usr_id'),
];
// UPDATE apt_result
$this->aptModel->updateAptVideoTarget($params);
}
} else {
throw new Exception("저장할 데이터 누락");
}
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'), // 단지코드
'pho_no' => $this->request->getGet('pho_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'), // 종료일
'households_cnt1' => $this->request->getGet('households_cnt1'), // 총세대수1
'households_cnt2' => $this->request->getGet('households_cnt2'), // 총세대수2
'dong_cnt1' => $this->request->getGet('dong_cnt1'), // 총동수1
'dong_cnt2' => $this->request->getGet('dong_cnt2'), // 총동수2
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'stat' => $this->request->getGet('stat'), // 진행상태
];
$datas = $this->aptModel->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 아파트단지 상세화면
public function detail($id = null): string
{
$rcpt_no = (int) $id;
if ($rcpt_no == null) {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
}
$bonbu = $this->aptModel->getBonbuList();
$team = $this->aptModel->getTeamList();
$user = $this->aptModel->getUserList();
$codes = $this->codeModel->getCodeLists(['VIDEO_TARGET', 'PHO_CATE1', 'PHO_CATE2']); // 코드조회
$apt = $this->aptModel->getDetail($rcpt_no);
//이미지 리스트
$image = $this->aptModel->getImgList($rcpt_no);
//이미지 총 개수
$cntAllPho = $this->aptModel->cntAllPho($rcpt_no);
if (empty($cntAllPho)) {
$cntAllPho = 0;
}
//동영상 리스트
$vdo = $this->aptModel->getVideoList($rcpt_no);
//사진및 설명정보의 카테고리 리스트
$cateInfo = $this->aptModel->getCateInfoList($rcpt_no);
//정보변경이력
$history = $this->aptModel->getHistory($rcpt_no);
$code1 = [];
$code2 = [];
$video = [];
if (!empty($codes)) {
foreach ($codes as $code) {
if ($code['category'] === "PHO_CATE1") {
array_push($code1, $code);
} else if ($code['category'] === "PHO_CATE2") {
array_push($code2, $code);
} else if ($code['category'] === "VIDEO_TARGET") {
array_push($video, $code);
}
}
}
// return print_r($image);
return view("pages/article/detail", [
'apt' => $apt,
'bonbu' => $bonbu,
'team' => $team,
'user' => $user,
'code1' => $code1,
'code2' => $code2,
'video' => $video,
'image' => $image,
'vdo' => $vdo,
'history' => $history,
'cateInfo' => $cateInfo,
'cntAllPho' => $cntAllPho
]);
}
public function cateJson()
{
$params = [
$this->request->getGet('pho_cate1'),
];
$datas = $this->aptModel->getCateJson($params);
return $this->response->setJSON($datas);
}
// 담당자 정보 저장
public function saveKeeper()
{
try {
$params = [
'rcpt_no' => $this->request->getPost('rcpt_no'),
'bonbu' => $this->request->getPost('bonbu'),
'team' => $this->request->getPost('team'),
'user' => $this->request->getPost('user'),
];
// UPDATE apt_result
$this->aptModel->saveKeeper($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 지도좌표 수정
public function saveCoordinate()
{
try {
$params = [
'rcpt_no' => $this->request->getPost('rcpt_no'),
'rcpt_x' => $this->request->getPost('rcpt_x'),
'rcpt_y' => $this->request->getPost('rcpt_y'),
];
// UPDATE apt_receipt, apt_result
$this->aptModel->saveCoordinate($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 단지 특이사항 저장
public function saveNote()
{
try {
$params = [
'rcpt_no' => $this->request->getPost('rcpt_no'),
'note' => $this->request->getPost('note'),
];
// UPDATE apt_result
$this->aptModel->saveNote($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 동영상 촬영정보 저장
public function saveVideoTarget()
{
try {
$params = [
'rcpt_no' => $this->request->getPost('rcpt_no'),
'target' => $this->request->getPost('video_target'),
];
// UPDATE apt_result
$this->aptModel->saveVideoTarget($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 촬영불가사유 저장
public function saveVideoReason()
{
try {
$params = [
'rcpt_no' => $this->request->getPost('rcpt_no'),
'not_vdo_reson' => $this->request->getPost('not_vdo_reson'),
'vdo_up_ynx' => $this->request->getPost('vdo_up_ynx'),
];
// UPDATE apt_result
$this->aptModel->saveVideoReason($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 사진업로드 불가사유 저장
public function savePhoReason()
{
try {
$params = [
'rcpt_no' => $this->request->getPost('rcpt_no'),
'pho_cate2' => $this->request->getPost('pho_cate2'),
'pho_up_nu' => $this->request->getPost('pho_up_nu'),
'usr_id' => session('usr_id'),
];
// UPDATE apt_category
$this->aptModel->savePhoReason($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 사진 카테고리 수정
public function saveCate()
{
try {
$phoNo = $this->request->getPost('pho_no');
if (!is_array($phoNo)) {
$phoNo = [$phoNo];
}
$params = [
'pho_no' => $phoNo,
'pho_cate1' => $this->request->getPost('pho_cate1'),
'pho_cate2' => $this->request->getPost('pho_cate2'),
'rcpt_no' => $this->request->getPost('rcpt_no'),
'now_cate' => $this->request->getPost('nowCate2'),
];
$this->aptModel->saveCate($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 사진 노출정보 저장
public function savePhotoView()
{
try {
$phoNo = $this->request->getPost('pho_no');
if (!is_array($phoNo)) {
$phoNo = [$phoNo];
}
$pho_cate2 = $this->request->getPost('pho_cate2');
$params = [
'pho_no' => $phoNo,
'pho_view_yn' => $this->request->getPost('pho_view_yn_' . $pho_cate2),
'rcpt_no' => $this->request->getPost('rcpt_no'),
];
$this->aptModel->savePhotoView($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 사진정보삭제
public function removePhoto()
{
try {
$phoNo = $this->request->getPost('pho_no');
if (!is_array($phoNo)) {
$phoNo = [$phoNo];
}
$pho_cate2 = $this->request->getPost('pho_cate2');
$params = [
'pho_no' => $phoNo,
'rcpt_no' => $this->request->getPost('rcpt_no'),
'cate2_cd' => $this->request->getPost('cate2_cd'),
];
$this->aptModel->removePhoto($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 사진설명 저장
public function savePhoExplain()
{
try {
$params = [
'rcpt_no' => $this->request->getPost('rcpt_no'),
'pho_cate2' => $this->request->getPost('pho_cate2'),
'pho_explain' => session('pho_explain'),
'usr_id' => session('usr_id'),
];
$this->aptModel->savePhoExplain($params);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 검수완료 저장
public function confirmAptInfo()
{
try {
$rcpt_no = $this->request->getPost('rcpt_no');
$hscp_no = $this->request->getPost('hscp_no');
$params = [
'rcpt_no' => $rcpt_no,
'hscp_no' => $hscp_no,
];
$apiData = $this->aptModel->new_api_photo_send_data($rcpt_no);
$ip_addr = array(
'172.16.100.2',
'172.16.100.3',
'172.16.100.4',
'172.16.100.5'
);
if (
isset($_SERVER['HTTPS']) &&
($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'
) {
$protocol = 'https://';
} else {
$protocol = 'http://';
}
if (in_array($_SERVER['SERVER_ADDR'], $ip_addr) == false) {
$domain = $protocol . $_SERVER['HTTP_HOST'];
// $domain = $protocol . 'test-admin.confirms.co.kr';
} else {
$domain = $protocol . 'admin.confirms.co.kr';
}
foreach ($apiData as $key => $d) {
$isExposed = ($d['use_yn'] == 'Y' ? true : false);
$array[] = array('mainCategory' => $d['cate1_cd'], 'subCategory' => $d['cate2_cd'], 'comment' => $d['pho_explain']);
$array1[] = array(
'photoNumber' => $d['pho_no'],
'mainCategory' => $d['cate1_cd'],
'subCategory' => $d['cate2_cd'],
'lat' => $d['pho_lati'],
'lng' => $d['pho_long'],
'url' => $d['url'],
'isExposed' => $isExposed,
'order' => 1
);
}
$serializedArray = array_map('serialize', $array);
$uniqueArray = array_unique($serializedArray);
$post_data_array['categories'] = array_map('unserialize', array_values($uniqueArray));
$post_data_array['photos'] = $array1;
$send_post_data = json_encode($post_data_array, JSON_UNESCAPED_UNICODE);
/**API시작**/
$result = $this->syncRequestListNew($hscp_no, $send_post_data);
/**API끝**/
if ($result['code'] == 'success') {
$syncId = '';
$this->aptModel->saveCheck($rcpt_no, $syncId);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} else {
return $this->response->setJSON([
'code' => '9',
'msg' => '저장실패'
]);
}
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 재전송
public function resendAptInfo()
{
try {
$rcpt_no = $this->request->getPost('rcpt_no');
$hscp_no = $this->request->getPost('hscp_no');
$params = [
'rcpt_no' => $rcpt_no,
'hscp_no' => $hscp_no,
];
$apiData = $this->aptModel->new_api_photo_send_data($rcpt_no);
$ip_addr = array(
'172.16.100.2',
'172.16.100.3',
'172.16.100.4',
'172.16.100.5'
);
if (
isset($_SERVER['HTTPS']) &&
($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'
) {
$protocol = 'https://';
} else {
$protocol = 'http://';
}
if (in_array($_SERVER['SERVER_ADDR'], $ip_addr) == false) {
$domain = $protocol . $_SERVER['HTTP_HOST'];
// $domain = $protocol . 'test-admin.confirms.co.kr';
} else {
$domain = $protocol . 'admin.confirms.co.kr';
}
foreach ($apiData as $key => $d) {
$isExposed = ($d['use_yn'] == 'Y' ? true : false);
$array[] = array('mainCategory' => $d['cate1_cd'], 'subCategory' => $d['cate2_cd'], 'comment' => $d['pho_explain']);
$array1[] = array(
'photoNumber' => $d['pho_no'],
'mainCategory' => $d['cate1_cd'],
'subCategory' => $d['cate2_cd'],
'lat' => $d['pho_lati'],
'lng' => $d['pho_long'],
'url' => $d['url'],
'isExposed' => $isExposed,
'order' => 1
);
}
$serializedArray = array_map('serialize', $array);
$uniqueArray = array_unique($serializedArray);
$post_data_array['categories'] = array_map('unserialize', array_values($uniqueArray));
$post_data_array['photos'] = $array1;
$send_post_data = json_encode($post_data_array, JSON_UNESCAPED_UNICODE);
log_message('debug', 'APT_SEND rcpt_no:::::::' . $rcpt_no . ':::::::' . $send_post_data);
// $send_post_data = to_han( json_encode( $post_data_array) );
/**API시작**/
$result = $this->syncRequestListNew($hscp_no, $send_post_data);
/**API끝**/
if ($result['code'] == 'success') {
$syncId = '';
$this->aptModel->saveResend($rcpt_no, $syncId);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} else {
return $this->response->setJSON([
'code' => '9',
'msg' => '저장실패'
]);
}
} 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');
$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;
if (!isset($files['files'])) {
return $this->response->setJSON([
'success' => false,
'msg' => '파일 없음'
]);
}
if ($uploadType === "photo") {
// foreach ($files['files'] as $file) {
// if ($file->isValid()) {
// $file->move(WRITEPATH . 'uploads');
// INSERT apt_photo
print_r($_FILES);
// }
// $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();
// }
} else if ($uploadType === "video") {
}
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
/**
* 동기화요청 API
*/
public function syncRequestListNew($hscp_no, $postData)
{
$addr = $this->apt_model->getSyncAddr();
$key = $addr['api_key'];
$server = $addr['api_server'];
$secret = $addr['api_secret'];
$urlString = $server . "/kiso/confirms/complex/" . $hscp_no . "/photo";
$postData = str_replace("\\/", '/', $postData);
$headers = array();
$headers[] = 'x-naver-client-id: ' . $key;
if (!empty($secret)) {
$headers[] = 'x-naver-client-secret: ' . $secret;
}
$headers[] = 'Accept: application/json';
$headers[] = 'Content-Type: application/json';
// var_dump( $urlString );
// var_dump( $headers );
log_message('debug', ' syncRequestListNew => url =>' . $urlString . '===============postData =>' . $postData);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $urlString,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => $headers,
));
$response = curl_exec($curl);
$info = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
$result = json_decode($response, TRUE);
log_message('debug', ' syncRequestListNew => url =>' . $urlString . '===============returnData =>' . $response . '====http_code===' . $info);
// if ( $info == "200" ) {
if (isset($result) && $result['code'] == 'success') {
return $result;
} else {
return array('code' => 'fail', 'message' => '전송실패', "timeStamp" => date("Y-m-dTH:i:s"));
}
// $jsonArray = json_decode($response, TRUE);
// if ($response === false || $info['http_code'] != 200){
// $return = "false";
// }else{
// $jsonArray = json_decode($response, TRUE);
// if ($jsonArray['code'] == "success"){
// // $return = $jsonArray['syncList'];
// $return = "true";
// }else{
// $return = "false";
// }
// }
// return $return;
}
}

477
app/Libraries/MyUpload.php Normal file
View File

@@ -0,0 +1,477 @@
<?php
namespace App\Libraries;
use Aws\S3\S3Client;
class MyUpload
{
// ===== CI3 Upload 유사 설정값 =====
public string $upload_path = '';
public string $allowed_types = '*'; // 'jpg|png|gif|pdf' 형태
public int $max_size = 0; // KB 단위(0이면 무제한)
public int $max_filename = 0;
public bool $overwrite = false;
public bool $remove_spaces = true;
public bool $xss_clean = false; // CI3의 file XSS 검사와 완전 동일하진 않음(아래 설명)
public string $_file_name_override = '';
// ===== 업로드 결과값(CI3 유사) =====
public string $file_temp = '';
public int $file_size = 0;
public string $file_type = '';
public string $file_name = '';
public string $file_ext = '';
public string $client_name = '';
public string $orig_name = '';
public int $image_width = 0;
public int $image_height = 0;
public string $image_type = '';
public int $image_size_str = 0;
protected array $errors = [];
protected array $s3_data = [];
public function __construct(array $config = [])
{
if ($config)
$this->initialize($config);
}
public function initialize(array $config): self
{
foreach ($config as $k => $v) {
if (property_exists($this, $k)) {
$this->{$k} = $v;
}
}
return $this;
}
// CI3 스타일: do_upload()
public function do_upload(string $field = 'userfile'): bool
{
$request = service('request');
$file = $request->getFile($field);
if (!$file) {
$this->set_error('upload_no_file_selected');
return false;
}
if (!$file->isValid()) {
// CI3의 $_FILES 에러코드 대응(가까운 메시지로 매핑)
$err = $file->getError();
switch ($err) {
case UPLOAD_ERR_INI_SIZE:
$this->set_error('upload_file_exceeds_limit');
break;
case UPLOAD_ERR_FORM_SIZE:
$this->set_error('upload_file_exceeds_form_limit');
break;
case UPLOAD_ERR_PARTIAL:
$this->set_error('upload_file_partial');
break;
case UPLOAD_ERR_NO_FILE:
$this->set_error('upload_no_file_selected');
break;
case UPLOAD_ERR_NO_TMP_DIR:
$this->set_error('upload_no_temp_directory');
break;
case UPLOAD_ERR_CANT_WRITE:
$this->set_error('upload_unable_to_write_file');
break;
case UPLOAD_ERR_EXTENSION:
$this->set_error('upload_stopped_by_extension');
break;
default:
$this->set_error('upload_no_file_selected');
break;
}
return false;
}
// upload_path가 비어있으면 CI3도 실패함
if (!$this->upload_path) {
$this->set_error('upload_no_file_selected');
return false;
}
// (너가 올린 코드처럼) 디렉토리 생성
$this->make_dirs($this->upload_path);
// temp file / client file name
$this->file_temp = $file->getTempName();
$this->client_name = $file->getClientName();
// file size (bytes)
$this->file_size = (int) $file->getSize(); // bytes
// mime / type
$this->file_type = strtolower((string) $file->getClientMimeType());
$this->file_name = $this->_prep_filename($this->client_name);
$this->file_ext = $this->get_extension($this->file_name);
// CI3처럼 override 처리
if ($this->_file_name_override !== '') {
$this->file_name = $this->_prep_filename($this->_file_name_override);
if (strpos($this->_file_name_override, '.') === false) {
$this->file_name .= $this->file_ext;
} else {
$this->file_ext = $this->get_extension($this->_file_name_override);
}
}
// allowed type 체크
if (!$this->is_allowed_filetype($file->getClientExtension(), $this->file_type)) {
$this->set_error('upload_invalid_filetype');
return false;
}
// max size 체크 (CI3는 KB 기반)
if (!$this->is_allowed_filesize($this->file_size)) {
$this->set_error('upload_invalid_filesize');
return false;
}
// 파일명 정리/길이 제한/공백 제거
$this->file_name = $this->clean_file_name($this->file_name);
if ($this->max_filename > 0) {
$this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
}
if ($this->remove_spaces) {
$this->file_name = preg_replace("/\s+/", "_", $this->file_name);
}
$this->orig_name = $this->file_name;
// overwrite=false면 충돌 시 파일명 변경(CI3 유사)
if (!$this->overwrite) {
$this->file_name = $this->set_filename($this->upload_path, $this->file_name);
if ($this->file_name === false)
return false;
}
// (주의) CI3의 do_xss_clean 완전 동일 구현은 어려움
// 여기서는 위험한 확장자/패턴 정도만 1차 차단 수준으로 처리(원하면 더 강화 가능)
if ($this->xss_clean) {
if (!$this->basic_xss_guard($this->file_name, $this->file_type)) {
$this->set_error('upload_unable_to_write_file');
return false;
}
}
// ===== 너의 기존 로직 핵심: 로컬 move 대신 S3 업로드 =====
$destKeyLikeCi3 = $this->upload_path . $this->file_name;
if (!$this->upload_object_storage($destKeyLikeCi3, $this->file_temp, 'file')) {
$this->set_error('upload_destination_cloud_error');
return false;
}
// 이미지면 width/height
$this->set_image_properties($destKeyLikeCi3, $this->file_temp);
return true;
}
// CI3 스타일: data()
public function data(): array
{
$data = [
'file_name' => $this->file_name,
'file_type' => $this->file_type,
'file_path' => $this->upload_path,
'full_path' => rtrim($this->upload_path, '/') . '/' . $this->file_name,
'raw_name' => $this->raw_name($this->file_name),
'orig_name' => $this->orig_name,
'client_name' => $this->client_name,
'file_ext' => $this->file_ext,
'file_size' => $this->file_size,
'is_image' => ($this->image_width > 0 && $this->image_height > 0),
'image_width' => $this->image_width,
'image_height' => $this->image_height,
'image_type' => $this->image_type,
'image_size_str' => $this->image_size_str,
];
if (!empty($this->s3_data)) {
$data = array_merge($data, $this->s3_data);
}
return $data;
}
public function display_errors(string $open = '', string $close = ''): string
{
if (!$this->errors)
return '';
return $open . implode($close . $open, $this->errors) . $close;
}
public function get_errors(): array
{
return $this->errors;
}
protected function set_error(string $msg): void
{
$this->errors[] = $msg;
}
// --------------------------------------------------------------------
// === 너의 기존 S3 메서드들 (CI4용으로 client 생성만 보강) ===
public function upload_object_storage(string $key, string $temp_file, string $type = 'file'): bool
{
// CI3 코드의 경로 치환 로직 유지 (FCPATH는 CI4에도 존재)
$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 {
$body = file_get_contents($temp_file);
$response = $s3Client->putObject([
'Bucket' => NCLOUD_S3_BUCKET,
'Key' => ltrim($object_storage_upload_path, '/'),
'Body' => $body,
'ACL' => 'public-read',
]);
$this->s3_data = [
'object_storage_upload_path' => $object_storage_upload_path,
'object_storage_url' => $response['ObjectURL'] ?? null,
];
} catch (\Throwable $e) {
// 운영에서는 echo 지양. 로그로 남기는 걸 추천
// log_message('error', $e->getMessage());
return false;
}
return true;
}
public function upload_object_storage_imagick(string $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 {
$s3Client->putObject([
'Bucket' => NCLOUD_S3_BUCKET,
'Key' => ltrim($object_storage_upload_path, '/'),
'Body' => $blobData,
'ACL' => 'public-read',
]);
} catch (\Throwable $e) {
return false;
}
return true;
}
public function upload_object_storage_rename(string $key, string $new_name): bool
{
$s3Client = $this->makeS3Client();
try {
$s3Client->copyObject([
'Bucket' => NCLOUD_S3_BUCKET,
'CopySource' => NCLOUD_S3_BUCKET . '/' . ltrim($key, '/'),
'Key' => ltrim($new_name, '/'),
'ACL' => 'public-read',
]);
$s3Client->deleteObject([
'Bucket' => NCLOUD_S3_BUCKET,
'Key' => ltrim($key, '/'),
]);
return true;
} catch (\Throwable $e) {
return false;
}
}
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,
]);
}
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],
]);
}
// --------------------------------------------------------------------
// === CI3 Upload 유사 유틸들 ===
protected function is_allowed_filetype(string $ext, string $mime): bool
{
if ($this->allowed_types === '*' || $this->allowed_types === '')
return true;
$ext = strtolower(ltrim($ext, '.'));
$allowed = array_map('strtolower', explode('|', $this->allowed_types));
return in_array($ext, $allowed, true);
}
protected function is_allowed_filesize(int $bytes): bool
{
if ($this->max_size <= 0)
return true;
$kb = (int) ceil($bytes / 1024);
return $kb <= $this->max_size;
}
protected function clean_file_name(string $filename): string
{
// CI3처럼 위험문자 제거
$bad = ['<!--', '-->', '<', '>', '"', "'", '&', '$', '=', ';', '?', '/', '\\', '%', '#', '{', '}', '[', ']', ':', ',', '`', '|'];
return str_replace($bad, '', $filename);
}
protected function limit_filename_length(string $filename, int $length): string
{
if (mb_strlen($filename) <= $length)
return $filename;
$ext = $this->get_extension($filename);
$name = $this->raw_name($filename);
$name = mb_substr($name, 0, max(1, $length - mb_strlen($ext)));
return $name . $ext;
}
protected function set_filename(string $path, string $filename)
{
$path = rtrim($path, '/') . '/';
$name = $this->raw_name($filename);
$ext = $this->get_extension($filename);
$i = 0;
$candidate = $filename;
while (is_file($path . $candidate)) {
$i++;
$candidate = $name . '_' . $i . $ext;
if ($i > 9999) {
$this->set_error('upload_filename_overflow');
return false;
}
}
return $candidate;
}
protected function set_image_properties(string $keyLike, string $tempFile): void
{
// 실제 파일은 S3로 올라갔으니 임시파일에서만 추출
$info = @getimagesize($tempFile);
if (!$info)
return;
$this->image_width = (int) $info[0];
$this->image_height = (int) $info[1];
$this->image_type = (string) ($info['mime'] ?? '');
$this->image_size_str = (int) ($info[3] ?? 0);
}
protected function get_extension(string $filename): string
{
$x = strrchr($filename, '.');
return $x === false ? '' : strtolower($x);
}
protected function raw_name(string $filename): string
{
$ext = $this->get_extension($filename);
return $ext ? substr($filename, 0, -strlen($ext)) : $filename;
}
protected function _prep_filename(string $filename): string
{
// 다중 점 처리 등 CI3 유사
return str_replace(' ', '_', $filename);
}
protected function basic_xss_guard(string $filename, string $mime): bool
{
// CI3 do_xss_clean 완전판은 아니고 최소 방어
$lower = strtolower($filename);
if (preg_match('/\.(php|phtml|phar|php\d|cgi|pl|asp|aspx|jsp)$/i', $lower)) {
return false;
}
// mime이 text/html 같은 경우도 거부하고 싶으면 여기서 추가
return true;
}
// --------------------------------------------------------------------
// 너가 올린 make_dirs 로직 이식( VIEW_PATH 없는 부분 보완 )
protected function make_dirs(string $path, bool $last_is_file = false)
{
$dir_arr = explode("/", $path);
if (empty($dir_arr[0])) {
$path = "";
} elseif ($dir_arr[0] === "." || $dir_arr[0] === "..") {
$path = realpath($dir_arr[0]) ?: '';
$dir_arr[0] = "";
} else {
$path = "/";
}
foreach ($dir_arr as $dir) {
$dir = trim($dir);
if (!$dir)
continue;
if ($last_is_file) {
if ($dir === $dir_arr[count($dir_arr) - 1]) {
return false;
}
}
$path = isset($path) ? ($path . "/" . $dir) : $dir;
if (@is_dir($path))
continue;
@mkdir($path, 0707, true);
@chmod($path, 0707);
// CI3는 VIEW_PATH/index.html 복사였는데 CI4에서는 없을 수 있으니 직접 생성
$index = rtrim($path, '/') . '/index.html';
if (!is_file($index)) {
@file_put_contents($index, "<html><head><title>403 Forbidden</title></head><body><p>Directory access is forbidden.</p></body></html>");
@chmod($index, 0606);
}
}
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -14,9 +14,44 @@ class CodeModel extends Model
" WHERE category = ?" . " WHERE category = ?" .
" AND use_yn = 'Y'" . " AND use_yn = 'Y'" .
" ORDER BY view_odr"; " ORDER BY view_odr";
$data = array($category); $data = [$category];
$query = $this->db->query($sql, $data); $query = $this->db->query($sql, $data);
return $query->getResultArray(); return $query->getResultArray();
} }
public function getCodeLists($data): array
{
return $this->db->table('codes')
->select('category, category_nm, cd, cd_nm')
->whereIn('category', $data)
->where('use_yn', 'Y')
->orderBy('view_odr')
->get()
->getResultArray();
}
public function getCategoryCodeList($category = array(), $useYn = '')
{
$this->db->select('category, cd, cd_nm, use_yn');
$this->db->from('codes');
$this->db->where_in('category', $category);
if (!empty($useYn)) {
$this->db->where('use_yn', $useYn);
}
$this->db->order_by('category', 'asc');
$this->db->order_by('view_odr', 'asc');
$query = $this->db->get();
//echo $this->db->last_query()."<br>";
//여기 아래부분을 해줘야 배열을 카테고리로 뽑아쓸수있다 위에는 배열에 배열이담김
$codes = [];
foreach ($query->getResultArray() as $row) {
$codes[$row['category']][] = ['cd' => $row['cd'], 'cd_nm' => $row['cd_nm']];
}
return $codes;
}
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,237 @@
<?php
$cnt = count($listDept);
$lati = 0;
$long = 0;
foreach ($listDept as $dept) {
$lati += $dept['rcpt_y'];
$long += $dept['rcpt_x'];
}
$lati = $lati / $cnt;
$long = $long / $cnt;
?>
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Language" content="ko">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>컨펌스 로그인</title>
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no" />
<meta name="description" content="ArchitectUI HTML Bootstrap 5 Dashboard Template">
<script defer src="/architectui/assets/scripts/vendors.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/main.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/demo.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/ladda.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/blockui.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/circle_progress.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/count_up.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/toastr.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/sweet_alerts.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/scrollbar.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/sticky_elements.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/carousel_slider.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/fullcalendar.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/treeview.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/maps.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/rating.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/image_crop.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/guided_tours.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/tables.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/form_validation.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/form_wizard.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/clipboard.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/datepicker.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/input_mask.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/input_select.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/range_slider.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/textarea_autosize.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/toggle_switch.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/chart_js.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/apex_charts.98288b227c064e6a107f.js"></script>
<script defer src="/architectui/assets/scripts/sparklines.98288b227c064e6a107f.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<link href="/architectui/assets/styles/vendors.98288b227c064e6a107f.css" rel="stylesheet">
<link href="/architectui/assets/styles/main.98288b227c064e6a107f.css" rel="stylesheet">
<style>
.marker-label {
position: absolute;
transform: translate(-50%, -100%);
background: #fff;
border: 1px solid #333;
border-radius: 6px;
padding: 3px 6px;
font-size: 12px;
white-space: nowrap;
box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
pointer-events: none;
/* 지도 드래그 방해 안 하게 */
}
</style>
</head>
<body>
<div class="my-loader-template d-none">
<div class="loader bg-transparent no-shadow p-0">
<div class="ball-grid-pulse">
<div class="bg-white"></div>
<div class="bg-white"></div>
<div class="bg-white"></div>
<div class="bg-white"></div>
<div class="bg-white"></div>
<div class="bg-white"></div>
<div class="bg-white"></div>
<div class="bg-white"></div>
<div class="bg-white"></div>
</div>
</div>
</div>
<div class="app-container app-theme-white body-tabs-shadow">
<div class="app-container">
<div class="app-main__outer">
<div class="app-main__inner px-4 py-3">
<div class="app-page-title">
<div class="page-title-wrapper d-flex align-items-center">
<div class="page-title-heading">
<div class="page-title-icon">
<i class="pe-7s-map icon-gradient bg-premium-dark"></i>
</div>
<div>
관할 배정 지도
</div>
</div>
<div class="ms-auto">
<button type="button" class="btn btn-primary" onclick="fn_print();">
인쇄하기
</button>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="main-card mb-3 card" id="mapArea">
<div class="card-body" style="height: 400px;">
<div id="map_view" style="width:100%;height:700px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpClientId=kvyjyj00fp"></script> -->
<!-- <script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script> -->
<!-- <script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpClientId=dtounkwjc5"></script> -->
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
const tpl = document.querySelector('.my-loader-template');
var map;
$(function () {
map = new naver.maps.Map('map_view', {
center: new naver.maps.LatLng(<?= $lati ?>, <?= $long ?>), //지도의 초기 중심 좌표
useStyleMap: true,
zoom: 15, //지도의 초기 줌 레벨
minZoom: 1, //지도의 최소 줌 레벨
mapTypeControl: true, //지도 유형 컨트롤의 표시 여부
mapTypeControlOptions: { //지도 유형 컨트롤의 옵션
style: naver.maps.MapTypeControlStyle.BUTTON,
position: naver.maps.Position.TOP_LEFT
},
zoomControl: true, //줌 컨트롤의 표시 여부
zoomControlOptions: { //줌 컨트롤의 옵션
position: naver.maps.Position.TOP_RIGHT
}
});
<?php reset($listDept);
foreach ($listDept as $dept): ?>
const pos_<?= $dept['rcpt_no'] ?> = new naver.maps.LatLng(<?= $dept['rcpt_y'] ?>, <?= $dept['rcpt_x'] ?>);
// 기본 마커
new naver.maps.Marker({
position: pos_<?= $dept['rcpt_no'] ?>,
map: map,
// icon: {
// url: HOME_PATH + '/plugin/img/pin.png',
// size: new naver.maps.Size(50, 52),
// origin: new naver.maps.Point(0, 0),
// anchor: new naver.maps.Point(25, 26)
// }
});
// 라벨 오버레이(텍스트만)
new LabelOverlay({
position: pos_<?= $dept['rcpt_no'] ?>,
text: "<?= addslashes($dept['rcpt_hscp_nm']) ?>",
map: map
});
<?php endforeach; ?>
});
function LabelOverlay(options) {
this._position = options.position;
this._text = options.text;
this._map = options.map;
this.setMap(this._map);
}
LabelOverlay.prototype = new naver.maps.OverlayView();
LabelOverlay.prototype.onAdd = function () {
const el = document.createElement('div');
el.className = 'marker-label';
el.textContent = this._text;
this._el = el;
const overlayLayer = this.getPanes().overlayLayer;
overlayLayer.appendChild(el);
};
LabelOverlay.prototype.draw = function () {
const projection = this.getProjection();
const point = projection.fromCoordToOffset(this._position);
// 라벨을 마커 위로 올리기
this._el.style.left = point.x + 'px';
this._el.style.top = (point.y - 30) + 'px';
};
LabelOverlay.prototype.onRemove = function () {
if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
this._el = null;
};
// 인쇄하기
function fn_print() {
var initBody;
window.onbeforeprint = function () {
initBody = document.body.innerHTML;
document.body.innerHTML = document.getElementById('mapArea').innerHTML;
};
window.onafterprint = function () {
document.body.innerHTML = initBody;
};
window.print();
return false;
}
</script>
</body>
</html>

View File

@@ -11,6 +11,7 @@
}, },
"require": { "require": {
"php": "^8.1", "php": "^8.1",
"aws/aws-sdk-php": "^3.369",
"codeigniter4/framework": "^4.0" "codeigniter4/framework": "^4.0"
}, },
"require-dev": { "require-dev": {

1120
composer.lock generated

File diff suppressed because it is too large Load Diff

BIN
public/plugin/img/photo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
public/plugin/img/pin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB