Compare commits

...

2 Commits

Author SHA1 Message Date
0605948ab5 파일업로드 추가
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/42
2026-01-28 16:10:35 +09:00
yangsh
d134b27614 파일업로드 추가
Some checks failed
Close Pull Request / main (pull_request_target) Has been cancelled
2026-01-28 16:09:52 +09:00
5 changed files with 1330 additions and 257 deletions

View File

@@ -74,7 +74,10 @@ $routes->group('', ['namespace' => 'App\Controllers\Article'], static function (
$routes->post('rsrvcancel', 'Receipt::rsrvcancel'); // 예약취소
$routes->post('sendSms', 'Receipt::sendSms'); // 문자발송
$routes->post('saveRecInfo', 'Receipt::saveRecInfo'); // 거주인정보저장
$routes->post('uploadFile', 'Receipt::uploadFile'); // 파일업로드
$routes->post('removeUploadFile', 'Receipt::removeUploadFile'); // 파일삭제
$routes->get('downloadAllImages', 'Receipt::downloadAllImages'); // 이미지 일괄 다운로드
$routes->post('saveImgLocation', 'Receipt::saveImgLocation'); // 촬영위치 저장
});
/**

View File

@@ -2,6 +2,7 @@
namespace App\Controllers\Article;
use App\Controllers\BaseController;
use App\Libraries\Common;
use App\Libraries\MyUpload;
use App\Models\article\ReceiptModel;
use App\Models\common\CodeModel;
@@ -461,4 +462,331 @@ class Receipt extends BaseController
]);
}
}
// 파일업로드
public function uploadFile()
{
$lib = new MyUpload();
$common = new Common();
try {
$rcpt_key = $this->request->getPost('rcpt_key');
$rsrv_sq = $this->request->getPost('rsrv_sq');
$rcpt_sq = $this->request->getPost('rcpt_sq');
$img_type = $this->request->getPost('img_type');
$files = $this->request->getFiles();
$uploadPath = "/upload/result/" . $rsrv_sq . "/";
if (!isset($files['files'])) {
return $this->response->setJSON([
'success' => false,
'msg' => '파일 없음'
]);
}
$uploadFiles = $files['files'];
if ($uploadFiles instanceof \CodeIgniter\HTTP\Files\UploadedFile) {
$uploadFiles = [$uploadFiles];
}
// 매물정보 가져오기
$receipt = $this->model->getDetail($rcpt_key);
// 워터마크 이미지 조회
$watermark_info = [];
if (!empty($receipt) && ($receipt['comp_sq'] ?? '') == '2') {
$watermark_info = $this->model->getWatermarkList($receipt['rcpt_cpid']);
}
$arrUploadfile = [];
foreach ($uploadFiles as $file) {
log_message('info', '[Receipt::uploadFile] upload start name={name} size={size} type={type} error={error}:{errorString} path={path}', [
'name' => $file->getName(),
'size' => $file->getSize(),
'type' => $file->getMimeType(),
'error' => $file->getError(),
'errorString' => $file->getErrorString(),
'path' => $uploadPath,
]);
$uploadData = $lib->do_upload2($file, $uploadPath);
if ($uploadData !== false) {
$arrUploadfile[] = $uploadData;
log_message('info', '[Receipt::uploadFile] upload success name={name} stored={stored}', [
'name' => $file->getName(),
'stored' => $uploadData['file_name'] ?? '(unknown)',
]);
} else {
log_message('error', '[Receipt::uploadFile] do_upload2 failed name={name} error={error}:{errorString}', [
'name' => $file->getName(),
'error' => $file->getError(),
'errorString' => $file->getErrorString(),
]);
}
}
$gps_lat = null;
$gps_lon = null;
$camDate = null;
if (!empty($arrUploadfile)) {
foreach ($arrUploadfile as $key => $uploadFile) {
$object_storage_url = $uploadFile['object_storage_url'];
$imgWidth = '';
$imgHeight = '';
if ($img_type !== 'V1') {
$base = $uploadFile['base_name']; // xxxx
$dir = rtrim(dirname($uploadFile['object_key']), '/'); // upload/result/*
$thumbKey = $dir . '/' . $base . '_thumb.jpg';
$imageDataBlob = file_get_contents($object_storage_url);
$im = new \Imagick();
$im->readImageBlob($imageDataBlob);
$imgWidth = $im->getImageWidth();
$imgHeight = $im->getImageHeight();
$im->thumbnailImage(105, 80, false);
$thumb_im = $im->getImageBlob();
// 썸네일 s3 전송
$lib->upload_object_storage_imagick2($thumbKey, $thumb_im);
$im->destroy();
}
// 워터마크 삽입
$watermark_imgs = ['I3', 'I4'];
if (in_array($img_type, $watermark_imgs)) {
if (!empty($watermark_info)) {
$common->watermarking($object_storage_url, $watermark_info, '', $receipt['rcpt_cpid'], $uploadFile['object_key']);
}
}
// 촬영정보 가져오기
$arrExifData = @exif_read_data($object_storage_url);
if (!is_array($arrExifData)) {
$arrExifData = [];
}
if (!isset($arrExifData['COMPUTED']) || !is_array($arrExifData['COMPUTED'])) {
$arrExifData['COMPUTED'] = [];
}
$notFound = "Unavailable";
// Make - 카메라 제조사
if (@array_key_exists('Make', $arrExifData)) {
$camMake = $arrExifData['Make'];
} else {
$camMake = $notFound;
}
// Model - 카메라 모델
if (@array_key_exists('Model', $arrExifData)) {
$camModel = $arrExifData['Model'];
} else {
$camModel = $notFound;
}
// Date - 촬영일시
if (@array_key_exists('DateTime', $arrExifData)) {
$camDate = $arrExifData['DateTime'];
} else {
$camDate = $notFound;
}
// COMPUTED.Height - 세로크기
if (@array_key_exists('Height', $arrExifData['COMPUTED'])) {
$camHeight = $arrExifData['COMPUTED']['Height'];
} else {
$camHeight = $notFound;
}
// COMPUTED.Width - 가로크기
if (@array_key_exists('Width', $arrExifData['COMPUTED'])) {
$camWidth = $arrExifData['COMPUTED']['Width'];
} else {
$camWidth = $notFound;
}
$imageMetaData = "카메라 제조사: " . $camMake;
$imageMetaData .= "\n카메라 모델: " . $camModel;
$imageMetaData .= "\n촬영일시: " . $camDate;
$imageMetaData .= "\n가로: " . $camWidth;
$imageMetaData .= "\n세로: " . $camHeight;
$metaData = $imageMetaData;
/**
* 파일업로드 내용 저장
*/
$uploadParam = [
'rcpt_key' => $rcpt_key, // 접수번호
'rsrv_sq' => $rsrv_sq, // 예약일련번호
'rcpt_sq' => $rcpt_sq, // 접수일련번호
// 'gps_lat' => $gps_lat, // latitude
// 'gps_lon' => $gps_lon, // longitude
'origin_name' => $uploadFile['origin_name'], // 원본파일명
'file_name' => $uploadFile['file_name'], // 저장파일명
'upload_path' => $uploadPath, // 저장경로
'size' => $file->getSize(),
'width' => $imgWidth,
'height' => $imgHeight,
// 'thumb_name' => $base . '_thumb.jpg',
'cam_date' => $camDate, // 촬영일
'meta_data' => $metaData, // 이미지메타데이터
'receipt' => $receipt,
'img_type' => $img_type,
];
$this->model->saveImg($uploadParam);
}
}
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 매물사진 일괄 다운로드 (zip)
public function downloadAllImages()
{
$rsrv_sq = $this->request->getGet('rsrv_sq');
$img_type = $this->request->getGet('img_type') ?? 'I4';
if (empty($rsrv_sq)) {
return $this->response->setStatusCode(400)->setBody('rsrv_sq required');
}
$images = $this->model->getImageListByType($rsrv_sq, $img_type);
if (empty($images)) {
return $this->response->setStatusCode(404)->setBody('No files');
}
$zip = new \ZipArchive();
$zipName = 'images_' . $rsrv_sq . '_' . $img_type . '_' . date('Ymd_His') . '.zip';
$zipPath = WRITEPATH . 'cache/' . $zipName;
if ($zip->open($zipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
return $this->response->setStatusCode(500)->setBody('Failed to create zip');
}
foreach ($images as $index => $img) {
$filePath = $img['img_path'] . $img['img_filenm'];
$zipFileName = sprintf('%02d_%s', $index + 1, basename($img['img_filenm']));
if (($img['cloud_upload_yn'] ?? 'N') === 'Y') {
$sourceUrl = NCLOUD_OBJECT_STORAGE_URL . $filePath;
$content = @file_get_contents($sourceUrl);
if ($content !== false) {
$zip->addFromString($zipFileName, $content);
}
continue;
}
$localPath = FCPATH . ltrim($filePath, '/');
if (is_file($localPath)) {
$zip->addFile($localPath, $zipFileName);
continue;
}
$content = @file_get_contents($filePath);
if ($content !== false) {
$zip->addFromString($zipFileName, $content);
}
}
$zip->close();
if (!is_file($zipPath)) {
return $this->response->setStatusCode(500)->setBody('Zip not found');
}
register_shutdown_function(static function () use ($zipPath) {
if (is_file($zipPath)) {
@unlink($zipPath);
}
});
return $this->response->download($zipPath, null)->setFileName($zipName);
}
// 촬영위치 저장
public function saveImgLocation()
{
try {
$img_sq = $this->request->getPost('img_sq');
$rsrv_sq = $this->request->getPost('rsrv_sq');
$location = $this->request->getPost('location');
$this->model->saveImgLocation($img_sq, $rsrv_sq, $location);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 업로드파일 삭제
public function removeUploadFile()
{
try {
$rcpt_sq = $this->request->getPost('rcpt_sq');
$img_sq = $this->request->getPost('img_sq');
// 파일정보 조회
$file = $this->model->getUploadFileInfo($img_sq);
if (!empty($file)) {
$lib = new MyUpload();
$path = $file['img_path'] . "" . $file['img_filenm'];
$thumb = explode(".", $file['img_filenm']);
$thumbPath = $file['img_path'] . "" . $thumb[0] . "_thumb." . $thumb[1];
// if ($file['cloud_upload_yn'] == "Y") {
// $path = NCLOUD_OBJECT_STORAGE_URL . $path;
// }
$lib->deleteFile($path);
$lib->deleteFile($thumbPath);
}
$this->model->removeUploadFile($rcpt_sq, $img_sq);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
}
}
}

View File

@@ -38,11 +38,7 @@ class Common
*/
public function watermarking($imagePath, $watermark_info, $wmText, $cpid, $key = '')
{
$CI =& get_instance();
$CI->load->library('upload');
$uploader = new MyUpload();
$wmImagePath = ''; // 워터마크 이미지의 경로
$wmSpaceHeihgt = 0; // 워터마크 이미지 하단 공백
@@ -54,9 +50,31 @@ class Common
try {
// $img = new Imagick($imagePath);
$img = new \Imagick();
if (is_string($imagePath) && is_file($imagePath)) {
$img->readImage($imagePath);
} elseif (is_string($imagePath) && filter_var($imagePath, FILTER_VALIDATE_URL)) {
$headers = @get_headers($imagePath, 1) ?: [];
$blob = @file_get_contents($imagePath);
$contentType = '';
if (!empty($headers)) {
$contentType = is_array($headers['Content-Type'] ?? null)
? end($headers['Content-Type'])
: ($headers['Content-Type'] ?? '');
}
log_message('info', '[watermarking] source url={url} status={status} content_type={ctype} size={size}', [
'url' => $imagePath,
'status' => is_array($headers) && isset($headers[0]) ? $headers[0] : '(no status)',
'ctype' => $contentType,
'size' => $blob === false ? 0 : strlen($blob),
]);
if ($blob === false) {
throw new \RuntimeException('Failed to load image from URL');
}
$img->readImageBlob($blob);
} else {
$img->readImageBlob($imagePath);
}
$hImg = $img->getImageHeight();
$wImg = $img->getImageWidth();
@@ -90,7 +108,7 @@ class Common
$wm = new Imagick(FCPATH . $wmImagePath);
$wm = new \Imagick($wmImagePath);
$hWm = $wm->getImageHeight();
$wWm = $wm->getImageWidth();
@@ -98,22 +116,25 @@ class Common
$wmImgTop = floor(($hImg - $hWm - $wmSpaceHeihgt - $wmTextHeight) / 2); // 워터마크 이미지의 위치 top
$wmTxtTop = $wmImgTop + $hWm + $wmSpaceHeihgt + ($wmTextHeight * 0.6); // 워터마크 텍스트의 위치
$img->compositeImage($wm, imagick::COMPOSITE_OVER, $wmImgLeft, $wmImgTop, imagick::ALIGN_CENTER);
$img->compositeImage($wm, \Imagick::COMPOSITE_OVER, $wmImgLeft, $wmImgTop);
$wm->destroy();
$draw = new \ImagickDraw();
$wmFont = BASEPATH . 'fonts/' . $wmFont;
$basePath = defined('BASEPATH') ? BASEPATH : (defined('ROOTPATH') ? ROOTPATH . 'system/' : '');
$wmFont = $basePath . 'fonts/' . $wmFont;
if (is_file($wmFont)) {
$draw->setFont($wmFont);
}
$draw->setFontSize($wmFontSize);
$draw->setFillColor(new ImagickPixel($wmTextColor));
$draw->setFillColor(new \ImagickPixel($wmTextColor));
// $draw->setFillAlpha( $wmTextAlpha );
$draw->setFillOpacity($wmTextAlpha); // 워터마크 텍스트 투명도 설정
$draw->setTextAlignment(2); // center
$draw->setStrokeAntialias(1);
$draw->setStrokeWidth(1);
$draw->setStrokeColor(new ImagickPixel('#000000'));
$draw->setStrokeColor(new \ImagickPixel('#000000'));
// $draw->setStrokeAlpha(0.1);
$draw->setStrokeOpacity(0.1);
$draw->annotation($wImg / 2, $wmTxtTop, $wmText);
@@ -125,12 +146,27 @@ class Common
$watermark_img = $img->getImageBlob();
$CI->upload->upload_object_storage_imagick($key, $watermark_img);
if (empty($key)) {
throw new \RuntimeException('Empty upload key');
}
$ok = $uploader->upload_object_storage_imagick2($key, $watermark_img);
if ($ok) {
log_message('info', '[watermarking] upload success key={key} size={size} cpid={cpid}', [
'key' => $key,
'size' => strlen($watermark_img),
'cpid' => $cpid,
]);
} else {
log_message('error', '[watermarking] upload failed key={key} cpid={cpid}', [
'key' => $key,
'cpid' => $cpid,
]);
}
$img->destroy();
// $object_upload = $this->upload->upload_object_storage($imagePath , $imagePath , 'data');
} catch (Exception $e) {
echo $e->getMessage();
} catch (\Throwable $e) {
log_message('error', '[watermarking] ' . $e->getMessage());
}
}

View File

@@ -1035,6 +1035,7 @@ class ReceiptModel extends Model
,a.rcpt_sido
,a.rcpt_gugun
,a.rcpt_dong
,c.region_nm AS addr
,a.rcpt_dtl_addr
,a.rcpt_li_addr
,a.rcpt_jibun_addr
@@ -1145,7 +1146,6 @@ class ReceiptModel extends Model
,get_code_name('RECEIPT_STATUS3', a.rcpt_stat) AS rcpt_stat_nm
,DATE_FORMAT(a.insert_tm, '%Y년 %m월 %d일') as insert_tm2
,DATE_FORMAT(a.rsrv_date, '%Y-%m-%d') as rsrv_date2
,c.region_nm as addr
,c.dept_sq as region_dept_sq
,c.usr_sq as region_usr_sq
,d.pdept_sq
@@ -1348,6 +1348,20 @@ class ReceiptModel extends Model
return $query->getResultArray();
}
public function getImageListByType($rsrv_sq, $img_type)
{
$sql = "SELECT * " .
" FROM result_imgs" .
" WHERE rsrv_sq = ?" .
" AND img_type = ?" .
" AND use_yn = 'Y'" .
" ORDER BY view_odr";
$data = [$rsrv_sq, $img_type];
$query = $this->db->query($sql, $data);
return $query->getResultArray();
}
public function getImageCountByType($rsrv_sq)
{
$sql = "SELECT img_type, COUNT(*) img_cnt" .
@@ -1669,9 +1683,9 @@ class ReceiptModel extends Model
";
$param = [
$data['rsrv_sq'],
$f['file_path'],
$f['new_name'],
$f['orig_name'],
$f['upload_path'],
$f['file_name'],
$f['origin_name'],
$f['size'],
$data['rec_tel'],
$data['rec_nm'],
@@ -1709,4 +1723,325 @@ class ReceiptModel extends Model
'success' => true,
];
}
// 워터마크 조회
public function getWatermarkList($rcpt_cpid)
{
$builder = $this->db->table('watermark');
$builder->select('cpid, wm_type, wm_img_path, wm_img_height, wm_img_width, wm_position, wm_img_opacity, wm_space, text_font, text_color, text_opacity, text_size, text_pixel, img_width_min, img_width_max');
$builder->where('cpid', $rcpt_cpid);
$row = $builder->get()->getResultArray();
return $row;
}
// 업로드정보 저장
public function saveImg($param)
{
$this->db->transStart();
$usr_id = session('usr_id');
$usr_sq = session('usr_sq');
$receipt = $param['receipt'];
$cloud_upload_yn = 'Y';
if ($param['img_type'] == 'I6' || $param['img_type'] == 'I7') {
$yn_sql = "update receipt " .
" set exp_spc_yn = 'Y' " .
" where rcpt_sq = ? ";
$yn_data = [$param['rcpt_sq']];
$this->db->query($yn_sql, $yn_data);
} else if ($param['img_type'] == 'I8') {
$yn_sql = "update receipt " .
" set exp_spc_yn = 'Y' " .
" where rcpt_sq = ? ";
$yn_data = [$param['rcpt_sq']];
$this->db->query($yn_sql, $yn_data);
} else if ($param['img_type'] == 'I9') {
$yn_sql = "update receipt " .
" set image_360_yn = 'Y' " .
" where rcpt_sq = ? ";
$yn_data = [$param['rcpt_sq']];
$this->db->query($yn_sql, $yn_data);
} else if ($param['img_type'] == 'I11') {
$yn_sql = "update receipt " .
" set check_list_img_yn = 'Y' " .
" where rcpt_sq = ? ";
$yn_data = [$param['rcpt_sq']];
$this->db->query($yn_sql, $yn_data);
}
//한장의 사진만 업로드하는것들은 UPDATE -> INSERT
$img_list = ['I1', 'I2', 'I5', 'I6', 'I7', 'V1', 'I10', 'I11'];
// 주소가 rcpt_jibun_addr 있을때는 그 주소로
$addr_nm = $receipt['addr'];
if ($receipt['rcpt_jibun_addr']) {
$img_hannm = '컨펌스_' . $addr_nm . ' ' . $receipt['rcpt_jibun_addr'] . ' ' . $receipt['rcpt_etc_addr'] . '_' . $receipt['excls_spc'] . '.jpeg';
} else {
$img_hannm = '컨펌스_' . $addr_nm . ' ' . $receipt['rcpt_dtl_addr'] . ' ' . $receipt['rcpt_ho'] . '_' . $receipt['excls_spc'] . '.jpeg';
}
if (in_array($param['img_type'], $img_list)) {
//업데이트할게없어도 에러가 안난다 단지 row(s)affected 가 0 일뿐
$sql = "UPDATE result_imgs" .
" SET use_yn = 'N'" .
" WHERE rsrv_sq = ?" .
" AND img_type = ?" .
" AND use_yn = 'Y'";
$data = [$param['rsrv_sq'], $param['img_type']];
$this->db->query($sql, $data);
//새로운 이미지 생성
$sql = "INSERT INTO result_imgs(rsrv_sq, use_yn, img_type, view_odr, img_path, img_filenm, img_nm, img_size, img_width, img_height, insert_usr, insert_tm, meta_data, img_hannm , cloud_upload_yn )" .
"VALUES (?, 'Y', ?, 1, ?, ?, ?, ?, ?, ?, ?, NOW(), ?,? , ?)";
$data = [
$param['rsrv_sq'],
$param['img_type'],
$param['upload_path'],
$param['file_name'],
$param['origin_name'],
$param['size'],
$param['width'],
$param['height'],
$usr_sq,
isset($param['meta_data']) ? $param['meta_data'] : null,
$img_hannm,
$cloud_upload_yn
];
$res = $this->db->query($sql, $data);
} else {
$odr_sql = "SELECT COALESCE(MAX(view_odr), 0) + 1 as seq FROM result_imgs WHERE rsrv_sq = ? AND img_type = ? AND use_yn = 'Y'";
$odr_data = array($param['rsrv_sq'], $param['img_type']);
$query = $this->db->query($odr_sql, $odr_data);
$row = $query->getRowArray();
$view_odr = $row['seq'];
$sql = "INSERT INTO result_imgs(rsrv_sq, use_yn, img_type, view_odr, img_path, img_filenm, img_nm, img_size, img_width, img_height, insert_usr, insert_tm, meta_data, img_hannm , cloud_upload_yn )" .
"VALUES (?, 'Y', ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?,?, ?)";
$data = [
$param['rsrv_sq'],
$param['img_type'],
$view_odr,
$param['upload_path'],
$param['file_name'],
$param['origin_name'],
$param['size'],
$param['width'],
$param['height'],
$usr_sq,
isset($param['meta_data']) ? $param['meta_data'] : null,
$img_hannm,
$cloud_upload_yn
];
$res = $this->db->query($sql, $data);
}
if ($res) {
switch ($param['img_type']) {
case 'I1':
$remark = "홍보확인서 사진 업로드";
break;
case 'I2':
$remark = "현장확인 내역서 사진 업로드";
break;
case 'I3':
$remark = "건물외관 사진 업르도";
break;
case 'I4':
$remark = "매물사진 업로드";
break;
case 'I5':
$remark = "평면도 업로드";
break;
case 'I6':
$remark = "전용면적 파일 업로드";
break;
case 'I7':
$remark = "공용면적 파일 업로드";
break;
case 'I8':
$remark = "분양권 파일 업로드";
break;
case 'I9':
$remark = "360이미지 업로드";
break;
case 'I10':
$remark = "촬영동의서 사진 업로드";
break;
case 'I11':
$remark = "체크리스트 사진 업로드";
break;
case 'V1':
$remark = "동영상 업로드";
break;
}
$this->saveChangedHistory($param['rcpt_sq'], $receipt['rcpt_stat'], 'C16', $usr_id, $remark);
$this->db->transComplete();
return [
'success' => true,
];
} else {
return [
'success' => false,
'msg' => '저장실패',
];
}
}
// 파일정보조회
public function getUploadFileInfo($img_sq)
{
$sql = "SELECT * FROM result_imgs WHERE img_sq = ?";
$query = $this->db->query($sql, [$img_sq]);
$row = $query->getRowArray();
return $row;
}
// 업로드파일 삭제
public function removeUploadFile($rcpt_sq, $img_sq)
{
$this->db->transStart();
$usr_id = session('usr_id');
// 이미지정보 조회
$row = $this->getUploadFileInfo($img_sq);
if (!empty($row)) {
if ($row['img_type'] == 'I6' || $row['img_type'] == 'I7') {
$yn_sql = "update receipt " .
" set exp_spc_yn = 'N' " .
" where rcpt_sq = ? ";
$yn_data = [$rcpt_sq];
$this->db->query($yn_sql, $yn_data);
} else if ($row['img_type'] == 'I8') {
$yn_sql = "UPDATE receipt" .
" SET parcel_out_yn = CASE (SELECT COUNT('x')" .
" FROM result_imgs " .
" WHERE rsrv_sq = (SELECT rsrv_sq FROM result_imgs WHERE img_sq = ? AND img_type = 'I8')" .
" AND use_yn = 'Y'" .
" AND img_type = 'I8') WHEN 0 THEN 'N' ELSE 'Y' END" .
" WHERE rcpt_sq = ? ";
$yn_data = [$rcpt_sq];
$this->db->query($yn_sql, $yn_data);
} else if ($row['img_type'] == 'I9') {
$yn_sql = "UPDATE receipt" .
" SET image_360_yn = (" .
" CASE (SELECT COUNT(1)" .
" FROM result_imgs" .
" WHERE rsrv_sq = (SELECT rsrv_sq FROM result_imgs WHERE img_sq = ? AND img_type = 'I9')" .
" AND img_type = 'I9' AND use_yn = 'Y')" .
" WHEN 0 THEN 'N'" .
" ELSE 'Y'" .
" END" .
" )" .
" WHERE rcpt_sq = ?";
$yn_data = [$rcpt_sq];
$this->db->query($yn_sql, $yn_data);
} else if ($row['img_type'] == 'I11') {
$yn_sql = "update receipt " .
" set check_list_img_yn = 'N' " .
" where rcpt_sq = ? ";
$yn_data = [$rcpt_sq];
$this->db->query($yn_sql, $yn_data);
}
//삭제이미지보다 순번이 높은거는 순번 업데이트
$sql = "UPDATE result_imgs SET view_odr = view_odr - 1 WHERE rsrv_sq = ? AND img_type = ? AND view_odr > ? AND use_yn = 'Y'";
$data = [$row['rsrv_sq'], $row['img_type'], $row['view_odr']];
$this->db->query($sql, $data);
//이미지 삭제
$sql = "DELETE FROM result_imgs WHERE img_sq = ?";
$data = [$img_sq];
if ($this->db->query($sql, $data) === false) {
return [
'success' => false,
'msg' => '삭제실패',
];
}
if (in_array($row['img_type'], ['I1', 'I2', 'I8', 'I10', 'I11'])) {
$remark = "";
switch ($row['img_type']) {
case 'I1':
$remark = "홍보확인서 사진 삭제";
break;
case 'I2':
$remark = "현장확인 내역서 사진 삭제";
break;
case 'I8':
$remark = "분양권 파일 삭제";
break;
case 'I10':
$remark = "촬영동의서 사진 삭제";
break;
case 'I11':
$remark = "체크리스트 사진 삭제";
break;
}
// 상태값을 가져오기위한 쿼리 해오기
$sql = "SELECT rcpt_stat FROM receipt WHERE rcpt_sq = ?";
$data = [$rcpt_sq];
$query = $this->db->query($sql, $data);
$row = $query->getRowArray();
$this->saveChangedHistory($rcpt_sq, $row['rcpt_stat'], 'C31', $usr_id, $remark);
}
$this->db->transComplete();
return [
'success' => true,
];
}
}
// 촬영위치 저장
public function saveImgLocation($img_sq, $rsrv_sq, $location)
{
$sql = "UPDATE result_imgs" .
" SET img_location = ?" .
" WHERE img_sq = ?" .
" AND rsrv_sq = ?";
$data = [$location, $img_sq, $rsrv_sq];
if ($this->db->query($sql, $data) === false) {
return [
'success' => false,
'msg' => '저장실패',
];
} else {
return [
'success' => true,
];
}
}
}

View File

@@ -27,12 +27,21 @@ $usr_level = session('usr_level');
max-height: 300px;
overflow-y: scroll;
}
a[onclick] img {
cursor: pointer;
}
.img-location-input {
width: 100%;
}
</style>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div>현장확인매물 상세 내용</div>
<?= $data['rcpt_cpid'] ?>
</div>
</div>
</div>
@@ -1107,18 +1116,6 @@ $usr_level = session('usr_level');
<!-- 홍보확인서 -->
<div class="col-12 col-lg-4">
<div class="border rounded-3 p-2 ">
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-semibold">홍보확인서</div>
<!-- 업로드 버튼(기존 input file 유지) -->
<label class="btn btn-sm btn-outline-secondary mb-0">
파일
<input type="file" id="img_file_I1" name="img_file_I1" accept=".jpg,.jpeg,.png,.gif" class="d-none"
onclick="type_alert_onclick(event, 'I1', '0')" onchange="imgFind_onchange(event, 'I1', '0')">
</label>
</div>
<div class="ratio ratio-4x3 rounded-2 overflow-hidden">
<?php
$arrI1 = array();
reset($images);
@@ -1128,6 +1125,22 @@ $usr_level = session('usr_level');
unset($images[$key]);
}
}
$sq = !empty($arrI1) ? ($arrI1[0]['img_sq'] ?? '') : '';
?>
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-semibold">홍보확인서</div>
<div class="d-flex align-items-center gap-1">
<?php if (!empty($arrI1)) { ?>
<button type="button" class="btn btn-sm btn-outline-danger"
onclick="removeFile('<?= $sq ?>')">삭제</button>
<?php } ?>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="viewFilePop('I1', '')">파일</button>
</div>
</div>
<div class="ratio ratio-4x3 rounded-2 overflow-hidden">
<?php
if (!empty($arrI1)) {
foreach ($arrI1 as $img) {
list($filename, $ext) = explode(".", $img['img_filenm']);
@@ -1160,17 +1173,33 @@ $usr_level = session('usr_level');
<!-- 촬영동의서 -->
<div class="col-12 col-lg-4">
<div class="border rounded-3 p-2 ">
<?php
$arrI10 = [];
reset($images);
foreach ($images as $key => $img) {
if ($img['img_type'] == 'I10') {
$arrI10[] = $img;
unset($images[$key]);
}
}
$sqI10 = !empty($arrI10) ? ($arrI10[0]['img_sq'] ?? '') : '';
?>
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-semibold">촬영동의서</div>
<div class="d-flex align-items-center gap-1">
<?php if (!empty($arrI10)) { ?>
<button type="button" class="btn btn-sm btn-outline-danger"
onclick="removeFile('<?= $sqI10 ?>')">삭제</button>
<?php } ?>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="viewFilePop('I10', '')">파일</button>
</div>
</div>
<div class="ratio ratio-4x3 rounded-2 overflow-hidden">
<?php
if (isset($imgs_count['I10']) && $imgs_count['I10'] != 0) {
foreach ($images as $img) {
if ($img['img_type'] == 'I10') {
if (!empty($arrI10)) {
foreach ($arrI10 as $img) {
$temp2 = explode(".", $img['img_filenm']);
//$name = $temp2[0]."_thumb.".$temp2[1];
$name = $temp2[0] . "_thumb.jpg";
@@ -1191,7 +1220,6 @@ $usr_level = session('usr_level');
</a>
<?php
}
}
} else {
?>
<img src="/plugin/img/photo.gif" alt="촬영동의서" class="w-100 object-fit-contain">
@@ -1203,17 +1231,33 @@ $usr_level = session('usr_level');
<!-- 현장확인내역서 -->
<div class="col-12 col-lg-4">
<div class="border rounded-3 p-2 ">
<?php
$arrI2 = [];
reset($images);
foreach ($images as $key => $img) {
if ($img['img_type'] == 'I2') {
$arrI2[] = $img;
unset($images[$key]);
}
}
$sqI2 = !empty($arrI2) ? ($arrI2[0]['img_sq'] ?? '') : '';
?>
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-semibold">현장확인내역서</div>
<div class="d-flex align-items-center gap-1">
<?php if (!empty($arrI2)) { ?>
<button type="button" class="btn btn-sm btn-outline-danger"
onclick="removeFile('<?= $sqI2 ?>')">삭제</button>
<?php } ?>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="viewFilePop('I2', '')">파일</button>
</div>
</div>
<div class="ratio ratio-4x3 rounded-2 overflow-hidden">
<?php
if (isset($imgs_count['I2']) && $imgs_count['I2'] != 0) {
foreach ($images as $img) {
if ($img['img_type'] == 'I2') {
if (!empty($arrI2)) {
foreach ($arrI2 as $img) {
$temp2 = explode(".", $img['img_filenm']);
//$name = $temp2[0]."_thumb.".$temp2[1];
$name = $temp2[0] . "_thumb.jpg";
@@ -1232,7 +1276,6 @@ $usr_level = session('usr_level');
</a>
<?php
}
}
} else {
?>
<img src="/plugin/img/photo.gif" alt="현장확인내역서" class="w-100 object-fit-contain">
@@ -1253,8 +1296,6 @@ $usr_level = session('usr_level');
</div>
<div class="d-flex flex-wrap gap-2">
<!-- NOTE: 기존 코드가 id 중복(photo-display2_I8)이라 반드시 고쳐야 함 -->
<div class="thumb-box">
<?php
$arrI8 = array();
reset($images);
@@ -1282,15 +1323,25 @@ $usr_level = session('usr_level');
$agreement_image = NCLOUD_OBJECT_STORAGE_URL . $link;
}
?>
<a onclick="fn_preview('<?= $agreement_image ?>')">
<img src="<?= $agreement_image_thumbnail ?>" alt="분양권1" class="w-100 object-fit-contain">
<div class="thumb-card">
<div class="thumb-box">
<a onclick="fn_preview_group(this)" data-preview-group="I8"
data-preview-src="<?= $agreement_image ?>">
<img src="<?= $agreement_image_thumbnail ?>" alt="분양권" class="thumb-img">
</a>
</div>
<button type="button" class="btn btn-block btn-outline-danger w-100 mt-1"
onclick="removeFile('<?= $sq ?>')">삭제</button>
</div>
<?php } ?>
<?php } else { ?>
<img id="photo-display2_I8_1" src="/plugin/img/photo.gif" alt="분양권1" class="thumb-img">
<?php } ?>
<div class="thumb-card">
<div class="thumb-box">
<img src="/plugin/img/photo.gif" alt="분양권" class="thumb-img">
</div>
</div>
<?php } ?>
</div>
</div>
<hr class="my-3">
@@ -1301,13 +1352,15 @@ $usr_level = session('usr_level');
<div class="fw-semibold">매물사진 (최대 15장)</div>
<div class="d-flex gap-1 flex-wrap">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="viewFilePop('I4', '')">파일</button>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="saveImgOrder('I4', 'M201')">저장</button>
<button type="button" class="btn btn-sm btn-outline-danger"
onclick="btnSilverDeleteAllImage_onclick('I4')">일괄삭제</button>
onclick="viewFilePop('I4', '')">파일</button>
<?php
if (isset($imgs_count['I4']) && $imgs_count['I4'] != 0) { ?>
<button type="button" class="btn btn-sm btn-outline-focus"
onclick="btnSilverDownloadAllImage_onclick()">일괄다운로드</button>
<?php } ?>
<!-- <button type="button" class="btn btn-sm btn-outline-danger"
onclick="btnSilverDeleteAllImage_onclick('I4')">일괄삭제</button> -->
</div>
</div>
@@ -1343,10 +1396,13 @@ $usr_level = session('usr_level');
value="<?= $img['view_odr'] ?>" />
<input type="hidden" name="i4_seq[]" value="<?= $img['img_sq'] ?>" size="2" />
<div class="thumb-box">
<a onclick="fn_preview('<?= $agreement_image ?>')">
<a onclick="fn_preview_group(this)" data-preview-group="I4"
data-preview-src="<?= $agreement_image ?>">
<img src="<?= $agreement_image_thumbnail ?>" alt="매물사진" class="thumb-img">
</a>
</div>
<button type="button" class="btn btn-block btn-outline-danger w-100 mt-1"
onclick="removeFile('<?= $img['img_sq'] ?>')">삭제</button>
</div>
<?php }
} ?>
@@ -1367,16 +1423,32 @@ $usr_level = session('usr_level');
<div class="row g-3 mb-3">
<div class="col-12 col-lg-4">
<div class="border rounded-3 p-2 ">
<?php
$arrV1 = [];
reset($images);
foreach ($images as $key => $img) {
if ($img['img_type'] == 'V1') {
$arrV1[] = $img;
unset($images[$key]);
}
}
$sqV1 = !empty($arrV1) ? ($arrV1[0]['img_sq'] ?? '') : '';
?>
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-semibold">동영상</div>
<div class="d-flex align-items-center gap-1">
<?php if (!empty($arrV1)) { ?>
<button type="button" class="btn btn-sm btn-outline-danger"
onclick="removeFile('<?= $sqV1 ?>')">삭제</button>
<?php } ?>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="viewFilePop('V1', '')">파일</button>
</div>
</div>
<div class="ratio ratio-4x3 rounded-2 overflow-hidden">
<?php
if (isset($imgs_count['V1']) && $imgs_count['V1'] != 0) {
foreach ($images as $img) {
if ($img['img_type'] == 'V1') {
if (!empty($arrV1)) {
foreach ($arrV1 as $img) {
$link = $img['img_path'] . $img['img_filenm'];
$temp2 = explode(".", $img['img_filenm']);
@@ -1396,7 +1468,6 @@ $usr_level = session('usr_level');
<?php
}
}
} else {
?>
<img src="/plugin/img/photo.gif" alt="동영상" class="w-100 object-fit-contain">
@@ -1407,16 +1478,32 @@ $usr_level = session('usr_level');
<div class="col-12 col-lg-4">
<div class="border rounded-3 p-2 ">
<?php
$arrI5 = [];
reset($images);
foreach ($images as $key => $img) {
if ($img['img_type'] == 'I5') {
$arrI5[] = $img;
unset($images[$key]);
}
}
$sqI5 = !empty($arrI5) ? ($arrI5[0]['img_sq'] ?? '') : '';
?>
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-semibold">평면도</div>
<div class="d-flex align-items-center gap-1">
<?php if (!empty($arrI5)) { ?>
<button type="button" class="btn btn-sm btn-outline-danger"
onclick="removeFile('<?= $sqI5 ?>')">삭제</button>
<?php } ?>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="viewFilePop('I5', '')">파일</button>
</div>
</div>
<div class="ratio ratio-4x3 rounded-2 overflow-hidden">
<?php
if (isset($imgs_count['I5']) && $imgs_count['I5'] != 0) {
foreach ($images as $img) {
if ($img['img_type'] == 'I5') {
if (!empty($arrI5)) {
foreach ($arrI5 as $img) {
$link = $img['img_path'] . $img['img_filenm'];
$temp2 = explode(".", $img['img_filenm']);
$name = $temp2[0] . "_thumb.jpg";
@@ -1431,7 +1518,6 @@ $usr_level = session('usr_level');
<img id="photo-display2_I1" src="<?= $thumblink ?>" alt="평면도" class="w-100 object-fit-contain">
</a>
<?php }
}
} else { ?>
<img src="/plugin/img/photo.gif" alt="평면도" class="w-100 object-fit-contain">
@@ -1442,16 +1528,32 @@ $usr_level = session('usr_level');
<div class="col-12 col-lg-4">
<div class="border rounded-3 p-2 ">
<?php
$arrI11 = [];
reset($images);
foreach ($images as $key => $img) {
if ($img['img_type'] == 'I11') {
$arrI11[] = $img;
unset($images[$key]);
}
}
$sqI11 = !empty($arrI11) ? ($arrI11[0]['img_sq'] ?? '') : '';
?>
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-semibold">체크리스트</div>
<div class="d-flex align-items-center gap-1">
<?php if (!empty($arrI11)) { ?>
<button type="button" class="btn btn-sm btn-outline-danger"
onclick="removeFile('<?= $sqI11 ?>')">삭제</button>
<?php } ?>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="viewFilePop('I11', '')">파일</button>
</div>
</div>
<div class="ratio ratio-4x3 rounded-2 overflow-hidden">
<?php
if (isset($imgs_count['I11']) && $imgs_count['I11'] != 0) {
foreach ($images as $img) {
if ($img['img_type'] == 'I11') {
if (!empty($arrI11)) {
foreach ($arrI11 as $img) {
$link = $img['img_path'] . $img['img_filenm'];
$temp2 = explode(".", $img['img_filenm']);
$name = $temp2[0] . "_thumb.jpg";
@@ -1466,7 +1568,6 @@ $usr_level = session('usr_level');
<img id="photo-display2_I1" src="<?= $thumblink ?>" alt="체크리스트" class="w-100 object-fit-contain">
</a>
<?php }
}
} else { ?>
<img src="/plugin/img/photo.gif" alt="체크리스트" class="w-100 object-fit-contain">
@@ -1798,13 +1899,17 @@ $usr_level = session('usr_level');
?>
<div class="thumb-card">
<div class="thumb-box mb-1">
<a onclick="fn_preview('<?= $link ?>')">
<a onclick="fn_preview_group(this)" data-preview-group="I9" data-preview-src="<?= $link ?>">
<img src="<?= $thumblink ?>" alt="360이미지" class="thumb-img">
</a>
</div>
<input class="form-control form-control-sm" type="text" name="img_location_<?= $img['img_sq'] ?>"
id="img_location_<?= $img['img_sq'] ?>" value="<?= $img['img_location'] ?>" size="11"
style="width: 160px;">
<input class="form-control form-control-sm img-location-input" type="text"
name="img_location_<?= $img['img_sq'] ?>" id="img_location_<?= $img['img_sq'] ?>"
value="<?= $img['img_location'] ?>" size="11">
<button type="button" class="btn btn-block btn-outline-focus w-100 mt-1"
onclick="saveImgLocation('<?= $img['img_sq'] ?>')">저장</button>
<button type="button" class="btn btn-block btn-outline-danger w-100 mt-1"
onclick="removeFile('<?= $img['img_sq'] ?>')">삭제</button>
</div>
<?php }
}
@@ -1813,7 +1918,7 @@ $usr_level = session('usr_level');
<div class="thumb-box mb-1">
<img src="/plugin/img/photo.gif" alt="360이미지" class="thumb-img">
</div>
<input class="form-control form-control-sm" type="text" placeholder="촬영위치" style="width: 160px;">
<input class="form-control form-control-sm img-location-input" type="text" placeholder="촬영위치">
</div>
<?php } ?>
</div>
@@ -1991,6 +2096,12 @@ $usr_level = session('usr_level');
<source id="videoSource" src="" type="video/mp4">
브라우저가 video 태그를 지원하지 않습니다.
</video>
<div id="imgSliderControls" class="d-flex justify-content-between align-items-center p-2"
style="display: none;">
<button type="button" class="btn btn-sm btn-outline-secondary" id="btnPrevImg">이전</button>
<div id="imgSlideCounter" class="small text-muted"></div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="btnNextImg">다음</button>
</div>
</div>
</div>
</div>
@@ -2005,7 +2116,11 @@ $usr_level = session('usr_level');
</div>
<div class="modal-body p-0">
<form id="frm_file_info" method="post" enctype="multipart/form-data" onsubmit="return false;">
<input type="hidden" name="rcpt_key" value="">
<input type="hidden" name="rcpt_key" value="<?= esc($data['rcpt_key'] ?? '') ?>">
<input type="hidden" name="rsrv_sq" value="<?= esc($data['rsrv_sq'] ?? '') ?>">
<input type="hidden" name="rcpt_sq" value="<?= esc($data['rcpt_sq'] ?? '') ?>">
<input type="hidden" name="img_type" value="">
<input type="hidden" name="img_sub_type" value="">
<!-- 버튼 툴바 -->
<div class="d-flex justify-content-end gap-2 mb-3" style="padding: 16px 10px 0 0;">
@@ -2092,11 +2207,244 @@ $usr_level = session('usr_level');
const lng = parseFloat("<?= esc($data['rcpt_x'] ?? '0') ?>");
const smsArr = <?= json_encode($sms ?? [], JSON_UNESCAPED_UNICODE); ?>;
const existingImgCounts = <?= json_encode($imgs_count ?? [], JSON_UNESCAPED_UNICODE); ?>;
var map;
Dropzone.autoDiscover = false;
/**
* 파일 Dropzone (모달 오픈 시 재생성)
* */
let dz = null;
let isFormDataAppended = false;
let lastUploadResponse = null;
function createDropzone() {
if (dz) {
dz.destroy();
dz = null;
}
isFormDataAppended = false;
lastUploadResponse = null;
const imgType = $("#frm_file_info [name=img_type]").val();
let maxFiles = 1;
if (imgType === "I8") {
maxFiles = 5;
} else if (imgType === "I4") {
maxFiles = 15;
} else if (imgType === "I9") {
maxFiles = 5;
}
const existingCount = Number(existingImgCounts[imgType] || 0);
const remainingFiles = Math.max(maxFiles - existingCount, 0);
const acceptedFiles = imgType === "V1"
? ".mp4,.mov,.avi,.wmv,.mkv"
: ".jpg,.jpeg,.png,.gif,.webp,.bmp";
dz = new Dropzone("#myDropzone", {
url: "/article/receipt/uploadFile",
method: "post",
paramName: "files",
autoProcessQueue: false, // 자동 업로드 끄기
uploadMultiple: true,
parallelUploads: 20,
maxFilesize: 100,
maxFiles: remainingFiles,
acceptedFiles: acceptedFiles,
addRemoveLinks: true,
dictRemoveFile: "삭제",
dictDefaultMessage: "파일을 여기에 드래그하거나 클릭해서 추가하세요",
dictFallbackMessage: "브라우저가 드래그앤드롭을 지원하지 않습니다.",
dictFileTooBig: "파일이 너무 큽니다 (최대 {{maxFilesize}}MB)",
dictInvalidFileType: "허용되지 않은 파일 형식입니다.",
dictResponseError: "서버 오류가 발생했습니다.",
dictCancelUpload: "업로드 취소",
dictRemoveFile: "삭제",
dictMaxFilesExceeded: "더 이상 파일을 추가할 수 없습니다.",
init: function () {
if (remainingFiles <= 0) {
alert("이미 업로드된 파일이 있어 추가 업로드가 불가합니다. (최대 " + maxFiles + "개)");
this.removeAllFiles(true);
return;
}
this.on("addedfile", function (file) {
if (this.files.length > remainingFiles) {
alert("파일은 최대 " + maxFiles + "개까지 업로드할 수 있습니다. (남은 가능 수: " + remainingFiles + ")");
this.removeFile(file);
return;
}
});
},
});
dz.on("addedfile", function (file) {
const removeBtn = file.previewElement.querySelector(".dz-remove");
if (removeBtn) {
removeBtn.classList.add(
"btn",
"btn-sm",
"btn-outline-danger",
"mt-2"
);
}
});
dz.on("sending", function (file, xhr, formData) {
if (isFormDataAppended) return;
formData.append("rcpt_key", $("#frm_file_info [name=rcpt_key]").val());
formData.append("rsrv_sq", $("#frm_file_info [name=rsrv_sq]").val());
formData.append("rcpt_sq", $("#frm_file_info [name=rcpt_sq]").val());
formData.append("img_type", $("#frm_file_info [name=img_type]").val());
formData.append("img_sub_type", $("#frm_file_info [name=img_sub_type]").val());
isFormDataAppended = true;
});
dz.on("success", function (file, response) {
lastUploadResponse = response;
});
dz.on("error", function (file, errorMessage, xhr) {
if (xhr && xhr.responseText) {
try {
lastUploadResponse = JSON.parse(xhr.responseText);
} catch (e) {
lastUploadResponse = { code: "-1", msg: xhr.responseText };
}
} else {
lastUploadResponse = { code: "-1", msg: errorMessage || "업로드 실패" };
}
});
dz.on("queuecomplete", function () {
let result = lastUploadResponse;
if (typeof result === "string") {
try {
result = JSON.parse(result);
} catch (e) {
result = { code: "-1", msg: result };
}
}
if (String(result.code) === "0") {
swal.fire({
title: "업로드가 완료되었습니다.",
icon: "success",
});
location.reload();
return;
}
const msg = result.msg ? result.msg : "업로드 실패";
swal.fire({
title: msg,
icon: "error",
draggable: true
});
});
dz.on("successmultiple", function () {
isFormDataAppended = false;
});
dz.on("errormultiple", function () {
isFormDataAppended = false;
});
dz.on("canceledmultiple", function () {
isFormDataAppended = false;
});
dz.on("processingmultiple", function () { });
}
// 파일업로드 모달 오픈
function viewFilePop(imgType, imgSubType) {
$("#frm_file_info [name=img_type]").val(imgType || "");
$("#frm_file_info [name=img_sub_type]").val(imgSubType || "");
createDropzone();
$("#uploadModal").modal("show");
}
// 이미지 촬영위치 저장
function saveImgLocation(img_sq) {
swal.fire({
text: "저장 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
const location = $(`#img_location_${img_sq}`).val();
var params = {
'location': location,
'img_sq': img_sq,
'rsrv_sq': '<?= $data['rsrv_sq'] ?>',
};
callAjax("/article/receipt/saveImgLocation", params, fn_result);
}
});
}
// 파일삭제
function removeFile(img_sq) {
swal.fire({
text: "삭제 하시겠습니까?",
type: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {
if (result.isConfirmed) {
var params = {
'img_sq': img_sq,
'rcpt_sq': '<?= $data['rcpt_sq'] ?>',
};
callAjax("/article/receipt/removeUploadFile", params, fn_result);
}
});
}
// 매물사진 일괄 다운로드
function btnSilverDownloadAllImage_onclick() {
const rsrvSq = '<?= $data['rsrv_sq'] ?>';
if (!rsrvSq) {
swal.fire({
title: "예약번호가 없습니다.",
icon: "error",
draggable: true
});
return;
}
const url = "/article/receipt/downloadAllImages?rsrv_sq=" + encodeURIComponent(rsrvSq) + "&img_type=I4";
window.location.href = url;
}
$(function () {
buildPreviewGroups();
trade_type_onchange();
if (isDefined(rcpt_hscp_nm)) {
@@ -2125,90 +2473,21 @@ $usr_level = session('usr_level');
});
/**
* 파일 Dropzone
* */
const dz = new Dropzone("#myDropzone", {
url: "/m712/m712a/uploadFile",
method: "post",
paramName: "files",
autoProcessQueue: false, // 자동 업로드 끄기
uploadMultiple: false,
parallelUploads: 20,
maxFilesize: 100,
// acceptedFiles: '.ogg,.mp3,.wma,.wav,.au,.rm,.mid,.MP3,.OGG,.WMA,.WAV,.AU,.RM,.MID,.gsm',
addRemoveLinks: true,
dictRemoveFile: "삭제",
dictDefaultMessage: "파일을 여기에 드래그하거나 클릭해서 추가하세요",
dictFallbackMessage: "브라우저가 드래그앤드롭을 지원하지 않습니다.",
dictFileTooBig: "파일이 너무 큽니다 (최대 {{maxFilesize}}MB)",
dictInvalidFileType: "허용되지 않은 파일 형식입니다.",
dictResponseError: "서버 오류가 발생했습니다.",
dictCancelUpload: "업로드 취소",
dictRemoveFile: "삭제",
dictMaxFilesExceeded: "더 이상 파일을 추가할 수 없습니다.",
init: function () {
this.on("addedfile", function (file) {
if (this.files.length > 1) {
alert("파일은 1개만 업로드할 수 있습니다.");
this.removeFile(file);
return;
}
});
},
});
dz.on("addedfile", function (file) {
const removeBtn = file.previewElement.querySelector(".dz-remove");
if (removeBtn) {
removeBtn.classList.add(
"btn",
"btn-sm",
"btn-outline-danger",
"mt-2"
);
}
});
let isFormDataAppended = false;
dz.on("sending", function (file, xhr, formData) {
if (isFormDataAppended) return;
formData.append("vr_sq", $("#frm_file_info [name=vr_sq]").val());
isFormDataAppended = true;
});
dz.on("queuecomplete", function () {
location.reload();
});
dz.on("successmultiple", function () {
isFormDataAppended = false;
});
dz.on("errormultiple", function () {
isFormDataAppended = false;
});
dz.on("canceledmultiple", function () {
isFormDataAppended = false;
});
dz.on("processingmultiple", function () { });
// 업로드파일 선택
$("#uploadPick").on("click", function () {
if (!dz) return;
isFormDataAppended = false;
dz.hiddenFileInput.click();
});
$("#btnUpload").on("click", function () {
if (!dz) return;
dz.processQueue(); // 업로드 실행
isFormDataAppended = false;
});
$("#btnRemove").on("click", function () {
if (!dz) return;
const files = dz.getAcceptedFiles();
if (files.length === 0) {
@@ -2224,8 +2503,15 @@ $usr_level = session('usr_level');
// 파일업로드 open
$("#btnUploadModal").on("click", function () {
viewFilePop($("#frm_file_info [name=img_type]").val(), $("#frm_file_info [name=img_sub_type]").val());
});
$("#uploadModal").modal("show");
$("#btnPrevImg").on("click", function () {
movePreview(-1);
});
$("#btnNextImg").on("click", function () {
movePreview(1);
});
});
@@ -2688,6 +2974,89 @@ $usr_level = session('usr_level');
let previewGroups = {};
let currentPreviewGroup = null;
let currentPreviewIndex = 0;
function buildPreviewGroups() {
previewGroups = {};
document.querySelectorAll('[data-preview-group][data-preview-src]').forEach((el) => {
const group = el.dataset.previewGroup;
const src = el.dataset.previewSrc;
if (!previewGroups[group]) {
previewGroups[group] = [];
}
previewGroups[group].push(src);
});
}
function showImagePreview(src) {
const $img = $('#imgPreview');
const $video = $('#vdoPreview');
const video = document.getElementById('vdoPreview');
const source = document.getElementById('videoSource');
video.pause();
source.src = '';
video.load();
$video.hide();
$img.attr('src', src).show();
}
function updateSliderControls() {
const $controls = $('#imgSliderControls');
const $counter = $('#imgSlideCounter');
if (!currentPreviewGroup || !previewGroups[currentPreviewGroup] || previewGroups[currentPreviewGroup].length <= 1) {
$controls.hide();
$counter.text('');
return;
}
const total = previewGroups[currentPreviewGroup].length;
$counter.text((currentPreviewIndex + 1) + ' / ' + total);
$controls.show();
}
function openPreviewModal() {
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
modal.show();
}
function fn_preview_group(el) {
const group = el.dataset.previewGroup;
const src = el.dataset.previewSrc;
buildPreviewGroups();
currentPreviewGroup = group;
currentPreviewIndex = (previewGroups[group] || []).indexOf(src);
if (currentPreviewIndex < 0) {
currentPreviewIndex = 0;
}
showImagePreview(src);
updateSliderControls();
openPreviewModal();
}
function movePreview(step) {
if (!currentPreviewGroup || !previewGroups[currentPreviewGroup]) {
return;
}
const total = previewGroups[currentPreviewGroup].length;
if (total === 0) {
return;
}
currentPreviewIndex = (currentPreviewIndex + step + total) % total;
const nextSrc = previewGroups[currentPreviewGroup][currentPreviewIndex];
showImagePreview(nextSrc);
updateSliderControls();
}
function fn_preview(src, type = 'img') {
const $img = $('#imgPreview');
@@ -2695,6 +3064,9 @@ $usr_level = session('usr_level');
const video = document.getElementById('vdoPreview');
const source = document.getElementById('videoSource');
currentPreviewGroup = null;
updateSliderControls();
if (type === 'vdo') {
// 이미지 숨김
$img.hide().attr('src', '');
@@ -2720,8 +3092,7 @@ $usr_level = session('usr_level');
$('#previewTitle').text('이미지 미리보기');
}
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
modal.show();
openPreviewModal();
}
function callAjax(target, params, callback) {